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