• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2017 Mockito contributors
3  * This program is made available under the terms of the MIT License.
4  */
5 package org.mockito.internal.creation.bytebuddy;
6 
7 import org.junit.Before;
8 import org.junit.Test;
9 import org.mockito.mock.SerializableMode;
10 import org.mockitoutil.VmArgAssumptions;
11 
12 import java.lang.ref.PhantomReference;
13 import java.lang.ref.Reference;
14 import java.lang.ref.ReferenceQueue;
15 import java.lang.ref.WeakReference;
16 import java.util.Collections;
17 import java.util.WeakHashMap;
18 
19 import static org.assertj.core.api.Assertions.assertThat;
20 import static org.mockito.internal.creation.bytebuddy.MockFeatures.withMockFeatures;
21 import static org.mockitoutil.ClassLoaders.inMemoryClassLoader;
22 import static org.mockitoutil.SimpleClassGenerator.makeMarkerInterface;
23 
24 public class TypeCachingMockBytecodeGeneratorTest {
25 
26     @Before
ensure_disable_gc_is_activated()27     public void ensure_disable_gc_is_activated() throws Exception {
28         VmArgAssumptions.assumeVmArgNotPresent("-XX:+DisableExplicitGC");
29     }
30 
31     @Test
ensure_cache_is_cleared_if_no_reference_to_classloader_and_classes()32     public void ensure_cache_is_cleared_if_no_reference_to_classloader_and_classes() throws Exception {
33         // given
34         ClassLoader classloader_with_life_shorter_than_cache = inMemoryClassLoader()
35                 .withClassDefinition("foo.Bar", makeMarkerInterface("foo.Bar"))
36                 .build();
37 
38         TypeCachingBytecodeGenerator cachingMockBytecodeGenerator = new TypeCachingBytecodeGenerator(new SubclassBytecodeGenerator(), true);
39 
40         Class<?> the_mock_type = cachingMockBytecodeGenerator.mockClass(withMockFeatures(
41                 classloader_with_life_shorter_than_cache.loadClass("foo.Bar"),
42                 Collections.<Class<?>>emptySet(),
43                 SerializableMode.NONE,
44                 false
45         ));
46 
47         ReferenceQueue<Object> referenceQueue = new ReferenceQueue<Object>();
48         Reference<Object> typeReference = new PhantomReference<Object>(the_mock_type, referenceQueue);
49 
50         // when
51         classloader_with_life_shorter_than_cache = is_no_more_referenced();
52         the_mock_type = is_no_more_referenced();
53 
54         System.gc();
55         ensure_gc_happened();
56 
57         // then
58         assertThat(referenceQueue.poll()).isEqualTo(typeReference);
59     }
60 
61     @Test
ensure_cache_returns_same_instance()62     public void ensure_cache_returns_same_instance() throws Exception {
63         // given
64         ClassLoader classloader_with_life_shorter_than_cache = inMemoryClassLoader()
65                 .withClassDefinition("foo.Bar", makeMarkerInterface("foo.Bar"))
66                 .build();
67 
68         TypeCachingBytecodeGenerator cachingMockBytecodeGenerator = new TypeCachingBytecodeGenerator(new SubclassBytecodeGenerator(), true);
69         Class<?> the_mock_type = cachingMockBytecodeGenerator.mockClass(withMockFeatures(
70                         classloader_with_life_shorter_than_cache.loadClass("foo.Bar"),
71                         Collections.<Class<?>>emptySet(),
72                         SerializableMode.NONE,
73                         false
74                 ));
75 
76         Class<?> other_mock_type = cachingMockBytecodeGenerator.mockClass(withMockFeatures(
77                 classloader_with_life_shorter_than_cache.loadClass("foo.Bar"),
78                 Collections.<Class<?>>emptySet(),
79                 SerializableMode.NONE,
80                 false
81         ));
82 
83         assertThat(other_mock_type).isSameAs(the_mock_type);
84 
85         ReferenceQueue<Object> referenceQueue = new ReferenceQueue<Object>();
86         Reference<Object> typeReference = new PhantomReference<Object>(the_mock_type, referenceQueue);
87 
88         // when
89         classloader_with_life_shorter_than_cache = is_no_more_referenced();
90         the_mock_type = is_no_more_referenced();
91         other_mock_type = is_no_more_referenced();
92 
93         System.gc();
94         ensure_gc_happened();
95 
96         // then
97         assertThat(referenceQueue.poll()).isEqualTo(typeReference);
98     }
99 
100     @Test
ensure_cache_returns_different_instance_serializableMode()101     public void ensure_cache_returns_different_instance_serializableMode() throws Exception {
102         // given
103         ClassLoader classloader_with_life_shorter_than_cache = inMemoryClassLoader()
104                 .withClassDefinition("foo.Bar", makeMarkerInterface("foo.Bar"))
105                 .build();
106 
107         TypeCachingBytecodeGenerator cachingMockBytecodeGenerator = new TypeCachingBytecodeGenerator(new SubclassBytecodeGenerator(), true);
108         Class<?> the_mock_type = cachingMockBytecodeGenerator.mockClass(withMockFeatures(
109                 classloader_with_life_shorter_than_cache.loadClass("foo.Bar"),
110                 Collections.<Class<?>>emptySet(),
111                 SerializableMode.NONE,
112                 false
113         ));
114 
115         Class<?> other_mock_type = cachingMockBytecodeGenerator.mockClass(withMockFeatures(
116                 classloader_with_life_shorter_than_cache.loadClass("foo.Bar"),
117                 Collections.<Class<?>>emptySet(),
118                 SerializableMode.BASIC,
119                 false
120         ));
121 
122         assertThat(other_mock_type).isNotSameAs(the_mock_type);
123     }
124 
125     @Test
validate_simple_code_idea_where_weakhashmap_with_classloader_as_key_get_GCed_when_no_more_references()126     public void validate_simple_code_idea_where_weakhashmap_with_classloader_as_key_get_GCed_when_no_more_references() throws Exception {
127         // given
128         WeakHashMap<ClassLoader, Object> cache = new WeakHashMap<ClassLoader, Object>();
129         ClassLoader short_lived_classloader = inMemoryClassLoader()
130                 .withClassDefinition("foo.Bar", makeMarkerInterface("foo.Bar"))
131                 .build();
132 
133         cache.put(short_lived_classloader, new HoldingAReference(new WeakReference<Class<?>>(short_lived_classloader.loadClass("foo.Bar"))));
134 
135         assertThat(cache).hasSize(1);
136 
137         // when
138         short_lived_classloader = is_no_more_referenced();
139 
140         System.gc();
141         ensure_gc_happened();
142 
143         // then
144         assertThat(cache).isEmpty();
145     }
146 
147     static class HoldingAReference {
148         final WeakReference<Class<?>> a;
149 
HoldingAReference(WeakReference<Class<?>> a)150         HoldingAReference(WeakReference<Class<?>> a) {
151             this.a = a;
152         }
153     }
154 
155 
is_no_more_referenced()156     private static <T> T is_no_more_referenced() {
157         return null;
158     }
159 
ensure_gc_happened()160     private static void ensure_gc_happened() throws InterruptedException {
161         // wait in order to make sure the GC happened
162         Thread.sleep(500);
163     }
164 }
165