/*
* 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 <gtest/gtest.h>
#ifndef GTEST_IS_THREADSAFE
#error "GTest did not detect pthread library."
#endif
#include <android/hardware/tests/msgq/1.0/ITestMsgQ.h>
#include <fmq/EventFlag.h>
#include <fmq/MessageQueue.h>
#include <hidl/ServiceManagement.h>
// libutils:
using android::OK;
using android::sp;
using android::status_t;
// generated
using android::hardware::tests::msgq::V1_0::ITestMsgQ;
// libhidl
using android::hardware::kSynchronizedReadWrite;
using android::hardware::kUnsynchronizedWrite;
using android::hardware::MessageQueue;
using android::hardware::MQDescriptorSync;
using android::hardware::MQDescriptorUnsync;
using android::hardware::details::waitForHwService;
typedef MessageQueue<uint16_t, kSynchronizedReadWrite> MessageQueueSync;
typedef MessageQueue<uint16_t, kUnsynchronizedWrite> MessageQueueUnsync;
static sp<ITestMsgQ> waitGetTestService() {
// waitForHwService is required because ITestMsgQ is not in manifest.xml.
// "Real" HALs shouldn't be doing this.
waitForHwService(ITestMsgQ::descriptor, "default");
return ITestMsgQ::getService();
}
class UnsynchronizedWriteClientMultiProcess : public ::testing::Test {
protected:
void getQueue(MessageQueueUnsync** fmq, sp<ITestMsgQ>* service, bool setupQueue) {
*service = waitGetTestService();
*fmq = nullptr;
if (*service == nullptr) return;
if (!(*service)->isRemote()) return;
(*service)->getFmqUnsyncWrite(setupQueue,
[fmq](bool ret, const MQDescriptorUnsync<uint16_t>& in) {
ASSERT_TRUE(ret);
*fmq = new (std::nothrow) MessageQueueUnsync(in);
});
}
};
class SynchronizedReadWriteClient : public ::testing::Test {
protected:
virtual void TearDown() {
delete mQueue;
}
virtual void SetUp() {
static constexpr size_t kNumElementsInQueue = 1024;
mService = waitGetTestService();
ASSERT_NE(mService, nullptr);
ASSERT_TRUE(mService->isRemote());
// create a queue on the client side
mQueue = new (std::nothrow)
MessageQueueSync(kNumElementsInQueue, true /* configure event flag word */);
ASSERT_NE(nullptr, mQueue);
ASSERT_TRUE(mQueue->isValid());
mNumMessagesMax = mQueue->getQuantumCount();
// tell server to set up the queue on its end
ASSERT_TRUE(mService->configureFmqSyncReadWrite(*mQueue->getDesc()));
}
sp<ITestMsgQ> mService;
MessageQueueSync* mQueue = nullptr;
size_t mNumMessagesMax = 0;
};
class UnsynchronizedWriteClient : public ::testing::Test {
protected:
virtual void TearDown() {
delete mQueue;
}
virtual void SetUp() {
mService = waitGetTestService();
ASSERT_NE(mService, nullptr);
ASSERT_TRUE(mService->isRemote());
mService->getFmqUnsyncWrite(true /* configureFmq */,
[this](bool ret, const MQDescriptorUnsync<uint16_t>& in) {
ASSERT_TRUE(ret);
mQueue = new (std::nothrow) MessageQueueUnsync(in);
});
ASSERT_NE(nullptr, mQueue);
ASSERT_TRUE(mQueue->isValid());
mNumMessagesMax = mQueue->getQuantumCount();
}
sp<ITestMsgQ> mService;
MessageQueueUnsync* mQueue = nullptr;
size_t mNumMessagesMax = 0;
};
/*
* Utility function to verify data read from the fast message queue.
*/
bool verifyData(uint16_t* data, size_t count) {
for (size_t i = 0; i < count; i++) {
if (data[i] != i) return false;
}
return true;
}
/*
* Utility function to initialize data to be written to the FMQ
*/
inline void initData(uint16_t* data, size_t count) {
for (size_t i = 0; i < count; i++) {
data[i] = i;
}
}
/*
* Verify that for an unsynchronized flavor of FMQ, multiple readers
* can recover from a write overflow condition.
*/
TEST_F(UnsynchronizedWriteClientMultiProcess, MultipleReadersAfterOverflow) {
const size_t dataLen = 16;
pid_t pid;
/* creating first reader process */
if ((pid = fork()) == 0) {
sp<ITestMsgQ> testService;
MessageQueueUnsync* queue = nullptr;
getQueue(&queue, &testService, true /* setupQueue */);
ASSERT_NE(testService, nullptr);
ASSERT_TRUE(testService->isRemote());
ASSERT_NE(queue, nullptr);
ASSERT_TRUE(queue->isValid());
size_t numMessagesMax = queue->getQuantumCount();
// The following two writes will cause a write overflow.
auto ret = testService->requestWriteFmqUnsync(numMessagesMax);
ASSERT_TRUE(ret.isOk());
ASSERT_TRUE(ret);
ret = testService->requestWriteFmqUnsync(1);
ASSERT_TRUE(ret.isOk());
ASSERT_TRUE(ret);
// The following read should fail due to the overflow.
std::vector<uint16_t> readData(numMessagesMax);
ASSERT_FALSE(queue->read(&readData[0], numMessagesMax));
/*
* Request another write to verify that the reader can recover from the
* overflow condition.
*/
ASSERT_LT(dataLen, numMessagesMax);
ret = testService->requestWriteFmqUnsync(dataLen);
ASSERT_TRUE(ret.isOk());
ASSERT_TRUE(ret);
// Verify that the read is successful.
ASSERT_TRUE(queue->read(&readData[0], dataLen));
ASSERT_TRUE(verifyData(&readData[0], dataLen));
delete queue;
exit(0);
}
ASSERT_GT(pid, 0 /* parent should see PID greater than 0 for a good fork */);
int status;
// wait for the first reader process to exit.
ASSERT_EQ(pid, waitpid(pid, &status, 0 /* options */));
// creating second reader process.
if ((pid = fork()) == 0) {
sp<ITestMsgQ> testService;
MessageQueueUnsync* queue = nullptr;
getQueue(&queue, &testService, false /* setupQueue */);
ASSERT_NE(testService, nullptr);
ASSERT_TRUE(testService->isRemote());
ASSERT_NE(queue, nullptr);
ASSERT_TRUE(queue->isValid());
// This read should fail due to the write overflow.
std::vector<uint16_t> readData(dataLen);
ASSERT_FALSE(queue->read(&readData[0], dataLen));
/*
* Request another write to verify that the process that recover from
* the overflow condition.
*/
auto ret = testService->requestWriteFmqUnsync(dataLen);
ASSERT_TRUE(ret.isOk());
ASSERT_TRUE(ret);
// verify that the read is successful.
ASSERT_TRUE(queue->read(&readData[0], dataLen));
ASSERT_TRUE(verifyData(&readData[0], dataLen));
delete queue;
exit(0);
}
ASSERT_GT(pid, 0 /* parent should see PID greater than 0 for a good fork */);
ASSERT_EQ(pid, waitpid(pid, &status, 0 /* options */));
}
/*
* Test that basic blocking works using readBlocking()/writeBlocking() APIs
* using the EventFlag object owned by FMQ.
*/
TEST_F(SynchronizedReadWriteClient, BlockingReadWrite1) {
const size_t dataLen = 64;
uint16_t data[dataLen] = {0};
/*
* Request service to perform a blocking read. This call is oneway and will
* return immediately.
*/
mService->requestBlockingRead(dataLen);
bool ret = mQueue->writeBlocking(data,
dataLen,
static_cast<uint32_t>(ITestMsgQ::EventFlagBits::FMQ_NOT_FULL),
static_cast<uint32_t>(ITestMsgQ::EventFlagBits::FMQ_NOT_EMPTY),
5000000000 /* timeOutNanos */);
ASSERT_TRUE(ret);
ret = mQueue->writeBlocking(data, mNumMessagesMax,
static_cast<uint32_t>(ITestMsgQ::EventFlagBits::FMQ_NOT_FULL),
static_cast<uint32_t>(ITestMsgQ::EventFlagBits::FMQ_NOT_EMPTY),
5000000000 /* timeOutNanos */);
ASSERT_TRUE(ret);
}
/*
* Test that basic blocking works using readBlocking()/writeBlocking() APIs
* using the EventFlag object owned by FMQ and using the default EventFlag
* notification bit mask.
*/
TEST_F(SynchronizedReadWriteClient, BlockingReadWrite2) {
const size_t dataLen = 64;
std::vector<uint16_t> data(mNumMessagesMax);
/*
* Request service to perform a blocking read using default EventFlag
* notification bit mask. This call is oneway and will
* return immediately.
*/
mService->requestBlockingReadDefaultEventFlagBits(dataLen);
/* Cause a context switch to allow service to block */
sched_yield();
bool ret = mQueue->writeBlocking(&data[0],
dataLen);
ASSERT_TRUE(ret);
/*
* If the blocking read was successful, another write of size
* mNumMessagesMax will succeed.
*/
ret = mQueue->writeBlocking(&data[0], mNumMessagesMax, 5000000000 /* timeOutNanos */);
ASSERT_TRUE(ret);
}
/*
* Test that repeated blocking reads and writes work using readBlocking()/writeBlocking() APIs
* using the EventFlag object owned by FMQ.
* Each write operation writes the same amount of data as a single read
* operation.
*/
TEST_F(SynchronizedReadWriteClient, BlockingReadWriteRepeat1) {
const size_t dataLen = 64;
uint16_t data[dataLen] = {0};
bool ret = false;
/*
* Request service to perform a blocking read. This call is oneway and will
* return immediately.
*/
const size_t writeCount = 1024;
mService->requestBlockingReadRepeat(dataLen, writeCount);
for (size_t i = 0; i < writeCount; i++) {
ret = mQueue->writeBlocking(data, dataLen,
static_cast<uint32_t>(ITestMsgQ::EventFlagBits::FMQ_NOT_FULL),
static_cast<uint32_t>(ITestMsgQ::EventFlagBits::FMQ_NOT_EMPTY),
5000000000 /* timeOutNanos */);
ASSERT_TRUE(ret);
}
ret = mQueue->writeBlocking(data, mNumMessagesMax,
static_cast<uint32_t>(ITestMsgQ::EventFlagBits::FMQ_NOT_FULL),
static_cast<uint32_t>(ITestMsgQ::EventFlagBits::FMQ_NOT_EMPTY),
5000000000 /* timeOutNanos */);
ASSERT_TRUE(ret);
}
/*
* Test that repeated blocking reads and writes work using readBlocking()/writeBlocking() APIs
* using the EventFlag object owned by FMQ. Each read operation reads twice the
* amount of data as a single write.
*
*/
TEST_F(SynchronizedReadWriteClient, BlockingReadWriteRepeat2) {
const size_t dataLen = 64;
uint16_t data[dataLen] = {0};
bool ret = false;
/*
* Request service to perform a blocking read. This call is oneway and will
* return immediately.
*/
const size_t writeCount = 1024;
mService->requestBlockingReadRepeat(dataLen*2, writeCount/2);
for (size_t i = 0; i < writeCount; i++) {
ret = mQueue->writeBlocking(data, dataLen,
static_cast<uint32_t>(ITestMsgQ::EventFlagBits::FMQ_NOT_FULL),
static_cast<uint32_t>(ITestMsgQ::EventFlagBits::FMQ_NOT_EMPTY),
5000000000 /* timeOutNanos */);
ASSERT_TRUE(ret);
}
ret = mQueue->writeBlocking(data, mNumMessagesMax,
static_cast<uint32_t>(ITestMsgQ::EventFlagBits::FMQ_NOT_FULL),
static_cast<uint32_t>(ITestMsgQ::EventFlagBits::FMQ_NOT_EMPTY),
5000000000 /* timeOutNanos */);
ASSERT_TRUE(ret);
}
/*
* Test that basic blocking works using readBlocking()/writeBlocking() APIs
* using the EventFlag object owned by FMQ. Each write operation writes twice
* the amount of data as a single read.
*/
TEST_F(SynchronizedReadWriteClient, BlockingReadWriteRepeat3) {
const size_t dataLen = 64;
uint16_t data[dataLen] = {0};
bool ret = false;
/*
* Request service to perform a blocking read. This call is oneway and will
* return immediately.
*/
size_t writeCount = 1024;
mService->requestBlockingReadRepeat(dataLen/2, writeCount*2);
for (size_t i = 0; i < writeCount; i++) {
ret = mQueue->writeBlocking(data, dataLen,
static_cast<uint32_t>(ITestMsgQ::EventFlagBits::FMQ_NOT_FULL),
static_cast<uint32_t>(ITestMsgQ::EventFlagBits::FMQ_NOT_EMPTY),
5000000000 /* timeOutNanos */);
ASSERT_TRUE(ret);
}
ret = mQueue->writeBlocking(data, mNumMessagesMax,
static_cast<uint32_t>(ITestMsgQ::EventFlagBits::FMQ_NOT_FULL),
static_cast<uint32_t>(ITestMsgQ::EventFlagBits::FMQ_NOT_EMPTY),
5000000000 /* timeOutNanos */);
ASSERT_TRUE(ret);
}
/*
* Test that writeBlocking()/readBlocking() APIs do not block on
* attempts to write/read 0 messages and return true.
*/
TEST_F(SynchronizedReadWriteClient, BlockingReadWriteZeroMessages) {
uint16_t data = 0;
/*
* Trigger a blocking write for zero messages with no timeout.
*/
bool ret = mQueue->writeBlocking(
&data,
0,
static_cast<uint32_t>(ITestMsgQ::EventFlagBits::FMQ_NOT_FULL),
static_cast<uint32_t>(ITestMsgQ::EventFlagBits::FMQ_NOT_EMPTY));
ASSERT_TRUE(ret);
/*
* Trigger a blocking read for zero messages with no timeout.
*/
ret = mQueue->readBlocking(&data,
0,
static_cast<uint32_t>(ITestMsgQ::EventFlagBits::FMQ_NOT_FULL),
static_cast<uint32_t>(ITestMsgQ::EventFlagBits::FMQ_NOT_EMPTY));
ASSERT_TRUE(ret);
}
/*
* Request mService to write a small number of messages
* to the FMQ. Read and verify data.
*/
TEST_F(SynchronizedReadWriteClient, SmallInputReaderTest1) {
const size_t dataLen = 16;
ASSERT_LE(dataLen, mNumMessagesMax);
bool ret = mService->requestWriteFmqSync(dataLen);
ASSERT_TRUE(ret);
uint16_t readData[dataLen] = {};
ASSERT_TRUE(mQueue->read(readData, dataLen));
ASSERT_TRUE(verifyData(readData, dataLen));
}
/*
* Request mService to write a small number of messages
* to the FMQ. Read and verify each message using
* beginRead/Commit read APIs.
*/
TEST_F(SynchronizedReadWriteClient, SmallInputReaderTest2) {
const size_t dataLen = 16;
ASSERT_LE(dataLen, mNumMessagesMax);
auto ret = mService->requestWriteFmqSync(dataLen);
ASSERT_TRUE(ret.isOk());
ASSERT_TRUE(ret);
MessageQueueSync::MemTransaction tx;
ASSERT_TRUE(mQueue->beginRead(dataLen, &tx));
auto first = tx.getFirstRegion();
auto second = tx.getSecondRegion();
size_t firstRegionLength = first.getLength();
for (size_t i = 0; i < dataLen; i++) {
if (i < firstRegionLength) {
ASSERT_EQ(i, *(first.getAddress() + i));
} else {
ASSERT_EQ(i, *(second.getAddress() + i - firstRegionLength));
}
}
ASSERT_TRUE(mQueue->commitRead(dataLen));
}
/*
* Write a small number of messages to FMQ. Request
* mService to read and verify that the write was succesful.
*/
TEST_F(SynchronizedReadWriteClient, SmallInputWriterTest1) {
const size_t dataLen = 16;
ASSERT_LE(dataLen, mNumMessagesMax);
size_t originalCount = mQueue->availableToWrite();
uint16_t data[dataLen];
initData(data, dataLen);
ASSERT_TRUE(mQueue->write(data, dataLen));
bool ret = mService->requestReadFmqSync(dataLen);
ASSERT_TRUE(ret);
size_t availableCount = mQueue->availableToWrite();
ASSERT_EQ(originalCount, availableCount);
}
/*
* Write a small number of messages to FMQ using the beginWrite()/CommitWrite()
* APIs. Request mService to read and verify that the write was succesful.
*/
TEST_F(SynchronizedReadWriteClient, SmallInputWriterTest2) {
const size_t dataLen = 16;
ASSERT_LE(dataLen, mNumMessagesMax);
size_t originalCount = mQueue->availableToWrite();
uint16_t data[dataLen];
initData(data, dataLen);
MessageQueueSync::MemTransaction tx;
ASSERT_TRUE(mQueue->beginWrite(dataLen, &tx));
auto first = tx.getFirstRegion();
auto second = tx.getSecondRegion();
size_t firstRegionLength = first.getLength();
uint16_t* firstBaseAddress = first.getAddress();
uint16_t* secondBaseAddress = second.getAddress();
for (size_t i = 0; i < dataLen; i++) {
if (i < firstRegionLength) {
*(firstBaseAddress + i) = i;
} else {
*(secondBaseAddress + i - firstRegionLength) = i;
}
}
ASSERT_TRUE(mQueue->commitWrite(dataLen));
auto ret = mService->requestReadFmqSync(dataLen);
ASSERT_TRUE(ret.isOk());
ASSERT_TRUE(ret);
size_t availableCount = mQueue->availableToWrite();
ASSERT_EQ(originalCount, availableCount);
}
/*
* Verify that the FMQ is empty and read fails when it is empty.
*/
TEST_F(SynchronizedReadWriteClient, ReadWhenEmpty) {
ASSERT_EQ(0UL, mQueue->availableToRead());
const size_t numMessages = 2;
ASSERT_LE(numMessages, mNumMessagesMax);
uint16_t readData[numMessages];
ASSERT_FALSE(mQueue->read(readData, numMessages));
}
/*
* Verify FMQ is empty.
* Write enough messages to fill it.
* Verify availableToWrite() method returns is zero.
* Try writing another message and verify that
* the attempted write was unsuccesful. Request mService
* to read and verify the messages in the FMQ.
*/
TEST_F(SynchronizedReadWriteClient, WriteWhenFull) {
std::vector<uint16_t> data(mNumMessagesMax);
initData(&data[0], mNumMessagesMax);
ASSERT_TRUE(mQueue->write(&data[0], mNumMessagesMax));
ASSERT_EQ(0UL, mQueue->availableToWrite());
ASSERT_FALSE(mQueue->write(&data[0], 1));
bool ret = mService->requestReadFmqSync(mNumMessagesMax);
ASSERT_TRUE(ret);
}
/*
* Verify FMQ is empty.
* Request mService to write data equal to queue size.
* Read and verify data in mQueue.
*/
TEST_F(SynchronizedReadWriteClient, LargeInputTest1) {
bool ret = mService->requestWriteFmqSync(mNumMessagesMax);
ASSERT_TRUE(ret);
std::vector<uint16_t> readData(mNumMessagesMax);
ASSERT_TRUE(mQueue->read(&readData[0], mNumMessagesMax));
ASSERT_TRUE(verifyData(&readData[0], mNumMessagesMax));
}
/*
* Request mService to write more than maximum number of messages to the FMQ.
* Verify that the write fails. Verify that availableToRead() method
* still returns 0 and verify that attempt to read fails.
*/
TEST_F(SynchronizedReadWriteClient, LargeInputTest2) {
ASSERT_EQ(0UL, mQueue->availableToRead());
const size_t numMessages = 2048;
ASSERT_GT(numMessages, mNumMessagesMax);
bool ret = mService->requestWriteFmqSync(numMessages);
ASSERT_FALSE(ret);
uint16_t readData;
ASSERT_EQ(0UL, mQueue->availableToRead());
ASSERT_FALSE(mQueue->read(&readData, 1));
}
/*
* Write until FMQ is full.
* Verify that the number of messages available to write
* is equal to mNumMessagesMax.
* Verify that another write attempt fails.
* Request mService to read. Verify read count.
*/
TEST_F(SynchronizedReadWriteClient, LargeInputTest3) {
std::vector<uint16_t> data(mNumMessagesMax);
initData(&data[0], mNumMessagesMax);
ASSERT_TRUE(mQueue->write(&data[0], mNumMessagesMax));
ASSERT_EQ(0UL, mQueue->availableToWrite());
ASSERT_FALSE(mQueue->write(&data[0], 1));
bool ret = mService->requestReadFmqSync(mNumMessagesMax);
ASSERT_TRUE(ret);
}
/*
* Confirm that the FMQ is empty. Request mService to write to FMQ.
* Do multiple reads to empty FMQ and verify data.
*/
TEST_F(SynchronizedReadWriteClient, MultipleRead) {
const size_t chunkSize = 100;
const size_t chunkNum = 5;
const size_t numMessages = chunkSize * chunkNum;
ASSERT_LE(numMessages, mNumMessagesMax);
size_t availableToRead = mQueue->availableToRead();
size_t expectedCount = 0;
ASSERT_EQ(expectedCount, availableToRead);
bool ret = mService->requestWriteFmqSync(numMessages);
ASSERT_TRUE(ret);
uint16_t readData[numMessages] = {};
for (size_t i = 0; i < chunkNum; i++) {
ASSERT_TRUE(mQueue->read(readData + i * chunkSize, chunkSize));
}
ASSERT_TRUE(verifyData(readData, numMessages));
}
/*
* Write to FMQ in bursts.
* Request mService to read data. Verify the read was successful.
*/
TEST_F(SynchronizedReadWriteClient, MultipleWrite) {
const size_t chunkSize = 100;
const size_t chunkNum = 5;
const size_t numMessages = chunkSize * chunkNum;
ASSERT_LE(numMessages, mNumMessagesMax);
uint16_t data[numMessages];
initData(&data[0], numMessages);
for (size_t i = 0; i < chunkNum; i++) {
ASSERT_TRUE(mQueue->write(data + i * chunkSize, chunkSize));
}
bool ret = mService->requestReadFmqSync(numMessages);
ASSERT_TRUE(ret);
}
/*
* Write enough messages into the FMQ to fill half of it.
* Request mService to read back the same.
* Write mNumMessagesMax messages into the queue. This should cause a
* wrap around. Request mService to read and verify the data.
*/
TEST_F(SynchronizedReadWriteClient, ReadWriteWrapAround) {
size_t numMessages = mNumMessagesMax / 2;
std::vector<uint16_t> data(mNumMessagesMax);
initData(&data[0], mNumMessagesMax);
ASSERT_TRUE(mQueue->write(&data[0], numMessages));
bool ret = mService->requestReadFmqSync(numMessages);
ASSERT_TRUE(ret);
ASSERT_TRUE(mQueue->write(&data[0], mNumMessagesMax));
ret = mService->requestReadFmqSync(mNumMessagesMax);
ASSERT_TRUE(ret);
}
/*
* Use beginWrite/commitWrite/getSlot APIs to test wrap arounds are handled
* correctly.
* Write enough messages into the FMQ to fill half of it
* and read back the same.
* Write mNumMessagesMax messages into the queue. This will cause a
* wrap around. Read and verify the data.
*/
TEST_F(SynchronizedReadWriteClient, ReadWriteWrapAround2) {
size_t numMessages = mNumMessagesMax / 2;
std::vector<uint16_t> data(mNumMessagesMax);
initData(&data[0], mNumMessagesMax);
ASSERT_TRUE(mQueue->write(&data[0], numMessages));
auto ret = mService->requestReadFmqSync(numMessages);
ASSERT_TRUE(ret.isOk());
ASSERT_TRUE(ret);
/*
* The next write and read will have to deal with with wrap arounds.
*/
MessageQueueSync::MemTransaction tx;
ASSERT_TRUE(mQueue->beginWrite(mNumMessagesMax, &tx));
ASSERT_EQ(tx.getFirstRegion().getLength() + tx.getSecondRegion().getLength(), mNumMessagesMax);
for (size_t i = 0; i < mNumMessagesMax; i++) {
uint16_t* ptr = tx.getSlot(i);
*ptr = data[i];
}
ASSERT_TRUE(mQueue->commitWrite(mNumMessagesMax));
ret = mService->requestReadFmqSync(mNumMessagesMax);
ASSERT_TRUE(ret.isOk());
ASSERT_TRUE(ret);
}
/*
* Request mService to write a small number of messages
* to the FMQ. Read and verify data.
*/
TEST_F(UnsynchronizedWriteClient, SmallInputReaderTest1) {
const size_t dataLen = 16;
ASSERT_LE(dataLen, mNumMessagesMax);
bool ret = mService->requestWriteFmqUnsync(dataLen);
ASSERT_TRUE(ret);
uint16_t readData[dataLen] = {};
ASSERT_TRUE(mQueue->read(readData, dataLen));
ASSERT_TRUE(verifyData(readData, dataLen));
}
/*
* Write a small number of messages to FMQ. Request
* mService to read and verify that the write was succesful.
*/
TEST_F(UnsynchronizedWriteClient, SmallInputWriterTest1) {
const size_t dataLen = 16;
ASSERT_LE(dataLen, mNumMessagesMax);
uint16_t data[dataLen];
initData(data, dataLen);
ASSERT_TRUE(mQueue->write(data, dataLen));
bool ret = mService->requestReadFmqUnsync(dataLen);
ASSERT_TRUE(ret);
}
/*
* Verify that the FMQ is empty and read fails when it is empty.
*/
TEST_F(UnsynchronizedWriteClient, ReadWhenEmpty) {
ASSERT_EQ(0UL, mQueue->availableToRead());
const size_t numMessages = 2;
ASSERT_LE(numMessages, mNumMessagesMax);
uint16_t readData[numMessages];
ASSERT_FALSE(mQueue->read(readData, numMessages));
}
/*
* Verify FMQ is empty.
* Write enough messages to fill it.
* Verify availableToWrite() method returns is zero.
* Try writing another message and verify that
* the attempted write was successful. Request mService
* to read the messages in the FMQ and verify that it is unsuccesful.
*/
TEST_F(UnsynchronizedWriteClient, WriteWhenFull) {
std::vector<uint16_t> data(mNumMessagesMax);
initData(&data[0], mNumMessagesMax);
ASSERT_TRUE(mQueue->write(&data[0], mNumMessagesMax));
ASSERT_EQ(0UL, mQueue->availableToWrite());
ASSERT_TRUE(mQueue->write(&data[0], 1));
bool ret = mService->requestReadFmqUnsync(mNumMessagesMax);
ASSERT_FALSE(ret);
}
/*
* Verify FMQ is empty.
* Request mService to write data equal to queue size.
* Read and verify data in mQueue.
*/
TEST_F(UnsynchronizedWriteClient, LargeInputTest1) {
bool ret = mService->requestWriteFmqUnsync(mNumMessagesMax);
ASSERT_TRUE(ret);
std::vector<uint16_t> data(mNumMessagesMax);
ASSERT_TRUE(mQueue->read(&data[0], mNumMessagesMax));
ASSERT_TRUE(verifyData(&data[0], mNumMessagesMax));
}
/*
* Request mService to write more than maximum number of messages to the FMQ.
* Verify that the write fails. Verify that availableToRead() method
* still returns 0 and verify that attempt to read fails.
*/
TEST_F(UnsynchronizedWriteClient, LargeInputTest2) {
ASSERT_EQ(0UL, mQueue->availableToRead());
const size_t numMessages = mNumMessagesMax + 1;
bool ret = mService->requestWriteFmqUnsync(numMessages);
ASSERT_FALSE(ret);
uint16_t readData;
ASSERT_EQ(0UL, mQueue->availableToRead());
ASSERT_FALSE(mQueue->read(&readData, 1));
}
/*
* Write until FMQ is full.
* Verify that the number of messages available to write
* is equal to mNumMessagesMax.
* Verify that another write attempt is succesful.
* Request mService to read. Verify that read is unsuccessful.
* Perform another write and verify that the read is succesful
* to check if the reader process can recover from the error condition.
*/
TEST_F(UnsynchronizedWriteClient, LargeInputTest3) {
std::vector<uint16_t> data(mNumMessagesMax);
initData(&data[0], mNumMessagesMax);
ASSERT_TRUE(mQueue->write(&data[0], mNumMessagesMax));
ASSERT_EQ(0UL, mQueue->availableToWrite());
ASSERT_TRUE(mQueue->write(&data[0], 1));
bool ret = mService->requestReadFmqUnsync(mNumMessagesMax);
ASSERT_FALSE(ret);
ASSERT_TRUE(mQueue->write(&data[0], mNumMessagesMax));
ret = mService->requestReadFmqUnsync(mNumMessagesMax);
ASSERT_TRUE(ret);
}
/*
* Confirm that the FMQ is empty. Request mService to write to FMQ.
* Do multiple reads to empty FMQ and verify data.
*/
TEST_F(UnsynchronizedWriteClient, MultipleRead) {
const size_t chunkSize = 100;
const size_t chunkNum = 5;
const size_t numMessages = chunkSize * chunkNum;
ASSERT_LE(numMessages, mNumMessagesMax);
size_t availableToRead = mQueue->availableToRead();
size_t expectedCount = 0;
ASSERT_EQ(expectedCount, availableToRead);
bool ret = mService->requestWriteFmqUnsync(numMessages);
ASSERT_TRUE(ret);
uint16_t readData[numMessages] = {};
for (size_t i = 0; i < chunkNum; i++) {
ASSERT_TRUE(mQueue->read(readData + i * chunkSize, chunkSize));
}
ASSERT_TRUE(verifyData(readData, numMessages));
}
/*
* Write to FMQ in bursts.
* Request mService to read data, verify that it was successful.
*/
TEST_F(UnsynchronizedWriteClient, MultipleWrite) {
const size_t chunkSize = 100;
const size_t chunkNum = 5;
const size_t numMessages = chunkSize * chunkNum;
ASSERT_LE(numMessages, mNumMessagesMax);
uint16_t data[numMessages];
initData(data, numMessages);
for (size_t i = 0; i < chunkNum; i++) {
ASSERT_TRUE(mQueue->write(data + i * chunkSize, chunkSize));
}
bool ret = mService->requestReadFmqUnsync(numMessages);
ASSERT_TRUE(ret);
}
/*
* Write enough messages into the FMQ to fill half of it.
* Request mService to read back the same.
* Write mNumMessagesMax messages into the queue. This should cause a
* wrap around. Request mService to read and verify the data.
*/
TEST_F(UnsynchronizedWriteClient, ReadWriteWrapAround) {
size_t numMessages = mNumMessagesMax / 2;
std::vector<uint16_t> data(mNumMessagesMax);
initData(&data[0], mNumMessagesMax);
ASSERT_TRUE(mQueue->write(&data[0], numMessages));
bool ret = mService->requestReadFmqUnsync(numMessages);
ASSERT_TRUE(ret);
ASSERT_TRUE(mQueue->write(&data[0], mNumMessagesMax));
ret = mService->requestReadFmqUnsync(mNumMessagesMax);
ASSERT_TRUE(ret);
}
/*
* Request mService to write a small number of messages
* to the FMQ. Read and verify data from two threads configured
* as readers to the FMQ.
*/
TEST_F(UnsynchronizedWriteClient, SmallInputMultipleReaderTest) {
auto desc = mQueue->getDesc();
std::unique_ptr<MessageQueue<uint16_t, kUnsynchronizedWrite>> mQueue2(
new (std::nothrow) MessageQueue<uint16_t, kUnsynchronizedWrite>(*desc));
ASSERT_NE(nullptr, mQueue2.get());
const size_t dataLen = 16;
ASSERT_LE(dataLen, mNumMessagesMax);
bool ret = mService->requestWriteFmqUnsync(dataLen);
ASSERT_TRUE(ret);
pid_t pid;
if ((pid = fork()) == 0) {
/* child process */
uint16_t readData[dataLen] = {};
ASSERT_TRUE(mQueue2->read(readData, dataLen));
ASSERT_TRUE(verifyData(readData, dataLen));
exit(0);
} else {
ASSERT_GT(pid,
0 /* parent should see PID greater than 0 for a good fork */);
uint16_t readData[dataLen] = {};
ASSERT_TRUE(mQueue->read(readData, dataLen));
ASSERT_TRUE(verifyData(readData, dataLen));
}
}
/*
* Request mService to write into the FMQ until it is full.
* Request mService to do another write and verify it is successful.
* Use two reader processes to read and verify that both fail.
*/
TEST_F(UnsynchronizedWriteClient, OverflowNotificationTest) {
auto desc = mQueue->getDesc();
std::unique_ptr<MessageQueue<uint16_t, kUnsynchronizedWrite>> mQueue2(
new (std::nothrow) MessageQueue<uint16_t, kUnsynchronizedWrite>(*desc));
ASSERT_NE(nullptr, mQueue2.get());
bool ret = mService->requestWriteFmqUnsync(mNumMessagesMax);
ASSERT_TRUE(ret);
ret = mService->requestWriteFmqUnsync(1);
ASSERT_TRUE(ret);
pid_t pid;
if ((pid = fork()) == 0) {
/* child process */
std::vector<uint16_t> readData(mNumMessagesMax);
ASSERT_FALSE(mQueue2->read(&readData[0], mNumMessagesMax));
exit(0);
} else {
ASSERT_GT(pid, 0/* parent should see PID greater than 0 for a good fork */);
std::vector<uint16_t> readData(mNumMessagesMax);
ASSERT_FALSE(mQueue->read(&readData[0], mNumMessagesMax));
}
}