blob: 56917efdf9df2e9a5bed6339e6c8f37dce8d9ea7 [file] [log] [blame]
#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);
}