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 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 48 void btstack_run_lopo_deinit(void){ 49 btstack_timer = NULL; 50 } 51 52 void btstack_run_loop_add_timer(btstack_timer_source_t * timer){ 53 btstack_timer = timer; 54 } 55 56 int btstack_run_loop_remove_timer(btstack_timer_source_t * timer){ 57 btstack_timer = NULL; 58 return 1; 59 } 60 61 void btstack_run_loop_set_timer(btstack_timer_source_t * timer, uint32_t timeout_in_ms){ 62 } 63 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 68 void btstack_run_loop_set_timer_context(btstack_timer_source_t * timer, void * context){ 69 timer->context = context; 70 } 71 72 void * btstack_run_loop_get_timer_context(btstack_timer_source_t * timer){ 73 return timer->context; 74 } 75 76 void mock_btstack_run_loop_trigger_timer(void){ 77 btstack_assert(btstack_timer != NULL); 78 (*btstack_timer->process)(btstack_timer); 79 } 80 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 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 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 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 176 TEST(ANCS_CLIENT, connect_no_service){ 177 connect(); 178 mock_gatt_client_run(); 179 } 180 181 TEST(ANCS_CLIENT, connect_unexpected_event_during_service_disc){ 182 connect(); 183 mock_gatt_client_emit_dummy_event(); 184 } 185 186 TEST(ANCS_CLIENT, connect){ 187 setup_service(true, true); 188 connect(); 189 mock_gatt_client_run(); 190 CHECK_TRUE(ancs_connected); 191 } 192 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 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 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 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 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 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 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 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 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 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 296 int main (int argc, const char * argv[]){ 297 return CommandLineTestRunner::RunAllTests(argc, argv); 298 } 299