1 // Copyright 2016 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "device/bluetooth/device.h"
6
7 #include <memory>
8 #include <string>
9 #include <utility>
10
11 #include "base/bind.h"
12 #include "base/logging.h"
13 #include "base/memory/ptr_util.h"
14 #include "base/memory/weak_ptr.h"
15 #include "base/run_loop.h"
16 #include "base/test/task_environment.h"
17 #include "device/bluetooth/test/mock_bluetooth_adapter.h"
18 #include "device/bluetooth/test/mock_bluetooth_device.h"
19 #include "device/bluetooth/test/mock_bluetooth_gatt_characteristic.h"
20 #include "device/bluetooth/test/mock_bluetooth_gatt_connection.h"
21 #include "device/bluetooth/test/mock_bluetooth_gatt_service.h"
22 #include "mojo/public/cpp/bindings/remote.h"
23 #include "testing/gtest/include/gtest/gtest.h"
24
25 using ::testing::Return;
26
27 namespace bluetooth {
28
29 using NiceMockBluetoothAdapter =
30 testing::NiceMock<device::MockBluetoothAdapter>;
31 using NiceMockBluetoothDevice = testing::NiceMock<device::MockBluetoothDevice>;
32 using NiceMockBluetoothGattService =
33 testing::NiceMock<device::MockBluetoothGattService>;
34 using NiceMockBluetoothGattCharacteristic =
35 testing::NiceMock<device::MockBluetoothGattCharacteristic>;
36 using NiceMockBluetoothGattConnection =
37 testing::NiceMock<device::MockBluetoothGattConnection>;
38
39 using Properties = device::BluetoothGattCharacteristic::Properties;
40 using Property = device::BluetoothGattCharacteristic::Property;
41
42 namespace {
43 const char kTestLeDeviceAddress0[] = "11:22:33:44:55:66";
44 const char kTestLeDeviceName0[] = "Test LE Device 0";
45
46 const char kTestServiceId0[] = "service_id0";
47 const char kTestServiceUuid0[] = "1234";
48
49 const char kTestServiceId1[] = "service_id1";
50 const char kTestServiceUuid1[] = "5678";
51
52 const char kTestCharacteristicId0[] = "characteristic_id0";
53 const char kTestCharacteristicUuid0[] = "1234";
54
55 const char kTestCharacteristicId1[] = "characteristic_id1";
56 const char kTestCharacteristicUuid1[] = "5678";
57
58 const char kTestCharacteristicId2[] = "characteristic_id2";
59 const char kTestCharacteristicUuid2[] = "9012";
60
61 const Properties kReadWriteProperties =
62 Property::PROPERTY_READ | Property::PROPERTY_WRITE;
63 const Properties kAllProperties = Property::NUM_PROPERTY - 1;
64
65 class BluetoothInterfaceDeviceTest : public testing::Test {
66 public:
67 enum class Call { EXPECTED, NOT_EXPECTED };
68
BluetoothInterfaceDeviceTest()69 BluetoothInterfaceDeviceTest()
70 : adapter_(new NiceMockBluetoothAdapter),
71 device_(adapter_.get(),
72 0,
73 kTestLeDeviceName0,
74 kTestLeDeviceAddress0,
75 false,
76 true) {
77 ON_CALL(*adapter_, GetDevice(kTestLeDeviceAddress0))
78 .WillByDefault(Return(&device_));
79
80 auto service1 = std::make_unique<NiceMockBluetoothGattService>(
81 &device_, kTestServiceId0, device::BluetoothUUID(kTestServiceUuid0),
82 true /* is_primary */, false /* is_local */);
83
84 auto characteristic1 =
85 std::make_unique<NiceMockBluetoothGattCharacteristic>(
86 service1.get(), kTestCharacteristicId0,
87 device::BluetoothUUID(kTestCharacteristicUuid0),
88 false /* is_local */, kReadWriteProperties, 0 /* permissions */);
89
90 auto characteristic2 =
91 std::make_unique<NiceMockBluetoothGattCharacteristic>(
92 service1.get(), kTestCharacteristicId1,
93 device::BluetoothUUID(kTestCharacteristicUuid1),
94 false /* is_local */, kReadWriteProperties, 0 /* permissions */);
95
96 service1->AddMockCharacteristic(std::move(characteristic1));
97 service1->AddMockCharacteristic(std::move(characteristic2));
98
99 auto service2 = std::make_unique<NiceMockBluetoothGattService>(
100 &device_, kTestServiceId1, device::BluetoothUUID(kTestServiceUuid1),
101 true /* is_primary */, false /* is_local */);
102
103 auto characteristic3 =
104 std::make_unique<NiceMockBluetoothGattCharacteristic>(
105 service2.get(), kTestCharacteristicId2,
106 device::BluetoothUUID(kTestCharacteristicUuid2),
107 false /* is_local */, kAllProperties, 0 /* permissions */);
108
109 service2->AddMockCharacteristic(std::move(characteristic3));
110
111 device_.AddMockService(std::move(service1));
112 device_.AddMockService(std::move(service2));
113
114 EXPECT_CALL(device_, GetGattServices())
115 .WillRepeatedly(
116 Invoke(&device_, &device::MockBluetoothDevice::GetMockServices));
117
118 EXPECT_CALL(device_, GetGattService(testing::_))
119 .WillRepeatedly(
120 Invoke(&device_, &device::MockBluetoothDevice::GetMockService));
121
122 auto connection = std::make_unique<NiceMockBluetoothGattConnection>(
123 adapter_, device_.GetAddress());
124
125 Device::Create(adapter_, std::move(connection),
126 proxy_.BindNewPipeAndPassReceiver());
127
128 proxy_.set_disconnect_handler(
129 base::BindOnce(&BluetoothInterfaceDeviceTest::OnConnectionError,
130 weak_factory_.GetWeakPtr()));
131 }
132
TearDown()133 void TearDown() override {
134 EXPECT_EQ(expected_success_callback_calls_, actual_success_callback_calls_);
135 EXPECT_EQ(message_pipe_closed_, expect_device_service_deleted_);
136 proxy_.reset();
137 base::RunLoop().RunUntilIdle();
138 }
139
140 protected:
OnConnectionError()141 void OnConnectionError() { message_pipe_closed_ = true; }
142
SimulateGattServicesDiscovered()143 void SimulateGattServicesDiscovered() {
144 for (auto& observer : adapter_->GetObservers())
145 observer.GattServicesDiscovered(adapter_.get(), &device_);
146 }
147
SimulateDeviceChanged()148 void SimulateDeviceChanged() {
149 for (auto& observer : adapter_->GetObservers())
150 observer.DeviceChanged(adapter_.get(), &device_);
151 }
152
CheckGetServicesCountImpl(Call expected,size_t expected_service_count,int num_of_preceding_calls,std::vector<mojom::ServiceInfoPtr> services)153 void CheckGetServicesCountImpl(Call expected,
154 size_t expected_service_count,
155 int num_of_preceding_calls,
156 std::vector<mojom::ServiceInfoPtr> services) {
157 EXPECT_EQ(num_of_preceding_calls, actual_callback_count_);
158 ++actual_callback_count_;
159
160 if (expected == Call::EXPECTED)
161 ++actual_success_callback_calls_;
162
163 EXPECT_EQ(expected_service_count, services.size());
164 }
165
CheckGetServicesCount(Call expected)166 Device::GetServicesCallback CheckGetServicesCount(Call expected) {
167 if (expected == Call::EXPECTED)
168 ++expected_success_callback_calls_;
169
170 return base::BindOnce(
171 &BluetoothInterfaceDeviceTest::CheckGetServicesCountImpl,
172 weak_factory_.GetWeakPtr(), expected, 2 /* expected_service_count */,
173 expected_callback_count_++);
174 }
175
176 scoped_refptr<NiceMockBluetoothAdapter> adapter_;
177 NiceMockBluetoothDevice device_;
178 base::test::SingleThreadTaskEnvironment task_environment_;
179 mojo::Remote<mojom::Device> proxy_;
180
181 bool message_pipe_closed_ = false;
182 bool expect_device_service_deleted_ = false;
183 int expected_success_callback_calls_ = 0;
184 int actual_success_callback_calls_ = 0;
185 int actual_callback_count_ = 0;
186 int expected_callback_count_ = 0;
187
188 base::WeakPtrFactory<BluetoothInterfaceDeviceTest> weak_factory_{this};
189 };
190 } // namespace
191
TEST_F(BluetoothInterfaceDeviceTest,GetServices)192 TEST_F(BluetoothInterfaceDeviceTest, GetServices) {
193 EXPECT_CALL(device_, IsGattServicesDiscoveryComplete())
194 .WillRepeatedly(Return(true));
195
196 proxy_->GetServices(CheckGetServicesCount(Call::EXPECTED));
197
198 base::RunLoop().RunUntilIdle();
199 }
200
TEST_F(BluetoothInterfaceDeviceTest,GetServicesNotDiscovered)201 TEST_F(BluetoothInterfaceDeviceTest, GetServicesNotDiscovered) {
202 EXPECT_CALL(device_, IsGattServicesDiscoveryComplete())
203 .WillOnce(Return(false))
204 .WillOnce(Return(false))
205 .WillRepeatedly(Return(true));
206
207 // Client: Sends multiple requests for services.
208 proxy_->GetServices(CheckGetServicesCount(Call::EXPECTED));
209 proxy_->GetServices(CheckGetServicesCount(Call::EXPECTED));
210
211 base::RunLoop().RunUntilIdle();
212
213 SimulateGattServicesDiscovered();
214
215 // No more GetServices calls will complete.
216 SimulateGattServicesDiscovered();
217
218 base::RunLoop().RunUntilIdle();
219
220 // Client: Sends more requests which run immediately.
221 proxy_->GetServices(CheckGetServicesCount(Call::EXPECTED));
222 proxy_->GetServices(CheckGetServicesCount(Call::EXPECTED));
223
224 base::RunLoop().RunUntilIdle();
225
226 // No more GetServices calls will complete.
227 SimulateGattServicesDiscovered();
228
229 // Wait for message pipe to process error.
230 base::RunLoop().RunUntilIdle();
231 }
232
TEST_F(BluetoothInterfaceDeviceTest,GetServicesLostConnectionWithPendingRequests)233 TEST_F(BluetoothInterfaceDeviceTest,
234 GetServicesLostConnectionWithPendingRequests) {
235 EXPECT_CALL(device_, IsGattServicesDiscoveryComplete())
236 .WillRepeatedly(Return(false));
237 // Client: Sends multiple requests for services.
238 proxy_->GetServices(CheckGetServicesCount(Call::NOT_EXPECTED));
239 proxy_->GetServices(CheckGetServicesCount(Call::NOT_EXPECTED));
240 EXPECT_EQ(0, actual_callback_count_);
241
242 // Simulate connection loss.
243 device_.SetConnected(false);
244 SimulateDeviceChanged();
245 expect_device_service_deleted_ = true;
246
247 // Wait for message pipe to process error.
248 base::RunLoop().RunUntilIdle();
249 }
250
TEST_F(BluetoothInterfaceDeviceTest,GetServicesForcedDisconnectionWithPendingRequests)251 TEST_F(BluetoothInterfaceDeviceTest,
252 GetServicesForcedDisconnectionWithPendingRequests) {
253 EXPECT_CALL(device_, IsGattServicesDiscoveryComplete())
254 .WillRepeatedly(Return(false));
255
256 // Client: Sends multiple requests for services.
257 proxy_->GetServices(CheckGetServicesCount(Call::NOT_EXPECTED));
258 proxy_->GetServices(CheckGetServicesCount(Call::NOT_EXPECTED));
259 EXPECT_EQ(0, actual_callback_count_);
260
261 // Simulate connection loss.
262 proxy_->Disconnect();
263 expect_device_service_deleted_ = true;
264
265 // Wait for message pipe to process error.
266 base::RunLoop().RunUntilIdle();
267 }
268 } // namespace bluetooth
269