OLD | NEW |
| (Empty) |
1 // Copyright 2014 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 "base/memory/scoped_vector.h" | |
6 #include "base/message_loop/message_loop.h" | |
7 #include "base/run_loop.h" | |
8 #include "dbus/object_path.h" | |
9 #include "device/bluetooth/bluetooth_adapter.h" | |
10 #include "device/bluetooth/bluetooth_adapter_factory.h" | |
11 #include "device/bluetooth/bluetooth_device.h" | |
12 #include "device/bluetooth/bluetooth_gatt_characteristic.h" | |
13 #include "device/bluetooth/bluetooth_gatt_connection.h" | |
14 #include "device/bluetooth/bluetooth_gatt_descriptor.h" | |
15 #include "device/bluetooth/bluetooth_gatt_notify_session.h" | |
16 #include "device/bluetooth/bluetooth_gatt_service.h" | |
17 #include "device/bluetooth/bluetooth_uuid.h" | |
18 #include "device/bluetooth/dbus/bluez_dbus_manager.h" | |
19 #include "device/bluetooth/dbus/fake_bluetooth_adapter_client.h" | |
20 #include "device/bluetooth/dbus/fake_bluetooth_agent_manager_client.h" | |
21 #include "device/bluetooth/dbus/fake_bluetooth_device_client.h" | |
22 #include "device/bluetooth/dbus/fake_bluetooth_gatt_characteristic_client.h" | |
23 #include "device/bluetooth/dbus/fake_bluetooth_gatt_descriptor_client.h" | |
24 #include "device/bluetooth/dbus/fake_bluetooth_gatt_service_client.h" | |
25 #include "device/bluetooth/dbus/fake_bluetooth_input_client.h" | |
26 #include "device/bluetooth/test/test_bluetooth_adapter_observer.h" | |
27 #include "testing/gtest/include/gtest/gtest.h" | |
28 | |
29 using device::BluetoothAdapter; | |
30 using device::BluetoothDevice; | |
31 using device::BluetoothGattCharacteristic; | |
32 using device::BluetoothGattConnection; | |
33 using device::BluetoothGattDescriptor; | |
34 using device::BluetoothGattService; | |
35 using device::BluetoothGattNotifySession; | |
36 using device::BluetoothUUID; | |
37 using device::TestBluetoothAdapterObserver; | |
38 | |
39 namespace chromeos { | |
40 | |
41 namespace { | |
42 | |
43 const BluetoothUUID kHeartRateMeasurementUUID( | |
44 bluez::FakeBluetoothGattCharacteristicClient::kHeartRateMeasurementUUID); | |
45 const BluetoothUUID kBodySensorLocationUUID( | |
46 bluez::FakeBluetoothGattCharacteristicClient::kBodySensorLocationUUID); | |
47 const BluetoothUUID kHeartRateControlPointUUID( | |
48 bluez::FakeBluetoothGattCharacteristicClient::kHeartRateControlPointUUID); | |
49 | |
50 // Compares GATT characteristic/descriptor values. Returns true, if the values | |
51 // are equal. | |
52 bool ValuesEqual(const std::vector<uint8>& value0, | |
53 const std::vector<uint8>& value1) { | |
54 if (value0.size() != value1.size()) | |
55 return false; | |
56 for (size_t i = 0; i < value0.size(); ++i) | |
57 if (value0[i] != value1[i]) | |
58 return false; | |
59 return true; | |
60 } | |
61 | |
62 } // namespace | |
63 | |
64 class BluetoothGattChromeOSTest : public testing::Test { | |
65 public: | |
66 BluetoothGattChromeOSTest() | |
67 : fake_bluetooth_gatt_service_client_(NULL), | |
68 success_callback_count_(0), | |
69 error_callback_count_(0) { | |
70 } | |
71 | |
72 void SetUp() override { | |
73 scoped_ptr<bluez::BluezDBusManagerSetter> dbus_setter = | |
74 bluez::BluezDBusManager::GetSetterForTesting(); | |
75 fake_bluetooth_device_client_ = new bluez::FakeBluetoothDeviceClient; | |
76 fake_bluetooth_gatt_service_client_ = | |
77 new bluez::FakeBluetoothGattServiceClient; | |
78 fake_bluetooth_gatt_characteristic_client_ = | |
79 new bluez::FakeBluetoothGattCharacteristicClient; | |
80 fake_bluetooth_gatt_descriptor_client_ = | |
81 new bluez::FakeBluetoothGattDescriptorClient; | |
82 dbus_setter->SetBluetoothDeviceClient( | |
83 scoped_ptr<bluez::BluetoothDeviceClient>( | |
84 fake_bluetooth_device_client_)); | |
85 dbus_setter->SetBluetoothGattServiceClient( | |
86 scoped_ptr<bluez::BluetoothGattServiceClient>( | |
87 fake_bluetooth_gatt_service_client_)); | |
88 dbus_setter->SetBluetoothGattCharacteristicClient( | |
89 scoped_ptr<bluez::BluetoothGattCharacteristicClient>( | |
90 fake_bluetooth_gatt_characteristic_client_)); | |
91 dbus_setter->SetBluetoothGattDescriptorClient( | |
92 scoped_ptr<bluez::BluetoothGattDescriptorClient>( | |
93 fake_bluetooth_gatt_descriptor_client_)); | |
94 dbus_setter->SetBluetoothAdapterClient( | |
95 scoped_ptr<bluez::BluetoothAdapterClient>( | |
96 new bluez::FakeBluetoothAdapterClient)); | |
97 dbus_setter->SetBluetoothInputClient( | |
98 scoped_ptr<bluez::BluetoothInputClient>( | |
99 new bluez::FakeBluetoothInputClient)); | |
100 dbus_setter->SetBluetoothAgentManagerClient( | |
101 scoped_ptr<bluez::BluetoothAgentManagerClient>( | |
102 new bluez::FakeBluetoothAgentManagerClient)); | |
103 | |
104 GetAdapter(); | |
105 | |
106 adapter_->SetPowered( | |
107 true, | |
108 base::Bind(&base::DoNothing), | |
109 base::Bind(&base::DoNothing)); | |
110 ASSERT_TRUE(adapter_->IsPowered()); | |
111 } | |
112 | |
113 void TearDown() override { | |
114 adapter_ = NULL; | |
115 update_sessions_.clear(); | |
116 gatt_conn_.reset(); | |
117 bluez::BluezDBusManager::Shutdown(); | |
118 } | |
119 | |
120 void GetAdapter() { | |
121 device::BluetoothAdapterFactory::GetAdapter( | |
122 base::Bind(&BluetoothGattChromeOSTest::AdapterCallback, | |
123 base::Unretained(this))); | |
124 ASSERT_TRUE(adapter_.get() != NULL); | |
125 ASSERT_TRUE(adapter_->IsInitialized()); | |
126 ASSERT_TRUE(adapter_->IsPresent()); | |
127 } | |
128 | |
129 void AdapterCallback(scoped_refptr<BluetoothAdapter> adapter) { | |
130 adapter_ = adapter; | |
131 } | |
132 | |
133 void SuccessCallback() { | |
134 ++success_callback_count_; | |
135 } | |
136 | |
137 void ValueCallback(const std::vector<uint8>& value) { | |
138 ++success_callback_count_; | |
139 last_read_value_ = value; | |
140 } | |
141 | |
142 void GattConnectionCallback(scoped_ptr<BluetoothGattConnection> conn) { | |
143 ++success_callback_count_; | |
144 gatt_conn_ = conn.Pass(); | |
145 } | |
146 | |
147 void NotifySessionCallback(scoped_ptr<BluetoothGattNotifySession> session) { | |
148 ++success_callback_count_; | |
149 update_sessions_.push_back(session.release()); | |
150 QuitMessageLoop(); | |
151 } | |
152 | |
153 void ServiceErrorCallback(BluetoothGattService::GattErrorCode err) { | |
154 ++error_callback_count_; | |
155 last_service_error_ = err; | |
156 } | |
157 | |
158 void ErrorCallback() { | |
159 ++error_callback_count_; | |
160 } | |
161 | |
162 void DBusErrorCallback(const std::string& error_name, | |
163 const std::string& error_message) { | |
164 ++error_callback_count_; | |
165 } | |
166 | |
167 void ConnectErrorCallback(BluetoothDevice::ConnectErrorCode error) { | |
168 ++error_callback_count_; | |
169 } | |
170 | |
171 protected: | |
172 void QuitMessageLoop() { | |
173 if (base::MessageLoop::current() && | |
174 base::MessageLoop::current()->is_running()) | |
175 base::MessageLoop::current()->QuitWhenIdle(); | |
176 } | |
177 | |
178 base::MessageLoop message_loop_; | |
179 | |
180 bluez::FakeBluetoothDeviceClient* fake_bluetooth_device_client_; | |
181 bluez::FakeBluetoothGattServiceClient* fake_bluetooth_gatt_service_client_; | |
182 bluez::FakeBluetoothGattCharacteristicClient* | |
183 fake_bluetooth_gatt_characteristic_client_; | |
184 bluez::FakeBluetoothGattDescriptorClient* | |
185 fake_bluetooth_gatt_descriptor_client_; | |
186 scoped_ptr<device::BluetoothGattConnection> gatt_conn_; | |
187 ScopedVector<BluetoothGattNotifySession> update_sessions_; | |
188 scoped_refptr<BluetoothAdapter> adapter_; | |
189 | |
190 int success_callback_count_; | |
191 int error_callback_count_; | |
192 std::vector<uint8> last_read_value_; | |
193 BluetoothGattService::GattErrorCode last_service_error_; | |
194 }; | |
195 | |
196 TEST_F(BluetoothGattChromeOSTest, GattConnection) { | |
197 fake_bluetooth_device_client_->CreateDevice( | |
198 dbus::ObjectPath(bluez::FakeBluetoothAdapterClient::kAdapterPath), | |
199 dbus::ObjectPath(bluez::FakeBluetoothDeviceClient::kLowEnergyPath)); | |
200 BluetoothDevice* device = | |
201 adapter_->GetDevice(bluez::FakeBluetoothDeviceClient::kLowEnergyAddress); | |
202 ASSERT_TRUE(device); | |
203 ASSERT_FALSE(device->IsConnected()); | |
204 ASSERT_FALSE(gatt_conn_.get()); | |
205 ASSERT_EQ(0, success_callback_count_); | |
206 ASSERT_EQ(0, error_callback_count_); | |
207 | |
208 device->CreateGattConnection( | |
209 base::Bind(&BluetoothGattChromeOSTest::GattConnectionCallback, | |
210 base::Unretained(this)), | |
211 base::Bind(&BluetoothGattChromeOSTest::ConnectErrorCallback, | |
212 base::Unretained(this))); | |
213 | |
214 EXPECT_EQ(1, success_callback_count_); | |
215 EXPECT_EQ(0, error_callback_count_); | |
216 EXPECT_TRUE(device->IsConnected()); | |
217 ASSERT_TRUE(gatt_conn_.get()); | |
218 EXPECT_TRUE(gatt_conn_->IsConnected()); | |
219 EXPECT_EQ(bluez::FakeBluetoothDeviceClient::kLowEnergyAddress, | |
220 gatt_conn_->GetDeviceAddress()); | |
221 | |
222 gatt_conn_->Disconnect(); | |
223 EXPECT_TRUE(device->IsConnected()); | |
224 EXPECT_FALSE(gatt_conn_->IsConnected()); | |
225 | |
226 device->CreateGattConnection( | |
227 base::Bind(&BluetoothGattChromeOSTest::GattConnectionCallback, | |
228 base::Unretained(this)), | |
229 base::Bind(&BluetoothGattChromeOSTest::ConnectErrorCallback, | |
230 base::Unretained(this))); | |
231 | |
232 EXPECT_EQ(2, success_callback_count_); | |
233 EXPECT_EQ(0, error_callback_count_); | |
234 EXPECT_TRUE(device->IsConnected()); | |
235 ASSERT_TRUE(gatt_conn_.get()); | |
236 EXPECT_TRUE(gatt_conn_->IsConnected()); | |
237 | |
238 device->Disconnect( | |
239 base::Bind(&BluetoothGattChromeOSTest::SuccessCallback, | |
240 base::Unretained(this)), | |
241 base::Bind(&BluetoothGattChromeOSTest::ErrorCallback, | |
242 base::Unretained(this))); | |
243 | |
244 EXPECT_EQ(3, success_callback_count_); | |
245 EXPECT_EQ(0, error_callback_count_); | |
246 ASSERT_TRUE(gatt_conn_.get()); | |
247 EXPECT_FALSE(gatt_conn_->IsConnected()); | |
248 | |
249 device->CreateGattConnection( | |
250 base::Bind(&BluetoothGattChromeOSTest::GattConnectionCallback, | |
251 base::Unretained(this)), | |
252 base::Bind(&BluetoothGattChromeOSTest::ConnectErrorCallback, | |
253 base::Unretained(this))); | |
254 | |
255 EXPECT_EQ(4, success_callback_count_); | |
256 EXPECT_EQ(0, error_callback_count_); | |
257 EXPECT_TRUE(device->IsConnected()); | |
258 EXPECT_TRUE(gatt_conn_->IsConnected()); | |
259 | |
260 fake_bluetooth_device_client_->RemoveDevice( | |
261 dbus::ObjectPath(bluez::FakeBluetoothAdapterClient::kAdapterPath), | |
262 dbus::ObjectPath(bluez::FakeBluetoothDeviceClient::kLowEnergyPath)); | |
263 ASSERT_TRUE(gatt_conn_.get()); | |
264 EXPECT_FALSE(gatt_conn_->IsConnected()); | |
265 } | |
266 | |
267 TEST_F(BluetoothGattChromeOSTest, GattServiceAddedAndRemoved) { | |
268 // Create a fake LE device. We store the device pointer here because this is a | |
269 // test. It's unsafe to do this in production as the device might get deleted. | |
270 fake_bluetooth_device_client_->CreateDevice( | |
271 dbus::ObjectPath(bluez::FakeBluetoothAdapterClient::kAdapterPath), | |
272 dbus::ObjectPath(bluez::FakeBluetoothDeviceClient::kLowEnergyPath)); | |
273 BluetoothDevice* device = | |
274 adapter_->GetDevice(bluez::FakeBluetoothDeviceClient::kLowEnergyAddress); | |
275 ASSERT_TRUE(device); | |
276 | |
277 TestBluetoothAdapterObserver observer(adapter_); | |
278 | |
279 EXPECT_EQ(0, observer.gatt_service_added_count()); | |
280 EXPECT_EQ(0, observer.gatt_service_removed_count()); | |
281 EXPECT_TRUE(observer.last_gatt_service_id().empty()); | |
282 EXPECT_FALSE(observer.last_gatt_service_uuid().IsValid()); | |
283 EXPECT_TRUE(device->GetGattServices().empty()); | |
284 | |
285 // Expose the fake Heart Rate Service. | |
286 fake_bluetooth_gatt_service_client_->ExposeHeartRateService( | |
287 dbus::ObjectPath(bluez::FakeBluetoothDeviceClient::kLowEnergyPath)); | |
288 EXPECT_EQ(1, observer.gatt_service_added_count()); | |
289 EXPECT_EQ(0, observer.gatt_service_removed_count()); | |
290 EXPECT_FALSE(observer.last_gatt_service_id().empty()); | |
291 EXPECT_EQ(1U, device->GetGattServices().size()); | |
292 EXPECT_EQ(BluetoothUUID( | |
293 bluez::FakeBluetoothGattServiceClient::kHeartRateServiceUUID), | |
294 observer.last_gatt_service_uuid()); | |
295 | |
296 BluetoothGattService* service = | |
297 device->GetGattService(observer.last_gatt_service_id()); | |
298 EXPECT_FALSE(service->IsLocal()); | |
299 EXPECT_TRUE(service->IsPrimary()); | |
300 EXPECT_EQ(service, device->GetGattServices()[0]); | |
301 EXPECT_EQ(service, device->GetGattService(service->GetIdentifier())); | |
302 | |
303 EXPECT_EQ(observer.last_gatt_service_uuid(), service->GetUUID()); | |
304 | |
305 // Hide the service. | |
306 observer.last_gatt_service_uuid() = BluetoothUUID(); | |
307 observer.last_gatt_service_id().clear(); | |
308 fake_bluetooth_gatt_service_client_->HideHeartRateService(); | |
309 | |
310 EXPECT_EQ(1, observer.gatt_service_added_count()); | |
311 EXPECT_EQ(1, observer.gatt_service_removed_count()); | |
312 EXPECT_FALSE(observer.last_gatt_service_id().empty()); | |
313 EXPECT_TRUE(device->GetGattServices().empty()); | |
314 EXPECT_EQ(BluetoothUUID( | |
315 bluez::FakeBluetoothGattServiceClient::kHeartRateServiceUUID), | |
316 observer.last_gatt_service_uuid()); | |
317 | |
318 EXPECT_EQ(NULL, device->GetGattService(observer.last_gatt_service_id())); | |
319 | |
320 // Expose the service again. | |
321 observer.last_gatt_service_uuid() = BluetoothUUID(); | |
322 observer.last_gatt_service_id().clear(); | |
323 fake_bluetooth_gatt_service_client_->ExposeHeartRateService( | |
324 dbus::ObjectPath(bluez::FakeBluetoothDeviceClient::kLowEnergyPath)); | |
325 EXPECT_EQ(2, observer.gatt_service_added_count()); | |
326 EXPECT_EQ(1, observer.gatt_service_removed_count()); | |
327 EXPECT_FALSE(observer.last_gatt_service_id().empty()); | |
328 EXPECT_EQ(1U, device->GetGattServices().size()); | |
329 EXPECT_EQ(BluetoothUUID( | |
330 bluez::FakeBluetoothGattServiceClient::kHeartRateServiceUUID), | |
331 observer.last_gatt_service_uuid()); | |
332 | |
333 // The object |service| points to should have been deallocated. |device| | |
334 // should contain a brand new instance. | |
335 service = device->GetGattService(observer.last_gatt_service_id()); | |
336 EXPECT_EQ(service, device->GetGattServices()[0]); | |
337 EXPECT_FALSE(service->IsLocal()); | |
338 EXPECT_TRUE(service->IsPrimary()); | |
339 | |
340 EXPECT_EQ(observer.last_gatt_service_uuid(), service->GetUUID()); | |
341 | |
342 // Remove the device. The observer should be notified of the removed service. | |
343 // |device| becomes invalid after this. | |
344 observer.last_gatt_service_uuid() = BluetoothUUID(); | |
345 observer.last_gatt_service_id().clear(); | |
346 fake_bluetooth_device_client_->RemoveDevice( | |
347 dbus::ObjectPath(bluez::FakeBluetoothAdapterClient::kAdapterPath), | |
348 dbus::ObjectPath(bluez::FakeBluetoothDeviceClient::kLowEnergyPath)); | |
349 | |
350 EXPECT_EQ(2, observer.gatt_service_added_count()); | |
351 EXPECT_EQ(2, observer.gatt_service_removed_count()); | |
352 EXPECT_FALSE(observer.last_gatt_service_id().empty()); | |
353 EXPECT_EQ(BluetoothUUID( | |
354 bluez::FakeBluetoothGattServiceClient::kHeartRateServiceUUID), | |
355 observer.last_gatt_service_uuid()); | |
356 EXPECT_EQ(NULL, adapter_->GetDevice( | |
357 bluez::FakeBluetoothDeviceClient::kLowEnergyAddress)); | |
358 } | |
359 | |
360 TEST_F(BluetoothGattChromeOSTest, ServicesDiscovered) { | |
361 // Create a fake LE device. We store the device pointer here because this is a | |
362 // test. It's unsafe to do this in production as the device might get deleted. | |
363 fake_bluetooth_device_client_->CreateDevice( | |
364 dbus::ObjectPath(bluez::FakeBluetoothAdapterClient::kAdapterPath), | |
365 dbus::ObjectPath(bluez::FakeBluetoothDeviceClient::kLowEnergyPath)); | |
366 BluetoothDevice* device = | |
367 adapter_->GetDevice(bluez::FakeBluetoothDeviceClient::kLowEnergyAddress); | |
368 bluez::FakeBluetoothDeviceClient::Properties* properties = | |
369 fake_bluetooth_device_client_->GetProperties( | |
370 dbus::ObjectPath(bluez::FakeBluetoothDeviceClient::kLowEnergyPath)); | |
371 | |
372 ASSERT_TRUE(device); | |
373 | |
374 TestBluetoothAdapterObserver observer(adapter_); | |
375 | |
376 EXPECT_EQ(0, observer.gatt_services_discovered_count()); | |
377 | |
378 // Expose the fake Heart Rate Service. | |
379 fake_bluetooth_gatt_service_client_->ExposeHeartRateService( | |
380 dbus::ObjectPath(bluez::FakeBluetoothDeviceClient::kLowEnergyPath)); | |
381 // Notify that all services have been discovered. | |
382 properties->gatt_services.ReplaceValue( | |
383 fake_bluetooth_gatt_service_client_->GetServices()); | |
384 | |
385 EXPECT_EQ(1, observer.gatt_services_discovered_count()); | |
386 EXPECT_EQ(device, observer.last_device()); | |
387 EXPECT_EQ(bluez::FakeBluetoothDeviceClient::kLowEnergyAddress, | |
388 observer.last_device_address()); | |
389 } | |
390 | |
391 TEST_F(BluetoothGattChromeOSTest, GattCharacteristicAddedAndRemoved) { | |
392 fake_bluetooth_device_client_->CreateDevice( | |
393 dbus::ObjectPath(bluez::FakeBluetoothAdapterClient::kAdapterPath), | |
394 dbus::ObjectPath(bluez::FakeBluetoothDeviceClient::kLowEnergyPath)); | |
395 BluetoothDevice* device = | |
396 adapter_->GetDevice(bluez::FakeBluetoothDeviceClient::kLowEnergyAddress); | |
397 ASSERT_TRUE(device); | |
398 | |
399 TestBluetoothAdapterObserver observer(adapter_); | |
400 | |
401 // Expose the fake Heart Rate service. This will asynchronously expose | |
402 // characteristics. | |
403 fake_bluetooth_gatt_service_client_->ExposeHeartRateService( | |
404 dbus::ObjectPath(bluez::FakeBluetoothDeviceClient::kLowEnergyPath)); | |
405 ASSERT_EQ(1, observer.gatt_service_added_count()); | |
406 | |
407 BluetoothGattService* service = | |
408 device->GetGattService(observer.last_gatt_service_id()); | |
409 | |
410 EXPECT_EQ(0, observer.gatt_service_changed_count()); | |
411 EXPECT_EQ(0, observer.gatt_discovery_complete_count()); | |
412 EXPECT_EQ(0, observer.gatt_characteristic_added_count()); | |
413 EXPECT_EQ(0, observer.gatt_characteristic_removed_count()); | |
414 EXPECT_EQ(0, observer.gatt_characteristic_value_changed_count()); | |
415 EXPECT_TRUE(service->GetCharacteristics().empty()); | |
416 | |
417 // Run the message loop so that the characteristics appear. | |
418 base::MessageLoop::current()->Run(); | |
419 | |
420 // 3 characteristics should appear. Only 1 of the characteristics sends | |
421 // value changed signals. Service changed should be fired once for | |
422 // descriptor added. | |
423 EXPECT_EQ(0, observer.gatt_service_changed_count()); | |
424 EXPECT_EQ(1, observer.gatt_discovery_complete_count()); | |
425 EXPECT_EQ(3, observer.gatt_characteristic_added_count()); | |
426 EXPECT_EQ(0, observer.gatt_characteristic_removed_count()); | |
427 EXPECT_EQ(0, observer.gatt_characteristic_value_changed_count()); | |
428 EXPECT_EQ(3U, service->GetCharacteristics().size()); | |
429 | |
430 // Hide the characteristics. 3 removed signals should be received. | |
431 fake_bluetooth_gatt_characteristic_client_->HideHeartRateCharacteristics(); | |
432 EXPECT_EQ(0, observer.gatt_service_changed_count()); | |
433 EXPECT_EQ(3, observer.gatt_characteristic_added_count()); | |
434 EXPECT_EQ(3, observer.gatt_characteristic_removed_count()); | |
435 EXPECT_EQ(0, observer.gatt_characteristic_value_changed_count()); | |
436 EXPECT_TRUE(service->GetCharacteristics().empty()); | |
437 | |
438 // Re-expose the heart rate characteristics. We shouldn't get another | |
439 // GattDiscoveryCompleteForService call, since the service thinks that | |
440 // discovery is done. On the bluetoothd side, characteristics will be removed | |
441 // only if the service will also be subsequently removed. | |
442 fake_bluetooth_gatt_characteristic_client_->ExposeHeartRateCharacteristics( | |
443 fake_bluetooth_gatt_service_client_->GetHeartRateServicePath()); | |
444 EXPECT_EQ(0, observer.gatt_service_changed_count()); | |
445 EXPECT_EQ(1, observer.gatt_discovery_complete_count()); | |
446 EXPECT_EQ(6, observer.gatt_characteristic_added_count()); | |
447 EXPECT_EQ(3, observer.gatt_characteristic_removed_count()); | |
448 EXPECT_EQ(0, observer.gatt_characteristic_value_changed_count()); | |
449 EXPECT_EQ(3U, service->GetCharacteristics().size()); | |
450 | |
451 // Hide the service. All characteristics should disappear. | |
452 fake_bluetooth_gatt_service_client_->HideHeartRateService(); | |
453 EXPECT_EQ(0, observer.gatt_service_changed_count()); | |
454 EXPECT_EQ(6, observer.gatt_characteristic_added_count()); | |
455 EXPECT_EQ(6, observer.gatt_characteristic_removed_count()); | |
456 EXPECT_EQ(0, observer.gatt_characteristic_value_changed_count()); | |
457 } | |
458 | |
459 TEST_F(BluetoothGattChromeOSTest, GattDescriptorAddedAndRemoved) { | |
460 fake_bluetooth_device_client_->CreateDevice( | |
461 dbus::ObjectPath(bluez::FakeBluetoothAdapterClient::kAdapterPath), | |
462 dbus::ObjectPath(bluez::FakeBluetoothDeviceClient::kLowEnergyPath)); | |
463 BluetoothDevice* device = | |
464 adapter_->GetDevice(bluez::FakeBluetoothDeviceClient::kLowEnergyAddress); | |
465 ASSERT_TRUE(device); | |
466 | |
467 TestBluetoothAdapterObserver observer(adapter_); | |
468 | |
469 // Expose the fake Heart Rate service. This will asynchronously expose | |
470 // characteristics. | |
471 fake_bluetooth_gatt_service_client_->ExposeHeartRateService( | |
472 dbus::ObjectPath(bluez::FakeBluetoothDeviceClient::kLowEnergyPath)); | |
473 ASSERT_EQ(1, observer.gatt_service_added_count()); | |
474 | |
475 BluetoothGattService* service = | |
476 device->GetGattService(observer.last_gatt_service_id()); | |
477 | |
478 EXPECT_EQ(0, observer.gatt_service_changed_count()); | |
479 EXPECT_EQ(0, observer.gatt_descriptor_added_count()); | |
480 EXPECT_EQ(0, observer.gatt_descriptor_removed_count()); | |
481 EXPECT_EQ(0, observer.gatt_descriptor_value_changed_count()); | |
482 | |
483 EXPECT_TRUE(service->GetCharacteristics().empty()); | |
484 | |
485 // Run the message loop so that the characteristics appear. | |
486 base::MessageLoop::current()->Run(); | |
487 EXPECT_EQ(0, observer.gatt_service_changed_count()); | |
488 | |
489 // Only the Heart Rate Measurement characteristic has a descriptor. | |
490 EXPECT_EQ(1, observer.gatt_descriptor_added_count()); | |
491 EXPECT_EQ(0, observer.gatt_descriptor_removed_count()); | |
492 EXPECT_EQ(0, observer.gatt_descriptor_value_changed_count()); | |
493 | |
494 BluetoothGattCharacteristic* characteristic = service->GetCharacteristic( | |
495 fake_bluetooth_gatt_characteristic_client_-> | |
496 GetBodySensorLocationPath().value()); | |
497 ASSERT_TRUE(characteristic); | |
498 EXPECT_TRUE(characteristic->GetDescriptors().empty()); | |
499 | |
500 characteristic = service->GetCharacteristic( | |
501 fake_bluetooth_gatt_characteristic_client_-> | |
502 GetHeartRateControlPointPath().value()); | |
503 ASSERT_TRUE(characteristic); | |
504 EXPECT_TRUE(characteristic->GetDescriptors().empty()); | |
505 | |
506 characteristic = service->GetCharacteristic( | |
507 fake_bluetooth_gatt_characteristic_client_-> | |
508 GetHeartRateMeasurementPath().value()); | |
509 ASSERT_TRUE(characteristic); | |
510 EXPECT_EQ(1U, characteristic->GetDescriptors().size()); | |
511 | |
512 BluetoothGattDescriptor* descriptor = characteristic->GetDescriptors()[0]; | |
513 EXPECT_FALSE(descriptor->IsLocal()); | |
514 EXPECT_EQ(BluetoothGattDescriptor::ClientCharacteristicConfigurationUuid(), | |
515 descriptor->GetUUID()); | |
516 EXPECT_EQ(descriptor->GetUUID(), observer.last_gatt_descriptor_uuid()); | |
517 EXPECT_EQ(descriptor->GetIdentifier(), observer.last_gatt_descriptor_id()); | |
518 | |
519 // Hide the descriptor. | |
520 fake_bluetooth_gatt_descriptor_client_->HideDescriptor( | |
521 dbus::ObjectPath(descriptor->GetIdentifier())); | |
522 EXPECT_TRUE(characteristic->GetDescriptors().empty()); | |
523 EXPECT_EQ(0, observer.gatt_service_changed_count()); | |
524 EXPECT_EQ(1, observer.gatt_descriptor_added_count()); | |
525 EXPECT_EQ(1, observer.gatt_descriptor_removed_count()); | |
526 EXPECT_EQ(0, observer.gatt_descriptor_value_changed_count()); | |
527 | |
528 // Expose the descriptor again. | |
529 observer.last_gatt_descriptor_id().clear(); | |
530 observer.last_gatt_descriptor_uuid() = BluetoothUUID(); | |
531 fake_bluetooth_gatt_descriptor_client_->ExposeDescriptor( | |
532 dbus::ObjectPath(characteristic->GetIdentifier()), | |
533 bluez::FakeBluetoothGattDescriptorClient:: | |
534 kClientCharacteristicConfigurationUUID); | |
535 EXPECT_EQ(0, observer.gatt_service_changed_count()); | |
536 EXPECT_EQ(1U, characteristic->GetDescriptors().size()); | |
537 EXPECT_EQ(2, observer.gatt_descriptor_added_count()); | |
538 EXPECT_EQ(1, observer.gatt_descriptor_removed_count()); | |
539 EXPECT_EQ(0, observer.gatt_descriptor_value_changed_count()); | |
540 | |
541 descriptor = characteristic->GetDescriptors()[0]; | |
542 EXPECT_FALSE(descriptor->IsLocal()); | |
543 EXPECT_EQ(BluetoothGattDescriptor::ClientCharacteristicConfigurationUuid(), | |
544 descriptor->GetUUID()); | |
545 EXPECT_EQ(descriptor->GetUUID(), observer.last_gatt_descriptor_uuid()); | |
546 EXPECT_EQ(descriptor->GetIdentifier(), observer.last_gatt_descriptor_id()); | |
547 } | |
548 | |
549 TEST_F(BluetoothGattChromeOSTest, AdapterAddedAfterGattService) { | |
550 // This unit test tests that all remote GATT objects are created for D-Bus | |
551 // objects that were already exposed. | |
552 adapter_ = NULL; | |
553 ASSERT_FALSE(device::BluetoothAdapterFactory::HasSharedInstanceForTesting()); | |
554 | |
555 // Create the fake D-Bus objects. | |
556 fake_bluetooth_device_client_->CreateDevice( | |
557 dbus::ObjectPath(bluez::FakeBluetoothAdapterClient::kAdapterPath), | |
558 dbus::ObjectPath(bluez::FakeBluetoothDeviceClient::kLowEnergyPath)); | |
559 fake_bluetooth_gatt_service_client_->ExposeHeartRateService( | |
560 dbus::ObjectPath(bluez::FakeBluetoothDeviceClient::kLowEnergyPath)); | |
561 while (!fake_bluetooth_gatt_characteristic_client_->IsHeartRateVisible()) | |
562 base::RunLoop().RunUntilIdle(); | |
563 ASSERT_TRUE(fake_bluetooth_gatt_service_client_->IsHeartRateVisible()); | |
564 ASSERT_TRUE(fake_bluetooth_gatt_characteristic_client_->IsHeartRateVisible()); | |
565 | |
566 // Create the adapter. This should create all the GATT objects. | |
567 GetAdapter(); | |
568 BluetoothDevice* device = | |
569 adapter_->GetDevice(bluez::FakeBluetoothDeviceClient::kLowEnergyAddress); | |
570 ASSERT_TRUE(device); | |
571 EXPECT_EQ(1U, device->GetGattServices().size()); | |
572 | |
573 BluetoothGattService* service = device->GetGattServices()[0]; | |
574 ASSERT_TRUE(service); | |
575 EXPECT_FALSE(service->IsLocal()); | |
576 EXPECT_TRUE(service->IsPrimary()); | |
577 EXPECT_EQ(BluetoothUUID( | |
578 bluez::FakeBluetoothGattServiceClient::kHeartRateServiceUUID), | |
579 service->GetUUID()); | |
580 EXPECT_EQ(service, device->GetGattServices()[0]); | |
581 EXPECT_EQ(service, device->GetGattService(service->GetIdentifier())); | |
582 EXPECT_FALSE(service->IsLocal()); | |
583 EXPECT_EQ(3U, service->GetCharacteristics().size()); | |
584 | |
585 BluetoothGattCharacteristic* characteristic = service->GetCharacteristic( | |
586 fake_bluetooth_gatt_characteristic_client_-> | |
587 GetBodySensorLocationPath().value()); | |
588 ASSERT_TRUE(characteristic); | |
589 EXPECT_EQ(BluetoothUUID(bluez::FakeBluetoothGattCharacteristicClient:: | |
590 kBodySensorLocationUUID), | |
591 characteristic->GetUUID()); | |
592 EXPECT_FALSE(characteristic->IsLocal()); | |
593 EXPECT_TRUE(characteristic->GetDescriptors().empty()); | |
594 | |
595 characteristic = service->GetCharacteristic( | |
596 fake_bluetooth_gatt_characteristic_client_-> | |
597 GetHeartRateControlPointPath().value()); | |
598 ASSERT_TRUE(characteristic); | |
599 EXPECT_EQ(BluetoothUUID(bluez::FakeBluetoothGattCharacteristicClient:: | |
600 kHeartRateControlPointUUID), | |
601 characteristic->GetUUID()); | |
602 EXPECT_FALSE(characteristic->IsLocal()); | |
603 EXPECT_TRUE(characteristic->GetDescriptors().empty()); | |
604 | |
605 characteristic = service->GetCharacteristic( | |
606 fake_bluetooth_gatt_characteristic_client_-> | |
607 GetHeartRateMeasurementPath().value()); | |
608 ASSERT_TRUE(characteristic); | |
609 EXPECT_EQ(BluetoothUUID(bluez::FakeBluetoothGattCharacteristicClient:: | |
610 kHeartRateMeasurementUUID), | |
611 characteristic->GetUUID()); | |
612 EXPECT_FALSE(characteristic->IsLocal()); | |
613 EXPECT_EQ(1U, characteristic->GetDescriptors().size()); | |
614 | |
615 BluetoothGattDescriptor* descriptor = characteristic->GetDescriptors()[0]; | |
616 ASSERT_TRUE(descriptor); | |
617 EXPECT_EQ(BluetoothGattDescriptor::ClientCharacteristicConfigurationUuid(), | |
618 descriptor->GetUUID()); | |
619 EXPECT_FALSE(descriptor->IsLocal()); | |
620 } | |
621 | |
622 TEST_F(BluetoothGattChromeOSTest, GattCharacteristicValue) { | |
623 fake_bluetooth_device_client_->CreateDevice( | |
624 dbus::ObjectPath(bluez::FakeBluetoothAdapterClient::kAdapterPath), | |
625 dbus::ObjectPath(bluez::FakeBluetoothDeviceClient::kLowEnergyPath)); | |
626 BluetoothDevice* device = | |
627 adapter_->GetDevice(bluez::FakeBluetoothDeviceClient::kLowEnergyAddress); | |
628 ASSERT_TRUE(device); | |
629 | |
630 TestBluetoothAdapterObserver observer(adapter_); | |
631 | |
632 // Expose the fake Heart Rate service. This will asynchronously expose | |
633 // characteristics. | |
634 fake_bluetooth_gatt_service_client_->ExposeHeartRateService( | |
635 dbus::ObjectPath(bluez::FakeBluetoothDeviceClient::kLowEnergyPath)); | |
636 ASSERT_EQ(1, observer.gatt_service_added_count()); | |
637 | |
638 BluetoothGattService* service = | |
639 device->GetGattService(observer.last_gatt_service_id()); | |
640 | |
641 EXPECT_EQ(0, observer.gatt_characteristic_value_changed_count()); | |
642 | |
643 // Run the message loop so that the characteristics appear. | |
644 base::MessageLoop::current()->Run(); | |
645 | |
646 // Issue write request to non-writable characteristics. | |
647 observer.Reset(); | |
648 | |
649 std::vector<uint8> write_value; | |
650 write_value.push_back(0x01); | |
651 BluetoothGattCharacteristic* characteristic = | |
652 service->GetCharacteristic(fake_bluetooth_gatt_characteristic_client_-> | |
653 GetHeartRateMeasurementPath().value()); | |
654 ASSERT_TRUE(characteristic); | |
655 EXPECT_FALSE(characteristic->IsNotifying()); | |
656 EXPECT_EQ(fake_bluetooth_gatt_characteristic_client_-> | |
657 GetHeartRateMeasurementPath().value(), | |
658 characteristic->GetIdentifier()); | |
659 EXPECT_EQ(kHeartRateMeasurementUUID, characteristic->GetUUID()); | |
660 characteristic->WriteRemoteCharacteristic( | |
661 write_value, | |
662 base::Bind(&BluetoothGattChromeOSTest::SuccessCallback, | |
663 base::Unretained(this)), | |
664 base::Bind(&BluetoothGattChromeOSTest::ServiceErrorCallback, | |
665 base::Unretained(this))); | |
666 EXPECT_TRUE(observer.last_gatt_characteristic_id().empty()); | |
667 EXPECT_FALSE(observer.last_gatt_characteristic_uuid().IsValid()); | |
668 EXPECT_EQ(0, success_callback_count_); | |
669 EXPECT_EQ(1, error_callback_count_); | |
670 EXPECT_EQ(BluetoothGattService::GATT_ERROR_NOT_SUPPORTED, | |
671 last_service_error_); | |
672 EXPECT_EQ(0, observer.gatt_characteristic_value_changed_count()); | |
673 | |
674 characteristic = service->GetCharacteristic( | |
675 fake_bluetooth_gatt_characteristic_client_-> | |
676 GetBodySensorLocationPath().value()); | |
677 ASSERT_TRUE(characteristic); | |
678 EXPECT_EQ(fake_bluetooth_gatt_characteristic_client_-> | |
679 GetBodySensorLocationPath().value(), | |
680 characteristic->GetIdentifier()); | |
681 EXPECT_EQ(kBodySensorLocationUUID, characteristic->GetUUID()); | |
682 characteristic->WriteRemoteCharacteristic( | |
683 write_value, | |
684 base::Bind(&BluetoothGattChromeOSTest::SuccessCallback, | |
685 base::Unretained(this)), | |
686 base::Bind(&BluetoothGattChromeOSTest::ServiceErrorCallback, | |
687 base::Unretained(this))); | |
688 EXPECT_TRUE(observer.last_gatt_characteristic_id().empty()); | |
689 EXPECT_FALSE(observer.last_gatt_characteristic_uuid().IsValid()); | |
690 EXPECT_EQ(0, success_callback_count_); | |
691 EXPECT_EQ(2, error_callback_count_); | |
692 EXPECT_EQ(BluetoothGattService::GATT_ERROR_NOT_PERMITTED, | |
693 last_service_error_); | |
694 EXPECT_EQ(0, observer.gatt_characteristic_value_changed_count()); | |
695 | |
696 // Issue write request to writable characteristic. The "Body Sensor Location" | |
697 // characteristic does not send notifications and WriteValue does not result | |
698 // in a CharacteristicValueChanged event, thus no such event should be | |
699 // received. | |
700 characteristic = service->GetCharacteristic( | |
701 fake_bluetooth_gatt_characteristic_client_-> | |
702 GetHeartRateControlPointPath().value()); | |
703 ASSERT_TRUE(characteristic); | |
704 EXPECT_EQ(fake_bluetooth_gatt_characteristic_client_-> | |
705 GetHeartRateControlPointPath().value(), | |
706 characteristic->GetIdentifier()); | |
707 EXPECT_EQ(kHeartRateControlPointUUID, characteristic->GetUUID()); | |
708 characteristic->WriteRemoteCharacteristic( | |
709 write_value, | |
710 base::Bind(&BluetoothGattChromeOSTest::SuccessCallback, | |
711 base::Unretained(this)), | |
712 base::Bind(&BluetoothGattChromeOSTest::ServiceErrorCallback, | |
713 base::Unretained(this))); | |
714 EXPECT_TRUE(observer.last_gatt_characteristic_id().empty()); | |
715 EXPECT_FALSE(observer.last_gatt_characteristic_uuid().IsValid()); | |
716 EXPECT_EQ(1, success_callback_count_); | |
717 EXPECT_EQ(2, error_callback_count_); | |
718 EXPECT_EQ(0, observer.gatt_characteristic_value_changed_count()); | |
719 | |
720 // Issue some invalid write requests to the characteristic. | |
721 // The value should still not change. | |
722 | |
723 std::vector<uint8> invalid_write_length; | |
724 invalid_write_length.push_back(0x01); | |
725 invalid_write_length.push_back(0x00); | |
726 characteristic->WriteRemoteCharacteristic( | |
727 invalid_write_length, | |
728 base::Bind(&BluetoothGattChromeOSTest::SuccessCallback, | |
729 base::Unretained(this)), | |
730 base::Bind(&BluetoothGattChromeOSTest::ServiceErrorCallback, | |
731 base::Unretained(this))); | |
732 EXPECT_EQ(1, success_callback_count_); | |
733 EXPECT_EQ(3, error_callback_count_); | |
734 EXPECT_EQ(BluetoothGattService::GATT_ERROR_INVALID_LENGTH, | |
735 last_service_error_); | |
736 EXPECT_EQ(0, observer.gatt_characteristic_value_changed_count()); | |
737 | |
738 std::vector<uint8> invalid_write_value; | |
739 invalid_write_value.push_back(0x02); | |
740 characteristic->WriteRemoteCharacteristic( | |
741 invalid_write_value, | |
742 base::Bind(&BluetoothGattChromeOSTest::SuccessCallback, | |
743 base::Unretained(this)), | |
744 base::Bind(&BluetoothGattChromeOSTest::ServiceErrorCallback, | |
745 base::Unretained(this))); | |
746 EXPECT_EQ(1, success_callback_count_); | |
747 EXPECT_EQ(4, error_callback_count_); | |
748 EXPECT_EQ(BluetoothGattService::GATT_ERROR_FAILED, last_service_error_); | |
749 EXPECT_EQ(0, observer.gatt_characteristic_value_changed_count()); | |
750 | |
751 // Issue a read request. A successful read results in a | |
752 // CharacteristicValueChanged notification. | |
753 characteristic = service->GetCharacteristic( | |
754 fake_bluetooth_gatt_characteristic_client_-> | |
755 GetBodySensorLocationPath().value()); | |
756 ASSERT_TRUE(characteristic); | |
757 EXPECT_EQ(fake_bluetooth_gatt_characteristic_client_-> | |
758 GetBodySensorLocationPath().value(), | |
759 characteristic->GetIdentifier()); | |
760 EXPECT_EQ(kBodySensorLocationUUID, characteristic->GetUUID()); | |
761 characteristic->ReadRemoteCharacteristic( | |
762 base::Bind(&BluetoothGattChromeOSTest::ValueCallback, | |
763 base::Unretained(this)), | |
764 base::Bind(&BluetoothGattChromeOSTest::ServiceErrorCallback, | |
765 base::Unretained(this))); | |
766 EXPECT_EQ(2, success_callback_count_); | |
767 EXPECT_EQ(4, error_callback_count_); | |
768 EXPECT_EQ(1, observer.gatt_characteristic_value_changed_count()); | |
769 EXPECT_TRUE(ValuesEqual(characteristic->GetValue(), last_read_value_)); | |
770 | |
771 // Test long-running actions. | |
772 fake_bluetooth_gatt_characteristic_client_->SetExtraProcessing(1); | |
773 characteristic = service->GetCharacteristic( | |
774 fake_bluetooth_gatt_characteristic_client_->GetBodySensorLocationPath() | |
775 .value()); | |
776 ASSERT_TRUE(characteristic); | |
777 EXPECT_EQ( | |
778 fake_bluetooth_gatt_characteristic_client_->GetBodySensorLocationPath() | |
779 .value(), | |
780 characteristic->GetIdentifier()); | |
781 EXPECT_EQ(kBodySensorLocationUUID, characteristic->GetUUID()); | |
782 characteristic->ReadRemoteCharacteristic( | |
783 base::Bind(&BluetoothGattChromeOSTest::ValueCallback, | |
784 base::Unretained(this)), | |
785 base::Bind(&BluetoothGattChromeOSTest::ServiceErrorCallback, | |
786 base::Unretained(this))); | |
787 | |
788 // Callback counts shouldn't change, this one will be delayed until after | |
789 // tne next one. | |
790 EXPECT_EQ(2, success_callback_count_); | |
791 EXPECT_EQ(4, error_callback_count_); | |
792 EXPECT_EQ(1, observer.gatt_characteristic_value_changed_count()); | |
793 | |
794 // Next read should error because IN_PROGRESS | |
795 characteristic->ReadRemoteCharacteristic( | |
796 base::Bind(&BluetoothGattChromeOSTest::ValueCallback, | |
797 base::Unretained(this)), | |
798 base::Bind(&BluetoothGattChromeOSTest::ServiceErrorCallback, | |
799 base::Unretained(this))); | |
800 EXPECT_EQ(5, error_callback_count_); | |
801 EXPECT_EQ(BluetoothGattService::GATT_ERROR_IN_PROGRESS, last_service_error_); | |
802 | |
803 // But previous call finished. | |
804 EXPECT_EQ(3, success_callback_count_); | |
805 EXPECT_EQ(2, observer.gatt_characteristic_value_changed_count()); | |
806 EXPECT_TRUE(ValuesEqual(characteristic->GetValue(), last_read_value_)); | |
807 fake_bluetooth_gatt_characteristic_client_->SetExtraProcessing(0); | |
808 | |
809 // Test unauthorized actions. | |
810 fake_bluetooth_gatt_characteristic_client_->SetAuthorized(false); | |
811 characteristic->ReadRemoteCharacteristic( | |
812 base::Bind(&BluetoothGattChromeOSTest::ValueCallback, | |
813 base::Unretained(this)), | |
814 base::Bind(&BluetoothGattChromeOSTest::ServiceErrorCallback, | |
815 base::Unretained(this))); | |
816 EXPECT_EQ(3, success_callback_count_); | |
817 EXPECT_EQ(6, error_callback_count_); | |
818 EXPECT_EQ(BluetoothGattService::GATT_ERROR_NOT_AUTHORIZED, | |
819 last_service_error_); | |
820 EXPECT_EQ(2, observer.gatt_characteristic_value_changed_count()); | |
821 fake_bluetooth_gatt_characteristic_client_->SetAuthorized(true); | |
822 | |
823 // Test unauthenticated / needs login. | |
824 fake_bluetooth_gatt_characteristic_client_->SetAuthenticated(false); | |
825 characteristic->ReadRemoteCharacteristic( | |
826 base::Bind(&BluetoothGattChromeOSTest::ValueCallback, | |
827 base::Unretained(this)), | |
828 base::Bind(&BluetoothGattChromeOSTest::ServiceErrorCallback, | |
829 base::Unretained(this))); | |
830 EXPECT_EQ(3, success_callback_count_); | |
831 EXPECT_EQ(7, error_callback_count_); | |
832 EXPECT_EQ(BluetoothGattService::GATT_ERROR_NOT_PAIRED, last_service_error_); | |
833 EXPECT_EQ(2, observer.gatt_characteristic_value_changed_count()); | |
834 fake_bluetooth_gatt_characteristic_client_->SetAuthenticated(true); | |
835 } | |
836 | |
837 TEST_F(BluetoothGattChromeOSTest, GattCharacteristicProperties) { | |
838 fake_bluetooth_device_client_->CreateDevice( | |
839 dbus::ObjectPath(bluez::FakeBluetoothAdapterClient::kAdapterPath), | |
840 dbus::ObjectPath(bluez::FakeBluetoothDeviceClient::kLowEnergyPath)); | |
841 BluetoothDevice* device = | |
842 adapter_->GetDevice(bluez::FakeBluetoothDeviceClient::kLowEnergyAddress); | |
843 ASSERT_TRUE(device); | |
844 | |
845 TestBluetoothAdapterObserver observer(adapter_); | |
846 | |
847 // Expose the fake Heart Rate service. This will asynchronously expose | |
848 // characteristics. | |
849 fake_bluetooth_gatt_service_client_->ExposeHeartRateService( | |
850 dbus::ObjectPath(bluez::FakeBluetoothDeviceClient::kLowEnergyPath)); | |
851 | |
852 BluetoothGattService* service = | |
853 device->GetGattService(observer.last_gatt_service_id()); | |
854 | |
855 EXPECT_TRUE(service->GetCharacteristics().empty()); | |
856 | |
857 // Run the message loop so that the characteristics appear. | |
858 base::MessageLoop::current()->Run(); | |
859 | |
860 BluetoothGattCharacteristic *characteristic = service->GetCharacteristic( | |
861 fake_bluetooth_gatt_characteristic_client_-> | |
862 GetBodySensorLocationPath().value()); | |
863 EXPECT_EQ(BluetoothGattCharacteristic::PROPERTY_READ, | |
864 characteristic->GetProperties()); | |
865 | |
866 characteristic = service->GetCharacteristic( | |
867 fake_bluetooth_gatt_characteristic_client_-> | |
868 GetHeartRateControlPointPath().value()); | |
869 EXPECT_EQ(BluetoothGattCharacteristic::PROPERTY_WRITE, | |
870 characteristic->GetProperties()); | |
871 | |
872 characteristic = service->GetCharacteristic( | |
873 fake_bluetooth_gatt_characteristic_client_-> | |
874 GetHeartRateMeasurementPath().value()); | |
875 EXPECT_EQ(BluetoothGattCharacteristic::PROPERTY_NOTIFY, | |
876 characteristic->GetProperties()); | |
877 } | |
878 | |
879 TEST_F(BluetoothGattChromeOSTest, GattDescriptorValue) { | |
880 fake_bluetooth_device_client_->CreateDevice( | |
881 dbus::ObjectPath(bluez::FakeBluetoothAdapterClient::kAdapterPath), | |
882 dbus::ObjectPath(bluez::FakeBluetoothDeviceClient::kLowEnergyPath)); | |
883 BluetoothDevice* device = | |
884 adapter_->GetDevice(bluez::FakeBluetoothDeviceClient::kLowEnergyAddress); | |
885 ASSERT_TRUE(device); | |
886 | |
887 TestBluetoothAdapterObserver observer(adapter_); | |
888 | |
889 // Expose the fake Heart Rate service. This will asynchronously expose | |
890 // characteristics. | |
891 fake_bluetooth_gatt_service_client_->ExposeHeartRateService( | |
892 dbus::ObjectPath(bluez::FakeBluetoothDeviceClient::kLowEnergyPath)); | |
893 ASSERT_EQ(1, observer.gatt_service_added_count()); | |
894 | |
895 BluetoothGattService* service = | |
896 device->GetGattService(observer.last_gatt_service_id()); | |
897 | |
898 EXPECT_EQ(0, observer.gatt_service_changed_count()); | |
899 EXPECT_EQ(0, observer.gatt_discovery_complete_count()); | |
900 EXPECT_EQ(0, observer.gatt_descriptor_value_changed_count()); | |
901 EXPECT_TRUE(service->GetCharacteristics().empty()); | |
902 | |
903 // Run the message loop so that the characteristics appear. | |
904 base::MessageLoop::current()->Run(); | |
905 EXPECT_EQ(0, observer.gatt_service_changed_count()); | |
906 EXPECT_EQ(1, observer.gatt_discovery_complete_count()); | |
907 | |
908 // Only the Heart Rate Measurement characteristic has a descriptor. | |
909 BluetoothGattCharacteristic* characteristic = service->GetCharacteristic( | |
910 fake_bluetooth_gatt_characteristic_client_-> | |
911 GetHeartRateMeasurementPath().value()); | |
912 ASSERT_TRUE(characteristic); | |
913 EXPECT_EQ(1U, characteristic->GetDescriptors().size()); | |
914 EXPECT_FALSE(characteristic->IsNotifying()); | |
915 | |
916 BluetoothGattDescriptor* descriptor = characteristic->GetDescriptors()[0]; | |
917 EXPECT_FALSE(descriptor->IsLocal()); | |
918 EXPECT_EQ(BluetoothGattDescriptor::ClientCharacteristicConfigurationUuid(), | |
919 descriptor->GetUUID()); | |
920 | |
921 std::vector<uint8_t> desc_value = {0x00, 0x00}; | |
922 | |
923 /* The cached value will be empty until the first read request */ | |
924 EXPECT_FALSE(ValuesEqual(desc_value, descriptor->GetValue())); | |
925 EXPECT_TRUE(descriptor->GetValue().empty()); | |
926 | |
927 EXPECT_EQ(0, success_callback_count_); | |
928 EXPECT_EQ(0, error_callback_count_); | |
929 EXPECT_TRUE(last_read_value_.empty()); | |
930 | |
931 // Read value. GattDescriptorValueChanged event will be sent after a | |
932 // successful read. | |
933 descriptor->ReadRemoteDescriptor( | |
934 base::Bind(&BluetoothGattChromeOSTest::ValueCallback, | |
935 base::Unretained(this)), | |
936 base::Bind(&BluetoothGattChromeOSTest::ServiceErrorCallback, | |
937 base::Unretained(this))); | |
938 EXPECT_EQ(1, success_callback_count_); | |
939 EXPECT_EQ(0, error_callback_count_); | |
940 EXPECT_TRUE(ValuesEqual(last_read_value_, descriptor->GetValue())); | |
941 EXPECT_TRUE(ValuesEqual(desc_value, descriptor->GetValue())); | |
942 EXPECT_EQ(0, observer.gatt_service_changed_count()); | |
943 EXPECT_EQ(1, observer.gatt_descriptor_value_changed_count()); | |
944 | |
945 // Write value. Writes to this descriptor will fail. | |
946 desc_value[0] = 0x03; | |
947 descriptor->WriteRemoteDescriptor( | |
948 desc_value, | |
949 base::Bind(&BluetoothGattChromeOSTest::SuccessCallback, | |
950 base::Unretained(this)), | |
951 base::Bind(&BluetoothGattChromeOSTest::ServiceErrorCallback, | |
952 base::Unretained(this))); | |
953 EXPECT_EQ(1, success_callback_count_); | |
954 EXPECT_EQ(1, error_callback_count_); | |
955 EXPECT_EQ(BluetoothGattService::GATT_ERROR_NOT_PERMITTED, | |
956 last_service_error_); | |
957 EXPECT_TRUE(ValuesEqual(last_read_value_, descriptor->GetValue())); | |
958 EXPECT_FALSE(ValuesEqual(desc_value, descriptor->GetValue())); | |
959 EXPECT_EQ(0, observer.gatt_service_changed_count()); | |
960 EXPECT_EQ(1, observer.gatt_descriptor_value_changed_count()); | |
961 | |
962 // Read value. The value should remain unchanged. | |
963 descriptor->ReadRemoteDescriptor( | |
964 base::Bind(&BluetoothGattChromeOSTest::ValueCallback, | |
965 base::Unretained(this)), | |
966 base::Bind(&BluetoothGattChromeOSTest::ServiceErrorCallback, | |
967 base::Unretained(this))); | |
968 EXPECT_EQ(2, success_callback_count_); | |
969 EXPECT_EQ(1, error_callback_count_); | |
970 EXPECT_TRUE(ValuesEqual(last_read_value_, descriptor->GetValue())); | |
971 EXPECT_FALSE(ValuesEqual(desc_value, descriptor->GetValue())); | |
972 EXPECT_EQ(0, observer.gatt_service_changed_count()); | |
973 EXPECT_EQ(1, observer.gatt_descriptor_value_changed_count()); | |
974 | |
975 // Start notifications on the descriptor's characteristic. The descriptor | |
976 // value should change. | |
977 characteristic->StartNotifySession( | |
978 base::Bind(&BluetoothGattChromeOSTest::NotifySessionCallback, | |
979 base::Unretained(this)), | |
980 base::Bind(&BluetoothGattChromeOSTest::ServiceErrorCallback, | |
981 base::Unretained(this))); | |
982 base::MessageLoop::current()->Run(); | |
983 EXPECT_EQ(3, success_callback_count_); | |
984 EXPECT_EQ(1, error_callback_count_); | |
985 EXPECT_EQ(1U, update_sessions_.size()); | |
986 EXPECT_TRUE(characteristic->IsNotifying()); | |
987 | |
988 // Read the new descriptor value. We should receive a value updated event. | |
989 descriptor->ReadRemoteDescriptor( | |
990 base::Bind(&BluetoothGattChromeOSTest::ValueCallback, | |
991 base::Unretained(this)), | |
992 base::Bind(&BluetoothGattChromeOSTest::ServiceErrorCallback, | |
993 base::Unretained(this))); | |
994 EXPECT_EQ(4, success_callback_count_); | |
995 EXPECT_EQ(1, error_callback_count_); | |
996 EXPECT_TRUE(ValuesEqual(last_read_value_, descriptor->GetValue())); | |
997 EXPECT_FALSE(ValuesEqual(desc_value, descriptor->GetValue())); | |
998 EXPECT_EQ(0, observer.gatt_service_changed_count()); | |
999 EXPECT_EQ(2, observer.gatt_descriptor_value_changed_count()); | |
1000 } | |
1001 | |
1002 TEST_F(BluetoothGattChromeOSTest, NotifySessions) { | |
1003 fake_bluetooth_device_client_->CreateDevice( | |
1004 dbus::ObjectPath(bluez::FakeBluetoothAdapterClient::kAdapterPath), | |
1005 dbus::ObjectPath(bluez::FakeBluetoothDeviceClient::kLowEnergyPath)); | |
1006 BluetoothDevice* device = | |
1007 adapter_->GetDevice(bluez::FakeBluetoothDeviceClient::kLowEnergyAddress); | |
1008 ASSERT_TRUE(device); | |
1009 | |
1010 TestBluetoothAdapterObserver observer(adapter_); | |
1011 | |
1012 // Expose the fake Heart Rate service. This will asynchronously expose | |
1013 // characteristics. | |
1014 fake_bluetooth_gatt_service_client_->ExposeHeartRateService( | |
1015 dbus::ObjectPath(bluez::FakeBluetoothDeviceClient::kLowEnergyPath)); | |
1016 ASSERT_EQ(1, observer.gatt_service_added_count()); | |
1017 | |
1018 BluetoothGattService* service = | |
1019 device->GetGattService(observer.last_gatt_service_id()); | |
1020 | |
1021 EXPECT_EQ(0, observer.gatt_characteristic_value_changed_count()); | |
1022 | |
1023 // Run the message loop so that the characteristics appear. | |
1024 base::MessageLoop::current()->Run(); | |
1025 | |
1026 BluetoothGattCharacteristic* characteristic = service->GetCharacteristic( | |
1027 fake_bluetooth_gatt_characteristic_client_->GetHeartRateMeasurementPath() | |
1028 .value()); | |
1029 ASSERT_TRUE(characteristic); | |
1030 EXPECT_FALSE(characteristic->IsNotifying()); | |
1031 EXPECT_TRUE(update_sessions_.empty()); | |
1032 | |
1033 // Request to start notifications. | |
1034 characteristic->StartNotifySession( | |
1035 base::Bind(&BluetoothGattChromeOSTest::NotifySessionCallback, | |
1036 base::Unretained(this)), | |
1037 base::Bind(&BluetoothGattChromeOSTest::ServiceErrorCallback, | |
1038 base::Unretained(this))); | |
1039 | |
1040 // The operation still hasn't completed but we should have received the first | |
1041 // notification. | |
1042 EXPECT_EQ(0, success_callback_count_); | |
1043 EXPECT_EQ(0, error_callback_count_); | |
1044 EXPECT_EQ(1, observer.gatt_characteristic_value_changed_count()); | |
1045 EXPECT_TRUE(update_sessions_.empty()); | |
1046 | |
1047 // Send a two more requests, which should get queued. | |
1048 characteristic->StartNotifySession( | |
1049 base::Bind(&BluetoothGattChromeOSTest::NotifySessionCallback, | |
1050 base::Unretained(this)), | |
1051 base::Bind(&BluetoothGattChromeOSTest::ServiceErrorCallback, | |
1052 base::Unretained(this))); | |
1053 characteristic->StartNotifySession( | |
1054 base::Bind(&BluetoothGattChromeOSTest::NotifySessionCallback, | |
1055 base::Unretained(this)), | |
1056 base::Bind(&BluetoothGattChromeOSTest::ServiceErrorCallback, | |
1057 base::Unretained(this))); | |
1058 EXPECT_EQ(0, success_callback_count_); | |
1059 EXPECT_EQ(0, error_callback_count_); | |
1060 EXPECT_EQ(1, observer.gatt_characteristic_value_changed_count()); | |
1061 EXPECT_TRUE(update_sessions_.empty()); | |
1062 EXPECT_TRUE(characteristic->IsNotifying()); | |
1063 | |
1064 // Run the main loop. The initial call should complete. The queued call should | |
1065 // succeed immediately. | |
1066 base::MessageLoop::current()->Run(); | |
1067 | |
1068 EXPECT_EQ(3, success_callback_count_); | |
1069 EXPECT_EQ(0, error_callback_count_); | |
1070 EXPECT_EQ(1, observer.gatt_characteristic_value_changed_count()); | |
1071 EXPECT_EQ(3U, update_sessions_.size()); | |
1072 | |
1073 // Notifications should be getting sent regularly now. | |
1074 base::MessageLoop::current()->Run(); | |
1075 EXPECT_GT(observer.gatt_characteristic_value_changed_count(), 1); | |
1076 | |
1077 // Stop one of the sessions. The session should become inactive but the | |
1078 // characteristic should still be notifying. | |
1079 BluetoothGattNotifySession* session = update_sessions_[0]; | |
1080 EXPECT_TRUE(session->IsActive()); | |
1081 session->Stop(base::Bind(&BluetoothGattChromeOSTest::SuccessCallback, | |
1082 base::Unretained(this))); | |
1083 EXPECT_EQ(4, success_callback_count_); | |
1084 EXPECT_EQ(0, error_callback_count_); | |
1085 EXPECT_FALSE(session->IsActive()); | |
1086 EXPECT_EQ(characteristic->GetIdentifier(), | |
1087 session->GetCharacteristicIdentifier()); | |
1088 EXPECT_TRUE(characteristic->IsNotifying()); | |
1089 | |
1090 // Delete another session. Characteristic should still be notifying. | |
1091 update_sessions_.pop_back(); | |
1092 EXPECT_EQ(2U, update_sessions_.size()); | |
1093 EXPECT_TRUE(characteristic->IsNotifying()); | |
1094 EXPECT_FALSE(update_sessions_[0]->IsActive()); | |
1095 EXPECT_TRUE(update_sessions_[1]->IsActive()); | |
1096 | |
1097 // Clear the last session. | |
1098 update_sessions_.clear(); | |
1099 EXPECT_TRUE(update_sessions_.empty()); | |
1100 EXPECT_FALSE(characteristic->IsNotifying()); | |
1101 | |
1102 success_callback_count_ = 0; | |
1103 observer.Reset(); | |
1104 | |
1105 // Enable notifications again. | |
1106 characteristic->StartNotifySession( | |
1107 base::Bind(&BluetoothGattChromeOSTest::NotifySessionCallback, | |
1108 base::Unretained(this)), | |
1109 base::Bind(&BluetoothGattChromeOSTest::ServiceErrorCallback, | |
1110 base::Unretained(this))); | |
1111 EXPECT_EQ(0, success_callback_count_); | |
1112 EXPECT_EQ(0, error_callback_count_); | |
1113 EXPECT_EQ(1, observer.gatt_characteristic_value_changed_count()); | |
1114 EXPECT_TRUE(update_sessions_.empty()); | |
1115 EXPECT_TRUE(characteristic->IsNotifying()); | |
1116 | |
1117 // Run the message loop. Notifications should begin. | |
1118 base::MessageLoop::current()->Run(); | |
1119 | |
1120 EXPECT_EQ(1, success_callback_count_); | |
1121 EXPECT_EQ(0, error_callback_count_); | |
1122 EXPECT_EQ(1, observer.gatt_characteristic_value_changed_count()); | |
1123 EXPECT_EQ(1U, update_sessions_.size()); | |
1124 EXPECT_TRUE(update_sessions_[0]->IsActive()); | |
1125 EXPECT_TRUE(characteristic->IsNotifying()); | |
1126 | |
1127 // Check that notifications are happening. | |
1128 base::MessageLoop::current()->Run(); | |
1129 EXPECT_GT(observer.gatt_characteristic_value_changed_count(), 1); | |
1130 | |
1131 // Request another session. This should return immediately. | |
1132 characteristic->StartNotifySession( | |
1133 base::Bind(&BluetoothGattChromeOSTest::NotifySessionCallback, | |
1134 base::Unretained(this)), | |
1135 base::Bind(&BluetoothGattChromeOSTest::ServiceErrorCallback, | |
1136 base::Unretained(this))); | |
1137 EXPECT_EQ(2, success_callback_count_); | |
1138 EXPECT_EQ(0, error_callback_count_); | |
1139 EXPECT_EQ(2U, update_sessions_.size()); | |
1140 EXPECT_TRUE(update_sessions_[0]->IsActive()); | |
1141 EXPECT_TRUE(update_sessions_[1]->IsActive()); | |
1142 EXPECT_TRUE(characteristic->IsNotifying()); | |
1143 | |
1144 // Hide the characteristic. The sessions should become inactive. | |
1145 fake_bluetooth_gatt_characteristic_client_->HideHeartRateCharacteristics(); | |
1146 EXPECT_EQ(2U, update_sessions_.size()); | |
1147 EXPECT_FALSE(update_sessions_[0]->IsActive()); | |
1148 EXPECT_FALSE(update_sessions_[1]->IsActive()); | |
1149 } | |
1150 | |
1151 TEST_F(BluetoothGattChromeOSTest, NotifySessionsMadeInactive) { | |
1152 fake_bluetooth_device_client_->CreateDevice( | |
1153 dbus::ObjectPath(bluez::FakeBluetoothAdapterClient::kAdapterPath), | |
1154 dbus::ObjectPath(bluez::FakeBluetoothDeviceClient::kLowEnergyPath)); | |
1155 BluetoothDevice* device = | |
1156 adapter_->GetDevice(bluez::FakeBluetoothDeviceClient::kLowEnergyAddress); | |
1157 ASSERT_TRUE(device); | |
1158 | |
1159 TestBluetoothAdapterObserver observer(adapter_); | |
1160 | |
1161 // Expose the fake Heart Rate service. This will asynchronously expose | |
1162 // characteristics. | |
1163 fake_bluetooth_gatt_service_client_->ExposeHeartRateService( | |
1164 dbus::ObjectPath(bluez::FakeBluetoothDeviceClient::kLowEnergyPath)); | |
1165 ASSERT_EQ(1, observer.gatt_service_added_count()); | |
1166 | |
1167 BluetoothGattService* service = | |
1168 device->GetGattService(observer.last_gatt_service_id()); | |
1169 | |
1170 EXPECT_EQ(0, observer.gatt_characteristic_value_changed_count()); | |
1171 | |
1172 // Run the message loop so that the characteristics appear. | |
1173 base::MessageLoop::current()->Run(); | |
1174 | |
1175 BluetoothGattCharacteristic* characteristic = service->GetCharacteristic( | |
1176 fake_bluetooth_gatt_characteristic_client_->GetHeartRateMeasurementPath() | |
1177 .value()); | |
1178 ASSERT_TRUE(characteristic); | |
1179 EXPECT_FALSE(characteristic->IsNotifying()); | |
1180 EXPECT_TRUE(update_sessions_.empty()); | |
1181 | |
1182 // Send several requests to start notifications. | |
1183 characteristic->StartNotifySession( | |
1184 base::Bind(&BluetoothGattChromeOSTest::NotifySessionCallback, | |
1185 base::Unretained(this)), | |
1186 base::Bind(&BluetoothGattChromeOSTest::ServiceErrorCallback, | |
1187 base::Unretained(this))); | |
1188 characteristic->StartNotifySession( | |
1189 base::Bind(&BluetoothGattChromeOSTest::NotifySessionCallback, | |
1190 base::Unretained(this)), | |
1191 base::Bind(&BluetoothGattChromeOSTest::ServiceErrorCallback, | |
1192 base::Unretained(this))); | |
1193 characteristic->StartNotifySession( | |
1194 base::Bind(&BluetoothGattChromeOSTest::NotifySessionCallback, | |
1195 base::Unretained(this)), | |
1196 base::Bind(&BluetoothGattChromeOSTest::ServiceErrorCallback, | |
1197 base::Unretained(this))); | |
1198 characteristic->StartNotifySession( | |
1199 base::Bind(&BluetoothGattChromeOSTest::NotifySessionCallback, | |
1200 base::Unretained(this)), | |
1201 base::Bind(&BluetoothGattChromeOSTest::ServiceErrorCallback, | |
1202 base::Unretained(this))); | |
1203 | |
1204 // The operation still hasn't completed but we should have received the first | |
1205 // notification. | |
1206 EXPECT_EQ(0, success_callback_count_); | |
1207 EXPECT_EQ(0, error_callback_count_); | |
1208 EXPECT_EQ(1, observer.gatt_characteristic_value_changed_count()); | |
1209 EXPECT_TRUE(characteristic->IsNotifying()); | |
1210 EXPECT_TRUE(update_sessions_.empty()); | |
1211 | |
1212 // Run the main loop. The initial call should complete. The queued calls | |
1213 // should succeed immediately. | |
1214 base::MessageLoop::current()->Run(); | |
1215 | |
1216 EXPECT_EQ(4, success_callback_count_); | |
1217 EXPECT_EQ(0, error_callback_count_); | |
1218 EXPECT_EQ(1, observer.gatt_characteristic_value_changed_count()); | |
1219 EXPECT_TRUE(characteristic->IsNotifying()); | |
1220 EXPECT_EQ(4U, update_sessions_.size()); | |
1221 | |
1222 for (int i = 0; i < 4; i++) | |
1223 EXPECT_TRUE(update_sessions_[0]->IsActive()); | |
1224 | |
1225 // Stop notifications directly through the client. The sessions should get | |
1226 // marked as inactive. | |
1227 fake_bluetooth_gatt_characteristic_client_->StopNotify( | |
1228 fake_bluetooth_gatt_characteristic_client_->GetHeartRateMeasurementPath(), | |
1229 base::Bind(&BluetoothGattChromeOSTest::SuccessCallback, | |
1230 base::Unretained(this)), | |
1231 base::Bind(&BluetoothGattChromeOSTest::DBusErrorCallback, | |
1232 base::Unretained(this))); | |
1233 EXPECT_EQ(5, success_callback_count_); | |
1234 EXPECT_EQ(0, error_callback_count_); | |
1235 EXPECT_FALSE(characteristic->IsNotifying()); | |
1236 EXPECT_EQ(4U, update_sessions_.size()); | |
1237 | |
1238 for (int i = 0; i < 4; i++) | |
1239 EXPECT_FALSE(update_sessions_[0]->IsActive()); | |
1240 | |
1241 // It should be possible to restart notifications and the call should reset | |
1242 // the session count and make a request through the client. | |
1243 update_sessions_.clear(); | |
1244 success_callback_count_ = 0; | |
1245 observer.Reset(); | |
1246 characteristic->StartNotifySession( | |
1247 base::Bind(&BluetoothGattChromeOSTest::NotifySessionCallback, | |
1248 base::Unretained(this)), | |
1249 base::Bind(&BluetoothGattChromeOSTest::ServiceErrorCallback, | |
1250 base::Unretained(this))); | |
1251 | |
1252 EXPECT_EQ(0, success_callback_count_); | |
1253 EXPECT_EQ(0, error_callback_count_); | |
1254 EXPECT_EQ(1, observer.gatt_characteristic_value_changed_count()); | |
1255 EXPECT_TRUE(characteristic->IsNotifying()); | |
1256 EXPECT_TRUE(update_sessions_.empty()); | |
1257 | |
1258 base::MessageLoop::current()->Run(); | |
1259 | |
1260 EXPECT_EQ(1, success_callback_count_); | |
1261 EXPECT_EQ(0, error_callback_count_); | |
1262 EXPECT_EQ(1, observer.gatt_characteristic_value_changed_count()); | |
1263 EXPECT_TRUE(characteristic->IsNotifying()); | |
1264 EXPECT_EQ(1U, update_sessions_.size()); | |
1265 EXPECT_TRUE(update_sessions_[0]->IsActive()); | |
1266 } | |
1267 | |
1268 } // namespace chromeos | |
OLD | NEW |