1 /*
2  * we include the c source file to get at the opaque types and
3  * api functions
4  */
5 #include <string.h>
6 #include <stdio.h>
7 #include <assert.h>
8 #include <sys/types.h>
9 #include <signal.h>
10 #include <unistd.h>
11 #include <sys/time.h>
12 #include "squeue.c"
13 #include "t-utils.h"
14 
squeue_foreach(squeue_t * q,int (* walker)(squeue_event *,void *),void * arg)15 static void squeue_foreach(squeue_t *q, int (*walker)(squeue_event *, void *), void *arg)
16 {
17 	squeue_t *dup;
18 	void *e, *dup_d;
19 
20 	dup = squeue_create(q->size);
21 	dup_d = dup->d;
22 	memcpy(dup, q, sizeof(*q));
23 	dup->d = dup_d;
24 	memcpy(dup->d, q->d, (q->size * sizeof(void *)));
25 
26 	while ((e = pqueue_pop(dup))) {
27 		walker(e, arg);
28 	}
29 	squeue_destroy(dup, 0);
30 }
31 
32 #define t(expr, args...) \
33 	do { \
34 		if ((expr)) { \
35 			t_pass(#expr); \
36 		} else { \
37 			t_fail(#expr " @%s:%d", __FILE__, __LINE__); \
38 		} \
39 	} while(0)
40 
41 typedef struct sq_test_event {
42 	unsigned long id;
43 	squeue_event *evt;
44 } sq_test_event;
45 
46 static time_t sq_high = 0;
sq_walker(squeue_event * evt,void * arg)47 static int sq_walker(squeue_event *evt, void *arg)
48 {
49 	static int walks = 0;
50 
51 	walks++;
52 	t(sq_high <= evt->when.tv_sec, "sq_high: %lu; evt->when: %lu\n",
53 	  sq_high, evt->when.tv_sec);
54 	sq_high = (unsigned long)evt->when.tv_sec;
55 
56 	return 0;
57 }
58 
59 #define EVT_ARY 65101
sq_test_random(squeue_t * sq)60 static int sq_test_random(squeue_t *sq)
61 {
62 	unsigned long size, i;
63 	unsigned long long numbers[EVT_ARY], *d, max = 0;
64 	struct timeval now;
65 
66 	size = squeue_size(sq);
67 	now.tv_sec = time(NULL);
68 	srand((int)now.tv_sec);
69 	for (i = 0; i < EVT_ARY; i++) {
70 		now.tv_usec = (time_t)rand();
71 		squeue_add_tv(sq, &now, &numbers[i]);
72 		numbers[i] = evt_compute_pri(&now);
73 		t(squeue_size(sq) == i + 1 + size);
74 	}
75 
76 	t(pqueue_is_valid(sq));
77 
78 	/*
79 	 * make sure we pop events in increasing "priority",
80 	 * since we calculate priority based on time and later
81 	 * is lower prio
82 	 */
83 	for (i = 0; i < EVT_ARY; i++) {
84 		d = (unsigned long long *)squeue_pop(sq);
85 		t(max <= *d, "popping randoms. i: %lu; delta: %lld; max: %llu; *d: %llu\n",
86 		  i, max - *d, max, *d);
87 		max = *d;
88 		t(squeue_size(sq) == size + (EVT_ARY - i - 1));
89 	}
90 	t(pqueue_is_valid(sq));
91 
92 	return 0;
93 }
94 
main(int argc,char ** argv)95 int main(int argc, char **argv)
96 {
97 	squeue_t *sq;
98 	struct timeval tv;
99 	sq_test_event a, b, c, d, *x;
100 
101 	t_set_colors(0);
102 	t_start("squeue tests");
103 
104 	a.id = 1;
105 	b.id = 2;
106 	c.id = 3;
107 	d.id = 4;
108 
109 	gettimeofday(&tv, NULL);
110 	/* Order in is a, b, c, d, but we should get b, c, d, a out. */
111 	srand(tv.tv_usec ^ tv.tv_sec);
112 	t((sq = squeue_create(1024)) != NULL);
113 	t(squeue_size(sq) == 0);
114 
115 	/* we fill and empty the squeue completely once before testing */
116 	sq_test_random(sq);
117 	t(squeue_size(sq) == 0, "Size should be 0 after first sq_test_random");
118 
119 	t((a.evt = squeue_add(sq, time(NULL) + 9, &a)) != NULL);
120 	t(squeue_size(sq) == 1);
121 	t((b.evt = squeue_add(sq, time(NULL) + 3, &b)) != NULL);
122 	t(squeue_size(sq) == 2);
123 	t((c.evt = squeue_add_msec(sq, time(NULL) + 5, 0, &c)) != NULL);
124 	t(squeue_size(sq) == 3);
125 	t((d.evt = squeue_add_usec(sq, time(NULL) + 5, 1, &d)) != NULL);
126 	t(squeue_size(sq) == 4);
127 
128 	/* add and remove lots. remainder should be what we have above */
129 	sq_test_random(sq);
130 
131 	/* testing squeue_peek() */
132 	t((x = (sq_test_event *)squeue_peek(sq)) != NULL);
133 	t(x == &b, "x: %p; a: %p; b: %p; c: %p; d: %p\n", x, &a, &b, &c, &d);
134 	t(x->id == b.id);
135 	t(squeue_size(sq) == 4);
136 
137 	/* testing squeue_remove() and re-add */
138 	t(squeue_remove(sq, b.evt) == 0);
139 	t(squeue_size(sq) == 3);
140 	t((x = squeue_peek(sq)) != NULL);
141 	t(x == &c);
142 	t((b.evt = squeue_add(sq, time(NULL) + 3, &b)) != NULL);
143 	t(squeue_size(sq) == 4);
144 
145 	/* peek should now give us the &b event (again) */
146 	t((x = squeue_peek(sq)) != NULL);
147 	if (x != &b) {
148 		printf("about to fail pretty fucking hard...\n");
149 		printf("ea: %p; &b: %p; &c: %p; ed: %p; x: %p\n",
150 			   &a, &b, &c, &d, x);
151 	}
152 	t(x == &b);
153 	t(x->id == b.id);
154 	t(squeue_size(sq) == 4);
155 
156 	/* testing squeue_pop(), lifo manner */
157 	t((x = squeue_pop(sq)) != NULL);
158 	t(squeue_size(sq) == 3,
159 	  "squeue_size(sq) = %d\n", squeue_size(sq));
160 	t(x == &b, "x: %p; &b: %p\n", x, &b);
161 	t(x->id == b.id, "x->id: %lu; d.id: %lu\n", x->id, d.id);
162 
163 	/* Test squeue_pop() */
164 	t((x = squeue_pop(sq)) != NULL);
165 	t(squeue_size(sq) == 2);
166 	t(x == &c, "x->id: %lu; c.id: %lu\n", x->id, c.id);
167 	t(x->id == c.id, "x->id: %lu; c.id: %lu\n", x->id, c.id);
168 
169 	/* this should fail gracefully (-1 return from squeue_remove()) */
170 	t(squeue_remove(NULL, NULL) == -1);
171 	t(squeue_remove(NULL, a.evt) == -1);
172 
173 	squeue_foreach(sq, sq_walker, NULL);
174 
175 	/* clean up to prevent false valgrind positives */
176 	squeue_destroy(sq, 0);
177 
178 	return t_end();
179 }
180