1 /* libcoap unit tests
2  *
3  * Copyright (C) 2013,2015 Olaf Bergmann <bergmann@tzi.org>
4  *
5  * This file is part of the CoAP library libcoap. Please see
6  * README for terms of use.
7  */
8 
9 #include "coap_config.h"
10 #include "test_sendqueue.h"
11 
12 #include <coap.h>
13 
14 #include <stdio.h>
15 
16 static coap_queue_t *sendqueue;
17 
18 /* timestamps for tests. The first element in this array denotes the
19  * base time in ticks, the following elements are timestamps relative
20  * to this basetime.
21  */
22 static coap_tick_t timestamp[] = {
23   0, 100, 200, 30, 160
24 };
25 
26 /* nodes for testing. node[0] is left empty */
27 coap_queue_t *node[5];
28 
29 static coap_tick_t
add_timestamps(coap_queue_t * queue,size_t num)30 add_timestamps(coap_queue_t *queue, size_t num) {
31   coap_tick_t t = 0;
32   while (queue && num--) {
33     t += queue->t;
34     queue = queue->next;
35   }
36 
37   return t;
38 }
39 
40 static void
t_sendqueue1(void)41 t_sendqueue1(void) {
42   int result = coap_insert_node(&sendqueue, node[1]);
43 
44   CU_ASSERT(result > 0);
45   CU_ASSERT_PTR_NOT_NULL(sendqueue);
46   CU_ASSERT_PTR_EQUAL(sendqueue, node[1]);
47   CU_ASSERT(node[1]->t == timestamp[1]);
48 }
49 
50 static void
t_sendqueue2(void)51 t_sendqueue2(void) {
52   int result;
53 
54   result = coap_insert_node(&sendqueue, node[2]);
55 
56   CU_ASSERT(result > 0);
57   CU_ASSERT_PTR_EQUAL(sendqueue, node[1]);
58   CU_ASSERT_PTR_EQUAL(sendqueue->next, node[2]);
59 
60   CU_ASSERT(sendqueue->t == timestamp[1]);
61   CU_ASSERT(node[2]->t == timestamp[2] - timestamp[1]);
62 }
63 
64 /* insert new node as first element in queue */
65 static void
t_sendqueue3(void)66 t_sendqueue3(void) {
67   int result;
68   result = coap_insert_node(&sendqueue, node[3]);
69 
70   CU_ASSERT(result > 0);
71 
72   CU_ASSERT_PTR_EQUAL(sendqueue, node[3]);
73   CU_ASSERT(node[3]->t == timestamp[3]);
74 
75   CU_ASSERT_PTR_NOT_NULL(sendqueue->next);
76   CU_ASSERT_PTR_NOT_NULL(sendqueue->next->next);
77 
78   CU_ASSERT(sendqueue->next->t == timestamp[1] - timestamp[3]);
79   CU_ASSERT(sendqueue->next->next->t == timestamp[2] - timestamp[1]);
80 }
81 
82 /* insert new node as fourth element in queue */
83 static void
t_sendqueue4(void)84 t_sendqueue4(void) {
85   int result;
86 
87   result = coap_insert_node(&sendqueue, node[4]);
88 
89   CU_ASSERT(result > 0);
90 
91   CU_ASSERT_PTR_EQUAL(sendqueue, node[3]);
92 
93   CU_ASSERT_PTR_NOT_NULL(sendqueue->next);
94   CU_ASSERT_PTR_EQUAL(sendqueue->next, node[1]);
95 
96   CU_ASSERT_PTR_NOT_NULL(sendqueue->next->next);
97   CU_ASSERT_PTR_EQUAL(sendqueue->next->next, node[4]);
98 
99   CU_ASSERT_PTR_NOT_NULL(sendqueue->next->next->next);
100   CU_ASSERT_PTR_EQUAL(sendqueue->next->next->next, node[2]);
101 
102   CU_ASSERT(sendqueue->next->t == timestamp[1] - timestamp[3]);
103   CU_ASSERT(add_timestamps(sendqueue, 1) == timestamp[3]);
104   CU_ASSERT(add_timestamps(sendqueue, 2) == timestamp[1]);
105   CU_ASSERT(add_timestamps(sendqueue, 3) == timestamp[4]);
106   CU_ASSERT(add_timestamps(sendqueue, 4) == timestamp[2]);
107 }
108 
109 static void
t_sendqueue5(void)110 t_sendqueue5(void) {
111   const coap_tick_diff_t delta1 = 20, delta2 = 130;
112   unsigned int result;
113   coap_tick_t now;
114   struct coap_context_t ctx;
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 = sendqueue, i = 0; p; p = p->next, i++) {
124     times[i] = p->t;
125   }
126 
127   coap_ticks(&now);
128   ctx.sendqueue = sendqueue;
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 = 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   struct coap_context_t ctx;
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 = 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 timestamps of nodes in the sendqueue */
186   for (p = sendqueue, i = 0; p; p = p->next, i++) {
187     p->t = times[i];
188   }
189 }
190 
191 static void
t_sendqueue7(void)192 t_sendqueue7(void) {
193   int result;
194   coap_queue_t *tmp_node;
195 
196   CU_ASSERT_PTR_NOT_NULL(sendqueue);
197   CU_ASSERT_PTR_EQUAL(sendqueue, node[3]);
198 
199   CU_ASSERT_PTR_NOT_NULL(sendqueue->next);
200   CU_ASSERT_PTR_EQUAL(sendqueue->next, node[1]);
201 
202   result = coap_remove_from_queue(&sendqueue, 3, &tmp_node);
203 
204   CU_ASSERT(result == 1);
205   CU_ASSERT_PTR_NOT_NULL(tmp_node);
206   CU_ASSERT_PTR_EQUAL(tmp_node, node[3]);
207 
208   CU_ASSERT_PTR_NOT_NULL(sendqueue);
209   CU_ASSERT_PTR_EQUAL(sendqueue, node[1]);
210 
211   CU_ASSERT(sendqueue->t == timestamp[1]);
212 }
213 
214 static void
t_sendqueue8(void)215 t_sendqueue8(void) {
216   int result;
217   coap_queue_t *tmp_node;
218 
219   result = coap_remove_from_queue(&sendqueue, 4, &tmp_node);
220 
221   CU_ASSERT(result == 1);
222   CU_ASSERT_PTR_NOT_NULL(tmp_node);
223   CU_ASSERT_PTR_EQUAL(tmp_node, node[4]);
224 
225   CU_ASSERT_PTR_NOT_NULL(sendqueue);
226   CU_ASSERT_PTR_EQUAL(sendqueue, node[1]);
227   CU_ASSERT(sendqueue->t == timestamp[1]);
228 
229   CU_ASSERT_PTR_NOT_NULL(sendqueue->next);
230   CU_ASSERT_PTR_EQUAL(sendqueue->next, node[2]);
231   CU_ASSERT(sendqueue->next->t == timestamp[2] - timestamp[1]);
232 
233   CU_ASSERT_PTR_NULL(sendqueue->next->next);
234 }
235 
236 static void
t_sendqueue9(void)237 t_sendqueue9(void) {
238   coap_queue_t *tmp_node;
239   struct coap_context_t ctx;
240 
241   /* Initialize a fake context that points to our global sendqueue
242    * Note that all changes happen on ctx.sendqueue. */
243   ctx.sendqueue = sendqueue;
244   tmp_node = coap_peek_next(&ctx);
245   sendqueue = ctx.sendqueue;	/* must update global sendqueue for correct result */
246 
247   CU_ASSERT_PTR_NOT_NULL(tmp_node);
248   CU_ASSERT_PTR_EQUAL(tmp_node, node[1]);
249   CU_ASSERT_PTR_EQUAL(tmp_node, ctx.sendqueue);
250 
251   tmp_node = coap_pop_next(&ctx);
252   sendqueue = ctx.sendqueue;	/* must update global sendqueue for correct result */
253 
254   CU_ASSERT_PTR_NOT_NULL(tmp_node);
255   CU_ASSERT_PTR_EQUAL(tmp_node, node[1]);
256 
257   CU_ASSERT_PTR_NOT_NULL(sendqueue);
258   CU_ASSERT_PTR_EQUAL(sendqueue, node[2]);
259 
260   CU_ASSERT(tmp_node->t == timestamp[1]);
261   CU_ASSERT(sendqueue->t == timestamp[2]);
262 
263   CU_ASSERT_PTR_NULL(sendqueue->next);
264 }
265 
266 static void
t_sendqueue10(void)267 t_sendqueue10(void) {
268   coap_queue_t *tmp_node;
269   struct coap_context_t ctx;
270 
271   /* Initialize a fake context that points to our global sendqueue
272    * Note that all changes happen on ctx.sendqueue. */
273   ctx.sendqueue = sendqueue;
274 
275   tmp_node = coap_pop_next(&ctx);
276   sendqueue = ctx.sendqueue;	/* must update global sendqueue for correct result */
277 
278   CU_ASSERT_PTR_NOT_NULL(tmp_node);
279   CU_ASSERT_PTR_EQUAL(tmp_node, node[2]);
280 
281   CU_ASSERT_PTR_NULL(sendqueue);
282 
283   CU_ASSERT(tmp_node->t == timestamp[2]);
284 }
285 
286 /* This function creates a set of nodes for testing. These nodes
287  * will exist for all tests and are modified by coap_insert_node()
288  * and coap_remove_from_queue().
289  */
290 static int
t_sendqueue_tests_create(void)291 t_sendqueue_tests_create(void) {
292   size_t n, error = 0;
293   sendqueue = NULL;
294   coap_ticks(&timestamp[0]);
295 
296   memset(node, 0, sizeof(node));
297   for (n = 1; n < sizeof(node)/sizeof(coap_queue_t *); n++) {
298     node[n] = coap_new_node();
299     if (!node[n]) {
300       error = 1;
301       break;
302     }
303 
304     node[n]->id = n;
305     node[n]->t = timestamp[n];
306   }
307 
308   if (error) {
309     /* destroy all test nodes and set entry to zero */
310     for (n = 0; n < sizeof(node)/sizeof(coap_queue_t *); n++) {
311       if (node[n]) {
312 	coap_delete_node(node[n]);
313 	node[n] = NULL;
314       }
315     }
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 
325   /* destroy all test nodes */
326   for (n = 0; n < sizeof(node)/sizeof(coap_queue_t *); n++) {
327     if (node[n]) {
328       coap_delete_node(node[n]);
329     }
330   }
331 
332   return 0;
333 }
334 
335 CU_pSuite
t_init_sendqueue_tests(void)336 t_init_sendqueue_tests(void) {
337   CU_pSuite suite;
338 
339   suite = CU_add_suite("sendqueue",
340 		       t_sendqueue_tests_create, t_sendqueue_tests_remove);
341   if (!suite) {			/* signal error */
342     fprintf(stderr, "W: cannot add sendqueue test suite (%s)\n",
343 	    CU_get_error_msg());
344 
345     return NULL;
346   }
347 
348 #define SENDQUEUE_TEST(s,t)					      \
349   if (!CU_ADD_TEST(s,t)) {					      \
350     fprintf(stderr, "W: cannot add sendqueue test (%s)\n",	      \
351 	    CU_get_error_msg());				      \
352   }
353 
354   SENDQUEUE_TEST(suite, t_sendqueue1);
355   SENDQUEUE_TEST(suite, t_sendqueue2);
356   SENDQUEUE_TEST(suite, t_sendqueue3);
357   SENDQUEUE_TEST(suite, t_sendqueue4);
358   SENDQUEUE_TEST(suite, t_sendqueue5);
359   SENDQUEUE_TEST(suite, t_sendqueue6);
360   SENDQUEUE_TEST(suite, t_sendqueue7);
361   SENDQUEUE_TEST(suite, t_sendqueue8);
362   SENDQUEUE_TEST(suite, t_sendqueue9);
363   SENDQUEUE_TEST(suite, t_sendqueue10);
364 
365   return suite;
366 }
367 
368