xref: /haiku/src/tests/kits/app/bmessagequeue/ConcurrencyTest1.cpp (revision 21258e2674226d6aa732321b6f8494841895af5f)
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