blob: e2168a067050aac69f56fb913d338ad899110b1c [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/components/tether/error_tolerant_ble_advertisement_impl.h"
#include "base/bind.h"
#include "base/callback_forward.h"
#include "base/memory/ptr_util.h"
#include "chromeos/components/tether/ble_constants.h"
#include "chromeos/components/tether/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 tether {
namespace {
const uint8_t kInvertedConnectionFlag = 0x01;
const char kDeviceId[] = "deviceId";
std::unique_ptr<cryptauth::DataWithTimestamp> GenerateAdvertisementData() {
return base::MakeUnique<cryptauth::DataWithTimestamp>("advertisement1", 1000L,
2000L);
}
} // namespace
class ErrorTolerantBleAdvertisementImplTest : public testing::Test {
protected:
ErrorTolerantBleAdvertisementImplTest()
: fake_advertisement_data_(GenerateAdvertisementData()) {}
void SetUp() override {
fake_advertisement_ = nullptr;
stopped_callback_called_ = false;
fake_synchronizer_ = base::MakeUnique<FakeBleSynchronizer>();
advertisement_ = base::MakeUnique<ErrorTolerantBleAdvertisementImpl>(
kDeviceId,
base::MakeUnique<cryptauth::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());
std::vector<uint8_t> service_data_from_args =
service_data->at(kAdvertisingServiceUuid);
EXPECT_EQ(service_data_from_args.size(),
advertisement_->advertisement_data().data.size() + 1);
EXPECT_FALSE(memcmp(advertisement_->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() {
advertisement_->AdvertisementReleased(fake_advertisement_);
}
void CallStop() {
advertisement_->Stop(
base::Bind(&ErrorTolerantBleAdvertisementImplTest::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<cryptauth::DataWithTimestamp> fake_advertisement_data_;
std::unique_ptr<FakeBleSynchronizer> fake_synchronizer_;
device::MockBluetoothAdvertisement* fake_advertisement_;
bool stopped_callback_called_;
std::unique_ptr<ErrorTolerantBleAdvertisementImpl> advertisement_;
private:
DISALLOW_COPY_AND_ASSIGN(ErrorTolerantBleAdvertisementImplTest);
};
TEST_F(ErrorTolerantBleAdvertisementImplTest, 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(ErrorTolerantBleAdvertisementImplTest, 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(ErrorTolerantBleAdvertisementImplTest, 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(ErrorTolerantBleAdvertisementImplTest, 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 tether
} // namespace chromeos