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