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