PageRenderTime 46ms CodeModel.GetById 20ms RepoModel.GetById 1ms app.codeStats 0ms

/core/test/com/google/inject/internal/WeakKeySetTest.java

https://gitlab.com/metamorphiccode/guice
Java | 528 lines | 360 code | 116 blank | 52 comment | 0 complexity | 4fac5e5f308088a3050686c49254a716 MD5 | raw file
  1. /**
  2. * Copyright (C) 2014 Google Inc.
  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. package com.google.inject.internal;
  17. import static com.google.inject.Asserts.awaitClear;
  18. import static com.google.inject.Asserts.awaitFullGc;
  19. import static com.google.inject.internal.WeakKeySetUtils.assertBlacklisted;
  20. import static com.google.inject.internal.WeakKeySetUtils.assertInSet;
  21. import static com.google.inject.internal.WeakKeySetUtils.assertNotBlacklisted;
  22. import static com.google.inject.internal.WeakKeySetUtils.assertNotInSet;
  23. import static com.google.inject.internal.WeakKeySetUtils.assertSourceNotInSet;
  24. import com.google.common.collect.ImmutableList;
  25. import com.google.common.collect.ImmutableMap;
  26. import com.google.common.collect.ImmutableSet;
  27. import com.google.inject.AbstractModule;
  28. import com.google.inject.Binding;
  29. import com.google.inject.Guice;
  30. import com.google.inject.Injector;
  31. import com.google.inject.Key;
  32. import com.google.inject.Scope;
  33. import com.google.inject.TypeLiteral;
  34. import com.google.inject.spi.ModuleAnnotatedMethodScannerBinding;
  35. import com.google.inject.spi.ProvisionListenerBinding;
  36. import com.google.inject.spi.ScopeBinding;
  37. import com.google.inject.spi.TypeConverterBinding;
  38. import com.google.inject.spi.TypeListenerBinding;
  39. import junit.framework.TestCase;
  40. import java.lang.annotation.Annotation;
  41. import java.lang.ref.WeakReference;
  42. import java.util.List;
  43. import java.util.Map;
  44. import java.util.Set;
  45. /**
  46. * Tests for {@link WeakKeySet}.
  47. * <p>
  48. * Multibinding specific tests can be found in MultibinderTest and MapBinderTest.
  49. *
  50. * @author dweis@google.com (Daniel Weis)
  51. */
  52. public class WeakKeySetTest extends TestCase {
  53. private WeakKeySet set;
  54. @Override
  55. protected void setUp() throws Exception {
  56. set = new WeakKeySet(new Object());
  57. }
  58. public void testEviction() {
  59. TestState state = new TestState();
  60. Key<Integer> key = Key.get(Integer.class);
  61. Object source = new Object();
  62. WeakReference<Key<Integer>> weakKeyRef = new WeakReference<Key<Integer>>(key);
  63. set.add(key, state, source);
  64. assertInSet(set, key, 1, source);
  65. state = null;
  66. awaitFullGc();
  67. assertNotInSet(set, Key.get(Integer.class));
  68. // Ensure there are no hanging references.
  69. key = null;
  70. awaitClear(weakKeyRef);
  71. }
  72. public void testEviction_nullSource() {
  73. TestState state = new TestState();
  74. Key<Integer> key = Key.get(Integer.class);
  75. Object source = null;
  76. WeakReference<Key<Integer>> weakKeyRef = new WeakReference<Key<Integer>>(key);
  77. set.add(key, state, source);
  78. assertInSet(set, key, 1, source);
  79. state = null;
  80. awaitFullGc();
  81. assertNotInSet(set, Key.get(Integer.class));
  82. // Ensure there are no hanging references.
  83. key = null;
  84. awaitClear(weakKeyRef);
  85. }
  86. public void testEviction_keyOverlap_2x() {
  87. TestState state1 = new TestState();
  88. TestState state2 = new TestState();
  89. Key<Integer> key1 = Key.get(Integer.class);
  90. Key<Integer> key2 = Key.get(Integer.class);
  91. Object source1 = new Object();
  92. Object source2 = new Object();
  93. set.add(key1, state1, source1);
  94. assertInSet(set, key1, 1, source1);
  95. set.add(key2, state2, source2);
  96. assertInSet(set, key2, 2, source1, source2);
  97. WeakReference<Key<Integer>> weakKey1Ref = new WeakReference<Key<Integer>>(key1);
  98. WeakReference<Key<Integer>> weakKey2Ref = new WeakReference<Key<Integer>>(key2);
  99. WeakReference<Object> weakSource1Ref = new WeakReference<Object>(source1);
  100. WeakReference<Object> weakSource2Ref = new WeakReference<Object>(source2);
  101. Key<Integer> key = key1 = key2 = Key.get(Integer.class);
  102. state1 = null;
  103. awaitFullGc();
  104. assertSourceNotInSet(set, key, source1);
  105. assertInSet(set, key, 1, source2);
  106. source1 = source2 = null;
  107. awaitClear(weakSource1Ref);
  108. // Key1 will be referenced as the key in the sources backingSet and won't be
  109. // GC'd.
  110. // Should not be GC'd until state2 goes away.
  111. assertNotNull(weakSource2Ref.get());
  112. state2 = null;
  113. awaitFullGc();
  114. assertNotInSet(set, key);
  115. awaitClear(weakKey2Ref);
  116. awaitClear(weakSource2Ref);
  117. // Now that the backing set is emptied, key1 is released.
  118. awaitClear(weakKey1Ref);
  119. }
  120. public void testNoEviction_keyOverlap_2x() {
  121. TestState state1 = new TestState();
  122. TestState state2 = new TestState();
  123. Key<Integer> key1 = Key.get(Integer.class);
  124. Key<Integer> key2 = Key.get(Integer.class);
  125. Object source1 = new Object();
  126. Object source2 = new Object();
  127. set.add(key1, state1, source1);
  128. assertInSet(set, key1, 1, source1);
  129. set.add(key2, state2, source2);
  130. assertInSet(set, key2, 2, source1, source2);
  131. WeakReference<Key<Integer>> weakKey1Ref = new WeakReference<Key<Integer>>(key1);
  132. WeakReference<Key<Integer>> weakKey2Ref = new WeakReference<Key<Integer>>(key2);
  133. Key<Integer> key = key1 = key2 = Key.get(Integer.class);
  134. awaitFullGc();
  135. assertInSet(set, key, 2, source1, source2);
  136. // Ensure the keys don't get GC'd when states are still referenced. key1 will be present in the
  137. // as the map key but key2 could be GC'd if the implementation does something wrong.
  138. assertNotNull(weakKey1Ref.get());
  139. assertNotNull(weakKey2Ref.get());
  140. }
  141. public void testEviction_keyAndSourceOverlap_null() {
  142. TestState state1 = new TestState();
  143. TestState state2 = new TestState();
  144. Key<Integer> key1 = Key.get(Integer.class);
  145. Key<Integer> key2 = Key.get(Integer.class);
  146. Object source = null;
  147. set.add(key1, state1, source);
  148. assertInSet(set, key1, 1, source);
  149. set.add(key2, state2, source);
  150. // Same source so still only one value.
  151. assertInSet(set, key2, 1, source);
  152. assertInSet(set, key1, 1, source);
  153. WeakReference<Key<Integer>> weakKey1Ref = new WeakReference<Key<Integer>>(key1);
  154. WeakReference<Key<Integer>> weakKey2Ref = new WeakReference<Key<Integer>>(key2);
  155. WeakReference<Object> weakSourceRef = new WeakReference<Object>(source);
  156. Key<Integer> key = key1 = key2 = Key.get(Integer.class);
  157. state1 = null;
  158. awaitFullGc();
  159. // Should still have a single source.
  160. assertInSet(set, key, 1, source);
  161. source = null;
  162. awaitClear(weakSourceRef);
  163. // Key1 will be referenced as the key in the sources backingSet and won't be
  164. // GC'd.
  165. state2 = null;
  166. awaitFullGc();
  167. assertNotInSet(set, key);
  168. awaitClear(weakKey2Ref);
  169. awaitClear(weakSourceRef);
  170. // Now that the backing set is emptied, key1 is released.
  171. awaitClear(weakKey1Ref);
  172. }
  173. public void testEviction_keyAndSourceOverlap_nonNull() {
  174. TestState state1 = new TestState();
  175. TestState state2 = new TestState();
  176. Key<Integer> key1 = Key.get(Integer.class);
  177. Key<Integer> key2 = Key.get(Integer.class);
  178. Object source = new Object();
  179. set.add(key1, state1, source);
  180. assertInSet(set, key1, 1, source);
  181. set.add(key2, state2, source);
  182. // Same source so still only one value.
  183. assertInSet(set, key2, 1, source);
  184. WeakReference<Key<Integer>> weakKey1Ref = new WeakReference<Key<Integer>>(key1);
  185. WeakReference<Key<Integer>> weakKey2Ref = new WeakReference<Key<Integer>>(key2);
  186. WeakReference<Object> weakSourceRef = new WeakReference<Object>(source);
  187. Key<Integer> key = key1 = key2 = Key.get(Integer.class);
  188. state1 = null;
  189. awaitFullGc();
  190. // Same source so still only one value.
  191. assertInSet(set, key, 1, source);
  192. assertInSet(set, key1, 1, source);
  193. source = null;
  194. awaitFullGc();
  195. assertNotNull(weakSourceRef.get());
  196. // Key1 will be referenced as the key in the sources backingSet and won't be
  197. // GC'd.
  198. state2 = null;
  199. awaitFullGc();
  200. assertNotInSet(set, key);
  201. awaitClear(weakKey2Ref);
  202. awaitClear(weakSourceRef);
  203. // Now that the backing set is emptied, key1 is released.
  204. awaitClear(weakKey1Ref);
  205. }
  206. public void testEviction_keyOverlap_3x() {
  207. TestState state1 = new TestState();
  208. TestState state2 = new TestState();
  209. TestState state3 = new TestState();
  210. Key<Integer> key1 = Key.get(Integer.class);
  211. Key<Integer> key2 = Key.get(Integer.class);
  212. Key<Integer> key3 = Key.get(Integer.class);
  213. Object source1 = new Object();
  214. Object source2 = new Object();
  215. Object source3 = new Object();
  216. set.add(key1, state1, source1);
  217. assertInSet(set, key1, 1, source1);
  218. set.add(key2, state2, source2);
  219. assertInSet(set, key1, 2, source1, source2);
  220. set.add(key3, state3, source3);
  221. assertInSet(set, key1, 3, source1, source2, source3);
  222. WeakReference<Key<Integer>> weakKey1Ref = new WeakReference<Key<Integer>>(key1);
  223. WeakReference<Key<Integer>> weakKey2Ref = new WeakReference<Key<Integer>>(key2);
  224. WeakReference<Key<Integer>> weakKey3Ref = new WeakReference<Key<Integer>>(key3);
  225. WeakReference<Object> weakSource1Ref = new WeakReference<Object>(source1);
  226. WeakReference<Object> weakSource2Ref = new WeakReference<Object>(source2);
  227. WeakReference<Object> weakSource3Ref = new WeakReference<Object>(source3);
  228. Key<Integer> key = key1 = key2 = key3 = Key.get(Integer.class);
  229. state1 = null;
  230. awaitFullGc();
  231. assertSourceNotInSet(set, key, source1);
  232. assertInSet(set, key, 2, source2, source3);
  233. source1 = null;
  234. // Key1 will be referenced as the key in the sources backingSet and won't be
  235. // GC'd.
  236. awaitClear(weakSource1Ref);
  237. state2 = null;
  238. awaitFullGc();
  239. assertSourceNotInSet(set, key, source2);
  240. assertInSet(set, key, 1, source3);
  241. awaitClear(weakKey2Ref);
  242. source2 = null;
  243. awaitClear(weakSource2Ref);
  244. // Key1 will be referenced as the key in the sources backingSet and won't be
  245. // GC'd.
  246. state3 = null;
  247. awaitFullGc();
  248. assertNotInSet(set, key);
  249. awaitClear(weakKey3Ref);
  250. source3 = null;
  251. awaitClear(weakSource3Ref);
  252. // Now that the backing set is emptied, key1 is released.
  253. awaitClear(weakKey1Ref);
  254. }
  255. public void testWeakKeySet_integration() {
  256. Injector parentInjector = Guice.createInjector(new AbstractModule() {
  257. @Override protected void configure() {
  258. bind(Integer.class).toInstance(4);
  259. }
  260. });
  261. assertNotBlacklisted(parentInjector, Key.get(String.class));
  262. Injector childInjector = parentInjector.createChildInjector(new AbstractModule() {
  263. @Override protected void configure() {
  264. bind(String.class).toInstance("bar");
  265. }
  266. });
  267. WeakReference<Injector> weakRef = new WeakReference<Injector>(childInjector);
  268. assertBlacklisted(parentInjector, Key.get(String.class));
  269. // Clear the ref, GC, and ensure that we are no longer blacklisting.
  270. childInjector = null;
  271. awaitClear(weakRef);
  272. assertNotBlacklisted(parentInjector, Key.get(String.class));
  273. }
  274. public void testWeakKeySet_integration_multipleChildren() {
  275. Injector parentInjector = Guice.createInjector(new AbstractModule() {
  276. @Override protected void configure() {
  277. bind(Integer.class).toInstance(4);
  278. }
  279. });
  280. assertNotBlacklisted(parentInjector, Key.get(String.class));
  281. assertNotBlacklisted(parentInjector, Key.get(Long.class));
  282. Injector childInjector1 = parentInjector.createChildInjector(new AbstractModule() {
  283. @Override protected void configure() {
  284. bind(String.class).toInstance("foo");
  285. }
  286. });
  287. WeakReference<Injector> weakRef1 = new WeakReference<Injector>(childInjector1);
  288. assertBlacklisted(parentInjector, Key.get(String.class));
  289. assertNotBlacklisted(parentInjector, Key.get(Long.class));
  290. Injector childInjector2 = parentInjector.createChildInjector(new AbstractModule() {
  291. @Override protected void configure() {
  292. bind(Long.class).toInstance(6L);
  293. }
  294. });
  295. WeakReference<Injector> weakRef2 = new WeakReference<Injector>(childInjector2);
  296. assertBlacklisted(parentInjector, Key.get(String.class));
  297. assertBlacklisted(parentInjector, Key.get(Long.class));
  298. // Clear ref1, GC, and ensure that we still blacklist.
  299. childInjector1 = null;
  300. awaitClear(weakRef1);
  301. assertNotBlacklisted(parentInjector, Key.get(String.class));
  302. assertBlacklisted(parentInjector, Key.get(Long.class));
  303. // Clear the ref, GC, and ensure that we are no longer blacklisting.
  304. childInjector2 = null;
  305. awaitClear(weakRef2);
  306. assertNotBlacklisted(parentInjector, Key.get(String.class));
  307. assertNotBlacklisted(parentInjector, Key.get(Long.class));
  308. }
  309. public void testWeakKeySet_integration_multipleChildren_overlappingKeys() {
  310. Injector parentInjector = Guice.createInjector(new AbstractModule() {
  311. @Override protected void configure() {
  312. bind(Integer.class).toInstance(4);
  313. }
  314. });
  315. assertNotBlacklisted(parentInjector, Key.get(String.class));
  316. Injector childInjector1 = parentInjector.createChildInjector(new AbstractModule() {
  317. @Override protected void configure() {
  318. bind(String.class).toInstance("foo");
  319. }
  320. });
  321. WeakReference<Injector> weakRef1 = new WeakReference<Injector>(childInjector1);
  322. assertBlacklisted(parentInjector, Key.get(String.class));
  323. Injector childInjector2 = parentInjector.createChildInjector(new AbstractModule() {
  324. @Override protected void configure() {
  325. bind(String.class).toInstance("bar");
  326. }
  327. });
  328. WeakReference<Injector> weakRef2 = new WeakReference<Injector>(childInjector2);
  329. assertBlacklisted(parentInjector, Key.get(String.class));
  330. // Clear ref1, GC, and ensure that we still blacklist.
  331. childInjector1 = null;
  332. awaitClear(weakRef1);
  333. assertBlacklisted(parentInjector, Key.get(String.class));
  334. // Clear the ref, GC, and ensure that we are no longer blacklisting.
  335. childInjector2 = null;
  336. awaitClear(weakRef2);
  337. assertNotBlacklisted(parentInjector, Key.get(String.class));
  338. }
  339. private static class TestState implements State {
  340. public State parent() {
  341. return new TestState();
  342. }
  343. public <T> BindingImpl<T> getExplicitBinding(Key<T> key) {
  344. return null;
  345. }
  346. public Map<Key<?>, Binding<?>> getExplicitBindingsThisLevel() {
  347. throw new UnsupportedOperationException();
  348. }
  349. public void putBinding(Key<?> key, BindingImpl<?> binding) {
  350. throw new UnsupportedOperationException();
  351. }
  352. public ScopeBinding getScopeBinding(Class<? extends Annotation> scopingAnnotation) {
  353. return null;
  354. }
  355. public void putScopeBinding(Class<? extends Annotation> annotationType, ScopeBinding scope) {
  356. throw new UnsupportedOperationException();
  357. }
  358. public void addConverter(TypeConverterBinding typeConverterBinding) {
  359. throw new UnsupportedOperationException();
  360. }
  361. public TypeConverterBinding getConverter(String stringValue, TypeLiteral<?> type, Errors errors,
  362. Object source) {
  363. throw new UnsupportedOperationException();
  364. }
  365. public Iterable<TypeConverterBinding> getConvertersThisLevel() {
  366. return ImmutableSet.of();
  367. }
  368. /*if[AOP]*/
  369. public void addMethodAspect(MethodAspect methodAspect) {
  370. throw new UnsupportedOperationException();
  371. }
  372. public ImmutableList<MethodAspect> getMethodAspects() {
  373. return ImmutableList.of();
  374. }
  375. /*end[AOP]*/
  376. public void addTypeListener(TypeListenerBinding typeListenerBinding) {
  377. throw new UnsupportedOperationException();
  378. }
  379. public List<TypeListenerBinding> getTypeListenerBindings() {
  380. return ImmutableList.of();
  381. }
  382. public void addProvisionListener(ProvisionListenerBinding provisionListenerBinding) {
  383. throw new UnsupportedOperationException();
  384. }
  385. public List<ProvisionListenerBinding> getProvisionListenerBindings() {
  386. return ImmutableList.of();
  387. }
  388. public void addScanner(ModuleAnnotatedMethodScannerBinding scanner) {
  389. throw new UnsupportedOperationException();
  390. }
  391. public List<ModuleAnnotatedMethodScannerBinding> getScannerBindings() {
  392. return ImmutableList.of();
  393. }
  394. public void blacklist(Key<?> key, State state, Object source) {
  395. }
  396. public boolean isBlacklisted(Key<?> key) {
  397. return true;
  398. }
  399. public Set<Object> getSourcesForBlacklistedKey(Key<?> key) {
  400. throw new UnsupportedOperationException();
  401. }
  402. public Object lock() {
  403. throw new UnsupportedOperationException();
  404. }
  405. public Object singletonCreationLock() {
  406. throw new UnsupportedOperationException();
  407. }
  408. public Map<Class<? extends Annotation>, Scope> getScopes() {
  409. return ImmutableMap.of();
  410. }
  411. }
  412. }