1 // Copyright (c) 2014 The Chromium OS 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 <gtest/gtest.h>
6
7 extern "C" {
8 #include "cras_bt_constants.h"
9 #include "cras_bt_device.h"
10 #include "cras_bt_io.h"
11 #include "cras_bt_log.h"
12 #include "cras_iodev.h"
13 #include "cras_main_message.h"
14
15 #define FAKE_OBJ_PATH "/obj/path"
16 }
17
18 static const unsigned int CONN_WATCH_MAX_RETRIES = 30;
19
20 static struct cras_iodev* cras_bt_io_create_profile_ret;
21 static struct cras_iodev* cras_bt_io_append_btio_val;
22 static struct cras_ionode* cras_bt_io_get_profile_ret;
23 static unsigned int cras_bt_io_create_called;
24 static unsigned int cras_bt_io_append_called;
25 static unsigned int cras_bt_io_remove_called;
26 static unsigned int cras_bt_io_destroy_called;
27 static enum cras_bt_device_profile cras_bt_io_create_profile_val;
28 static enum cras_bt_device_profile cras_bt_io_append_profile_val;
29 static unsigned int cras_bt_io_try_remove_ret;
30
31 static cras_main_message* cras_main_message_send_msg;
32 static cras_message_callback cras_main_message_add_handler_callback;
33 static void* cras_main_message_add_handler_callback_data;
34 static int cras_tm_create_timer_called;
35 static int cras_tm_cancel_timer_called;
36 static int cras_a2dp_start_called;
37 static int cras_a2dp_suspend_connected_device_called;
38 static int cras_hfp_ag_remove_conflict_called;
39 static int cras_hfp_ag_start_called;
40 static int cras_hfp_ag_suspend_connected_device_called;
41 static void (*cras_tm_create_timer_cb)(struct cras_timer* t, void* data);
42 static void* cras_tm_create_timer_cb_data;
43 static int dbus_message_new_method_call_called;
44 static const char* dbus_message_new_method_call_method;
45 static struct cras_bt_device* cras_a2dp_connected_device_ret;
46 static struct cras_bt_device* cras_a2dp_suspend_connected_device_dev;
47 static struct cras_timer* cras_tm_cancel_timer_arg;
48 static struct cras_timer* cras_tm_create_timer_ret;
49 static size_t cras_iodev_set_node_plugged_called;
50 static int cras_iodev_set_node_plugged_value;
51
52 struct MockDBusMessage {
53 int type;
54 void* value;
55 MockDBusMessage* next;
56 MockDBusMessage* recurse;
57 };
58
ResetStubData()59 void ResetStubData() {
60 cras_bt_io_get_profile_ret = NULL;
61 cras_bt_io_create_called = 0;
62 cras_bt_io_append_called = 0;
63 cras_bt_io_remove_called = 0;
64 cras_bt_io_destroy_called = 0;
65 cras_bt_io_try_remove_ret = 0;
66 cras_main_message_send_msg = NULL;
67 cras_tm_create_timer_called = 0;
68 cras_tm_cancel_timer_called = 0;
69 cras_a2dp_start_called = 0;
70 cras_a2dp_suspend_connected_device_called = 0;
71 cras_hfp_ag_remove_conflict_called = 0;
72 cras_hfp_ag_start_called = 0;
73 cras_hfp_ag_suspend_connected_device_called = 0;
74 dbus_message_new_method_call_method = NULL;
75 dbus_message_new_method_call_called = 0;
76 cras_a2dp_connected_device_ret = NULL;
77 cras_iodev_set_node_plugged_called = 0;
78 }
79
FreeMockDBusMessage(MockDBusMessage * head)80 static void FreeMockDBusMessage(MockDBusMessage* head) {
81 if (head->next != NULL)
82 FreeMockDBusMessage(head->next);
83 if (head->recurse != NULL)
84 FreeMockDBusMessage(head->recurse);
85 if (head->type == DBUS_TYPE_STRING)
86 free((char*)head->value);
87 delete head;
88 }
89
NewMockDBusConnectedMessage(long connected)90 static struct MockDBusMessage* NewMockDBusConnectedMessage(long connected) {
91 MockDBusMessage* msg = new MockDBusMessage{DBUS_TYPE_ARRAY, NULL};
92 MockDBusMessage* dict =
93 new MockDBusMessage{DBUS_TYPE_STRING, (void*)strdup("Connected")};
94 MockDBusMessage* variant =
95 new MockDBusMessage{DBUS_TYPE_BOOLEAN, (void*)connected};
96
97 msg->recurse = dict;
98 dict->next = new MockDBusMessage{DBUS_TYPE_INVALID, NULL};
99 dict->next->recurse = variant;
100 return msg;
101 }
102
103 namespace {
104
105 class BtDeviceTestSuite : public testing::Test {
106 protected:
SetUp()107 virtual void SetUp() {
108 ResetStubData();
109 bt_iodev1.direction = CRAS_STREAM_OUTPUT;
110 bt_iodev1.update_active_node = update_active_node;
111 bt_iodev2.direction = CRAS_STREAM_INPUT;
112 bt_iodev2.update_active_node = update_active_node;
113 d1_.direction = CRAS_STREAM_OUTPUT;
114 d1_.update_active_node = update_active_node;
115 d2_.direction = CRAS_STREAM_OUTPUT;
116 d2_.update_active_node = update_active_node;
117 d3_.direction = CRAS_STREAM_INPUT;
118 d3_.update_active_node = update_active_node;
119 btlog = cras_bt_event_log_init();
120 }
121
TearDown()122 virtual void TearDown() {
123 if (cras_main_message_send_msg)
124 free(cras_main_message_send_msg);
125 cras_bt_event_log_deinit(btlog);
126 }
127
update_active_node(struct cras_iodev * iodev,unsigned node_idx,unsigned dev_enabled)128 static void update_active_node(struct cras_iodev* iodev,
129 unsigned node_idx,
130 unsigned dev_enabled) {}
131
132 struct cras_iodev bt_iodev1;
133 struct cras_iodev bt_iodev2;
134 struct cras_iodev d3_;
135 struct cras_iodev d2_;
136 struct cras_iodev d1_;
137 };
138
TEST(BtDeviceSuite,CreateBtDevice)139 TEST(BtDeviceSuite, CreateBtDevice) {
140 struct cras_bt_device* device;
141
142 device = cras_bt_device_create(NULL, FAKE_OBJ_PATH);
143 EXPECT_NE((void*)NULL, device);
144
145 device = cras_bt_device_get(FAKE_OBJ_PATH);
146 EXPECT_NE((void*)NULL, device);
147
148 cras_bt_device_remove(device);
149 device = cras_bt_device_get(FAKE_OBJ_PATH);
150 EXPECT_EQ((void*)NULL, device);
151 }
152
TEST_F(BtDeviceTestSuite,AppendRmIodev)153 TEST_F(BtDeviceTestSuite, AppendRmIodev) {
154 struct cras_bt_device* device;
155 device = cras_bt_device_create(NULL, FAKE_OBJ_PATH);
156 bt_iodev1.nodes = reinterpret_cast<struct cras_ionode*>(0x123);
157 cras_bt_io_create_profile_ret = &bt_iodev1;
158 cras_bt_device_append_iodev(device, &d1_, CRAS_BT_DEVICE_PROFILE_A2DP_SOURCE);
159 EXPECT_EQ(1, cras_bt_io_create_called);
160 EXPECT_EQ(0, cras_bt_io_append_called);
161 EXPECT_EQ(CRAS_BT_DEVICE_PROFILE_A2DP_SOURCE, cras_bt_io_create_profile_val);
162 cras_bt_device_set_active_profile(device, CRAS_BT_DEVICE_PROFILE_A2DP_SOURCE);
163
164 cras_bt_device_append_iodev(device, &d2_,
165 CRAS_BT_DEVICE_PROFILE_HFP_AUDIOGATEWAY);
166 EXPECT_EQ(1, cras_bt_io_create_called);
167 EXPECT_EQ(1, cras_bt_io_append_called);
168 EXPECT_EQ(CRAS_BT_DEVICE_PROFILE_HFP_AUDIOGATEWAY,
169 cras_bt_io_append_profile_val);
170 EXPECT_EQ(&bt_iodev1, cras_bt_io_append_btio_val);
171
172 /* Test HFP disconnected and switch to A2DP. */
173 cras_bt_io_get_profile_ret = bt_iodev1.nodes;
174 cras_bt_io_try_remove_ret = CRAS_BT_DEVICE_PROFILE_A2DP_SOURCE;
175 cras_bt_device_set_active_profile(device,
176 CRAS_BT_DEVICE_PROFILE_HFP_AUDIOGATEWAY);
177 cras_bt_device_rm_iodev(device, &d2_);
178 EXPECT_EQ(1, cras_bt_io_remove_called);
179 EXPECT_EQ(1, cras_iodev_set_node_plugged_called);
180 EXPECT_EQ(0, cras_iodev_set_node_plugged_value);
181
182 /* Test A2DP disconnection will cause bt_io destroy. */
183 cras_bt_io_try_remove_ret = 0;
184 cras_bt_device_rm_iodev(device, &d1_);
185 EXPECT_EQ(1, cras_bt_io_remove_called);
186 EXPECT_EQ(1, cras_bt_io_destroy_called);
187 EXPECT_EQ(0, cras_bt_device_get_active_profile(device));
188 EXPECT_EQ(2, cras_iodev_set_node_plugged_called);
189 EXPECT_EQ(0, cras_iodev_set_node_plugged_value);
190 cras_bt_device_remove(device);
191 }
192
TEST_F(BtDeviceTestSuite,SwitchProfile)193 TEST_F(BtDeviceTestSuite, SwitchProfile) {
194 struct cras_bt_device* device;
195
196 ResetStubData();
197 device = cras_bt_device_create(NULL, FAKE_OBJ_PATH);
198 cras_bt_io_create_profile_ret = &bt_iodev1;
199 cras_bt_device_append_iodev(device, &d1_, CRAS_BT_DEVICE_PROFILE_A2DP_SOURCE);
200 cras_bt_io_create_profile_ret = &bt_iodev2;
201 cras_bt_device_append_iodev(device, &d3_,
202 CRAS_BT_DEVICE_PROFILE_HFP_AUDIOGATEWAY);
203
204 cras_bt_device_start_monitor();
205 cras_bt_device_switch_profile_enable_dev(device, &bt_iodev1);
206
207 /* Two bt iodevs were all active. */
208 cras_main_message_add_handler_callback(
209 cras_main_message_send_msg, cras_main_message_add_handler_callback_data);
210
211 /* One bt iodev was active, the other was not. */
212 cras_bt_device_switch_profile_enable_dev(device, &bt_iodev2);
213 cras_main_message_add_handler_callback(
214 cras_main_message_send_msg, cras_main_message_add_handler_callback_data);
215
216 /* Output bt iodev wasn't active, close the active input iodev. */
217 cras_bt_device_switch_profile(device, &bt_iodev2);
218 cras_main_message_add_handler_callback(
219 cras_main_message_send_msg, cras_main_message_add_handler_callback_data);
220 cras_bt_device_remove(device);
221 }
222
TEST_F(BtDeviceTestSuite,SetDeviceConnectedA2dpOnly)223 TEST_F(BtDeviceTestSuite, SetDeviceConnectedA2dpOnly) {
224 struct cras_bt_device* device;
225 struct MockDBusMessage *msg_root, *cur;
226 ResetStubData();
227
228 device = cras_bt_device_create(NULL, FAKE_OBJ_PATH);
229 EXPECT_NE((void*)NULL, device);
230
231 cras_bt_device_set_supported_profiles(device,
232 CRAS_BT_DEVICE_PROFILE_A2DP_SINK);
233
234 cur = msg_root = NewMockDBusConnectedMessage(1);
235 cras_bt_device_update_properties(device, (DBusMessageIter*)&cur, NULL);
236 EXPECT_EQ(1, cras_tm_create_timer_called);
237 EXPECT_NE((void*)NULL, cras_tm_create_timer_cb);
238
239 /* Schedule another timer, if A2DP not yet configured. */
240 cras_tm_create_timer_cb(NULL, cras_tm_create_timer_cb_data);
241 EXPECT_EQ(2, cras_tm_create_timer_called);
242
243 /* ConnectProfile must not be called, since this is A2DP only case. */
244 EXPECT_EQ(0, dbus_message_new_method_call_called);
245
246 cras_bt_device_a2dp_configured(device);
247
248 /* Prepate the iodev created by cras_a2dp_start. */
249 cras_bt_io_create_profile_ret = &bt_iodev1;
250 cras_bt_device_append_iodev(device, &d1_, CRAS_BT_DEVICE_PROFILE_A2DP_SOURCE);
251
252 cras_tm_create_timer_cb(NULL, cras_tm_create_timer_cb_data);
253 EXPECT_EQ(2, cras_tm_create_timer_called);
254 EXPECT_EQ(1, cras_hfp_ag_remove_conflict_called);
255 EXPECT_EQ(1, cras_a2dp_start_called);
256 EXPECT_EQ(1, cras_iodev_set_node_plugged_called);
257 EXPECT_EQ(1, cras_iodev_set_node_plugged_value);
258
259 cras_bt_device_remove(device);
260 FreeMockDBusMessage(msg_root);
261 }
262
TEST_F(BtDeviceTestSuite,SetDeviceConnectedHfpHspOnly)263 TEST_F(BtDeviceTestSuite, SetDeviceConnectedHfpHspOnly) {
264 struct cras_bt_device* device;
265 struct MockDBusMessage *msg_root, *cur;
266
267 ResetStubData();
268
269 device = cras_bt_device_create(NULL, FAKE_OBJ_PATH);
270 EXPECT_NE((void*)NULL, device);
271
272 cras_bt_device_set_supported_profiles(
273 device, CRAS_BT_DEVICE_PROFILE_HSP_HEADSET |
274 CRAS_BT_DEVICE_PROFILE_HFP_HANDSFREE);
275
276 cur = msg_root = NewMockDBusConnectedMessage(1);
277 cras_bt_device_update_properties(device, (DBusMessageIter*)&cur, NULL);
278 EXPECT_EQ(1, cras_tm_create_timer_called);
279 EXPECT_NE((void*)NULL, cras_tm_create_timer_cb);
280
281 /* Schedule another timer, if HFP AG not yet intialized. */
282 cras_tm_create_timer_cb(NULL, cras_tm_create_timer_cb_data);
283 EXPECT_EQ(2, cras_tm_create_timer_called);
284
285 /* ConnectProfile must not be called, since this is HFP only case. */
286 EXPECT_EQ(0, dbus_message_new_method_call_called);
287
288 cras_bt_device_audio_gateway_initialized(device);
289
290 /* Prepate the iodev created by ag initialization. */
291 cras_bt_io_create_profile_ret = &bt_iodev2;
292 cras_bt_device_append_iodev(device, &d3_,
293 CRAS_BT_DEVICE_PROFILE_HFP_AUDIOGATEWAY);
294
295 cras_tm_create_timer_cb(NULL, cras_tm_create_timer_cb_data);
296 EXPECT_EQ(2, cras_tm_create_timer_called);
297 EXPECT_EQ(1, cras_hfp_ag_remove_conflict_called);
298 EXPECT_EQ(1, cras_hfp_ag_start_called);
299 EXPECT_EQ(1, cras_iodev_set_node_plugged_called);
300 EXPECT_EQ(1, cras_iodev_set_node_plugged_value);
301
302 cras_bt_device_remove(device);
303 FreeMockDBusMessage(msg_root);
304 }
305
TEST_F(BtDeviceTestSuite,SetDeviceConnectedA2dpHfpHsp)306 TEST_F(BtDeviceTestSuite, SetDeviceConnectedA2dpHfpHsp) {
307 struct cras_bt_device* device;
308 struct MockDBusMessage *msg_root, *cur;
309
310 ResetStubData();
311
312 device = cras_bt_device_create(NULL, FAKE_OBJ_PATH);
313 EXPECT_NE((void*)NULL, device);
314
315 cras_bt_device_set_supported_profiles(
316 device, CRAS_BT_DEVICE_PROFILE_A2DP_SINK |
317 CRAS_BT_DEVICE_PROFILE_HSP_HEADSET |
318 CRAS_BT_DEVICE_PROFILE_HFP_HANDSFREE);
319
320 cur = msg_root = NewMockDBusConnectedMessage(1);
321 cras_bt_device_update_properties(device, (DBusMessageIter*)&cur, NULL);
322 EXPECT_EQ(1, cras_tm_create_timer_called);
323 EXPECT_NE((void*)NULL, cras_tm_create_timer_cb);
324
325 /* Schedule another timer, if not HFP nor A2DP is ready. */
326 cras_tm_create_timer_cb(NULL, cras_tm_create_timer_cb_data);
327 EXPECT_EQ(2, cras_tm_create_timer_called);
328
329 /* ConnectProfile must not be called, since the first profile connection
330 * should be initiated by Bluez.
331 */
332 EXPECT_EQ(0, dbus_message_new_method_call_called);
333
334 cras_bt_device_audio_gateway_initialized(device);
335
336 /* Schedule another timer, because A2DP is not ready. */
337 cras_tm_create_timer_cb(NULL, cras_tm_create_timer_cb_data);
338 EXPECT_EQ(3, cras_tm_create_timer_called);
339 EXPECT_EQ(0, cras_hfp_ag_start_called);
340
341 /* ConnectProfile should be called to connect A2DP, since HFP is connected */
342 EXPECT_EQ(1, dbus_message_new_method_call_called);
343 EXPECT_STREQ("ConnectProfile", dbus_message_new_method_call_method);
344
345 cras_bt_device_a2dp_configured(device);
346
347 cras_tm_create_timer_cb(NULL, cras_tm_create_timer_cb_data);
348 EXPECT_EQ(3, cras_tm_create_timer_called);
349 EXPECT_EQ(1, cras_hfp_ag_remove_conflict_called);
350 EXPECT_EQ(1, cras_a2dp_start_called);
351 EXPECT_EQ(1, cras_hfp_ag_start_called);
352
353 cras_bt_device_remove(device);
354 FreeMockDBusMessage(msg_root);
355 }
356
TEST_F(BtDeviceTestSuite,DevConnectedConflictCheck)357 TEST_F(BtDeviceTestSuite, DevConnectedConflictCheck) {
358 struct cras_bt_device* device;
359 struct MockDBusMessage *msg_root, *cur;
360
361 ResetStubData();
362
363 device = cras_bt_device_create(NULL, FAKE_OBJ_PATH);
364 EXPECT_NE((void*)NULL, device);
365
366 cras_bt_device_set_supported_profiles(
367 device, CRAS_BT_DEVICE_PROFILE_A2DP_SINK |
368 CRAS_BT_DEVICE_PROFILE_HSP_HEADSET |
369 CRAS_BT_DEVICE_PROFILE_HFP_HANDSFREE);
370
371 cur = msg_root = NewMockDBusConnectedMessage(1);
372 cras_bt_device_update_properties(device, (DBusMessageIter*)&cur, NULL);
373 cras_bt_device_audio_gateway_initialized(device);
374 cras_bt_device_a2dp_configured(device);
375 EXPECT_EQ(1, cras_tm_create_timer_called);
376
377 /* Fake that a different device already connected with A2DP */
378 cras_a2dp_connected_device_ret =
379 reinterpret_cast<struct cras_bt_device*>(0x99);
380 cras_tm_create_timer_cb(NULL, cras_tm_create_timer_cb_data);
381 EXPECT_EQ(1, cras_tm_create_timer_called);
382
383 /* Expect check conflict in HFP AG and A2DP. */
384 EXPECT_EQ(1, cras_hfp_ag_remove_conflict_called);
385 EXPECT_EQ(1, cras_a2dp_suspend_connected_device_called);
386 EXPECT_EQ(cras_a2dp_suspend_connected_device_dev,
387 cras_a2dp_connected_device_ret);
388
389 EXPECT_EQ(1, cras_a2dp_start_called);
390 EXPECT_EQ(1, cras_hfp_ag_start_called);
391
392 cras_bt_device_remove(device);
393 FreeMockDBusMessage(msg_root);
394 }
395
TEST_F(BtDeviceTestSuite,A2dpDropped)396 TEST_F(BtDeviceTestSuite, A2dpDropped) {
397 struct cras_bt_device* device;
398 struct MockDBusMessage *msg_root, *cur;
399
400 ResetStubData();
401
402 device = cras_bt_device_create(NULL, FAKE_OBJ_PATH);
403 EXPECT_NE((void*)NULL, device);
404
405 cras_bt_device_set_supported_profiles(
406 device, CRAS_BT_DEVICE_PROFILE_A2DP_SINK |
407 CRAS_BT_DEVICE_PROFILE_HSP_HEADSET |
408 CRAS_BT_DEVICE_PROFILE_HFP_HANDSFREE);
409
410 cur = msg_root = NewMockDBusConnectedMessage(1);
411 cras_bt_device_update_properties(device, (DBusMessageIter*)&cur, NULL);
412 cras_bt_device_audio_gateway_initialized(device);
413 cras_bt_device_a2dp_configured(device);
414 EXPECT_EQ(1, cras_tm_create_timer_called);
415 EXPECT_NE((void*)NULL, cras_tm_create_timer_cb);
416
417 cras_bt_device_notify_profile_dropped(device,
418 CRAS_BT_DEVICE_PROFILE_A2DP_SINK);
419 EXPECT_EQ(2, cras_tm_create_timer_called);
420
421 /* Expect suspend timer is scheduled. */
422 cras_tm_create_timer_cb(NULL, cras_tm_create_timer_cb_data);
423 EXPECT_EQ(1, cras_a2dp_suspend_connected_device_called);
424 EXPECT_EQ(1, cras_hfp_ag_suspend_connected_device_called);
425 EXPECT_EQ(1, dbus_message_new_method_call_called);
426 EXPECT_STREQ("Disconnect", dbus_message_new_method_call_method);
427
428 cras_bt_device_remove(device);
429 FreeMockDBusMessage(msg_root);
430 }
431
TEST_F(BtDeviceTestSuite,DevConnectDisconnectBackToBack)432 TEST_F(BtDeviceTestSuite, DevConnectDisconnectBackToBack) {
433 struct cras_bt_device* device;
434 struct MockDBusMessage *msg_root, *cur;
435
436 ResetStubData();
437
438 device = cras_bt_device_create(NULL, FAKE_OBJ_PATH);
439 EXPECT_NE((void*)NULL, device);
440
441 cras_bt_device_set_supported_profiles(
442 device, CRAS_BT_DEVICE_PROFILE_A2DP_SINK |
443 CRAS_BT_DEVICE_PROFILE_HSP_HEADSET |
444 CRAS_BT_DEVICE_PROFILE_HFP_HANDSFREE);
445
446 cur = msg_root = NewMockDBusConnectedMessage(1);
447 cras_bt_device_update_properties(device, (DBusMessageIter*)&cur, NULL);
448 EXPECT_EQ(1, cras_tm_create_timer_called);
449 EXPECT_NE((void*)NULL, cras_tm_create_timer_cb);
450 FreeMockDBusMessage(msg_root);
451
452 cras_bt_device_a2dp_configured(device);
453 cras_bt_device_audio_gateway_initialized(device);
454
455 /* Expect suspend timer is scheduled. */
456 cras_tm_create_timer_ret = reinterpret_cast<struct cras_timer*>(0x101);
457 cras_bt_device_notify_profile_dropped(device,
458 CRAS_BT_DEVICE_PROFILE_A2DP_SINK);
459 EXPECT_EQ(2, cras_tm_create_timer_called);
460 /* Another profile drop won't schedule another timer because one is
461 * already armed. */
462 EXPECT_NE((void*)NULL, cras_tm_create_timer_cb);
463 cras_bt_device_notify_profile_dropped(device,
464 CRAS_BT_DEVICE_PROFILE_HFP_HANDSFREE);
465 EXPECT_EQ(2, cras_tm_create_timer_called);
466
467 cur = msg_root = NewMockDBusConnectedMessage(0);
468 cras_bt_device_update_properties(device, (DBusMessageIter*)&cur, NULL);
469
470 /* When BlueZ reports headset disconnection, cancel the pending timer. */
471 EXPECT_EQ(cras_tm_cancel_timer_called, 1);
472 EXPECT_EQ(cras_tm_cancel_timer_arg, (void*)0x101);
473 FreeMockDBusMessage(msg_root);
474
475 /* Headset connects again. */
476 cur = msg_root = NewMockDBusConnectedMessage(1);
477 cras_bt_device_update_properties(device, (DBusMessageIter*)&cur, NULL);
478 EXPECT_EQ(3, cras_tm_create_timer_called);
479 EXPECT_NE((void*)NULL, cras_tm_create_timer_cb);
480 FreeMockDBusMessage(msg_root);
481
482 /* Headset disconnects, later profile drop events shouldn't trigger
483 * suspend timer because headset is already in disconnected stats.
484 */
485 cur = msg_root = NewMockDBusConnectedMessage(0);
486 cras_bt_device_update_properties(device, (DBusMessageIter*)&cur, NULL);
487 FreeMockDBusMessage(msg_root);
488
489 cras_tm_create_timer_called = 0;
490 cras_bt_device_notify_profile_dropped(device,
491 CRAS_BT_DEVICE_PROFILE_A2DP_SINK);
492 EXPECT_EQ(0, cras_tm_create_timer_called);
493 cras_bt_device_notify_profile_dropped(device,
494 CRAS_BT_DEVICE_PROFILE_HFP_HANDSFREE);
495 EXPECT_EQ(0, cras_tm_create_timer_called);
496
497 cras_bt_device_remove(device);
498 }
499
TEST_F(BtDeviceTestSuite,ConnectionWatchTimeout)500 TEST_F(BtDeviceTestSuite, ConnectionWatchTimeout) {
501 struct cras_bt_device* device;
502 struct MockDBusMessage *msg_root, *cur;
503
504 ResetStubData();
505
506 device = cras_bt_device_create(NULL, FAKE_OBJ_PATH);
507 EXPECT_NE((void*)NULL, device);
508
509 cras_bt_device_set_supported_profiles(
510 device, CRAS_BT_DEVICE_PROFILE_A2DP_SINK |
511 CRAS_BT_DEVICE_PROFILE_HSP_HEADSET |
512 CRAS_BT_DEVICE_PROFILE_HFP_HANDSFREE);
513
514 cur = msg_root = NewMockDBusConnectedMessage(1);
515 cras_bt_device_update_properties(device, (DBusMessageIter*)&cur, NULL);
516 EXPECT_EQ(1, cras_tm_create_timer_called);
517 EXPECT_NE((void*)NULL, cras_tm_create_timer_cb);
518
519 cras_bt_device_a2dp_configured(device);
520
521 for (unsigned int i = 0; i < CONN_WATCH_MAX_RETRIES; i++) {
522 cras_tm_create_timer_cb(NULL, cras_tm_create_timer_cb_data);
523 EXPECT_EQ(i + 2, cras_tm_create_timer_called);
524 EXPECT_EQ(0, cras_a2dp_start_called);
525 EXPECT_EQ(0, cras_hfp_ag_start_called);
526 EXPECT_EQ(0, cras_hfp_ag_remove_conflict_called);
527 }
528
529 dbus_message_new_method_call_called = 0;
530
531 /* Expect suspend timer is scheduled. */
532 cras_tm_create_timer_cb(NULL, cras_tm_create_timer_cb_data);
533 EXPECT_EQ(1, cras_a2dp_suspend_connected_device_called);
534 EXPECT_EQ(1, cras_hfp_ag_suspend_connected_device_called);
535 EXPECT_EQ(1, dbus_message_new_method_call_called);
536 EXPECT_STREQ("Disconnect", dbus_message_new_method_call_method);
537
538 cras_bt_device_remove(device);
539 FreeMockDBusMessage(msg_root);
540 }
541
542 /* Stubs */
543 extern "C" {
544
545 struct cras_bt_event_log* btlog;
546
547 /* From bt_io */
cras_bt_io_create(struct cras_bt_device * device,struct cras_iodev * dev,enum cras_bt_device_profile profile)548 struct cras_iodev* cras_bt_io_create(struct cras_bt_device* device,
549 struct cras_iodev* dev,
550 enum cras_bt_device_profile profile) {
551 cras_bt_io_create_called++;
552 cras_bt_io_create_profile_val = profile;
553 return cras_bt_io_create_profile_ret;
554 }
cras_bt_io_destroy(struct cras_iodev * bt_iodev)555 void cras_bt_io_destroy(struct cras_iodev* bt_iodev) {
556 cras_bt_io_destroy_called++;
557 }
cras_bt_io_get_profile(struct cras_iodev * bt_iodev,enum cras_bt_device_profile profile)558 struct cras_ionode* cras_bt_io_get_profile(
559 struct cras_iodev* bt_iodev,
560 enum cras_bt_device_profile profile) {
561 return cras_bt_io_get_profile_ret;
562 }
cras_bt_io_append(struct cras_iodev * bt_iodev,struct cras_iodev * dev,enum cras_bt_device_profile profile)563 int cras_bt_io_append(struct cras_iodev* bt_iodev,
564 struct cras_iodev* dev,
565 enum cras_bt_device_profile profile) {
566 cras_bt_io_append_called++;
567 cras_bt_io_append_profile_val = profile;
568 cras_bt_io_append_btio_val = bt_iodev;
569 return 0;
570 }
cras_bt_io_on_profile(struct cras_iodev * bt_iodev,enum cras_bt_device_profile profile)571 int cras_bt_io_on_profile(struct cras_iodev* bt_iodev,
572 enum cras_bt_device_profile profile) {
573 return 0;
574 }
cras_bt_io_try_remove(struct cras_iodev * bt_iodev,struct cras_iodev * dev)575 unsigned int cras_bt_io_try_remove(struct cras_iodev* bt_iodev,
576 struct cras_iodev* dev) {
577 return cras_bt_io_try_remove_ret;
578 }
cras_bt_io_remove(struct cras_iodev * bt_iodev,struct cras_iodev * dev)579 int cras_bt_io_remove(struct cras_iodev* bt_iodev, struct cras_iodev* dev) {
580 cras_bt_io_remove_called++;
581 return 0;
582 }
583
584 /* From bt_adapter */
cras_bt_adapter_get(const char * object_path)585 struct cras_bt_adapter* cras_bt_adapter_get(const char* object_path) {
586 return NULL;
587 }
cras_bt_adapter_address(const struct cras_bt_adapter * adapter)588 const char* cras_bt_adapter_address(const struct cras_bt_adapter* adapter) {
589 return NULL;
590 }
591
cras_bt_adapter_on_usb(struct cras_bt_adapter * adapter)592 int cras_bt_adapter_on_usb(struct cras_bt_adapter* adapter) {
593 return 1;
594 }
595
596 /* From bt_profile */
cras_bt_profile_on_device_disconnected(struct cras_bt_device * device)597 void cras_bt_profile_on_device_disconnected(struct cras_bt_device* device) {}
598
599 /* From hfp_ag_profile */
cras_hfp_ag_get_slc(struct cras_bt_device * device)600 struct hfp_slc_handle* cras_hfp_ag_get_slc(struct cras_bt_device* device) {
601 return NULL;
602 }
603
cras_hfp_ag_suspend_connected_device(struct cras_bt_device * device)604 void cras_hfp_ag_suspend_connected_device(struct cras_bt_device* device) {
605 cras_hfp_ag_suspend_connected_device_called++;
606 }
607
cras_a2dp_suspend_connected_device(struct cras_bt_device * device)608 void cras_a2dp_suspend_connected_device(struct cras_bt_device* device) {
609 cras_a2dp_suspend_connected_device_called++;
610 cras_a2dp_suspend_connected_device_dev = device;
611 }
612
cras_a2dp_start(struct cras_bt_device * device)613 void cras_a2dp_start(struct cras_bt_device* device) {
614 cras_a2dp_start_called++;
615 }
616
cras_a2dp_connected_device()617 struct cras_bt_device* cras_a2dp_connected_device() {
618 return cras_a2dp_connected_device_ret;
619 }
620
cras_hfp_ag_remove_conflict(struct cras_bt_device * device)621 int cras_hfp_ag_remove_conflict(struct cras_bt_device* device) {
622 cras_hfp_ag_remove_conflict_called++;
623 return 0;
624 }
625
cras_hfp_ag_start(struct cras_bt_device * device)626 int cras_hfp_ag_start(struct cras_bt_device* device) {
627 cras_hfp_ag_start_called++;
628 return 0;
629 }
630
cras_hfp_ag_suspend()631 void cras_hfp_ag_suspend() {}
632
633 /* From hfp_slc */
hfp_event_speaker_gain(struct hfp_slc_handle * handle,int gain)634 int hfp_event_speaker_gain(struct hfp_slc_handle* handle, int gain) {
635 return 0;
636 }
637
638 /* From iodev_list */
639
cras_iodev_open(struct cras_iodev * dev,unsigned int cb_level,const struct cras_audio_format * fmt)640 int cras_iodev_open(struct cras_iodev* dev,
641 unsigned int cb_level,
642 const struct cras_audio_format* fmt) {
643 return 0;
644 }
645
cras_iodev_close(struct cras_iodev * dev)646 int cras_iodev_close(struct cras_iodev* dev) {
647 return 0;
648 }
649
cras_iodev_set_node_plugged(struct cras_ionode * ionode,int plugged)650 void cras_iodev_set_node_plugged(struct cras_ionode* ionode, int plugged) {
651 cras_iodev_set_node_plugged_called++;
652 cras_iodev_set_node_plugged_value = plugged;
653 }
654
cras_iodev_list_dev_is_enabled(const struct cras_iodev * dev)655 int cras_iodev_list_dev_is_enabled(const struct cras_iodev* dev) {
656 return 0;
657 }
658
cras_iodev_list_suspend_dev(struct cras_iodev * dev)659 void cras_iodev_list_suspend_dev(struct cras_iodev* dev) {}
660
cras_iodev_list_resume_dev(struct cras_iodev * dev)661 void cras_iodev_list_resume_dev(struct cras_iodev* dev) {}
662
cras_iodev_list_notify_node_volume(struct cras_ionode * node)663 void cras_iodev_list_notify_node_volume(struct cras_ionode* node) {}
664
cras_main_message_send(struct cras_main_message * msg)665 int cras_main_message_send(struct cras_main_message* msg) {
666 // cras_main_message is a local variable from caller, we should allocate
667 // memory from heap and copy its data
668 if (cras_main_message_send_msg)
669 free(cras_main_message_send_msg);
670 cras_main_message_send_msg =
671 (struct cras_main_message*)calloc(1, msg->length);
672 memcpy((void*)cras_main_message_send_msg, (void*)msg, msg->length);
673 return 0;
674 }
675
cras_main_message_add_handler(enum CRAS_MAIN_MESSAGE_TYPE type,cras_message_callback callback,void * callback_data)676 int cras_main_message_add_handler(enum CRAS_MAIN_MESSAGE_TYPE type,
677 cras_message_callback callback,
678 void* callback_data) {
679 cras_main_message_add_handler_callback = callback;
680 cras_main_message_add_handler_callback_data = callback_data;
681 return 0;
682 }
683
684 /* From cras_system_state */
cras_system_state_get_tm()685 struct cras_tm* cras_system_state_get_tm() {
686 return NULL;
687 }
688
689 /* From cras_tm */
cras_tm_create_timer(struct cras_tm * tm,unsigned int ms,void (* cb)(struct cras_timer * t,void * data),void * cb_data)690 struct cras_timer* cras_tm_create_timer(struct cras_tm* tm,
691 unsigned int ms,
692 void (*cb)(struct cras_timer* t,
693 void* data),
694 void* cb_data) {
695 cras_tm_create_timer_called++;
696 cras_tm_create_timer_cb = cb;
697 cras_tm_create_timer_cb_data = cb_data;
698 return cras_tm_create_timer_ret;
699 }
700
cras_tm_cancel_timer(struct cras_tm * tm,struct cras_timer * t)701 void cras_tm_cancel_timer(struct cras_tm* tm, struct cras_timer* t) {
702 cras_tm_cancel_timer_called++;
703 cras_tm_cancel_timer_arg = t;
704 }
705
dbus_message_new_method_call(const char * destination,const char * path,const char * iface,const char * method)706 DBusMessage* dbus_message_new_method_call(const char* destination,
707 const char* path,
708 const char* iface,
709 const char* method) {
710 dbus_message_new_method_call_called++;
711 dbus_message_new_method_call_method = method;
712 return reinterpret_cast<DBusMessage*>(0x456);
713 }
714
dbus_message_unref(DBusMessage * message)715 void dbus_message_unref(DBusMessage* message) {}
716
dbus_message_append_args(DBusMessage * message,int first_arg_type,...)717 dbus_bool_t dbus_message_append_args(DBusMessage* message,
718 int first_arg_type,
719 ...) {
720 return true;
721 }
722
dbus_connection_send_with_reply(DBusConnection * connection,DBusMessage * message,DBusPendingCall ** pending_return,int timeout_milliseconds)723 dbus_bool_t dbus_connection_send_with_reply(DBusConnection* connection,
724 DBusMessage* message,
725 DBusPendingCall** pending_return,
726 int timeout_milliseconds) {
727 return true;
728 }
729
dbus_pending_call_set_notify(DBusPendingCall * pending,DBusPendingCallNotifyFunction function,void * user_data,DBusFreeFunction free_user_data)730 dbus_bool_t dbus_pending_call_set_notify(DBusPendingCall* pending,
731 DBusPendingCallNotifyFunction function,
732 void* user_data,
733 DBusFreeFunction free_user_data) {
734 return true;
735 }
736
dbus_message_iter_recurse(DBusMessageIter * iter,DBusMessageIter * sub)737 void dbus_message_iter_recurse(DBusMessageIter* iter, DBusMessageIter* sub) {
738 MockDBusMessage* msg = *(MockDBusMessage**)iter;
739 MockDBusMessage** cur = (MockDBusMessage**)sub;
740 *cur = msg->recurse;
741 }
742
dbus_message_iter_next(DBusMessageIter * iter)743 dbus_bool_t dbus_message_iter_next(DBusMessageIter* iter) {
744 MockDBusMessage** cur = (MockDBusMessage**)iter;
745 MockDBusMessage* msg = *cur;
746 *cur = msg->next;
747 return true;
748 }
749
dbus_message_iter_get_arg_type(DBusMessageIter * iter)750 int dbus_message_iter_get_arg_type(DBusMessageIter* iter) {
751 MockDBusMessage* msg;
752
753 if (iter == NULL)
754 return DBUS_TYPE_INVALID;
755
756 msg = *(MockDBusMessage**)iter;
757 if (msg == NULL)
758 return DBUS_TYPE_INVALID;
759
760 return msg->type;
761 }
762
dbus_message_iter_get_basic(DBusMessageIter * iter,void * value)763 void dbus_message_iter_get_basic(DBusMessageIter* iter, void* value) {
764 MockDBusMessage* msg = *(MockDBusMessage**)iter;
765 switch (msg->type) {
766 case DBUS_TYPE_BOOLEAN:
767 memcpy(value, &msg->value, sizeof(int));
768 break;
769 case DBUS_TYPE_STRING:
770 memcpy(value, &msg->value, sizeof(char*));
771 break;
772 }
773 }
774
775 } // extern "C"
776 } // namespace
777
main(int argc,char ** argv)778 int main(int argc, char** argv) {
779 ::testing::InitGoogleTest(&argc, argv);
780 return RUN_ALL_TESTS();
781 }
782