Home | History | Annotate | Download | only in util
      1 /*
      2  * Copyright (C) 2010 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 package com.android.tradefed.util;
     17 
     18 import com.android.tradefed.util.ConditionPriorityBlockingQueue.IMatcher;
     19 
     20 import junit.framework.TestCase;
     21 
     22 import java.util.Comparator;
     23 import java.util.concurrent.TimeUnit;
     24 
     25 /**
     26  * Unit tests for {@link ConditionPriorityBlockingQueue}.
     27  */
     28 public class ConditionPriorityBlockingQueueTest extends TestCase {
     29 
     30     private ConditionPriorityBlockingQueue<Integer> mQueue;
     31 
     32     /**
     33      * {@inheritDoc}
     34      */
     35     @Override
     36     protected void setUp() throws Exception {
     37         super.setUp();
     38         mQueue = new ConditionPriorityBlockingQueue<Integer>(new IntCompare());
     39     }
     40 
     41     /**
     42      * Test {@link ConditionPriorityBlockingQueue#poll()} when queue is empty.
     43      */
     44     public void testPoll_empty() {
     45         assertNull(mQueue.poll());
     46     }
     47 
     48     /**
     49      * Test {@link ConditionPriorityBlockingQueue#take()} when a single object is in queue.
     50      */
     51     public void testTake() throws InterruptedException {
     52         Integer one = Integer.valueOf(1);
     53         mQueue.add(one);
     54         assertEquals(one, mQueue.take());
     55         assertNull(mQueue.poll());
     56     }
     57 
     58     /**
     59      * Test {@link ConditionPriorityBlockingQueue#take()} when multiple objects are in queue, and
     60      * verify objects are returned in expected order.
     61      */
     62     public void testTake_priority() throws InterruptedException {
     63         Integer one = Integer.valueOf(1);
     64         Integer two = Integer.valueOf(2);
     65         mQueue.add(two);
     66         mQueue.add(one);
     67         assertEquals(one, mQueue.take());
     68         assertEquals(two, mQueue.take());
     69         assertNull(mQueue.poll());
     70     }
     71 
     72     /**
     73      * Test {@link ConditionPriorityBlockingQueue#poll()} when using FIFO ordering.
     74      */
     75     public void testTake_fifo() throws InterruptedException {
     76         ConditionPriorityBlockingQueue<Integer> fifoQueue =
     77             new ConditionPriorityBlockingQueue<Integer>();
     78         Integer one = Integer.valueOf(1);
     79         Integer two = Integer.valueOf(2);
     80         fifoQueue.add(two);
     81         fifoQueue.add(one);
     82         assertEquals(two, fifoQueue.take());
     83         assertEquals(one, fifoQueue.take());
     84         assertNull(fifoQueue.poll());
     85     }
     86 
     87     /**
     88      * Same as {@link ConditionPriorityBlockingQueueTest#testTake_priority()}, but add the test
     89      * objects in inverse order.
     90      */
     91     public void testTake_priorityReverse() throws InterruptedException {
     92         Integer one = Integer.valueOf(1);
     93         Integer two = Integer.valueOf(2);
     94         mQueue.add(one);
     95         mQueue.add(two);
     96         assertEquals(one, mQueue.take());
     97         assertEquals(two, mQueue.take());
     98         assertNull(mQueue.poll());
     99     }
    100 
    101     /**
    102      * Test {@link ConditionPriorityBlockingQueue#take()} when object is not initially present.
    103      */
    104     public void testTake_delayedAdd() throws InterruptedException {
    105         final Integer one = Integer.valueOf(1);
    106         Thread delayedAdd = new Thread() {
    107             @Override
    108             public void run() {
    109                 try {
    110                     sleep(200);
    111                 } catch (InterruptedException e) {
    112                 }
    113                 mQueue.add(one);
    114             }
    115         };
    116         delayedAdd.setName(getClass().getCanonicalName());
    117         delayedAdd.start();
    118         assertEquals(one, mQueue.take());
    119         assertNull(mQueue.poll());
    120     }
    121 
    122     /**
    123      * Test {@link ConditionPriorityBlockingQueue#take(IMatcher)} when object that matches is not
    124      * initially present.
    125      */
    126     public void testTake_matcher_delayedAdd() throws InterruptedException {
    127         final Integer one = Integer.valueOf(1);
    128         final Integer two = Integer.valueOf(2);
    129         mQueue.add(two);
    130         Thread delayedAdd = new Thread() {
    131             @Override
    132             public void run() {
    133                 try {
    134                     sleep(200);
    135                 } catch (InterruptedException e) {
    136                 }
    137                 mQueue.add(one);
    138             }
    139         };
    140         delayedAdd.setName(getClass().getCanonicalName());
    141         delayedAdd.start();
    142         assertEquals(one, mQueue.take(new OneMatcher()));
    143         assertNull(mQueue.poll(new OneMatcher()));
    144         assertEquals(two, mQueue.poll());
    145     }
    146 
    147     /**
    148      * Test {@link ConditionPriorityBlockingQueue#take(IMatcher)} when multiple threads are waiting
    149      */
    150     public void testTake_multiple_matchers() throws InterruptedException {
    151         final Integer one = Integer.valueOf(1);
    152         final Integer second_one = Integer.valueOf(1);
    153 
    154         Thread waiter = new Thread() {
    155             @Override
    156             public void run() {
    157                 try {
    158                     mQueue.take(new OneMatcher());
    159                 } catch (InterruptedException e) {
    160 
    161                 }
    162             }
    163         };
    164         waiter.setName(getClass().getCanonicalName() + "#testTake_multiple_matchers");
    165         waiter.start();
    166         Thread waiter2 = new Thread() {
    167             @Override
    168             public void run() {
    169                 try {
    170                     mQueue.take(new OneMatcher());
    171                 } catch (InterruptedException e) {
    172                 }
    173             }
    174         };
    175         waiter2.setName(getClass().getCanonicalName() + "#testTake_multiple_matchers");
    176         waiter2.start();
    177 
    178         Thread delayedAdd = new Thread() {
    179             @Override
    180             public void run() {
    181                 try {
    182                     sleep(200);
    183                 } catch (InterruptedException e) {
    184                 }
    185                 mQueue.add(one);
    186             }
    187         };
    188         delayedAdd.setName(getClass().getCanonicalName() + "#testTake_multiple_matchers");
    189         delayedAdd.start();
    190         Thread delayedAdd2 = new Thread() {
    191             @Override
    192             public void run() {
    193                 try {
    194                     sleep(300);
    195                 } catch (InterruptedException e) {
    196                 }
    197                 mQueue.add(second_one);
    198             }
    199         };
    200         delayedAdd2.setName(getClass().getCanonicalName() + "#testTake_multiple_matchers");
    201         delayedAdd2.start();
    202 
    203         // wait for blocked threads to die. This test will deadlock if failed
    204         waiter.join();
    205         waiter2.join();
    206 
    207         assertNull(mQueue.poll());
    208     }
    209 
    210     /**
    211      * Test {@link ConditionPriorityBlockingQueue#poll(IMatcher)} when queue is empty.
    212      */
    213     public void testPoll_condition_empty() {
    214         assertNull(mQueue.poll(new OneMatcher()));
    215     }
    216 
    217     /**
    218      * Test {@link ConditionPriorityBlockingQueue#poll(long, TimeUnit, IMatcher)} when queue is
    219      * empty.
    220      */
    221     public void testPoll_time_empty() throws InterruptedException {
    222         assertNull(mQueue.poll(100, TimeUnit.MILLISECONDS, new OneMatcher()));
    223     }
    224 
    225     /**
    226      * Test {@link ConditionPriorityBlockingQueue#poll(IMatcher)} when object matches, and one
    227      * doesn't.
    228      */
    229     public void testPoll_condition() {
    230         Integer one = Integer.valueOf(1);
    231         Integer two = Integer.valueOf(2);
    232         mQueue.add(one);
    233         mQueue.add(two);
    234         assertEquals(one, mQueue.poll(new OneMatcher()));
    235         assertNull(mQueue.poll(new OneMatcher()));
    236     }
    237 
    238     /**
    239      * Test {@link ConditionPriorityBlockingQueue#poll(long, TimeUnit, IMatcher)} when object
    240      * matches, and one doesn't.
    241      */
    242     public void testPoll_time_condition() throws InterruptedException {
    243         Integer one = Integer.valueOf(1);
    244         Integer two = Integer.valueOf(2);
    245         mQueue.add(one);
    246         mQueue.add(two);
    247         assertEquals(one, mQueue.poll(100, TimeUnit.MILLISECONDS, new OneMatcher()));
    248         assertNull(mQueue.poll(100, TimeUnit.MILLISECONDS, new OneMatcher()));
    249     }
    250 
    251     /**
    252      * Test {@link ConditionPriorityBlockingQueue#poll(IMatcher)} when object matches, and one
    253      * doesn't, using FIFO ordering.
    254      */
    255     public void testPoll_fifo_condition() {
    256         ConditionPriorityBlockingQueue<Integer> fifoQueue =
    257             new ConditionPriorityBlockingQueue<Integer>();
    258         Integer one = Integer.valueOf(1);
    259         Integer two = Integer.valueOf(2);
    260         fifoQueue.add(two);
    261         fifoQueue.add(one);
    262         assertEquals(one, fifoQueue.poll(new OneMatcher()));
    263         assertNull(fifoQueue.poll(new OneMatcher()));
    264     }
    265 
    266     /**
    267      * Same as {@link ConditionPriorityBlockingQueueTest#testPoll_condition()}, but objects are
    268      * added in inverse order.
    269      */
    270     public void testPoll_condition_reverse() {
    271         Integer one = Integer.valueOf(1);
    272         Integer two = Integer.valueOf(2);
    273         mQueue.add(two);
    274         mQueue.add(one);
    275         assertEquals(one, mQueue.poll(new OneMatcher()));
    276         assertNull(mQueue.poll(new OneMatcher()));
    277     }
    278 
    279     /**
    280      * Test behavior when queue is modified during iteration
    281      * @throws Throwable
    282      */
    283     public void testModificationOnIterating() throws Throwable {
    284         final ConditionPriorityBlockingQueue<Integer> queue =
    285                 new ConditionPriorityBlockingQueue<Integer>(new IntCompare());
    286         for (int i = 0; i < 10; i++) {
    287             queue.add(i);
    288         }
    289         final Throwable[] throwables = new Throwable[1];
    290         Thread iterator = new Thread() {
    291             @Override
    292             public void run() {
    293                 try {
    294                     for (@SuppressWarnings("unused") Integer i : queue) {
    295                         Thread.sleep(10);
    296                     }
    297                 } catch (Throwable t) {
    298                     throwables[0] = t;
    299                 }
    300             }
    301         };
    302         iterator.setName(getClass().getCanonicalName() + "#testModificationOnIterating");
    303         iterator.start();
    304         for (int i = 0; i < 10 && throwables[0] == null; i++) {
    305             queue.add(i);
    306             Thread.sleep(10);
    307         }
    308         if (throwables[0] != null) {
    309             throw throwables[0];
    310         }
    311     }
    312 
    313     /**
    314      * A {@link Comparator} for {@link Integer}
    315      */
    316     private static class IntCompare implements Comparator<Integer> {
    317 
    318         @Override
    319         public int compare(Integer o1, Integer o2) {
    320             return o1.compareTo(o2);
    321         }
    322 
    323     }
    324 
    325     private static class OneMatcher implements IMatcher<Integer> {
    326 
    327         @Override
    328         public boolean matches(Integer element) {
    329             return element == 1;
    330         }
    331     }
    332 }
    333