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