1/*
2 * Written by Doug Lea and Martin Buchholz with assistance from members
3 * of JCP JSR-166 Expert Group and released to the public domain, as
4 * explained at http://creativecommons.org/publicdomain/zero/1.0/
5 *
6 * Other contributors include Andrew Wright, Jeffrey Hayes,
7 * Pat Fisher, Mike Judd.
8 */
9
10package jsr166;
11
12import static java.util.concurrent.TimeUnit.MILLISECONDS;
13
14import java.util.ArrayList;
15import java.util.Arrays;
16import java.util.Collection;
17import java.util.Queue;
18import java.util.concurrent.BlockingQueue;
19import java.util.concurrent.CountDownLatch;
20
21import junit.framework.Test;
22import junit.framework.TestSuite;
23
24/**
25 * Contains "contract" tests applicable to all BlockingQueue implementations.
26 */
27public abstract class BlockingQueueTest extends JSR166TestCase {
28    /*
29     * This is the start of an attempt to refactor the tests for the
30     * various related implementations of related interfaces without
31     * too much duplicated code.  junit does not really support such
32     * testing.  Here subclasses of TestCase not only contain tests,
33     * but also configuration information that describes the
34     * implementation class, most importantly how to instantiate
35     * instances.
36     */
37
38    /** Like suite(), but non-static */
39    // android-note: Explicitly instantiated.
40    //
41    // public Test testSuite() {
42    //     // TODO: filter the returned tests using the configuration
43    //     // information provided by the subclass via protected methods.
44    //     return new TestSuite(this.getClass());
45    // }
46
47    //----------------------------------------------------------------
48    // Configuration methods
49    //----------------------------------------------------------------
50
51    /** Returns an empty instance of the implementation class. */
52    protected abstract BlockingQueue emptyCollection();
53
54    /**
55     * Returns an element suitable for insertion in the collection.
56     * Override for collections with unusual element types.
57     */
58    protected Object makeElement(int i) {
59        return Integer.valueOf(i);
60    }
61
62    //----------------------------------------------------------------
63    // Tests
64    //----------------------------------------------------------------
65
66    /**
67     * offer(null) throws NullPointerException
68     */
69    public void testOfferNull() {
70        final Queue q = emptyCollection();
71        try {
72            q.offer(null);
73            shouldThrow();
74        } catch (NullPointerException success) {}
75    }
76
77    /**
78     * add(null) throws NullPointerException
79     */
80    public void testAddNull() {
81        final Collection q = emptyCollection();
82        try {
83            q.add(null);
84            shouldThrow();
85        } catch (NullPointerException success) {}
86    }
87
88    /**
89     * timed offer(null) throws NullPointerException
90     */
91    public void testTimedOfferNull() throws InterruptedException {
92        final BlockingQueue q = emptyCollection();
93        long startTime = System.nanoTime();
94        try {
95            q.offer(null, LONG_DELAY_MS, MILLISECONDS);
96            shouldThrow();
97        } catch (NullPointerException success) {}
98        assertTrue(millisElapsedSince(startTime) < LONG_DELAY_MS);
99    }
100
101    /**
102     * put(null) throws NullPointerException
103     */
104    public void testPutNull() throws InterruptedException {
105        final BlockingQueue q = emptyCollection();
106        try {
107            q.put(null);
108            shouldThrow();
109        } catch (NullPointerException success) {}
110    }
111
112    /**
113     * put(null) throws NullPointerException
114     */
115    public void testAddAllNull() throws InterruptedException {
116        final Collection q = emptyCollection();
117        try {
118            q.addAll(null);
119            shouldThrow();
120        } catch (NullPointerException success) {}
121    }
122
123    /**
124     * addAll of a collection with null elements throws NullPointerException
125     */
126    public void testAddAllNullElements() {
127        final Collection q = emptyCollection();
128        final Collection<Integer> elements = Arrays.asList(new Integer[SIZE]);
129        try {
130            q.addAll(elements);
131            shouldThrow();
132        } catch (NullPointerException success) {}
133    }
134
135    /**
136     * toArray(null) throws NullPointerException
137     */
138    public void testToArray_NullArray() {
139        final Collection q = emptyCollection();
140        try {
141            q.toArray(null);
142            shouldThrow();
143        } catch (NullPointerException success) {}
144    }
145
146    /**
147     * drainTo(null) throws NullPointerException
148     */
149    public void testDrainToNull() {
150        final BlockingQueue q = emptyCollection();
151        try {
152            q.drainTo(null);
153            shouldThrow();
154        } catch (NullPointerException success) {}
155    }
156
157    /**
158     * drainTo(this) throws IllegalArgumentException
159     */
160    public void testDrainToSelf() {
161        final BlockingQueue q = emptyCollection();
162        try {
163            q.drainTo(q);
164            shouldThrow();
165        } catch (IllegalArgumentException success) {}
166    }
167
168    /**
169     * drainTo(null, n) throws NullPointerException
170     */
171    public void testDrainToNullN() {
172        final BlockingQueue q = emptyCollection();
173        try {
174            q.drainTo(null, 0);
175            shouldThrow();
176        } catch (NullPointerException success) {}
177    }
178
179    /**
180     * drainTo(this, n) throws IllegalArgumentException
181     */
182    public void testDrainToSelfN() {
183        final BlockingQueue q = emptyCollection();
184        try {
185            q.drainTo(q, 0);
186            shouldThrow();
187        } catch (IllegalArgumentException success) {}
188    }
189
190    /**
191     * drainTo(c, n) returns 0 and does nothing when n <= 0
192     */
193    public void testDrainToNonPositiveMaxElements() {
194        final BlockingQueue q = emptyCollection();
195        final int[] ns = { 0, -1, -42, Integer.MIN_VALUE };
196        for (int n : ns)
197            assertEquals(0, q.drainTo(new ArrayList(), n));
198        if (q.remainingCapacity() > 0) {
199            // Not SynchronousQueue, that is
200            Object one = makeElement(1);
201            q.add(one);
202            ArrayList c = new ArrayList();
203            for (int n : ns)
204                assertEquals(0, q.drainTo(new ArrayList(), n));
205            assertEquals(1, q.size());
206            assertSame(one, q.poll());
207            assertTrue(c.isEmpty());
208        }
209    }
210
211    /**
212     * timed poll before a delayed offer times out; after offer succeeds;
213     * on interruption throws
214     */
215    public void testTimedPollWithOffer() throws InterruptedException {
216        final BlockingQueue q = emptyCollection();
217        final CheckedBarrier barrier = new CheckedBarrier(2);
218        final Object zero = makeElement(0);
219        Thread t = newStartedThread(new CheckedRunnable() {
220            public void realRun() throws InterruptedException {
221                long startTime = System.nanoTime();
222                assertNull(q.poll(timeoutMillis(), MILLISECONDS));
223                assertTrue(millisElapsedSince(startTime) >= timeoutMillis());
224
225                barrier.await();
226
227                assertSame(zero, q.poll(LONG_DELAY_MS, MILLISECONDS));
228
229                Thread.currentThread().interrupt();
230                try {
231                    q.poll(LONG_DELAY_MS, MILLISECONDS);
232                    shouldThrow();
233                } catch (InterruptedException success) {}
234                assertFalse(Thread.interrupted());
235
236                barrier.await();
237                try {
238                    q.poll(LONG_DELAY_MS, MILLISECONDS);
239                    shouldThrow();
240                } catch (InterruptedException success) {}
241                assertFalse(Thread.interrupted());
242
243                assertTrue(millisElapsedSince(startTime) < LONG_DELAY_MS);
244            }});
245
246        barrier.await();
247        long startTime = System.nanoTime();
248        assertTrue(q.offer(zero, LONG_DELAY_MS, MILLISECONDS));
249        assertTrue(millisElapsedSince(startTime) < LONG_DELAY_MS);
250
251        barrier.await();
252        assertThreadStaysAlive(t);
253        t.interrupt();
254        awaitTermination(t);
255    }
256
257    /**
258     * take() blocks interruptibly when empty
259     */
260    public void testTakeFromEmptyBlocksInterruptibly() {
261        final BlockingQueue q = emptyCollection();
262        final CountDownLatch threadStarted = new CountDownLatch(1);
263        Thread t = newStartedThread(new CheckedRunnable() {
264            public void realRun() {
265                threadStarted.countDown();
266                try {
267                    q.take();
268                    shouldThrow();
269                } catch (InterruptedException success) {}
270                assertFalse(Thread.interrupted());
271            }});
272
273        await(threadStarted);
274        assertThreadStaysAlive(t);
275        t.interrupt();
276        awaitTermination(t);
277    }
278
279    /**
280     * take() throws InterruptedException immediately if interrupted
281     * before waiting
282     */
283    public void testTakeFromEmptyAfterInterrupt() {
284        final BlockingQueue q = emptyCollection();
285        Thread t = newStartedThread(new CheckedRunnable() {
286            public void realRun() {
287                Thread.currentThread().interrupt();
288                try {
289                    q.take();
290                    shouldThrow();
291                } catch (InterruptedException success) {}
292                assertFalse(Thread.interrupted());
293            }});
294
295        awaitTermination(t);
296    }
297
298    /**
299     * timed poll() blocks interruptibly when empty
300     */
301    public void testTimedPollFromEmptyBlocksInterruptibly() {
302        final BlockingQueue q = emptyCollection();
303        final CountDownLatch threadStarted = new CountDownLatch(1);
304        Thread t = newStartedThread(new CheckedRunnable() {
305            public void realRun() {
306                threadStarted.countDown();
307                try {
308                    q.poll(2 * LONG_DELAY_MS, MILLISECONDS);
309                    shouldThrow();
310                } catch (InterruptedException success) {}
311                assertFalse(Thread.interrupted());
312            }});
313
314        await(threadStarted);
315        assertThreadStaysAlive(t);
316        t.interrupt();
317        awaitTermination(t);
318    }
319
320    /**
321     * timed poll() throws InterruptedException immediately if
322     * interrupted before waiting
323     */
324    public void testTimedPollFromEmptyAfterInterrupt() {
325        final BlockingQueue q = emptyCollection();
326        Thread t = newStartedThread(new CheckedRunnable() {
327            public void realRun() {
328                Thread.currentThread().interrupt();
329                try {
330                    q.poll(2 * LONG_DELAY_MS, MILLISECONDS);
331                    shouldThrow();
332                } catch (InterruptedException success) {}
333                assertFalse(Thread.interrupted());
334            }});
335
336        awaitTermination(t);
337    }
338
339    /**
340     * remove(x) removes x and returns true if present
341     * TODO: move to superclass CollectionTest.java
342     */
343    public void testRemoveElement() {
344        final BlockingQueue q = emptyCollection();
345        final int size = Math.min(q.remainingCapacity(), SIZE);
346        final Object[] elts = new Object[size];
347        assertFalse(q.contains(makeElement(99)));
348        assertFalse(q.remove(makeElement(99)));
349        checkEmpty(q);
350        for (int i = 0; i < size; i++)
351            q.add(elts[i] = makeElement(i));
352        for (int i = 1; i < size; i += 2) {
353            for (int pass = 0; pass < 2; pass++) {
354                assertEquals((pass == 0), q.contains(elts[i]));
355                assertEquals((pass == 0), q.remove(elts[i]));
356                assertFalse(q.contains(elts[i]));
357                assertTrue(q.contains(elts[i - 1]));
358                if (i < size - 1)
359                    assertTrue(q.contains(elts[i + 1]));
360            }
361        }
362        if (size > 0)
363            assertTrue(q.contains(elts[0]));
364        for (int i = size - 2; i >= 0; i -= 2) {
365            assertTrue(q.contains(elts[i]));
366            assertFalse(q.contains(elts[i + 1]));
367            assertTrue(q.remove(elts[i]));
368            assertFalse(q.contains(elts[i]));
369            assertFalse(q.remove(elts[i + 1]));
370            assertFalse(q.contains(elts[i + 1]));
371        }
372        checkEmpty(q);
373    }
374
375    /** For debugging. */
376    public void XXXXtestFails() {
377        fail(emptyCollection().getClass().toString());
378    }
379
380}
381