1 package com.atlassian.plugin.manager;
2
3 import com.atlassian.plugin.ModuleCompleteKey;
4 import com.atlassian.plugin.ModuleDescriptor;
5 import com.atlassian.plugin.ModuleDescriptorFactory;
6 import com.atlassian.plugin.Plugin;
7 import com.atlassian.plugin.PluginDependencies;
8 import com.atlassian.plugin.PluginInformation;
9 import com.atlassian.plugin.PluginRestartState;
10 import com.atlassian.plugin.PluginState;
11 import com.atlassian.plugin.StateAware;
12 import com.atlassian.plugin.descriptors.AbstractModuleDescriptor;
13 import com.atlassian.plugin.event.PluginEventManager;
14 import com.atlassian.plugin.event.events.PluginEvent;
15 import com.atlassian.plugin.event.events.PluginModuleEvent;
16 import com.atlassian.plugin.impl.StaticPlugin;
17 import com.atlassian.plugin.loaders.PluginLoader;
18 import com.atlassian.plugin.module.ModuleFactory;
19 import com.google.common.collect.ImmutableList;
20 import com.google.common.collect.Lists;
21 import org.hamcrest.Description;
22 import org.hamcrest.Matcher;
23 import org.hamcrest.Matchers;
24 import org.hamcrest.TypeSafeMatcher;
25 import org.mockito.invocation.InvocationOnMock;
26 import org.mockito.stubbing.Answer;
27
28 import java.util.Arrays;
29 import java.util.Collection;
30 import java.util.stream.Collectors;
31
32 import static org.hamcrest.Matchers.instanceOf;
33 import static org.hamcrest.Matchers.is;
34 import static org.hamcrest.core.AnyOf.anyOf;
35 import static org.mockito.Matchers.any;
36 import static org.mockito.Matchers.anyString;
37 import static org.mockito.Matchers.isA;
38 import static org.mockito.Mockito.RETURNS_DEEP_STUBS;
39 import static org.mockito.Mockito.doAnswer;
40 import static org.mockito.Mockito.mock;
41 import static org.mockito.Mockito.when;
42 import static org.mockito.Mockito.withSettings;
43
44 class DefaultPluginManagerMocks {
45 public enum FailureMode {
46 FAIL_TO_ENABLE,
47 FAIL_TO_DISABLE
48 }
49
50 public static ModuleDescriptor<Object> mockFailingModuleDescriptor(final String completeKey, final FailureMode... failureModes) {
51 return new AbstractModuleDescriptor<Object>(ModuleFactory.LEGACY_MODULE_FACTORY) {
52 @Override
53 public String getKey() {
54 return completeKey.substring(completeKey.lastIndexOf(":") + 1, completeKey.length());
55 }
56
57 @Override
58 public String getCompleteKey() {
59 return completeKey;
60 }
61
62 @Override
63 public void enabled() {
64 if (Lists.newArrayList(failureModes).contains(FailureMode.FAIL_TO_ENABLE))
65 throw new IllegalArgumentException("Cannot enable");
66 }
67
68 @Override
69 public void disabled() {
70 if (Lists.newArrayList(failureModes).contains(FailureMode.FAIL_TO_DISABLE))
71 throw new IllegalArgumentException("Cannot disable");
72 }
73
74 @Override
75 public Object getModule() {
76 return null;
77 }
78 };
79 }
80
81 public static PluginLoader mockPluginLoaderForPlugins(final Plugin... plugins) {
82 final PluginLoader pluginLoader = mock(PluginLoader.class);
83 when(pluginLoader.loadAllPlugins(isA(ModuleDescriptorFactory.class))).thenReturn(Arrays.asList(plugins));
84 when(pluginLoader.supportsRemoval()).thenReturn(true);
85 return pluginLoader;
86 }
87
88 public static void mockPluginsSortOrder(final Plugin... mockPlugins) {
89 for (int i = 0; i < mockPlugins.length; ++i) {
90 for (int j = 0; j < mockPlugins.length; ++j) {
91
92 when(mockPlugins[i].compareTo(mockPlugins[j])).thenReturn(i - j);
93 }
94 }
95 }
96
97 public static PluginPersistentStateStore mockPluginPersistentStateStore() {
98 final PluginPersistentStateStore pluginPersistentStateStore = mock(PluginPersistentStateStore.class, RETURNS_DEEP_STUBS);
99 when(pluginPersistentStateStore.load().getPluginRestartState(anyString())).thenReturn(PluginRestartState.NONE);
100 when(pluginPersistentStateStore.load().isEnabled(any(Plugin.class))).thenReturn(true);
101 when(pluginPersistentStateStore.load().isEnabled(any(ModuleDescriptor.class))).thenReturn(true);
102 return pluginPersistentStateStore;
103 }
104
105 public static Plugin mockStateChangePlugin(final String pluginKey, final PluginEventManager pluginEventManager) {
106 final Plugin plugin = mockPlugin(pluginKey);
107
108 doAnswerPluginStateChangeWhen(plugin, PluginState.INSTALLED, pluginEventManager).install();
109 doAnswerPluginStateChangeWhen(plugin, PluginState.ENABLED, pluginEventManager).enable();
110 doAnswerPluginStateChangeWhen(plugin, PluginState.DISABLED, pluginEventManager).disable();
111 return plugin;
112 }
113
114 public static Plugin mockPluginWithVersion(final String pluginKey, final String version) {
115 final Plugin plugin = mockPlugin(pluginKey);
116 when(plugin.getPluginInformation().getVersion()).thenReturn(version);
117 return plugin;
118 }
119
120 public static Plugin mockPlugin(final String pluginKey) {
121 final Plugin plugin = mock(Plugin.class, RETURNS_DEEP_STUBS);
122 when(plugin.getKey()).thenReturn(pluginKey);
123 when(plugin.getPluginState()).thenReturn(PluginState.UNINSTALLED);
124 when(plugin.getModuleDescriptors()).thenReturn(ImmutableList.<ModuleDescriptor<?>>of());
125 when(plugin.getPluginInformation().satisfiesMinJavaVersion()).thenReturn(true);
126 when(plugin.isUninstallable()).thenReturn(true);
127 when(plugin.toString()).thenAnswer(new Answer<String>() {
128 @Override
129 public String answer(InvocationOnMock invocation) throws Throwable {
130 return plugin.getKey() + ":" + plugin.getPluginInformation().getVersion();
131 }
132 });
133 return plugin;
134 }
135
136 public static Plugin mockTestPlugin(Collection moduleDescriptors) {
137 final Plugin mockPlugin = mock(Plugin.class);
138 when(mockPlugin.getKey()).thenReturn("some-plugin-key");
139 when(mockPlugin.isEnabledByDefault()).thenReturn(true);
140 when(mockPlugin.isEnabled()).thenReturn(true);
141 when(mockPlugin.getPluginState()).thenReturn(PluginState.ENABLED);
142 when(mockPlugin.getModuleDescriptors()).thenReturn(moduleDescriptors);
143 when(mockPlugin.getDependencies()).thenReturn(new PluginDependencies());
144 return mockPlugin;
145 }
146
147 public static Plugin mockStaticPlugin(final String pluginKey, final ModuleDescriptor<?>... descriptors) {
148 return new StaticPlugin() {
149 {
150 setPluginInformation(new PluginInformation());
151 setEnabledByDefault(true);
152 setKey(pluginKey);
153 }
154
155 @Override
156 public Collection<ModuleDescriptor<?>> getModuleDescriptors() {
157 return Arrays.<ModuleDescriptor<?>>asList(descriptors);
158 }
159
160 @Override
161 public ModuleDescriptor<Object> getModuleDescriptor(final String moduleKey) {
162 for (ModuleDescriptor desc : descriptors) {
163 if (desc.getKey().equals(moduleKey))
164 return desc;
165 }
166 return null;
167 }
168 };
169 }
170
171
172
173
174
175
176
177
178
179 public static Plugin doAnswerPluginStateChangeWhen(
180 final Plugin plugin, final PluginState pluginState, final PluginEventManager pluginEventManager) {
181 final Answer answer = new Answer() {
182 @Override
183 public Object answer(final InvocationOnMock invocation) throws Throwable {
184 when(plugin.getPluginState()).thenReturn(pluginState);
185 pluginEventManager.broadcast(new PluginStateMarkerEvent(plugin, pluginState));
186 return null;
187 }
188 };
189 return doAnswer(answer).when(plugin);
190 }
191
192 public static ModuleDescriptor<?> mockStateChangePluginModule(
193 final String pluginKey, final String moduleKey, final PluginEventManager pluginEventManager) {
194 final ModuleDescriptor<?> module = mock(ModuleDescriptor.class, withSettings().extraInterfaces(StateAware.class));
195 when(module.getPluginKey()).thenReturn(pluginKey);
196 when(module.getCompleteKey()).thenReturn(new ModuleCompleteKey(pluginKey, moduleKey).getCompleteKey());
197 doAnswerModuleStateChangeWhen(module, true, pluginEventManager).enabled();
198 doAnswerModuleStateChangeWhen(module, false, pluginEventManager).disabled();
199 return module;
200 }
201
202 public static Matcher<PluginModuleEvent> pluginModuleStateChange(final ModuleDescriptor module, final boolean enabled) {
203 final Matcher<PluginModuleEvent> pluginModuleEventMatcher = pluginModuleEvent(PluginModuleStateMarkerEvent.class, module);
204 final Matcher<Boolean> pluginModuleStateMatcher = is(enabled);
205
206 return new TypeSafeMatcher<PluginModuleEvent>() {
207 @Override
208 protected boolean matchesSafely(final PluginModuleEvent event) {
209 return pluginModuleEventMatcher.matches(event)
210
211 && pluginModuleStateMatcher.matches(((PluginModuleStateMarkerEvent) event).isEnabled());
212 }
213
214 @Override
215 public void describeTo(final Description description) {
216 pluginModuleEventMatcher.describeTo(description);
217 description.appendText(" and .isEnabled() ");
218 pluginModuleStateMatcher.describeTo(description);
219 }
220 };
221 }
222
223
224
225
226
227
228
229
230
231 public static StateAware doAnswerModuleStateChangeWhen(
232 final ModuleDescriptor<?> module, final boolean enabled, final PluginEventManager pluginEventManager) {
233 final Answer answer = new Answer() {
234 @Override
235 public Object answer(final InvocationOnMock invocation) throws Throwable {
236 when(module.isEnabled()).thenReturn(enabled);
237 pluginEventManager.broadcast(new PluginModuleStateMarkerEvent(module, enabled));
238 return null;
239 }
240 };
241 return doAnswer(answer).when((StateAware) module);
242 }
243
244
245
246
247 public static class PluginModuleStateMarkerEvent extends PluginModuleEvent {
248 private final boolean enabled;
249
250 PluginModuleStateMarkerEvent(final ModuleDescriptor module, final boolean enabled) {
251 super(module);
252 this.enabled = enabled;
253 }
254
255 public boolean isEnabled() {
256 return enabled;
257 }
258
259 @Override
260 public String toString() {
261 return super.toString() + " with enabled " + Boolean.toString(enabled);
262 }
263 }
264
265 public static Matcher<PluginModuleEvent> pluginModuleEvent(final Class clazz, final ModuleDescriptor module) {
266 final Matcher<Class> classMatcher = instanceOf(clazz);
267 final Matcher<ModuleDescriptor> pluginModuleMatcher = is(module);
268 return new TypeSafeMatcher<PluginModuleEvent>() {
269 @Override
270 protected boolean matchesSafely(final PluginModuleEvent pluginModuleEvent) {
271 return classMatcher.matches(pluginModuleEvent) && pluginModuleMatcher.matches(pluginModuleEvent.getModule());
272 }
273
274 @Override
275 public void describeTo(final Description description) {
276 classMatcher.describeTo(description);
277 description.appendText(" for which .getModule() ");
278 pluginModuleMatcher.describeTo(description);
279 }
280 };
281 }
282
283
284
285
286 public static class PluginStateMarkerEvent extends PluginEvent {
287 private final PluginState pluginState;
288
289 PluginStateMarkerEvent(final Plugin plugin, final PluginState pluginState) {
290 super(plugin);
291 this.pluginState = pluginState;
292 }
293
294 public PluginState getPluginState() {
295 return pluginState;
296 }
297
298 @Override
299 public String toString() {
300 return super.toString() + " with pluginState " + pluginState;
301 }
302 }
303
304 public static Matcher<PluginEvent> anyPluginStateChange(final PluginState pluginState, final Plugin... plugin) {
305 final Matcher<PluginEvent> pluginEventMatcher = anyPluginEvent(PluginStateMarkerEvent.class, plugin);
306 final Matcher<PluginState> pluginStateMatcher = is(pluginState);
307
308 return new TypeSafeMatcher<PluginEvent>() {
309 @Override
310 protected boolean matchesSafely(final PluginEvent event) {
311 return pluginEventMatcher.matches(event)
312
313 && pluginStateMatcher.matches(((PluginStateMarkerEvent) event).getPluginState());
314 }
315
316 @Override
317 public void describeTo(final Description description) {
318 pluginEventMatcher.describeTo(description);
319 description.appendText(" and .getPluginState() ");
320 pluginStateMatcher.describeTo(description);
321 }
322 };
323 }
324
325 public static Matcher<PluginEvent> pluginStateChange(final Plugin plugin, final PluginState pluginState) {
326 return anyPluginStateChange(pluginState, plugin);
327 }
328
329 public static Matcher<PluginEvent> anyPluginEvent(final Class clazz, final Plugin... plugins) {
330 final Matcher<Class> classMatcher = instanceOf(clazz);
331 final Matcher<Plugin> pluginMatcher = anyOf(Arrays.stream(plugins).map(Matchers::is).collect(Collectors.toList()));
332
333 return new TypeSafeMatcher<PluginEvent>() {
334 @Override
335 protected boolean matchesSafely(final PluginEvent pluginEvent) {
336 return classMatcher.matches(pluginEvent) && pluginMatcher.matches(pluginEvent.getPlugin());
337 }
338
339 @Override
340 public void describeTo(final Description description) {
341 classMatcher.describeTo(description);
342 description.appendText(" for which .getPlugin() ");
343 pluginMatcher.describeTo(description);
344 }
345 };
346 }
347
348 public static Matcher<PluginEvent> pluginEvent(final Class clazz, final Plugin plugin) {
349 return anyPluginEvent(clazz, plugin);
350 }
351 }