1 /***************************************************************************
2  * Copyright (c) 2024 Microsoft Corporation
3  *
4  * This program and the accompanying materials are made available under the
5  * terms of the MIT License which is available at
6  * https://opensource.org/licenses/MIT.
7  *
8  * SPDX-License-Identifier: MIT
9  **************************************************************************/
10 
11 #include <stdio.h>
12 #include <setjmp.h>
13 #include <cmocka.h>  /* macros: https://api.cmocka.org/group__cmocka__asserts.html */
14 
15 #include "nx_api.h"
16 #include "nx_azure_iot_hub_client.h"
17 #include "nx_azure_iot_cert.h"
18 #include "nx_azure_iot_ciphersuites.h"
19 
20 
21 #define DEMO_DHCP_DISABLE
22 #define DEMO_IPV4_ADDRESS         IP_ADDRESS(192, 168, 100, 33)
23 #define DEMO_IPV4_MASK            0xFFFFFF00UL
24 #define DEMO_GATEWAY_ADDRESS      IP_ADDRESS(192, 168, 100, 1)
25 #define DEMO_DNS_SERVER_ADDRESS   IP_ADDRESS(192, 168, 100, 1)
26 #define NETWORK_DRIVER            _nx_ram_network_driver
27 
28 /* Include main.c in the test case since we need to disable DHCP in this test. */
29 #include "main.c"
30 
31 #ifndef DEMO_CLOUD_STACK_SIZE
32 #define DEMO_CLOUD_STACK_SIZE           2048
33 #endif /* DEMO_CLOUD_STACK_SIZE */
34 
35 #ifndef DEMO_CLOUD_THREAD_PRIORITY
36 #define DEMO_CLOUD_THREAD_PRIORITY      (4)
37 #endif /* DEMO_CLOUD_THREAD_PRIORITY */
38 
39 #ifndef MAXIMUM_PAYLOAD_LENGTH
40 #define MAXIMUM_PAYLOAD_LENGTH          10240
41 #endif /* MAXIMUM_PAYLOAD_LENGTH */
42 
43 typedef VOID (*NX_AZURE_TEST_FN)();
44 
45 
46 static UCHAR g_hostname[] = "unit-test.iot-azure.com";
47 static UCHAR g_device_id[] = "unit_test_device";
48 
49 static const CHAR direct_method_response_topic[] = "$iothub/methods/POST/test_method/?$rid=1";
50 static const CHAR test_method_response_payload[] = "{\"method\" : \"test_method\", \"parameter\": 1}";
51 static const CHAR test_method_name[] = "test_method";
52 static const CHAR test_request_id[] = "1";
53 static const CHAR test_send_payload[] = "{\"return\" : \"OK\"}";
54 
55 static UINT g_total_append = 0;
56 static UINT g_failed_append_index = 0;
57 static UINT g_total_allocation = 0;
58 static UINT g_failed_allocation_index = -1;
59 static NX_IP* g_ip_ptr;
60 static NX_PACKET_POOL* g_pool_ptr;
61 static NX_DNS* g_dns_ptr;
62 static ULONG g_available_packet;
63 static CHAR *g_expected_message;
64 
65 extern UINT _nxd_mqtt_client_append_message(NXD_MQTT_CLIENT *client_ptr, NX_PACKET *packet_ptr, CHAR *message,
66                                             UINT length, ULONG wait_option);
67 extern UINT _nxd_mqtt_client_set_fixed_header(NXD_MQTT_CLIENT *client_ptr, NX_PACKET *packet_ptr,
68                                               UCHAR control_header, UINT length, UINT wait_option);
69 
70 static NX_AZURE_IOT iot;
71 static NX_AZURE_IOT_HUB_CLIENT iot_client;
72 static NX_SECURE_X509_CERT root_ca_cert;
73 static UCHAR metadata_buffer[NX_AZURE_IOT_TLS_METADATA_BUFFER_SIZE];
74 static ULONG demo_cloud_thread_stack[DEMO_CLOUD_STACK_SIZE / sizeof(ULONG)];
75 static UCHAR message_payload[MAXIMUM_PAYLOAD_LENGTH];
76 static UCHAR result_buffer[MAXIMUM_PAYLOAD_LENGTH];
77 static VOID (*test_receive_notify)(NXD_MQTT_CLIENT *client_ptr, UINT message_count) = NX_NULL;
78 
__wrap_nx_azure_iot_security_module_enable(NX_AZURE_IOT * nx_azure_iot_ptr)79 UINT __wrap_nx_azure_iot_security_module_enable(NX_AZURE_IOT *nx_azure_iot_ptr)
80 {
81     printf("HIJACKED: %s\n", __func__);
82     return(NX_AZURE_IOT_SUCCESS);
83 }
84 
__wrap_nx_azure_iot_security_module_disable(NX_AZURE_IOT * nx_azure_iot_ptr)85 UINT __wrap_nx_azure_iot_security_module_disable(NX_AZURE_IOT *nx_azure_iot_ptr)
86 {
87     printf("HIJACKED: %s\n", __func__);
88     return(NX_AZURE_IOT_SUCCESS);
89 }
90 
__wrap__nxde_mqtt_client_receive_notify_set(NXD_MQTT_CLIENT * client_ptr,VOID (* receive_notify)(NXD_MQTT_CLIENT * client_ptr,UINT message_count))91 UINT __wrap__nxde_mqtt_client_receive_notify_set(NXD_MQTT_CLIENT *client_ptr,
92                                                  VOID (*receive_notify)(NXD_MQTT_CLIENT *client_ptr, UINT message_count))
93 {
94     printf("HIJACKED: %s\n", __func__);
95     test_receive_notify = receive_notify;
96     return(NX_AZURE_IOT_SUCCESS);
97 }
98 
__wrap__nxde_mqtt_client_subscribe(NXD_MQTT_CLIENT * client_ptr,UINT op,CHAR * topic_name,UINT topic_name_length,USHORT * packet_id_ptr,UINT QoS)99 UINT __wrap__nxde_mqtt_client_subscribe(NXD_MQTT_CLIENT *client_ptr, UINT op,
100                                         CHAR *topic_name, UINT topic_name_length,
101                                         USHORT *packet_id_ptr, UINT QoS)
102 {
103     printf("HIJACKED: %s\n", __func__);
104 
105     return((UINT)mock());
106 }
107 
__wrap__nxde_mqtt_client_unsubscribe(NXD_MQTT_CLIENT * client_ptr,CHAR * topic_name,UINT topic_name_length,UINT QoS)108 UINT __wrap__nxde_mqtt_client_unsubscribe(NXD_MQTT_CLIENT *client_ptr, CHAR *topic_name,
109                                           UINT topic_name_length, UINT QoS)
110 {
111     printf("HIJACKED: %s\n", __func__);
112     return((UINT)mock());
113 }
114 
115 UINT __real__nx_packet_data_append(NX_PACKET *packet_ptr, VOID *data_start, ULONG data_size,
116                                      NX_PACKET_POOL *pool_ptr, ULONG wait_option);
__wrap__nx_packet_data_append(NX_PACKET * packet_ptr,VOID * data_start,ULONG data_size,NX_PACKET_POOL * pool_ptr,ULONG wait_option)117 UINT __wrap__nx_packet_data_append(NX_PACKET *packet_ptr, VOID *data_start, ULONG data_size,
118                                      NX_PACKET_POOL *pool_ptr, ULONG wait_option)
119 {
120     printf("HIJACKED: %s\n", __func__);
121 
122     if (g_failed_append_index == g_total_append)
123     {
124         return(NX_NOT_SUCCESSFUL);
125     }
126 
127     g_total_append++;
128     return __real__nx_packet_data_append(packet_ptr, data_start, data_size, pool_ptr, wait_option);
129 }
130 
131 UINT __real_nx_azure_iot_buffer_allocate(NX_AZURE_IOT *nx_azure_iot_ptr, UCHAR **buffer_pptr,
132                                          UINT *buffer_size, VOID **buffer_context);
__wrap_nx_azure_iot_buffer_allocate(NX_AZURE_IOT * nx_azure_iot_ptr,UCHAR ** buffer_pptr,UINT * buffer_size,VOID ** buffer_context)133 UINT __wrap_nx_azure_iot_buffer_allocate(NX_AZURE_IOT *nx_azure_iot_ptr, UCHAR **buffer_pptr,
134                                          UINT *buffer_size, VOID **buffer_context)
135 {
136     printf("HIJACKED: %s\n", __func__);
137 
138     if (g_failed_allocation_index == g_total_allocation)
139     {
140         return(NX_NOT_SUCCESSFUL);
141     }
142 
143     g_total_allocation++;
144     return __real_nx_azure_iot_buffer_allocate(nx_azure_iot_ptr, buffer_pptr, buffer_size, buffer_context);
145 }
146 
__wrap__nxd_mqtt_client_publish_packet_send(NXD_MQTT_CLIENT * client_ptr,NX_PACKET * packet_ptr,USHORT packet_id,UINT QoS,ULONG wait_option)147 UINT __wrap__nxd_mqtt_client_publish_packet_send(NXD_MQTT_CLIENT *client_ptr, NX_PACKET *packet_ptr,
148                                                  USHORT packet_id, UINT QoS, ULONG wait_option)
149 {
150 UINT topic_name_length;
151 UINT message_length;
152 UCHAR *buffer_ptr;
153 UINT status = (UINT)mock();
154 
155     printf("HIJACKED: %s\n", __func__);
156     tx_mutex_put(client_ptr -> nxd_mqtt_client_mutex_ptr);
157 
158     if (status)
159     {
160         return(status);
161     }
162 
163     buffer_ptr = packet_ptr -> nx_packet_prepend_ptr;
164     topic_name_length = (buffer_ptr[5] << 8) | (buffer_ptr[6]);
165     message_length = packet_ptr -> nx_packet_length - (9 + topic_name_length);
166     assert_memory_equal(&buffer_ptr[7 + topic_name_length], g_expected_message, message_length);
167     assert_int_equal(QoS, 0);
168 
169     /* packet ownership taken and released */
170     nx_packet_release(packet_ptr);
171 
172     return(status);
173 }
174 
__wrap__nxde_mqtt_client_secure_connect(NXD_MQTT_CLIENT * client_ptr,NXD_ADDRESS * server_ip,UINT server_port,UINT (* tls_setup)(NXD_MQTT_CLIENT * client_ptr,NX_SECURE_TLS_SESSION *,NX_SECURE_X509_CERT *,NX_SECURE_X509_CERT *),UINT keepalive,UINT clean_session,ULONG wait_option)175 UINT __wrap__nxde_mqtt_client_secure_connect(NXD_MQTT_CLIENT *client_ptr, NXD_ADDRESS *server_ip, UINT server_port,
176                                              UINT (*tls_setup)(NXD_MQTT_CLIENT *client_ptr, NX_SECURE_TLS_SESSION *,
177                                                                NX_SECURE_X509_CERT *, NX_SECURE_X509_CERT *),
178                                              UINT keepalive, UINT clean_session, ULONG wait_option)
179 {
180     printf("HIJACKED: %s\n", __func__);
181 
182     tx_thread_suspend(&(iot.nx_azure_iot_ip_ptr -> nx_ip_thread));
183     client_ptr -> nxd_mqtt_client_state = NXD_MQTT_CLIENT_STATE_CONNECTED;
184     client_ptr -> nxd_mqtt_client_packet_identifier = 1;
185     client_ptr -> nxd_mqtt_tls_session.nx_secure_tls_id = NX_SECURE_TLS_ID;
186     client_ptr -> nxd_mqtt_tls_session.nx_secure_tls_local_session_active = NX_FALSE;
187     client_ptr -> nxd_mqtt_tls_session.nx_secure_tls_tcp_socket = &client_ptr -> nxd_mqtt_client_socket;
188     client_ptr -> nxd_mqtt_client_socket.nx_tcp_socket_connect_ip.nxd_ip_version = NX_IP_VERSION_V4;
189     client_ptr -> nxd_mqtt_client_socket.nx_tcp_socket_state = NX_TCP_ESTABLISHED;
190 
191     return(NXD_MQTT_SUCCESS);
192 }
193 
__wrap__nxde_mqtt_client_disconnect(NXD_MQTT_CLIENT * client_ptr)194 UINT __wrap__nxde_mqtt_client_disconnect(NXD_MQTT_CLIENT *client_ptr)
195 {
196     printf("HIJACKED: %s\n", __func__);
197     client_ptr -> nxd_mqtt_client_state = NXD_MQTT_CLIENT_STATE_IDLE;
198     client_ptr -> nxd_mqtt_client_socket.nx_tcp_socket_state = NX_TCP_CLOSED;
199     return(NXD_MQTT_SUCCESS);
200 }
201 
__wrap__nxde_dns_host_by_name_get(NX_DNS * dns_ptr,UCHAR * host_name,NXD_ADDRESS * host_address_ptr,ULONG wait_option,UINT lookup_type)202 UINT __wrap__nxde_dns_host_by_name_get(NX_DNS *dns_ptr, UCHAR *host_name, NXD_ADDRESS *host_address_ptr,
203                                        ULONG wait_option, UINT lookup_type)
204 {
205     printf("HIJACKED: %s\n", __func__);
206     host_address_ptr -> nxd_ip_address.v4 = IP_ADDRESS(127, 0, 0, 1);
207     return(NX_DNS_SUCCESS);
208 }
209 
on_receive_callback(NX_AZURE_IOT_HUB_CLIENT * hub_client_ptr,VOID * arg)210 static VOID on_receive_callback(NX_AZURE_IOT_HUB_CLIENT *hub_client_ptr, VOID *arg)
211 {
212     *((UINT *)arg) = 1;
213 }
214 
mqtt_client_set_fixed_header(NXD_MQTT_CLIENT * client_ptr,NX_PACKET * packet_ptr,UCHAR control_header,UINT length,UINT wait_option)215 static UINT mqtt_client_set_fixed_header(NXD_MQTT_CLIENT *client_ptr, NX_PACKET *packet_ptr, UCHAR control_header, UINT length, UINT wait_option)
216 {
217 UCHAR  fixed_header[5];
218 UCHAR *byte = fixed_header;
219 UINT   count = 0;
220 UINT   ret;
221 
222     *byte = control_header;
223     byte++;
224 
225     do
226     {
227         if (length & 0xFFFFFF80)
228         {
229             *(byte + count) = (UCHAR)((length & 0x7F) | 0x80);
230         }
231         else
232         {
233             *(byte + count) = length & 0x7F;
234         }
235         length = length >> 7;
236 
237         count++;
238     } while (length != 0);
239 
240     ret = __real__nx_packet_data_append(packet_ptr, fixed_header, count + 1,
241                                         client_ptr -> nxd_mqtt_client_packet_pool_ptr, wait_option);
242 
243     return(ret);
244 }
245 
construct_direct_method_response(NX_AZURE_IOT_HUB_CLIENT * hub_client_ptr,const UCHAR * topic,ULONG topic_len,const UCHAR * message_payload_ptr,ULONG message_payload_length,NX_PACKET ** packet_pptr)246 static VOID construct_direct_method_response(NX_AZURE_IOT_HUB_CLIENT *hub_client_ptr,
247                                              const UCHAR *topic, ULONG topic_len,
248                                              const UCHAR *message_payload_ptr, ULONG message_payload_length,
249                                              NX_PACKET **packet_pptr)
250 {
251 NX_PACKET *packet_ptr;
252 ULONG total_length;
253 ULONG topic_length = topic_len;
254 UCHAR bytes[2];
255 UINT i;
256 
257     assert_int_equal(nx_packet_allocate(iot.nx_azure_iot_pool_ptr, &packet_ptr, 0, NX_NO_WAIT),
258                      NX_AZURE_IOT_SUCCESS);
259     total_length = topic_length + 2 + 2 + message_payload_length; /* Two bytes for fixed topic_length field
260                                                                      and two bytes for packet id. */
261 
262     /* Set fixed header. */
263     assert_int_equal(mqtt_client_set_fixed_header(&(hub_client_ptr -> nx_azure_iot_hub_client_resource.resource_mqtt), packet_ptr,
264                                                   (UCHAR)((MQTT_CONTROL_PACKET_TYPE_PUBLISH << 4) | MQTT_PUBLISH_QOS_LEVEL_1),
265                                                   total_length, NX_NO_WAIT),
266                      NX_AZURE_IOT_SUCCESS);
267 
268     /* Set topic length. */
269     bytes[0] = (topic_length >> 8) & 0xFF;
270     bytes[1] = topic_length & 0xFF;
271     assert_int_equal(__real__nx_packet_data_append(packet_ptr, bytes, sizeof(bytes),
272                                                    iot.nx_azure_iot_pool_ptr, NX_NO_WAIT),
273                      NX_AZURE_IOT_SUCCESS);
274 
275     /* Set topic. */
276     assert_int_equal(__real__nx_packet_data_append(packet_ptr, (VOID *)topic, topic_len,
277                                                    iot.nx_azure_iot_pool_ptr, NX_NO_WAIT),
278                      NX_AZURE_IOT_SUCCESS);
279     /* Set packet ID. The value does not matter. */
280     assert_int_equal(__real__nx_packet_data_append(packet_ptr, bytes, sizeof(bytes),
281                                                    iot.nx_azure_iot_pool_ptr, NX_NO_WAIT),
282                      NX_AZURE_IOT_SUCCESS);
283 
284     /* Set message payload. */
285     if (message_payload_length > 0)
286     {
287         assert_int_equal(__real__nx_packet_data_append(packet_ptr, (VOID *)message_payload_ptr, message_payload_length,
288                                                        iot.nx_azure_iot_pool_ptr, NX_NO_WAIT),
289                          NX_AZURE_IOT_SUCCESS);
290     }
291 
292     *packet_pptr = packet_ptr;
293 }
294 
generate_direct_method_response(NX_AZURE_IOT_HUB_CLIENT * hub_client_ptr)295 static VOID generate_direct_method_response(NX_AZURE_IOT_HUB_CLIENT *hub_client_ptr)
296 {
297 NX_PACKET *packet_ptr;
298 
299     construct_direct_method_response(hub_client_ptr, direct_method_response_topic, sizeof(direct_method_response_topic) - 1,
300                                      test_method_response_payload, sizeof(test_method_response_payload) - 1,
301                                      &packet_ptr);
302 
303     /* Simulate callback from MQTT layer.  */
304     hub_client_ptr -> nx_azure_iot_hub_client_resource.resource_mqtt.message_receive_queue_head = packet_ptr;
305     hub_client_ptr -> nx_azure_iot_hub_client_resource.resource_mqtt.message_receive_queue_depth = 1;
306     tx_mutex_get(hub_client_ptr -> nx_azure_iot_ptr -> nx_azure_iot_mutex_ptr, NX_WAIT_FOREVER);
307     test_receive_notify(&(hub_client_ptr -> nx_azure_iot_hub_client_resource.resource_mqtt), 1);
308     tx_mutex_put(hub_client_ptr -> nx_azure_iot_ptr -> nx_azure_iot_mutex_ptr);
309 }
310 
reset_global_state()311 static VOID reset_global_state()
312 {
313     /* reset global state */
314     g_failed_append_index = (UINT)-1;
315     g_total_append = 0;
316     g_failed_allocation_index = (UINT)-1;
317     g_total_allocation = 0;
318     g_expected_message = NX_NULL;
319 }
320 
321 /* Hook execute before all tests. */
test_suit_begin()322 static VOID test_suit_begin()
323 {
324 
325     /* Initialize root certificate.  */
326     assert_int_equal(nx_secure_x509_certificate_initialize(&root_ca_cert,
327                                                            (UCHAR *)_nx_azure_iot_root_cert,
328                                                            (USHORT)_nx_azure_iot_root_cert_size,
329                                                            NX_NULL, 0, NULL, 0, NX_SECURE_X509_KEY_TYPE_NONE),
330                      NX_AZURE_IOT_SUCCESS);
331 
332     /* Initialize azure iot handle.  */
333     assert_int_equal(nx_azure_iot_create(&iot, (UCHAR *)"Azure IoT",
334                                          g_ip_ptr, g_pool_ptr, g_dns_ptr,
335                                          (UCHAR *)demo_cloud_thread_stack,
336                                          sizeof(demo_cloud_thread_stack),
337                                          DEMO_CLOUD_THREAD_PRIORITY, unix_time_get),
338                      NX_AZURE_IOT_SUCCESS);
339 
340     /* Record number of available packet before test */
341     g_available_packet = g_pool_ptr -> nx_packet_pool_available;
342 
343     /* Initialize azure iot handle.  */
344     assert_int_equal(nx_azure_iot_hub_client_initialize(&iot_client, &iot,
345                                                         g_hostname, sizeof(g_hostname),
346                                                         g_device_id, sizeof(g_device_id),
347                                                         "", 0,
348                                                         _nx_azure_iot_tls_supported_crypto,
349                                                         _nx_azure_iot_tls_supported_crypto_size,
350                                                         _nx_azure_iot_tls_ciphersuite_map,
351                                                         _nx_azure_iot_tls_ciphersuite_map_size,
352                                                         metadata_buffer, sizeof(metadata_buffer),
353                                                         &root_ca_cert),
354                      NX_AZURE_IOT_SUCCESS);
355 
356     /* Connect IoTHub client */
357     assert_int_equal(nx_azure_iot_hub_client_connect(&iot_client, NX_FALSE, NX_WAIT_FOREVER),
358                      NX_AZURE_IOT_SUCCESS);
359 }
360 
361 /* Hook execute after all tests are executed successfully */
test_suit_end()362 static VOID test_suit_end()
363 {
364 
365     /* Disconnect IoTHub client */
366     assert_int_equal(nx_azure_iot_hub_client_disconnect(&iot_client), NX_AZURE_IOT_SUCCESS);
367 
368     /* Check if all the packet are released */
369     assert_int_equal(g_pool_ptr -> nx_packet_pool_available, g_available_packet);
370 
371     /* Deinitialize IoTHub Client */
372     assert_int_equal(nx_azure_iot_hub_client_deinitialize(&iot_client),
373                      NX_AZURE_IOT_SUCCESS);
374 
375     /* SUCCESS: iot is deleted. */
376     assert_int_equal(nx_azure_iot_delete(&iot), NX_AZURE_IOT_SUCCESS);
377 }
378 
379 /* Hook executed before every test */
test_begin()380 static VOID test_begin()
381 {
382     reset_global_state();
383 }
384 
385 /* Hook execute after all tests are executed successfully */
test_end()386 static VOID test_end()
387 {
388 }
389 
390 /**
391  * Test direct method enable with invalid argument failed.
392  *
393  **/
test_nx_azure_iot_hub_client_direct_method_enable_invalid_argument_failure()394 static VOID test_nx_azure_iot_hub_client_direct_method_enable_invalid_argument_failure()
395 {
396     printf("test starts =>: %s\n", __func__);
397 
398     assert_int_not_equal(nx_azure_iot_hub_client_direct_method_enable(NX_NULL),
399                          NX_AZURE_IOT_SUCCESS);
400 }
401 
402 /**
403  * Test direct method enable with unsuccessful subscribe failed.
404  *
405  **/
test_nx_azure_iot_hub_client_direct_method_enable_failure()406 static VOID test_nx_azure_iot_hub_client_direct_method_enable_failure()
407 {
408     printf("test starts =>: %s\n", __func__);
409 
410     will_return(__wrap__nxde_mqtt_client_subscribe, NX_NOT_SUCCESSFUL);
411     assert_int_not_equal(nx_azure_iot_hub_client_direct_method_enable(&iot_client),
412                          NX_AZURE_IOT_SUCCESS);
413 }
414 
415 /**
416  * Test direct method enable succeeds.
417  *
418  **/
test_nx_azure_iot_hub_client_direct_method_enable_success()419 static VOID test_nx_azure_iot_hub_client_direct_method_enable_success()
420 {
421     printf("test starts =>: %s\n", __func__);
422 
423     will_return(__wrap__nxde_mqtt_client_subscribe, NX_AZURE_IOT_SUCCESS);
424     assert_int_equal(nx_azure_iot_hub_client_direct_method_enable(&iot_client),
425                      NX_AZURE_IOT_SUCCESS);
426 }
427 
428 /**
429  * Test direct method disable with invalid argument failed.
430  *
431  **/
test_nx_azure_iot_hub_client_direct_method_disable_invalid_argument_failure()432 static VOID test_nx_azure_iot_hub_client_direct_method_disable_invalid_argument_failure()
433 {
434     printf("test starts =>: %s\n", __func__);
435 
436     assert_int_not_equal(nx_azure_iot_hub_client_direct_method_disable(NX_NULL),
437                          NX_AZURE_IOT_SUCCESS);
438 }
439 
440 /**
441  * Test direct method disable with unsuccessful un-subscribe failed.
442  *
443  **/
test_nx_azure_iot_hub_client_direct_method_disable_failure()444 static VOID test_nx_azure_iot_hub_client_direct_method_disable_failure()
445 {
446     printf("test starts =>: %s\n", __func__);
447 
448     will_return(__wrap__nxde_mqtt_client_unsubscribe, NX_NOT_SUCCESSFUL);
449     assert_int_not_equal(nx_azure_iot_hub_client_direct_method_disable(&iot_client),
450                          NX_AZURE_IOT_SUCCESS);
451 }
452 
453 /**
454  * Test direct method disable succeeds.
455  *
456  **/
test_nx_azure_iot_hub_client_direct_method_disable_success()457 static VOID test_nx_azure_iot_hub_client_direct_method_disable_success()
458 {
459     printf("test starts =>: %s\n", __func__);
460 
461     will_return(__wrap__nxde_mqtt_client_unsubscribe, NX_AZURE_IOT_SUCCESS);
462     assert_int_equal(nx_azure_iot_hub_client_direct_method_disable(&iot_client),
463                      NX_AZURE_IOT_SUCCESS);
464 }
465 
466 /**
467  * Test direct method receive with invalid argument failed.
468  *
469  **/
test_nx_azure_iot_hub_client_direct_method_message_receive_invalid_argument_failure()470 static VOID test_nx_azure_iot_hub_client_direct_method_message_receive_invalid_argument_failure()
471 {
472 const UCHAR *method_name_ptr;
473 USHORT method_name_length;
474 VOID *context_ptr;
475 USHORT context_length;
476 NX_PACKET *packet_ptr;
477 
478     printf("test starts =>: %s\n", __func__);
479 
480     assert_int_not_equal(nx_azure_iot_hub_client_direct_method_message_receive(NX_NULL,
481                                                                                &method_name_ptr, &method_name_length,
482                                                                                &context_ptr, &context_length,
483                                                                                &packet_ptr, NX_WAIT_FOREVER),
484                          NX_AZURE_IOT_SUCCESS);
485 }
486 
487 /**
488  * Test direct method receive succeeds.
489  *
490  **/
test_nx_azure_iot_hub_client_direct_method_message_receive_success()491 static VOID test_nx_azure_iot_hub_client_direct_method_message_receive_success()
492 {
493 const UCHAR *method_name_ptr;
494 USHORT method_name_length;
495 VOID *context_ptr;
496 USHORT context_length;
497 NX_PACKET *packet_ptr;
498 ULONG bytes_copied;
499 
500     printf("test starts =>: %s\n", __func__);
501 
502     will_return(__wrap__nxde_mqtt_client_subscribe, NX_AZURE_IOT_SUCCESS);
503     assert_int_equal(nx_azure_iot_hub_client_direct_method_enable(&iot_client),
504                      NX_AZURE_IOT_SUCCESS);
505     generate_direct_method_response(&iot_client);
506 
507     assert_int_equal(nx_azure_iot_hub_client_direct_method_message_receive(&iot_client,
508                                                                            &method_name_ptr, &method_name_length,
509                                                                            &context_ptr, &context_length,
510                                                                            &packet_ptr, NX_WAIT_FOREVER),
511                      NX_AZURE_IOT_SUCCESS);
512 
513     assert_memory_equal(method_name_ptr, test_method_name, sizeof(test_method_name) - 1);
514     assert_int_equal(nx_packet_data_extract_offset(packet_ptr, 0, result_buffer,
515                                                    sizeof(result_buffer), &bytes_copied),
516                      NX_AZURE_IOT_SUCCESS);
517     assert_memory_equal(result_buffer, test_method_response_payload, sizeof(test_method_response_payload) - 1);
518 
519     nx_packet_release(packet_ptr);
520 }
521 
522 /**
523  * Test direct method receive succeeds with NX_NO_WAIT.
524  *
525  **/
test_nx_azure_iot_hub_client_direct_method_message_receive_no_blocking_success()526 static VOID test_nx_azure_iot_hub_client_direct_method_message_receive_no_blocking_success()
527 {
528 const UCHAR *method_name_ptr;
529 USHORT method_name_length;
530 VOID *context_ptr;
531 USHORT context_length;
532 NX_PACKET *packet_ptr;
533 ULONG bytes_copied;
534 UINT received = 0;
535 
536     printf("test starts =>: %s\n", __func__);
537 
538     assert_int_equal(nx_azure_iot_hub_client_receive_callback_set(&iot_client,
539                                                                   NX_AZURE_IOT_HUB_DIRECT_METHOD,
540                                                                   on_receive_callback,
541                                                                   (VOID *)&received),
542                      NX_AZURE_IOT_SUCCESS);
543     will_return(__wrap__nxde_mqtt_client_subscribe, NX_AZURE_IOT_SUCCESS);
544     assert_int_equal(nx_azure_iot_hub_client_direct_method_enable(&iot_client),
545                      NX_AZURE_IOT_SUCCESS);
546     generate_direct_method_response(&iot_client);
547 
548     while (!received)
549     {
550         tx_thread_sleep(NX_IP_PERIODIC_RATE / 10);
551     }
552 
553     assert_int_equal(nx_azure_iot_hub_client_direct_method_message_receive(&iot_client,
554                                                                            &method_name_ptr, &method_name_length,
555                                                                            &context_ptr, &context_length,
556                                                                            &packet_ptr, NX_NO_WAIT),
557                      NX_AZURE_IOT_SUCCESS);
558 
559     assert_memory_equal(method_name_ptr, test_method_name, sizeof(test_method_name) - 1);
560     assert_int_equal(nx_packet_data_extract_offset(packet_ptr, 0, result_buffer,
561                                                    sizeof(result_buffer), &bytes_copied),
562                      NX_AZURE_IOT_SUCCESS);
563     assert_memory_equal(result_buffer, test_method_response_payload, sizeof(test_method_response_payload) - 1);
564 
565     nx_packet_release(packet_ptr);
566 }
567 
568 /**
569  * Test no one is receiving direct method.
570  *
571  **/
test_nx_azure_iot_hub_client_direct_method_message_no_receive()572 static VOID test_nx_azure_iot_hub_client_direct_method_message_no_receive()
573 {
574 const UCHAR *method_name_ptr;
575 USHORT method_name_length;
576 VOID *context_ptr;
577 USHORT context_length;
578 NX_PACKET *packet_ptr;
579 ULONG bytes_copied;
580 
581     printf("test starts =>: %s\n", __func__);
582 
583     will_return(__wrap__nxde_mqtt_client_subscribe, NX_AZURE_IOT_SUCCESS);
584     assert_int_equal(nx_azure_iot_hub_client_direct_method_enable(&iot_client),
585                      NX_AZURE_IOT_SUCCESS);
586     generate_direct_method_response(&iot_client);
587 }
588 
589 
590 /**
591  * Test direct method response invalid argument fail.
592  *
593  **/
test_nx_azure_iot_hub_client_direct_method_message_response_invalid_argument_fail()594 static VOID test_nx_azure_iot_hub_client_direct_method_message_response_invalid_argument_fail()
595 {
596     printf("test starts =>: %s\n", __func__);
597 
598     assert_int_not_equal(nx_azure_iot_hub_client_direct_method_message_response(NX_NULL,
599                                                                                 200, (VOID *)test_request_id, sizeof(test_request_id) - 1,
600                                                                                 (UCHAR *)test_send_payload, sizeof(test_send_payload) - 1,
601                                                                                 NX_WAIT_FOREVER),
602                          NX_AZURE_IOT_SUCCESS);
603     assert_int_not_equal(nx_azure_iot_hub_client_direct_method_message_response(&iot_client,
604                                                                                 200, NX_NULL, 0,
605                                                                                 (UCHAR *)test_send_payload, sizeof(test_send_payload) - 1,
606                                                                                 NX_WAIT_FOREVER),
607                          NX_AZURE_IOT_SUCCESS);
608 }
609 
610 
611 /**
612  * Test direct method response send fail.
613  *
614  **/
test_nx_azure_iot_hub_client_direct_method_message_response_send_failure_fail()615 static VOID test_nx_azure_iot_hub_client_direct_method_message_response_send_failure_fail()
616 {
617     printf("test starts =>: %s\n", __func__);
618     will_return(__wrap__nxd_mqtt_client_publish_packet_send, NX_NOT_SUCCESSFUL);
619 
620     assert_int_not_equal(nx_azure_iot_hub_client_direct_method_message_response(&iot_client,
621                                                                                 200, (VOID *)test_request_id, sizeof(test_request_id) - 1,
622                                                                                 (UCHAR *)test_send_payload, sizeof(test_send_payload) - 1,
623                                                                                 NX_WAIT_FOREVER),
624                          NX_AZURE_IOT_SUCCESS);
625 }
626 
627 /**
628  * Test direct method response succeeds.
629  *
630  **/
test_nx_azure_iot_hub_client_direct_method_message_response_success()631 static VOID test_nx_azure_iot_hub_client_direct_method_message_response_success()
632 {
633     printf("test starts =>: %s\n", __func__);
634     will_return(__wrap__nxd_mqtt_client_publish_packet_send, NX_AZURE_IOT_SUCCESS);
635     g_expected_message = (CHAR *)test_send_payload;
636 
637     assert_int_equal(nx_azure_iot_hub_client_direct_method_message_response(&iot_client,
638                                                                             200, (VOID *)test_request_id, sizeof(test_request_id) - 1,
639                                                                             (UCHAR *)test_send_payload, sizeof(test_send_payload) - 1,
640                                                                             NX_WAIT_FOREVER),
641                      NX_AZURE_IOT_SUCCESS);
642 }
643 
644 /**
645  * Test direct method response empty json succeeds.
646  *
647  **/
test_nx_azure_iot_hub_client_direct_method_message_response_empty_success()648 static VOID test_nx_azure_iot_hub_client_direct_method_message_response_empty_success()
649 {
650     printf("test starts =>: %s\n", __func__);
651     will_return(__wrap__nxd_mqtt_client_publish_packet_send, NX_AZURE_IOT_SUCCESS);
652     g_expected_message = (CHAR *)"{}";
653 
654     assert_int_equal(nx_azure_iot_hub_client_direct_method_message_response(&iot_client,
655                                                                             200, (VOID *)test_request_id, sizeof(test_request_id) - 1,
656                                                                             NX_NULL, 0,
657                                                                             NX_WAIT_FOREVER),
658                      NX_AZURE_IOT_SUCCESS);
659 }
660 
demo_entry(NX_IP * ip_ptr,NX_PACKET_POOL * pool_ptr,NX_DNS * dns_ptr,UINT (* unix_time_callback)(ULONG * unix_time))661 VOID demo_entry(NX_IP* ip_ptr, NX_PACKET_POOL* pool_ptr, NX_DNS* dns_ptr, UINT (*unix_time_callback)(ULONG *unix_time))
662 {
663     NX_AZURE_TEST_FN tests[] = { test_nx_azure_iot_hub_client_direct_method_enable_invalid_argument_failure,
664                                test_nx_azure_iot_hub_client_direct_method_enable_failure,
665                                test_nx_azure_iot_hub_client_direct_method_enable_success,
666                                test_nx_azure_iot_hub_client_direct_method_disable_invalid_argument_failure,
667                                test_nx_azure_iot_hub_client_direct_method_disable_failure,
668                                test_nx_azure_iot_hub_client_direct_method_disable_success,
669                                test_nx_azure_iot_hub_client_direct_method_message_receive_invalid_argument_failure,
670                                test_nx_azure_iot_hub_client_direct_method_message_receive_success,
671                                test_nx_azure_iot_hub_client_direct_method_message_receive_no_blocking_success,
672                                test_nx_azure_iot_hub_client_direct_method_message_no_receive,
673                                test_nx_azure_iot_hub_client_direct_method_message_response_invalid_argument_fail,
674                                test_nx_azure_iot_hub_client_direct_method_message_response_send_failure_fail,
675                                test_nx_azure_iot_hub_client_direct_method_message_response_success,
676                                test_nx_azure_iot_hub_client_direct_method_message_response_empty_success };
677     INT number_of_tests =  sizeof(tests)/sizeof(tests[0]);
678     g_ip_ptr = ip_ptr;
679     g_pool_ptr = pool_ptr;
680     g_dns_ptr = dns_ptr;
681 
682     test_suit_begin();
683 
684     printf("Number of tests %d\r\n", number_of_tests);
685     for (INT index = 0; index < number_of_tests; index++)
686     {
687         test_begin();
688         tests[index]();
689         test_end();
690     }
691 
692     test_suit_end();
693 }
694