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
13static const size_t TEST_QUEUE_SIZE = 10;
14static const char* DUMMY_DATA_STRING = "Dummy data string";
15static const char* DUMMY_DATA_STRING1 = "Dummy data string1";
16static const char* DUMMY_DATA_STRING2 = "Dummy data string2";
17static const char* DUMMY_DATA_STRING3 = "Dummy data string3";
18static future_t* received_message_future = NULL;
19
20static 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.
24static 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
40static 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
46static 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
52class FixedQueueTest : public AllocationTestHarness {};
53
54TEST_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
82TEST_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
124TEST_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
146TEST_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
168TEST_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
196TEST_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
233TEST_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
263TEST_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
294TEST_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
329TEST_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