001: /*
002: * @(#)SynchQueueUTest.java
003: *
004: * Copyright (C) 2001-2004 Matt Albrecht
005: * groboclown@users.sourceforge.net
006: * http://groboutils.sourceforge.net
007: *
008: * Permission is hereby granted, free of charge, to any person obtaining a
009: * copy of this software and associated documentation files (the "Software"),
010: * to deal in the Software without restriction, including without limitation
011: * the rights to use, copy, modify, merge, publish, distribute, sublicense,
012: * and/or sell copies of the Software, and to permit persons to whom the
013: * Software is furnished to do so, subject to the following conditions:
014: *
015: * The above copyright notice and this permission notice shall be included in
016: * all copies or substantial portions of the Software.
017: *
018: * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
019: * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
020: * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
021: * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
022: * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
023: * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
024: * DEALINGS IN THE SOFTWARE.
025: */
026:
027: package net.sourceforge.groboutils.util.datastruct.v1;
028:
029: import net.sourceforge.groboutils.junit.v1.MultiThreadedTestRunner;
030: import net.sourceforge.groboutils.junit.v1.TestMonitorRunnable;
031: import net.sourceforge.groboutils.junit.v1.TestRunnable;
032:
033: import net.sourceforge.groboutils.autodoc.v1.AutoDoc;
034:
035: import junit.framework.Test;
036: import junit.framework.TestCase;
037: import junit.framework.TestSuite;
038:
039: /**
040: *
041: * <H3>Changes made for 0.9.1:</H3>
042: * <UL>
043: * <LI>Added a new test to check the size of the queue during the
044: * threaded part. The size should never go below 0.
045: * </UL>
046: *
047: * @author Matt Albrecht <a href="mailto:groboclown@users.sourceforge.net">groboclown@users.sourceforge.net</a>
048: * @since March 14, 2001 (Alpha 0.9.0)
049: * @version $Date: 2004/06/08 20:55:40 $
050: */
051: public class SynchQueueUTest extends TestCase {
052: private static final Class THIS_CLASS = SynchQueueUTest.class;
053: private static final AutoDoc DOC = new AutoDoc(THIS_CLASS);
054:
055: public SynchQueueUTest(String name) {
056: super (name);
057: }
058:
059: public static Test suite() {
060: TestSuite suite = new TestSuite(THIS_CLASS);
061:
062: return suite;
063: }
064:
065: public static void main(String[] args) {
066: String[] name = { THIS_CLASS.getName() };
067:
068: // junit.textui.TestRunner.main( name );
069: // junit.swingui.TestRunner.main( name );
070:
071: junit.textui.TestRunner.main(name);
072: }
073:
074: protected void setUp() throws Exception {
075: super .setUp();
076:
077: // set ourself up
078: }
079:
080: protected void tearDown() throws Exception {
081: // tear ourself down
082:
083: super .tearDown();
084: }
085:
086: public void testInstantiate1() {
087: Object o = new SynchQueue();
088: assertNotNull("New should never return null.", o);
089: assertTrue("Instantiation must be of the correct class.",
090: o instanceof SynchQueue);
091: assertTrue(
092: "Queue needs to be empty immediately after instantiation.",
093: ((SynchQueue) o).isEmpty());
094: }
095:
096: public void testSimpleAdd1() throws InterruptedException {
097: SynchQueue sq = new SynchQueue();
098: Object o1 = new Object();
099: sq.enqueue(o1);
100: assertTrue("Queue should not be empty.", !sq.isEmpty());
101: Object o2 = sq.dequeue();
102: assertEquals(
103: "What gets put in, needs to equal what gets put out.",
104: o1, o2);
105: assertTrue("Queue should be empty after removing.", sq
106: .isEmpty());
107: }
108:
109: public void testAddSize1() {
110: SynchQueue sq = new SynchQueue();
111: assertEquals("Size must be 0 immediately after instantiation.",
112: 0, sq.size());
113: for (int i = 1; i <= 20; i++) {
114: Object o = new Object();
115: sq.enqueue(o);
116: assertEquals("Size must be " + i + " after enqueue call.",
117: i, sq.size());
118: }
119: }
120:
121: public void testRemoveSize1() throws InterruptedException {
122: SynchQueue sq = new SynchQueue();
123: int count = 0;
124: for (int i = 1; i <= 20; i++) {
125: Object o = new Object();
126: sq.enqueue(o);
127: count++;
128: //System.out.println("Added element: size now "+count);
129: }
130: while (count > 0) {
131: assertTrue("Queue should not be empty.", !sq.isEmpty());
132: assertEquals("Queue size must be " + count + ".", count, sq
133: .size());
134: //System.out.println("Removing element: size is now "+sq.size()+" (should be "+count+")" );
135: sq.dequeue();
136: count--;
137: }
138: assertTrue("Queue should be empty after removing.", sq
139: .isEmpty());
140: assertEquals("Size must be 0 after dequeue all.", 0, sq.size());
141: }
142:
143: public void testUniqueRetrieval1() throws InterruptedException {
144: SynchQueue sq = new SynchQueue();
145: int maxSize = 20;
146: Object objs[] = new Object[maxSize];
147: for (int i = 0; i < maxSize; i++) {
148: objs[i] = "element " + i;
149: sq.enqueue(objs[i]);
150: }
151: // parse forwards through the list for checking the return values
152: // (its a queue, not a stack)
153: //System.err.println("Starting dequeue loop:");
154: for (int i = 0; i < maxSize; i++) {
155: //System.err.println("dequeueing element index "+i);
156: assertTrue(
157: "Queue cannot be empty at this point: should have "
158: + (i + 1) + " elements left.", !sq
159: .isEmpty());
160: Object o = sq.dequeue();
161: assertNotNull("Queue must never return null from dequeue.",
162: o);
163: assertEquals(
164: "Queue did not return the right object in the right "
165: + "order (element " + i + ", size = "
166: + sq.size() + ")", objs[i], o);
167: }
168: // yeah, we already have a test for this - but just to be careful.
169: assertTrue("Queue must be empty.", sq.isEmpty());
170: }
171:
172: public void testIdenticalRetrieval1() throws InterruptedException {
173: SynchQueue sq = new SynchQueue();
174: int maxSize = 20;
175: Object obj = new Object();
176: for (int i = 0; i < maxSize; i++) {
177: sq.enqueue(obj);
178: }
179: // parse forwards through the list for checking the return values
180: // (its a queue, not a stack)
181: //System.err.println("Starting dequeue loop:");
182: for (int i = 0; i < maxSize; i++) {
183: //System.err.println("dequeueing element index "+i);
184: assertTrue(
185: "Queue cannot be empty at this point: should have "
186: + (i + 1) + " elements left.", !sq
187: .isEmpty());
188: Object o = sq.dequeue();
189: assertNotNull("Queue must never return null from dequeue.",
190: o);
191: assertEquals(
192: "Queue did not return the right object in the right "
193: + "order (element " + i + ", size = "
194: + sq.size() + ")", obj, o);
195: }
196: // yeah, we already have a test for this - but just to be careful.
197: assertTrue("Queue must be empty.", sq.isEmpty());
198: }
199:
200: public void testPeek1() throws InterruptedException {
201: SynchQueue sq = new SynchQueue();
202: assertNull("Peek must return null on an empty queue", sq.peek());
203:
204: int maxSize = 20;
205: Object objs[] = new Object[maxSize];
206: for (int i = 0; i < maxSize; i++) {
207: objs[i] = "element " + i;
208: sq.enqueue(objs[i]);
209: }
210: // parse forwards through the list for checking the return values
211: // (its a queue, not a stack)
212: //System.err.println("Starting dequeue loop:");
213: for (int i = 0; i < maxSize; i++) {
214: //System.err.println("dequeueing element index "+i);
215: assertTrue(
216: "Queue cannot be empty at this point: should have "
217: + (i + 1) + " elements left.", !sq
218: .isEmpty());
219: Object o1 = sq.peek();
220: assertNotNull(
221: "Peek must not return null on a non-null queue", o1);
222: Object o2 = sq.dequeue();
223: assertNotNull("Queue must never return null from dequeue.",
224: o2);
225: assertEquals(
226: "Peek did not return the right element in the right "
227: + "order (element " + i + ", size = "
228: + sq.size() + ")", o2, o1);
229: }
230: // yeah, we already have a test for this - but just to be careful.
231: assertNull("Peek must return null on an empty queue", sq.peek());
232: }
233:
234: public void testRemoveAll1() throws InterruptedException {
235: SynchQueue sq = new SynchQueue();
236: assertNull("Peek must return null on an empty queue", sq.peek());
237:
238: int maxSize = 20;
239: Object objs[] = new Object[maxSize];
240: for (int i = 0; i < maxSize; i++) {
241: objs[i] = "element " + i;
242: sq.enqueue(objs[i]);
243: }
244: assertEquals("Queue must have " + maxSize + " elements.",
245: maxSize, sq.size());
246: sq.removeAll();
247: assertEquals("Queue must be empty.", 0, sq.size());
248: assertTrue("Queue must be empty.", sq.isEmpty());
249:
250: // now verify that the queue still works correctly
251: testUniqueRetrieval1();
252: }
253:
254: private class PutObjects extends TestRunnable {
255: private SynchQueue m_sq;
256: private Object[] m_objs;
257: private long m_delay;
258:
259: public PutObjects(SynchQueue sq, Object[] list, long delayMillis) {
260: this .m_sq = sq;
261: this .m_objs = list;
262: this .m_delay = delayMillis;
263: }
264:
265: public void runTest() throws Throwable {
266: try {
267: DOC.getLog().debug("Entering PutObjects.runTest()");
268: for (int i = 0; i < this .m_objs.length; i++) {
269: // for putting into the list, we delay before inserting
270: DOC.getLog().debug(
271: "Enqueue delay " + this .m_delay
272: + " millis.");
273: delay(this .m_delay);
274: DOC.getLog().debug(
275: new Object[] { "Enqueue object '",
276: this .m_objs[i], "'" });
277: this .m_sq.enqueue(this .m_objs[i]);
278: }
279: } finally {
280: DOC.getLog().debug("Leaving PutObjects.runTest()");
281: }
282: }
283: }
284:
285: private class CheckSize extends TestMonitorRunnable {
286: private SynchQueue m_sq;
287: private int m_maxSize;
288:
289: public CheckSize(SynchQueue sq, int maxSize) {
290: this .m_sq = sq;
291: this .m_maxSize = maxSize;
292: }
293:
294: public void runMonitor() throws Throwable {
295: int size = this .m_sq.size();
296: assertTrue("Invalid queue size " + size
297: + ": must be within the set [0, " + this .m_maxSize
298: + "].", (size >= 0) && (size <= this .m_maxSize));
299: }
300: }
301:
302: private class GetObjects extends TestRunnable {
303: private SynchQueue m_sq;
304: private Object[] m_objs;
305: private long m_delay;
306: private long m_waitMillis;
307: private int m_waitNanos;
308:
309: public GetObjects(SynchQueue sq, Object[] expectedlist,
310: long delayMillis) {
311: this (sq, expectedlist, delayMillis, -1, -1);
312: }
313:
314: public GetObjects(SynchQueue sq, Object[] expectedlist,
315: long delayMillis, long waitTime, int nanos) {
316: this .m_sq = sq;
317: this .m_objs = expectedlist;
318: this .m_delay = delayMillis;
319: this .m_waitMillis = waitTime;
320: this .m_waitNanos = nanos;
321: }
322:
323: public void runTest() throws Throwable {
324: DOC.getLog().debug("Entering GetObjects.runTest()");
325: for (int i = 0; i < this .m_objs.length; i++) {
326: DOC.getLog().debug(
327: "Dequeue delay " + this .m_delay + " millis.");
328: delay(this .m_delay);
329: Object o = dequeue();
330: assertEquals("Retrieved element " + i
331: + " doesn't match", this .m_objs[i], o);
332: }
333: DOC.getLog().debug("Leaving GetObjects.runTest()");
334: }
335:
336: protected Object dequeue() throws Throwable {
337: long startTime = System.currentTimeMillis();
338: Object ret;
339: if (this .m_waitMillis > 0) {
340: if (this .m_waitNanos > 0) {
341: DOC.getLog().debug("dequeue w/ nano delay");
342: ret = this .m_sq.dequeue(this .m_waitMillis,
343: this .m_waitNanos);
344: } else {
345: DOC.getLog().debug(
346: "dequeue w/ millis dely ["
347: + this .m_waitMillis + "]");
348: ret = this .m_sq.dequeue(this .m_waitMillis);
349: }
350: } else {
351: DOC.getLog().debug("dequeue w/ no time-out");
352: ret = this .m_sq.dequeue();
353: }
354: long endTime = System.currentTimeMillis();
355: DOC.getLog().debug(
356: new Object[] {
357: "returning dequeued object '",
358: ret,
359: "' after " + (endTime - startTime)
360: + " milliseconds." });
361: return ret;
362: }
363: }
364:
365: public void testSimpleThreaded() throws Throwable {
366: DOC.getLog().info("Entering testSimpleThreaded");
367: int numElements = 20;
368: SynchQueue sq = new SynchQueue();
369: Object list[] = new Object[numElements];
370: for (int i = 0; i < numElements; i++) {
371: list[i] = "element " + i;
372: }
373:
374: // MCA: 26-Oct-2003: changed GetObjects delay to 20 ms due to
375: // coverage number delays and file I/O on slower machines.
376: TestRunnable tcs[] = { new PutObjects(sq, list, 10),
377: new GetObjects(sq, list, 20) };
378: // allow for a maximum of 60 seconds for this test to run
379: DOC.getLog().debug("Starting SimpleThreaded()");
380: runTestRunnables(tcs, new CheckSize(sq, numElements), 1000 * 60);
381: DOC.getLog().debug("Finished SimpleThreaded()");
382: }
383:
384: public void testSyncapatedThreaded() throws Throwable {
385: DOC.getLog().info("Entering testSyncapatedThreaded");
386: int numElements = 20;
387: SynchQueue sq = new SynchQueue();
388: Object list[] = new Object[numElements];
389: for (int i = 0; i < numElements; i++) {
390: list[i] = "element " + i;
391: }
392: TestRunnable tcs[] = { new PutObjects(sq, list, 1000),
393: new GetObjects(sq, list, 10) };
394: DOC.getLog().debug("Starting SyncapatedThreaded()");
395: runTestRunnables(tcs, new CheckSize(sq, numElements), 1000 * 60);
396: DOC.getLog().debug("Finished SyncapatedThreaded()");
397: }
398:
399: public void testDelayMillisThreaded() throws Throwable {
400: DOC.getLog().info("Entering testDelayMillisThreaded");
401: int numElements = 1;
402: Object list[] = new Object[numElements];
403: SynchQueue sq = new SynchQueue();
404: // don't wait - detect the null immediately
405: TestRunnable tcs[] = { new GetObjects(sq, list, 0, 10, -1) };
406: DOC.getLog().debug("Starting DelayMillisThreaded()");
407: runTestRunnables(tcs, new CheckSize(sq, numElements), 2000);
408: DOC.getLog().debug("Finished DelayMillisThreaded()");
409: }
410:
411: public void testDelayNanosThreaded() throws Throwable {
412: DOC.getLog().info("Entering testDelayNanosThreaded");
413: int numElements = 1;
414: Object list[] = new Object[numElements];
415: SynchQueue sq = new SynchQueue();
416: // wait for 10 millis, 10 nanos, for null.
417: CheckSize cs = new CheckSize(sq, numElements);
418: TestRunnable tcs[] = { new GetObjects(sq, list, 0, 10, 10) };
419: DOC.getLog().debug("Starting DelayNanosThreaded()");
420: runTestRunnables(tcs, new CheckSize(sq, numElements), 2000);
421: DOC.getLog().debug("Finished DelayNanosThreaded()");
422: }
423:
424: public void testPutDelayMillisThreaded() throws Throwable {
425: DOC.getLog().info("Entering testPutDelayMillisThreaded");
426: int numElements = 20;
427: SynchQueue sq = new SynchQueue();
428: Object list[] = new Object[numElements];
429: for (int i = 0; i < numElements; i++) {
430: list[i] = "element " + i;
431: }
432: TestRunnable tcs[] = { new PutObjects(sq, list, 10),
433: new GetObjects(sq, list, 0, 500, -1) };
434: DOC.getLog().debug("Starting PutDelayMillisThreaded()");
435: runTestRunnables(tcs, new CheckSize(sq, numElements), 1000 * 60);
436: DOC.getLog().debug("Finished PutDelayMillisThreaded()");
437: }
438:
439: public void testPutDelayMillisThreaded2() throws Throwable {
440: DOC.getLog().info("Entering testPutDelayMillisThreaded2");
441: int numElements = 5;
442: SynchQueue sq = new SynchQueue();
443: Object list[] = new Object[numElements];
444: Object nulllist[] = new Object[numElements];
445: for (int i = 0; i < numElements; i++) {
446: list[i] = "element " + i;
447: }
448: // timing issues cause these numbers not to match up perfectly.
449: TestRunnable tcs[] = {
450: new PutObjects(sq, list, numElements * 500),
451: new GetObjects(sq, nulllist, 0, 100, -1) };
452: DOC.getLog().debug("Starting PutDelayMillisThreaded2()");
453: runTestRunnables(tcs, new CheckSize(sq, numElements), 1000 * 60);
454: DOC.getLog().debug("Finished PutDelayMillisThreaded2()");
455: }
456:
457: protected void runTestRunnables(TestRunnable tr[], TestRunnable tm,
458: long maxtime) throws Throwable {
459: MultiThreadedTestRunner mttr = new MultiThreadedTestRunner(tr,
460: new TestRunnable[] { tm });
461: mttr.runTestRunnables(maxtime);
462: }
463: }
|