1// 2// Copyright (C) 2015 Google, Inc. 3// 4// Licensed under the Apache License, Version 2.0 (the "License"); 5// you may not use this file except in compliance with the License. 6// You may obtain a copy of the License at: 7// 8// http://www.apache.org/licenses/LICENSE-2.0 9// 10// Unless required by applicable law or agreed to in writing, software 11// distributed under the License is distributed on an "AS IS" BASIS, 12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13// See the License for the specific language governing permissions and 14// limitations under the License. 15// 16 17#include <base/macros.h> 18#include <gmock/gmock.h> 19#include <gtest/gtest.h> 20 21#include "service/adapter.h" 22#include "service/hal/fake_bluetooth_gatt_interface.h" 23#include "service/low_energy_client.h" 24#include "stack/include/bt_types.h" 25#include "stack/include/hcidefs.h" 26#include "test/mock_adapter.h" 27 28using ::testing::_; 29using ::testing::Return; 30using ::testing::Pointee; 31using ::testing::DoAll; 32using ::testing::Invoke; 33 34namespace bluetooth { 35namespace { 36 37class MockGattHandler 38 : public hal::FakeBluetoothGattInterface::TestClientHandler { 39 public: 40 MockGattHandler(){}; 41 ~MockGattHandler() override = default; 42 43 MOCK_METHOD1(RegisterClient, bt_status_t(const bt_uuid_t&)); 44 MOCK_METHOD1(UnregisterClient, bt_status_t(int)); 45 MOCK_METHOD4(Connect, bt_status_t(int, const RawAddress&, bool, int)); 46 MOCK_METHOD3(Disconnect, bt_status_t(int, const RawAddress&, int)); 47 48 private: 49 DISALLOW_COPY_AND_ASSIGN(MockGattHandler); 50}; 51 52class TestDelegate : public LowEnergyClient::Delegate { 53 public: 54 TestDelegate() : connection_state_count_(0), last_mtu_(0) {} 55 56 ~TestDelegate() override = default; 57 58 int connection_state_count() const { return connection_state_count_; } 59 60 void OnConnectionState(LowEnergyClient* client, int status, 61 const char* address, bool connected) { 62 ASSERT_TRUE(client); 63 connection_state_count_++; 64 } 65 66 void OnMtuChanged(LowEnergyClient* client, int status, const char* address, 67 int mtu) { 68 ASSERT_TRUE(client); 69 last_mtu_ = mtu; 70 } 71 72 private: 73 int connection_state_count_; 74 75 int last_mtu_; 76 77 DISALLOW_COPY_AND_ASSIGN(TestDelegate); 78}; 79 80class LowEnergyClientTest : public ::testing::Test { 81 public: 82 LowEnergyClientTest() = default; 83 ~LowEnergyClientTest() override = default; 84 85 void SetUp() override { 86 // Only set |mock_handler_| if a test hasn't set it. 87 if (!mock_handler_) mock_handler_.reset(new MockGattHandler()); 88 fake_hal_gatt_iface_ = new hal::FakeBluetoothGattInterface( 89 nullptr, nullptr, 90 std::static_pointer_cast< 91 hal::FakeBluetoothGattInterface::TestClientHandler>(mock_handler_), 92 nullptr); 93 hal::BluetoothGattInterface::InitializeForTesting(fake_hal_gatt_iface_); 94 ble_factory_.reset(new LowEnergyClientFactory(mock_adapter_)); 95 } 96 97 void TearDown() override { 98 ble_factory_.reset(); 99 hal::BluetoothGattInterface::CleanUp(); 100 } 101 102 protected: 103 hal::FakeBluetoothGattInterface* fake_hal_gatt_iface_; 104 testing::MockAdapter mock_adapter_; 105 std::shared_ptr<MockGattHandler> mock_handler_; 106 std::unique_ptr<LowEnergyClientFactory> ble_factory_; 107 108 private: 109 DISALLOW_COPY_AND_ASSIGN(LowEnergyClientTest); 110}; 111 112// Used for tests that operate on a pre-registered client. 113class LowEnergyClientPostRegisterTest : public LowEnergyClientTest { 114 public: 115 LowEnergyClientPostRegisterTest() : next_client_id_(0) {} 116 ~LowEnergyClientPostRegisterTest() override = default; 117 118 void SetUp() override { 119 LowEnergyClientTest::SetUp(); 120 auto callback = [&](std::unique_ptr<LowEnergyClient> client) { 121 le_client_ = std::move(client); 122 }; 123 RegisterTestClient(callback); 124 } 125 126 void TearDown() override { 127 EXPECT_CALL(*mock_handler_, UnregisterClient(_)) 128 .Times(1) 129 .WillOnce(Return(BT_STATUS_SUCCESS)); 130 le_client_.reset(); 131 LowEnergyClientTest::TearDown(); 132 } 133 134 void RegisterTestClient( 135 const std::function<void(std::unique_ptr<LowEnergyClient> client)> 136 callback) { 137 UUID uuid = UUID::GetRandom(); 138 auto api_callback = [&](BLEStatus status, const UUID& in_uuid, 139 std::unique_ptr<BluetoothInstance> in_client) { 140 CHECK(in_uuid == uuid); 141 CHECK(in_client.get()); 142 CHECK(status == BLE_STATUS_SUCCESS); 143 144 callback(std::unique_ptr<LowEnergyClient>( 145 static_cast<LowEnergyClient*>(in_client.release()))); 146 }; 147 148 EXPECT_CALL(*mock_handler_, RegisterClient(_)) 149 .Times(1) 150 .WillOnce(Return(BT_STATUS_SUCCESS)); 151 152 ble_factory_->RegisterInstance(uuid, api_callback); 153 154 bt_uuid_t hal_uuid = uuid.GetBlueDroid(); 155 fake_hal_gatt_iface_->NotifyRegisterClientCallback(0, next_client_id_++, 156 hal_uuid); 157 ::testing::Mock::VerifyAndClearExpectations(mock_handler_.get()); 158 } 159 160 protected: 161 std::unique_ptr<LowEnergyClient> le_client_; 162 163 private: 164 int next_client_id_; 165 166 DISALLOW_COPY_AND_ASSIGN(LowEnergyClientPostRegisterTest); 167}; 168 169TEST_F(LowEnergyClientTest, RegisterInstance) { 170 EXPECT_CALL(*mock_handler_, RegisterClient(_)) 171 .Times(2) 172 .WillOnce(Return(BT_STATUS_FAIL)) 173 .WillOnce(Return(BT_STATUS_SUCCESS)); 174 175 // These will be asynchronously populated with a result when the callback 176 // executes. 177 BLEStatus status = BLE_STATUS_SUCCESS; 178 UUID cb_uuid; 179 std::unique_ptr<LowEnergyClient> client; 180 int callback_count = 0; 181 182 auto callback = [&](BLEStatus in_status, const UUID& uuid, 183 std::unique_ptr<BluetoothInstance> in_client) { 184 status = in_status; 185 cb_uuid = uuid; 186 client = std::unique_ptr<LowEnergyClient>( 187 static_cast<LowEnergyClient*>(in_client.release())); 188 callback_count++; 189 }; 190 191 UUID uuid0 = UUID::GetRandom(); 192 193 // HAL returns failure. 194 EXPECT_FALSE(ble_factory_->RegisterInstance(uuid0, callback)); 195 EXPECT_EQ(0, callback_count); 196 197 // HAL returns success. 198 EXPECT_TRUE(ble_factory_->RegisterInstance(uuid0, callback)); 199 EXPECT_EQ(0, callback_count); 200 201 // Calling twice with the same UUID should fail with no additional call into 202 // the stack. 203 EXPECT_FALSE(ble_factory_->RegisterInstance(uuid0, callback)); 204 205 ::testing::Mock::VerifyAndClearExpectations(mock_handler_.get()); 206 207 // Call with a different UUID while one is pending. 208 UUID uuid1 = UUID::GetRandom(); 209 EXPECT_CALL(*mock_handler_, RegisterClient(_)) 210 .Times(1) 211 .WillOnce(Return(BT_STATUS_SUCCESS)); 212 EXPECT_TRUE(ble_factory_->RegisterInstance(uuid1, callback)); 213 214 // Trigger callback with an unknown UUID. This should get ignored. 215 UUID uuid2 = UUID::GetRandom(); 216 bt_uuid_t hal_uuid = uuid2.GetBlueDroid(); 217 fake_hal_gatt_iface_->NotifyRegisterClientCallback(0, 0, hal_uuid); 218 EXPECT_EQ(0, callback_count); 219 220 // |uuid0| succeeds. 221 int client_if0 = 2; // Pick something that's not 0. 222 hal_uuid = uuid0.GetBlueDroid(); 223 fake_hal_gatt_iface_->NotifyRegisterClientCallback(BT_STATUS_SUCCESS, 224 client_if0, hal_uuid); 225 226 EXPECT_EQ(1, callback_count); 227 ASSERT_TRUE(client.get() != nullptr); // Assert to terminate in case of error 228 EXPECT_EQ(BLE_STATUS_SUCCESS, status); 229 EXPECT_EQ(client_if0, client->GetInstanceId()); 230 EXPECT_EQ(uuid0, client->GetAppIdentifier()); 231 EXPECT_EQ(uuid0, cb_uuid); 232 233 // The client should unregister itself when deleted. 234 EXPECT_CALL(*mock_handler_, UnregisterClient(client_if0)) 235 .Times(1) 236 .WillOnce(Return(BT_STATUS_SUCCESS)); 237 client.reset(); 238 ::testing::Mock::VerifyAndClearExpectations(mock_handler_.get()); 239 240 // |uuid1| fails. 241 int client_if1 = 3; 242 hal_uuid = uuid1.GetBlueDroid(); 243 fake_hal_gatt_iface_->NotifyRegisterClientCallback(BT_STATUS_FAIL, client_if1, 244 hal_uuid); 245 246 EXPECT_EQ(2, callback_count); 247 ASSERT_TRUE(client.get() == nullptr); // Assert to terminate in case of error 248 EXPECT_EQ(BLE_STATUS_FAILURE, status); 249 EXPECT_EQ(uuid1, cb_uuid); 250} 251 252MATCHER_P(BitEq, x, std::string(negation ? "isn't" : "is") + 253 " bitwise equal to " + ::testing::PrintToString(x)) { 254 static_assert(sizeof(x) == sizeof(arg), "Size mismatch"); 255 return std::memcmp(&arg, &x, sizeof(x)) == 0; 256} 257 258TEST_F(LowEnergyClientPostRegisterTest, Connect) { 259 const RawAddress kTestAddress = {{0x01, 0x02, 0x03, 0x0A, 0x0B, 0x0C}}; 260 const char kTestAddressStr[] = "01:02:03:0A:0B:0C"; 261 const bool kTestDirect = false; 262 const int connId = 12; 263 264 TestDelegate delegate; 265 le_client_->SetDelegate(&delegate); 266 267 // TODO(jpawlowski): NotifyConnectCallback should be called after returning 268 // success, fix it when it becomes important. 269 // These should succeed and result in a HAL call 270 EXPECT_CALL(*mock_handler_, 271 Connect(le_client_->GetInstanceId(), BitEq(kTestAddress), 272 kTestDirect, BT_TRANSPORT_LE)) 273 .Times(1) 274 .WillOnce(DoAll(Invoke([&](int client_id, const RawAddress& bd_addr, 275 bool is_direct, int transport) { 276 fake_hal_gatt_iface_->NotifyConnectCallback( 277 connId, BT_STATUS_SUCCESS, client_id, bd_addr); 278 }), 279 Return(BT_STATUS_SUCCESS))); 280 281 EXPECT_TRUE(le_client_->Connect(kTestAddressStr, kTestDirect)); 282 EXPECT_EQ(1, delegate.connection_state_count()); 283 284 // TODO(jpawlowski): same as above 285 // These should succeed and result in a HAL call 286 EXPECT_CALL(*mock_handler_, Disconnect(le_client_->GetInstanceId(), 287 BitEq(kTestAddress), connId)) 288 .Times(1) 289 .WillOnce(DoAll( 290 Invoke([&](int client_id, const RawAddress& bd_addr, int connId) { 291 fake_hal_gatt_iface_->NotifyDisconnectCallback( 292 connId, BT_STATUS_SUCCESS, client_id, bd_addr); 293 }), 294 Return(BT_STATUS_SUCCESS))); 295 296 EXPECT_TRUE(le_client_->Disconnect(kTestAddressStr)); 297 EXPECT_EQ(2, delegate.connection_state_count()); 298 299 le_client_->SetDelegate(nullptr); 300 ::testing::Mock::VerifyAndClearExpectations(mock_handler_.get()); 301} 302 303} // namespace 304} // namespace bluetooth 305