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