1 package com.atlassian.plugin.manager;
2
3 import com.atlassian.plugin.MockModuleDescriptor;
4 import com.atlassian.plugin.ModuleDescriptor;
5 import com.atlassian.plugin.Plugin;
6 import com.atlassian.plugin.PluginAccessor;
7 import com.atlassian.plugin.PluginController;
8 import com.atlassian.plugin.event.PluginEventManager;
9 import com.atlassian.plugin.event.events.PluginDisabledEvent;
10 import com.atlassian.plugin.event.events.PluginEnabledEvent;
11 import com.atlassian.plugin.event.events.PluginModuleDisabledEvent;
12 import com.atlassian.plugin.event.events.PluginModuleEnabledEvent;
13 import com.atlassian.plugin.event.impl.DefaultPluginEventManager;
14 import com.google.common.collect.ImmutableList;
15 import com.google.common.collect.Iterators;
16 import com.google.common.collect.Lists;
17 import org.junit.Before;
18 import org.junit.Rule;
19 import org.junit.Test;
20 import org.mockito.Mock;
21 import org.mockito.junit.MockitoJUnit;
22 import org.mockito.junit.MockitoRule;
23
24 import java.util.Collections;
25 import java.util.Iterator;
26 import java.util.List;
27
28 import static com.google.common.collect.Lists.newArrayList;
29 import static java.util.Collections.singletonList;
30 import static org.hamcrest.Matchers.contains;
31 import static org.hamcrest.Matchers.containsInAnyOrder;
32 import static org.hamcrest.Matchers.empty;
33 import static org.hamcrest.Matchers.sameInstance;
34 import static org.junit.Assert.assertEquals;
35 import static org.junit.Assert.assertFalse;
36 import static org.junit.Assert.assertSame;
37 import static org.junit.Assert.assertThat;
38 import static org.mockito.ArgumentMatchers.any;
39 import static org.mockito.Mockito.mock;
40 import static org.mockito.Mockito.never;
41 import static org.mockito.Mockito.times;
42 import static org.mockito.Mockito.verify;
43 import static org.mockito.Mockito.when;
44
45
46
47
48
49
50 public class TestEnabledModuleCachingPluginAccessor {
51 private PluginEventManager pluginEventManager;
52
53 @Rule
54 public final MockitoRule mockitoRule = MockitoJUnit.rule();
55
56 @Mock
57 private PluginAccessor delegate;
58 @Mock
59 private PluginController pluginController;
60 private PluginAccessor cachingPluginAccessor;
61
62 @Before
63 public void setUp() throws Exception {
64 pluginEventManager = new DefaultPluginEventManager();
65 cachingPluginAccessor = new EnabledModuleCachingPluginAccessor(delegate, pluginEventManager, pluginController);
66 }
67
68 @Test
69 public void testGetEnabledModuleDescriptorsByClassDelegateShouldCalculateAtMostOnce() {
70
71 cachingPluginAccessor.getEnabledModuleDescriptorsByClass(Descriptor.class);
72 cachingPluginAccessor.getEnabledModuleDescriptorsByClass(Descriptor.class);
73
74 verify(delegate, times(1)).getEnabledModuleDescriptorsByClass(Descriptor.class);
75
76
77 pluginEventManager.broadcast(new PluginModuleEnabledEvent(new Descriptor(new Module())));
78 cachingPluginAccessor.getEnabledModuleDescriptorsByClass(Descriptor.class);
79 cachingPluginAccessor.getEnabledModuleDescriptorsByClass(Descriptor.class);
80
81
82 verify(delegate, times(2)).getEnabledModuleDescriptorsByClass(Descriptor.class);
83 }
84
85 @Test
86 public void testGetEnabledModuleDescriptorsByClassFlushCacheAfterAnyPluginDisable() {
87
88 cachingPluginAccessor.getEnabledModuleDescriptorsByClass(Descriptor.class);
89 verify(delegate, times(1)).getEnabledModuleDescriptorsByClass(Descriptor.class);
90
91 pluginEventManager.broadcast(new PluginDisabledEvent(mock(Plugin.class)));
92 cachingPluginAccessor.getEnabledModuleDescriptorsByClass(Descriptor.class);
93 cachingPluginAccessor.getEnabledModuleDescriptorsByClass(Descriptor.class);
94
95
96 verify(delegate, times(2)).getEnabledModuleDescriptorsByClass(Descriptor.class);
97 }
98
99 @Test
100 public void testGetEnabledModuleDescriptorsByClassFlushCacheAfterAnyPluginEnable() {
101
102 cachingPluginAccessor.getEnabledModuleDescriptorsByClass(Descriptor.class);
103 verify(delegate, times(1)).getEnabledModuleDescriptorsByClass(Descriptor.class);
104
105 pluginEventManager.broadcast(new PluginEnabledEvent(mock(Plugin.class)));
106 cachingPluginAccessor.getEnabledModuleDescriptorsByClass(Descriptor.class);
107 cachingPluginAccessor.getEnabledModuleDescriptorsByClass(Descriptor.class);
108
109
110 verify(delegate, times(2)).getEnabledModuleDescriptorsByClass(Descriptor.class);
111 }
112
113 @Test
114 public void testGetEnabledModuleDescriptorsByClassChildAndParentClassBeingTrackedSeparately() {
115 final ChildDescriptor<ChildModule> childDescriptor = new ChildDescriptor<>(new ChildModule());
116 final ParentDescriptor<ParentModule> parentDescriptor = new ParentDescriptor<>(new ParentModule());
117
118 when(delegate.getEnabledModuleDescriptorsByClass(ChildDescriptor.class))
119 .thenReturn(Collections.<ChildDescriptor>singletonList(childDescriptor));
120 when(delegate.getEnabledModuleDescriptorsByClass(ParentDescriptor.class))
121 .thenReturn(Lists.<ParentDescriptor>newArrayList(parentDescriptor, childDescriptor));
122
123 final List<ChildDescriptor> result = cachingPluginAccessor.getEnabledModuleDescriptorsByClass(ChildDescriptor.class);
124 assertEquals(1, result.size());
125 assertSame(childDescriptor, result.get(0));
126
127 final List<ParentDescriptor> result2 = cachingPluginAccessor.getEnabledModuleDescriptorsByClass(ParentDescriptor.class);
128
129 assertEquals(2, result2.size());
130 assertEquals(parentDescriptor, result2.get(0));
131 assertEquals(childDescriptor, result2.get(1));
132 }
133
134 @Test
135 public void testGetEnabledModuleDescriptorsByClassFindsLateChild() {
136 final ChildDescriptor childDescriptor = new ChildDescriptor<>(new ChildModule());
137 final ParentDescriptor parentDescriptor = new ParentDescriptor<>(new ParentModule());
138
139 when(delegate.getEnabledModuleDescriptorsByClass(ChildDescriptor.class)).thenReturn(ImmutableList.of());
140 when(delegate.getEnabledModuleDescriptorsByClass(ParentDescriptor.class)).thenReturn(ImmutableList.of(parentDescriptor));
141
142 final List<ChildDescriptor> childBefore = cachingPluginAccessor.getEnabledModuleDescriptorsByClass(ChildDescriptor.class);
143 final List<ParentDescriptor> parentBefore = cachingPluginAccessor.getEnabledModuleDescriptorsByClass(ParentDescriptor.class);
144
145 assertThat(childBefore, empty());
146 assertThat(parentBefore, contains(parentDescriptor));
147
148
149
150 when(delegate.getEnabledModuleDescriptorsByClass(ChildDescriptor.class)).thenReturn(ImmutableList.of(childDescriptor));
151 when(delegate.getEnabledModuleDescriptorsByClass(ParentDescriptor.class)).
152 thenReturn(ImmutableList.of(parentDescriptor, childDescriptor));
153
154 pluginEventManager.broadcast(new PluginModuleEnabledEvent(childDescriptor));
155
156 final List<ChildDescriptor> childAfter = cachingPluginAccessor.getEnabledModuleDescriptorsByClass(ChildDescriptor.class);
157 final List<ParentDescriptor> parentAfter = cachingPluginAccessor.getEnabledModuleDescriptorsByClass(ParentDescriptor.class);
158
159 assertThat(childAfter, contains(childDescriptor));
160 assertThat(parentAfter, contains(parentDescriptor, childDescriptor));
161 }
162
163 @Test
164 public void testGetEnabledModuleDescriptorsByClassWhenModuleEnabledBeforeCacheAccessed() {
165 final Descriptor descriptor = new Descriptor(new Module());
166
167
168 when(delegate.getEnabledModuleDescriptorsByClass(Descriptor.class)).thenReturn(singletonList(descriptor));
169
170
171 List<Descriptor> result = cachingPluginAccessor.getEnabledModuleDescriptorsByClass(Descriptor.class);
172 assertThat(result, contains(descriptor));
173 }
174
175 @Test
176 public void testGetEnabledModuleDescriptorsByClassWhenModuleEnabledAfterCacheAccessed() {
177 final Descriptor descriptor = new Descriptor(new Module());
178
179
180 when(delegate.getEnabledModuleDescriptorsByClass(Descriptor.class)).thenReturn(Collections.<Descriptor>emptyList());
181
182
183 List<Descriptor> result = cachingPluginAccessor.getEnabledModuleDescriptorsByClass(Descriptor.class);
184 assertThat(result, empty());
185
186
187 when(delegate.getEnabledModuleDescriptorsByClass(Descriptor.class)).thenReturn(singletonList(descriptor));
188 pluginEventManager.broadcast(new PluginModuleEnabledEvent(descriptor));
189
190 result = cachingPluginAccessor.getEnabledModuleDescriptorsByClass(Descriptor.class);
191 assertThat(result, contains(descriptor));
192 }
193
194 @Test
195 public void testGetEnabledModulesByClassDelegateShouldCalculateAtMostOnce() {
196
197 cachingPluginAccessor.getEnabledModulesByClass(Module.class);
198 cachingPluginAccessor.getEnabledModulesByClass(Module.class);
199
200
201
202 verify(delegate, times(1)).getEnabledPlugins();
203 verify(delegate, never()).getEnabledModulesByClass(any(Class.class));
204
205
206 pluginEventManager.broadcast(new PluginModuleEnabledEvent(new Descriptor(new Module())));
207 cachingPluginAccessor.getEnabledModulesByClass(Module.class);
208 cachingPluginAccessor.getEnabledModulesByClass(Module.class);
209
210
211 verify(delegate, times(2)).getEnabledPlugins();
212 verify(delegate, never()).getEnabledModulesByClass(any(Class.class));
213 }
214
215 @Test
216 public void testGetEnabledModulesByClassFlushCacheAfterAnyPluginEnable() {
217
218 cachingPluginAccessor.getEnabledModulesByClass(Module.class);
219
220
221
222 verify(delegate, times(1)).getEnabledPlugins();
223 verify(delegate, never()).getEnabledModulesByClass(any(Class.class));
224
225 pluginEventManager.broadcast(new PluginEnabledEvent(mock(Plugin.class)));
226 cachingPluginAccessor.getEnabledModulesByClass(Module.class);
227 cachingPluginAccessor.getEnabledModulesByClass(Module.class);
228
229
230 verify(delegate, times(2)).getEnabledPlugins();
231 verify(delegate, never()).getEnabledModulesByClass(any(Class.class));
232 }
233
234 @Test
235 public void testGetEnabledModulesByClassFlushCacheAfterAnyPluginDisable() {
236
237 cachingPluginAccessor.getEnabledModulesByClass(Module.class);
238
239
240
241 verify(delegate, times(1)).getEnabledPlugins();
242 verify(delegate, never()).getEnabledModulesByClass(any(Class.class));
243
244 pluginEventManager.broadcast(new PluginDisabledEvent(mock(Plugin.class)));
245 cachingPluginAccessor.getEnabledModulesByClass(Module.class);
246 cachingPluginAccessor.getEnabledModulesByClass(Module.class);
247
248
249 verify(delegate, times(2)).getEnabledPlugins();
250 verify(delegate, never()).getEnabledModulesByClass(any(Class.class));
251 }
252
253 @Test
254 public void testGetEnabledModulesByClassFlushCacheAfterAnyPluginModuleDisable() {
255 Descriptor descriptor = new Descriptor(new Module());
256
257
258 cachingPluginAccessor.getEnabledModulesByClass(Module.class);
259
260
261
262 verify(delegate, times(1)).getEnabledPlugins();
263 verify(delegate, never()).getEnabledModulesByClass(any(Class.class));
264
265 pluginEventManager.broadcast(new PluginModuleDisabledEvent(descriptor, false));
266 cachingPluginAccessor.getEnabledModulesByClass(Module.class);
267 cachingPluginAccessor.getEnabledModulesByClass(Module.class);
268
269
270 verify(delegate, times(2)).getEnabledPlugins();
271 verify(delegate, never()).getEnabledModulesByClass(any(Class.class));
272 }
273
274 @Test
275 public void testGetEnabledModulesByClassChildAndParentClassBeingTrackedSeparately() {
276 final ChildModule childModule = new ChildModule();
277 final ChildDescriptor<ChildModule> childDescriptor = new ChildDescriptor<>(childModule);
278 childDescriptor.enabled();
279 final ParentModule parentModule = new ParentModule();
280 final ParentDescriptor<ParentModule> parentDescriptor = new ParentDescriptor<>(parentModule);
281 parentDescriptor.enabled();
282
283
284 final Plugin plugin = mock(Plugin.class);
285 when(delegate.getEnabledPlugins()).thenReturn(newArrayList(plugin));
286 when(plugin.getModuleDescriptors()).thenReturn(Lists.<ModuleDescriptor<?>>newArrayList(parentDescriptor, childDescriptor));
287
288 assertThat(cachingPluginAccessor.getEnabledModulesByClass(ChildModule.class),
289 contains(childModule));
290 assertThat(cachingPluginAccessor.getEnabledModulesByClass(ParentModule.class),
291 containsInAnyOrder(parentModule, childModule));
292 }
293
294 @Test
295 public void testGetEnabledModulesByClassWhenModuleEnabledBeforeCacheAccessed() {
296 final Module module = new Module();
297 final Descriptor descriptor = new Descriptor(module);
298 descriptor.enabled();
299
300
301 final Plugin plugin = mock(Plugin.class);
302 when(delegate.getEnabledPlugins()).thenReturn(newArrayList(plugin));
303 when(plugin.getModuleDescriptors()).thenReturn(Collections.<ModuleDescriptor<?>>singletonList(descriptor));
304
305
306 List<Module> result = cachingPluginAccessor.getEnabledModulesByClass(Module.class);
307 assertThat(result, contains(module));
308 }
309
310 @Test
311 public void testGetEnabledModulesByClassWhenModuleEnabledAfterCacheAccessed() {
312 final Module module = new Module();
313 final Descriptor descriptor = new Descriptor(module);
314 assertFalse(descriptor.isEnabled());
315
316
317 final Plugin plugin = mock(Plugin.class);
318 when(delegate.getEnabledPlugins()).thenReturn(newArrayList(plugin));
319 when(plugin.getModuleDescriptors()).thenReturn(Collections.<ModuleDescriptor<?>>singletonList(descriptor));
320
321
322 List<Module> result = cachingPluginAccessor.getEnabledModulesByClass(Module.class);
323 assertThat(result, empty());
324
325
326 descriptor.enabled();
327 pluginEventManager.broadcast(new PluginModuleEnabledEvent(descriptor));
328
329 result = cachingPluginAccessor.getEnabledModulesByClass(Module.class);
330 assertThat(result, contains(module));
331 }
332
333 @Test
334 public void testGetEnabledModulesByClassDoesNotCacheModulesOnlyDescriptors() {
335
336 final Module module1 = mock(Module.class, "module1");
337 final Module module2 = mock(Module.class, "module2");
338 final Module module3 = mock(Module.class, "module3");
339 final MockModuleDescriptor<Module> descriptor = new MockModuleDescriptor<Module>(mock(Plugin.class), "descriptor", module1) {
340 private Iterator<Module> modules = Iterators.forArray(module1, module2, module3);
341
342 @Override
343 public Module getModule() {
344 return modules.next();
345 }
346 };
347 descriptor.enabled();
348
349
350 final Plugin plugin = mock(Plugin.class);
351 when(delegate.getEnabledPlugins()).thenReturn(newArrayList(plugin));
352 when(plugin.getModuleDescriptors()).thenReturn(Collections.<ModuleDescriptor<?>>singletonList(descriptor));
353
354 List<Module> result = cachingPluginAccessor.getEnabledModulesByClass(Module.class);
355 assertEquals(1, result.size());
356 assertThat(result.get(0), sameInstance(module1));
357
358
359 result = cachingPluginAccessor.getEnabledModulesByClass(Module.class);
360 assertEquals(1, result.size());
361 assertThat(result.get(0), sameInstance(module2));
362
363 result = cachingPluginAccessor.getEnabledModulesByClass(Module.class);
364 assertEquals(1, result.size());
365 assertThat(result.get(0), sameInstance(module3));
366 }
367
368 class Module {
369 }
370
371 class ParentModule {
372 }
373
374 class ChildModule extends ParentModule {
375 }
376
377 class Descriptor extends MockModuleDescriptor<Module> {
378 public Descriptor(Module module) {
379 super(mock(Plugin.class), "descriptorKey", module);
380 }
381 }
382
383 class ParentDescriptor<M extends ParentModule> extends MockModuleDescriptor<M> {
384 public ParentDescriptor(String key, M module) {
385 super(mock(Plugin.class), key, module);
386 }
387
388 public ParentDescriptor(M module) {
389 this("parentDescriptorKey", module);
390 }
391 }
392
393 class ChildDescriptor<M extends ChildModule> extends ParentDescriptor<M> {
394 public ChildDescriptor(M module) {
395 super("childDescriptorKey", module);
396 }
397 }
398 }