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