1 #include <gtest/gtest.h>
2
3 #include <climits>
4
5 #include "AllocationTestHarness.h"
6
7 extern "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
15 static const size_t TEST_QUEUE_SIZE = 10;
16 static const char *DUMMY_DATA_STRING = "Dummy data string";
17 static const char *DUMMY_DATA_STRING1 = "Dummy data string1";
18 static const char *DUMMY_DATA_STRING2 = "Dummy data string2";
19 static const char *DUMMY_DATA_STRING3 = "Dummy data string3";
20 static 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.
is_fd_readable(int fd)24 static 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
41 static void
fixed_queue_ready(fixed_queue_t * queue,UNUSED_ATTR void * context)42 fixed_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
49 class FixedQueueTest : public AllocationTestHarness {};
50
TEST_F(FixedQueueTest,test_fixed_queue_new_free)51 TEST_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
TEST_F(FixedQueueTest,test_fixed_queue_is_empty)79 TEST_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
TEST_F(FixedQueueTest,test_fixed_queue_length)101 TEST_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
TEST_F(FixedQueueTest,test_fixed_queue_capacity)123 TEST_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
TEST_F(FixedQueueTest,test_fixed_queue_enqueue_dequeue)151 TEST_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
TEST_F(FixedQueueTest,test_fixed_queue_try_peek_first_last)188 TEST_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
TEST_F(FixedQueueTest,test_fixed_queue_try_remove_from_queue)218 TEST_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
TEST_F(FixedQueueTest,test_fixed_queue_get_enqueue_dequeue_fd)249 TEST_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
TEST_F(FixedQueueTest,test_fixed_queue_register_dequeue)284 TEST_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