blob: cfd62786a74894413eaef0cfc81f3b936cb9a1fc [file] [log] [blame]
// Copyright 2016 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/error_tolerant_ble_advertisement_impl.h"
#include <memory>
#include "base/bind.h"
#include "base/callback_forward.h"
#include "base/memory/ptr_util.h"
#include "chromeos/services/secure_channel/ble_constants.h"
#include "chromeos/services/secure_channel/fake_ble_synchronizer.h"
#include "device/bluetooth/bluetooth_advertisement.h"
#include "device/bluetooth/test/mock_bluetooth_advertisement.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace chromeos {
namespace secure_channel {
namespace {
const uint8_t kInvertedConnectionFlag = 0x01;
const char kDeviceId[] = "deviceId";
const char kLocalDeviceId[] = "localDeviceId";
std::unique_ptr<DataWithTimestamp> GenerateAdvertisementData() {
return std::make_unique<DataWithTimestamp>("advertisement1", 1000L, 2000L);
}
} // namespace
class SecureChannelErrorTolerantBleAdvertisementImplTest
: public testing::Test {
protected:
SecureChannelErrorTolerantBleAdvertisementImplTest()
: fake_advertisement_data_(GenerateAdvertisementData()) {}
void SetUp() override {
fake_advertisement_ = nullptr;
stopped_callback_called_ = false;
fake_synchronizer_ = std::make_unique<FakeBleSynchronizer>();
advertisement_ =
ErrorTolerantBleAdvertisementImpl::Factory::Get()->BuildInstance(
DeviceIdPair(kDeviceId, kLocalDeviceId),
std::make_unique<DataWithTimestamp>(*fake_advertisement_data_),
fake_synchronizer_.get());
VerifyServiceDataMatches(0u /* command_index */);
}
void VerifyServiceDataMatches(size_t command_index) {
device::BluetoothAdvertisement::Data& data =
fake_synchronizer_->GetAdvertisementData(command_index);
// First, verify that the service UUID list is correct.
std::unique_ptr<device::BluetoothAdvertisement::UUIDList> service_uuids =
data.service_uuids();
EXPECT_EQ(1u, service_uuids->size());
EXPECT_EQ(kAdvertisingServiceUuid, service_uuids->at(0));
// Then, verify that the service data is correct.
std::unique_ptr<device::BluetoothAdvertisement::ServiceData> service_data =
data.service_data();
EXPECT_EQ(1u, service_data->size());
ErrorTolerantBleAdvertisementImpl* derived_type =
static_cast<ErrorTolerantBleAdvertisementImpl*>(advertisement_.get());
std::vector<uint8_t> service_data_from_args =
service_data->at(kAdvertisingServiceUuid);
EXPECT_EQ(service_data_from_args.size(),
derived_type->advertisement_data().data.size() + 1);
EXPECT_FALSE(memcmp(derived_type->advertisement_data().data.data(),
service_data_from_args.data(), service_data->size()));
EXPECT_EQ(kInvertedConnectionFlag, service_data_from_args.back());
}
void InvokeRegisterCallback(bool success, size_t command_index) {
if (success) {
fake_advertisement_ = new device::MockBluetoothAdvertisement();
fake_synchronizer_->GetRegisterCallback(command_index)
.Run(base::WrapRefCounted(fake_advertisement_));
return;
}
fake_synchronizer_->GetRegisterErrorCallback(command_index)
.Run(device::BluetoothAdvertisement::ErrorCode::
INVALID_ADVERTISEMENT_ERROR_CODE);
}
void ReleaseAdvertisement() {
ErrorTolerantBleAdvertisementImpl* derived_type =
static_cast<ErrorTolerantBleAdvertisementImpl*>(advertisement_.get());
derived_type->AdvertisementReleased(fake_advertisement_);
}
void CallStop() {
advertisement_->Stop(base::Bind(
&SecureChannelErrorTolerantBleAdvertisementImplTest::OnStopped,
base::Unretained(this)));
}
void OnStopped() { stopped_callback_called_ = true; }
void InvokeUnregisterCallback(bool success, size_t command_index) {
if (success) {
fake_synchronizer_->GetUnregisterCallback(command_index).Run();
return;
}
fake_synchronizer_->GetUnregisterErrorCallback(command_index)
.Run(device::BluetoothAdvertisement::ErrorCode::
INVALID_ADVERTISEMENT_ERROR_CODE);
}
const std::unique_ptr<DataWithTimestamp> fake_advertisement_data_;
std::unique_ptr<FakeBleSynchronizer> fake_synchronizer_;
device::MockBluetoothAdvertisement* fake_advertisement_;
bool stopped_callback_called_;
std::unique_ptr<ErrorTolerantBleAdvertisement> advertisement_;
private:
DISALLOW_COPY_AND_ASSIGN(SecureChannelErrorTolerantBleAdvertisementImplTest);
};
TEST_F(SecureChannelErrorTolerantBleAdvertisementImplTest,
TestRegisterAndStop_Success) {
InvokeRegisterCallback(true /* success */, 0u /* command_index */);
EXPECT_FALSE(advertisement_->HasBeenStopped());
EXPECT_FALSE(stopped_callback_called_);
CallStop();
EXPECT_TRUE(advertisement_->HasBeenStopped());
EXPECT_FALSE(stopped_callback_called_);
InvokeUnregisterCallback(true /* success */, 1u /* command_index */);
EXPECT_TRUE(advertisement_->HasBeenStopped());
EXPECT_TRUE(stopped_callback_called_);
}
TEST_F(SecureChannelErrorTolerantBleAdvertisementImplTest,
TestStoppedBeforeStarted) {
// Before the advertisement has been started successfully.
CallStop();
EXPECT_TRUE(advertisement_->HasBeenStopped());
EXPECT_FALSE(stopped_callback_called_);
// Now, finish registering the advertisement.
InvokeRegisterCallback(true /* success */, 0u /* command_index */);
EXPECT_TRUE(advertisement_->HasBeenStopped());
EXPECT_FALSE(stopped_callback_called_);
// Successfully unregister.
InvokeUnregisterCallback(true /* success */, 1u /* command_index */);
EXPECT_TRUE(advertisement_->HasBeenStopped());
EXPECT_TRUE(stopped_callback_called_);
}
TEST_F(SecureChannelErrorTolerantBleAdvertisementImplTest,
TestRegisterAndStop_Released) {
InvokeRegisterCallback(true /* success */, 0u /* command_index */);
EXPECT_FALSE(advertisement_->HasBeenStopped());
EXPECT_FALSE(stopped_callback_called_);
// Simulate that advertisement being released. A new one should be created.
ReleaseAdvertisement();
VerifyServiceDataMatches(1u /* command_index */);
InvokeRegisterCallback(true /* success */, 1u /* command_index */);
EXPECT_FALSE(advertisement_->HasBeenStopped());
EXPECT_FALSE(stopped_callback_called_);
CallStop();
EXPECT_TRUE(advertisement_->HasBeenStopped());
EXPECT_FALSE(stopped_callback_called_);
InvokeUnregisterCallback(true /* success */, 2u /* command_index */);
EXPECT_TRUE(advertisement_->HasBeenStopped());
EXPECT_TRUE(stopped_callback_called_);
}
TEST_F(SecureChannelErrorTolerantBleAdvertisementImplTest,
TestRegisterAndStop_Errors) {
// Fail to register.
InvokeRegisterCallback(false /* success */, 0u /* command_index */);
EXPECT_FALSE(advertisement_->HasBeenStopped());
EXPECT_FALSE(stopped_callback_called_);
// Fail to register again.
InvokeRegisterCallback(false /* success */, 1u /* command_index */);
EXPECT_FALSE(advertisement_->HasBeenStopped());
EXPECT_FALSE(stopped_callback_called_);
// This time, succeed.
InvokeRegisterCallback(true /* success */, 2u /* command_index */);
EXPECT_FALSE(advertisement_->HasBeenStopped());
EXPECT_FALSE(stopped_callback_called_);
CallStop();
EXPECT_TRUE(advertisement_->HasBeenStopped());
EXPECT_FALSE(stopped_callback_called_);
// Fail to unregister.
InvokeUnregisterCallback(false /* success */, 3u /* command_index */);
EXPECT_FALSE(stopped_callback_called_);
// Fail to unregister again.
InvokeUnregisterCallback(false /* success */, 4u /* command_index */);
EXPECT_FALSE(stopped_callback_called_);
// This time, succeed.
InvokeUnregisterCallback(true /* success */, 5u /* command_index */);
EXPECT_TRUE(stopped_callback_called_);
}
} // namespace secure_channel
} // namespace chromeos