1 /* libcoap unit tests
2  *
3  * Copyright (C) 2013,2015 Olaf Bergmann <bergmann@tzi.org>
4  *
5  * SPDX-License-Identifier: BSD-2-Clause
6  *
7  * This file is part of the CoAP library libcoap. Please see
8  * README for terms of use.
9  */
10 
11 #include "test_common.h"
12 #include "test_error_response.h"
13 
14 #include <assert.h>
15 #include <stdio.h>
16 #include <stdlib.h>
17 #include <string.h>
18 
19 static coap_pdu_t *pdu;          /* Holds the request PDU for most tests */
20 static coap_opt_filter_t opts;   /* option filter used for generating responses */
21 
22 /************************************************************************
23  ** PDU decoder
24  ************************************************************************/
25 
26 /* FIXME: handle COAP_ERROR_PHRASE_LENGTH == 0 */
27 
28 static void
t_error_response1(void)29 t_error_response1(void) {
30   uint8_t teststr[] = {
31     0x60, 0x80, 0x12, 0x34, 0xff, 'B', 'a', 'd',
32     ' ', 'R', 'e', 'q', 'u', 'e', 's', 't'
33   };
34   coap_pdu_t *response;
35 
36   coap_pdu_clear(pdu, pdu->max_size);
37   pdu->type = COAP_MESSAGE_CON;
38   pdu->mid = 0x1234;
39 
40   /* result = coap_add_token(pdu, 5, (unsigned char *)"token"); */
41   coap_option_filter_clear(&opts);
42   response = coap_new_error_response(pdu, COAP_RESPONSE_CODE(400), &opts);
43 
44   CU_ASSERT_PTR_NOT_NULL(response);
45 
46   CU_ASSERT(response->used_size == sizeof(teststr) - 4);
47   CU_ASSERT(response->type == COAP_MESSAGE_ACK);
48   CU_ASSERT(response->token_length == 0);
49   CU_ASSERT(response->code == 0x80);
50   CU_ASSERT(response->mid == 0x1234);
51   CU_ASSERT(coap_pdu_encode_header(response, COAP_PROTO_UDP) == 4);
52   CU_ASSERT(memcmp(response->token - 4, teststr, sizeof(teststr)) == 0);
53   coap_delete_pdu(response);
54 }
55 
56 static void
t_error_response2(void)57 t_error_response2(void) {
58   uint8_t teststr[] = {
59     0x55, 0x84, 0x12, 0x34, 't', 'o', 'k', 'e',
60     'n', 0xff, 'N', 'o', 't', ' ', 'F', 'o',
61     'u', 'n', 'd'
62   };
63   coap_pdu_t *response;
64 
65   coap_pdu_clear(pdu, pdu->max_size);
66   pdu->type = COAP_MESSAGE_NON;
67   pdu->mid = 0x1234;
68   coap_add_token(pdu, 5, (const uint8_t *)"token");
69   coap_add_option(pdu, COAP_OPTION_URI_HOST, 4, (const uint8_t *)"time");
70 
71   coap_option_filter_clear(&opts);
72   response = coap_new_error_response(pdu, COAP_RESPONSE_CODE(404), &opts);
73 
74   CU_ASSERT_PTR_NOT_NULL(response);
75 
76   CU_ASSERT(response->used_size == sizeof(teststr) - 4);
77   CU_ASSERT(response->type == COAP_MESSAGE_NON);
78   CU_ASSERT(response->token_length == 5);
79   CU_ASSERT(response->code == 0x84);
80   CU_ASSERT(coap_pdu_encode_header(response, COAP_PROTO_UDP) == 4);
81   CU_ASSERT(memcmp(response->token - 4, teststr, sizeof(teststr)) == 0);
82   coap_delete_pdu(response);
83 }
84 
85 static void
t_error_response3(void)86 t_error_response3(void) {
87   const uint8_t code = COAP_RESPONSE_CODE(402);
88   uint8_t teststr[] = {
89     0x65, code, 0x00, 0x00, 't', 'o', 'k', 'e',
90     'n', 0x90, 0xff, 'B', 'a', 'd', ' ', 'O',
91     'p', 't', 'i', 'o', 'n'
92   };
93   coap_pdu_t *response;
94 
95   coap_pdu_clear(pdu, pdu->max_size);
96   pdu->type = COAP_MESSAGE_CON;
97   coap_add_token(pdu, 5, (const uint8_t *)"token");
98   /* coap_add_option(pdu, COAP_OPTION_URI_HOST, 4, (const uint8_t *)"time"); */
99 
100   /* unknown critical option 9 */
101   coap_add_option(pdu, 9, 0, NULL);
102 
103   coap_option_filter_clear(&opts);
104   coap_option_filter_set(&opts, 9);
105   response = coap_new_error_response(pdu, code, &opts);
106 
107   CU_ASSERT_PTR_NOT_NULL(response);
108 
109   CU_ASSERT(response->used_size == sizeof(teststr) - 4);
110   CU_ASSERT(response->type == COAP_MESSAGE_ACK);
111   CU_ASSERT(response->token_length == 5);
112   CU_ASSERT(response->code == code);
113   CU_ASSERT(coap_pdu_encode_header(response, COAP_PROTO_UDP) == 4);
114   CU_ASSERT(memcmp(response->token - 4, teststr, sizeof(teststr)) == 0);
115   coap_delete_pdu(response);
116 }
117 
118 static void
t_error_response4(void)119 t_error_response4(void) {
120   const uint8_t code = COAP_RESPONSE_CODE(402);
121   unsigned char optval[] = {
122     0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
123     0x08, 0x09, 0x0a, 0x0b
124   };
125   uint8_t teststr[] = {
126     0x65, code, 0x00, 0x00,  't',  'o',  'k',  'e',
127      'n', 0x9c, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05,
128     0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0xff,  'B',
129      'a',  'd',  ' ',  'O',  'p',  't',  'i',  'o',
130      'n'
131   };
132   coap_pdu_t *response;
133 
134   coap_pdu_clear(pdu, pdu->max_size);
135   pdu->type = COAP_MESSAGE_CON;
136   coap_add_token(pdu, 5, (const uint8_t *)"token");
137   /* coap_add_option(pdu, COAP_OPTION_URI_HOST, 4, (const uint8_t *)"time"); */
138 
139   /* unknown critical option 9 */
140   coap_add_option(pdu, 9, sizeof(optval), optval);
141 
142   coap_option_filter_clear(&opts);
143   coap_option_filter_set(&opts, 9);
144   response = coap_new_error_response(pdu, code, &opts);
145 
146   CU_ASSERT_PTR_NOT_NULL(response);
147 
148   CU_ASSERT(response->used_size == sizeof(teststr) - 4);
149   CU_ASSERT(response->type == COAP_MESSAGE_ACK);
150   CU_ASSERT(response->token_length == 5);
151   CU_ASSERT(response->code == code);
152   CU_ASSERT(coap_pdu_encode_header(response, COAP_PROTO_UDP) == 4);
153   CU_ASSERT(memcmp(response->token - 4, teststr, sizeof(teststr)) == 0);
154   coap_delete_pdu(response);
155 }
156 
157 static void
t_error_response5(void)158 t_error_response5(void) {
159   const uint8_t code = COAP_RESPONSE_CODE(402);
160   unsigned char optval[] = {
161     0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
162     0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
163     0x10, 0x11, 0x12
164   };
165   uint8_t teststr[] = {
166     0x65, code, 0x00, 0x00,  't',  'o',  'k',  'e',
167      'n', 0x9d, 0x06, 0x00, 0x01, 0x02, 0x03, 0x04,
168     0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c,
169     0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0xff,  'B',
170      'a',  'd',  ' ',  'O',  'p',  't',  'i',  'o',
171      'n'
172   };
173   coap_pdu_t *response;
174 
175   coap_pdu_clear(pdu, pdu->max_size);
176   pdu->type = COAP_MESSAGE_CON;
177   coap_add_token(pdu, 5, (const uint8_t *)"token");
178   /* coap_add_option(pdu, COAP_OPTION_URI_HOST, 4, (const uint8_t *)"time"); */
179 
180   /* unknown critical option 9 */
181   coap_add_option(pdu, 9, sizeof(optval), optval);
182 
183   coap_option_filter_clear(&opts);
184   coap_option_filter_set(&opts, 9);
185   response = coap_new_error_response(pdu, code, &opts);
186 
187   CU_ASSERT_PTR_NOT_NULL(response);
188 
189   CU_ASSERT(response->used_size == sizeof(teststr) - 4);
190   CU_ASSERT(response->type == COAP_MESSAGE_ACK);
191   CU_ASSERT(response->token_length == 5);
192   CU_ASSERT(response->code == code);
193   CU_ASSERT(coap_pdu_encode_header(response, COAP_PROTO_UDP) == 4);
194   CU_ASSERT(memcmp(response->token - 4, teststr, sizeof(teststr)) == 0);
195   coap_delete_pdu(response);
196 }
197 
198 static void
t_error_response6(void)199 t_error_response6(void) {
200   const uint8_t code = COAP_RESPONSE_CODE(402);
201   unsigned char optval[] = {
202     0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
203     0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
204     0x10, 0x11, 0x12
205   };
206   uint8_t teststr[] = {
207     0x65, code, 0x00, 0x00,  't',  'o',  'k',  'e',
208      'n', 0xdd, 0x0a, 0x06, 0x00, 0x01, 0x02, 0x03,
209     0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b,
210     0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0xff,
211      'B',  'a',  'd',  ' ',  'O',  'p',  't',  'i',
212      'o',  'n'
213   };
214   coap_pdu_t *response;
215 
216   coap_pdu_clear(pdu, pdu->max_size);
217   pdu->type = COAP_MESSAGE_CON;
218   coap_add_token(pdu, 5, (const uint8_t *)"token");
219   /* coap_add_option(pdu, COAP_OPTION_URI_HOST, 4, (const uint8_t *)"time"); */
220 
221   /* unknown critical option 23 */
222   coap_add_option(pdu, 23, sizeof(optval), optval);
223 
224   coap_option_filter_clear(&opts);
225   coap_option_filter_set(&opts, 23);
226   response = coap_new_error_response(pdu, code, &opts);
227 
228   CU_ASSERT_PTR_NOT_NULL(response);
229 
230   CU_ASSERT(response->used_size == sizeof(teststr) - 4);
231   CU_ASSERT(response->type == COAP_MESSAGE_ACK);
232   CU_ASSERT(response->token_length == 5);
233   CU_ASSERT(response->code == code);
234   CU_ASSERT(coap_pdu_encode_header(response, COAP_PROTO_UDP) == 4);
235   CU_ASSERT(memcmp(response->token - 4, teststr, sizeof(teststr)) == 0);
236   coap_delete_pdu(response);
237 }
238 
239 static void
t_error_response7(void)240 t_error_response7(void) {
241   const uint8_t code = COAP_RESPONSE_CODE(402);
242   unsigned char optval[] = {
243     0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
244     0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
245     0x10, 0x11, 0x12
246   };
247   uint8_t teststr[] = {
248     0x65, code, 0x00, 0x00,  't',  'o',  'k',  'e',
249      'n', 0xdd, 0x0a, 0x06, 0x00, 0x01, 0x02, 0x03,
250     0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b,
251     0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0xff,
252      'B',  'a',  'd',  ' ',  'O',  'p',  't',  'i',
253      'o',  'n'
254   };
255   coap_pdu_t *response;
256 
257   coap_pdu_clear(pdu, pdu->max_size);
258   pdu->type = COAP_MESSAGE_CON;
259   coap_add_token(pdu, 5, (const uint8_t *)"token");
260   /* known option 11 */
261   coap_add_option(pdu, 11, 4, (const uint8_t *)"time");
262 
263   /* unknown critical option 23 */
264   coap_add_option(pdu, 23, sizeof(optval), optval);
265 
266   coap_option_filter_clear(&opts);
267   coap_option_filter_set(&opts, 23);
268   response = coap_new_error_response(pdu, code, &opts);
269 
270   CU_ASSERT_PTR_NOT_NULL(response);
271 
272   CU_ASSERT(response->used_size == sizeof(teststr) - 4);
273   CU_ASSERT(response->type == COAP_MESSAGE_ACK);
274   CU_ASSERT(response->token_length == 5);
275   CU_ASSERT(response->code == code);
276   CU_ASSERT(coap_pdu_encode_header(response, COAP_PROTO_UDP) == 4);
277   CU_ASSERT(memcmp(response->token - 4, teststr, sizeof(teststr)) == 0);
278   coap_delete_pdu(response);
279 }
280 
281 static void
t_error_response8(void)282 t_error_response8(void) {
283   const uint8_t code = COAP_RESPONSE_CODE(503);
284   uint8_t teststr[] = {
285     0x65, code, 0x00, 0x00,  't',  'o',  'k',  'e',
286      'n', 0xe0, 0x02, 0xdc, 0xd0, 0x00, 0xff,  'S',
287      'e',  'r',  'v',  'i',  'c',  'e',  ' ',  'U',
288      'n',  'a',  'v',  'a',  'i',  'l',  'a',  'b',
289      'l',  'e'
290   };
291   coap_pdu_t *response;
292 
293   coap_pdu_clear(pdu, pdu->max_size);
294   pdu->type = COAP_MESSAGE_CON;
295   coap_add_token(pdu, 5, (const uint8_t *)"token");
296   /* known option 1000 */
297   coap_add_option(pdu, 1000, 0, NULL);
298 
299   /* unknown options 1001 and 1014 */
300   coap_add_option(pdu, 1001, 0, NULL);
301   coap_add_option(pdu, 1014, 0, NULL);
302 
303   /* known option 2000 */
304   coap_add_option(pdu, 2000, 0, NULL);
305 
306   coap_option_filter_clear(&opts);
307   coap_option_filter_set(&opts, 1001);
308   coap_option_filter_set(&opts, 1014);
309   response = coap_new_error_response(pdu, code, &opts);
310 
311   CU_ASSERT_PTR_NOT_NULL(response);
312 
313   CU_ASSERT(response->used_size == sizeof(teststr) - 4);
314   CU_ASSERT(response->type == COAP_MESSAGE_ACK);
315   CU_ASSERT(response->token_length == 5);
316   CU_ASSERT(response->code == code);
317   CU_ASSERT(coap_pdu_encode_header(response, COAP_PROTO_UDP) == 4);
318   CU_ASSERT(memcmp(response->token - 4, teststr, sizeof(teststr)) == 0);
319   coap_delete_pdu(response);
320 }
321 
322 static int
t_error_response_tests_create(void)323 t_error_response_tests_create(void) {
324   pdu = coap_pdu_init(0, 0, 0, COAP_DEFAULT_MTU);
325 
326   return pdu == NULL;
327 }
328 
329 static int
t_error_response_tests_remove(void)330 t_error_response_tests_remove(void) {
331   coap_delete_pdu(pdu);
332   return 0;
333 }
334 
335 CU_pSuite
t_init_error_response_tests(void)336 t_init_error_response_tests(void) {
337   CU_pSuite suite[1];
338 
339   suite[0] = CU_add_suite("error response generator",
340                           t_error_response_tests_create,
341                           t_error_response_tests_remove);
342   if (!suite[0]) {                        /* signal error */
343     fprintf(stderr, "W: cannot add error response generator test suite (%s)\n",
344             CU_get_error_msg());
345 
346     return NULL;
347   }
348 
349 #define ERROR_RESPONSE_TEST(s,t)                                        \
350   if (!CU_ADD_TEST(s,t)) {                                                \
351     fprintf(stderr, "W: cannot add error response generator test (%s)\n", \
352             CU_get_error_msg());                                        \
353   }
354 
355   ERROR_RESPONSE_TEST(suite[0], t_error_response1);
356   ERROR_RESPONSE_TEST(suite[0], t_error_response2);
357   ERROR_RESPONSE_TEST(suite[0], t_error_response3);
358   ERROR_RESPONSE_TEST(suite[0], t_error_response4);
359   ERROR_RESPONSE_TEST(suite[0], t_error_response5);
360   ERROR_RESPONSE_TEST(suite[0], t_error_response6);
361   ERROR_RESPONSE_TEST(suite[0], t_error_response7);
362   ERROR_RESPONSE_TEST(suite[0], t_error_response8);
363 
364   return suite[0];
365 }
366 
367