View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  
18  package org.apache.commons.logging.impl;
19  
20  import java.lang.ref.ReferenceQueue;
21  import java.lang.ref.WeakReference;
22  import java.util.ArrayList;
23  import java.util.Collection;
24  import java.util.Enumeration;
25  import java.util.HashMap;
26  import java.util.Map;
27  import java.util.Set;
28  
29  import junit.framework.TestCase;
30  
31  public class WeakHashtableTestCase extends TestCase {
32  
33      public static class StupidThread extends Thread {
34  
35          public StupidThread(final String name) {
36              super(name);
37          }
38  
39          @Override
40          public void run() {
41              for (int i = 0; i < RUN_LOOPS; i++) {
42                  hashtable.put("key" + ":" + i % 10, Boolean.TRUE);
43                  if (i % 50 == 0) {
44                      yield();
45                  }
46              }
47          }
48      }
49      private static final int WAIT_FOR_THREAD_COMPLETION = 5000; // 5 seconds
50      private static final int RUN_LOOPS = 3000;
51      private static final int OUTER_LOOP = 400;
52  
53      private static final int THREAD_COUNT = 10;
54  
55      private static WeakHashtable hashtable;
56  
57      /** Maximum number of iterations before our test fails */
58      private static final int MAX_GC_ITERATIONS = 50;
59      private WeakHashtable weakHashtable;
60      private Long keyOne;
61      private Long keyTwo;
62      private Long keyThree;
63      private Long valueOne;
64      private Long valueTwo;
65  
66      private Long valueThree;
67  
68      public WeakHashtableTestCase(final String testName) {
69          super(testName);
70      }
71  
72      @Override
73      protected void setUp() throws Exception {
74          super.setUp();
75          weakHashtable = new WeakHashtable();
76  
77          keyOne = Long.valueOf(1);
78          keyTwo = Long.valueOf(2);
79          keyThree = Long.valueOf(3);
80          valueOne = Long.valueOf(100);
81          valueTwo = Long.valueOf(200);
82          valueThree = Long.valueOf(300);
83  
84          weakHashtable.put(keyOne, valueOne);
85          weakHashtable.put(keyTwo, valueTwo);
86          weakHashtable.put(keyThree, valueThree);
87      }
88  
89      /** Tests public boolean contains(Object value) */
90      public void testContains() throws Exception {
91          assertFalse(weakHashtable.contains(Long.valueOf(1)));
92          assertFalse(weakHashtable.contains(Long.valueOf(2)));
93          assertFalse(weakHashtable.contains(Long.valueOf(3)));
94          assertTrue(weakHashtable.contains(Long.valueOf(100)));
95          assertTrue(weakHashtable.contains(Long.valueOf(200)));
96          assertTrue(weakHashtable.contains(Long.valueOf(300)));
97          assertFalse(weakHashtable.contains(Long.valueOf(400)));
98      }
99  
100     /** Tests public boolean containsKey(Object key) */
101     public void testContainsKey() throws Exception {
102         assertTrue(weakHashtable.containsKey(Long.valueOf(1)));
103         assertTrue(weakHashtable.containsKey(Long.valueOf(2)));
104         assertTrue(weakHashtable.containsKey(Long.valueOf(3)));
105         assertFalse(weakHashtable.containsKey(Long.valueOf(100)));
106         assertFalse(weakHashtable.containsKey(Long.valueOf(200)));
107         assertFalse(weakHashtable.containsKey(Long.valueOf(300)));
108         assertFalse(weakHashtable.containsKey(Long.valueOf(400)));
109     }
110 
111     /** Tests public boolean containsValue(Object value) */
112     public void testContainsValue() throws Exception {
113         assertFalse(weakHashtable.containsValue(Long.valueOf(1)));
114         assertFalse(weakHashtable.containsValue(Long.valueOf(2)));
115         assertFalse(weakHashtable.containsValue(Long.valueOf(3)));
116         assertTrue(weakHashtable.containsValue(Long.valueOf(100)));
117         assertTrue(weakHashtable.containsValue(Long.valueOf(200)));
118         assertTrue(weakHashtable.containsValue(Long.valueOf(300)));
119         assertFalse(weakHashtable.containsValue(Long.valueOf(400)));
120     }
121 
122     /** Tests public Enumeration elements() */
123     public void testElements() throws Exception {
124         final ArrayList elements = new ArrayList();
125         for (final Enumeration e = weakHashtable.elements(); e.hasMoreElements();) {
126             elements.add(e.nextElement());
127         }
128         assertEquals(3, elements.size());
129         assertTrue(elements.contains(valueOne));
130         assertTrue(elements.contains(valueTwo));
131         assertTrue(elements.contains(valueThree));
132     }
133 
134     /** Tests public Set entrySet() */
135     public void testEntrySet() throws Exception {
136         final Set entrySet = weakHashtable.entrySet();
137         for (final Object element : entrySet) {
138             final Map.Entry entry = (Map.Entry) element;
139             final Object key = entry.getKey();
140             if (keyOne.equals(key)) {
141                 assertEquals(valueOne, entry.getValue());
142             } else if (keyTwo.equals(key)) {
143                 assertEquals(valueTwo, entry.getValue());
144             } else if (keyThree.equals(key)) {
145                 assertEquals(valueThree, entry.getValue());
146             } else {
147                 fail("Unexpected key");
148             }
149         }
150     }
151 
152     /** Tests public Object get(Object key) */
153     public void testGet() throws Exception {
154         assertEquals(valueOne, weakHashtable.get(keyOne));
155         assertEquals(valueTwo, weakHashtable.get(keyTwo));
156         assertEquals(valueThree, weakHashtable.get(keyThree));
157         assertNull(weakHashtable.get(Long.valueOf(50)));
158     }
159 
160     /** Tests public Enumeration keys() */
161     public void testKeys() throws Exception {
162         final ArrayList keys = new ArrayList();
163         for (final Enumeration e = weakHashtable.keys(); e.hasMoreElements();) {
164             keys.add(e.nextElement());
165         }
166         assertEquals(3, keys.size());
167         assertTrue(keys.contains(keyOne));
168         assertTrue(keys.contains(keyTwo));
169         assertTrue(keys.contains(keyThree));
170     }
171 
172     /** Tests public Set keySet() */
173     public void testKeySet() throws Exception {
174         final Set keySet = weakHashtable.keySet();
175         assertEquals(3, keySet.size());
176         assertTrue(keySet.contains(keyOne));
177         assertTrue(keySet.contains(keyTwo));
178         assertTrue(keySet.contains(keyThree));
179     }
180 
181     public void testLOGGING_119() throws Exception {
182         final Thread [] t = new Thread[THREAD_COUNT];
183         for (int j=1; j <= OUTER_LOOP; j++) {
184             hashtable = new WeakHashtable();
185             for (int i = 0; i < t.length; i++) {
186                 t[i] = new StupidThread("Thread:" + i);
187                 t[i].setDaemon(true); // Otherwise we cannot exit
188                 t[i].start();
189             }
190             for (final Thread element : t) {
191                 element.join(WAIT_FOR_THREAD_COMPLETION);
192                 if (element.isAlive()) {
193                     break; // at least one thread is stuck
194                 }
195             }
196             int active=0;
197             for (final Thread element : t) {
198                 if (element.isAlive()) {
199                     active++;
200                 }
201             }
202             if (active > 0) {
203                 fail("Attempt: " + j + " Stuck threads: " + active);
204             }
205         }
206     }
207 
208     /** Tests public Object put(Object key, Object value) */
209     public void testPut() throws Exception {
210         final Long anotherKey = Long.valueOf(2004);
211         weakHashtable.put(anotherKey, Long.valueOf(1066));
212 
213         assertEquals(Long.valueOf(1066), weakHashtable.get(anotherKey));
214 
215         // Test compliance with the hashtable API re nulls
216         Exception caught = null;
217         try {
218             weakHashtable.put(null, new Object());
219         }
220         catch (final Exception e) {
221             caught = e;
222         }
223         assertNotNull("did not throw an exception adding a null key", caught);
224         caught = null;
225         try {
226             weakHashtable.put(new Object(), null);
227         }
228         catch (final Exception e) {
229             caught = e;
230         }
231         assertNotNull("did not throw an exception adding a null value", caught);
232     }
233 
234     /** Tests public void putAll(Map t) */
235     public void testPutAll() throws Exception {
236         final Map newValues = new HashMap();
237         final Long newKey = Long.valueOf(1066);
238         final Long newValue = Long.valueOf(1415);
239         newValues.put(newKey, newValue);
240         final Long anotherNewKey = Long.valueOf(1645);
241         final Long anotherNewValue = Long.valueOf(1815);
242         newValues.put(anotherNewKey, anotherNewValue);
243         weakHashtable.putAll(newValues);
244 
245         assertEquals(5, weakHashtable.size());
246         assertEquals(newValue, weakHashtable.get(newKey));
247         assertEquals(anotherNewValue, weakHashtable.get(anotherNewKey));
248     }
249 
250     /** Tests public Object remove(Object key) */
251     public void testRemove() throws Exception {
252         weakHashtable.remove(keyOne);
253         assertEquals(2, weakHashtable.size());
254         assertNull(weakHashtable.get(keyOne));
255     }
256 
257     /** Tests public Collection values() */
258     public void testValues() throws Exception {
259         final Collection values = weakHashtable.values();
260         assertEquals(3, values.size());
261         assertTrue(values.contains(valueOne));
262         assertTrue(values.contains(valueTwo));
263         assertTrue(values.contains(valueThree));
264     }
265 
266     /**
267      * Disabled this test as it makes wrong assumptions wrt the GC.
268      * This test especially fails with:
269      *
270      * Java(TM) SE Runtime Environment (build pxi3260sr12-20121025_01(SR12))
271      * IBM J9 VM (build 2.4, JRE 1.6.0 IBM J9 2.4 Linux x86-32 jvmxi3260sr12-20121024_1
272      */
273     public void xxxIgnoretestRelease() throws Exception {
274         assertNotNull(weakHashtable.get(Long.valueOf(1)));
275         final ReferenceQueue testQueue = new ReferenceQueue();
276         final WeakReference weakKeyOne = new WeakReference(keyOne, testQueue);
277 
278         // lose our references
279         keyOne = null;
280         keyTwo = null;
281         keyThree = null;
282         valueOne = null;
283         valueTwo = null;
284         valueThree = null;
285 
286         int iterations = 0;
287         int bytz = 2;
288         while(true) {
289             System.gc();
290             if (iterations++ > MAX_GC_ITERATIONS) {
291                 fail("Max iterations reached before resource released.");
292             }
293 
294             if (weakHashtable.get(Long.valueOf(1)) == null) {
295                 break;
296 
297             }
298             // create garbage:
299             final byte[] b =  new byte[bytz];
300             bytz *= 2;
301         }
302 
303         // some JVMs seem to take a little time to put references on
304         // the reference queue once the reference has been collected
305         // need to think about whether this is enough to justify
306         // stepping through the collection each time...
307         while(testQueue.poll() == null) {}
308 
309         // Test that the released objects are not taking space in the table
310         assertEquals("underlying table not emptied", 0, weakHashtable.size());
311     }
312 }