blob: 1fc2393ffe88d9092eba1322014f7cb88b461a8c [file] [log] [blame]
Arman Ugurayc2fc0f22015-09-03 15:09:41 -07001//
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
Jakub Pawlowski60b0e8f2016-01-12 13:51:35 -080021#include "service/adapter.h"
Arman Ugurayc2fc0f22015-09-03 15:09:41 -070022#include "service/hal/fake_bluetooth_gatt_interface.h"
23#include "service/low_energy_client.h"
Arman Uguray12338402015-09-16 18:00:05 -070024#include "stack/include/bt_types.h"
25#include "stack/include/hcidefs.h"
Jakub Pawlowski60b0e8f2016-01-12 13:51:35 -080026#include "test/mock_adapter.h"
Arman Ugurayc2fc0f22015-09-03 15:09:41 -070027
28using ::testing::_;
29using ::testing::Return;
Jakub Pawlowskia6372e92016-01-19 16:42:37 -080030using ::testing::Pointee;
31using ::testing::DoAll;
32using ::testing::Invoke;
Arman Ugurayc2fc0f22015-09-03 15:09:41 -070033
34namespace bluetooth {
35namespace {
36
Arman Uguray9e520532015-09-22 14:12:50 -070037class MockGattHandler
38 : public hal::FakeBluetoothGattInterface::TestClientHandler {
Arman Ugurayc2fc0f22015-09-03 15:09:41 -070039 public:
Jakub Pawlowskic3f6a512016-10-27 11:49:40 -070040 MockGattHandler() {};
Arman Ugurayc2fc0f22015-09-03 15:09:41 -070041 ~MockGattHandler() override = default;
42
43 MOCK_METHOD1(RegisterClient, bt_status_t(bt_uuid_t*));
44 MOCK_METHOD1(UnregisterClient, bt_status_t(int));
Jakub Pawlowskice021dd2016-01-19 16:35:20 -080045 MOCK_METHOD4(Connect, bt_status_t(int , const bt_bdaddr_t *, bool, int));
46 MOCK_METHOD3(Disconnect, bt_status_t(int , const bt_bdaddr_t *, int));
Arman Ugurayc2fc0f22015-09-03 15:09:41 -070047
48 private:
49 DISALLOW_COPY_AND_ASSIGN(MockGattHandler);
50};
51
Arman Uguray82ea72f2015-12-02 17:29:27 -080052class TestDelegate : public LowEnergyClient::Delegate {
53 public:
Jakub Pawlowskic3f6a512016-10-27 11:49:40 -070054 TestDelegate() : connection_state_count_(0), last_mtu_(0) {
Arman Uguray82ea72f2015-12-02 17:29:27 -080055 }
56
57 ~TestDelegate() override = default;
58
Jakub Pawlowskia6372e92016-01-19 16:42:37 -080059 int connection_state_count() const { return connection_state_count_; }
60
61 void OnConnectionState(LowEnergyClient* client, int status,
62 const char* address, bool connected) {
63 ASSERT_TRUE(client);
64 connection_state_count_++;
65 }
66
Jakub Pawlowskia6551072016-01-26 12:58:47 -080067 void OnMtuChanged(LowEnergyClient* client, int status, const char* address,
68 int mtu) {
69 ASSERT_TRUE(client);
70 last_mtu_ = mtu;
71 }
72
Arman Uguray82ea72f2015-12-02 17:29:27 -080073 private:
Jakub Pawlowskia6372e92016-01-19 16:42:37 -080074 int connection_state_count_;
75
Jakub Pawlowskia6551072016-01-26 12:58:47 -080076 int last_mtu_;
77
Arman Uguray82ea72f2015-12-02 17:29:27 -080078 DISALLOW_COPY_AND_ASSIGN(TestDelegate);
79};
80
Arman Ugurayc2fc0f22015-09-03 15:09:41 -070081class LowEnergyClientTest : public ::testing::Test {
82 public:
83 LowEnergyClientTest() = default;
84 ~LowEnergyClientTest() override = default;
85
86 void SetUp() override {
Ajay Panickerff651b72015-09-30 15:49:47 -070087 // Only set |mock_handler_| if a test hasn't set it.
88 if (!mock_handler_)
89 mock_handler_.reset(new MockGattHandler());
Arman Ugurayc2fc0f22015-09-03 15:09:41 -070090 fake_hal_gatt_iface_ = new hal::FakeBluetoothGattInterface(
Jakub Pawlowski67d5a252016-07-13 11:55:16 -070091 nullptr,
Jakub Pawlowskic3f6a512016-10-27 11:49:40 -070092 nullptr,
Arman Uguray9e520532015-09-22 14:12:50 -070093 std::static_pointer_cast<
94 hal::FakeBluetoothGattInterface::TestClientHandler>(mock_handler_),
95 nullptr);
Arman Ugurayc2fc0f22015-09-03 15:09:41 -070096 hal::BluetoothGattInterface::InitializeForTesting(fake_hal_gatt_iface_);
Jakub Pawlowski60b0e8f2016-01-12 13:51:35 -080097 ble_factory_.reset(new LowEnergyClientFactory(mock_adapter_));
Arman Ugurayc2fc0f22015-09-03 15:09:41 -070098 }
99
100 void TearDown() override {
101 ble_factory_.reset();
102 hal::BluetoothGattInterface::CleanUp();
103 }
104
105 protected:
106 hal::FakeBluetoothGattInterface* fake_hal_gatt_iface_;
Jakub Pawlowski60b0e8f2016-01-12 13:51:35 -0800107 testing::MockAdapter mock_adapter_;
Arman Ugurayc2fc0f22015-09-03 15:09:41 -0700108 std::shared_ptr<MockGattHandler> mock_handler_;
109 std::unique_ptr<LowEnergyClientFactory> ble_factory_;
110
111 private:
112 DISALLOW_COPY_AND_ASSIGN(LowEnergyClientTest);
113};
114
Arman Uguray12338402015-09-16 18:00:05 -0700115// Used for tests that operate on a pre-registered client.
116class LowEnergyClientPostRegisterTest : public LowEnergyClientTest {
117 public:
Jakub Pawlowski53cfa7c2016-01-13 15:41:06 -0800118 LowEnergyClientPostRegisterTest() : next_client_id_(0) {
119 }
Arman Uguray12338402015-09-16 18:00:05 -0700120 ~LowEnergyClientPostRegisterTest() override = default;
121
122 void SetUp() override {
123 LowEnergyClientTest::SetUp();
Jakub Pawlowski53cfa7c2016-01-13 15:41:06 -0800124 auto callback = [&](std::unique_ptr<LowEnergyClient> client) {
125 le_client_ = std::move(client);
Arman Uguray12338402015-09-16 18:00:05 -0700126 };
Jakub Pawlowski53cfa7c2016-01-13 15:41:06 -0800127 RegisterTestClient(callback);
Arman Uguray12338402015-09-16 18:00:05 -0700128 }
129
130 void TearDown() override {
Arman Uguray12338402015-09-16 18:00:05 -0700131 EXPECT_CALL(*mock_handler_, UnregisterClient(_))
132 .Times(1)
133 .WillOnce(Return(BT_STATUS_SUCCESS));
134 le_client_.reset();
135 LowEnergyClientTest::TearDown();
136 }
137
Jakub Pawlowski53cfa7c2016-01-13 15:41:06 -0800138 void RegisterTestClient(
Jakub Pawlowski67d5a252016-07-13 11:55:16 -0700139 const std::function<void(std::unique_ptr<LowEnergyClient> client)>
Jakub Pawlowski53cfa7c2016-01-13 15:41:06 -0800140 callback) {
141 UUID uuid = UUID::GetRandom();
142 auto api_callback = [&](BLEStatus status, const UUID& in_uuid,
143 std::unique_ptr<BluetoothInstance> in_client) {
144 CHECK(in_uuid == uuid);
145 CHECK(in_client.get());
146 CHECK(status == BLE_STATUS_SUCCESS);
147
148 callback(std::unique_ptr<LowEnergyClient>(
149 static_cast<LowEnergyClient*>(in_client.release())));
150 };
151
152 EXPECT_CALL(*mock_handler_, RegisterClient(_))
153 .Times(1)
154 .WillOnce(Return(BT_STATUS_SUCCESS));
155
156 ble_factory_->RegisterInstance(uuid, api_callback);
157
158 bt_uuid_t hal_uuid = uuid.GetBlueDroid();
159 fake_hal_gatt_iface_->NotifyRegisterClientCallback(
160 0, next_client_id_++, hal_uuid);
161 ::testing::Mock::VerifyAndClearExpectations(mock_handler_.get());
162 }
163
Arman Uguray12338402015-09-16 18:00:05 -0700164 protected:
165 std::unique_ptr<LowEnergyClient> le_client_;
166
167 private:
Jakub Pawlowski53cfa7c2016-01-13 15:41:06 -0800168 int next_client_id_;
169
Arman Uguray12338402015-09-16 18:00:05 -0700170 DISALLOW_COPY_AND_ASSIGN(LowEnergyClientPostRegisterTest);
171};
172
Arman Uguraybb18c412015-11-12 13:44:31 -0800173TEST_F(LowEnergyClientTest, RegisterInstance) {
Arman Ugurayc2fc0f22015-09-03 15:09:41 -0700174 EXPECT_CALL(*mock_handler_, RegisterClient(_))
175 .Times(2)
176 .WillOnce(Return(BT_STATUS_FAIL))
177 .WillOnce(Return(BT_STATUS_SUCCESS));
178
179 // These will be asynchronously populated with a result when the callback
180 // executes.
181 BLEStatus status = BLE_STATUS_SUCCESS;
182 UUID cb_uuid;
183 std::unique_ptr<LowEnergyClient> client;
184 int callback_count = 0;
185
Arman Uguray08f80eb2015-09-21 11:17:07 -0700186 auto callback = [&](BLEStatus in_status, const UUID& uuid,
Arman Uguraybb18c412015-11-12 13:44:31 -0800187 std::unique_ptr<BluetoothInstance> in_client) {
Arman Ugurayc2fc0f22015-09-03 15:09:41 -0700188 status = in_status;
189 cb_uuid = uuid;
Arman Uguray08f80eb2015-09-21 11:17:07 -0700190 client = std::unique_ptr<LowEnergyClient>(
191 static_cast<LowEnergyClient*>(in_client.release()));
Arman Ugurayc2fc0f22015-09-03 15:09:41 -0700192 callback_count++;
193 };
194
195 UUID uuid0 = UUID::GetRandom();
196
197 // HAL returns failure.
Arman Uguraybb18c412015-11-12 13:44:31 -0800198 EXPECT_FALSE(ble_factory_->RegisterInstance(uuid0, callback));
Arman Ugurayc2fc0f22015-09-03 15:09:41 -0700199 EXPECT_EQ(0, callback_count);
200
201 // HAL returns success.
Arman Uguraybb18c412015-11-12 13:44:31 -0800202 EXPECT_TRUE(ble_factory_->RegisterInstance(uuid0, callback));
Arman Ugurayc2fc0f22015-09-03 15:09:41 -0700203 EXPECT_EQ(0, callback_count);
204
205 // Calling twice with the same UUID should fail with no additional call into
206 // the stack.
Arman Uguraybb18c412015-11-12 13:44:31 -0800207 EXPECT_FALSE(ble_factory_->RegisterInstance(uuid0, callback));
Arman Ugurayc2fc0f22015-09-03 15:09:41 -0700208
Jakub Pawlowski60b0e8f2016-01-12 13:51:35 -0800209 ::testing::Mock::VerifyAndClearExpectations(mock_handler_.get());
Arman Ugurayc2fc0f22015-09-03 15:09:41 -0700210
211 // Call with a different UUID while one is pending.
212 UUID uuid1 = UUID::GetRandom();
213 EXPECT_CALL(*mock_handler_, RegisterClient(_))
214 .Times(1)
215 .WillOnce(Return(BT_STATUS_SUCCESS));
Arman Uguraybb18c412015-11-12 13:44:31 -0800216 EXPECT_TRUE(ble_factory_->RegisterInstance(uuid1, callback));
Arman Ugurayc2fc0f22015-09-03 15:09:41 -0700217
218 // Trigger callback with an unknown UUID. This should get ignored.
219 UUID uuid2 = UUID::GetRandom();
220 bt_uuid_t hal_uuid = uuid2.GetBlueDroid();
221 fake_hal_gatt_iface_->NotifyRegisterClientCallback(0, 0, hal_uuid);
222 EXPECT_EQ(0, callback_count);
223
224 // |uuid0| succeeds.
225 int client_if0 = 2; // Pick something that's not 0.
226 hal_uuid = uuid0.GetBlueDroid();
227 fake_hal_gatt_iface_->NotifyRegisterClientCallback(
228 BT_STATUS_SUCCESS, client_if0, hal_uuid);
229
230 EXPECT_EQ(1, callback_count);
231 ASSERT_TRUE(client.get() != nullptr); // Assert to terminate in case of error
232 EXPECT_EQ(BLE_STATUS_SUCCESS, status);
Arman Uguraybb18c412015-11-12 13:44:31 -0800233 EXPECT_EQ(client_if0, client->GetInstanceId());
Arman Uguray08f80eb2015-09-21 11:17:07 -0700234 EXPECT_EQ(uuid0, client->GetAppIdentifier());
Arman Ugurayc2fc0f22015-09-03 15:09:41 -0700235 EXPECT_EQ(uuid0, cb_uuid);
236
237 // The client should unregister itself when deleted.
238 EXPECT_CALL(*mock_handler_, UnregisterClient(client_if0))
239 .Times(1)
240 .WillOnce(Return(BT_STATUS_SUCCESS));
241 client.reset();
Jakub Pawlowski60b0e8f2016-01-12 13:51:35 -0800242 ::testing::Mock::VerifyAndClearExpectations(mock_handler_.get());
Arman Ugurayc2fc0f22015-09-03 15:09:41 -0700243
244 // |uuid1| fails.
245 int client_if1 = 3;
246 hal_uuid = uuid1.GetBlueDroid();
247 fake_hal_gatt_iface_->NotifyRegisterClientCallback(
248 BT_STATUS_FAIL, client_if1, hal_uuid);
249
250 EXPECT_EQ(2, callback_count);
251 ASSERT_TRUE(client.get() == nullptr); // Assert to terminate in case of error
252 EXPECT_EQ(BLE_STATUS_FAILURE, status);
253 EXPECT_EQ(uuid1, cb_uuid);
Arman Uguray12338402015-09-16 18:00:05 -0700254}
Arman Ugurayc2fc0f22015-09-03 15:09:41 -0700255
Jakub Pawlowskia6372e92016-01-19 16:42:37 -0800256MATCHER_P(BitEq, x, std::string(negation ? "isn't" : "is") +
257 " bitwise equal to " + ::testing::PrintToString(x)) {
258 static_assert(sizeof(x) == sizeof(arg), "Size mismatch");
259 return std::memcmp(&arg, &x, sizeof(x)) == 0;
260}
261
262TEST_F(LowEnergyClientPostRegisterTest, Connect) {
263 const bt_bdaddr_t kTestAddress = {
264 { 0x01, 0x02, 0x03, 0x0A, 0x0B, 0x0C }
265 };
266 const char kTestAddressStr[] = "01:02:03:0A:0B:0C";
267 const bool kTestDirect = false;
268 const int connId = 12;
269
270 TestDelegate delegate;
271 le_client_->SetDelegate(&delegate);
272
273 // TODO(jpawlowski): NotifyConnectCallback should be called after returning
274 // success, fix it when it becomes important.
275 // These should succeed and result in a HAL call
276 EXPECT_CALL(*mock_handler_, Connect(le_client_->GetInstanceId(),
277 Pointee(BitEq(kTestAddress)), kTestDirect, BT_TRANSPORT_LE))
278 .Times(1)
279 .WillOnce(DoAll(
280 Invoke([&](int client_id, const bt_bdaddr_t *bd_addr, bool is_direct,
281 int transport){
282 fake_hal_gatt_iface_->NotifyConnectCallback(connId, BT_STATUS_SUCCESS,
283 client_id, *bd_addr);
284 }),
285 Return(BT_STATUS_SUCCESS)));
286
287 EXPECT_TRUE(le_client_->Connect(kTestAddressStr, kTestDirect));
288 EXPECT_EQ(1, delegate.connection_state_count());
289
290 // TODO(jpawlowski): same as above
291 // These should succeed and result in a HAL call
292 EXPECT_CALL(*mock_handler_, Disconnect(le_client_->GetInstanceId(),
293 Pointee(BitEq(kTestAddress)), connId))
294 .Times(1)
295 .WillOnce(DoAll(
296 Invoke([&](int client_id, const bt_bdaddr_t *bd_addr, int connId){
297 fake_hal_gatt_iface_->NotifyDisconnectCallback(connId,
298 BT_STATUS_SUCCESS,
299 client_id, *bd_addr);
300 }),
301 Return(BT_STATUS_SUCCESS)));
302
303 EXPECT_TRUE(le_client_->Disconnect(kTestAddressStr));
304 EXPECT_EQ(2, delegate.connection_state_count());
305
306 le_client_->SetDelegate(nullptr);
307 ::testing::Mock::VerifyAndClearExpectations(mock_handler_.get());
308}
309
310
Arman Ugurayc2fc0f22015-09-03 15:09:41 -0700311} // namespace
312} // namespace bluetooth