1 /*
2 * Copyright (c) 2016 Intel Corporation.
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #include <zephyr/tc_util.h>
8 #include <mqtt_internal.h>
9 #include <zephyr/sys/util.h> /* for ARRAY_SIZE */
10 #include <zephyr/ztest.h>
11
12 #define CLIENTID MQTT_UTF8_LITERAL("zephyr")
13 #define TOPIC MQTT_UTF8_LITERAL("sensors")
14 #define WILL_TOPIC MQTT_UTF8_LITERAL("quitting")
15 #define WILL_MSG MQTT_UTF8_LITERAL("bye")
16 #define USERNAME MQTT_UTF8_LITERAL("zephyr1")
17 #define PASSWORD MQTT_UTF8_LITERAL("password")
18
19 #define BUFFER_SIZE 128
20
21 static ZTEST_DMEM uint8_t rx_buffer[BUFFER_SIZE];
22 static ZTEST_DMEM uint8_t tx_buffer[BUFFER_SIZE];
23 static ZTEST_DMEM struct mqtt_client client;
24
25 static ZTEST_DMEM struct mqtt_topic topic_qos_0 = {
26 .qos = 0,
27 .topic = TOPIC,
28 };
29 static ZTEST_DMEM struct mqtt_topic topic_qos_1 = {
30 .qos = 1,
31 .topic = TOPIC,
32 };
33 static ZTEST_DMEM struct mqtt_topic topic_qos_2 = {
34 .qos = 2,
35 .topic = TOPIC,
36 };
37 static ZTEST_DMEM struct mqtt_topic will_topic_qos_0 = {
38 .qos = 0,
39 .topic = WILL_TOPIC,
40 };
41 static ZTEST_DMEM struct mqtt_topic will_topic_qos_1 = {
42 .qos = 1,
43 .topic = WILL_TOPIC,
44 };
45 static ZTEST_DMEM struct mqtt_utf8 will_msg = WILL_MSG;
46 static ZTEST_DMEM struct mqtt_utf8 username = USERNAME;
47 static ZTEST_DMEM struct mqtt_utf8 password = PASSWORD;
48
49 /**
50 * @brief MQTT test structure
51 */
52 struct mqtt_test {
53 /* test name, for example: "test connect 1" */
54 const char *test_name;
55
56 /* cast to something like:
57 * struct mqtt_publish_param *msg_publish =
58 * (struct mqtt_publish_param *)ctx
59 */
60 void *ctx;
61
62 /* pointer to the eval routine, for example:
63 * eval_fcn = eval_msg_connect
64 */
65 int (*eval_fcn)(struct mqtt_test *);
66
67 /* expected result */
68 uint8_t *expected;
69
70 /* length of 'expected' */
71 uint16_t expected_len;
72 };
73
74 /**
75 * @brief eval_msg_connect Evaluate the given mqtt_test against the
76 * connect packing/unpacking routines.
77 * @param [in] mqtt_test MQTT test structure
78 * @return TC_PASS on success
79 * @return TC_FAIL on error
80 */
81 static int eval_msg_connect(struct mqtt_test *mqtt_test);
82
83 /**
84 * @brief eval_msg_publish Evaluate the given mqtt_test against the
85 * publish packing/unpacking routines.
86 * @param [in] mqtt_test MQTT test structure
87 * @return TC_PASS on success
88 * @return TC_FAIL on error
89 */
90 static int eval_msg_publish(struct mqtt_test *mqtt_test);
91
92 /**
93 * @brief eval_msg_corrupted_publish Evaluate the given mqtt_test against the
94 * corrupted publish message.
95 * @param [in] mqtt_test MQTT test structure
96 * @return TC_PASS on success
97 * @return TC_FAIL on error
98 */
99 static int eval_msg_corrupted_publish(struct mqtt_test *mqtt_test);
100
101 /**
102 * @brief eval_msg_subscribe Evaluate the given mqtt_test against the
103 * subscribe packing/unpacking routines.
104 * @param [in] mqtt_test MQTT test structure
105 * @return TC_PASS on success
106 * @return TC_FAIL on error
107 */
108 static int eval_msg_subscribe(struct mqtt_test *mqtt_test);
109
110 /**
111 * @brief eval_msg_suback Evaluate the given mqtt_test against the
112 * suback packing/unpacking routines.
113 * @param [in] mqtt_test MQTT test structure
114 * @return TC_PASS on success
115 * @return TC_FAIL on error
116 */
117 static int eval_msg_suback(struct mqtt_test *mqtt_test);
118
119 /**
120 * @brief eval_msg_pingreq Evaluate the given mqtt_test against the
121 * pingreq packing/unpacking routines.
122 * @param [in] mqtt_test MQTT test structure
123 * @return TC_PASS on success
124 * @return TC_FAIL on error
125 */
126 static int eval_msg_pingreq(struct mqtt_test *mqtt_test);
127
128 /**
129 * @brief eval_msg_puback Evaluate the given mqtt_test against the
130 * puback routines.
131 * @param [in] mqtt_test MQTT test structure
132 * @return TC_PASS on success
133 * @return TC_FAIL on error
134 */
135 static int eval_msg_puback(struct mqtt_test *mqtt_test);
136
137 /**
138 * @brief eval_msg_puback Evaluate the given mqtt_test against the
139 * pubcomp routines.
140 * @param [in] mqtt_test MQTT test structure
141 * @return TC_PASS on success
142 * @return TC_FAIL on error
143 */
144 static int eval_msg_pubcomp(struct mqtt_test *mqtt_test);
145
146 /**
147 * @brief eval_msg_pubrec Evaluate the given mqtt_test against the
148 * pubrec routines.
149 * @param [in] mqtt_test MQTT test structure
150 * @return TC_PASS on success
151 * @return TC_FAIL on error
152 */
153 static int eval_msg_pubrec(struct mqtt_test *mqtt_test);
154
155 /**
156 * @brief eval_msg_pubrel Evaluate the given mqtt_test against the
157 * pubrel routines.
158 * @param [in] mqtt_test MQTT test structure
159 * @return TC_PASS on success
160 * @return TC_FAIL on error
161 */
162 static int eval_msg_pubrel(struct mqtt_test *mqtt_test);
163
164 /**
165 * @brief eval_msg_unsuback Evaluate the given mqtt_test against the
166 * unsuback routines.
167 * @param [in] mqtt_test MQTT test structure
168 * @return TC_PASS on success
169 * @return TC_FAIL on error
170 */
171 static int eval_msg_unsuback(struct mqtt_test *mqtt_test);
172
173 /**
174 * @brief eval_msg_disconnect Evaluate the given mqtt_test against the
175 * disconnect routines.
176 * @param [in] mqtt_test MQTT test structure
177 * @return TC_PASS on success
178 * @return TC_FAIL on error
179 */
180 static int eval_msg_disconnect(struct mqtt_test *mqtt_test);
181
182 /**
183 * @brief eval_max_pkt_len Evaluate header with maximum allowed packet
184 * length.
185 * @param [in] mqtt_test MQTT test structure
186 * @return TC_PASS on success
187 * @return TC_FAIL on error
188 */
189 static int eval_max_pkt_len(struct mqtt_test *mqtt_test);
190
191 /**
192 * @brief eval_corrupted_pkt_len Evaluate header exceeding maximum
193 * allowed packet length.
194 * @param [in] mqtt_test MQTT test structure
195 * @return TC_PASS on success
196 * @return TC_FAIL on error
197 */
198 static int eval_corrupted_pkt_len(struct mqtt_test *mqtt_test);
199
200 /**
201 * @brief eval_buffers Evaluate if two given buffers are equal
202 * @param [in] buf Input buffer 1, mostly used as the 'computed'
203 * buffer
204 * @param [in] expected Expected buffer
205 * @param [in] len 'expected' len
206 * @return TC_PASS on success
207 * @return TC_FAIL on error and prints both buffers
208 */
209 static int eval_buffers(const struct buf_ctx *buf,
210 const uint8_t *expected, uint16_t len);
211
212
213 /**
214 * @brief print_array Prints the array 'a' of 'size' elements
215 * @param a The array
216 * @param size Array's size
217 */
218 static void print_array(const uint8_t *a, uint16_t size);
219
220 /*
221 * MQTT CONNECT msg:
222 * Clean session: 1 Client id: [6] 'zephyr' Will flag: 0
223 * Will QoS: 0 Will retain: 0 Will topic: [0]
224 * Will msg: [0] Keep alive: 60 User name: [0]
225 * Password: [0]
226 *
227 * Message can be generated by the following command:
228 * mosquitto_sub -V mqttv311 -i zephyr -k 60 -t sensors
229 */
230 static ZTEST_DMEM
231 uint8_t connect1[] = {0x10, 0x12, 0x00, 0x04, 0x4d, 0x51, 0x54, 0x54,
232 0x04, 0x02, 0x00, 0x3c, 0x00, 0x06, 0x7a, 0x65,
233 0x70, 0x68, 0x79, 0x72};
234
235 static ZTEST_DMEM struct mqtt_client client_connect1 = {
236 .clean_session = 1, .client_id = CLIENTID,
237 .will_retain = 0, .will_topic = NULL,
238 .will_message = NULL, .user_name = NULL,
239 .password = NULL
240 };
241
242 /*
243 * MQTT CONNECT msg:
244 * Clean session: 1 Client id: [6] 'zephyr' Will flag: 1
245 * Will QoS: 0 Will retain: 0 Will topic: [8] quitting
246 * Will msg: [3] bye Keep alive: 0
247 *
248 * Message can be generated by the following command:
249 * mosquitto_sub -V mqttv311 -i zephyr -k 60 -t sensors --will-topic quitting \
250 * --will-qos 0 --will-payload bye
251 */
252 static ZTEST_DMEM
253 uint8_t connect2[] = {0x10, 0x21, 0x00, 0x04, 0x4d, 0x51, 0x54, 0x54,
254 0x04, 0x06, 0x00, 0x3c, 0x00, 0x06, 0x7a, 0x65,
255 0x70, 0x68, 0x79, 0x72, 0x00, 0x08, 0x71, 0x75,
256 0x69, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x00, 0x03,
257 0x62, 0x79, 0x65};
258
259 static ZTEST_DMEM struct mqtt_client client_connect2 = {
260 .clean_session = 1, .client_id = CLIENTID,
261 .will_retain = 0, .will_topic = &will_topic_qos_0,
262 .will_message = &will_msg, .user_name = NULL,
263 .password = NULL
264 };
265
266 /*
267 * MQTT CONNECT msg:
268 * Same message as connect3, but set Will retain: 1
269 *
270 * Message can be generated by the following command:
271 * mosquitto_sub -V mqttv311 -i zephyr -k 60 -t sensors --will-topic quitting \
272 * --will-qos 0 --will-payload bye --will-retain
273 */
274 static ZTEST_DMEM
275 uint8_t connect3[] = {0x10, 0x21, 0x00, 0x04, 0x4d, 0x51, 0x54, 0x54,
276 0x04, 0x26, 0x00, 0x3c, 0x00, 0x06, 0x7a, 0x65,
277 0x70, 0x68, 0x79, 0x72, 0x00, 0x08, 0x71, 0x75,
278 0x69, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x00, 0x03,
279 0x62, 0x79, 0x65};
280
281 static ZTEST_DMEM struct mqtt_client client_connect3 = {
282 .clean_session = 1, .client_id = CLIENTID,
283 .will_retain = 1, .will_topic = &will_topic_qos_0,
284 .will_message = &will_msg, .user_name = NULL,
285 .password = NULL
286 };
287
288 /*
289 * MQTT CONNECT msg:
290 * Same message as connect3, but set Will QoS: 1
291 *
292 * Message can be generated by the following command:
293 * mosquitto_sub -V mqttv311 -i zephyr -k 60 -t sensors --will-topic quitting \
294 * --will-qos 1 --will-payload bye
295 */
296 static ZTEST_DMEM
297 uint8_t connect4[] = {0x10, 0x21, 0x00, 0x04, 0x4d, 0x51, 0x54, 0x54,
298 0x04, 0x0e, 0x00, 0x3c, 0x00, 0x06, 0x7a, 0x65,
299 0x70, 0x68, 0x79, 0x72, 0x00, 0x08, 0x71, 0x75,
300 0x69, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x00, 0x03,
301 0x62, 0x79, 0x65};
302
303 static ZTEST_DMEM struct mqtt_client client_connect4 = {
304 .clean_session = 1, .client_id = CLIENTID,
305 .will_retain = 0, .will_topic = &will_topic_qos_1,
306 .will_message = &will_msg, .user_name = NULL,
307 .password = NULL
308 };
309
310 /*
311 * MQTT CONNECT msg:
312 * Same message as connect5, but set Will retain: 1
313 *
314 * Message can be generated by the following command:
315 * mosquitto_sub -V mqttv311 -i zephyr -k 60 -t sensors --will-topic quitting \
316 * --will-qos 1 --will-payload bye --will-retain
317 */
318 static ZTEST_DMEM
319 uint8_t connect5[] = {0x10, 0x21, 0x00, 0x04, 0x4d, 0x51, 0x54, 0x54,
320 0x04, 0x2e, 0x00, 0x3c, 0x00, 0x06, 0x7a, 0x65,
321 0x70, 0x68, 0x79, 0x72, 0x00, 0x08, 0x71, 0x75,
322 0x69, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x00, 0x03,
323 0x62, 0x79, 0x65};
324
325 static ZTEST_DMEM struct mqtt_client client_connect5 = {
326 .clean_session = 1, .client_id = CLIENTID,
327 .will_retain = 1, .will_topic = &will_topic_qos_1,
328 .will_message = &will_msg, .user_name = NULL,
329 .password = NULL
330 };
331
332 /*
333 * MQTT CONNECT msg:
334 * Same message as connect6, but set username: zephyr1 and password: password
335 *
336 * Message can be generated by the following command:
337 * mosquitto_sub -V mqttv311 -i zephyr -k 60 -t sensors --will-topic quitting \
338 * --will-qos 1 --will-payload bye --will-retain -u zephyr1 -P password
339 */
340 static ZTEST_DMEM
341 uint8_t connect6[] = {0x10, 0x34, 0x00, 0x04, 0x4d, 0x51, 0x54, 0x54,
342 0x04, 0xee, 0x00, 0x3c, 0x00, 0x06, 0x7a, 0x65,
343 0x70, 0x68, 0x79, 0x72, 0x00, 0x08, 0x71, 0x75,
344 0x69, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x00, 0x03,
345 0x62, 0x79, 0x65, 0x00, 0x07, 0x7a, 0x65, 0x70,
346 0x68, 0x79, 0x72, 0x31, 0x00, 0x08, 0x70, 0x61,
347 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64};
348
349 static ZTEST_DMEM struct mqtt_client client_connect6 = {
350 .clean_session = 1, .client_id = CLIENTID,
351 .will_retain = 1, .will_topic = &will_topic_qos_1,
352 .will_message = &will_msg, .user_name = &username,
353 .password = &password
354 };
355
356 static ZTEST_DMEM
357 uint8_t disconnect1[] = {0xe0, 0x00};
358
359 /*
360 * MQTT PUBLISH msg:
361 * DUP: 0, QoS: 0, Retain: 0, topic: sensors, message: OK
362 *
363 * Message can be generated by the following command:
364 * mosquitto_pub -V mqttv311 -i zephyr -t sensors -q 0 -m "OK"
365 */
366 static ZTEST_DMEM
367 uint8_t publish1[] = {0x30, 0x0b, 0x00, 0x07, 0x73, 0x65, 0x6e, 0x73,
368 0x6f, 0x72, 0x73, 0x4f, 0x4b};
369
370 static ZTEST_DMEM struct mqtt_publish_param msg_publish1 = {
371 .dup_flag = 0, .retain_flag = 0, .message_id = 0,
372 .message.topic.qos = 0,
373 .message.topic.topic = TOPIC,
374 .message.payload.data = (uint8_t *)"OK",
375 .message.payload.len = 2,
376 };
377
378 /*
379 * MQTT PUBLISH msg:
380 * DUP: 0, QoS: 0, Retain: 1, topic: sensors, message: OK
381 *
382 * Message can be generated by the following command:
383 * mosquitto_pub -V mqttv311 -i zephyr -t sensors -q 0 -m "OK" -r
384 */
385 static ZTEST_DMEM
386 uint8_t publish2[] = {0x31, 0x0b, 0x00, 0x07, 0x73, 0x65, 0x6e, 0x73,
387 0x6f, 0x72, 0x73, 0x4f, 0x4b};
388
389 static ZTEST_DMEM struct mqtt_publish_param msg_publish2 = {
390 .dup_flag = 0, .retain_flag = 1, .message_id = 0,
391 .message.topic.qos = 0,
392 .message.topic.topic = TOPIC,
393 .message.payload.data = (uint8_t *)"OK",
394 .message.payload.len = 2,
395 };
396
397 /*
398 * MQTT PUBLISH msg:
399 * DUP: 0, QoS: 1, Retain: 1, topic: sensors, message: OK, pkt_id: 1
400 *
401 * Message can be generated by the following command:
402 * mosquitto_pub -V mqttv311 -i zephyr -t sensors -q 1 -m "OK" -r
403 */
404 static ZTEST_DMEM
405 uint8_t publish3[] = {0x33, 0x0d, 0x00, 0x07, 0x73, 0x65, 0x6e, 0x73,
406 0x6f, 0x72, 0x73, 0x00, 0x01, 0x4f, 0x4b};
407
408 static ZTEST_DMEM struct mqtt_publish_param msg_publish3 = {
409 .dup_flag = 0, .retain_flag = 1, .message_id = 1,
410 .message.topic.qos = 1,
411 .message.topic.topic = TOPIC,
412 .message.payload.data = (uint8_t *)"OK",
413 .message.payload.len = 2,
414 };
415
416 /*
417 * MQTT PUBLISH msg:
418 * DUP: 0, QoS: 2, Retain: 0, topic: sensors, message: OK, pkt_id: 1
419 *
420 * Message can be generated by the following command:
421 * mosquitto_pub -V mqttv311 -i zephyr -t sensors -q 2 -m "OK"
422 */
423 static ZTEST_DMEM
424 uint8_t publish4[] = {0x34, 0x0d, 0x00, 0x07, 0x73, 0x65, 0x6e, 0x73,
425 0x6f, 0x72, 0x73, 0x00, 0x01, 0x4f, 0x4b};
426 static ZTEST_DMEM struct mqtt_publish_param msg_publish4 = {
427 .dup_flag = 0, .retain_flag = 0, .message_id = 1,
428 .message.topic.qos = 2,
429 .message.topic.topic = TOPIC,
430 .message.payload.data = (uint8_t *)"OK",
431 .message.payload.len = 2,
432 };
433
434 static ZTEST_DMEM
435 uint8_t publish_corrupted[] = {0x30, 0x07, 0x00, 0x07, 0x73, 0x65, 0x6e, 0x73,
436 0x6f, 0x72, 0x73, 0x00, 0x01, 0x4f, 0x4b};
437 static ZTEST_DMEM struct buf_ctx publish_corrupted_buf = {
438 .cur = publish_corrupted,
439 .end = publish_corrupted + sizeof(publish_corrupted)
440 };
441
442 /*
443 * MQTT SUBSCRIBE msg:
444 * pkt_id: 1, topic: sensors, qos: 0
445 *
446 * Message can be generated by the following command:
447 * mosquitto_sub -V mqttv311 -i zephyr -t sensors -q 0
448 */
449 static ZTEST_DMEM
450 uint8_t subscribe1[] = {0x82, 0x0c, 0x00, 0x01, 0x00, 0x07, 0x73, 0x65,
451 0x6e, 0x73, 0x6f, 0x72, 0x73, 0x00};
452 static ZTEST_DMEM struct mqtt_subscription_list msg_subscribe1 = {
453 .message_id = 1, .list_count = 1, .list = &topic_qos_0
454 };
455
456 /*
457 * MQTT SUBSCRIBE msg:
458 * pkt_id: 1, topic: sensors, qos: 1
459 *
460 * Message can be generated by the following command:
461 * mosquitto_sub -V mqttv311 -i zephyr -t sensors -q 1
462 */
463 static ZTEST_DMEM
464 uint8_t subscribe2[] = {0x82, 0x0c, 0x00, 0x01, 0x00, 0x07, 0x73, 0x65,
465 0x6e, 0x73, 0x6f, 0x72, 0x73, 0x01};
466 static ZTEST_DMEM struct mqtt_subscription_list msg_subscribe2 = {
467 .message_id = 1, .list_count = 1, .list = &topic_qos_1
468 };
469
470 /*
471 * MQTT SUBSCRIBE msg:
472 * pkt_id: 1, topic: sensors, qos: 2
473 *
474 * Message can be generated by the following command:
475 * mosquitto_sub -V mqttv311 -i zephyr -t sensors -q 2
476 */
477 static ZTEST_DMEM
478 uint8_t subscribe3[] = {0x82, 0x0c, 0x00, 0x01, 0x00, 0x07, 0x73, 0x65,
479 0x6e, 0x73, 0x6f, 0x72, 0x73, 0x02};
480 static ZTEST_DMEM struct mqtt_subscription_list msg_subscribe3 = {
481 .message_id = 1, .list_count = 1, .list = &topic_qos_2
482 };
483
484 /*
485 * MQTT SUBACK msg
486 * pkt_id: 1, qos: 0
487 *
488 * Message can be generated by the following command:
489 * mosquitto_sub -V mqttv311 -i zephyr -t sensors -q 0
490 */
491 static ZTEST_DMEM
492 uint8_t suback1[] = {0x90, 0x03, 0x00, 0x01, 0x00};
493 static ZTEST_DMEM uint8_t data_suback1[] = { MQTT_SUBACK_SUCCESS_QoS_0 };
494 static ZTEST_DMEM struct mqtt_suback_param msg_suback1 = {
495 .message_id = 1, .return_codes.len = 1,
496 .return_codes.data = data_suback1
497 };
498
499 /*
500 * MQTT SUBACK message
501 * pkt_id: 1, qos: 1
502 *
503 * Message can be generated by the following command:
504 * mosquitto_sub -V mqttv311 -i zephyr -t sensors -q 1
505 */
506 static ZTEST_DMEM
507 uint8_t suback2[] = {0x90, 0x03, 0x00, 0x01, 0x01};
508 static ZTEST_DMEM uint8_t data_suback2[] = { MQTT_SUBACK_SUCCESS_QoS_1 };
509 static ZTEST_DMEM struct mqtt_suback_param msg_suback2 = {
510 .message_id = 1, .return_codes.len = 1,
511 .return_codes.data = data_suback2
512 };
513
514 /*
515 * MQTT SUBACK message
516 * pkt_id: 1, qos: 2
517 *
518 * Message can be generated by the following command:
519 * mosquitto_sub -V mqttv311 -i zephyr -t sensors -q 2
520 */
521 static ZTEST_DMEM
522 uint8_t suback3[] = {0x90, 0x03, 0x00, 0x01, 0x02};
523 static ZTEST_DMEM uint8_t data_suback3[] = { MQTT_SUBACK_SUCCESS_QoS_2 };
524 static ZTEST_DMEM struct mqtt_suback_param msg_suback3 = {
525 .message_id = 1, .return_codes.len = 1,
526 .return_codes.data = data_suback3
527 };
528
529 static ZTEST_DMEM
530 uint8_t pingreq1[] = {0xc0, 0x00};
531
532 static ZTEST_DMEM
533 uint8_t puback1[] = {0x40, 0x02, 0x00, 0x01};
534 static ZTEST_DMEM struct mqtt_puback_param msg_puback1 = {.message_id = 1};
535
536 static ZTEST_DMEM
537 uint8_t pubrec1[] = {0x50, 0x02, 0x00, 0x01};
538 static ZTEST_DMEM struct mqtt_pubrec_param msg_pubrec1 = {.message_id = 1};
539
540 static ZTEST_DMEM
541 uint8_t pubrel1[] = {0x62, 0x02, 0x00, 0x01};
542 static ZTEST_DMEM struct mqtt_pubrel_param msg_pubrel1 = {.message_id = 1};
543
544 static ZTEST_DMEM
545 uint8_t pubcomp1[] = {0x70, 0x02, 0x00, 0x01};
546 static ZTEST_DMEM struct mqtt_pubcomp_param msg_pubcomp1 = {.message_id = 1};
547
548 static ZTEST_DMEM
549 uint8_t unsuback1[] = {0xb0, 0x02, 0x00, 0x01};
550 static ZTEST_DMEM struct mqtt_unsuback_param msg_unsuback1 = {.message_id = 1};
551
552 static ZTEST_DMEM
553 uint8_t max_pkt_len[] = {0x30, 0xff, 0xff, 0xff, 0x7f};
554 static ZTEST_DMEM struct buf_ctx max_pkt_len_buf = {
555 .cur = max_pkt_len, .end = max_pkt_len + sizeof(max_pkt_len)
556 };
557
558 static ZTEST_DMEM
559 uint8_t corrupted_pkt_len[] = {0x30, 0xff, 0xff, 0xff, 0xff, 0x01};
560 static ZTEST_DMEM struct buf_ctx corrupted_pkt_len_buf = {
561 .cur = corrupted_pkt_len,
562 .end = corrupted_pkt_len + sizeof(corrupted_pkt_len)
563 };
564
565 static ZTEST_DMEM
566 struct mqtt_test mqtt_tests[] = {
567
568 {.test_name = "CONNECT, new session, zeros",
569 .ctx = &client_connect1, .eval_fcn = eval_msg_connect,
570 .expected = connect1, .expected_len = sizeof(connect1)},
571
572 {.test_name = "CONNECT, new session, will",
573 .ctx = &client_connect2, .eval_fcn = eval_msg_connect,
574 .expected = connect2, .expected_len = sizeof(connect2)},
575
576 {.test_name = "CONNECT, new session, will retain",
577 .ctx = &client_connect3, .eval_fcn = eval_msg_connect,
578 .expected = connect3, .expected_len = sizeof(connect3)},
579
580 {.test_name = "CONNECT, new session, will qos = 1",
581 .ctx = &client_connect4, .eval_fcn = eval_msg_connect,
582 .expected = connect4, .expected_len = sizeof(connect4)},
583
584 {.test_name = "CONNECT, new session, will qos = 1, will retain",
585 .ctx = &client_connect5, .eval_fcn = eval_msg_connect,
586 .expected = connect5, .expected_len = sizeof(connect5)},
587
588 {.test_name = "CONNECT, new session, username and password",
589 .ctx = &client_connect6, .eval_fcn = eval_msg_connect,
590 .expected = connect6, .expected_len = sizeof(connect6)},
591
592 {.test_name = "DISCONNECT",
593 .ctx = NULL, .eval_fcn = eval_msg_disconnect,
594 .expected = disconnect1, .expected_len = sizeof(disconnect1)},
595
596 {.test_name = "PUBLISH, qos = 0",
597 .ctx = &msg_publish1, .eval_fcn = eval_msg_publish,
598 .expected = publish1, .expected_len = sizeof(publish1)},
599
600 {.test_name = "PUBLISH, retain = 1",
601 .ctx = &msg_publish2, .eval_fcn = eval_msg_publish,
602 .expected = publish2, .expected_len = sizeof(publish2)},
603
604 {.test_name = "PUBLISH, retain = 1, qos = 1",
605 .ctx = &msg_publish3, .eval_fcn = eval_msg_publish,
606 .expected = publish3, .expected_len = sizeof(publish3)},
607
608 {.test_name = "PUBLISH, qos = 2",
609 .ctx = &msg_publish4, .eval_fcn = eval_msg_publish,
610 .expected = publish4, .expected_len = sizeof(publish4)},
611
612 {.test_name = "PUBLISH, corrupted message length (smaller than topic)",
613 .ctx = &publish_corrupted_buf, .eval_fcn = eval_msg_corrupted_publish},
614
615 {.test_name = "SUBSCRIBE, one topic, qos = 0",
616 .ctx = &msg_subscribe1, .eval_fcn = eval_msg_subscribe,
617 .expected = subscribe1, .expected_len = sizeof(subscribe1)},
618
619 {.test_name = "SUBSCRIBE, one topic, qos = 1",
620 .ctx = &msg_subscribe2, .eval_fcn = eval_msg_subscribe,
621 .expected = subscribe2, .expected_len = sizeof(subscribe2)},
622
623 {.test_name = "SUBSCRIBE, one topic, qos = 2",
624 .ctx = &msg_subscribe3, .eval_fcn = eval_msg_subscribe,
625 .expected = subscribe3, .expected_len = sizeof(subscribe3)},
626
627 {.test_name = "SUBACK, one topic, qos = 0",
628 .ctx = &msg_suback1, .eval_fcn = eval_msg_suback,
629 .expected = suback1, .expected_len = sizeof(suback1)},
630
631 {.test_name = "SUBACK, one topic, qos = 1",
632 .ctx = &msg_suback2, .eval_fcn = eval_msg_suback,
633 .expected = suback2, .expected_len = sizeof(suback2)},
634
635 {.test_name = "SUBACK, one topic, qos = 2",
636 .ctx = &msg_suback3, .eval_fcn = eval_msg_suback,
637 .expected = suback3, .expected_len = sizeof(suback3)},
638
639 {.test_name = "PINGREQ",
640 .ctx = NULL, .eval_fcn = eval_msg_pingreq,
641 .expected = pingreq1, .expected_len = sizeof(pingreq1)},
642
643 {.test_name = "PUBACK",
644 .ctx = &msg_puback1, .eval_fcn = eval_msg_puback,
645 .expected = puback1, .expected_len = sizeof(puback1)},
646
647 {.test_name = "PUBREC",
648 .ctx = &msg_pubrec1, .eval_fcn = eval_msg_pubrec,
649 .expected = pubrec1, .expected_len = sizeof(pubrec1)},
650
651 {.test_name = "PUBREL",
652 .ctx = &msg_pubrel1, .eval_fcn = eval_msg_pubrel,
653 .expected = pubrel1, .expected_len = sizeof(pubrel1)},
654
655 {.test_name = "PUBCOMP",
656 .ctx = &msg_pubcomp1, .eval_fcn = eval_msg_pubcomp,
657 .expected = pubcomp1, .expected_len = sizeof(pubcomp1)},
658
659 {.test_name = "UNSUBACK",
660 .ctx = &msg_unsuback1, .eval_fcn = eval_msg_unsuback,
661 .expected = unsuback1, .expected_len = sizeof(unsuback1)},
662
663 {.test_name = "Maximum packet length",
664 .ctx = &max_pkt_len_buf, .eval_fcn = eval_max_pkt_len},
665
666 {.test_name = "Corrupted packet length",
667 .ctx = &corrupted_pkt_len_buf, .eval_fcn = eval_corrupted_pkt_len},
668
669 /* last test case, do not remove it */
670 {.test_name = NULL}
671 };
672
print_array(const uint8_t * a,uint16_t size)673 static void print_array(const uint8_t *a, uint16_t size)
674 {
675 uint16_t i;
676
677 TC_PRINT("\n");
678 for (i = 0U; i < size; i++) {
679 TC_PRINT("%x ", a[i]);
680 if ((i+1) % 8 == 0U) {
681 TC_PRINT("\n");
682 }
683 }
684 TC_PRINT("\n");
685 }
686
687 static
eval_buffers(const struct buf_ctx * buf,const uint8_t * expected,uint16_t len)688 int eval_buffers(const struct buf_ctx *buf, const uint8_t *expected, uint16_t len)
689 {
690 if (buf->end - buf->cur != len) {
691 goto exit_eval;
692 }
693
694 if (memcmp(expected, buf->cur, buf->end - buf->cur) != 0) {
695 goto exit_eval;
696 }
697
698 return TC_PASS;
699
700 exit_eval:
701 TC_PRINT("FAIL\n");
702 TC_PRINT("Computed:");
703 print_array(buf->cur, buf->end - buf->cur);
704 TC_PRINT("Expected:");
705 print_array(expected, len);
706
707 return TC_FAIL;
708 }
709
eval_msg_connect(struct mqtt_test * mqtt_test)710 static int eval_msg_connect(struct mqtt_test *mqtt_test)
711 {
712 struct mqtt_client *test_client;
713 int rc;
714 struct buf_ctx buf;
715
716 test_client = (struct mqtt_client *)mqtt_test->ctx;
717
718 client.clean_session = test_client->clean_session;
719 client.client_id = test_client->client_id;
720 client.will_topic = test_client->will_topic;
721 client.will_retain = test_client->will_retain;
722 client.will_message = test_client->will_message;
723 client.user_name = test_client->user_name;
724 client.password = test_client->password;
725
726 buf.cur = client.tx_buf;
727 buf.end = client.tx_buf + client.tx_buf_size;
728
729 rc = connect_request_encode(&client, &buf);
730
731 /**TESTPOINTS: Check connect_request_encode functions*/
732 zassert_false(rc, "connect_request_encode failed");
733
734 rc = eval_buffers(&buf, mqtt_test->expected, mqtt_test->expected_len);
735
736 zassert_false(rc, "eval_buffers failed");
737
738 return TC_PASS;
739 }
740
eval_msg_disconnect(struct mqtt_test * mqtt_test)741 static int eval_msg_disconnect(struct mqtt_test *mqtt_test)
742 {
743 int rc;
744 struct buf_ctx buf;
745
746 buf.cur = client.tx_buf;
747 buf.end = client.tx_buf + client.tx_buf_size;
748
749 rc = disconnect_encode(&buf);
750
751 /**TESTPOINTS: Check disconnect_encode functions*/
752 zassert_false(rc, "disconnect_encode failed");
753
754 rc = eval_buffers(&buf, mqtt_test->expected, mqtt_test->expected_len);
755
756 zassert_false(rc, "eval_buffers failed");
757
758 return TC_PASS;
759 }
760
eval_msg_publish(struct mqtt_test * mqtt_test)761 static int eval_msg_publish(struct mqtt_test *mqtt_test)
762 {
763 struct mqtt_publish_param *param =
764 (struct mqtt_publish_param *)mqtt_test->ctx;
765 struct mqtt_publish_param dec_param;
766 int rc;
767 uint8_t type_and_flags;
768 uint32_t length;
769 struct buf_ctx buf;
770
771 memset(&dec_param, 0, sizeof(dec_param));
772
773 buf.cur = client.tx_buf;
774 buf.end = client.tx_buf + client.tx_buf_size;
775
776 rc = publish_encode(param, &buf);
777
778 /* Payload is not copied, copy it manually just after the header.*/
779 memcpy(buf.end, param->message.payload.data,
780 param->message.payload.len);
781 buf.end += param->message.payload.len;
782
783 /**TESTPOINT: Check publish_encode function*/
784 zassert_false(rc, "publish_encode failed");
785
786 rc = eval_buffers(&buf, mqtt_test->expected, mqtt_test->expected_len);
787
788 zassert_false(rc, "eval_buffers failed");
789
790 rc = fixed_header_decode(&buf, &type_and_flags, &length);
791
792 zassert_false(rc, "fixed_header_decode failed");
793
794 rc = publish_decode(type_and_flags, length, &buf, &dec_param);
795
796 /**TESTPOINT: Check publish_decode function*/
797 zassert_false(rc, "publish_decode failed");
798
799 zassert_equal(dec_param.message_id, param->message_id,
800 "message_id error");
801 zassert_equal(dec_param.dup_flag, param->dup_flag,
802 "dup flag error");
803 zassert_equal(dec_param.retain_flag, param->retain_flag,
804 "retain flag error");
805 zassert_equal(dec_param.message.topic.qos, param->message.topic.qos,
806 "topic qos error");
807 zassert_equal(dec_param.message.topic.topic.size,
808 param->message.topic.topic.size,
809 "topic len error");
810 if (memcmp(dec_param.message.topic.topic.utf8,
811 param->message.topic.topic.utf8,
812 dec_param.message.topic.topic.size) != 0) {
813 zassert_unreachable("topic content error");
814 }
815 zassert_equal(dec_param.message.payload.len,
816 param->message.payload.len,
817 "payload len error");
818
819 return TC_PASS;
820 }
821
eval_msg_corrupted_publish(struct mqtt_test * mqtt_test)822 static int eval_msg_corrupted_publish(struct mqtt_test *mqtt_test)
823 {
824 struct buf_ctx *buf = (struct buf_ctx *)mqtt_test->ctx;
825 int rc;
826 uint8_t type_and_flags;
827 uint32_t length;
828 struct mqtt_publish_param dec_param;
829
830 rc = fixed_header_decode(buf, &type_and_flags, &length);
831 zassert_equal(rc, 0, "fixed_header_decode failed");
832
833 rc = publish_decode(type_and_flags, length, buf, &dec_param);
834 zassert_equal(rc, -EINVAL, "publish_decode should fail");
835
836 return TC_PASS;
837 }
838
eval_msg_subscribe(struct mqtt_test * mqtt_test)839 static int eval_msg_subscribe(struct mqtt_test *mqtt_test)
840 {
841 struct mqtt_subscription_list *param =
842 (struct mqtt_subscription_list *)mqtt_test->ctx;
843 int rc;
844 struct buf_ctx buf;
845
846 buf.cur = client.tx_buf;
847 buf.end = client.tx_buf + client.tx_buf_size;
848
849 rc = subscribe_encode(param, &buf);
850
851 /**TESTPOINT: Check subscribe_encode function*/
852 zassert_false(rc, "subscribe_encode failed");
853
854 return eval_buffers(&buf, mqtt_test->expected, mqtt_test->expected_len);
855 }
856
eval_msg_suback(struct mqtt_test * mqtt_test)857 static int eval_msg_suback(struct mqtt_test *mqtt_test)
858 {
859 struct mqtt_suback_param *param =
860 (struct mqtt_suback_param *)mqtt_test->ctx;
861 struct mqtt_suback_param dec_param;
862
863 int rc;
864 uint8_t type_and_flags;
865 uint32_t length;
866 struct buf_ctx buf;
867
868 buf.cur = mqtt_test->expected;
869 buf.end = mqtt_test->expected + mqtt_test->expected_len;
870
871 memset(&dec_param, 0, sizeof(dec_param));
872
873 rc = fixed_header_decode(&buf, &type_and_flags, &length);
874
875 zassert_false(rc, "fixed_header_decode failed");
876
877 rc = subscribe_ack_decode(&buf, &dec_param);
878
879 /**TESTPOINT: Check subscribe_ack_decode function*/
880 zassert_false(rc, "subscribe_ack_decode failed");
881
882 zassert_equal(dec_param.message_id, param->message_id,
883 "packet identifier error");
884 zassert_equal(dec_param.return_codes.len,
885 param->return_codes.len,
886 "topic count error");
887 if (memcmp(dec_param.return_codes.data, param->return_codes.data,
888 dec_param.return_codes.len) != 0) {
889 zassert_unreachable("subscribe result error");
890 }
891
892 return TC_PASS;
893 }
894
eval_msg_pingreq(struct mqtt_test * mqtt_test)895 static int eval_msg_pingreq(struct mqtt_test *mqtt_test)
896 {
897 int rc;
898 struct buf_ctx buf;
899
900 buf.cur = client.tx_buf;
901 buf.end = client.tx_buf + client.tx_buf_size;
902
903 rc = ping_request_encode(&buf);
904
905 /**TESTPOINTS: Check eval_msg_pingreq functions*/
906 zassert_false(rc, "ping_request_encode failed");
907
908 rc = eval_buffers(&buf, mqtt_test->expected, mqtt_test->expected_len);
909
910 zassert_false(rc, "eval_buffers failed");
911
912 return TC_PASS;
913 }
914
eval_msg_puback(struct mqtt_test * mqtt_test)915 static int eval_msg_puback(struct mqtt_test *mqtt_test)
916 {
917 struct mqtt_puback_param *param =
918 (struct mqtt_puback_param *)mqtt_test->ctx;
919 struct mqtt_puback_param dec_param;
920 int rc;
921 uint8_t type_and_flags;
922 uint32_t length;
923 struct buf_ctx buf;
924
925 memset(&dec_param, 0, sizeof(dec_param));
926
927 buf.cur = client.tx_buf;
928 buf.end = client.tx_buf + client.tx_buf_size;
929
930 rc = publish_ack_encode(param, &buf);
931
932 /**TESTPOINTS: Check publish_ack_encode functions*/
933 zassert_false(rc, "publish_ack_encode failed");
934
935 rc = eval_buffers(&buf, mqtt_test->expected, mqtt_test->expected_len);
936
937 zassert_false(rc, "eval_buffers failed");
938
939 rc = fixed_header_decode(&buf, &type_and_flags, &length);
940
941 zassert_false(rc, "fixed_header_decode failed");
942
943 rc = publish_ack_decode(&buf, &dec_param);
944
945 zassert_false(rc, "publish_ack_decode failed");
946
947 zassert_equal(dec_param.message_id, param->message_id,
948 "packet identifier error");
949
950 return TC_PASS;
951 }
952
eval_msg_pubcomp(struct mqtt_test * mqtt_test)953 static int eval_msg_pubcomp(struct mqtt_test *mqtt_test)
954 {
955 struct mqtt_pubcomp_param *param =
956 (struct mqtt_pubcomp_param *)mqtt_test->ctx;
957 struct mqtt_pubcomp_param dec_param;
958 int rc;
959 uint32_t length;
960 uint8_t type_and_flags;
961 struct buf_ctx buf;
962
963 memset(&dec_param, 0, sizeof(dec_param));
964
965 buf.cur = client.tx_buf;
966 buf.end = client.tx_buf + client.tx_buf_size;
967
968 rc = publish_complete_encode(param, &buf);
969
970 /**TESTPOINTS: Check publish_complete_encode functions*/
971 zassert_false(rc, "publish_complete_encode failed");
972
973 rc = eval_buffers(&buf, mqtt_test->expected, mqtt_test->expected_len);
974
975 zassert_false(rc, "eval_buffers failed");
976
977 rc = fixed_header_decode(&buf, &type_and_flags, &length);
978
979 zassert_false(rc, "fixed_header_decode failed");
980
981 rc = publish_complete_decode(&buf, &dec_param);
982
983 zassert_false(rc, "publish_complete_decode failed");
984
985 zassert_equal(dec_param.message_id, param->message_id,
986 "packet identifier error");
987
988 return TC_PASS;
989 }
990
eval_msg_pubrec(struct mqtt_test * mqtt_test)991 static int eval_msg_pubrec(struct mqtt_test *mqtt_test)
992 {
993 struct mqtt_pubrec_param *param =
994 (struct mqtt_pubrec_param *)mqtt_test->ctx;
995 struct mqtt_pubrec_param dec_param;
996 int rc;
997 uint32_t length;
998 uint8_t type_and_flags;
999 struct buf_ctx buf;
1000
1001 memset(&dec_param, 0, sizeof(dec_param));
1002
1003 buf.cur = client.tx_buf;
1004 buf.end = client.tx_buf + client.tx_buf_size;
1005
1006 rc = publish_receive_encode(param, &buf);
1007
1008 /**TESTPOINTS: Check publish_receive_encode functions*/
1009 zassert_false(rc, "publish_receive_encode failed");
1010
1011 rc = eval_buffers(&buf, mqtt_test->expected, mqtt_test->expected_len);
1012
1013 zassert_false(rc, "eval_buffers failed");
1014
1015 rc = fixed_header_decode(&buf, &type_and_flags, &length);
1016
1017 zassert_false(rc, "fixed_header_decode failed");
1018
1019 rc = publish_receive_decode(&buf, &dec_param);
1020
1021 zassert_false(rc, "publish_receive_decode failed");
1022
1023 zassert_equal(dec_param.message_id, param->message_id,
1024 "packet identifier error");
1025
1026 return TC_PASS;
1027 }
1028
eval_msg_pubrel(struct mqtt_test * mqtt_test)1029 static int eval_msg_pubrel(struct mqtt_test *mqtt_test)
1030 {
1031 struct mqtt_pubrel_param *param =
1032 (struct mqtt_pubrel_param *)mqtt_test->ctx;
1033 struct mqtt_pubrel_param dec_param;
1034 int rc;
1035 uint32_t length;
1036 uint8_t type_and_flags;
1037 struct buf_ctx buf;
1038
1039 memset(&dec_param, 0, sizeof(dec_param));
1040
1041 buf.cur = client.tx_buf;
1042 buf.end = client.tx_buf + client.tx_buf_size;
1043
1044 rc = publish_release_encode(param, &buf);
1045
1046 /**TESTPOINTS: Check publish_release_encode functions*/
1047 zassert_false(rc, "publish_release_encode failed");
1048
1049 rc = eval_buffers(&buf, mqtt_test->expected, mqtt_test->expected_len);
1050
1051 zassert_false(rc, "eval_buffers failed");
1052
1053 rc = fixed_header_decode(&buf, &type_and_flags, &length);
1054
1055 zassert_false(rc, "fixed_header_decode failed");
1056
1057 rc = publish_release_decode(&buf, &dec_param);
1058
1059 zassert_false(rc, "publish_release_decode failed");
1060
1061 zassert_equal(dec_param.message_id, param->message_id,
1062 "packet identifier error");
1063
1064 return TC_PASS;
1065 }
1066
eval_msg_unsuback(struct mqtt_test * mqtt_test)1067 static int eval_msg_unsuback(struct mqtt_test *mqtt_test)
1068 {
1069 struct mqtt_unsuback_param *param =
1070 (struct mqtt_unsuback_param *)mqtt_test->ctx;
1071 struct mqtt_unsuback_param dec_param;
1072 int rc;
1073 uint32_t length;
1074 uint8_t type_and_flags;
1075 struct buf_ctx buf;
1076
1077 memset(&dec_param, 0, sizeof(dec_param));
1078
1079 buf.cur = mqtt_test->expected;
1080 buf.end = mqtt_test->expected + mqtt_test->expected_len;
1081
1082 rc = fixed_header_decode(&buf, &type_and_flags, &length);
1083
1084 zassert_false(rc, "fixed_header_decode failed");
1085
1086 rc = unsubscribe_ack_decode(&buf, &dec_param);
1087
1088 zassert_false(rc, "unsubscribe_ack_decode failed");
1089
1090 zassert_equal(dec_param.message_id, param->message_id,
1091 "packet identifier error");
1092
1093 return TC_PASS;
1094 }
1095
eval_max_pkt_len(struct mqtt_test * mqtt_test)1096 static int eval_max_pkt_len(struct mqtt_test *mqtt_test)
1097 {
1098 struct buf_ctx *buf = (struct buf_ctx *)mqtt_test->ctx;
1099 int rc;
1100 uint8_t flags;
1101 uint32_t length;
1102
1103 rc = fixed_header_decode(buf, &flags, &length);
1104
1105 zassert_equal(rc, 0, "fixed_header_decode failed");
1106 zassert_equal(length, MQTT_MAX_PAYLOAD_SIZE,
1107 "Invalid packet length decoded");
1108
1109 return TC_PASS;
1110 }
1111
eval_corrupted_pkt_len(struct mqtt_test * mqtt_test)1112 static int eval_corrupted_pkt_len(struct mqtt_test *mqtt_test)
1113 {
1114 struct buf_ctx *buf = (struct buf_ctx *)mqtt_test->ctx;
1115 int rc;
1116 uint8_t flags;
1117 uint32_t length;
1118
1119 rc = fixed_header_decode(buf, &flags, &length);
1120
1121 zassert_equal(rc, -EINVAL, "fixed_header_decode should fail");
1122
1123 return TC_PASS;
1124 }
1125
ZTEST(mqtt_packet_fn,test_mqtt_packet)1126 ZTEST(mqtt_packet_fn, test_mqtt_packet)
1127 {
1128 int rc;
1129 int i;
1130
1131 mqtt_client_init(&client);
1132 client.protocol_version = MQTT_VERSION_3_1_1;
1133 client.rx_buf = rx_buffer;
1134 client.rx_buf_size = sizeof(rx_buffer);
1135 client.tx_buf = tx_buffer;
1136 client.tx_buf_size = sizeof(tx_buffer);
1137
1138 i = 0;
1139 do {
1140 struct mqtt_test *test = &mqtt_tests[i];
1141
1142 if (test->test_name == NULL) {
1143 break;
1144 }
1145
1146 rc = test->eval_fcn(test);
1147 TC_PRINT("[%s] %d - %s\n", TC_RESULT_TO_STR(rc), i + 1,
1148 test->test_name);
1149
1150 /**TESTPOINT: Check eval_fcn*/
1151 zassert_false(rc, "mqtt_packet test error");
1152
1153 i++;
1154 } while (1);
1155
1156 mqtt_abort(&client);
1157 }
1158
1159 ZTEST_SUITE(mqtt_packet_fn, NULL, NULL, NULL, NULL, NULL);
1160