1/*
2 * Written by Doug Lea with assistance from members of JCP JSR-166
3 * Expert Group and released to the public domain, as explained at
4 * http://creativecommons.org/publicdomain/zero/1.0/
5 * Other contributors include Andrew Wright, Jeffrey Hayes,
6 * Pat Fisher, Mike Judd.
7 */
8
9package jsr166;
10
11import static java.util.concurrent.TimeUnit.MILLISECONDS;
12
13import java.util.ArrayList;
14import java.util.Arrays;
15import java.util.Collection;
16import java.util.Comparator;
17import java.util.Iterator;
18import java.util.NoSuchElementException;
19import java.util.Queue;
20import java.util.concurrent.BlockingQueue;
21import java.util.concurrent.CountDownLatch;
22import java.util.concurrent.Executors;
23import java.util.concurrent.ExecutorService;
24import java.util.concurrent.PriorityBlockingQueue;
25
26import junit.framework.Test;
27
28public class PriorityBlockingQueueTest extends JSR166TestCase {
29
30    // android-note: These tests have been moved into their own separate
31    // classes to work around CTS issues.
32    //
33    // public static class Generic extends BlockingQueueTest {
34    //     protected BlockingQueue emptyCollection() {
35    //         return new PriorityBlockingQueue();
36    //     }
37    // }
38
39    // public static class InitialCapacity extends BlockingQueueTest {
40    //     protected BlockingQueue emptyCollection() {
41    //         return new PriorityBlockingQueue(SIZE);
42    //     }
43    // }
44
45    // android-note: Removed because the CTS runner does a bad job of
46    // retrying tests that have suite() declarations.
47    //
48    // public static void main(String[] args) {
49    //     main(suite(), args);
50    // }
51    // public static Test suite() {
52    //     return newTestSuite(PriorityBlockingQueueTest.class,
53    //                         new Generic().testSuite(),
54    //                         new InitialCapacity().testSuite());
55    // }
56
57    /** Sample Comparator */
58    static class MyReverseComparator implements Comparator {
59        public int compare(Object x, Object y) {
60            return ((Comparable)y).compareTo(x);
61        }
62    }
63
64    /**
65     * Returns a new queue of given size containing consecutive
66     * Integers 0 ... n.
67     */
68    private PriorityBlockingQueue<Integer> populatedQueue(int n) {
69        PriorityBlockingQueue<Integer> q =
70            new PriorityBlockingQueue<Integer>(n);
71        assertTrue(q.isEmpty());
72        for (int i = n - 1; i >= 0; i -= 2)
73            assertTrue(q.offer(new Integer(i)));
74        for (int i = (n & 1); i < n; i += 2)
75            assertTrue(q.offer(new Integer(i)));
76        assertFalse(q.isEmpty());
77        assertEquals(Integer.MAX_VALUE, q.remainingCapacity());
78        assertEquals(n, q.size());
79        return q;
80    }
81
82    /**
83     * A new queue has unbounded capacity
84     */
85    public void testConstructor1() {
86        assertEquals(Integer.MAX_VALUE,
87                     new PriorityBlockingQueue(SIZE).remainingCapacity());
88    }
89
90    /**
91     * Constructor throws IAE if capacity argument nonpositive
92     */
93    public void testConstructor2() {
94        try {
95            new PriorityBlockingQueue(0);
96            shouldThrow();
97        } catch (IllegalArgumentException success) {}
98    }
99
100    /**
101     * Initializing from null Collection throws NPE
102     */
103    public void testConstructor3() {
104        try {
105            new PriorityBlockingQueue(null);
106            shouldThrow();
107        } catch (NullPointerException success) {}
108    }
109
110    /**
111     * Initializing from Collection of null elements throws NPE
112     */
113    public void testConstructor4() {
114        Collection<Integer> elements = Arrays.asList(new Integer[SIZE]);
115        try {
116            new PriorityBlockingQueue(elements);
117            shouldThrow();
118        } catch (NullPointerException success) {}
119    }
120
121    /**
122     * Initializing from Collection with some null elements throws NPE
123     */
124    public void testConstructor5() {
125        Integer[] ints = new Integer[SIZE];
126        for (int i = 0; i < SIZE - 1; ++i)
127            ints[i] = i;
128        Collection<Integer> elements = Arrays.asList(ints);
129        try {
130            new PriorityBlockingQueue(elements);
131            shouldThrow();
132        } catch (NullPointerException success) {}
133    }
134
135    /**
136     * Queue contains all elements of collection used to initialize
137     */
138    public void testConstructor6() {
139        Integer[] ints = new Integer[SIZE];
140        for (int i = 0; i < SIZE; ++i)
141            ints[i] = i;
142        PriorityBlockingQueue q = new PriorityBlockingQueue(Arrays.asList(ints));
143        for (int i = 0; i < SIZE; ++i)
144            assertEquals(ints[i], q.poll());
145    }
146
147    /**
148     * The comparator used in constructor is used
149     */
150    public void testConstructor7() {
151        MyReverseComparator cmp = new MyReverseComparator();
152        PriorityBlockingQueue q = new PriorityBlockingQueue(SIZE, cmp);
153        assertEquals(cmp, q.comparator());
154        Integer[] ints = new Integer[SIZE];
155        for (int i = 0; i < SIZE; ++i)
156            ints[i] = new Integer(i);
157        q.addAll(Arrays.asList(ints));
158        for (int i = SIZE - 1; i >= 0; --i)
159            assertEquals(ints[i], q.poll());
160    }
161
162    /**
163     * isEmpty is true before add, false after
164     */
165    public void testEmpty() {
166        PriorityBlockingQueue q = new PriorityBlockingQueue(2);
167        assertTrue(q.isEmpty());
168        assertEquals(Integer.MAX_VALUE, q.remainingCapacity());
169        q.add(one);
170        assertFalse(q.isEmpty());
171        q.add(two);
172        q.remove();
173        q.remove();
174        assertTrue(q.isEmpty());
175    }
176
177    /**
178     * remainingCapacity() always returns Integer.MAX_VALUE
179     */
180    public void testRemainingCapacity() {
181        BlockingQueue q = populatedQueue(SIZE);
182        for (int i = 0; i < SIZE; ++i) {
183            assertEquals(Integer.MAX_VALUE, q.remainingCapacity());
184            assertEquals(SIZE - i, q.size());
185            assertEquals(i, q.remove());
186        }
187        for (int i = 0; i < SIZE; ++i) {
188            assertEquals(Integer.MAX_VALUE, q.remainingCapacity());
189            assertEquals(i, q.size());
190            assertTrue(q.add(i));
191        }
192    }
193
194    /**
195     * Offer of comparable element succeeds
196     */
197    public void testOffer() {
198        PriorityBlockingQueue q = new PriorityBlockingQueue(1);
199        assertTrue(q.offer(zero));
200        assertTrue(q.offer(one));
201    }
202
203    /**
204     * Offer of non-Comparable throws CCE
205     */
206    public void testOfferNonComparable() {
207        PriorityBlockingQueue q = new PriorityBlockingQueue(1);
208        try {
209            q.offer(new Object());
210            q.offer(new Object());
211            shouldThrow();
212        } catch (ClassCastException success) {}
213    }
214
215    /**
216     * add of comparable succeeds
217     */
218    public void testAdd() {
219        PriorityBlockingQueue q = new PriorityBlockingQueue(SIZE);
220        for (int i = 0; i < SIZE; ++i) {
221            assertEquals(i, q.size());
222            assertTrue(q.add(new Integer(i)));
223        }
224    }
225
226    /**
227     * addAll(this) throws IAE
228     */
229    public void testAddAllSelf() {
230        PriorityBlockingQueue q = populatedQueue(SIZE);
231        try {
232            q.addAll(q);
233            shouldThrow();
234        } catch (IllegalArgumentException success) {}
235    }
236
237    /**
238     * addAll of a collection with any null elements throws NPE after
239     * possibly adding some elements
240     */
241    public void testAddAll3() {
242        PriorityBlockingQueue q = new PriorityBlockingQueue(SIZE);
243        Integer[] ints = new Integer[SIZE];
244        for (int i = 0; i < SIZE - 1; ++i)
245            ints[i] = new Integer(i);
246        try {
247            q.addAll(Arrays.asList(ints));
248            shouldThrow();
249        } catch (NullPointerException success) {}
250    }
251
252    /**
253     * Queue contains all elements of successful addAll
254     */
255    public void testAddAll5() {
256        Integer[] empty = new Integer[0];
257        Integer[] ints = new Integer[SIZE];
258        for (int i = SIZE - 1; i >= 0; --i)
259            ints[i] = new Integer(i);
260        PriorityBlockingQueue q = new PriorityBlockingQueue(SIZE);
261        assertFalse(q.addAll(Arrays.asList(empty)));
262        assertTrue(q.addAll(Arrays.asList(ints)));
263        for (int i = 0; i < SIZE; ++i)
264            assertEquals(ints[i], q.poll());
265    }
266
267    /**
268     * all elements successfully put are contained
269     */
270    public void testPut() {
271        PriorityBlockingQueue q = new PriorityBlockingQueue(SIZE);
272        for (int i = 0; i < SIZE; ++i) {
273            Integer x = new Integer(i);
274            q.put(x);
275            assertTrue(q.contains(x));
276        }
277        assertEquals(SIZE, q.size());
278    }
279
280    /**
281     * put doesn't block waiting for take
282     */
283    public void testPutWithTake() throws InterruptedException {
284        final PriorityBlockingQueue q = new PriorityBlockingQueue(2);
285        final int size = 4;
286        Thread t = newStartedThread(new CheckedRunnable() {
287            public void realRun() {
288                for (int i = 0; i < size; i++)
289                    q.put(new Integer(0));
290            }});
291
292        awaitTermination(t);
293        assertEquals(size, q.size());
294        q.take();
295    }
296
297    /**
298     * timed offer does not time out
299     */
300    public void testTimedOffer() throws InterruptedException {
301        final PriorityBlockingQueue q = new PriorityBlockingQueue(2);
302        Thread t = newStartedThread(new CheckedRunnable() {
303            public void realRun() {
304                q.put(new Integer(0));
305                q.put(new Integer(0));
306                assertTrue(q.offer(new Integer(0), SHORT_DELAY_MS, MILLISECONDS));
307                assertTrue(q.offer(new Integer(0), LONG_DELAY_MS, MILLISECONDS));
308            }});
309
310        awaitTermination(t);
311    }
312
313    /**
314     * take retrieves elements in priority order
315     */
316    public void testTake() throws InterruptedException {
317        PriorityBlockingQueue q = populatedQueue(SIZE);
318        for (int i = 0; i < SIZE; ++i) {
319            assertEquals(i, q.take());
320        }
321    }
322
323    /**
324     * Take removes existing elements until empty, then blocks interruptibly
325     */
326    public void testBlockingTake() throws InterruptedException {
327        final PriorityBlockingQueue q = populatedQueue(SIZE);
328        final CountDownLatch pleaseInterrupt = new CountDownLatch(1);
329        Thread t = newStartedThread(new CheckedRunnable() {
330            public void realRun() throws InterruptedException {
331                for (int i = 0; i < SIZE; ++i) {
332                    assertEquals(i, q.take());
333                }
334
335                Thread.currentThread().interrupt();
336                try {
337                    q.take();
338                    shouldThrow();
339                } catch (InterruptedException success) {}
340                assertFalse(Thread.interrupted());
341
342                pleaseInterrupt.countDown();
343                try {
344                    q.take();
345                    shouldThrow();
346                } catch (InterruptedException success) {}
347                assertFalse(Thread.interrupted());
348            }});
349
350        await(pleaseInterrupt);
351        assertThreadStaysAlive(t);
352        t.interrupt();
353        awaitTermination(t);
354    }
355
356    /**
357     * poll succeeds unless empty
358     */
359    public void testPoll() {
360        PriorityBlockingQueue q = populatedQueue(SIZE);
361        for (int i = 0; i < SIZE; ++i) {
362            assertEquals(i, q.poll());
363        }
364        assertNull(q.poll());
365    }
366
367    /**
368     * timed poll with zero timeout succeeds when non-empty, else times out
369     */
370    public void testTimedPoll0() throws InterruptedException {
371        PriorityBlockingQueue q = populatedQueue(SIZE);
372        for (int i = 0; i < SIZE; ++i) {
373            assertEquals(i, q.poll(0, MILLISECONDS));
374        }
375        assertNull(q.poll(0, MILLISECONDS));
376    }
377
378    /**
379     * timed poll with nonzero timeout succeeds when non-empty, else times out
380     */
381    public void testTimedPoll() throws InterruptedException {
382        PriorityBlockingQueue<Integer> q = populatedQueue(SIZE);
383        for (int i = 0; i < SIZE; ++i) {
384            long startTime = System.nanoTime();
385            assertEquals(i, (int) q.poll(LONG_DELAY_MS, MILLISECONDS));
386            assertTrue(millisElapsedSince(startTime) < LONG_DELAY_MS);
387        }
388        long startTime = System.nanoTime();
389        assertNull(q.poll(timeoutMillis(), MILLISECONDS));
390        assertTrue(millisElapsedSince(startTime) >= timeoutMillis());
391        checkEmpty(q);
392    }
393
394    /**
395     * Interrupted timed poll throws InterruptedException instead of
396     * returning timeout status
397     */
398    public void testInterruptedTimedPoll() throws InterruptedException {
399        final BlockingQueue<Integer> q = populatedQueue(SIZE);
400        final CountDownLatch aboutToWait = new CountDownLatch(1);
401        Thread t = newStartedThread(new CheckedRunnable() {
402            public void realRun() throws InterruptedException {
403                long startTime = System.nanoTime();
404                for (int i = 0; i < SIZE; ++i) {
405                    assertEquals(i, (int) q.poll(LONG_DELAY_MS, MILLISECONDS));
406                }
407                aboutToWait.countDown();
408                try {
409                    q.poll(LONG_DELAY_MS, MILLISECONDS);
410                    shouldThrow();
411                } catch (InterruptedException success) {
412                    assertTrue(millisElapsedSince(startTime) < LONG_DELAY_MS);
413                }
414            }});
415
416        aboutToWait.await();
417        waitForThreadToEnterWaitState(t, LONG_DELAY_MS);
418        t.interrupt();
419        awaitTermination(t);
420    }
421
422    /**
423     * peek returns next element, or null if empty
424     */
425    public void testPeek() {
426        PriorityBlockingQueue q = populatedQueue(SIZE);
427        for (int i = 0; i < SIZE; ++i) {
428            assertEquals(i, q.peek());
429            assertEquals(i, q.poll());
430            assertTrue(q.peek() == null ||
431                       !q.peek().equals(i));
432        }
433        assertNull(q.peek());
434    }
435
436    /**
437     * element returns next element, or throws NSEE if empty
438     */
439    public void testElement() {
440        PriorityBlockingQueue q = populatedQueue(SIZE);
441        for (int i = 0; i < SIZE; ++i) {
442            assertEquals(i, q.element());
443            assertEquals(i, q.poll());
444        }
445        try {
446            q.element();
447            shouldThrow();
448        } catch (NoSuchElementException success) {}
449    }
450
451    /**
452     * remove removes next element, or throws NSEE if empty
453     */
454    public void testRemove() {
455        PriorityBlockingQueue q = populatedQueue(SIZE);
456        for (int i = 0; i < SIZE; ++i) {
457            assertEquals(i, q.remove());
458        }
459        try {
460            q.remove();
461            shouldThrow();
462        } catch (NoSuchElementException success) {}
463    }
464
465    /**
466     * contains(x) reports true when elements added but not yet removed
467     */
468    public void testContains() {
469        PriorityBlockingQueue q = populatedQueue(SIZE);
470        for (int i = 0; i < SIZE; ++i) {
471            assertTrue(q.contains(new Integer(i)));
472            q.poll();
473            assertFalse(q.contains(new Integer(i)));
474        }
475    }
476
477    /**
478     * clear removes all elements
479     */
480    public void testClear() {
481        PriorityBlockingQueue q = populatedQueue(SIZE);
482        q.clear();
483        assertTrue(q.isEmpty());
484        assertEquals(0, q.size());
485        q.add(one);
486        assertFalse(q.isEmpty());
487        assertTrue(q.contains(one));
488        q.clear();
489        assertTrue(q.isEmpty());
490    }
491
492    /**
493     * containsAll(c) is true when c contains a subset of elements
494     */
495    public void testContainsAll() {
496        PriorityBlockingQueue q = populatedQueue(SIZE);
497        PriorityBlockingQueue p = new PriorityBlockingQueue(SIZE);
498        for (int i = 0; i < SIZE; ++i) {
499            assertTrue(q.containsAll(p));
500            assertFalse(p.containsAll(q));
501            p.add(new Integer(i));
502        }
503        assertTrue(p.containsAll(q));
504    }
505
506    /**
507     * retainAll(c) retains only those elements of c and reports true if changed
508     */
509    public void testRetainAll() {
510        PriorityBlockingQueue q = populatedQueue(SIZE);
511        PriorityBlockingQueue p = populatedQueue(SIZE);
512        for (int i = 0; i < SIZE; ++i) {
513            boolean changed = q.retainAll(p);
514            if (i == 0)
515                assertFalse(changed);
516            else
517                assertTrue(changed);
518
519            assertTrue(q.containsAll(p));
520            assertEquals(SIZE - i, q.size());
521            p.remove();
522        }
523    }
524
525    /**
526     * removeAll(c) removes only those elements of c and reports true if changed
527     */
528    public void testRemoveAll() {
529        for (int i = 1; i < SIZE; ++i) {
530            PriorityBlockingQueue q = populatedQueue(SIZE);
531            PriorityBlockingQueue p = populatedQueue(i);
532            assertTrue(q.removeAll(p));
533            assertEquals(SIZE - i, q.size());
534            for (int j = 0; j < i; ++j) {
535                Integer x = (Integer)(p.remove());
536                assertFalse(q.contains(x));
537            }
538        }
539    }
540
541    /**
542     * toArray contains all elements
543     */
544    public void testToArray() throws InterruptedException {
545        PriorityBlockingQueue q = populatedQueue(SIZE);
546        Object[] o = q.toArray();
547        Arrays.sort(o);
548        for (int i = 0; i < o.length; i++)
549            assertSame(o[i], q.take());
550    }
551
552    /**
553     * toArray(a) contains all elements
554     */
555    public void testToArray2() throws InterruptedException {
556        PriorityBlockingQueue<Integer> q = populatedQueue(SIZE);
557        Integer[] ints = new Integer[SIZE];
558        Integer[] array = q.toArray(ints);
559        assertSame(ints, array);
560        Arrays.sort(ints);
561        for (int i = 0; i < ints.length; i++)
562            assertSame(ints[i], q.take());
563    }
564
565    /**
566     * toArray(incompatible array type) throws ArrayStoreException
567     */
568    public void testToArray1_BadArg() {
569        PriorityBlockingQueue q = populatedQueue(SIZE);
570        try {
571            q.toArray(new String[10]);
572            shouldThrow();
573        } catch (ArrayStoreException success) {}
574    }
575
576    /**
577     * iterator iterates through all elements
578     */
579    public void testIterator() {
580        PriorityBlockingQueue q = populatedQueue(SIZE);
581        Iterator it = q.iterator();
582        int i;
583        for (i = 0; it.hasNext(); i++)
584            assertTrue(q.contains(it.next()));
585        assertEquals(i, SIZE);
586        assertIteratorExhausted(it);
587    }
588
589    /**
590     * iterator of empty collection has no elements
591     */
592    public void testEmptyIterator() {
593        assertIteratorExhausted(new PriorityBlockingQueue().iterator());
594    }
595
596    /**
597     * iterator.remove removes current element
598     */
599    public void testIteratorRemove() {
600        final PriorityBlockingQueue q = new PriorityBlockingQueue(3);
601        q.add(new Integer(2));
602        q.add(new Integer(1));
603        q.add(new Integer(3));
604
605        Iterator it = q.iterator();
606        it.next();
607        it.remove();
608
609        it = q.iterator();
610        assertEquals(it.next(), new Integer(2));
611        assertEquals(it.next(), new Integer(3));
612        assertFalse(it.hasNext());
613    }
614
615    /**
616     * toString contains toStrings of elements
617     */
618    public void testToString() {
619        PriorityBlockingQueue q = populatedQueue(SIZE);
620        String s = q.toString();
621        for (int i = 0; i < SIZE; ++i) {
622            assertTrue(s.contains(String.valueOf(i)));
623        }
624    }
625
626    /**
627     * timed poll transfers elements across Executor tasks
628     */
629    public void testPollInExecutor() {
630        final PriorityBlockingQueue q = new PriorityBlockingQueue(2);
631        final CheckedBarrier threadsStarted = new CheckedBarrier(2);
632        final ExecutorService executor = Executors.newFixedThreadPool(2);
633        try (PoolCleaner cleaner = cleaner(executor)) {
634            executor.execute(new CheckedRunnable() {
635                public void realRun() throws InterruptedException {
636                    assertNull(q.poll());
637                    threadsStarted.await();
638                    assertSame(one, q.poll(LONG_DELAY_MS, MILLISECONDS));
639                    checkEmpty(q);
640                }});
641
642            executor.execute(new CheckedRunnable() {
643                public void realRun() throws InterruptedException {
644                    threadsStarted.await();
645                    q.put(one);
646                }});
647        }
648    }
649
650    /**
651     * A deserialized serialized queue has same elements
652     */
653    public void testSerialization() throws Exception {
654        Queue x = populatedQueue(SIZE);
655        Queue y = serialClone(x);
656
657        assertNotSame(x, y);
658        assertEquals(x.size(), y.size());
659        while (!x.isEmpty()) {
660            assertFalse(y.isEmpty());
661            assertEquals(x.remove(), y.remove());
662        }
663        assertTrue(y.isEmpty());
664    }
665
666    /**
667     * drainTo(c) empties queue into another collection c
668     */
669    public void testDrainTo() {
670        PriorityBlockingQueue q = populatedQueue(SIZE);
671        ArrayList l = new ArrayList();
672        q.drainTo(l);
673        assertEquals(0, q.size());
674        assertEquals(SIZE, l.size());
675        for (int i = 0; i < SIZE; ++i)
676            assertEquals(l.get(i), new Integer(i));
677        q.add(zero);
678        q.add(one);
679        assertFalse(q.isEmpty());
680        assertTrue(q.contains(zero));
681        assertTrue(q.contains(one));
682        l.clear();
683        q.drainTo(l);
684        assertEquals(0, q.size());
685        assertEquals(2, l.size());
686        for (int i = 0; i < 2; ++i)
687            assertEquals(l.get(i), new Integer(i));
688    }
689
690    /**
691     * drainTo empties queue
692     */
693    public void testDrainToWithActivePut() throws InterruptedException {
694        final PriorityBlockingQueue q = populatedQueue(SIZE);
695        Thread t = new Thread(new CheckedRunnable() {
696            public void realRun() {
697                q.put(new Integer(SIZE + 1));
698            }});
699
700        t.start();
701        ArrayList l = new ArrayList();
702        q.drainTo(l);
703        assertTrue(l.size() >= SIZE);
704        for (int i = 0; i < SIZE; ++i)
705            assertEquals(l.get(i), new Integer(i));
706        t.join();
707        assertTrue(q.size() + l.size() >= SIZE);
708    }
709
710    /**
711     * drainTo(c, n) empties first min(n, size) elements of queue into c
712     */
713    public void testDrainToN() {
714        PriorityBlockingQueue q = new PriorityBlockingQueue(SIZE * 2);
715        for (int i = 0; i < SIZE + 2; ++i) {
716            for (int j = 0; j < SIZE; j++)
717                assertTrue(q.offer(new Integer(j)));
718            ArrayList l = new ArrayList();
719            q.drainTo(l, i);
720            int k = (i < SIZE) ? i : SIZE;
721            assertEquals(k, l.size());
722            assertEquals(SIZE - k, q.size());
723            for (int j = 0; j < k; ++j)
724                assertEquals(l.get(j), new Integer(j));
725            do {} while (q.poll() != null);
726        }
727    }
728
729    /**
730     * remove(null), contains(null) always return false
731     */
732    public void testNeverContainsNull() {
733        Collection<?>[] qs = {
734            new PriorityBlockingQueue<Object>(),
735            populatedQueue(2),
736        };
737
738        for (Collection<?> q : qs) {
739            assertFalse(q.contains(null));
740            assertFalse(q.remove(null));
741        }
742    }
743
744}
745