1 // Copyright 2011 Google Inc. All Rights Reserved. 2 3 package com.google.common.testing; 4 5 import com.google.common.testing.GcFinalization.FinalizationPredicate; 6 import com.google.common.util.concurrent.SettableFuture; 7 8 import junit.framework.TestCase; 9 10 import java.lang.ref.WeakReference; 11 import java.util.WeakHashMap; 12 import java.util.concurrent.CountDownLatch; 13 import java.util.concurrent.atomic.AtomicBoolean; 14 15 /** 16 * Tests for {@link GcFinalization}. 17 * 18 * @author martinrb (at) google.com (Martin Buchholz) 19 * @author schmoe (at) google.com (mike nonemacher) 20 */ 21 22 public class GcFinalizationTest extends TestCase { 23 24 //---------------------------------------------------------------- 25 // Ordinary tests of successful method execution 26 //---------------------------------------------------------------- 27 28 public void testAwait_CountDownLatch() { 29 final CountDownLatch latch = new CountDownLatch(1); 30 Object x = new Object() { 31 protected void finalize() { latch.countDown(); } 32 }; 33 x = null; // Hint to the JIT that x is unreachable 34 GcFinalization.await(latch); 35 assertEquals(0, latch.getCount()); 36 } 37 38 public void testAwaitDone_Future() { 39 final SettableFuture<Void> future = SettableFuture.create(); 40 Object x = new Object() { 41 protected void finalize() { future.set(null); } 42 }; 43 x = null; // Hint to the JIT that x is unreachable 44 GcFinalization.awaitDone(future); 45 assertTrue(future.isDone()); 46 assertFalse(future.isCancelled()); 47 } 48 49 public void testAwaitDone_Future_Cancel() { 50 final SettableFuture<Void> future = SettableFuture.create(); 51 Object x = new Object() { 52 protected void finalize() { future.cancel(false); } 53 }; 54 x = null; // Hint to the JIT that x is unreachable 55 GcFinalization.awaitDone(future); 56 assertTrue(future.isDone()); 57 assertTrue(future.isCancelled()); 58 } 59 60 public void testAwaitClear() { 61 final WeakReference<Object> ref = new WeakReference<Object>(new Object()); 62 GcFinalization.awaitClear(ref); 63 assertNull(ref.get()); 64 } 65 66 public void testAwaitDone_FinalizationPredicate() { 67 final WeakHashMap<Object, Object> map = new WeakHashMap<Object, Object>(); 68 map.put(new Object(), Boolean.TRUE); 69 GcFinalization.awaitDone(new FinalizationPredicate() { 70 public boolean isDone() { 71 return map.isEmpty(); 72 } 73 }); 74 assertTrue(map.isEmpty()); 75 } 76 77 //---------------------------------------------------------------- 78 // Test that interrupts result in RuntimeException, not InterruptedException. 79 // Trickier than it looks, because runFinalization swallows interrupts. 80 //---------------------------------------------------------------- 81 82 class Interruptenator extends Thread { 83 final AtomicBoolean shutdown; 84 Interruptenator(final Thread interruptee) { 85 this(interruptee, new AtomicBoolean(false)); 86 } 87 Interruptenator(final Thread interruptee, 88 final AtomicBoolean shutdown) { 89 super(new Runnable() { 90 public void run() { 91 while (!shutdown.get()) { 92 interruptee.interrupt(); 93 Thread.yield(); 94 }}}); 95 this.shutdown = shutdown; 96 start(); 97 } 98 void shutdown() { 99 shutdown.set(true); 100 while (this.isAlive()) { 101 Thread.yield(); 102 } 103 } 104 } 105 106 void assertWrapsInterruptedException(RuntimeException e) { 107 assertTrue(e.getMessage().contains("Unexpected interrupt")); 108 assertTrue(e.getCause() instanceof InterruptedException); 109 } 110 111 public void testAwait_CountDownLatch_Interrupted() { 112 Interruptenator interruptenator = new Interruptenator(Thread.currentThread()); 113 try { 114 final CountDownLatch latch = new CountDownLatch(1); 115 try { 116 GcFinalization.await(latch); 117 fail("should throw"); 118 } catch (RuntimeException expected) { 119 assertWrapsInterruptedException(expected); 120 } 121 } finally { 122 interruptenator.shutdown(); 123 Thread.interrupted(); 124 } 125 } 126 127 public void testAwaitDone_Future_Interrupted_Interrupted() { 128 Interruptenator interruptenator = new Interruptenator(Thread.currentThread()); 129 try { 130 final SettableFuture<Void> future = SettableFuture.create(); 131 try { 132 GcFinalization.awaitDone(future); 133 fail("should throw"); 134 } catch (RuntimeException expected) { 135 assertWrapsInterruptedException(expected); 136 } 137 } finally { 138 interruptenator.shutdown(); 139 Thread.interrupted(); 140 } 141 } 142 143 public void testAwaitClear_Interrupted() { 144 Interruptenator interruptenator = new Interruptenator(Thread.currentThread()); 145 try { 146 final WeakReference<Object> ref = new WeakReference<Object>(Boolean.TRUE); 147 try { 148 GcFinalization.awaitClear(ref); 149 fail("should throw"); 150 } catch (RuntimeException expected) { 151 assertWrapsInterruptedException(expected); 152 } 153 } finally { 154 interruptenator.shutdown(); 155 Thread.interrupted(); 156 } 157 } 158 159 public void testAwaitDone_FinalizationPredicate_Interrupted() { 160 Interruptenator interruptenator = new Interruptenator(Thread.currentThread()); 161 try { 162 try { 163 GcFinalization.awaitDone(new FinalizationPredicate() { 164 public boolean isDone() { 165 return false; 166 } 167 }); 168 fail("should throw"); 169 } catch (RuntimeException expected) { 170 assertWrapsInterruptedException(expected); 171 } 172 } finally { 173 interruptenator.shutdown(); 174 Thread.interrupted(); 175 } 176 } 177 178 } 179