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