| #include <gtest/gtest.h> |
| |
| #include <climits> |
| |
| #include "AllocationTestHarness.h" |
| |
| #include "osi/include/allocator.h" |
| #include "osi/include/fixed_queue.h" |
| #include "osi/include/future.h" |
| #include "osi/include/osi.h" |
| #include "osi/include/thread.h" |
| |
| static const size_t TEST_QUEUE_SIZE = 10; |
| static const char* DUMMY_DATA_STRING = "Dummy data string"; |
| static const char* DUMMY_DATA_STRING1 = "Dummy data string1"; |
| static const char* DUMMY_DATA_STRING2 = "Dummy data string2"; |
| static const char* DUMMY_DATA_STRING3 = "Dummy data string3"; |
| static future_t* received_message_future = NULL; |
| |
| static int test_queue_entry_free_counter = 0; |
| |
| // Test whether a file descriptor |fd| is readable. |
| // Return true if the file descriptor is readable, otherwise false. |
| static bool is_fd_readable(int fd) { |
| fd_set rfds; |
| struct timeval tv; |
| |
| FD_ZERO(&rfds); |
| tv.tv_sec = 0; |
| tv.tv_usec = 0; |
| FD_SET(fd, &rfds); |
| // Only the enqueue_fd should be readable |
| int result = select(FD_SETSIZE, &rfds, NULL, NULL, &tv); |
| EXPECT_TRUE(result >= 0); |
| |
| return FD_ISSET(fd, &rfds); |
| } |
| |
| // Function for performing dequeue operations from the queue when is ready |
| static void fixed_queue_ready(fixed_queue_t* queue, UNUSED_ATTR void* context) { |
| void* msg = fixed_queue_try_dequeue(queue); |
| EXPECT_TRUE(msg != NULL); |
| future_ready(received_message_future, msg); |
| } |
| |
| static void test_queue_entry_free_cb(void* data) { |
| // Don't free the data, because we are testing only whether the callback |
| // is called. |
| test_queue_entry_free_counter++; |
| } |
| |
| class FixedQueueTest : public AllocationTestHarness {}; |
| |
| TEST_F(FixedQueueTest, test_fixed_queue_new_free) { |
| fixed_queue_t* queue; |
| |
| // Test a corner case: queue of size 0 |
| queue = fixed_queue_new(0); |
| EXPECT_TRUE(queue != NULL); |
| fixed_queue_free(queue, NULL); |
| |
| // Test a corner case: queue of size 1 |
| queue = fixed_queue_new(1); |
| EXPECT_TRUE(queue != NULL); |
| fixed_queue_free(queue, NULL); |
| |
| // Test a corner case: queue of maximum size |
| queue = fixed_queue_new((size_t)-1); |
| EXPECT_TRUE(queue != NULL); |
| fixed_queue_free(queue, NULL); |
| |
| // Test a queue of some size |
| queue = fixed_queue_new(TEST_QUEUE_SIZE); |
| EXPECT_TRUE(queue != NULL); |
| fixed_queue_free(queue, NULL); |
| |
| // Test free-ing a NULL queue |
| fixed_queue_free(NULL, NULL); |
| fixed_queue_free(NULL, osi_free); |
| } |
| |
| TEST_F(FixedQueueTest, test_fixed_queue_flush) { |
| fixed_queue_t* queue; |
| |
| // Test a corner case: queue of size 0 and no callback to free entries |
| queue = fixed_queue_new(0); |
| EXPECT_TRUE(queue != NULL); |
| fixed_queue_flush(queue, NULL); |
| EXPECT_TRUE(fixed_queue_is_empty(queue)); |
| fixed_queue_free(queue, osi_free); |
| |
| // Test a corner case: queue of size 0 and a callback to free entries |
| queue = fixed_queue_new(0); |
| EXPECT_TRUE(queue != NULL); |
| fixed_queue_flush(queue, osi_free); |
| EXPECT_TRUE(fixed_queue_is_empty(queue)); |
| fixed_queue_free(queue, osi_free); |
| |
| // Test a queue of some size and no callback to free entries |
| queue = fixed_queue_new(TEST_QUEUE_SIZE); |
| EXPECT_TRUE(queue != NULL); |
| fixed_queue_try_enqueue(queue, (void*)DUMMY_DATA_STRING1); |
| fixed_queue_try_enqueue(queue, (void*)DUMMY_DATA_STRING2); |
| fixed_queue_try_enqueue(queue, (void*)DUMMY_DATA_STRING3); |
| EXPECT_FALSE(fixed_queue_is_empty(queue)); |
| fixed_queue_flush(queue, NULL); |
| EXPECT_TRUE(fixed_queue_is_empty(queue)); |
| fixed_queue_free(queue, osi_free); |
| |
| // Test a queue of some size and a callback to free entries |
| test_queue_entry_free_counter = 0; |
| queue = fixed_queue_new(TEST_QUEUE_SIZE); |
| EXPECT_TRUE(queue != NULL); |
| fixed_queue_try_enqueue(queue, (void*)DUMMY_DATA_STRING1); |
| fixed_queue_try_enqueue(queue, (void*)DUMMY_DATA_STRING2); |
| fixed_queue_try_enqueue(queue, (void*)DUMMY_DATA_STRING3); |
| EXPECT_FALSE(fixed_queue_is_empty(queue)); |
| fixed_queue_flush(queue, test_queue_entry_free_cb); |
| EXPECT_TRUE(test_queue_entry_free_counter == 3); |
| EXPECT_TRUE(fixed_queue_is_empty(queue)); |
| fixed_queue_free(queue, osi_free); |
| } |
| |
| TEST_F(FixedQueueTest, test_fixed_queue_is_empty) { |
| fixed_queue_t* queue; |
| |
| // Test a NULL queue |
| EXPECT_TRUE(fixed_queue_is_empty(NULL)); |
| |
| // Test an empty queue |
| queue = fixed_queue_new(TEST_QUEUE_SIZE); |
| ASSERT_TRUE(queue != NULL); |
| EXPECT_TRUE(fixed_queue_is_empty(queue)); |
| |
| // Test a non-empty queue |
| fixed_queue_try_enqueue(queue, (void*)DUMMY_DATA_STRING); |
| EXPECT_FALSE(fixed_queue_is_empty(queue)); |
| |
| // Test an empty dequeued queue |
| ASSERT_EQ(DUMMY_DATA_STRING, fixed_queue_try_dequeue(queue)); |
| EXPECT_TRUE(fixed_queue_is_empty(queue)); |
| |
| fixed_queue_free(queue, NULL); |
| } |
| |
| TEST_F(FixedQueueTest, test_fixed_queue_length) { |
| fixed_queue_t* queue; |
| |
| // Test a NULL queue |
| EXPECT_EQ((size_t)0, fixed_queue_length(NULL)); |
| |
| // Test an empty queue |
| queue = fixed_queue_new(TEST_QUEUE_SIZE); |
| ASSERT_TRUE(queue != NULL); |
| EXPECT_EQ((size_t)0, fixed_queue_length(queue)); |
| |
| // Test a non-empty queue |
| fixed_queue_try_enqueue(queue, (void*)DUMMY_DATA_STRING); |
| EXPECT_EQ((size_t)1, fixed_queue_length(queue)); |
| |
| // Test an empty dequeued queue |
| ASSERT_EQ(DUMMY_DATA_STRING, fixed_queue_try_dequeue(queue)); |
| EXPECT_EQ((size_t)0, fixed_queue_length(queue)); |
| |
| fixed_queue_free(queue, NULL); |
| } |
| |
| TEST_F(FixedQueueTest, test_fixed_queue_capacity) { |
| fixed_queue_t* queue; |
| |
| // Test a corner case: queue of size 0 |
| queue = fixed_queue_new(0); |
| ASSERT_TRUE(queue != NULL); |
| EXPECT_EQ((size_t)0, fixed_queue_capacity(queue)); |
| fixed_queue_free(queue, NULL); |
| |
| // Test a corner case: queue of size 1 |
| queue = fixed_queue_new(1); |
| ASSERT_TRUE(queue != NULL); |
| EXPECT_EQ((size_t)1, fixed_queue_capacity(queue)); |
| fixed_queue_free(queue, NULL); |
| |
| // Test a corner case: queue of maximum size |
| queue = fixed_queue_new((size_t)-1); |
| ASSERT_TRUE(queue != NULL); |
| EXPECT_EQ((size_t)-1, fixed_queue_capacity(queue)); |
| fixed_queue_free(queue, NULL); |
| |
| // Test a queue of some size |
| queue = fixed_queue_new(TEST_QUEUE_SIZE); |
| ASSERT_TRUE(queue != NULL); |
| EXPECT_EQ(TEST_QUEUE_SIZE, fixed_queue_capacity(queue)); |
| fixed_queue_free(queue, NULL); |
| } |
| |
| TEST_F(FixedQueueTest, test_fixed_queue_enqueue_dequeue) { |
| fixed_queue_t* queue = fixed_queue_new(TEST_QUEUE_SIZE); |
| ASSERT_TRUE(queue != NULL); |
| |
| // Test blocking enqueue and blocking dequeue |
| fixed_queue_enqueue(queue, (void*)DUMMY_DATA_STRING); |
| EXPECT_EQ((size_t)1, fixed_queue_length(queue)); |
| EXPECT_EQ(DUMMY_DATA_STRING, fixed_queue_dequeue(queue)); |
| EXPECT_EQ((size_t)0, fixed_queue_length(queue)); |
| |
| // Test non-blocking enqueue and non-blocking dequeue |
| EXPECT_TRUE(fixed_queue_try_enqueue(queue, (void*)DUMMY_DATA_STRING)); |
| EXPECT_EQ((size_t)1, fixed_queue_length(queue)); |
| EXPECT_EQ(DUMMY_DATA_STRING, fixed_queue_try_dequeue(queue)); |
| EXPECT_EQ((size_t)0, fixed_queue_length(queue)); |
| |
| // Test non-blocking enqueue beyond queue capacity |
| for (size_t i = 0; i < TEST_QUEUE_SIZE; i++) { |
| EXPECT_TRUE(fixed_queue_try_enqueue(queue, (void*)DUMMY_DATA_STRING)); |
| } |
| // The next enqueue operation is beyond the queue capacity, so it should fail |
| EXPECT_FALSE(fixed_queue_try_enqueue(queue, (void*)DUMMY_DATA_STRING)); |
| |
| // Test non-blocking dequeue from a queue that is full to max capacity |
| for (size_t i = 0; i < TEST_QUEUE_SIZE; i++) { |
| EXPECT_EQ(DUMMY_DATA_STRING, fixed_queue_try_dequeue(queue)); |
| } |
| |
| // Test non-blocking dequeue from an empty queue |
| EXPECT_EQ(NULL, fixed_queue_try_dequeue(queue)); |
| |
| // Test non-blocking dequeue from a NULL queue |
| EXPECT_EQ(NULL, fixed_queue_try_dequeue(NULL)); |
| |
| fixed_queue_free(queue, NULL); |
| } |
| |
| TEST_F(FixedQueueTest, test_fixed_queue_try_peek_first_last) { |
| fixed_queue_t* queue = fixed_queue_new(TEST_QUEUE_SIZE); |
| ASSERT_TRUE(queue != NULL); |
| |
| // Test peek first/last from a NULL queue |
| EXPECT_EQ(NULL, fixed_queue_try_peek_first(NULL)); |
| EXPECT_EQ(NULL, fixed_queue_try_peek_last(NULL)); |
| |
| // Test peek first/last from an empty queue |
| EXPECT_EQ(NULL, fixed_queue_try_peek_first(queue)); |
| EXPECT_EQ(NULL, fixed_queue_try_peek_last(queue)); |
| |
| // Test peek first/last from a queue with one element |
| fixed_queue_enqueue(queue, (void*)DUMMY_DATA_STRING1); |
| EXPECT_EQ(DUMMY_DATA_STRING1, fixed_queue_try_peek_first(queue)); |
| EXPECT_EQ(DUMMY_DATA_STRING1, fixed_queue_try_peek_last(queue)); |
| |
| // Test peek first/last from a queue with two elements |
| fixed_queue_enqueue(queue, (void*)DUMMY_DATA_STRING2); |
| EXPECT_EQ(DUMMY_DATA_STRING1, fixed_queue_try_peek_first(queue)); |
| EXPECT_EQ(DUMMY_DATA_STRING2, fixed_queue_try_peek_last(queue)); |
| |
| // Test peek first/last from a queue with three elements |
| fixed_queue_enqueue(queue, (void*)DUMMY_DATA_STRING3); |
| EXPECT_EQ(DUMMY_DATA_STRING1, fixed_queue_try_peek_first(queue)); |
| EXPECT_EQ(DUMMY_DATA_STRING3, fixed_queue_try_peek_last(queue)); |
| |
| fixed_queue_free(queue, NULL); |
| } |
| |
| TEST_F(FixedQueueTest, test_fixed_queue_try_remove_from_queue) { |
| fixed_queue_t* queue = fixed_queue_new(TEST_QUEUE_SIZE); |
| ASSERT_TRUE(queue != NULL); |
| |
| // Test removing from a NULL queue |
| EXPECT_EQ(NULL, |
| fixed_queue_try_remove_from_queue(NULL, (void*)DUMMY_DATA_STRING)); |
| |
| // Test removing from an empty queue |
| EXPECT_EQ(NULL, |
| fixed_queue_try_remove_from_queue(queue, (void*)DUMMY_DATA_STRING)); |
| |
| // Test removing a queued string from a queue |
| fixed_queue_enqueue(queue, (void*)DUMMY_DATA_STRING1); |
| fixed_queue_enqueue(queue, (void*)DUMMY_DATA_STRING2); |
| fixed_queue_enqueue(queue, (void*)DUMMY_DATA_STRING3); |
| EXPECT_EQ((size_t)3, fixed_queue_length(queue)); |
| EXPECT_EQ(DUMMY_DATA_STRING2, fixed_queue_try_remove_from_queue( |
| queue, (void*)DUMMY_DATA_STRING2)); |
| EXPECT_EQ((size_t)2, fixed_queue_length(queue)); |
| // Removing again should fail |
| EXPECT_EQ(NULL, fixed_queue_try_remove_from_queue(queue, |
| (void*)DUMMY_DATA_STRING2)); |
| |
| // Test removing a non-queued string from a queue |
| EXPECT_EQ(NULL, |
| fixed_queue_try_remove_from_queue(queue, (void*)DUMMY_DATA_STRING)); |
| |
| fixed_queue_free(queue, NULL); |
| } |
| |
| TEST_F(FixedQueueTest, test_fixed_queue_get_enqueue_dequeue_fd) { |
| fixed_queue_t* queue = fixed_queue_new(TEST_QUEUE_SIZE); |
| ASSERT_TRUE(queue != NULL); |
| |
| // Test validity of enqueue and dequeue file descriptors |
| int enqueue_fd = fixed_queue_get_enqueue_fd(queue); |
| int dequeue_fd = fixed_queue_get_dequeue_fd(queue); |
| EXPECT_TRUE(enqueue_fd >= 0); |
| EXPECT_TRUE(dequeue_fd >= 0); |
| EXPECT_TRUE(enqueue_fd < FD_SETSIZE); |
| EXPECT_TRUE(dequeue_fd < FD_SETSIZE); |
| |
| // Test the file descriptors of an empty queue |
| // Only the enqueue_fd should be readable |
| EXPECT_TRUE(is_fd_readable(enqueue_fd)); |
| EXPECT_FALSE(is_fd_readable(dequeue_fd)); |
| |
| // Test the file descriptors of a non-empty queue |
| // Both the enqueue_fd and dequeue_fd should be readable |
| fixed_queue_enqueue(queue, (void*)DUMMY_DATA_STRING); |
| EXPECT_TRUE(is_fd_readable(enqueue_fd)); |
| EXPECT_TRUE(is_fd_readable(dequeue_fd)); |
| fixed_queue_dequeue(queue); |
| |
| // Test the file descriptors of a full queue |
| // Only the dequeue_fd should be readable |
| for (size_t i = 0; i < TEST_QUEUE_SIZE; i++) { |
| EXPECT_TRUE(fixed_queue_try_enqueue(queue, (void*)DUMMY_DATA_STRING)); |
| } |
| EXPECT_FALSE(is_fd_readable(enqueue_fd)); |
| EXPECT_TRUE(is_fd_readable(dequeue_fd)); |
| |
| fixed_queue_free(queue, NULL); |
| } |
| |
| TEST_F(FixedQueueTest, test_fixed_queue_register_dequeue) { |
| fixed_queue_t* queue = fixed_queue_new(TEST_QUEUE_SIZE); |
| ASSERT_TRUE(queue != NULL); |
| |
| received_message_future = future_new(); |
| ASSERT_TRUE(received_message_future != NULL); |
| |
| thread_t* worker_thread = thread_new("test_fixed_queue_worker_thread"); |
| ASSERT_TRUE(worker_thread != NULL); |
| |
| fixed_queue_register_dequeue(queue, thread_get_reactor(worker_thread), |
| fixed_queue_ready, NULL); |
| |
| // Add a message to the queue, and expect to receive it |
| fixed_queue_enqueue(queue, (void*)DUMMY_DATA_STRING); |
| const char* msg = (const char*)future_await(received_message_future); |
| EXPECT_EQ(DUMMY_DATA_STRING, msg); |
| |
| fixed_queue_unregister_dequeue(queue); |
| thread_free(worker_thread); |
| fixed_queue_free(queue, NULL); |
| } |