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