1/* 2 * Copyright (C) 2011 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 17package libcore.java.lang.ref; 18 19import java.lang.ref.ReferenceQueue; 20import java.lang.ref.WeakReference; 21import java.util.concurrent.CountDownLatch; 22import java.util.concurrent.ScheduledThreadPoolExecutor; 23import java.util.concurrent.TimeUnit; 24 25import junit.framework.TestCase; 26import sun.misc.Cleaner; 27 28public final class ReferenceQueueTest extends TestCase { 29 30 public void testRemoveWithInvalidTimeout() throws Exception { 31 ReferenceQueue<Object> referenceQueue = new ReferenceQueue<Object>(); 32 try { 33 referenceQueue.remove(-1); 34 fail(); 35 } catch (IllegalArgumentException expected) { 36 } 37 } 38 39 public void testRemoveWithVeryLargeTimeout() throws Exception { 40 ReferenceQueue<Object> referenceQueue = new ReferenceQueue<Object>(); 41 enqueueLater(referenceQueue, 500); 42 referenceQueue.remove(Long.MAX_VALUE); 43 } 44 45 public void testRemoveWithSpuriousNotify() throws Exception { 46 final ReferenceQueue<Object> referenceQueue = new ReferenceQueue<Object>(); 47 48 runLater(new Runnable() { 49 @Override public void run() { 50 synchronized (referenceQueue) { 51 referenceQueue.notifyAll(); 52 } 53 } 54 }, 500); 55 56 long startNanos = System.nanoTime(); 57 referenceQueue.remove(1000); 58 long durationNanos = System.nanoTime() - startNanos; 59 long durationMillis = TimeUnit.NANOSECONDS.toMillis(durationNanos); 60 assertTrue(durationMillis > 750 && durationMillis < 1250); 61 } 62 63 public void testRemoveWithImmediateResultAndNoTimeout() throws Exception { 64 ReferenceQueue<Object> referenceQueue = new ReferenceQueue<Object>(); 65 enqueue(referenceQueue); 66 assertNotNull(referenceQueue.remove()); 67 } 68 69 public void testRemoveWithImmediateResultAndTimeout() throws Exception { 70 ReferenceQueue<Object> referenceQueue = new ReferenceQueue<Object>(); 71 enqueue(referenceQueue); 72 assertNotNull(referenceQueue.remove(1000)); 73 } 74 75 public void testRemoveWithDelayedResultAndNoTimeout() throws Exception { 76 ReferenceQueue<Object> referenceQueue = new ReferenceQueue<Object>(); 77 enqueueLater(referenceQueue, 500); 78 long startNanos = System.nanoTime(); 79 referenceQueue.remove(); 80 long durationNanos = System.nanoTime() - startNanos; 81 long durationMillis = TimeUnit.NANOSECONDS.toMillis(durationNanos); 82 assertTrue(durationMillis > 250 && durationMillis < 750); 83 } 84 85 public void testRemoveWithDelayedResultAndTimeout() throws Exception { 86 ReferenceQueue<Object> referenceQueue = new ReferenceQueue<Object>(); 87 enqueueLater(referenceQueue, 500); 88 long startNanos = System.nanoTime(); 89 referenceQueue.remove(1000); 90 long durationNanos = System.nanoTime() - startNanos; 91 long durationMillis = TimeUnit.NANOSECONDS.toMillis(durationNanos); 92 assertTrue(durationMillis > 250 && durationMillis < 750); 93 } 94 95 public void testCleanersCleaned() { 96 Object object = new Object(); 97 final CountDownLatch cdl = new CountDownLatch(1); 98 99 Cleaner cleaner = Cleaner.create(object, new Runnable() { 100 @Override 101 public void run() { 102 cdl.countDown(); 103 } 104 }); 105 106 boolean countedDown = false; 107 object = null; 108 for (int i = 0; i < 5; ++i) { 109 Runtime.getRuntime().gc(); 110 try { 111 countedDown = cdl.await(1000, TimeUnit.MILLISECONDS); 112 if (countedDown) { 113 break; 114 } 115 } catch (InterruptedException ie) { 116 fail(); 117 } 118 } 119 120 assertTrue(countedDown); 121 } 122 123 private void runLater(Runnable runnable, int delayMillis) { 124 ScheduledThreadPoolExecutor executor = new ScheduledThreadPoolExecutor(1); 125 executor.schedule(runnable, delayMillis, TimeUnit.MILLISECONDS); 126 executor.shutdown(); 127 } 128 129 private void enqueueLater(final ReferenceQueue<Object> queue, int delayMillis) { 130 runLater(new Runnable() { 131 @Override public void run() { 132 enqueue(queue); 133 } 134 }, delayMillis); 135 } 136 137 private void enqueue(ReferenceQueue<Object> queue) { 138 new WeakReference<Object>(new Object(), queue).enqueue(); 139 } 140} 141