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