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