1 // *****************************************************************************
2 //
3 // test ANCS Client
4 //
5 // *****************************************************************************
6
7
8 #include <stdint.h>
9 #include <stdio.h>
10 #include <stdlib.h>
11 #include <string.h>
12
13 #include "CppUTest/TestHarness.h"
14 #include "CppUTest/CommandLineTestRunner.h"
15 #include "CppUTestExt/MockSupport.h"
16
17 #include "bluetooth.h"
18 #include "bluetooth_gatt.h"
19 #include "btstack_debug.h"
20 #include "btstack_event.h"
21 #include "btstack_memory.h"
22 #include "btstack_util.h"
23 #include "hci.h"
24
25 #include "ble/gatt-service/ancs_client.h"
26 #include "mock_gatt_client.h"
27
28 extern "C" void ancs_client_set_invalid_parser_state(void);
29
30 // mock hci
31
32 static const uint8_t ancs_service_uuid[] = {0x79,0x05,0xF4,0x31,0xB5,0xCE,0x4E,0x99,0xA4,0x0F,0x4B,0x1E,0x12,0x2D,0x00,0xD0};
33 static const uint8_t ancs_notification_source_uuid[] = {0x9F,0xBF,0x12,0x0D,0x63,0x01,0x42,0xD9,0x8C,0x58,0x25,0xE6,0x99,0xA2,0x1D,0xBD};
34 static const uint8_t ancs_control_point_uuid[] = {0x69,0xD1,0xD8,0xF3,0x45,0xE1,0x49,0xA8,0x98,0x21,0x9B,0xBD,0xFD,0xAA,0xD9,0xD9};
35 static const uint8_t ancs_data_source_uuid[] = {0x22,0xEA,0xC6,0xE9,0x24,0xD6,0x4B,0xB5,0xBE,0x44,0xB3,0x6A,0xCE,0x7C,0x7B,0xFB};
36
37 static const hci_con_handle_t ancs_con_handle = 0x001;
38 static bool ancs_connected;
39
40 // mock sm
sm_request_pairing(hci_con_handle_t con_handle)41 void sm_request_pairing(hci_con_handle_t con_handle){
42 }
43
44 // temp btstack run loop mock
45
46 static btstack_timer_source_t * btstack_timer = NULL;
47
btstack_run_lopo_deinit(void)48 void btstack_run_lopo_deinit(void){
49 btstack_timer = NULL;
50 }
51
btstack_run_loop_add_timer(btstack_timer_source_t * timer)52 void btstack_run_loop_add_timer(btstack_timer_source_t * timer){
53 btstack_timer = timer;
54 }
55
btstack_run_loop_remove_timer(btstack_timer_source_t * timer)56 int btstack_run_loop_remove_timer(btstack_timer_source_t * timer){
57 btstack_timer = NULL;
58 return 1;
59 }
60
btstack_run_loop_set_timer(btstack_timer_source_t * timer,uint32_t timeout_in_ms)61 void btstack_run_loop_set_timer(btstack_timer_source_t * timer, uint32_t timeout_in_ms){
62 }
63
btstack_run_loop_set_timer_handler(btstack_timer_source_t * timer,void (* process)(btstack_timer_source_t * _timer))64 void btstack_run_loop_set_timer_handler(btstack_timer_source_t * timer, void (*process)(btstack_timer_source_t * _timer)){
65 timer->process = process;
66 }
67
btstack_run_loop_set_timer_context(btstack_timer_source_t * timer,void * context)68 void btstack_run_loop_set_timer_context(btstack_timer_source_t * timer, void * context){
69 timer->context = context;
70 }
71
btstack_run_loop_get_timer_context(btstack_timer_source_t * timer)72 void * btstack_run_loop_get_timer_context(btstack_timer_source_t * timer){
73 return timer->context;
74 }
75
mock_btstack_run_loop_trigger_timer(void)76 void mock_btstack_run_loop_trigger_timer(void){
77 btstack_assert(btstack_timer != NULL);
78 (*btstack_timer->process)(btstack_timer);
79 }
80
ancs_client_event_handler(uint8_t packet_type,uint16_t channel,uint8_t * packet,uint16_t size)81 static void ancs_client_event_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){
82 UNUSED(packet_type);
83 UNUSED(channel);
84 UNUSED(size);
85
86 switch (hci_event_gattservice_meta_get_subevent_code(packet)){
87 case ANCS_SUBEVENT_CLIENT_CONNECTED:
88 ancs_connected = true;
89 break;
90 default:
91 break;
92 }
93 }
94
TEST_GROUP(ANCS_CLIENT)95 TEST_GROUP(ANCS_CLIENT){
96 mock_gatt_client_service_t * service;
97 mock_gatt_client_characteristic_t * ancs_data_source_characteristic;
98 mock_gatt_client_characteristic_t * ancs_notification_source_characteristic;
99 mock_gatt_client_characteristic_t * ancs_control_point_characteristic;
100 mock_gatt_client_characteristic_descriptor_t * descriptor;
101
102 uint8_t value_buffer[3];
103
104 void setup(void){
105 ancs_connected = false;
106 mock_gatt_client_reset();
107 ancs_client_init();
108 ancs_client_register_callback(&ancs_client_event_handler);
109 }
110
111 void setup_service(bool add_characteristics, bool add_descriptors){
112 // TODO: setup ANCS Service
113 service = mock_gatt_client_add_primary_service_uuid128(ancs_service_uuid);
114
115 if (!add_characteristics) return;
116 ancs_control_point_characteristic = mock_gatt_client_add_characteristic_uuid128(ancs_control_point_uuid, ATT_PROPERTY_NOTIFY);
117 if (add_descriptors) {
118 descriptor = mock_gatt_client_add_characteristic_descriptor_uuid16(ORG_BLUETOOTH_DESCRIPTOR_GATT_CLIENT_CHARACTERISTIC_CONFIGURATION);
119 }
120 ancs_data_source_characteristic = mock_gatt_client_add_characteristic_uuid128(ancs_data_source_uuid, ATT_PROPERTY_NOTIFY);
121 if (add_descriptors) {
122 descriptor = mock_gatt_client_add_characteristic_descriptor_uuid16(ORG_BLUETOOTH_DESCRIPTOR_GATT_CLIENT_CHARACTERISTIC_CONFIGURATION);
123 }
124 ancs_notification_source_characteristic = mock_gatt_client_add_characteristic_uuid128(ancs_notification_source_uuid, ATT_PROPERTY_NOTIFY);
125 if (add_descriptors) {
126 descriptor = mock_gatt_client_add_characteristic_descriptor_uuid16(ORG_BLUETOOTH_DESCRIPTOR_GATT_CLIENT_CHARACTERISTIC_CONFIGURATION);
127 }
128 // mock_gatt_client_dump_services();
129
130 }
131
132 void connect(void){
133 // simulated connected
134 bd_addr_t some_address;
135 mock_hci_emit_le_connection_complete(0, some_address, ancs_con_handle, ERROR_CODE_SUCCESS);
136 mock_hci_emit_connection_encrypted(ancs_con_handle, 1);
137 }
138
139 void teardown(void){
140 }
141 };
142
143
TEST(ANCS_CLIENT,resolve_ids)144 TEST(ANCS_CLIENT, resolve_ids){
145 for (int i = 0; i<6; i++){
146 const char * name = ancs_client_attribute_name_for_id(i);
147 CHECK_TRUE(name != NULL);
148 }
149 CHECK_EQUAL(NULL, ancs_client_attribute_name_for_id(6));
150 }
151
TEST(ANCS_CLIENT,ignored_events)152 TEST(ANCS_CLIENT, ignored_events){
153 // default hci event
154 uint8_t some_other_event[] = { 0, 0};
155 mock_hci_emit_event(some_other_event, sizeof(some_other_event));
156
157 // default hci le subevent
158 uint8_t some_le_event[] = { HCI_EVENT_LE_META, 1, 0};
159 mock_hci_emit_event(some_le_event, sizeof(some_le_event));
160 // encypted but different con handle
161 mock_hci_emit_connection_encrypted(ancs_con_handle+1, 1);
162 // encypted but different state
163 mock_hci_emit_connection_encrypted(ancs_con_handle, 1);
164 // non-encypted
165 mock_hci_emit_connection_encrypted(ancs_con_handle, 0);
166 // disconnected different handle
167 mock_hci_emit_disconnection_complete(ancs_con_handle+1,0);
168 // disconnected different handle
169 mock_hci_emit_disconnection_complete(ancs_con_handle,0);
170
171 // some hci gap meta subevent
172 uint8_t some_gap_meta_event[] = { HCI_EVENT_META_GAP, 1, HCI_SUBEVENT_LE_CONNECTION_COMPLETE + 1};
173 mock_hci_emit_event(some_gap_meta_event, sizeof(some_gap_meta_event));
174 }
175
TEST(ANCS_CLIENT,connect_no_service)176 TEST(ANCS_CLIENT, connect_no_service){
177 connect();
178 mock_gatt_client_run();
179 }
180
TEST(ANCS_CLIENT,connect_unexpected_event_during_service_disc)181 TEST(ANCS_CLIENT, connect_unexpected_event_during_service_disc){
182 connect();
183 mock_gatt_client_emit_dummy_event();
184 }
185
TEST(ANCS_CLIENT,connect)186 TEST(ANCS_CLIENT, connect){
187 setup_service(true, true);
188 connect();
189 mock_gatt_client_run();
190 CHECK_TRUE(ancs_connected);
191 }
192
TEST(ANCS_CLIENT,connect_extra_characteristic)193 TEST(ANCS_CLIENT, connect_extra_characteristic){
194 setup_service(true, true);
195 mock_gatt_client_add_characteristic_uuid16(ORG_BLUETOOTH_CHARACTERISTIC_BATTERY_LEVEL, 0);
196 connect();
197 mock_gatt_client_run();
198 }
199
TEST(ANCS_CLIENT,disconnect)200 TEST(ANCS_CLIENT, disconnect){
201 setup_service(true, true);
202 connect();
203 mock_gatt_client_run();
204 mock_hci_emit_disconnection_complete(ancs_con_handle,0);
205 }
206
TEST(ANCS_CLIENT,notification_characteristic)207 TEST(ANCS_CLIENT, notification_characteristic){
208 setup_service(true, true);
209 connect();
210 mock_gatt_client_run();
211 const uint8_t data[] = {};
212 mock_gatt_client_send_notification(ancs_notification_source_characteristic, data, sizeof(data));
213 }
214
TEST(ANCS_CLIENT,data_source_characteristic)215 TEST(ANCS_CLIENT, data_source_characteristic){
216 setup_service(true, true);
217 connect();
218 mock_gatt_client_run();
219 // simulate notification
220 const uint8_t notification_data[] = {0,0,0,0,0,0,0,0};
221 mock_gatt_client_send_notification(ancs_notification_source_characteristic, notification_data, sizeof(notification_data));
222 // command id = 0 / CommandIDGetNotificationAttributes
223 // notification uid 0x1111
224 // attribute id 1
225 // len 1
226 // attribute id 2
227 // len 0
228 const uint8_t data[] = { 0, 0,0,0,0, 1, 1, 0, 'a', 2, 0, 0};
229 mock_gatt_client_send_notification(ancs_data_source_characteristic, data, sizeof(data));
230 }
231
TEST(ANCS_CLIENT,data_source_characteristic_no_handler)232 TEST(ANCS_CLIENT, data_source_characteristic_no_handler){
233 ancs_client_register_callback(NULL);
234 setup_service(true, true);
235 connect();
236 mock_gatt_client_run();
237 // simulate notification
238 const uint8_t notification_data[] = {0,0,0,0,0,0,0,0};
239 mock_gatt_client_send_notification(ancs_notification_source_characteristic, notification_data, sizeof(notification_data));
240 // command id = 0 / CommandIDGetNotificationAttributes
241 // notification uid 0x1111
242 // attribute id 1
243 // len 1
244 // attribute id 2
245 // len 0
246 const uint8_t data[] = { 0, 0,0,0,0, 1, 1, 0, 'a', 2, 0, 0};
247 mock_gatt_client_send_notification(ancs_data_source_characteristic, data, sizeof(data));
248 }
249
TEST(ANCS_CLIENT,notifications_other)250 TEST(ANCS_CLIENT, notifications_other){
251 setup_service(true, true);
252 connect();
253 mock_gatt_client_run();
254 const uint8_t data[] = {};
255 mock_gatt_client_send_notification_with_handle(ancs_notification_source_characteristic, 0x0001, data, sizeof(data));
256 }
257
TEST(ANCS_CLIENT,indications_other)258 TEST(ANCS_CLIENT, indications_other){
259 setup_service(true, true);
260 connect();
261 mock_gatt_client_run();
262 const uint8_t data[] = {};
263 mock_gatt_client_send_indication_with_handle(ancs_notification_source_characteristic, 0x0001, data, sizeof(data));
264 }
265
TEST(ANCS_CLIENT,notifications_invalid_parser)266 TEST(ANCS_CLIENT, notifications_invalid_parser){
267 setup_service(true, true);
268 ancs_client_set_invalid_parser_state();
269 connect();
270 mock_gatt_client_run();
271 const uint8_t data[] = {1,2,3,4,5,6};
272 mock_gatt_client_send_notification(ancs_data_source_characteristic, data, sizeof(data));
273 }
274
TEST(ANCS_CLIENT,connect_unexpected_events)275 TEST(ANCS_CLIENT, connect_unexpected_events){
276 printf("connect_unexpected_events\n");
277 setup_service(true, true);
278 connect();
279 mock_gatt_client_run_once();
280 mock_gatt_client_emit_dummy_event();
281 mock_gatt_client_run_once();
282 mock_gatt_client_emit_dummy_event();
283 mock_gatt_client_run_once();
284 mock_gatt_client_emit_dummy_event();
285 mock_gatt_client_run_once();
286 mock_gatt_client_emit_dummy_event();
287 }
288
TEST(ANCS_CLIENT,connect_unexpected_events_in_idle_state)289 TEST(ANCS_CLIENT, connect_unexpected_events_in_idle_state){
290 printf("connect_unexpected_events\n");
291 connect();
292 mock_gatt_client_run_once();
293 mock_gatt_client_emit_dummy_event();
294 }
295
main(int argc,const char * argv[])296 int main (int argc, const char * argv[]){
297 return CommandLineTestRunner::RunAllTests(argc, argv);
298 }
299