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