• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2005 The Guava Authors
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 
17 package com.google.common.base;
18 
19 import com.google.common.base.internal.Finalizer;
20 
21 import junit.framework.TestCase;
22 
23 import java.lang.ref.ReferenceQueue;
24 import java.lang.ref.WeakReference;
25 import java.net.URL;
26 import java.net.URLClassLoader;
27 
28 /**
29  * Unit test for {@link FinalizableReferenceQueue}.
30  *
31  * @author Bob Lee
32  */
33 public class FinalizableReferenceQueueTest extends TestCase {
34 
35   private FinalizableReferenceQueue frq;
36 
37   @Override
tearDown()38   protected void tearDown() throws Exception {
39     frq = null;
40   }
41 
testFinalizeReferentCalled()42   public void testFinalizeReferentCalled() {
43     MockReference reference = new MockReference(
44         frq = new FinalizableReferenceQueue());
45     // wait up to 5s
46     for (int i = 0; i < 500; i++) {
47       if (reference.finalizeReferentCalled) {
48         return;
49       }
50       try {
51         System.gc();
52         Thread.sleep(10);
53       } catch (InterruptedException e) { /* ignore */ }
54     }
55     fail();
56   }
57 
58   static class MockReference extends FinalizableWeakReference<Object> {
59 
60     volatile boolean finalizeReferentCalled;
61 
MockReference(FinalizableReferenceQueue frq)62     MockReference(FinalizableReferenceQueue frq) {
63       super(new Object(), frq);
64     }
65 
66     @Override
finalizeReferent()67     public void finalizeReferent() {
68       finalizeReferentCalled = true;
69     }
70   }
71 
72   /**
73    * Keeps a weak reference to the underlying reference queue. When this
74    * reference is cleared, we know that the background thread has stopped
75    * and released its strong reference.
76    */
77   private WeakReference<ReferenceQueue<Object>> queueReference;
78 
testThatFinalizerStops()79   public void testThatFinalizerStops() {
80     weaklyReferenceQueue();
81 
82     // wait up to 5s
83     for (int i = 0; i < 500; i++) {
84       if (queueReference.get() == null) {
85         return;
86       }
87       try {
88         System.gc();
89         Thread.sleep(10);
90       } catch (InterruptedException e) { /* ignore */ }
91     }
92     fail();
93   }
94 
95   /**
96    * If we don't keep a strong reference to the reference object, it won't
97    * be enqueued.
98    */
99   FinalizableWeakReference<Object> reference;
100 
101   /**
102    * Create the FRQ in a method that goes out of scope so that we're sure
103    * it will be reclaimed.
104    */
weaklyReferenceQueue()105   private void weaklyReferenceQueue() {
106     frq = new FinalizableReferenceQueue();
107     queueReference = new WeakReference<ReferenceQueue<Object>>(frq.queue);
108 
109     /*
110      * Queue and clear a reference for good measure. We test later on that
111      * the finalizer thread stopped, but we should test that it actually
112      * started first.
113      */
114     reference = new FinalizableWeakReference<Object>(new Object(), frq) {
115       @Override
116       public void finalizeReferent() {
117         reference = null;
118         frq = null;
119       }
120     };
121   }
122 
testDecoupledLoader()123   public void testDecoupledLoader() {
124     FinalizableReferenceQueue.DecoupledLoader decoupledLoader =
125         new FinalizableReferenceQueue.DecoupledLoader() {
126           @Override
127           URLClassLoader newLoader(URL base) {
128             return new DecoupledClassLoader(new URL[] { base });
129           }
130         };
131 
132     Class<?> finalizerCopy = decoupledLoader.loadFinalizer();
133 
134     assertNotNull(finalizerCopy);
135     assertNotSame(Finalizer.class, finalizerCopy);
136 
137     assertNotNull(FinalizableReferenceQueue.getStartFinalizer(finalizerCopy));
138   }
139 
140   static class DecoupledClassLoader extends URLClassLoader {
141 
DecoupledClassLoader(URL[] urls)142     public DecoupledClassLoader(URL[] urls) {
143       super(urls);
144     }
145 
146     @Override
loadClass(String name, boolean resolve)147     protected synchronized Class<?> loadClass(String name, boolean resolve)
148         throws ClassNotFoundException {
149       // Force Finalizer to load from this class loader, not its parent.
150       if (name.equals(Finalizer.class.getName())) {
151         Class<?> clazz = findClass(name);
152         if (resolve) {
153           resolveClass(clazz);
154         }
155         return clazz;
156       }
157 
158       return super.loadClass(name, resolve);
159     }
160   }
161 
testGetFinalizerUrl()162   public void testGetFinalizerUrl() {
163     assertNotNull(getClass().getResource("internal/Finalizer.class"));
164   }
165 }
166