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