blob: b005af105c9d4ea2315c3714e3e41f3bad28398c [file] [log] [blame]
/*
* Copyright (C) 2016 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <asm-generic/mman.h>
#include <cutils/ashmem.h>
#include <gtest/gtest.h>
#include <cstdlib>
#include <sstream>
#include "common/MessageQueue.h"
static const int queue_size = 1024;
typedef uint64_t mq_position_t;
class MQTests : public ::testing::Test {
protected:
virtual void TearDown() {
if (fmsgq) {
delete fmsgq;
}
}
virtual void SetUp() {
size_t eventQueueTotal = 4096;
int ashmemFd = ashmem_create_region("MessageQueue", eventQueueTotal);
ashmem_set_prot_region(ashmemFd, PROT_READ | PROT_WRITE);
ASSERT_TRUE(ashmemFd >= 0);
native_handle_t* mq_handle = native_handle_create(1, 0);
ASSERT_TRUE(mq_handle != nullptr);
std::vector<android::hardware::GrantorDescriptor> Grantors(
MINIMUM_GRANTOR_COUNT);
/*
* The native handle will contain the fds to be
* mapped.
*/
mq_handle->data[0] = ashmemFd;
/*
* Create Grantor Descriptors for read, write pointers and the data
* buffer.
*/
Grantors[android::hardware::READPTRPOS] = {0, 0, 0, sizeof(mq_position_t)};
Grantors[android::hardware::WRITEPTRPOS] = {0, 0, sizeof(mq_position_t),
sizeof(mq_position_t)};
Grantors[android::hardware::DATAPTRPOS] = {0, 0, 2 * sizeof(mq_position_t),
queue_size};
android::hardware::MQDescriptor mydesc(Grantors, mq_handle, 0, sizeof(uint8_t));
fmsgq = new android::hardware::MessageQueue<uint8_t>(mydesc);
ASSERT_TRUE(fmsgq != nullptr);
ASSERT_TRUE(fmsgq->isValid());
}
android::hardware::MessageQueue<uint8_t>* fmsgq;
};
/*
* Verify that a few bytes of data can be successfully written and read.
*/
TEST_F(MQTests, SmallInputTest1) {
const int data_len = 16;
int write_count = -1;
ASSERT_TRUE(data_len <= queue_size);
uint8_t data[data_len];
for (int i = 0; i < data_len; i++) {
data[i] = i & 0xFF;
}
ASSERT_TRUE(fmsgq->write(data, data_len));
uint8_t read_data[data_len] = {};
ASSERT_TRUE(fmsgq->read(read_data, data_len));
ASSERT_TRUE(memcmp(data, read_data, data_len) == 0);
}
/*
* Verify that read() returns false when trying to read from an empty queue.
*/
TEST_F(MQTests, ReadWhenEmpty) {
ASSERT_TRUE(fmsgq->availableToRead() == 0);
const int data_len = 2;
ASSERT_TRUE(data_len < queue_size);
uint8_t read_data[data_len];
ASSERT_FALSE(fmsgq->read(read_data, data_len));
}
/*
* Write the queue when full. Verify that subsequent writes fail.
* Verify that availableToWrite() returns 0 as expected.
*/
TEST_F(MQTests, WriteWhenFull) {
ASSERT_TRUE(fmsgq->availableToRead() == 0);
uint8_t* data = new uint8_t[queue_size];
for (int i = 0; i < queue_size; i++) {
data[i] = i & 0xFF;
}
ASSERT_TRUE(fmsgq->write(data, queue_size));
ASSERT_TRUE(fmsgq->availableToWrite() == 0);
ASSERT_FALSE(fmsgq->write(data, 1));
uint8_t* read_data = new uint8_t[queue_size]();
ASSERT_TRUE(fmsgq->read(read_data, queue_size));
ASSERT_TRUE(memcmp(data, read_data, queue_size) == 0);
delete[] data;
delete[] read_data;
}
/*
* Write a chunk of data equal to the queue size.
* Verify that the write is successful and the subsequent read
* returns the expected data.
*/
TEST_F(MQTests, LargeInputTest1) {
uint8_t* data = new uint8_t[queue_size];
for (int i = 0; i < queue_size; i++) {
data[i] = i & 0xFF;
}
ASSERT_TRUE(fmsgq->write(data, queue_size));
uint8_t* read_data = new uint8_t[queue_size]();
ASSERT_TRUE(fmsgq->read(read_data, queue_size));
ASSERT_TRUE(memcmp(data, read_data, queue_size) == 0);
delete[] data;
delete[] read_data;
}
/*
* Attempt to write a chunk of data larger than the queue size.
* Verify that it fails. Verify that a subsequent read fails and
* the queue is still empty.
*/
TEST_F(MQTests, LargeInputTest2) {
ASSERT_TRUE(fmsgq->availableToRead() == 0);
const int data_len = 4096;
ASSERT_TRUE(data_len > queue_size);
uint8_t* data = new uint8_t[data_len];
for (int i = 0; i < data_len; i++) {
data[i] = i & 0xFF;
}
ASSERT_FALSE(fmsgq->write(data, data_len));
uint8_t* read_data = new uint8_t[queue_size]();
ASSERT_FALSE(fmsgq->read(read_data, queue_size));
ASSERT_FALSE(memcmp(data, read_data, queue_size) == 0);
ASSERT_TRUE(fmsgq->availableToRead() == 0);
delete[] data;
delete[] read_data;
}
/*
* After the queue is full, try to write more data. Verify that
* the attempt returns false. Verify that the attempt did not
* affect the pre-existing data in the queue.
*/
TEST_F(MQTests, LargeInputTest3) {
uint8_t* data = new uint8_t[queue_size];
for (int i = 0; i < queue_size; i++) {
data[i] = i & 0xFF;
}
ASSERT_TRUE(fmsgq->write(data, queue_size));
ASSERT_FALSE(fmsgq->write(data, 1));
uint8_t* read_data = new uint8_t[queue_size];
ASSERT_TRUE(fmsgq->read(read_data, queue_size));
ASSERT_TRUE(memcmp(read_data, data, queue_size) == 0);
delete[] data;
delete[] read_data;
}
/*
* Verify that multiple reads one after the other return expected data.
*/
TEST_F(MQTests, MultipleRead) {
const int chunkSize = 100;
const int chunkNum = 5;
const size_t data_len = chunkSize * chunkNum;
ASSERT_TRUE(data_len <= queue_size);
uint8_t data[data_len];
for (unsigned int i = 0; i < data_len; i++) {
data[i] = i & 0xFF;
}
ASSERT_TRUE(fmsgq->write(data, data_len));
uint8_t read_data[data_len] = {};
for (unsigned int i = 0; i < chunkNum; i++) {
ASSERT_TRUE(fmsgq->read(read_data + i * chunkSize, chunkSize));
}
ASSERT_TRUE(memcmp(read_data, data, data_len) == 0);
}
/*
* Verify that multiple writes one after the other happens correctly.
*/
TEST_F(MQTests, MultipleWrite) {
const int chunkSize = 100;
const int chunkNum = 5;
const size_t data_len = chunkSize * chunkNum;
ASSERT_TRUE(data_len <= queue_size);
uint8_t data[data_len];
for (unsigned int i = 0; i < data_len; i++) {
data[i] = i & 0xFF;
}
for (unsigned int i = 0; i < chunkNum; i++) {
ASSERT_TRUE(fmsgq->write(data + i * chunkSize, chunkSize));
}
uint8_t read_data[data_len] = {};
ASSERT_TRUE(fmsgq->read(read_data, data_len));
ASSERT_TRUE(memcmp(read_data, data, data_len) == 0);
}
/*
* Write enough messages into the FMQ to fill half of it
* and read back the same.
* Write queue_size messages into the queue. This will cause a
* wrap around. Read and verify the data.
*/
TEST_F(MQTests, ReadWriteWrapAround) {
size_t numMessages = queue_size / 2;
uint8_t* data = new uint8_t[queue_size];
uint8_t* read_data = new uint8_t[queue_size]();
for (int i = 0; i < queue_size; i++) {
data[i] = i & 0xFF;
}
ASSERT_TRUE(fmsgq->write(data, numMessages));
ASSERT_TRUE(fmsgq->read(read_data, numMessages));
ASSERT_TRUE(fmsgq->write(data, queue_size));
ASSERT_TRUE(fmsgq->read(read_data, queue_size));
ASSERT_TRUE(memcmp(read_data, data, queue_size) == 0);
delete[] data;
delete[] read_data;
}