You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
350 lines
12 KiB
350 lines
12 KiB
#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); |
|
}
|
|
|