11d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert// Copyright 2011 Google Inc. All Rights Reserved.
21d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
31d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertpackage com.google.common.testing;
41d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
51d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport com.google.common.testing.GcFinalization.FinalizationPredicate;
61d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport com.google.common.util.concurrent.SettableFuture;
71d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
81d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport junit.framework.TestCase;
91d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
101d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport java.lang.ref.WeakReference;
111d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport java.util.WeakHashMap;
121d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport java.util.concurrent.CountDownLatch;
131d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport java.util.concurrent.atomic.AtomicBoolean;
141d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
151d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert/**
161d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * Tests for {@link GcFinalization}.
171d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert *
181d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * @author martinrb@google.com (Martin Buchholz)
191d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * @author schmoe@google.com (mike nonemacher)
201d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert */
211d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
221d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertpublic class GcFinalizationTest extends TestCase {
231d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
241d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  //----------------------------------------------------------------
251d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  // Ordinary tests of successful method execution
261d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  //----------------------------------------------------------------
271d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
281d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  public void testAwait_CountDownLatch() {
291d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    final CountDownLatch latch = new CountDownLatch(1);
301d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    Object x = new Object() {
311d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      protected void finalize() { latch.countDown(); }
321d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    };
331d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    x = null;  // Hint to the JIT that x is unreachable
341d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    GcFinalization.await(latch);
351d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertEquals(0, latch.getCount());
361d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  }
371d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
381d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  public void testAwaitDone_Future() {
391d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    final SettableFuture<Void> future = SettableFuture.create();
401d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    Object x = new Object() {
411d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      protected void finalize() { future.set(null); }
421d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    };
431d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    x = null;  // Hint to the JIT that x is unreachable
441d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    GcFinalization.awaitDone(future);
451d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertTrue(future.isDone());
461d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertFalse(future.isCancelled());
471d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  }
481d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
491d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  public void testAwaitDone_Future_Cancel() {
501d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    final SettableFuture<Void> future = SettableFuture.create();
511d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    Object x = new Object() {
521d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      protected void finalize() { future.cancel(false); }
531d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    };
541d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    x = null;  // Hint to the JIT that x is unreachable
551d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    GcFinalization.awaitDone(future);
561d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertTrue(future.isDone());
571d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertTrue(future.isCancelled());
581d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  }
591d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
601d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  public void testAwaitClear() {
611d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    final WeakReference<Object> ref = new WeakReference<Object>(new Object());
621d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    GcFinalization.awaitClear(ref);
631d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertNull(ref.get());
641d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  }
651d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
661d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  public void testAwaitDone_FinalizationPredicate() {
671d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    final WeakHashMap<Object, Object> map = new WeakHashMap<Object, Object>();
681d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    map.put(new Object(), Boolean.TRUE);
691d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    GcFinalization.awaitDone(new FinalizationPredicate() {
701d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      public boolean isDone() {
711d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        return map.isEmpty();
721d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      }
731d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    });
741d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertTrue(map.isEmpty());
751d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  }
761d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
771d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  //----------------------------------------------------------------
781d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  // Test that interrupts result in RuntimeException, not InterruptedException.
791d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  // Trickier than it looks, because runFinalization swallows interrupts.
801d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  //----------------------------------------------------------------
811d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
821d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  class Interruptenator extends Thread {
831d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    final AtomicBoolean shutdown;
841d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    Interruptenator(final Thread interruptee) {
851d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      this(interruptee, new AtomicBoolean(false));
861d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    }
871d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    Interruptenator(final Thread interruptee,
881d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert                    final AtomicBoolean shutdown) {
891d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      super(new Runnable() {
901d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert          public void run() {
911d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert            while (!shutdown.get()) {
921d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert              interruptee.interrupt();
931d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert              Thread.yield();
941d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert            }}});
951d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      this.shutdown = shutdown;
961d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      start();
971d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    }
981d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    void shutdown() {
991d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      shutdown.set(true);
1001d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      while (this.isAlive()) {
1011d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        Thread.yield();
1021d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      }
1031d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    }
1041d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  }
1051d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
1061d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  void assertWrapsInterruptedException(RuntimeException e) {
1071d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertTrue(e.getMessage().contains("Unexpected interrupt"));
1081d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertTrue(e.getCause() instanceof InterruptedException);
1091d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  }
1101d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
1111d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  public void testAwait_CountDownLatch_Interrupted() {
1121d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    Interruptenator interruptenator = new Interruptenator(Thread.currentThread());
1131d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    try {
1141d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      final CountDownLatch latch = new CountDownLatch(1);
1151d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      try {
1161d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        GcFinalization.await(latch);
1171d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        fail("should throw");
1181d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      } catch (RuntimeException expected) {
1191d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        assertWrapsInterruptedException(expected);
1201d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      }
1211d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    } finally {
1221d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      interruptenator.shutdown();
1231d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      Thread.interrupted();
1241d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    }
1251d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  }
1261d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
1271d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  public void testAwaitDone_Future_Interrupted_Interrupted() {
1281d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    Interruptenator interruptenator = new Interruptenator(Thread.currentThread());
1291d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    try {
1301d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      final SettableFuture<Void> future = SettableFuture.create();
1311d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      try {
1321d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        GcFinalization.awaitDone(future);
1331d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        fail("should throw");
1341d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      } catch (RuntimeException expected) {
1351d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        assertWrapsInterruptedException(expected);
1361d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      }
1371d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    } finally {
1381d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      interruptenator.shutdown();
1391d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      Thread.interrupted();
1401d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    }
1411d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  }
1421d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
1431d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  public void testAwaitClear_Interrupted() {
1441d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    Interruptenator interruptenator = new Interruptenator(Thread.currentThread());
1451d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    try {
1461d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      final WeakReference<Object> ref = new WeakReference<Object>(Boolean.TRUE);
1471d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      try {
1481d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        GcFinalization.awaitClear(ref);
1491d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        fail("should throw");
1501d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      } catch (RuntimeException expected) {
1511d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        assertWrapsInterruptedException(expected);
1521d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      }
1531d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    } finally {
1541d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      interruptenator.shutdown();
1551d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      Thread.interrupted();
1561d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    }
1571d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  }
1581d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
1591d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  public void testAwaitDone_FinalizationPredicate_Interrupted() {
1601d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    Interruptenator interruptenator = new Interruptenator(Thread.currentThread());
1611d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    try {
1621d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      try {
1631d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        GcFinalization.awaitDone(new FinalizationPredicate() {
1641d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert            public boolean isDone() {
1651d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert              return false;
1661d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert            }
1671d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert          });
1681d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        fail("should throw");
1691d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      } catch (RuntimeException expected) {
1701d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        assertWrapsInterruptedException(expected);
1711d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      }
1721d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    } finally {
1731d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      interruptenator.shutdown();
1741d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      Thread.interrupted();
1751d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    }
1761d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  }
1771d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
1781d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert}
179