xref: /btstack/test/gatt-service-client/battery_service_client_test.cpp (revision 1d6958009fc4c0630c04aa67fcd162c8eb50c8fd)
1 
2 // *****************************************************************************
3 //
4 // test Battery Service Client
5 //
6 // *****************************************************************************
7 
8 
9 #include <stdint.h>
10 #include <stdio.h>
11 #include <stdlib.h>
12 #include <string.h>
13 
14 #include "CppUTest/TestHarness.h"
15 #include "CppUTest/CommandLineTestRunner.h"
16 #include "CppUTestExt/MockSupport.h"
17 
18 #include "bluetooth.h"
19 #include "bluetooth_gatt.h"
20 #include "btstack_debug.h"
21 #include "btstack_event.h"
22 #include "btstack_memory.h"
23 #include "btstack_util.h"
24 #include "hci.h"
25 
26 #include "ble/gatt-service/battery_service_client.h"
27 #include "mock_gatt_client.h"
28 
29 static const hci_con_handle_t con_handle = 0x01;
30 static bool connected;
31 static uint8_t num_instances = 0;
32 // temp btstack run loop mock
33 
34 static btstack_timer_source_t * btstack_timer = NULL;
35 static uint8_t  battery_level[10];
36 static uint16_t battery_level_size;
37 
38 void btstack_run_lopo_deinit(void){
39         btstack_timer = NULL;
40 }
41 
42 void btstack_run_loop_add_timer(btstack_timer_source_t * timer){
43     btstack_timer = timer;
44 }
45 
46 int btstack_run_loop_remove_timer(btstack_timer_source_t * timer){
47     btstack_timer = NULL;
48     return 1;
49 }
50 
51 void btstack_run_loop_set_timer(btstack_timer_source_t * timer, uint32_t timeout_in_ms){
52 }
53 
54 void btstack_run_loop_set_timer_handler(btstack_timer_source_t * timer, void (*process)(btstack_timer_source_t * _timer)){
55     timer->process = process;
56 }
57 
58 void btstack_run_loop_set_timer_context(btstack_timer_source_t * timer, void * context){
59     timer->context = context;
60 }
61 
62 void * btstack_run_loop_get_timer_context(btstack_timer_source_t * timer){
63     return timer->context;
64 }
65 
66 void mock_btstack_run_loop_trigger_timer(void){
67     btstack_assert(btstack_timer != NULL);
68     (*btstack_timer->process)(btstack_timer);
69 }
70 
71 // simulate  btstack_memory_battery_service_client_get
72 
73 static bool mock_btstack_memory_battery_service_client_no_memory;
74 static battery_service_client_t * mock_btstack_memory_battery_service_client_last_alloc;
75 
76 void btstack_memory_init(void){
77     mock_btstack_memory_battery_service_client_no_memory = false;
78     mock_btstack_memory_battery_service_client_last_alloc = NULL;
79 }
80 
81 void mock_btstack_memory_battery_service_client_simulate_no_memory(void){
82     mock_btstack_memory_battery_service_client_no_memory = true;
83 }
84 
85 battery_service_client_t * mock_btstack_memory_battery_service_client_get_last_alloc(void){
86     btstack_assert(mock_btstack_memory_battery_service_client_last_alloc != NULL);
87     return mock_btstack_memory_battery_service_client_last_alloc;
88 }
89 
90 battery_service_client_t * btstack_memory_battery_service_client_get(void){
91     if (mock_btstack_memory_battery_service_client_no_memory){
92         return NULL;
93     }
94     mock_btstack_memory_battery_service_client_last_alloc =  (battery_service_client_t *) malloc(sizeof(battery_service_client_t));
95     memset(mock_btstack_memory_battery_service_client_last_alloc, 0, sizeof(battery_service_client_t));
96     return mock_btstack_memory_battery_service_client_last_alloc;
97 }
98 
99 void btstack_memory_battery_service_client_free(battery_service_client_t *battery_service_client){
100     free(battery_service_client);
101 }
102 
103 static void gatt_client_event_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){
104     UNUSED(packet_type);
105     UNUSED(channel);
106     UNUSED(size);
107 
108     uint8_t status;
109     uint8_t att_status;
110 
111     if (hci_event_packet_get_type(packet) != HCI_EVENT_GATTSERVICE_META){
112         return;
113     }
114 
115     switch (hci_event_gattservice_meta_get_subevent_code(packet)){
116         case GATTSERVICE_SUBEVENT_BATTERY_SERVICE_CONNECTED:
117             status = gattservice_subevent_battery_service_connected_get_status(packet);
118             switch (status){
119                 case ERROR_CODE_SUCCESS:
120                     num_instances = gattservice_subevent_battery_service_connected_get_num_instances(packet);
121                     connected = true;
122                     break;
123                 default:
124                     connected = false;
125                     break;
126             }
127             break;
128 
129         case GATTSERVICE_SUBEVENT_BATTERY_SERVICE_LEVEL:
130             att_status = gattservice_subevent_battery_service_level_get_att_status(packet);
131             if (att_status != ATT_ERROR_SUCCESS){
132                 // printf("Battery level read failed, ATT Error 0x%02x\n", att_status);
133                 break;
134             }
135 
136             // printf("Battery level 0x%02x\n", gattservice_subevent_battery_service_level_get_level(packet));
137             CHECK_EQUAL(battery_level[0], gattservice_subevent_battery_service_level_get_level(packet));
138             CHECK_EQUAL(0, gattservice_subevent_battery_service_level_get_sevice_index(packet));
139             break;
140 
141         default:
142             break;
143     }
144 }
145 
146 TEST_GROUP(BATTERY_SERVICE_CLIENT){
147     uint16_t battery_service_cid;
148     uint32_t poll_interval_ms;
149     mock_gatt_client_service_t * service;
150     mock_gatt_client_characteristic_t * characteristic;
151     mock_gatt_client_characteristic_descriptor_t * descriptor;
152 
153     uint8_t  value_buffer[3];
154 
155     void setup(void){
156         battery_service_cid = 1;
157         connected = false;
158         poll_interval_ms = 2000;
159 
160         uint16_t i;
161         for (i = 0; i < sizeof(value_buffer); i++){
162             value_buffer[i] = (i+1)*11;
163         }
164 
165         btstack_memory_init();
166         mock_gatt_client_reset();
167         battery_service_client_init();
168     }
169 
170     void set_battery_level_of_size(uint16_t value_length){
171         battery_level_size = btstack_min(value_length, sizeof(battery_level));
172         uint8_t i;
173         for (i=0; i<battery_level_size; i++){
174             battery_level[i] = i+1;
175         }
176         mock_gatt_client_set_characteristic_value(characteristic, battery_level, battery_level_size);
177     }
178 
179     void setup_service(bool add_characteristics, bool add_descriptors){
180         service = mock_gatt_client_add_primary_service_uuid16(ORG_BLUETOOTH_SERVICE_BATTERY_SERVICE);
181         if (!add_characteristics) return;
182 
183         characteristic = mock_gatt_client_add_characteristic_uuid16(ORG_BLUETOOTH_CHARACTERISTIC_BATTERY_LEVEL, ATT_PROPERTY_NOTIFY);
184 
185         if (!add_descriptors) return;
186         descriptor = mock_gatt_client_add_characteristic_descriptor_uuid16(ORG_BLUETOOTH_DESCRIPTOR_GATT_CLIENT_CHARACTERISTIC_CONFIGURATION);
187         mock_gatt_client_set_descriptor_characteristic_value(descriptor, value_buffer, sizeof(value_buffer));
188 
189         // mock_gatt_client_dump_services();
190     }
191 
192     void setup_service_without_notify_capabality(bool add_characteristics, bool add_descriptors){
193         service = mock_gatt_client_add_primary_service_uuid16(ORG_BLUETOOTH_SERVICE_BATTERY_SERVICE);
194         if (!add_characteristics) return;
195 
196         characteristic = mock_gatt_client_add_characteristic_uuid16(ORG_BLUETOOTH_CHARACTERISTIC_BATTERY_LEVEL, ATT_PROPERTY_READ);
197 
198         if (!add_descriptors) return;
199         descriptor = mock_gatt_client_add_characteristic_descriptor_uuid16(ORG_BLUETOOTH_DESCRIPTOR_GATT_CLIENT_CHARACTERISTIC_CONFIGURATION);
200         mock_gatt_client_set_descriptor_characteristic_value(descriptor, value_buffer, sizeof(value_buffer));
201 
202         // mock_gatt_client_dump_services();
203     }
204 
205     void connect(void){
206         uint8_t status = battery_service_client_connect(con_handle, &gatt_client_event_handler, poll_interval_ms, &battery_service_cid);
207         CHECK_EQUAL(ERROR_CODE_SUCCESS, status);
208         mock_gatt_client_run();
209     }
210 
211     void teardown(void){
212         battery_service_client_deinit();
213     }
214 };
215 
216 TEST(BATTERY_SERVICE_CLIENT, unhandled_gatt_event){
217     mock_gatt_client_emit_dummy_event();
218 }
219 
220 TEST(BATTERY_SERVICE_CLIENT, gatt_event_in_wrong_state){
221     uint8_t status = battery_service_client_connect(con_handle, &gatt_client_event_handler, poll_interval_ms, NULL);
222     CHECK_EQUAL(ERROR_CODE_SUCCESS, status);
223     // mock_gatt_client_run_once();
224     // mock_gatt_client_emit_complete(ERROR_CODE_SUCCESS);
225 }
226 
227 TEST(BATTERY_SERVICE_CLIENT, connect_no_memory){
228     mock_btstack_memory_battery_service_client_simulate_no_memory();
229     uint8_t status = battery_service_client_connect(con_handle, &gatt_client_event_handler, poll_interval_ms, NULL);
230     CHECK_EQUAL(BTSTACK_MEMORY_ALLOC_FAILED, status);
231 }
232 
233 TEST(BATTERY_SERVICE_CLIENT, connect_no_cid){
234     uint8_t status = battery_service_client_connect(con_handle, &gatt_client_event_handler, poll_interval_ms, NULL);
235     CHECK_EQUAL(ERROR_CODE_SUCCESS, status);
236 
237     mock_gatt_client_run();
238     CHECK_EQUAL(false, connected);
239 }
240 
241 TEST(BATTERY_SERVICE_CLIENT, connect_no_service){
242     uint8_t status = battery_service_client_connect(con_handle, &gatt_client_event_handler, poll_interval_ms, &battery_service_cid);
243     CHECK_EQUAL(ERROR_CODE_SUCCESS, status);
244 
245     mock_gatt_client_run();
246     CHECK_EQUAL(false, connected);
247 }
248 
249 
250 TEST(BATTERY_SERVICE_CLIENT, connect_with_service_no_chr_no_desc){
251     setup_service(false, false);
252     connect();
253     CHECK_EQUAL(false, connected);
254 }
255 
256 TEST(BATTERY_SERVICE_CLIENT, connect_with_service_and_chr_no_desc){
257     setup_service(true, false);
258     connect();
259     CHECK_EQUAL(true, connected);
260 }
261 
262 TEST(BATTERY_SERVICE_CLIENT, connect_with_service_and_chr_and_desc){
263     setup_service(true, true);
264     connect();
265     CHECK_EQUAL(true, connected);
266 }
267 
268 TEST(BATTERY_SERVICE_CLIENT, connect_with_one_invalid_and_one_valid_service){
269     setup_service(false, false);
270     setup_service(true, true);
271     connect();
272     CHECK_EQUAL(true, connected);
273 }
274 
275 
276 TEST(BATTERY_SERVICE_CLIENT, double_connect){
277     setup_service(true, true);
278     connect();
279     CHECK_EQUAL(true, connected);
280     uint8_t status = battery_service_client_connect(con_handle, &gatt_client_event_handler, poll_interval_ms, &battery_service_cid);
281     CHECK_EQUAL(ERROR_CODE_COMMAND_DISALLOWED, status);
282 }
283 
284 TEST(BATTERY_SERVICE_CLIENT, connect_discover_primary_service_error){
285     mock_gatt_client_set_att_error_discover_primary_services();
286     setup_service(true, true);
287     connect();
288     CHECK_EQUAL(false, connected);
289 }
290 
291 TEST(BATTERY_SERVICE_CLIENT, connect_discover_characteristics_error){
292     mock_gatt_client_set_att_error_discover_characteristics();
293     setup_service(true, true);
294     connect();
295     CHECK_EQUAL(false, connected);
296 }
297 
298 TEST(BATTERY_SERVICE_CLIENT, connect_discover_characteristic_descriptors_error){
299     mock_gatt_client_set_att_error_discover_characteristic_descriptors();
300     setup_service(true, true);
301     connect();
302     CHECK_EQUAL(true, connected);
303 }
304 
305 TEST(BATTERY_SERVICE_CLIENT, connect_ignore_too_many_service){
306     uint8_t i;
307     for (i = 0; i < MAX_NUM_BATTERY_SERVICES + 2; i++){
308         setup_service(true, true);
309     }
310     setup_service(true, true);
311     connect();
312 
313     CHECK_EQUAL(num_instances, MAX_NUM_BATTERY_SERVICES);
314     CHECK_EQUAL(true, connected);
315 }
316 
317 TEST(BATTERY_SERVICE_CLIENT, disconnect_not_connected){
318     uint8_t status;
319 
320     status = battery_service_client_disconnect(battery_service_cid);
321     CHECK_EQUAL(ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER, status);
322 }
323 
324 TEST(BATTERY_SERVICE_CLIENT, double_disconnect){
325     uint8_t status;
326 
327     setup_service(true, true);
328     connect();
329     CHECK_EQUAL(true, connected);
330 
331     status = battery_service_client_disconnect(battery_service_cid);
332     CHECK_EQUAL(ERROR_CODE_SUCCESS, status);
333 
334     status = battery_service_client_disconnect(battery_service_cid);
335     CHECK_EQUAL(ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER, status);
336 }
337 
338 
339 TEST(BATTERY_SERVICE_CLIENT, notify_battery_value_invalid_0){
340     setup_service(true, true);
341     connect();
342     CHECK_EQUAL(true, connected);
343 
344     set_battery_level_of_size(0);
345     mock_gatt_client_send_notification(characteristic, battery_level, battery_level_size);
346     // TODO: check battery level was not received
347 }
348 
349 
350 TEST(BATTERY_SERVICE_CLIENT, notify_battery_value_invalid_5){
351     setup_service(true, true);
352     connect();
353     CHECK_EQUAL(true, connected);
354 
355     set_battery_level_of_size(5);
356     mock_gatt_client_send_notification(characteristic, battery_level, battery_level_size);
357     // TODO: check battery level was not received
358 }
359 
360 TEST(BATTERY_SERVICE_CLIENT, notify_battery_value_wrong_handle){
361     setup_service(true, true);
362     connect();
363     CHECK_EQUAL(true, connected);
364 
365     set_battery_level_of_size(1);
366     mock_gatt_client_send_notification_with_handle(characteristic, 0x1234, battery_level, battery_level_size);
367     // TODO: check battery level was not received
368 }
369 
370 TEST(BATTERY_SERVICE_CLIENT, notify_battery_value_wrong_handle_multiple){
371     setup_service(true, true);
372     setup_service(true, true);
373     connect();
374     CHECK_EQUAL(true, connected);
375 
376     set_battery_level_of_size(1);
377     mock_gatt_client_send_notification_with_handle(characteristic, 0x1234, battery_level, battery_level_size);
378     // TODO: check battery level was not received
379 }
380 
381 TEST(BATTERY_SERVICE_CLIENT, notify_battery_value_valid){
382     setup_service(true, true);
383     connect();
384     CHECK_EQUAL(true, connected);
385 
386     set_battery_level_of_size(1);
387     mock_gatt_client_send_notification(characteristic, battery_level, battery_level_size);
388     // TODO: check battery level was received
389 }
390 
391 TEST(BATTERY_SERVICE_CLIENT, multiple_connection){
392     battery_service_client_connect(con_handle, &gatt_client_event_handler, poll_interval_ms, &battery_service_cid);
393     battery_service_client_connect(con_handle+1, &gatt_client_event_handler, poll_interval_ms, &battery_service_cid);
394     battery_service_client_read_battery_level(10, 0);
395 }
396 
397 TEST(BATTERY_SERVICE_CLIENT, read_battery_level_wrong_cid){
398     uint8_t status = battery_service_client_read_battery_level(10, 0);
399     CHECK_EQUAL(ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER, status);
400 }
401 
402 TEST(BATTERY_SERVICE_CLIENT, read_battery_level_wrong_state){
403     // without calling mock_gatt_client_run(), state remains in BATTERY_SERVICE_CLIENT_STATE_W2_QUERY_SERVICE
404     uint8_t status = battery_service_client_connect(con_handle, &gatt_client_event_handler, poll_interval_ms, &battery_service_cid);
405     CHECK_EQUAL(ERROR_CODE_SUCCESS, status);
406     CHECK_EQUAL(false, connected);
407 
408     status = battery_service_client_read_battery_level(battery_service_cid, 0);
409     CHECK_EQUAL(GATT_CLIENT_IN_WRONG_STATE, status);
410 }
411 
412 TEST(BATTERY_SERVICE_CLIENT, read_battery_level_wrong_state_in_packet_handler){
413     setup_service(true, true);
414     connect();
415     CHECK_EQUAL(true, connected);
416     mock_btstack_memory_battery_service_client_get_last_alloc()->state = BATTERY_SERVICE_CLIENT_STATE_IDLE;
417     mock_gatt_client_emit_complete(ERROR_CODE_SUCCESS);
418 }
419 
420 TEST(BATTERY_SERVICE_CLIENT, read_battery_level_wrong_service_index){
421     setup_service(true, true);
422     connect();
423     CHECK_EQUAL(true, connected);
424 
425     uint8_t status = battery_service_client_read_battery_level(battery_service_cid, 10);
426     CHECK_EQUAL(ERROR_CODE_UNSUPPORTED_FEATURE_OR_PARAMETER_VALUE, status);
427 }
428 
429 TEST(BATTERY_SERVICE_CLIENT, poll_battery_value_invalid){
430     setup_service(true, true);
431     mock_gatt_client_enable_notification(characteristic, false);
432     set_battery_level_of_size(5);
433 
434 
435     connect();
436     CHECK_EQUAL(true, connected);
437 
438     uint8_t status = battery_service_client_read_battery_level(battery_service_cid, 0);
439     CHECK_EQUAL(ERROR_CODE_SUCCESS, status);
440 }
441 
442 TEST(BATTERY_SERVICE_CLIENT, poll_battery_value){
443     setup_service(true, true);
444     set_battery_level_of_size(1);
445 
446     mock_gatt_client_enable_notification(characteristic, false);
447 
448     connect();
449     CHECK_EQUAL(true, connected);
450 
451     uint8_t status = battery_service_client_read_battery_level(battery_service_cid, 0);
452     CHECK_EQUAL(ERROR_CODE_SUCCESS, status);
453 }
454 
455 TEST(BATTERY_SERVICE_CLIENT, poll_battery_value_with_error){
456     setup_service(true, true);
457     set_battery_level_of_size(1);
458 
459     mock_gatt_client_enable_notification(characteristic, false);
460 
461     connect();
462     CHECK_EQUAL(true, connected);
463 
464     uint8_t status = battery_service_client_read_battery_level(battery_service_cid, 0);
465     CHECK_EQUAL(ERROR_CODE_SUCCESS, status);
466     mock_gatt_client_emit_complete(1);
467 }
468 
469 TEST(BATTERY_SERVICE_CLIENT, poll_battery_value_zero_poll_interval){
470     setup_service(true, true);
471     set_battery_level_of_size(1);
472 
473     mock_gatt_client_enable_notification(characteristic, false);
474 
475     uint8_t status = battery_service_client_connect(con_handle, &gatt_client_event_handler, 0, &battery_service_cid);
476     CHECK_EQUAL(ERROR_CODE_SUCCESS, status);
477     mock_gatt_client_run();
478     CHECK_EQUAL(true, connected);
479 
480     status = battery_service_client_read_battery_level(battery_service_cid, 0);
481     CHECK_EQUAL(ERROR_CODE_SUCCESS, status);
482 }
483 
484 
485 TEST(BATTERY_SERVICE_CLIENT, poll_battery_value_trigger_timer){
486     setup_service(true, true);
487     set_battery_level_of_size(1);
488 
489     mock_gatt_client_enable_notification(characteristic, false);
490 
491     connect();
492     CHECK_EQUAL(true, connected);
493     mock_btstack_run_loop_trigger_timer();
494     mock_gatt_client_run();
495 }
496 
497 TEST(BATTERY_SERVICE_CLIENT, poll_battery_value_trigger_timer_unxpected_complete){
498     setup_service(true, true);
499     set_battery_level_of_size(1);
500 
501     mock_gatt_client_enable_notification(characteristic, false);
502 
503     connect();
504     CHECK_EQUAL(true, connected);
505     mock_btstack_run_loop_trigger_timer();
506     mock_gatt_client_run();
507 
508     // polling done, emit another complete event
509     mock_gatt_client_emit_complete(0);
510 }
511 
512 
513 TEST(BATTERY_SERVICE_CLIENT, mixed_poll_and_notify_battery_value){
514     setup_service(true, true);
515     mock_gatt_client_enable_notification(characteristic, true);
516 
517     setup_service(true, true);
518     mock_gatt_client_enable_notification(characteristic, false);
519 
520     setup_service(true, true);
521     mock_gatt_client_enable_notification(characteristic, true);
522 
523     connect();
524     CHECK_EQUAL(true, connected);
525 }
526 
527 TEST(BATTERY_SERVICE_CLIENT, hci_disconnect_event){
528     setup_service(true, true);
529     connect();
530     CHECK_EQUAL(true, connected);
531 
532     mock_hci_emit_disconnection_complete(con_handle, 0);
533     uint8_t status = battery_service_client_disconnect(battery_service_cid);
534     CHECK_EQUAL(ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER, status);
535 
536     mock_hci_emit_disconnection_complete(HCI_CON_HANDLE_INVALID, 0);
537 }
538 
539 TEST(BATTERY_SERVICE_CLIENT, ignored_events){
540     setup_service(true, true);
541     connect();
542     CHECK_EQUAL(true, connected);
543 
544     // unexpected event
545     mock_hci_emit_connection_encrypted(con_handle, 0);
546     // event with wrong con handle
547     mock_hci_emit_disconnection_complete(HCI_CON_HANDLE_INVALID, 0);
548 }
549 
550 int main (int argc, const char * argv[]){
551     return CommandLineTestRunner::RunAllTests(argc, argv);
552 }
553