xref: /btstack/test/gatt-service-client/ancs_client_test.cpp (revision 500d8180fa32d9bb205d49465fb0f7fa20250313)
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     // default hci le subevent
157     uint8_t some_le_event[] = { HCI_EVENT_LE_META, 1, 0};
158     mock_hci_emit_event(some_le_event, sizeof(some_le_event));
159     // encypted but different con handle
160     mock_hci_emit_connection_encrypted(ancs_con_handle+1, 1);
161     // encypted but different state
162     mock_hci_emit_connection_encrypted(ancs_con_handle, 1);
163     // non-encypted
164     mock_hci_emit_connection_encrypted(ancs_con_handle, 0);
165     // disconnected different handle
166     mock_hci_emit_disconnection_complete(ancs_con_handle+1,0);
167     // disconnected different handle
168     mock_hci_emit_disconnection_complete(ancs_con_handle,0);
169 }
170 
171 TEST(ANCS_CLIENT, connect_no_service){
172     connect();
173     mock_gatt_client_run();
174 }
175 
176 TEST(ANCS_CLIENT, connect_unexpected_event_during_service_disc){
177     connect();
178     mock_gatt_client_emit_dummy_event();
179 }
180 
181 TEST(ANCS_CLIENT, connect_unexpected_events){
182     setup_service(true, true);
183     connect();
184     mock_gatt_client_run_once();
185     mock_gatt_client_emit_dummy_event();
186     mock_gatt_client_run_once();
187     mock_gatt_client_emit_dummy_event();
188     mock_gatt_client_run_once();
189     mock_gatt_client_emit_dummy_event();
190     mock_gatt_client_run_once();
191     mock_gatt_client_emit_dummy_event();
192 }
193 
194 TEST(ANCS_CLIENT, connect){
195     setup_service(true, true);
196     connect();
197     mock_gatt_client_run();
198     CHECK_TRUE(ancs_connected);
199 }
200 
201 TEST(ANCS_CLIENT, connect_extra_characteristic){
202     setup_service(true, true);
203     mock_gatt_client_add_characteristic_uuid16(ORG_BLUETOOTH_CHARACTERISTIC_BATTERY_LEVEL, 0);
204     connect();
205     mock_gatt_client_run();
206 }
207 
208 TEST(ANCS_CLIENT, disconnect){
209     setup_service(true, true);
210     connect();
211     mock_gatt_client_run();
212     mock_hci_emit_disconnection_complete(ancs_con_handle,0);
213 }
214 
215 TEST(ANCS_CLIENT, notification_characteristic){
216     setup_service(true, true);
217     connect();
218     mock_gatt_client_run();
219     const uint8_t data[] = {};
220     mock_gatt_client_send_notification(ancs_notification_source_characteristic, data, sizeof(data));
221 }
222 
223 TEST(ANCS_CLIENT, data_source_characteristic){
224     setup_service(true, true);
225     connect();
226     mock_gatt_client_run();
227     // simulate notification
228     const uint8_t notification_data[] = {0,0,0,0,0,0,0,0};
229     mock_gatt_client_send_notification(ancs_notification_source_characteristic, notification_data, sizeof(notification_data));
230     // command id = 0 / CommandIDGetNotificationAttributes
231     // notification uid 0x1111
232     // attribute id 1
233     // len 1
234     // attribute id 2
235     // len 0
236     const uint8_t data[] = { 0, 0,0,0,0, 1, 1, 0, 'a', 2, 0, 0};
237     mock_gatt_client_send_notification(ancs_data_source_characteristic, data, sizeof(data));
238 }
239 
240 TEST(ANCS_CLIENT, data_source_characteristic_no_handler){
241     ancs_client_register_callback(NULL);
242     setup_service(true, true);
243     connect();
244     mock_gatt_client_run();
245     // simulate notification
246     const uint8_t notification_data[] = {0,0,0,0,0,0,0,0};
247     mock_gatt_client_send_notification(ancs_notification_source_characteristic, notification_data, sizeof(notification_data));
248     // command id = 0 / CommandIDGetNotificationAttributes
249     // notification uid 0x1111
250     // attribute id 1
251     // len 1
252     // attribute id 2
253     // len 0
254     const uint8_t data[] = { 0, 0,0,0,0, 1, 1, 0, 'a', 2, 0, 0};
255     mock_gatt_client_send_notification(ancs_data_source_characteristic, data, sizeof(data));
256 }
257 
258 TEST(ANCS_CLIENT, notifications_other){
259     setup_service(true, true);
260     connect();
261     mock_gatt_client_run();
262     const uint8_t data[] = {};
263     mock_gatt_client_send_notification_with_handle(ancs_notification_source_characteristic, 0x0001, data, sizeof(data));
264 }
265 
266 TEST(ANCS_CLIENT, indications_other){
267     setup_service(true, true);
268     connect();
269     mock_gatt_client_run();
270     const uint8_t data[] = {};
271     mock_gatt_client_send_indication_with_handle(ancs_notification_source_characteristic, 0x0001, data, sizeof(data));
272 }
273 
274 TEST(ANCS_CLIENT, notifications_invalid_parser){
275     setup_service(true, true);
276     ancs_client_set_invalid_parser_state();
277     connect();
278     mock_gatt_client_run();
279     const uint8_t data[] = {1,2,3,4,5,6};
280     mock_gatt_client_send_notification(ancs_data_source_characteristic, data, sizeof(data));
281 }
282 
283 int main (int argc, const char * argv[]){
284     return CommandLineTestRunner::RunAllTests(argc, argv);
285 }
286