be2939cab7
git-svn-id: file:///srv/svn/repos/haiku/trunk/current@383 a95241bf-73f2-0310-859d-f6bbb57e9c96
231 lines
7.0 KiB
C++
231 lines
7.0 KiB
C++
/*
|
|
$Id: ConcurrencyTest1.cpp,v 1.2 2002/07/22 09:28:00 tylerdauwalder Exp $
|
|
|
|
This file implements a test class for testing BMessageQueue functionality.
|
|
It tests use cases Destruction, Add Message 1, Add Message 3, Remove Message 1,
|
|
Remove Message 2, Count Messages, Find Message 1, Next Message 1 and Next Message
|
|
2.
|
|
|
|
The test works like the following:
|
|
- It does the test two times, one using an internal BList to keep track of
|
|
what should be in the queue and once without. It does it without because
|
|
using the internal BList isn't a good test of mutual exclusion because an
|
|
explicit lock is used. However, it is worth testing with the BList to show
|
|
that the result is what was expected.
|
|
- It starts three threads.
|
|
- In one thread, numAddMessages are added to the queue
|
|
- In the second thread, numNextMessages are removed from the queue using
|
|
NextMessage().
|
|
- In the third thread, numAddMessages are added to the queue however every
|
|
numRemovedMessagesPerAdd messages is removed using RemoveMessage().
|
|
- Once all three threads complete, the number of elements on the queue is
|
|
compared to what it expects.
|
|
- If the BList is being used internally, the queue is checked against the list.
|
|
- It checks that no BMessages have been deleted.
|
|
- It deletes the message queue.
|
|
- It checks that the expected number of BMessages have been deleted.
|
|
- It creates a new message queue and restarts the test again if necessary
|
|
(ie perform it without the internal list).
|
|
|
|
*/
|
|
|
|
|
|
#include "ThreadedTestCaller.h"
|
|
#include "ConcurrencyTest1.h"
|
|
#include "ThreadedTestCaller.h"
|
|
#include "TestSuite.h"
|
|
#include <MessageQueue.h>
|
|
#include <Autolock.h>
|
|
|
|
|
|
// This constant indicates how many messages to add to the queue.
|
|
const int numAddMessages = 5000;
|
|
|
|
// This constant indicates how many times to call NextMessage() on the queue.
|
|
const int numNextMessages = 100;
|
|
|
|
// This constant says how many adds to perform before doing a remove.
|
|
const int numAddMessagesPerRemove = 5;
|
|
|
|
|
|
/*
|
|
* Method: ConcurrencyTest1::ConcurrencyTest1()
|
|
* Descr: This is the constructor for this test.
|
|
*/
|
|
|
|
|
|
ConcurrencyTest1::ConcurrencyTest1(std::string name, bool listFlag) :
|
|
MessageQueueTestCase(name), useList(listFlag)
|
|
{
|
|
}
|
|
|
|
|
|
/*
|
|
* Method: ConcurrencyTest1::~ConcurrencyTest1()
|
|
* Descr: This is the destructor for this test.
|
|
*/
|
|
|
|
|
|
ConcurrencyTest1::~ConcurrencyTest1()
|
|
{
|
|
}
|
|
|
|
|
|
/*
|
|
* Method: ConcurrencyTest1::setUp()
|
|
* Descr: This member function prepares the enviroment for test execution.
|
|
* It resets the message destructor count and puts "numAddMessages"
|
|
* messages on the queue.
|
|
*/
|
|
|
|
void ConcurrencyTest1::setUp(void)
|
|
{
|
|
testMessageClass::messageDestructorCount = 0;
|
|
|
|
int i;
|
|
for (i=0; i < numAddMessages; i++) {
|
|
BMessage *theMessage = new testMessageClass(i);
|
|
if (useList) {
|
|
AddMessage(theMessage);
|
|
} else {
|
|
theMessageQueue->AddMessage(theMessage);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
* Method: ConcurrencyTest1::TestThread1()
|
|
* Descr: This member function is one of the three threads for performing
|
|
* this test. It waits until the other two threads complete and
|
|
* then checks the state of the message queue. If the list is
|
|
* being used, the queue is compared to the list. It checks that
|
|
* the expected number of messages are on the queue and that they
|
|
* are all deleted when the message queue is destructed.
|
|
*/
|
|
|
|
void ConcurrencyTest1::TestThread1(void)
|
|
{
|
|
NextSubTest();
|
|
snooze(1000000);
|
|
thread2Lock.Lock();
|
|
thread3Lock.Lock();
|
|
|
|
if (useList) {
|
|
CheckQueueAgainstList();
|
|
}
|
|
|
|
int numMessages = (2*numAddMessages) -
|
|
(numAddMessages / numAddMessagesPerRemove) -
|
|
numNextMessages;
|
|
CPPUNIT_ASSERT(numMessages == theMessageQueue->CountMessages());
|
|
CPPUNIT_ASSERT(testMessageClass::messageDestructorCount == 0);
|
|
|
|
delete theMessageQueue;
|
|
theMessageQueue = NULL;
|
|
CPPUNIT_ASSERT(testMessageClass::messageDestructorCount == numMessages);
|
|
}
|
|
|
|
|
|
/*
|
|
* Method: ConcurrencyTest1::TestThread2()
|
|
* Descr: This member function is one of the three threads for performing
|
|
* this test. It performs NextMessage() numNextMessages times on
|
|
* the queue. It confirms that it always receives a message from
|
|
* the queue.
|
|
*/
|
|
|
|
void ConcurrencyTest1::TestThread2(void)
|
|
{
|
|
BAutolock mySafetyLock(&thread2Lock);
|
|
|
|
int i;
|
|
for(i = 0; i < numNextMessages; i++) {
|
|
if (i % (numNextMessages / 10) == 0)
|
|
NextSubTest();
|
|
|
|
snooze(5000);
|
|
BMessage *theMessage;
|
|
if (useList) {
|
|
theMessage = NextMessage();
|
|
} else {
|
|
theMessage = theMessageQueue->NextMessage();
|
|
}
|
|
CPPUNIT_ASSERT(theMessage != NULL);
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
* Method: ConcurrencyTest1::TestThread3()
|
|
* Descr: This member function is one of the three threads for performing
|
|
* this test. It adds numAddMessages messages to the queue. For
|
|
* every numAddMessagesPerRemove messages it adds, one message
|
|
* is removed.
|
|
*/
|
|
|
|
void ConcurrencyTest1::TestThread3(void)
|
|
{
|
|
BAutolock mySafetyLock(&thread3Lock);
|
|
|
|
int i;
|
|
BList messagesToRemove;
|
|
|
|
for (i=0; i < numAddMessages; i++) {
|
|
if (i % (numAddMessages / 10) == 0)
|
|
NextSubTest();
|
|
|
|
BMessage *theMessage = new testMessageClass(i);
|
|
if (useList) {
|
|
AddMessage(theMessage);
|
|
} else {
|
|
theMessageQueue->AddMessage(theMessage);
|
|
}
|
|
if ((i % numAddMessagesPerRemove) == numAddMessagesPerRemove - 1) {
|
|
snooze(500);
|
|
if (useList) {
|
|
RemoveMessage(theMessage);
|
|
} else {
|
|
theMessageQueue->RemoveMessage(theMessage);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
* Method: ConcurrencyTest1::suite()
|
|
* Descr: This static member function returns a test suite for performing
|
|
* all combinations of "ConcurrencyTest1". The test suite contains
|
|
* two instances of the test. One is performed with a list,
|
|
* the other without. Each individual test
|
|
* is created as a ThreadedTestCase (typedef'd as
|
|
* ConcurrencyTest1Caller) with three independent threads.
|
|
*/
|
|
|
|
Test *ConcurrencyTest1::suite(void)
|
|
{
|
|
typedef BThreadedTestCaller<ConcurrencyTest1>
|
|
ConcurrencyTest1Caller;
|
|
TestSuite *testSuite = new TestSuite("ConcurrencyTest1");
|
|
|
|
ConcurrencyTest1 *theTest = new ConcurrencyTest1("WithList", true);
|
|
ConcurrencyTest1Caller *threadedTest1 = new ConcurrencyTest1Caller("BMessageQueue::Concurrency Test #1 (with list)", theTest);
|
|
threadedTest1->addThread("A", &ConcurrencyTest1::TestThread1);
|
|
threadedTest1->addThread("B", &ConcurrencyTest1::TestThread2);
|
|
threadedTest1->addThread("C", &ConcurrencyTest1::TestThread3);
|
|
|
|
theTest = new ConcurrencyTest1("WithoutList", false);
|
|
ConcurrencyTest1Caller *threadedTest2 = new ConcurrencyTest1Caller("BMessageQueue::Concurrency Test #1 (without list)", theTest);
|
|
threadedTest2->addThread("A", &ConcurrencyTest1::TestThread1);
|
|
threadedTest2->addThread("B", &ConcurrencyTest1::TestThread2);
|
|
threadedTest2->addThread("C", &ConcurrencyTest1::TestThread3);
|
|
|
|
testSuite->addTest(threadedTest1);
|
|
testSuite->addTest(threadedTest2);
|
|
return(testSuite);
|
|
}
|
|
|
|
|
|
|