1 //
2 // Copyright 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
28 using ::testing::_;
29 using ::testing::Return;
30 using ::testing::Pointee;
31 using ::testing::DoAll;
32 using ::testing::Invoke;
33
34 namespace bluetooth {
35 namespace {
36
37 class MockGattHandler
38 : public hal::FakeBluetoothGattInterface::TestClientHandler {
39 public:
MockGattHandler()40 MockGattHandler(){};
41 ~MockGattHandler() override = default;
42
43 MOCK_METHOD1(RegisterClient, bt_status_t(const bluetooth::Uuid&));
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
52 class TestDelegate : public LowEnergyClient::Delegate {
53 public:
TestDelegate()54 TestDelegate() : connection_state_count_(0), last_mtu_(0) {}
55
56 ~TestDelegate() override = default;
57
connection_state_count() const58 int connection_state_count() const { return connection_state_count_; }
59
OnConnectionState(LowEnergyClient * client,int status,const char * address,bool connected)60 void OnConnectionState(LowEnergyClient* client, int status,
61 const char* address, bool connected) override {
62 ASSERT_TRUE(client);
63 connection_state_count_++;
64 }
65
OnMtuChanged(LowEnergyClient * client,int status,const char * address,int mtu)66 void OnMtuChanged(LowEnergyClient* client, int status, const char* address,
67 int mtu) override {
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
80 class LowEnergyClientTest : public ::testing::Test {
81 public:
82 LowEnergyClientTest() = default;
83 ~LowEnergyClientTest() override = default;
84
SetUp()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
TearDown()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.
113 class LowEnergyClientPostRegisterTest : public LowEnergyClientTest {
114 public:
LowEnergyClientPostRegisterTest()115 LowEnergyClientPostRegisterTest() : next_client_id_(0) {}
116 ~LowEnergyClientPostRegisterTest() override = default;
117
SetUp()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
TearDown()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
RegisterTestClient(const std::function<void (std::unique_ptr<LowEnergyClient> client)> callback)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 fake_hal_gatt_iface_->NotifyRegisterClientCallback(0, next_client_id_++,
155 uuid);
156 ::testing::Mock::VerifyAndClearExpectations(mock_handler_.get());
157 }
158
159 protected:
160 std::unique_ptr<LowEnergyClient> le_client_;
161
162 private:
163 int next_client_id_;
164
165 DISALLOW_COPY_AND_ASSIGN(LowEnergyClientPostRegisterTest);
166 };
167
TEST_F(LowEnergyClientTest,RegisterInstance)168 TEST_F(LowEnergyClientTest, RegisterInstance) {
169 EXPECT_CALL(*mock_handler_, RegisterClient(_))
170 .Times(2)
171 .WillOnce(Return(BT_STATUS_FAIL))
172 .WillOnce(Return(BT_STATUS_SUCCESS));
173
174 // These will be asynchronously populated with a result when the callback
175 // executes.
176 BLEStatus status = BLE_STATUS_SUCCESS;
177 Uuid cb_uuid;
178 std::unique_ptr<LowEnergyClient> client;
179 int callback_count = 0;
180
181 auto callback = [&](BLEStatus in_status, const Uuid& uuid,
182 std::unique_ptr<BluetoothInstance> in_client) {
183 status = in_status;
184 cb_uuid = uuid;
185 client = std::unique_ptr<LowEnergyClient>(
186 static_cast<LowEnergyClient*>(in_client.release()));
187 callback_count++;
188 };
189
190 Uuid uuid0 = Uuid::GetRandom();
191
192 // HAL returns failure.
193 EXPECT_FALSE(ble_factory_->RegisterInstance(uuid0, callback));
194 EXPECT_EQ(0, callback_count);
195
196 // HAL returns success.
197 EXPECT_TRUE(ble_factory_->RegisterInstance(uuid0, callback));
198 EXPECT_EQ(0, callback_count);
199
200 // Calling twice with the same Uuid should fail with no additional call into
201 // the stack.
202 EXPECT_FALSE(ble_factory_->RegisterInstance(uuid0, callback));
203
204 ::testing::Mock::VerifyAndClearExpectations(mock_handler_.get());
205
206 // Call with a different Uuid while one is pending.
207 Uuid uuid1 = Uuid::GetRandom();
208 EXPECT_CALL(*mock_handler_, RegisterClient(_))
209 .Times(1)
210 .WillOnce(Return(BT_STATUS_SUCCESS));
211 EXPECT_TRUE(ble_factory_->RegisterInstance(uuid1, callback));
212
213 // Trigger callback with an unknown Uuid. This should get ignored.
214 Uuid uuid2 = Uuid::GetRandom();
215 fake_hal_gatt_iface_->NotifyRegisterClientCallback(0, 0, uuid2);
216 EXPECT_EQ(0, callback_count);
217
218 // |uuid0| succeeds.
219 int client_if0 = 2; // Pick something that's not 0.
220 fake_hal_gatt_iface_->NotifyRegisterClientCallback(BT_STATUS_SUCCESS,
221 client_if0, uuid0);
222
223 EXPECT_EQ(1, callback_count);
224 ASSERT_TRUE(client.get() != nullptr); // Assert to terminate in case of error
225 EXPECT_EQ(BLE_STATUS_SUCCESS, status);
226 EXPECT_EQ(client_if0, client->GetInstanceId());
227 EXPECT_EQ(uuid0, client->GetAppIdentifier());
228 EXPECT_EQ(uuid0, cb_uuid);
229
230 // The client should unregister itself when deleted.
231 EXPECT_CALL(*mock_handler_, UnregisterClient(client_if0))
232 .Times(1)
233 .WillOnce(Return(BT_STATUS_SUCCESS));
234 client.reset();
235 ::testing::Mock::VerifyAndClearExpectations(mock_handler_.get());
236
237 // |uuid1| fails.
238 int client_if1 = 3;
239 fake_hal_gatt_iface_->NotifyRegisterClientCallback(BT_STATUS_FAIL, client_if1,
240 uuid1);
241
242 EXPECT_EQ(2, callback_count);
243 ASSERT_TRUE(client.get() == nullptr); // Assert to terminate in case of error
244 EXPECT_EQ(BLE_STATUS_FAILURE, status);
245 EXPECT_EQ(uuid1, cb_uuid);
246 }
247
248 MATCHER_P(BitEq, x, std::string(negation ? "isn't" : "is") +
249 " bitwise equal to " + ::testing::PrintToString(x)) {
250 static_assert(sizeof(x) == sizeof(arg), "Size mismatch");
251 return std::memcmp(&arg, &x, sizeof(x)) == 0;
252 }
253
TEST_F(LowEnergyClientPostRegisterTest,Connect)254 TEST_F(LowEnergyClientPostRegisterTest, Connect) {
255 const RawAddress kTestAddress = {{0x01, 0x02, 0x03, 0x0A, 0x0B, 0x0C}};
256 const char kTestAddressStr[] = "01:02:03:0A:0B:0C";
257 const bool kTestDirect = false;
258 const int connId = 12;
259
260 TestDelegate delegate;
261 le_client_->SetDelegate(&delegate);
262
263 // TODO(jpawlowski): NotifyConnectCallback should be called after returning
264 // success, fix it when it becomes important.
265 // These should succeed and result in a HAL call
266 EXPECT_CALL(*mock_handler_,
267 Connect(le_client_->GetInstanceId(), BitEq(kTestAddress),
268 kTestDirect, BT_TRANSPORT_LE))
269 .Times(1)
270 .WillOnce(DoAll(Invoke([&](int client_id, const RawAddress& bd_addr,
271 bool is_direct, int transport) {
272 fake_hal_gatt_iface_->NotifyConnectCallback(
273 connId, BT_STATUS_SUCCESS, client_id, bd_addr);
274 }),
275 Return(BT_STATUS_SUCCESS)));
276
277 EXPECT_TRUE(le_client_->Connect(kTestAddressStr, kTestDirect));
278 EXPECT_EQ(1, delegate.connection_state_count());
279
280 // TODO(jpawlowski): same as above
281 // These should succeed and result in a HAL call
282 EXPECT_CALL(*mock_handler_, Disconnect(le_client_->GetInstanceId(),
283 BitEq(kTestAddress), connId))
284 .Times(1)
285 .WillOnce(DoAll(
286 Invoke([&](int client_id, const RawAddress& bd_addr, int connId) {
287 fake_hal_gatt_iface_->NotifyDisconnectCallback(
288 connId, BT_STATUS_SUCCESS, client_id, bd_addr);
289 }),
290 Return(BT_STATUS_SUCCESS)));
291
292 EXPECT_TRUE(le_client_->Disconnect(kTestAddressStr));
293 EXPECT_EQ(2, delegate.connection_state_count());
294
295 le_client_->SetDelegate(nullptr);
296 ::testing::Mock::VerifyAndClearExpectations(mock_handler_.get());
297 }
298
299 } // namespace
300 } // namespace bluetooth
301