1 /* libcoap unit tests
2 *
3 * Copyright (C) 2013,2015,2022-2023 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_sendqueue.h"
13
14 #include <stdio.h>
15
16 #if COAP_CLIENT_SUPPORT
17 static coap_context_t *ctx; /* Holds the coap context for most tests */
18 static coap_session_t *session; /* Holds a reference-counted session object */
19
20 /* timestamps for tests. The first element in this array denotes the
21 * base time in ticks, the following elements are timestamps relative
22 * to this basetime.
23 */
24 static coap_tick_t timestamp[] = {
25 0, 100, 200, 30, 160
26 };
27
28 /* nodes for testing. node[0] is left empty */
29 coap_queue_t *node[5];
30
31 static coap_tick_t
add_timestamps(coap_queue_t *queue, size_t num)32 add_timestamps(coap_queue_t *queue, size_t num) {
33 coap_tick_t t = 0;
34 while (queue && num--) {
35 t += queue->t;
36 queue = queue->next;
37 }
38
39 return t;
40 }
41
42 static void
t_sendqueue1(void)43 t_sendqueue1(void) {
44 int result = coap_insert_node(&ctx->sendqueue, node[1]);
45
46 CU_ASSERT(result > 0);
47 CU_ASSERT_PTR_NOT_NULL(ctx->sendqueue);
48 CU_ASSERT_PTR_EQUAL(ctx->sendqueue, node[1]);
49 CU_ASSERT(node[1]->t == timestamp[1]);
50 }
51
52 static void
t_sendqueue2(void)53 t_sendqueue2(void) {
54 int result;
55
56 result = coap_insert_node(&ctx->sendqueue, node[2]);
57
58 CU_ASSERT(result > 0);
59 CU_ASSERT_PTR_EQUAL(ctx->sendqueue, node[1]);
60 CU_ASSERT_PTR_EQUAL(ctx->sendqueue->next, node[2]);
61
62 CU_ASSERT(ctx->sendqueue->t == timestamp[1]);
63 CU_ASSERT(node[2]->t == timestamp[2] - timestamp[1]);
64 }
65
66 /* insert new node as first element in queue */
67 static void
t_sendqueue3(void)68 t_sendqueue3(void) {
69 int result;
70 result = coap_insert_node(&ctx->sendqueue, node[3]);
71
72 CU_ASSERT(result > 0);
73
74 CU_ASSERT_PTR_EQUAL(ctx->sendqueue, node[3]);
75 CU_ASSERT(node[3]->t == timestamp[3]);
76
77 CU_ASSERT_PTR_NOT_NULL(ctx->sendqueue->next);
78 CU_ASSERT_PTR_NOT_NULL(ctx->sendqueue->next->next);
79
80 CU_ASSERT(ctx->sendqueue->next->t == timestamp[1] - timestamp[3]);
81 CU_ASSERT(ctx->sendqueue->next->next->t == timestamp[2] - timestamp[1]);
82 }
83
84 /* insert new node as fourth element in queue */
85 static void
t_sendqueue4(void)86 t_sendqueue4(void) {
87 int result;
88
89 result = coap_insert_node(&ctx->sendqueue, node[4]);
90
91 CU_ASSERT(result > 0);
92
93 CU_ASSERT_PTR_EQUAL(ctx->sendqueue, node[3]);
94
95 CU_ASSERT_PTR_NOT_NULL(ctx->sendqueue->next);
96 CU_ASSERT_PTR_EQUAL(ctx->sendqueue->next, node[1]);
97
98 CU_ASSERT_PTR_NOT_NULL(ctx->sendqueue->next->next);
99 CU_ASSERT_PTR_EQUAL(ctx->sendqueue->next->next, node[4]);
100
101 CU_ASSERT_PTR_NOT_NULL(ctx->sendqueue->next->next->next);
102 CU_ASSERT_PTR_EQUAL(ctx->sendqueue->next->next->next, node[2]);
103
104 CU_ASSERT(ctx->sendqueue->next->t == timestamp[1] - timestamp[3]);
105 CU_ASSERT(add_timestamps(ctx->sendqueue, 1) == timestamp[3]);
106 CU_ASSERT(add_timestamps(ctx->sendqueue, 2) == timestamp[1]);
107 CU_ASSERT(add_timestamps(ctx->sendqueue, 3) == timestamp[4]);
108 CU_ASSERT(add_timestamps(ctx->sendqueue, 4) == timestamp[2]);
109 }
110
111 static void
t_sendqueue5(void)112 t_sendqueue5(void) {
113 const coap_tick_diff_t delta1 = 20, delta2 = 130;
114 unsigned int result;
115 coap_tick_t now;
116
117 /* space for saving the current node timestamps */
118 static coap_tick_t times[sizeof(timestamp)/sizeof(coap_tick_t)];
119 coap_queue_t *p;
120 int i;
121
122 /* save timestamps of nodes in the sendqueue in their actual order */
123 memset(times, 0, sizeof(times));
124 for (p = ctx->sendqueue, i = 0; p; p = p->next, i++) {
125 times[i] = p->t;
126 }
127
128 coap_ticks(&now);
129 ctx->sendqueue_basetime = now;
130
131 now -= delta1;
132 result = coap_adjust_basetime(ctx, now);
133
134 CU_ASSERT(result == 0);
135 CU_ASSERT_PTR_NOT_NULL(ctx->sendqueue);
136 CU_ASSERT(ctx->sendqueue_basetime == now);
137 CU_ASSERT(ctx->sendqueue->t == timestamp[3] + delta1);
138
139 now += delta2;
140 result = coap_adjust_basetime(ctx, now);
141 CU_ASSERT(result == 2);
142 CU_ASSERT(ctx->sendqueue_basetime == now);
143 CU_ASSERT_PTR_NOT_NULL(ctx->sendqueue);
144 CU_ASSERT(ctx->sendqueue->t == 0);
145
146 CU_ASSERT_PTR_NOT_NULL(ctx->sendqueue->next);
147 CU_ASSERT(ctx->sendqueue->next->t == 0);
148
149 CU_ASSERT_PTR_NOT_NULL(ctx->sendqueue->next->next);
150 CU_ASSERT(ctx->sendqueue->next->next->t == delta2 - delta1 - timestamp[1]);
151
152 /* restore timestamps of nodes in the sendqueue */
153 for (p = ctx->sendqueue, i = 0; p; p = p->next, i++) {
154 p->t = times[i];
155 }
156 }
157
158 static void
t_sendqueue6(void)159 t_sendqueue6(void) {
160 unsigned int result;
161 coap_tick_t now;
162 const coap_tick_diff_t delta = 20;
163 coap_queue_t *tmpqueue = ctx->sendqueue;
164
165 /* space for saving the current node timestamps */
166 static coap_tick_t times[sizeof(timestamp)/sizeof(coap_tick_t)];
167 coap_queue_t *p;
168 int i;
169
170 /* save timestamps of nodes in the sendqueue in their actual order */
171 memset(times, 0, sizeof(times));
172 for (p = ctx->sendqueue, i = 0; p; p = p->next, i++) {
173 times[i] = p->t;
174 }
175
176 coap_ticks(&now);
177 ctx->sendqueue = NULL;
178 ctx->sendqueue_basetime = now;
179
180 result = coap_adjust_basetime(ctx, now + delta);
181
182 CU_ASSERT(result == 0);
183 CU_ASSERT(ctx->sendqueue_basetime == now + delta);
184
185 /* restore sendqueue */
186 ctx->sendqueue = tmpqueue;
187 }
188
189 static void
t_sendqueue7(void)190 t_sendqueue7(void) {
191 int result;
192 coap_queue_t *tmp_node;
193
194 CU_ASSERT_PTR_NOT_NULL(ctx->sendqueue);
195 CU_ASSERT_PTR_EQUAL(ctx->sendqueue, node[3]);
196
197 CU_ASSERT_PTR_NOT_NULL(ctx->sendqueue->next);
198 CU_ASSERT_PTR_EQUAL(ctx->sendqueue->next, node[1]);
199
200 result = coap_remove_from_queue(&ctx->sendqueue, session, 3, &tmp_node);
201
202 CU_ASSERT(result == 1);
203 CU_ASSERT_PTR_NOT_NULL(tmp_node);
204 CU_ASSERT_PTR_EQUAL(tmp_node, node[3]);
205
206 CU_ASSERT_PTR_NOT_NULL(ctx->sendqueue);
207 CU_ASSERT_PTR_EQUAL(ctx->sendqueue, node[1]);
208
209 CU_ASSERT(ctx->sendqueue->t == timestamp[1]);
210 }
211
212 static void
t_sendqueue8(void)213 t_sendqueue8(void) {
214 int result;
215 coap_queue_t *tmp_node;
216
217 result = coap_remove_from_queue(&ctx->sendqueue, session, 4, &tmp_node);
218
219 CU_ASSERT(result == 1);
220 CU_ASSERT_PTR_NOT_NULL(tmp_node);
221 CU_ASSERT_PTR_EQUAL(tmp_node, node[4]);
222
223 CU_ASSERT_PTR_NOT_NULL(ctx->sendqueue);
224 CU_ASSERT_PTR_EQUAL(ctx->sendqueue, node[1]);
225 CU_ASSERT(ctx->sendqueue->t == timestamp[1]);
226
227 CU_ASSERT_PTR_NOT_NULL(ctx->sendqueue->next);
228 CU_ASSERT_PTR_EQUAL(ctx->sendqueue->next, node[2]);
229 CU_ASSERT(ctx->sendqueue->next->t == timestamp[2] - timestamp[1]);
230
231 CU_ASSERT_PTR_NULL(ctx->sendqueue->next->next);
232 }
233
234 static void
t_sendqueue9(void)235 t_sendqueue9(void) {
236 coap_queue_t *tmp_node;
237 tmp_node = coap_peek_next(ctx);
238
239 CU_ASSERT_PTR_NOT_NULL(tmp_node);
240 CU_ASSERT_PTR_EQUAL(tmp_node, node[1]);
241 CU_ASSERT_PTR_EQUAL(tmp_node, ctx->sendqueue);
242
243 tmp_node = coap_pop_next(ctx);
244
245 CU_ASSERT_PTR_NOT_NULL(tmp_node);
246 CU_ASSERT_PTR_EQUAL(tmp_node, node[1]);
247
248 CU_ASSERT_PTR_NOT_NULL(ctx->sendqueue);
249 CU_ASSERT_PTR_EQUAL(ctx->sendqueue, node[2]);
250
251 CU_ASSERT(tmp_node->t == timestamp[1]);
252 CU_ASSERT(ctx->sendqueue->t == timestamp[2]);
253
254 CU_ASSERT_PTR_NULL(ctx->sendqueue->next);
255 }
256
257 static void
t_sendqueue10(void)258 t_sendqueue10(void) {
259 coap_queue_t *tmp_node;
260
261 tmp_node = coap_pop_next(ctx);
262
263 CU_ASSERT_PTR_NOT_NULL(tmp_node);
264 CU_ASSERT_PTR_EQUAL(tmp_node, node[2]);
265
266 CU_ASSERT_PTR_NULL(ctx->sendqueue);
267
268 CU_ASSERT(tmp_node->t == timestamp[2]);
269 }
270
271 /* This function creates a set of nodes for testing. These nodes
272 * will exist for all tests and are modified by coap_insert_node()
273 * and coap_remove_from_queue().
274 */
275 static int
t_sendqueue_tests_create(void)276 t_sendqueue_tests_create(void) {
277 size_t n, error = 0;
278 coap_address_t addr;
279 coap_address_init(&addr);
280
281 addr.size = sizeof(struct sockaddr_in6);
282 addr.addr.sin6.sin6_family = AF_INET6;
283 addr.addr.sin6.sin6_addr = in6addr_any;
284 addr.addr.sin6.sin6_port = htons(COAP_DEFAULT_PORT);
285
286 ctx = coap_new_context(&addr);
287
288 addr.addr.sin6.sin6_addr = in6addr_loopback;
289 session = coap_new_client_session(ctx, NULL, &addr, COAP_PROTO_UDP);
290
291 coap_ticks(×tamp[0]);
292
293 memset(node, 0, sizeof(node));
294 for (n = 1; n < sizeof(node)/sizeof(coap_queue_t *); n++) {
295 node[n] = coap_new_node();
296 if (!node[n]) {
297 error = 1;
298 break;
299 }
300
301 node[n]->id = n;
302 node[n]->t = timestamp[n];
303 node[n]->session = coap_session_reference(session);
304 }
305
306 if (error) {
307 /* destroy all test nodes and set entry to zero */
308 for (n = 0; n < sizeof(node)/sizeof(coap_queue_t *); n++) {
309 if (node[n]) {
310 coap_delete_node(node[n]);
311 node[n] = NULL;
312 }
313 }
314 coap_free_context(ctx);
315 ctx = NULL;
316 }
317
318 return error;
319 }
320
321 static int
t_sendqueue_tests_remove(void)322 t_sendqueue_tests_remove(void) {
323 size_t n;
324 for (n = 0; n < sizeof(node)/sizeof(coap_queue_t *); n++) {
325 if (node[n]) {
326 coap_delete_node(node[n]);
327 node[n] = NULL;
328 }
329 }
330 coap_free_context(ctx);
331 return 0;
332 }
333
334 CU_pSuite
t_init_sendqueue_tests(void)335 t_init_sendqueue_tests(void) {
336 CU_pSuite suite;
337
338 suite = CU_add_suite("sendqueue",
339 t_sendqueue_tests_create, t_sendqueue_tests_remove);
340 if (!suite) { /* signal error */
341 fprintf(stderr, "W: cannot add sendqueue test suite (%s)\n",
342 CU_get_error_msg());
343
344 return NULL;
345 }
346
347 #define SENDQUEUE_TEST(s,t) \
348 if (!CU_ADD_TEST(s,t)) { \
349 fprintf(stderr, "W: cannot add sendqueue test (%s)\n", \
350 CU_get_error_msg()); \
351 }
352
353 SENDQUEUE_TEST(suite, t_sendqueue1);
354 SENDQUEUE_TEST(suite, t_sendqueue2);
355 SENDQUEUE_TEST(suite, t_sendqueue3);
356 SENDQUEUE_TEST(suite, t_sendqueue4);
357 SENDQUEUE_TEST(suite, t_sendqueue5);
358 SENDQUEUE_TEST(suite, t_sendqueue6);
359 SENDQUEUE_TEST(suite, t_sendqueue7);
360 SENDQUEUE_TEST(suite, t_sendqueue8);
361 SENDQUEUE_TEST(suite, t_sendqueue9);
362 SENDQUEUE_TEST(suite, t_sendqueue10);
363
364 return suite;
365 }
366 #endif /* COAP_CLIENT_SUPPORT */
367