Commit 5fed877b authored by Kyle Horimoto's avatar Kyle Horimoto Committed by Commit Bot

[CrOS MultiDevice] Update ConnectionAttempt.

Now, ConnectionAttempt uses a single ConnectToDeviceOperation throughout
its lifetime, which drastically cleans up the code and removes the
ConnectToDeviceOperationFactory, which is not really needed.

This CL removes ConnectToDeviceOperationFactory entirely.

Bug: 824568, 752273
Change-Id: Iaf8182da258e864b1377aa94cefa1ed9440e8bd1
Reviewed-on: https://chromium-review.googlesource.com/1103337
Commit-Queue: Kyle Horimoto <khorimoto@chromium.org>
Reviewed-by: default avatarRyan Hansberry <hansberry@chromium.org>
Cr-Commit-Position: refs/heads/master@{#568181}
parent b5db59bc
......@@ -51,8 +51,6 @@ static_library("secure_channel") {
"client_connection_parameters_impl.h",
"connect_to_device_operation.h",
"connect_to_device_operation_base.h",
"connect_to_device_operation_factory.h",
"connect_to_device_operation_factory_base.h",
"connection_attempt.h",
"connection_attempt_base.h",
"connection_attempt_delegate.h",
......@@ -146,7 +144,6 @@ static_library("test_support") {
"fake_client_connection_parameters.cc",
"fake_client_connection_parameters.h",
"fake_connect_to_device_operation.h",
"fake_connect_to_device_operation_factory.h",
"fake_connection_attempt.h",
"fake_connection_attempt_delegate.cc",
"fake_connection_attempt_delegate.h",
......@@ -201,7 +198,6 @@ source_set("unit_tests") {
"ble_synchronizer_unittest.cc",
"client_connection_parameters_impl_unittest.cc",
"connect_to_device_operation_base_unittest.cc",
"connect_to_device_operation_factory_base_unittest.cc",
"connection_attempt_base_unittest.cc",
"error_tolerant_ble_advertisement_impl_unittest.cc",
"multiplexed_channel_impl_unittest.cc",
......
......@@ -37,15 +37,14 @@ std::unique_ptr<ConnectToDeviceOperation<BleInitiatorFailureType>>
BleInitiatorOperation::Factory::BuildInstance(
ConnectToDeviceOperation<BleInitiatorFailureType>::ConnectionSuccessCallback
success_callback,
ConnectToDeviceOperation<BleInitiatorFailureType>::ConnectionFailedCallback
failure_callback,
const ConnectToDeviceOperation<
BleInitiatorFailureType>::ConnectionFailedCallback& failure_callback,
const DeviceIdPair& device_id_pair,
ConnectionPriority connection_priority,
base::OnceClosure destructor_callback,
scoped_refptr<base::TaskRunner> task_runner) {
return base::WrapUnique(new BleInitiatorOperation(
std::move(success_callback), std::move(failure_callback), device_id_pair,
connection_priority, std::move(destructor_callback), task_runner));
connection_priority, task_runner));
}
BleInitiatorOperation::~BleInitiatorOperation() = default;
......@@ -53,18 +52,16 @@ BleInitiatorOperation::~BleInitiatorOperation() = default;
BleInitiatorOperation::BleInitiatorOperation(
ConnectToDeviceOperation<BleInitiatorFailureType>::ConnectionSuccessCallback
success_callback,
ConnectToDeviceOperation<BleInitiatorFailureType>::ConnectionFailedCallback
failure_callback,
const ConnectToDeviceOperation<
BleInitiatorFailureType>::ConnectionFailedCallback& failure_callback,
const DeviceIdPair& device_id_pair,
ConnectionPriority connection_priority,
base::OnceClosure destructor_callback,
scoped_refptr<base::TaskRunner> task_runner)
: ConnectToDeviceOperationBase<BleInitiatorFailureType>(
std::move(success_callback),
std::move(failure_callback),
device_id_pair,
connection_priority,
std::move(destructor_callback),
task_runner) {}
void BleInitiatorOperation::AttemptConnectionToDevice(
......
......@@ -30,11 +30,10 @@ class BleInitiatorOperation
virtual std::unique_ptr<ConnectToDeviceOperation<BleInitiatorFailureType>>
BuildInstance(ConnectToDeviceOperation<BleInitiatorFailureType>::
ConnectionSuccessCallback success_callback,
ConnectToDeviceOperation<BleInitiatorFailureType>::
ConnectionFailedCallback failure_callback,
const ConnectToDeviceOperation<BleInitiatorFailureType>::
ConnectionFailedCallback& failure_callback,
const DeviceIdPair& device_id_pair,
ConnectionPriority connection_priority,
base::OnceClosure destructor_callback,
scoped_refptr<base::TaskRunner> task_runner =
base::ThreadTaskRunnerHandle::Get());
......@@ -48,11 +47,10 @@ class BleInitiatorOperation
BleInitiatorOperation(
ConnectToDeviceOperation<
BleInitiatorFailureType>::ConnectionSuccessCallback success_callback,
ConnectToDeviceOperation<
BleInitiatorFailureType>::ConnectionFailedCallback failure_callback,
const ConnectToDeviceOperation<
BleInitiatorFailureType>::ConnectionFailedCallback& failure_callback,
const DeviceIdPair& device_id_pair,
ConnectionPriority connection_priority,
base::OnceClosure destructor_callback,
scoped_refptr<base::TaskRunner> task_runner);
// ConnectToDeviceOperationBase<BleInitiatorFailureType>:
......
......@@ -37,15 +37,14 @@ std::unique_ptr<ConnectToDeviceOperation<BleListenerFailureType>>
BleListenerOperation::Factory::BuildInstance(
ConnectToDeviceOperation<BleListenerFailureType>::ConnectionSuccessCallback
success_callback,
ConnectToDeviceOperation<BleListenerFailureType>::ConnectionFailedCallback
failure_callback,
const ConnectToDeviceOperation<
BleListenerFailureType>::ConnectionFailedCallback& failure_callback,
const DeviceIdPair& device_id_pair,
ConnectionPriority connection_priority,
base::OnceClosure destructor_callback,
scoped_refptr<base::TaskRunner> task_runner) {
return base::WrapUnique(new BleListenerOperation(
std::move(success_callback), std::move(failure_callback), device_id_pair,
connection_priority, std::move(destructor_callback), task_runner));
connection_priority, task_runner));
}
BleListenerOperation::~BleListenerOperation() = default;
......@@ -53,18 +52,16 @@ BleListenerOperation::~BleListenerOperation() = default;
BleListenerOperation::BleListenerOperation(
ConnectToDeviceOperation<BleListenerFailureType>::ConnectionSuccessCallback
success_callback,
ConnectToDeviceOperation<BleListenerFailureType>::ConnectionFailedCallback
failure_callback,
const ConnectToDeviceOperation<
BleListenerFailureType>::ConnectionFailedCallback& failure_callback,
const DeviceIdPair& device_id_pair,
ConnectionPriority connection_priority,
base::OnceClosure destructor_callback,
scoped_refptr<base::TaskRunner> task_runner)
: ConnectToDeviceOperationBase<BleListenerFailureType>(
std::move(success_callback),
std::move(failure_callback),
device_id_pair,
connection_priority,
std::move(destructor_callback),
task_runner) {}
void BleListenerOperation::AttemptConnectionToDevice(
......
......@@ -31,11 +31,10 @@ class BleListenerOperation
BuildInstance(
ConnectToDeviceOperation<
BleListenerFailureType>::ConnectionSuccessCallback success_callback,
ConnectToDeviceOperation<
BleListenerFailureType>::ConnectionFailedCallback failure_callback,
const ConnectToDeviceOperation<
BleListenerFailureType>::ConnectionFailedCallback& failure_callback,
const DeviceIdPair& device_id_pair,
ConnectionPriority connection_priority,
base::OnceClosure destructor_callback,
scoped_refptr<base::TaskRunner> task_runner =
base::ThreadTaskRunnerHandle::Get());
......@@ -49,11 +48,10 @@ class BleListenerOperation
BleListenerOperation(
ConnectToDeviceOperation<
BleListenerFailureType>::ConnectionSuccessCallback success_callback,
ConnectToDeviceOperation<BleListenerFailureType>::ConnectionFailedCallback
failure_callback,
const ConnectToDeviceOperation<
BleListenerFailureType>::ConnectionFailedCallback& failure_callback,
const DeviceIdPair& device_id_pair,
ConnectionPriority connection_priority,
base::OnceClosure destructor_callback,
scoped_refptr<base::TaskRunner> task_runner);
// ConnectToDeviceOperationBase<BleListenerFailureType>:
......
......@@ -26,10 +26,11 @@ class ConnectToDeviceOperation {
public:
using ConnectionSuccessCallback =
base::OnceCallback<void(std::unique_ptr<AuthenticatedChannel>)>;
using ConnectionFailedCallback = base::OnceCallback<void(FailureDetailType)>;
using ConnectionFailedCallback =
base::RepeatingCallback<void(FailureDetailType)>;
virtual ~ConnectToDeviceOperation() {
if (!is_active_)
if (has_finished_)
return;
PA_LOG(ERROR) << "ConnectToDeviceOperation::~ConnectToDeviceOperation(): "
......@@ -39,7 +40,7 @@ class ConnectToDeviceOperation {
// Updates the priority for this operation.
void UpdateConnectionPriority(ConnectionPriority connection_priority) {
if (!is_active_) {
if (has_finished_) {
PA_LOG(ERROR) << "ConnectToDeviceOperation::UpdateConnectionPriority(): "
<< "Connection priority update requested, but the "
<< "operation was no longer active.";
......@@ -54,14 +55,14 @@ class ConnectToDeviceOperation {
// Note: Canceling an ongoing connection attempt will not cause either of the
// success/failure callbacks passed to the constructor to be invoked.
void Cancel() {
if (!is_active_) {
if (has_finished_) {
PA_LOG(ERROR) << "ConnectToDeviceOperation::Cancel(): Tried to cancel "
<< "operation after it had already finished.";
NOTREACHED();
return;
}
is_active_ = false;
has_finished_ = true;
PerformCancellation();
}
......@@ -71,10 +72,10 @@ class ConnectToDeviceOperation {
protected:
ConnectToDeviceOperation(ConnectionSuccessCallback success_callback,
ConnectionFailedCallback failure_callback,
const ConnectionFailedCallback& failure_callback,
ConnectionPriority connection_priority)
: success_callback_(std::move(success_callback)),
failure_callback_(std::move(failure_callback)),
failure_callback_(failure_callback),
connection_priority_(connection_priority) {}
virtual void PerformCancellation() = 0;
......@@ -83,31 +84,23 @@ class ConnectToDeviceOperation {
void OnSuccessfulConnectionAttempt(
std::unique_ptr<AuthenticatedChannel> authenticated_channel) {
if (!is_active_) {
if (has_finished_) {
PA_LOG(ERROR) << "ConnectToDeviceOperation::"
<< "OnSuccessfulConnectionAttempt(): Tried to "
<< "complete operation after it had already finished.";
return;
}
is_active_ = false;
has_finished_ = true;
std::move(success_callback_).Run(std::move(authenticated_channel));
}
void OnFailedConnectionAttempt(FailureDetailType failure_detail) {
if (!is_active_) {
PA_LOG(ERROR) << "ConnectToDeviceOperation::"
<< "OnFailedConnectionAttempt(): Tried to "
<< "complete operation after it had already finished.";
return;
}
is_active_ = false;
std::move(failure_callback_).Run(failure_detail);
failure_callback_.Run(failure_detail);
}
private:
bool is_active_ = true;
bool has_finished_ = false;
ConnectionSuccessCallback success_callback_;
ConnectionFailedCallback failure_callback_;
......
......@@ -34,14 +34,12 @@ class ConnectToDeviceOperationBase
FailureDetailType>::ConnectionFailedCallback failure_callback,
const DeviceIdPair& device_id_pair,
ConnectionPriority connection_priority,
base::OnceClosure destructor_callback,
scoped_refptr<base::TaskRunner> task_runner =
base::ThreadTaskRunnerHandle::Get())
: ConnectToDeviceOperation<FailureDetailType>(std::move(success_callback),
std::move(failure_callback),
connection_priority),
device_id_pair_(device_id_pair),
destructor_callback_(std::move(destructor_callback)),
task_runner_(task_runner),
weak_ptr_factory_(this) {
// Attempt a connection; however, post this as a task to be run after the
......@@ -54,9 +52,7 @@ class ConnectToDeviceOperationBase
weak_ptr_factory_.GetWeakPtr(), connection_priority));
}
~ConnectToDeviceOperationBase() override {
std::move(destructor_callback_).Run();
}
~ConnectToDeviceOperationBase() override = default;
virtual void AttemptConnectionToDevice(
ConnectionPriority connection_priority) = 0;
......@@ -65,7 +61,6 @@ class ConnectToDeviceOperationBase
private:
const DeviceIdPair& device_id_pair_;
base::OnceClosure destructor_callback_;
scoped_refptr<base::TaskRunner> task_runner_;
base::WeakPtrFactory<ConnectToDeviceOperationBase> weak_ptr_factory_;
......
......@@ -20,7 +20,6 @@ namespace secure_channel {
namespace {
const char kTestFailureReason[] = "testFailureReason";
const char kTestRemoteDeviceId[] = "testRemoteDeviceId";
const char kTestLocalDeviceId[] = "testLocalDeviceId";
......@@ -32,16 +31,14 @@ class TestConnectToDeviceOperation
static std::unique_ptr<TestConnectToDeviceOperation> Create(
ConnectToDeviceOperation<std::string>::ConnectionSuccessCallback
success_callback,
ConnectToDeviceOperation<std::string>::ConnectionFailedCallback
const ConnectToDeviceOperation<std::string>::ConnectionFailedCallback&
failure_callback,
const DeviceIdPair& device_id_pair,
ConnectionPriority connection_priority,
base::OnceClosure destructor_callback) {
ConnectionPriority connection_priority) {
auto test_task_runner = base::MakeRefCounted<base::TestSimpleTaskRunner>();
auto operation = base::WrapUnique(new TestConnectToDeviceOperation(
std::move(success_callback), std::move(failure_callback),
device_id_pair, connection_priority, std::move(destructor_callback),
test_task_runner));
device_id_pair, connection_priority, test_task_runner));
test_task_runner->RunUntilIdle();
return operation;
}
......@@ -70,19 +67,16 @@ class TestConnectToDeviceOperation
TestConnectToDeviceOperation(
ConnectToDeviceOperation<std::string>::ConnectionSuccessCallback
success_callback,
ConnectToDeviceOperation<std::string>::ConnectionFailedCallback
const ConnectToDeviceOperation<std::string>::ConnectionFailedCallback&
failure_callback,
const DeviceIdPair& device_id_pair,
ConnectionPriority connection_priority,
base::OnceClosure destructor_callback,
scoped_refptr<base::TestSimpleTaskRunner> test_task_runner)
: ConnectToDeviceOperationBase<std::string>(
std::move(success_callback),
std::move(failure_callback),
device_id_pair,
connection_priority,
std::move(destructor_callback),
test_task_runner) {}
: ConnectToDeviceOperationBase<std::string>(std::move(success_callback),
std::move(failure_callback),
device_id_pair,
connection_priority,
test_task_runner) {}
bool has_attempted_connection_ = false;
bool has_canceled_connection_ = false;
......@@ -97,25 +91,15 @@ class SecureChannelConnectToDeviceOperationBaseTest : public testing::Test {
~SecureChannelConnectToDeviceOperationBaseTest() override = default;
// testing::Test:
void TearDown() override {
EXPECT_FALSE(destructor_callback_called_);
test_operation_.reset();
EXPECT_TRUE(destructor_callback_called_);
}
void CreateOperation(ConnectionPriority connection_priority) {
test_operation_ = TestConnectToDeviceOperation::Create(
base::BindOnce(&SecureChannelConnectToDeviceOperationBaseTest::
OnSuccessfulConnectionAttempt,
base::Unretained(this)),
base::BindOnce(&SecureChannelConnectToDeviceOperationBaseTest::
OnFailedConnectionAttempt,
base::Unretained(this)),
test_device_id_pair_, connection_priority,
base::BindOnce(
&SecureChannelConnectToDeviceOperationBaseTest::OnOperationDeleted,
base::Unretained(this)));
base::BindRepeating(&SecureChannelConnectToDeviceOperationBaseTest::
OnFailedConnectionAttempt,
base::Unretained(this)),
test_device_id_pair_, connection_priority);
EXPECT_TRUE(test_operation_->has_attempted_connection());
}
......@@ -141,14 +125,11 @@ class SecureChannelConnectToDeviceOperationBaseTest : public testing::Test {
last_failure_detail_ = failure_detail;
}
void OnOperationDeleted() { destructor_callback_called_ = true; }
const base::test::ScopedTaskEnvironment scoped_task_environment_;
const DeviceIdPair test_device_id_pair_;
std::unique_ptr<AuthenticatedChannel> last_authenticated_channel_;
std::string last_failure_detail_;
bool destructor_callback_called_ = false;
std::unique_ptr<TestConnectToDeviceOperation> test_operation_;
......@@ -177,8 +158,14 @@ TEST_F(SecureChannelConnectToDeviceOperationBaseTest, Success) {
TEST_F(SecureChannelConnectToDeviceOperationBaseTest, Failure) {
CreateOperation(ConnectionPriority::kLow);
test_operation()->OnFailedConnectionAttempt(kTestFailureReason);
EXPECT_EQ(kTestFailureReason, last_failure_detail());
test_operation()->OnFailedConnectionAttempt("failureReason1");
EXPECT_EQ("failureReason1", last_failure_detail());
test_operation()->OnFailedConnectionAttempt("failureReason2");
EXPECT_EQ("failureReason2", last_failure_detail());
test_operation()->Cancel();
}
TEST_F(SecureChannelConnectToDeviceOperationBaseTest, Cancelation) {
......
// Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CHROMEOS_SERVICES_SECURE_CHANNEL_CONNECT_TO_DEVICE_OPERATION_FACTORY_H_
#define CHROMEOS_SERVICES_SECURE_CHANNEL_CONNECT_TO_DEVICE_OPERATION_FACTORY_H_
#include "base/callback_forward.h"
#include "base/macros.h"
#include "chromeos/services/secure_channel/connect_to_device_operation.h"
#include "chromeos/services/secure_channel/device_id_pair.h"
#include "chromeos/services/secure_channel/public/cpp/shared/connection_priority.h"
namespace chromeos {
namespace secure_channel {
// Factory for creating ConnectToDeviceOperation instances.
template <typename FailureDetailType>
class ConnectToDeviceOperationFactory {
public:
virtual ~ConnectToDeviceOperationFactory() = default;
virtual std::unique_ptr<ConnectToDeviceOperation<FailureDetailType>>
CreateOperation(
const DeviceIdPair& device_id_pair,
ConnectionPriority connection_priority,
typename ConnectToDeviceOperation<
FailureDetailType>::ConnectionSuccessCallback success_callback,
typename ConnectToDeviceOperation<
FailureDetailType>::ConnectionFailedCallback failure_callback) = 0;
protected:
ConnectToDeviceOperationFactory() = default;
private:
DISALLOW_COPY_AND_ASSIGN(ConnectToDeviceOperationFactory);
};
} // namespace secure_channel
} // namespace chromeos
#endif // CHROMEOS_SERVICES_SECURE_CHANNEL_CONNECT_TO_DEVICE_OPERATION_FACTORY_H_
// Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CHROMEOS_SERVICES_SECURE_CHANNEL_CONNECT_TO_DEVICE_OPERATION_FACTORY_BASE_H_
#define CHROMEOS_SERVICES_SECURE_CHANNEL_CONNECT_TO_DEVICE_OPERATION_FACTORY_BASE_H_
#include "base/bind.h"
#include "base/callback_forward.h"
#include "base/logging.h"
#include "base/macros.h"
#include "base/memory/weak_ptr.h"
#include "chromeos/services/secure_channel/connect_to_device_operation_factory.h"
#include "chromeos/services/secure_channel/device_id_pair.h"
namespace chromeos {
namespace secure_channel {
// ConnectToDeviceOperationFactory implementation, which ensures that only one
// operation can be active at a time.
template <typename FailureDetailType>
class ConnectToDeviceOperationFactoryBase
: public ConnectToDeviceOperationFactory<FailureDetailType> {
public:
~ConnectToDeviceOperationFactoryBase() override = default;
protected:
ConnectToDeviceOperationFactoryBase(const DeviceIdPair& device_id_pair)
: device_id_pair_(device_id_pair), weak_ptr_factory_(this) {}
// Derived types should overload this function, passing the provided
// parameters to the constructor of a type derived from
// ConnectToDeviceOperationBase.
virtual std::unique_ptr<ConnectToDeviceOperation<FailureDetailType>>
PerformCreateOperation(
const DeviceIdPair& device_id_pair,
ConnectionPriority connection_priority,
typename ConnectToDeviceOperation<
FailureDetailType>::ConnectionSuccessCallback success_callback,
typename ConnectToDeviceOperation<
FailureDetailType>::ConnectionFailedCallback failure_callback,
base::OnceClosure destructor_callback) = 0;
private:
// ConnectToDeviceOperationFactory<FailureDetailType>:
std::unique_ptr<ConnectToDeviceOperation<FailureDetailType>> CreateOperation(
const DeviceIdPair& device_id_pair,
ConnectionPriority connection_priority,
typename ConnectToDeviceOperation<
FailureDetailType>::ConnectionSuccessCallback success_callback,
typename ConnectToDeviceOperation<FailureDetailType>::
ConnectionFailedCallback failure_callback) override {
if (is_last_operation_active_) {
PA_LOG(ERROR) << "ConnectToDeviceOperationFactoryBase::CreateOperation():"
<< " Requested new operation before the previous one was "
<< "finished.";
NOTREACHED();
return nullptr;
}
is_last_operation_active_ = true;
return PerformCreateOperation(
device_id_pair_, connection_priority, std::move(success_callback),
std::move(failure_callback),
base::BindOnce(&ConnectToDeviceOperationFactoryBase<
FailureDetailType>::OnPreviousOperationDeleted,
weak_ptr_factory_.GetWeakPtr()));
}
void OnPreviousOperationDeleted() { is_last_operation_active_ = false; }
const DeviceIdPair device_id_pair_;
bool is_last_operation_active_ = false;
base::WeakPtrFactory<ConnectToDeviceOperationFactoryBase> weak_ptr_factory_;
DISALLOW_COPY_AND_ASSIGN(ConnectToDeviceOperationFactoryBase);
};
} // namespace secure_channel
} // namespace chromeos
#endif // CHROMEOS_SERVICES_SECURE_CHANNEL_CONNECT_TO_DEVICE_OPERATION_FACTORY_BASE_H_
// Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chromeos/services/secure_channel/connect_to_device_operation_factory_base.h"
#include <memory>
#include "base/bind_helpers.h"
#include "base/test/gtest_util.h"
#include "chromeos/services/secure_channel/device_id_pair.h"
#include "chromeos/services/secure_channel/fake_connect_to_device_operation.h"
#include "chromeos/services/secure_channel/public/cpp/shared/authenticated_channel.h"
#include "components/cryptauth/secure_channel.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace chromeos {
namespace secure_channel {
namespace {
constexpr const ConnectionPriority kTestPriority = ConnectionPriority::kLow;
const char kTestRemoteDeviceId[] = "testRemoteDeviceId";
const char kTestLocalDeviceId[] = "testLocalDeviceId";
// Since ConnectToDeviceOperationFactoryBase is templatized, a concrete
// implementation is needed for its test.
class TestConnectToDeviceOperationFactory
: public ConnectToDeviceOperationFactoryBase<std::string> {
public:
TestConnectToDeviceOperationFactory(const DeviceIdPair& device_id_pair)
: ConnectToDeviceOperationFactoryBase<std::string>(device_id_pair),
device_id_pair_(device_id_pair) {}
~TestConnectToDeviceOperationFactory() override = default;
void InvokePendingDestructorCallback() {
EXPECT_TRUE(last_destructor_callback_);
std::move(last_destructor_callback_).Run();
}
// ConnectToDeviceOperationFactoryBase<std::string>:
std::unique_ptr<ConnectToDeviceOperation<std::string>> PerformCreateOperation(
const DeviceIdPair& device_id_pair,
ConnectionPriority connection_priority,
typename ConnectToDeviceOperation<std::string>::ConnectionSuccessCallback
success_callback,
typename ConnectToDeviceOperation<std::string>::ConnectionFailedCallback
failure_callback,
base::OnceClosure destructor_callback) override {
// The previous destructor callback should have been invoked by the time
// this function runs.
EXPECT_FALSE(last_destructor_callback_);
last_destructor_callback_ = std::move(destructor_callback);
EXPECT_EQ(kTestPriority, connection_priority);
EXPECT_EQ(device_id_pair_, device_id_pair);
return std::make_unique<FakeConnectToDeviceOperation<std::string>>(
std::move(success_callback), std::move(failure_callback),
connection_priority);
}
private:
const DeviceIdPair device_id_pair_;
base::OnceClosure last_destructor_callback_;
};
} // namespace
class SecureChannelConnectToDeviceOperationFactoryBaseTest
: public testing::Test {
protected:
SecureChannelConnectToDeviceOperationFactoryBaseTest()
: test_device_id_pair_(kTestRemoteDeviceId, kTestLocalDeviceId) {}
~SecureChannelConnectToDeviceOperationFactoryBaseTest() override = default;
void SetUp() override {
test_factory_ = std::make_unique<TestConnectToDeviceOperationFactory>(
test_device_id_pair_);
}
std::unique_ptr<ConnectToDeviceOperation<std::string>> CallCreateOperation() {
// Use a pointer to ConnectToDeviceOperationFactory, since
// ConnectToDeviceOperationFactoryBase makes CreateOperation private.
ConnectToDeviceOperationFactory<std::string>* factory = test_factory_.get();
return factory->CreateOperation(test_device_id_pair_, kTestPriority,
base::DoNothing() /* success_callback */,
base::DoNothing() /* failure_callback */);
}
void FinishActiveOperation(
std::unique_ptr<ConnectToDeviceOperation<std::string>>
operation_to_finish) {
EXPECT_TRUE(operation_to_finish);
// Use a pointer to FakeConnectToDeviceOperation, since
// ConnectToDeviceOperation makes OnSuccessfulConnectionAttempt() protected.
FakeConnectToDeviceOperation<std::string>* operation =
static_cast<FakeConnectToDeviceOperation<std::string>*>(
operation_to_finish.get());
operation->OnFailedConnectionAttempt(
"arbitraryFailureDetail" /* failure_detail */);
test_factory_->InvokePendingDestructorCallback();
}
private:
const DeviceIdPair test_device_id_pair_;
std::unique_ptr<TestConnectToDeviceOperationFactory> test_factory_;
DISALLOW_COPY_AND_ASSIGN(
SecureChannelConnectToDeviceOperationFactoryBaseTest);
};
TEST_F(SecureChannelConnectToDeviceOperationFactoryBaseTest,
UseFactoryCorrectly) {
auto operation1 = CallCreateOperation();
EXPECT_TRUE(operation1);
// Invoke the destructor callback and try again.
FinishActiveOperation(std::move(operation1));
auto operation2 = CallCreateOperation();
EXPECT_TRUE(operation2);
// Invoke the destructor callback and try again.
FinishActiveOperation(std::move(operation2));
auto operation3 = CallCreateOperation();
EXPECT_TRUE(operation3);
FinishActiveOperation(std::move(operation3));
}
TEST_F(SecureChannelConnectToDeviceOperationFactoryBaseTest,
UseFactoryIncorrectly) {
// First operation should always complete successfully.
auto operation = CallCreateOperation();
EXPECT_TRUE(operation);
// The first operation's destructor callback has not yet been invoked, so
// creating another should fail.
EXPECT_DCHECK_DEATH(CallCreateOperation());
FinishActiveOperation(std::move(operation));
}
} // namespace secure_channel
} // namespace chromeos
......@@ -17,6 +17,7 @@
#include "chromeos/services/secure_channel/connection_attempt_details.h"
#include "chromeos/services/secure_channel/connection_details.h"
#include "chromeos/services/secure_channel/pending_connection_request.h"
#include "chromeos/services/secure_channel/pending_connection_request_delegate.h"
namespace chromeos {
......@@ -29,7 +30,7 @@ class AuthenticatedChannel;
// more PendingConnectionRequests and notifies its delegate when the attempt has
// succeeded or failed.
template <typename FailureDetailType>
class ConnectionAttempt {
class ConnectionAttempt : public PendingConnectionRequestDelegate {
public:
// Extracts all of the ClientConnectionParameters owned by |attempt|'s
// PendingConnectionRequests. This function deletes |attempt| as part of this
......@@ -57,7 +58,7 @@ class ConnectionAttempt {
return false;
}
if (has_notified_delegate_) {
if (has_notified_delegate_of_success_) {
PA_LOG(ERROR) << "ConnectionAttempt::AddPendingConnectionRequest(): "
<< "Tried to add an additional request,but the attempt had "
<< "already finished.";
......@@ -88,21 +89,21 @@ class ConnectionAttempt {
void OnConnectionAttemptSucceeded(
std::unique_ptr<AuthenticatedChannel> authenticated_channel) {
if (has_notified_delegate_) {
if (has_notified_delegate_of_success_) {
PA_LOG(ERROR) << "ConnectionAttempt::OnConnectionAttemptSucceeded(): "
<< "Tried to alert delegate of a successful connection, "
<< "but the attempt had already finished.";
return;
}
has_notified_delegate_ = true;
has_notified_delegate_of_success_ = true;
delegate_->OnConnectionAttemptSucceeded(
connection_attempt_details_.GetAssociatedConnectionDetails(),
std::move(authenticated_channel));
}
void OnConnectionAttemptFinishedWithoutConnection() {
if (has_notified_delegate_) {
if (has_notified_delegate_of_success_) {
PA_LOG(ERROR) << "ConnectionAttempt::"
<< "OnConnectionAttemptFinishedWithoutConnection(): "
<< "Tried to alert delegate of a failed connection, "
......@@ -110,7 +111,6 @@ class ConnectionAttempt {
return;
}
has_notified_delegate_ = true;
delegate_->OnConnectionAttemptFinishedWithoutConnection(
connection_attempt_details_);
}
......@@ -119,7 +119,7 @@ class ConnectionAttempt {
ConnectionAttemptDelegate* delegate_;
const ConnectionAttemptDetails connection_attempt_details_;
bool has_notified_delegate_ = false;
bool has_notified_delegate_of_success_ = false;
DISALLOW_COPY_AND_ASSIGN(ConnectionAttempt);
};
......
......@@ -5,22 +5,19 @@
#ifndef CHROMEOS_SERVICES_SECURE_CHANNEL_CONNECTION_ATTEMPT_BASE_H_
#define CHROMEOS_SERVICES_SECURE_CHANNEL_CONNECTION_ATTEMPT_BASE_H_
#include <unordered_map>
#include "base/containers/flat_map.h"
#include "base/logging.h"
#include "base/macros.h"
#include "base/memory/weak_ptr.h"
#include "base/observer_list.h"
#include "base/stl_util.h"
#include "base/threading/thread_task_runner_handle.h"
#include "chromeos/components/proximity_auth/logging/logging.h"
#include "chromeos/services/secure_channel/connect_to_device_operation.h"
#include "chromeos/services/secure_channel/connect_to_device_operation_factory.h"
#include "chromeos/services/secure_channel/connection_attempt.h"
#include "chromeos/services/secure_channel/connection_attempt_details.h"
#include "chromeos/services/secure_channel/connection_details.h"
#include "chromeos/services/secure_channel/pending_connection_request.h"
#include "chromeos/services/secure_channel/pending_connection_request_delegate.h"
#include "chromeos/services/secure_channel/public/cpp/shared/authenticated_channel.h"
#include "chromeos/services/secure_channel/public/cpp/shared/connection_priority.h"
#include "chromeos/services/secure_channel/public/mojom/secure_channel.mojom.h"
......@@ -47,28 +44,29 @@ class AuthenticatedChannel;
// ConnectionAttempt simply starts up a new operation and retries the
// connection.
template <typename FailureDetailType>
class ConnectionAttemptBase : public ConnectionAttempt<FailureDetailType>,
public PendingConnectionRequestDelegate {
class ConnectionAttemptBase : public ConnectionAttempt<FailureDetailType> {
protected:
ConnectionAttemptBase(
std::unique_ptr<ConnectToDeviceOperationFactory<FailureDetailType>>
connect_to_device_operation_factory,
ConnectionAttemptDelegate* delegate,
const ConnectionAttemptDetails& connection_attempt_details,
scoped_refptr<base::TaskRunner> task_runner =
base::ThreadTaskRunnerHandle::Get())
const ConnectionAttemptDetails& connection_attempt_details)
: ConnectionAttempt<FailureDetailType>(delegate,
connection_attempt_details),
connect_to_device_operation_factory_(
std::move(connect_to_device_operation_factory)),
task_runner_(task_runner),
weak_ptr_factory_(this) {}
~ConnectionAttemptBase() override {
if (current_operation_)
current_operation_->Cancel();
if (operation_)
operation_->Cancel();
}
virtual std::unique_ptr<ConnectToDeviceOperation<FailureDetailType>>
CreateConnectToDeviceOperation(
const DeviceIdPair& device_id_pair,
ConnectionPriority connection_priority,
typename ConnectToDeviceOperation<
FailureDetailType>::ConnectionSuccessCallback success_callback,
const typename ConnectToDeviceOperation<
FailureDetailType>::ConnectionFailedCallback& failure_callback) = 0;
private:
// ConnectionAttempt<FailureDetailType>:
void ProcessAddingNewConnectionRequest(
......@@ -88,16 +86,26 @@ class ConnectionAttemptBase : public ConnectionAttempt<FailureDetailType>,
id_to_request_map_[request->GetRequestId()] = std::move(request);
// In the case that this ConnectionAttempt was just created and had not yet
// received a request yet, start up an operation.
// received a request yet, start up its operation.
if (was_empty) {
StartNextConnectToDeviceOperation();
operation_ = CreateConnectToDeviceOperation(
this->connection_attempt_details().device_id_pair(),
GetHighestRemainingConnectionPriority(),
base::BindOnce(
&ConnectionAttemptBase<
FailureDetailType>::OnConnectToDeviceOperationSuccess,
weak_ptr_factory_.GetWeakPtr()),
base::BindRepeating(
&ConnectionAttemptBase<
FailureDetailType>::OnConnectToDeviceOperationFailure,
weak_ptr_factory_.GetWeakPtr()));
return;
}
ConnectionPriority priority_after_add =
GetHighestRemainingConnectionPriority();
if (priority_before_add != priority_after_add)
current_operation_->UpdateConnectionPriority(priority_after_add);
operation_->UpdateConnectionPriority(priority_after_add);
}
std::vector<std::unique_ptr<ClientConnectionParameters>>
......@@ -130,51 +138,21 @@ class ConnectionAttemptBase : public ConnectionAttempt<FailureDetailType>,
ConnectionPriority priority_after_removal =
GetHighestRemainingConnectionPriority();
if (priority_before_removal != priority_after_removal)
current_operation_->UpdateConnectionPriority(priority_after_removal);
operation_->UpdateConnectionPriority(priority_after_removal);
// If there are no longer any active entries, this attempt is finished.
if (id_to_request_map_.empty())
this->OnConnectionAttemptFinishedWithoutConnection();
}
void StartNextConnectToDeviceOperation() {
DCHECK(!current_operation_);
current_operation_ = connect_to_device_operation_factory_->CreateOperation(
this->connection_attempt_details().device_id_pair(),
GetHighestRemainingConnectionPriority(),
base::BindOnce(
&ConnectionAttemptBase<
FailureDetailType>::OnConnectToDeviceOperationSuccess,
weak_ptr_factory_.GetWeakPtr()),
base::BindOnce(
&ConnectionAttemptBase<
FailureDetailType>::OnConnectToDeviceOperationFailure,
weak_ptr_factory_.GetWeakPtr()));
}
void OnConnectToDeviceOperationSuccess(
std::unique_ptr<AuthenticatedChannel> authenticated_channel) {
DCHECK(current_operation_);
current_operation_.reset();
DCHECK(operation_);
operation_.reset();
this->OnConnectionAttemptSucceeded(std::move(authenticated_channel));
}
void OnConnectToDeviceOperationFailure(FailureDetailType failure_detail) {
DCHECK(current_operation_);
current_operation_.reset();
// After all requests have been notified of the failure (below), start a
// retry attempt. If all requests give up without a connection, this
// instance's delegate will be notified and will, in response, delete
// |this|. Thus, the retry attempt is posted as a task using a WeakPtr to
// ensure that a segfault will not occur.
task_runner_->PostTask(
FROM_HERE,
base::BindOnce(
&ConnectionAttemptBase<
FailureDetailType>::StartNextConnectToDeviceOperation,
weak_ptr_factory_.GetWeakPtr()));
for (auto& map_entry : id_to_request_map_)
map_entry.second->HandleConnectionFailure(failure_detail);
}
......@@ -188,17 +166,10 @@ class ConnectionAttemptBase : public ConnectionAttempt<FailureDetailType>,
return highest_priority;
}
std::unique_ptr<ConnectToDeviceOperationFactory<FailureDetailType>>
connect_to_device_operation_factory_;
std::unique_ptr<ConnectToDeviceOperation<FailureDetailType>>
current_operation_;
std::unordered_map<
base::UnguessableToken,
std::unique_ptr<PendingConnectionRequest<FailureDetailType>>,
base::UnguessableTokenHash>
std::unique_ptr<ConnectToDeviceOperation<FailureDetailType>> operation_;
base::flat_map<base::UnguessableToken,
std::unique_ptr<PendingConnectionRequest<FailureDetailType>>>
id_to_request_map_;
scoped_refptr<base::TaskRunner> task_runner_;
base::WeakPtrFactory<ConnectionAttemptBase<FailureDetailType>>
weak_ptr_factory_;
......
......@@ -18,7 +18,6 @@
#include "chromeos/services/secure_channel/device_id_pair.h"
#include "chromeos/services/secure_channel/fake_client_connection_parameters.h"
#include "chromeos/services/secure_channel/fake_connect_to_device_operation.h"
#include "chromeos/services/secure_channel/fake_connect_to_device_operation_factory.h"
#include "chromeos/services/secure_channel/fake_connection_attempt_delegate.h"
#include "chromeos/services/secure_channel/fake_connection_delegate.h"
#include "chromeos/services/secure_channel/fake_pending_connection_request.h"
......@@ -41,20 +40,44 @@ const char kTestLocalDeviceId[] = "testLocalDeviceId";
class TestConnectionAttempt
: public ConnectionAttemptBase<BleInitiatorFailureType> {
public:
TestConnectionAttempt(
std::unique_ptr<FakeConnectToDeviceOperationFactory<
BleInitiatorFailureType>> connect_to_device_operation_factory,
FakeConnectionAttemptDelegate* delegate,
scoped_refptr<base::TestSimpleTaskRunner> task_runner)
TestConnectionAttempt(FakeConnectionAttemptDelegate* delegate)
: ConnectionAttemptBase<BleInitiatorFailureType>(
std::move(connect_to_device_operation_factory),
delegate,
ConnectionAttemptDetails(kTestRemoteDeviceId,
kTestLocalDeviceId,
ConnectionMedium::kBluetoothLowEnergy,
ConnectionRole::kListenerRole),
task_runner) {}
ConnectionRole::kListenerRole)) {}
~TestConnectionAttempt() override = default;
FakeConnectToDeviceOperation<BleInitiatorFailureType>* fake_operation() {
return fake_operation_;
}
private:
// ConnectionAttemptBase<BleInitiatorFailureType>:
std::unique_ptr<ConnectToDeviceOperation<BleInitiatorFailureType>>
CreateConnectToDeviceOperation(
const DeviceIdPair& device_id_pair,
ConnectionPriority connection_priority,
ConnectToDeviceOperation<
BleInitiatorFailureType>::ConnectionSuccessCallback success_callback,
const ConnectToDeviceOperation<BleInitiatorFailureType>::
ConnectionFailedCallback& failure_callback) override {
EXPECT_FALSE(fake_operation_);
auto fake_operation =
std::make_unique<FakeConnectToDeviceOperation<BleInitiatorFailureType>>(
std::move(success_callback), failure_callback, connection_priority);
fake_operation_ = fake_operation.get();
return std::move(fake_operation);
}
FakeConnectToDeviceOperation<BleInitiatorFailureType>* fake_operation_ =
nullptr;
DISALLOW_COPY_AND_ASSIGN(TestConnectionAttempt);
};
} // namespace
......@@ -67,17 +90,10 @@ class SecureChannelConnectionAttemptBaseTest : public testing::Test {
void SetUp() override {
fake_authenticated_channel_ = std::make_unique<FakeAuthenticatedChannel>();
auto fake_operation_factory = std::make_unique<
FakeConnectToDeviceOperationFactory<BleInitiatorFailureType>>();
fake_operation_factory_ = fake_operation_factory.get();
fake_delegate_ = std::make_unique<FakeConnectionAttemptDelegate>();
test_task_runner_ = base::MakeRefCounted<base::TestSimpleTaskRunner>();
connection_attempt_ = std::make_unique<TestConnectionAttempt>(
std::move(fake_operation_factory), fake_delegate_.get(),
test_task_runner_);
connection_attempt_ =
std::make_unique<TestConnectionAttempt>(fake_delegate_.get());
}
void TearDown() override {
......@@ -86,25 +102,24 @@ class SecureChannelConnectionAttemptBaseTest : public testing::Test {
if (is_extract_client_data_test_)
return;
bool should_test_active_operation_canceled = active_operation_ != nullptr;
// If the operation did not complete successfully, the operation should be
// canceled.
bool should_operation_be_canceled_in_destructor =
fake_delegate_->authenticated_channel() == nullptr;
if (should_test_active_operation_canceled) {
EXPECT_FALSE(active_operation_->canceled());
EXPECT_FALSE(was_active_operation_canceled_in_teardown_);
active_operation_->set_destructor_callback(
if (should_operation_be_canceled_in_destructor) {
EXPECT_FALSE(fake_operation()->canceled());
EXPECT_FALSE(was_operation_canceled_in_tear_down_);
fake_operation()->set_cancel_callback(
base::BindOnce(&SecureChannelConnectionAttemptBaseTest::
OnActiveOperationDeletedInTeardown,
OnOperationCanceledInTeardown,
base::Unretained(this)));
}
connection_attempt_.reset();
if (should_test_active_operation_canceled)
EXPECT_TRUE(was_active_operation_canceled_in_teardown_);
// Ensure that running any posted tasks after |connection_attempt_| is
// deleted do not cause segfaults.
test_task_runner_->RunUntilIdle();
if (should_operation_be_canceled_in_destructor)
EXPECT_TRUE(was_operation_canceled_in_tear_down_);
}
FakePendingConnectionRequest<BleInitiatorFailureType>* AddNewRequest(
......@@ -130,24 +145,7 @@ class SecureChannelConnectionAttemptBaseTest : public testing::Test {
EXPECT_EQ(1u, active_requests_.erase(request));
}
FakeConnectToDeviceOperation<BleInitiatorFailureType>*
GetLastCreatedOperation(size_t expected_num_created) {
VerifyNumOperationsCreated(expected_num_created);
active_operation_ = fake_operation_factory_->last_created_instance();
return active_operation_;
}
void VerifyNumOperationsCreated(size_t expected_num_created) {
EXPECT_EQ(expected_num_created,
fake_operation_factory_->num_instances_created());
}
// If |should_run_next_operation| is true, the next operation is started
// after the current one has failed. |should_run_next_operation| should be
// false if the test requires that request failures be processed.
void FailOperation(
FakeConnectToDeviceOperation<BleInitiatorFailureType>* operation,
bool should_run_next_operation = true) {
void FailOperation() {
// Before failing the operation, check to see how many failure details each
// request has been passed.
std::unordered_map<base::UnguessableToken, size_t,
......@@ -158,10 +156,8 @@ class SecureChannelConnectionAttemptBaseTest : public testing::Test {
request->handled_failure_details().size();
}
EXPECT_EQ(active_operation_, operation);
operation->OnFailedConnectionAttempt(
fake_operation()->OnFailedConnectionAttempt(
BleInitiatorFailureType::kAuthenticationError);
active_operation_ = nullptr;
// Now, ensure that each active request had one additional failure detail
// added, and verify that it was kAuthenticationError.
......@@ -171,20 +167,14 @@ class SecureChannelConnectionAttemptBaseTest : public testing::Test {
EXPECT_EQ(BleInitiatorFailureType::kAuthenticationError,
request->handled_failure_details().back());
}
if (should_run_next_operation)
RunNextOperationTask();
}
void FinishOperationSuccessfully(
FakeConnectToDeviceOperation<BleInitiatorFailureType>* operation) {
void FinishOperationSuccessfully() {
EXPECT_TRUE(fake_authenticated_channel_);
auto* fake_authenticated_channel_raw = fake_authenticated_channel_.get();
EXPECT_EQ(active_operation_, operation);
operation->OnSuccessfulConnectionAttempt(
fake_operation()->OnSuccessfulConnectionAttempt(
std::move(fake_authenticated_channel_));
active_operation_ = nullptr;
// |fake_delegate_|'s delegate should have received the
// AuthenticatedChannel.
......@@ -195,12 +185,6 @@ class SecureChannelConnectionAttemptBaseTest : public testing::Test {
fake_delegate_->authenticated_channel());
}
void RunNextOperationTask() {
// This function should only be run if there actually is a pending task.
EXPECT_EQ(1u, test_task_runner_->NumPendingTasks());
test_task_runner_->RunPendingTasks();
}
void VerifyDelegateNotNotified() {
EXPECT_FALSE(fake_delegate_->connection_details());
EXPECT_FALSE(fake_delegate_->connection_attempt_details());
......@@ -222,24 +206,23 @@ class SecureChannelConnectionAttemptBaseTest : public testing::Test {
ExtractClientConnectionParameters(std::move(connection_attempt_));
}
FakeConnectToDeviceOperation<BleInitiatorFailureType>* fake_operation() {
return connection_attempt_->fake_operation();
}
private:
void OnActiveOperationDeletedInTeardown() {
was_active_operation_canceled_in_teardown_ = true;
void OnOperationCanceledInTeardown() {
was_operation_canceled_in_tear_down_ = true;
}
const base::test::ScopedTaskEnvironment scoped_task_environment_;
FakeConnectToDeviceOperationFactory<BleInitiatorFailureType>*
fake_operation_factory_;
std::unique_ptr<FakeConnectionAttemptDelegate> fake_delegate_;
scoped_refptr<base::TestSimpleTaskRunner> test_task_runner_;
std::unique_ptr<FakeAuthenticatedChannel> fake_authenticated_channel_;
std::set<FakePendingConnectionRequest<BleInitiatorFailureType>*>
active_requests_;
FakeConnectToDeviceOperation<BleInitiatorFailureType>* active_operation_ =
nullptr;
bool was_active_operation_canceled_in_teardown_ = false;
bool was_operation_canceled_in_tear_down_ = false;
bool is_extract_client_data_test_ = false;
......@@ -250,22 +233,18 @@ class SecureChannelConnectionAttemptBaseTest : public testing::Test {
TEST_F(SecureChannelConnectionAttemptBaseTest, SingleRequest_Success) {
AddNewRequest(ConnectionPriority::kLow);
FakeConnectToDeviceOperation<BleInitiatorFailureType>* operation =
GetLastCreatedOperation(1u /* expected_num_created */);
EXPECT_EQ(ConnectionPriority::kLow, operation->connection_priority());
FinishOperationSuccessfully(operation);
EXPECT_EQ(ConnectionPriority::kLow, fake_operation()->connection_priority());
FinishOperationSuccessfully();
}
TEST_F(SecureChannelConnectionAttemptBaseTest, SingleRequest_Fails) {
FakePendingConnectionRequest<BleInitiatorFailureType>* request =
AddNewRequest(ConnectionPriority::kLow);
FakeConnectToDeviceOperation<BleInitiatorFailureType>* operation =
GetLastCreatedOperation(1u /* expected_num_created */);
EXPECT_EQ(ConnectionPriority::kLow, operation->connection_priority());
EXPECT_EQ(ConnectionPriority::kLow, fake_operation()->connection_priority());
// Fail the operation; the delegate should not have been notified since no
// request has yet indicated failure.
FailOperation(operation, false /* should_run_next_operation */);
FailOperation();
VerifyDelegateNotNotified();
FinishRequestWithoutConnection(
......@@ -286,49 +265,39 @@ TEST_F(SecureChannelConnectionAttemptBaseTest, SingleRequest_Canceled) {
TEST_F(SecureChannelConnectionAttemptBaseTest, SingleRequest_FailThenSuccess) {
AddNewRequest(ConnectionPriority::kLow);
FakeConnectToDeviceOperation<BleInitiatorFailureType>* operation1 =
GetLastCreatedOperation(1u /* expected_num_created */);
EXPECT_EQ(ConnectionPriority::kLow, operation1->connection_priority());
EXPECT_EQ(ConnectionPriority::kLow, fake_operation()->connection_priority());
// Fail the operation; the delegate should not have been notified since no
// request has yet indicated failure.
FailOperation(operation1);
FailOperation();
VerifyDelegateNotNotified();
FakeConnectToDeviceOperation<BleInitiatorFailureType>* operation2 =
GetLastCreatedOperation(2u /* expected_num_created */);
EXPECT_EQ(ConnectionPriority::kLow, operation2->connection_priority());
FinishOperationSuccessfully(operation2);
EXPECT_EQ(ConnectionPriority::kLow, fake_operation()->connection_priority());
FinishOperationSuccessfully();
}
TEST_F(SecureChannelConnectionAttemptBaseTest, TwoRequests_Success) {
AddNewRequest(ConnectionPriority::kLow);
FakeConnectToDeviceOperation<BleInitiatorFailureType>* operation =
GetLastCreatedOperation(1u /* expected_num_created */);
EXPECT_EQ(ConnectionPriority::kLow, operation->connection_priority());
EXPECT_EQ(ConnectionPriority::kLow, fake_operation()->connection_priority());
// Add a second request; the first operation should still be active.
AddNewRequest(ConnectionPriority::kLow);
VerifyNumOperationsCreated(1u /* expected_num_created */);
FinishOperationSuccessfully(operation);
FinishOperationSuccessfully();
}
TEST_F(SecureChannelConnectionAttemptBaseTest, TwoRequests_Fails) {
FakePendingConnectionRequest<BleInitiatorFailureType>* request1 =
AddNewRequest(ConnectionPriority::kLow);
FakeConnectToDeviceOperation<BleInitiatorFailureType>* operation =
GetLastCreatedOperation(1u /* expected_num_created */);
EXPECT_EQ(ConnectionPriority::kLow, operation->connection_priority());
EXPECT_EQ(ConnectionPriority::kLow, fake_operation()->connection_priority());
// Add a second request; the first operation should still be active.
// Add a second request.
FakePendingConnectionRequest<BleInitiatorFailureType>* request2 =
AddNewRequest(ConnectionPriority::kLow);
VerifyNumOperationsCreated(1u /* expected_num_created */);
// Fail the operation; the delegate should not have been notified since no
// request has yet indicated failure.
FailOperation(operation, false /* should_run_next_operation */);
FailOperation();
VerifyDelegateNotNotified();
// Finish the first request; since a second request remains, the delegate
......@@ -348,10 +317,8 @@ TEST_F(SecureChannelConnectionAttemptBaseTest, TwoRequests_Fails) {
TEST_F(SecureChannelConnectionAttemptBaseTest, TwoRequests_Canceled) {
FakePendingConnectionRequest<BleInitiatorFailureType>* request1 =
AddNewRequest(ConnectionPriority::kLow);
VerifyNumOperationsCreated(1u /* expected_num_created */);
FakePendingConnectionRequest<BleInitiatorFailureType>* request2 =
AddNewRequest(ConnectionPriority::kLow);
VerifyNumOperationsCreated(1u /* expected_num_created */);
FinishRequestWithoutConnection(
request1, PendingConnectionRequestDelegate::FailedConnectionReason::
......@@ -367,23 +334,17 @@ TEST_F(SecureChannelConnectionAttemptBaseTest, TwoRequests_Canceled) {
TEST_F(SecureChannelConnectionAttemptBaseTest, TwoRequests_FailThenSuccess) {
FakePendingConnectionRequest<BleInitiatorFailureType>* request1 =
AddNewRequest(ConnectionPriority::kLow);
FakeConnectToDeviceOperation<BleInitiatorFailureType>* operation1 =
GetLastCreatedOperation(1u /* expected_num_created */);
EXPECT_EQ(ConnectionPriority::kLow, operation1->connection_priority());
EXPECT_EQ(ConnectionPriority::kLow, fake_operation()->connection_priority());
// Fail the operation; a new operation should have been created.
FailOperation(operation1);
// Fail the operation.
FailOperation();
VerifyDelegateNotNotified();
FakeConnectToDeviceOperation<BleInitiatorFailureType>* operation2 =
GetLastCreatedOperation(2u /* expected_num_created */);
EXPECT_EQ(ConnectionPriority::kLow, operation2->connection_priority());
EXPECT_EQ(ConnectionPriority::kLow, fake_operation()->connection_priority());
// Add a second request; this should not result in a new operation.
// Add a second request.
AddNewRequest(ConnectionPriority::kLow);
VerifyNumOperationsCreated(2u /* expected_num_created */);
// Fail the second operation.
FailOperation(operation2, false /* should_run_next_operation */);
FailOperation();
VerifyDelegateNotNotified();
// Simulate the first request finishing due to failures; since a second
......@@ -393,44 +354,40 @@ TEST_F(SecureChannelConnectionAttemptBaseTest, TwoRequests_FailThenSuccess) {
PendingConnectionRequestDelegate::FailedConnectionReason::kRequestFailed);
VerifyDelegateNotNotified();
// Start the next operation running, and simulate it finishing successfully.
RunNextOperationTask();
FakeConnectToDeviceOperation<BleInitiatorFailureType>* operation3 =
GetLastCreatedOperation(3u /* expected_num_created */);
EXPECT_EQ(ConnectionPriority::kLow, operation3->connection_priority());
FinishOperationSuccessfully(operation3);
EXPECT_EQ(ConnectionPriority::kLow, fake_operation()->connection_priority());
FinishOperationSuccessfully();
}
TEST_F(SecureChannelConnectionAttemptBaseTest, ManyRequests_UpdatePriority) {
AddNewRequest(ConnectionPriority::kLow);
FakeConnectToDeviceOperation<BleInitiatorFailureType>* operation =
GetLastCreatedOperation(1u /* expected_num_created */);
EXPECT_EQ(ConnectionPriority::kLow, operation->connection_priority());
EXPECT_EQ(ConnectionPriority::kLow, fake_operation()->connection_priority());
// Add a medium-priority request. This should update the operation's priority
// as well.
FakePendingConnectionRequest<BleInitiatorFailureType>* request2 =
AddNewRequest(ConnectionPriority::kMedium);
EXPECT_EQ(ConnectionPriority::kMedium, operation->connection_priority());
EXPECT_EQ(ConnectionPriority::kMedium,
fake_operation()->connection_priority());
// Add a high-priority request and verify that the operation is updated.
FakePendingConnectionRequest<BleInitiatorFailureType>* request3 =
AddNewRequest(ConnectionPriority::kHigh);
EXPECT_EQ(ConnectionPriority::kHigh, operation->connection_priority());
EXPECT_EQ(ConnectionPriority::kHigh, fake_operation()->connection_priority());
// Remote the high-priority request; the operation should go back to medium.
FinishRequestWithoutConnection(
request3, PendingConnectionRequestDelegate::FailedConnectionReason::
kRequestCanceledByClient);
EXPECT_EQ(ConnectionPriority::kMedium, operation->connection_priority());
EXPECT_EQ(ConnectionPriority::kMedium,
fake_operation()->connection_priority());
// Remote the medium-priority request; the operation should go back to low.
FinishRequestWithoutConnection(
request2, PendingConnectionRequestDelegate::FailedConnectionReason::
kRequestCanceledByClient);
EXPECT_EQ(ConnectionPriority::kLow, operation->connection_priority());
EXPECT_EQ(ConnectionPriority::kLow, fake_operation()->connection_priority());
FinishOperationSuccessfully(operation);
FinishOperationSuccessfully();
}
TEST_F(SecureChannelConnectionAttemptBaseTest,
......
......@@ -42,6 +42,10 @@ class FakeConnectToDeviceOperation
destructor_callback_ = std::move(destructor_callback);
}
void set_cancel_callback(base::OnceClosure cancel_callback) {
cancel_callback_ = std::move(cancel_callback);
}
// Make On{Successful|Failed}ConnectionAttempt() public for testing.
using ConnectToDeviceOperation<
FailureDetailType>::OnSuccessfulConnectionAttempt;
......@@ -49,7 +53,12 @@ class FakeConnectToDeviceOperation
private:
// ConnectToDeviceOperation<FailureDetailType>:
void PerformCancellation() override { canceled_ = true; }
void PerformCancellation() override {
canceled_ = true;
if (cancel_callback_)
std::move(cancel_callback_).Run();
}
void PerformUpdateConnectionPriority(
ConnectionPriority connection_priority) override {
......@@ -59,6 +68,7 @@ class FakeConnectToDeviceOperation
bool canceled_ = false;
base::Optional<ConnectionPriority> updated_priority_;
base::OnceClosure destructor_callback_;
base::OnceClosure cancel_callback_;
DISALLOW_COPY_AND_ASSIGN(FakeConnectToDeviceOperation);
};
......
// Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CHROMEOS_SERVICES_SECURE_CHANNEL_FAKE_CONNECT_TO_DEVICE_OPERATION_FACTORY_H_
#define CHROMEOS_SERVICES_SECURE_CHANNEL_FAKE_CONNECT_TO_DEVICE_OPERATION_FACTORY_H_
#include "base/callback_forward.h"
#include "base/macros.h"
#include "base/optional.h"
#include "chromeos/services/secure_channel/connect_to_device_operation_factory.h"
#include "chromeos/services/secure_channel/device_id_pair.h"
#include "chromeos/services/secure_channel/fake_connect_to_device_operation_factory.h"
#include "chromeos/services/secure_channel/public/cpp/shared/connection_priority.h"
namespace chromeos {
namespace secure_channel {
// Fake ConnectToDeviceOperationFactory implementation.
template <typename FailureDetailType>
class FakeConnectToDeviceOperationFactory
: public ConnectToDeviceOperationFactory<FailureDetailType> {
public:
FakeConnectToDeviceOperationFactory() = default;
~FakeConnectToDeviceOperationFactory() override = default;
FakeConnectToDeviceOperation<FailureDetailType>* last_created_instance() {
return last_created_instance_;
}
const base::Optional<ConnectionPriority>& last_created_priority() const {
return last_created_priority_;
}
size_t num_instances_created() const { return num_instances_created_; }
private:
// ConnectToDeviceOperationFactory<FailureDetailType>:
std::unique_ptr<ConnectToDeviceOperation<FailureDetailType>> CreateOperation(
const DeviceIdPair& device_id_pair,
ConnectionPriority connection_priority,
typename ConnectToDeviceOperation<
FailureDetailType>::ConnectionSuccessCallback success_callback,
typename ConnectToDeviceOperation<FailureDetailType>::
ConnectionFailedCallback failure_callback) override {
auto instance =
std::make_unique<FakeConnectToDeviceOperation<FailureDetailType>>(
std::move(success_callback), std::move(failure_callback),
connection_priority);
last_created_instance_ = instance.get();
++num_instances_created_;
return instance;
}
FakeConnectToDeviceOperation<FailureDetailType>* last_created_instance_ =
nullptr;
base::Optional<ConnectionPriority> last_created_priority_;
size_t num_instances_created_ = 0u;
DISALLOW_COPY_AND_ASSIGN(FakeConnectToDeviceOperationFactory);
};
} // namespace secure_channel
} // namespace chromeos
#endif // CHROMEOS_SERVICES_SECURE_CHANNEL_FAKE_CONNECT_TO_DEVICE_OPERATION_FACTORY_H_
......@@ -58,6 +58,12 @@ class FakeConnectionAttempt : public ConnectionAttempt<FailureDetailType> {
id_to_request_map_[request->GetRequestId()] = std::move(request);
}
// PendingConnectionRequestDelegate:
void OnRequestFinishedWithoutConnection(
const base::UnguessableToken& request_id,
PendingConnectionRequestDelegate::FailedConnectionReason reason)
override {}
std::vector<std::unique_ptr<ClientConnectionParameters>>
ExtractClientConnectionParameters() override {
return std::move(client_data_for_extraction_);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment