1 #include <gtest/gtest.h>
2
3 #include <climits>
4
5 #include "AllocationTestHarness.h"
6
7 #include "osi/include/allocator.h"
8 #include "osi/include/fixed_queue.h"
9 #include "osi/include/future.h"
10 #include "osi/include/osi.h"
11 #include "osi/include/thread.h"
12
13 static const size_t TEST_QUEUE_SIZE = 10;
14 static const char* DUMMY_DATA_STRING = "Dummy data string";
15 static const char* DUMMY_DATA_STRING1 = "Dummy data string1";
16 static const char* DUMMY_DATA_STRING2 = "Dummy data string2";
17 static const char* DUMMY_DATA_STRING3 = "Dummy data string3";
18 static future_t* received_message_future = NULL;
19
20 static int test_queue_entry_free_counter = 0;
21
22 // Test whether a file descriptor |fd| is readable.
23 // Return true if the file descriptor is readable, otherwise false.
is_fd_readable(int fd)24 static bool is_fd_readable(int fd) {
25 fd_set rfds;
26 struct timeval tv;
27
28 FD_ZERO(&rfds);
29 tv.tv_sec = 0;
30 tv.tv_usec = 0;
31 FD_SET(fd, &rfds);
32 // Only the enqueue_fd should be readable
33 int result = select(FD_SETSIZE, &rfds, NULL, NULL, &tv);
34 EXPECT_TRUE(result >= 0);
35
36 return FD_ISSET(fd, &rfds);
37 }
38
39 // Function for performing dequeue operations from the queue when is ready
fixed_queue_ready(fixed_queue_t * queue,UNUSED_ATTR void * context)40 static void fixed_queue_ready(fixed_queue_t* queue, UNUSED_ATTR void* context) {
41 void* msg = fixed_queue_try_dequeue(queue);
42 EXPECT_TRUE(msg != NULL);
43 future_ready(received_message_future, msg);
44 }
45
test_queue_entry_free_cb(void * data)46 static void test_queue_entry_free_cb(void* data) {
47 // Don't free the data, because we are testing only whether the callback
48 // is called.
49 test_queue_entry_free_counter++;
50 }
51
52 class FixedQueueTest : public AllocationTestHarness {};
53
TEST_F(FixedQueueTest,test_fixed_queue_new_free)54 TEST_F(FixedQueueTest, test_fixed_queue_new_free) {
55 fixed_queue_t* queue;
56
57 // Test a corner case: queue of size 0
58 queue = fixed_queue_new(0);
59 EXPECT_TRUE(queue != NULL);
60 fixed_queue_free(queue, NULL);
61
62 // Test a corner case: queue of size 1
63 queue = fixed_queue_new(1);
64 EXPECT_TRUE(queue != NULL);
65 fixed_queue_free(queue, NULL);
66
67 // Test a corner case: queue of maximum size
68 queue = fixed_queue_new((size_t)-1);
69 EXPECT_TRUE(queue != NULL);
70 fixed_queue_free(queue, NULL);
71
72 // Test a queue of some size
73 queue = fixed_queue_new(TEST_QUEUE_SIZE);
74 EXPECT_TRUE(queue != NULL);
75 fixed_queue_free(queue, NULL);
76
77 // Test free-ing a NULL queue
78 fixed_queue_free(NULL, NULL);
79 fixed_queue_free(NULL, osi_free);
80 }
81
TEST_F(FixedQueueTest,test_fixed_queue_flush)82 TEST_F(FixedQueueTest, test_fixed_queue_flush) {
83 fixed_queue_t* queue;
84
85 // Test a corner case: queue of size 0 and no callback to free entries
86 queue = fixed_queue_new(0);
87 EXPECT_TRUE(queue != NULL);
88 fixed_queue_flush(queue, NULL);
89 EXPECT_TRUE(fixed_queue_is_empty(queue));
90 fixed_queue_free(queue, osi_free);
91
92 // Test a corner case: queue of size 0 and a callback to free entries
93 queue = fixed_queue_new(0);
94 EXPECT_TRUE(queue != NULL);
95 fixed_queue_flush(queue, osi_free);
96 EXPECT_TRUE(fixed_queue_is_empty(queue));
97 fixed_queue_free(queue, osi_free);
98
99 // Test a queue of some size and no callback to free entries
100 queue = fixed_queue_new(TEST_QUEUE_SIZE);
101 EXPECT_TRUE(queue != NULL);
102 fixed_queue_try_enqueue(queue, (void*)DUMMY_DATA_STRING1);
103 fixed_queue_try_enqueue(queue, (void*)DUMMY_DATA_STRING2);
104 fixed_queue_try_enqueue(queue, (void*)DUMMY_DATA_STRING3);
105 EXPECT_FALSE(fixed_queue_is_empty(queue));
106 fixed_queue_flush(queue, NULL);
107 EXPECT_TRUE(fixed_queue_is_empty(queue));
108 fixed_queue_free(queue, osi_free);
109
110 // Test a queue of some size and a callback to free entries
111 test_queue_entry_free_counter = 0;
112 queue = fixed_queue_new(TEST_QUEUE_SIZE);
113 EXPECT_TRUE(queue != NULL);
114 fixed_queue_try_enqueue(queue, (void*)DUMMY_DATA_STRING1);
115 fixed_queue_try_enqueue(queue, (void*)DUMMY_DATA_STRING2);
116 fixed_queue_try_enqueue(queue, (void*)DUMMY_DATA_STRING3);
117 EXPECT_FALSE(fixed_queue_is_empty(queue));
118 fixed_queue_flush(queue, test_queue_entry_free_cb);
119 EXPECT_TRUE(test_queue_entry_free_counter == 3);
120 EXPECT_TRUE(fixed_queue_is_empty(queue));
121 fixed_queue_free(queue, osi_free);
122 }
123
TEST_F(FixedQueueTest,test_fixed_queue_is_empty)124 TEST_F(FixedQueueTest, test_fixed_queue_is_empty) {
125 fixed_queue_t* queue;
126
127 // Test a NULL queue
128 EXPECT_TRUE(fixed_queue_is_empty(NULL));
129
130 // Test an empty queue
131 queue = fixed_queue_new(TEST_QUEUE_SIZE);
132 ASSERT_TRUE(queue != NULL);
133 EXPECT_TRUE(fixed_queue_is_empty(queue));
134
135 // Test a non-empty queue
136 fixed_queue_try_enqueue(queue, (void*)DUMMY_DATA_STRING);
137 EXPECT_FALSE(fixed_queue_is_empty(queue));
138
139 // Test an empty dequeued queue
140 ASSERT_EQ(DUMMY_DATA_STRING, fixed_queue_try_dequeue(queue));
141 EXPECT_TRUE(fixed_queue_is_empty(queue));
142
143 fixed_queue_free(queue, NULL);
144 }
145
TEST_F(FixedQueueTest,test_fixed_queue_length)146 TEST_F(FixedQueueTest, test_fixed_queue_length) {
147 fixed_queue_t* queue;
148
149 // Test a NULL queue
150 EXPECT_EQ((size_t)0, fixed_queue_length(NULL));
151
152 // Test an empty queue
153 queue = fixed_queue_new(TEST_QUEUE_SIZE);
154 ASSERT_TRUE(queue != NULL);
155 EXPECT_EQ((size_t)0, fixed_queue_length(queue));
156
157 // Test a non-empty queue
158 fixed_queue_try_enqueue(queue, (void*)DUMMY_DATA_STRING);
159 EXPECT_EQ((size_t)1, fixed_queue_length(queue));
160
161 // Test an empty dequeued queue
162 ASSERT_EQ(DUMMY_DATA_STRING, fixed_queue_try_dequeue(queue));
163 EXPECT_EQ((size_t)0, fixed_queue_length(queue));
164
165 fixed_queue_free(queue, NULL);
166 }
167
TEST_F(FixedQueueTest,test_fixed_queue_capacity)168 TEST_F(FixedQueueTest, test_fixed_queue_capacity) {
169 fixed_queue_t* queue;
170
171 // Test a corner case: queue of size 0
172 queue = fixed_queue_new(0);
173 ASSERT_TRUE(queue != NULL);
174 EXPECT_EQ((size_t)0, fixed_queue_capacity(queue));
175 fixed_queue_free(queue, NULL);
176
177 // Test a corner case: queue of size 1
178 queue = fixed_queue_new(1);
179 ASSERT_TRUE(queue != NULL);
180 EXPECT_EQ((size_t)1, fixed_queue_capacity(queue));
181 fixed_queue_free(queue, NULL);
182
183 // Test a corner case: queue of maximum size
184 queue = fixed_queue_new((size_t)-1);
185 ASSERT_TRUE(queue != NULL);
186 EXPECT_EQ((size_t)-1, fixed_queue_capacity(queue));
187 fixed_queue_free(queue, NULL);
188
189 // Test a queue of some size
190 queue = fixed_queue_new(TEST_QUEUE_SIZE);
191 ASSERT_TRUE(queue != NULL);
192 EXPECT_EQ(TEST_QUEUE_SIZE, fixed_queue_capacity(queue));
193 fixed_queue_free(queue, NULL);
194 }
195
TEST_F(FixedQueueTest,test_fixed_queue_enqueue_dequeue)196 TEST_F(FixedQueueTest, test_fixed_queue_enqueue_dequeue) {
197 fixed_queue_t* queue = fixed_queue_new(TEST_QUEUE_SIZE);
198 ASSERT_TRUE(queue != NULL);
199
200 // Test blocking enqueue and blocking dequeue
201 fixed_queue_enqueue(queue, (void*)DUMMY_DATA_STRING);
202 EXPECT_EQ((size_t)1, fixed_queue_length(queue));
203 EXPECT_EQ(DUMMY_DATA_STRING, fixed_queue_dequeue(queue));
204 EXPECT_EQ((size_t)0, fixed_queue_length(queue));
205
206 // Test non-blocking enqueue and non-blocking dequeue
207 EXPECT_TRUE(fixed_queue_try_enqueue(queue, (void*)DUMMY_DATA_STRING));
208 EXPECT_EQ((size_t)1, fixed_queue_length(queue));
209 EXPECT_EQ(DUMMY_DATA_STRING, fixed_queue_try_dequeue(queue));
210 EXPECT_EQ((size_t)0, fixed_queue_length(queue));
211
212 // Test non-blocking enqueue beyond queue capacity
213 for (size_t i = 0; i < TEST_QUEUE_SIZE; i++) {
214 EXPECT_TRUE(fixed_queue_try_enqueue(queue, (void*)DUMMY_DATA_STRING));
215 }
216 // The next enqueue operation is beyond the queue capacity, so it should fail
217 EXPECT_FALSE(fixed_queue_try_enqueue(queue, (void*)DUMMY_DATA_STRING));
218
219 // Test non-blocking dequeue from a queue that is full to max capacity
220 for (size_t i = 0; i < TEST_QUEUE_SIZE; i++) {
221 EXPECT_EQ(DUMMY_DATA_STRING, fixed_queue_try_dequeue(queue));
222 }
223
224 // Test non-blocking dequeue from an empty queue
225 EXPECT_EQ(NULL, fixed_queue_try_dequeue(queue));
226
227 // Test non-blocking dequeue from a NULL queue
228 EXPECT_EQ(NULL, fixed_queue_try_dequeue(NULL));
229
230 fixed_queue_free(queue, NULL);
231 }
232
TEST_F(FixedQueueTest,test_fixed_queue_try_peek_first_last)233 TEST_F(FixedQueueTest, test_fixed_queue_try_peek_first_last) {
234 fixed_queue_t* queue = fixed_queue_new(TEST_QUEUE_SIZE);
235 ASSERT_TRUE(queue != NULL);
236
237 // Test peek first/last from a NULL queue
238 EXPECT_EQ(NULL, fixed_queue_try_peek_first(NULL));
239 EXPECT_EQ(NULL, fixed_queue_try_peek_last(NULL));
240
241 // Test peek first/last from an empty queue
242 EXPECT_EQ(NULL, fixed_queue_try_peek_first(queue));
243 EXPECT_EQ(NULL, fixed_queue_try_peek_last(queue));
244
245 // Test peek first/last from a queue with one element
246 fixed_queue_enqueue(queue, (void*)DUMMY_DATA_STRING1);
247 EXPECT_EQ(DUMMY_DATA_STRING1, fixed_queue_try_peek_first(queue));
248 EXPECT_EQ(DUMMY_DATA_STRING1, fixed_queue_try_peek_last(queue));
249
250 // Test peek first/last from a queue with two elements
251 fixed_queue_enqueue(queue, (void*)DUMMY_DATA_STRING2);
252 EXPECT_EQ(DUMMY_DATA_STRING1, fixed_queue_try_peek_first(queue));
253 EXPECT_EQ(DUMMY_DATA_STRING2, fixed_queue_try_peek_last(queue));
254
255 // Test peek first/last from a queue with three elements
256 fixed_queue_enqueue(queue, (void*)DUMMY_DATA_STRING3);
257 EXPECT_EQ(DUMMY_DATA_STRING1, fixed_queue_try_peek_first(queue));
258 EXPECT_EQ(DUMMY_DATA_STRING3, fixed_queue_try_peek_last(queue));
259
260 fixed_queue_free(queue, NULL);
261 }
262
TEST_F(FixedQueueTest,test_fixed_queue_try_remove_from_queue)263 TEST_F(FixedQueueTest, test_fixed_queue_try_remove_from_queue) {
264 fixed_queue_t* queue = fixed_queue_new(TEST_QUEUE_SIZE);
265 ASSERT_TRUE(queue != NULL);
266
267 // Test removing from a NULL queue
268 EXPECT_EQ(NULL,
269 fixed_queue_try_remove_from_queue(NULL, (void*)DUMMY_DATA_STRING));
270
271 // Test removing from an empty queue
272 EXPECT_EQ(NULL,
273 fixed_queue_try_remove_from_queue(queue, (void*)DUMMY_DATA_STRING));
274
275 // Test removing a queued string from a queue
276 fixed_queue_enqueue(queue, (void*)DUMMY_DATA_STRING1);
277 fixed_queue_enqueue(queue, (void*)DUMMY_DATA_STRING2);
278 fixed_queue_enqueue(queue, (void*)DUMMY_DATA_STRING3);
279 EXPECT_EQ((size_t)3, fixed_queue_length(queue));
280 EXPECT_EQ(DUMMY_DATA_STRING2, fixed_queue_try_remove_from_queue(
281 queue, (void*)DUMMY_DATA_STRING2));
282 EXPECT_EQ((size_t)2, fixed_queue_length(queue));
283 // Removing again should fail
284 EXPECT_EQ(NULL, fixed_queue_try_remove_from_queue(queue,
285 (void*)DUMMY_DATA_STRING2));
286
287 // Test removing a non-queued string from a queue
288 EXPECT_EQ(NULL,
289 fixed_queue_try_remove_from_queue(queue, (void*)DUMMY_DATA_STRING));
290
291 fixed_queue_free(queue, NULL);
292 }
293
TEST_F(FixedQueueTest,test_fixed_queue_get_enqueue_dequeue_fd)294 TEST_F(FixedQueueTest, test_fixed_queue_get_enqueue_dequeue_fd) {
295 fixed_queue_t* queue = fixed_queue_new(TEST_QUEUE_SIZE);
296 ASSERT_TRUE(queue != NULL);
297
298 // Test validity of enqueue and dequeue file descriptors
299 int enqueue_fd = fixed_queue_get_enqueue_fd(queue);
300 int dequeue_fd = fixed_queue_get_dequeue_fd(queue);
301 EXPECT_TRUE(enqueue_fd >= 0);
302 EXPECT_TRUE(dequeue_fd >= 0);
303 EXPECT_TRUE(enqueue_fd < FD_SETSIZE);
304 EXPECT_TRUE(dequeue_fd < FD_SETSIZE);
305
306 // Test the file descriptors of an empty queue
307 // Only the enqueue_fd should be readable
308 EXPECT_TRUE(is_fd_readable(enqueue_fd));
309 EXPECT_FALSE(is_fd_readable(dequeue_fd));
310
311 // Test the file descriptors of a non-empty queue
312 // Both the enqueue_fd and dequeue_fd should be readable
313 fixed_queue_enqueue(queue, (void*)DUMMY_DATA_STRING);
314 EXPECT_TRUE(is_fd_readable(enqueue_fd));
315 EXPECT_TRUE(is_fd_readable(dequeue_fd));
316 fixed_queue_dequeue(queue);
317
318 // Test the file descriptors of a full queue
319 // Only the dequeue_fd should be readable
320 for (size_t i = 0; i < TEST_QUEUE_SIZE; i++) {
321 EXPECT_TRUE(fixed_queue_try_enqueue(queue, (void*)DUMMY_DATA_STRING));
322 }
323 EXPECT_FALSE(is_fd_readable(enqueue_fd));
324 EXPECT_TRUE(is_fd_readable(dequeue_fd));
325
326 fixed_queue_free(queue, NULL);
327 }
328
TEST_F(FixedQueueTest,test_fixed_queue_register_dequeue)329 TEST_F(FixedQueueTest, test_fixed_queue_register_dequeue) {
330 fixed_queue_t* queue = fixed_queue_new(TEST_QUEUE_SIZE);
331 ASSERT_TRUE(queue != NULL);
332
333 received_message_future = future_new();
334 ASSERT_TRUE(received_message_future != NULL);
335
336 thread_t* worker_thread = thread_new("test_fixed_queue_worker_thread");
337 ASSERT_TRUE(worker_thread != NULL);
338
339 fixed_queue_register_dequeue(queue, thread_get_reactor(worker_thread),
340 fixed_queue_ready, NULL);
341
342 // Add a message to the queue, and expect to receive it
343 fixed_queue_enqueue(queue, (void*)DUMMY_DATA_STRING);
344 const char* msg = (const char*)future_await(received_message_future);
345 EXPECT_EQ(DUMMY_DATA_STRING, msg);
346
347 fixed_queue_unregister_dequeue(queue);
348 thread_free(worker_thread);
349 fixed_queue_free(queue, NULL);
350 }
351