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