/* * Copyright 2022 Haiku, Inc. All rights reserved. * Distributed under the terms of the MIT License. * * Authors: * Leorize, leorize+oss@disroot.org */ #include "MemoryRingIOTest.h" #include #include #include #include #include #include #include #include #define BIG_PAYLOAD \ "a really long string that can fill the buffer multiple times" #define FULL_PAYLOAD "16 characters x" #define SMALL_PAYLOAD "shorter" static void ReadCheck(BMemoryRingIO& ring, const void* cmp, size_t size) { char* buffer = new char[size]; memset(buffer, 0, size); size_t read; CHK(ring.ReadExactly(buffer, size, &read) == B_OK); CHK(read == size); CHK(memcmp(buffer, cmp, size) == 0); } void MemoryRingIOTest::WriteTest() { CHK(fRing.InitCheck() == B_OK); CHK(fRing.WriteExactly(SMALL_PAYLOAD, sizeof(SMALL_PAYLOAD), NULL) == B_OK); CHK(fRing.WriteExactly(FULL_PAYLOAD, sizeof(FULL_PAYLOAD), NULL) == B_OK); CHK(fRing.WriteExactly(BIG_PAYLOAD, sizeof(BIG_PAYLOAD), NULL) == B_OK); } void MemoryRingIOTest::ReadTest() { CHK(fRing.InitCheck() == B_OK); ReadCheck(fRing, SMALL_PAYLOAD, sizeof(SMALL_PAYLOAD)); ReadCheck(fRing, FULL_PAYLOAD, sizeof(FULL_PAYLOAD)); ReadCheck(fRing, BIG_PAYLOAD, sizeof(BIG_PAYLOAD)); } void MemoryRingIOTest::BusyWriterTest() { CHK(fRing.InitCheck() == B_OK); CHK(fRing.BufferSize() < sizeof(BIG_PAYLOAD)); CHK(fRing.WriteExactly(BIG_PAYLOAD, sizeof(BIG_PAYLOAD), NULL) == B_DEVICE_FULL); } void MemoryRingIOTest::BusyReaderTest() { CHK(fRing.InitCheck() == B_OK); char buffer[100]; CHK(fRing.Read(buffer, sizeof(buffer)) == 0); } void MemoryRingIOTest::ReadWriteSingleTest() { CHK(fRing.SetSize(sizeof(BIG_PAYLOAD)) == B_OK); CHK(fRing.WriteExactly(BIG_PAYLOAD, sizeof(BIG_PAYLOAD)) == B_OK); ReadCheck(fRing, BIG_PAYLOAD, sizeof(BIG_PAYLOAD)); CHK(fRing.SetSize(sizeof(FULL_PAYLOAD)) == B_OK); // the size of FULL_PAYLOAD is a power of two, so our ring // should be using the exact size. CHK(fRing.BufferSize() == sizeof(FULL_PAYLOAD)); CHK(fRing.WriteExactly(FULL_PAYLOAD, sizeof(FULL_PAYLOAD)) == B_OK); ReadCheck(fRing, FULL_PAYLOAD, sizeof(FULL_PAYLOAD)); CHK(fRing.SetSize(sizeof(SMALL_PAYLOAD)) == B_OK); CHK(fRing.WriteExactly(SMALL_PAYLOAD, sizeof(SMALL_PAYLOAD)) == B_OK); ReadCheck(fRing, SMALL_PAYLOAD, sizeof(SMALL_PAYLOAD)); } void MemoryRingIOTest::InvalidResizeTest() { CHK(fRing.SetSize(sizeof(FULL_PAYLOAD)) == B_OK); CHK(fRing.WriteExactly(FULL_PAYLOAD, sizeof(FULL_PAYLOAD)) == B_OK); CHK(fRing.SetSize(0) == B_BAD_VALUE); } void MemoryRingIOTest::TimeoutTest() { fRing.Clear(); CHK(fRing.SetSize(0) == B_OK); bigtime_t start = system_time(); const bigtime_t timeout = 100; CHK(fRing.WaitForRead(timeout) == B_TIMED_OUT); CHK(system_time() - start <= timeout + 10); start = system_time(); CHK(fRing.WaitForWrite(timeout) == B_TIMED_OUT); CHK(system_time() - start <= timeout + 10); } void MemoryRingIOTest::_DisableWriteOnFullBuffer() { CHK(fRing.InitCheck() == B_OK); while (fRing.SpaceAvailable() > 0) fRing.WaitForRead(); /* snooze for sometime to ensure that the other thread entered * WaitForWrite(). */ snooze(1000); /* this should unblock the other thread */ fRing.SetWriteDisabled(true); } void MemoryRingIOTest::_DisableWriteOnEmptyBuffer() { CHK(fRing.InitCheck() == B_OK); while (fRing.BytesAvailable() > 0) fRing.WaitForWrite(); /* snooze for sometime to ensure that the other thread entered * WaitForRead(). */ snooze(1000); /* this should unblock the other thread */ fRing.SetWriteDisabled(true); } /* static */ void MemoryRingIOTest::AddTests(BTestSuite& parent) { CppUnit::TestSuite* suite = new CppUnit::TestSuite("MemoryRingIOTest"); BThreadedTestCaller* caller; MemoryRingIOTest* big = new MemoryRingIOTest(sizeof(BIG_PAYLOAD)); caller = new BThreadedTestCaller( "MemoryRingIOTest: RW threaded, big buffer", big); caller->addThread("WR", &MemoryRingIOTest::WriteTest); caller->addThread("RD", &MemoryRingIOTest::ReadTest); suite->addTest(caller); MemoryRingIOTest* full = new MemoryRingIOTest(sizeof(FULL_PAYLOAD)); caller = new BThreadedTestCaller( "MemoryRingIOTest: RW threaded, medium buffer", full); caller->addThread("WR", &MemoryRingIOTest::WriteTest); caller->addThread("RD", &MemoryRingIOTest::ReadTest); suite->addTest(caller); MemoryRingIOTest* small = new MemoryRingIOTest(sizeof(SMALL_PAYLOAD)); caller = new BThreadedTestCaller( "MemoryRingIOTest: RW threaded, small buffer", small); caller->addThread("WR", &MemoryRingIOTest::WriteTest); caller->addThread("RD", &MemoryRingIOTest::ReadTest); suite->addTest(caller); MemoryRingIOTest* endWrite = new MemoryRingIOTest(sizeof(FULL_PAYLOAD)); caller = new BThreadedTestCaller( "MemoryRingIOTest: RW threaded, reader set end reached on writer wait", endWrite); caller->addThread("WR #1", &MemoryRingIOTest::BusyWriterTest); caller->addThread("WR #2", &MemoryRingIOTest::BusyWriterTest); caller->addThread("WR #3", &MemoryRingIOTest::BusyWriterTest); caller->addThread("RD", &MemoryRingIOTest::_DisableWriteOnFullBuffer); suite->addTest(caller); MemoryRingIOTest* endRead = new MemoryRingIOTest(sizeof(FULL_PAYLOAD)); caller = new BThreadedTestCaller( "MemoryRingIOTest: RW threaded, writer set end reached on reader wait", endRead); caller->addThread("RD #1", &MemoryRingIOTest::BusyReaderTest); caller->addThread("RD #2", &MemoryRingIOTest::BusyReaderTest); caller->addThread("RD #3", &MemoryRingIOTest::BusyReaderTest); caller->addThread("WR", &MemoryRingIOTest::_DisableWriteOnEmptyBuffer); suite->addTest(caller); MemoryRingIOTest* single = new MemoryRingIOTest(0); suite->addTest(new CppUnit::TestCaller( "MemoryRingIOTest: RW single threaded with resizing", &MemoryRingIOTest::ReadWriteSingleTest, single)); suite->addTest(new CppUnit::TestCaller( "MemoryRingIOTest: Attempt to truncate buffer", &MemoryRingIOTest::InvalidResizeTest, single)); suite->addTest(new CppUnit::TestCaller( "MemoryRingIOTest: Wait timeout", &MemoryRingIOTest::TimeoutTest, single)); parent.addTest("MemoryRingIOTest", suite); }