1 /* 2 $Id: ConcurrencyTest1.cpp 383 2002-07-22 09:28:00Z tylerdauwalder $ 3 4 This file implements a test class for testing BMessageQueue functionality. 5 It tests use cases Destruction, Add Message 1, Add Message 3, Remove Message 1, 6 Remove Message 2, Count Messages, Find Message 1, Next Message 1 and Next Message 7 2. 8 9 The test works like the following: 10 - It does the test two times, one using an internal BList to keep track of 11 what should be in the queue and once without. It does it without because 12 using the internal BList isn't a good test of mutual exclusion because an 13 explicit lock is used. However, it is worth testing with the BList to show 14 that the result is what was expected. 15 - It starts three threads. 16 - In one thread, numAddMessages are added to the queue 17 - In the second thread, numNextMessages are removed from the queue using 18 NextMessage(). 19 - In the third thread, numAddMessages are added to the queue however every 20 numRemovedMessagesPerAdd messages is removed using RemoveMessage(). 21 - Once all three threads complete, the number of elements on the queue is 22 compared to what it expects. 23 - If the BList is being used internally, the queue is checked against the list. 24 - It checks that no BMessages have been deleted. 25 - It deletes the message queue. 26 - It checks that the expected number of BMessages have been deleted. 27 - It creates a new message queue and restarts the test again if necessary 28 (ie perform it without the internal list). 29 30 */ 31 32 33 #include "ThreadedTestCaller.h" 34 #include "ConcurrencyTest1.h" 35 #include "ThreadedTestCaller.h" 36 #include "TestSuite.h" 37 #include <MessageQueue.h> 38 #include <Autolock.h> 39 40 41 // This constant indicates how many messages to add to the queue. 42 const int numAddMessages = 5000; 43 44 // This constant indicates how many times to call NextMessage() on the queue. 45 const int numNextMessages = 100; 46 47 // This constant says how many adds to perform before doing a remove. 48 const int numAddMessagesPerRemove = 5; 49 50 51 /* 52 * Method: ConcurrencyTest1::ConcurrencyTest1() 53 * Descr: This is the constructor for this test. 54 */ 55 56 57 ConcurrencyTest1::ConcurrencyTest1(std::string name, bool listFlag) : 58 MessageQueueTestCase(name), useList(listFlag) 59 { 60 } 61 62 63 /* 64 * Method: ConcurrencyTest1::~ConcurrencyTest1() 65 * Descr: This is the destructor for this test. 66 */ 67 68 69 ConcurrencyTest1::~ConcurrencyTest1() 70 { 71 } 72 73 74 /* 75 * Method: ConcurrencyTest1::setUp() 76 * Descr: This member function prepares the enviroment for test execution. 77 * It resets the message destructor count and puts "numAddMessages" 78 * messages on the queue. 79 */ 80 81 void ConcurrencyTest1::setUp(void) 82 { 83 testMessageClass::messageDestructorCount = 0; 84 85 int i; 86 for (i=0; i < numAddMessages; i++) { 87 BMessage *theMessage = new testMessageClass(i); 88 if (useList) { 89 AddMessage(theMessage); 90 } else { 91 theMessageQueue->AddMessage(theMessage); 92 } 93 } 94 } 95 96 97 /* 98 * Method: ConcurrencyTest1::TestThread1() 99 * Descr: This member function is one of the three threads for performing 100 * this test. It waits until the other two threads complete and 101 * then checks the state of the message queue. If the list is 102 * being used, the queue is compared to the list. It checks that 103 * the expected number of messages are on the queue and that they 104 * are all deleted when the message queue is destructed. 105 */ 106 107 void ConcurrencyTest1::TestThread1(void) 108 { 109 NextSubTest(); 110 snooze(1000000); 111 thread2Lock.Lock(); 112 thread3Lock.Lock(); 113 114 if (useList) { 115 CheckQueueAgainstList(); 116 } 117 118 int numMessages = (2*numAddMessages) - 119 (numAddMessages / numAddMessagesPerRemove) - 120 numNextMessages; 121 CPPUNIT_ASSERT(numMessages == theMessageQueue->CountMessages()); 122 CPPUNIT_ASSERT(testMessageClass::messageDestructorCount == 0); 123 124 delete theMessageQueue; 125 theMessageQueue = NULL; 126 CPPUNIT_ASSERT(testMessageClass::messageDestructorCount == numMessages); 127 } 128 129 130 /* 131 * Method: ConcurrencyTest1::TestThread2() 132 * Descr: This member function is one of the three threads for performing 133 * this test. It performs NextMessage() numNextMessages times on 134 * the queue. It confirms that it always receives a message from 135 * the queue. 136 */ 137 138 void ConcurrencyTest1::TestThread2(void) 139 { 140 BAutolock mySafetyLock(&thread2Lock); 141 142 int i; 143 for(i = 0; i < numNextMessages; i++) { 144 if (i % (numNextMessages / 10) == 0) 145 NextSubTest(); 146 147 snooze(5000); 148 BMessage *theMessage; 149 if (useList) { 150 theMessage = NextMessage(); 151 } else { 152 theMessage = theMessageQueue->NextMessage(); 153 } 154 CPPUNIT_ASSERT(theMessage != NULL); 155 } 156 } 157 158 159 /* 160 * Method: ConcurrencyTest1::TestThread3() 161 * Descr: This member function is one of the three threads for performing 162 * this test. It adds numAddMessages messages to the queue. For 163 * every numAddMessagesPerRemove messages it adds, one message 164 * is removed. 165 */ 166 167 void ConcurrencyTest1::TestThread3(void) 168 { 169 BAutolock mySafetyLock(&thread3Lock); 170 171 int i; 172 BList messagesToRemove; 173 174 for (i=0; i < numAddMessages; i++) { 175 if (i % (numAddMessages / 10) == 0) 176 NextSubTest(); 177 178 BMessage *theMessage = new testMessageClass(i); 179 if (useList) { 180 AddMessage(theMessage); 181 } else { 182 theMessageQueue->AddMessage(theMessage); 183 } 184 if ((i % numAddMessagesPerRemove) == numAddMessagesPerRemove - 1) { 185 snooze(500); 186 if (useList) { 187 RemoveMessage(theMessage); 188 } else { 189 theMessageQueue->RemoveMessage(theMessage); 190 } 191 } 192 } 193 } 194 195 196 /* 197 * Method: ConcurrencyTest1::suite() 198 * Descr: This static member function returns a test suite for performing 199 * all combinations of "ConcurrencyTest1". The test suite contains 200 * two instances of the test. One is performed with a list, 201 * the other without. Each individual test 202 * is created as a ThreadedTestCase (typedef'd as 203 * ConcurrencyTest1Caller) with three independent threads. 204 */ 205 206 Test *ConcurrencyTest1::suite(void) 207 { 208 typedef BThreadedTestCaller<ConcurrencyTest1> 209 ConcurrencyTest1Caller; 210 TestSuite *testSuite = new TestSuite("ConcurrencyTest1"); 211 212 ConcurrencyTest1 *theTest = new ConcurrencyTest1("WithList", true); 213 ConcurrencyTest1Caller *threadedTest1 = new ConcurrencyTest1Caller("BMessageQueue::Concurrency Test #1 (with list)", theTest); 214 threadedTest1->addThread("A", &ConcurrencyTest1::TestThread1); 215 threadedTest1->addThread("B", &ConcurrencyTest1::TestThread2); 216 threadedTest1->addThread("C", &ConcurrencyTest1::TestThread3); 217 218 theTest = new ConcurrencyTest1("WithoutList", false); 219 ConcurrencyTest1Caller *threadedTest2 = new ConcurrencyTest1Caller("BMessageQueue::Concurrency Test #1 (without list)", theTest); 220 threadedTest2->addThread("A", &ConcurrencyTest1::TestThread1); 221 threadedTest2->addThread("B", &ConcurrencyTest1::TestThread2); 222 threadedTest2->addThread("C", &ConcurrencyTest1::TestThread3); 223 224 testSuite->addTest(threadedTest1); 225 testSuite->addTest(threadedTest2); 226 return(testSuite); 227 } 228 229 230 231