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.ArgumentMatchers.any;
36 import static org.mockito.ArgumentMatchers.anyString;
37 import static org.mockito.ArgumentMatchers.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.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.getPluginState()).thenReturn(PluginState.ENABLED);
141 when(mockPlugin.getModuleDescriptors()).thenReturn(moduleDescriptors);
142 when(mockPlugin.getDependencies()).thenReturn(new PluginDependencies());
143 return mockPlugin;
144 }
145
146 public static Plugin mockStaticPlugin(final String pluginKey, final ModuleDescriptor<?>... descriptors) {
147 return new StaticPlugin() {
148 {
149 setPluginInformation(new PluginInformation());
150 setEnabledByDefault(true);
151 setKey(pluginKey);
152 }
153
154 @Override
155 public Collection<ModuleDescriptor<?>> getModuleDescriptors() {
156 return Arrays.<ModuleDescriptor<?>>asList(descriptors);
157 }
158
159 @Override
160 public ModuleDescriptor<Object> getModuleDescriptor(final String moduleKey) {
161 for (ModuleDescriptor desc : descriptors) {
162 if (desc.getKey().equals(moduleKey))
163 return desc;
164 }
165 return null;
166 }
167 };
168 }
169
170
171
172
173
174
175
176
177
178 public static Plugin doAnswerPluginStateChangeWhen(
179 final Plugin plugin, final PluginState pluginState, final PluginEventManager pluginEventManager) {
180 final Answer answer = new Answer() {
181 @Override
182 public Object answer(final InvocationOnMock invocation) throws Throwable {
183 when(plugin.getPluginState()).thenReturn(pluginState);
184 pluginEventManager.broadcast(new PluginStateMarkerEvent(plugin, pluginState));
185 return null;
186 }
187 };
188 return doAnswer(answer).when(plugin);
189 }
190
191 public static ModuleDescriptor<?> mockStateChangePluginModule(
192 final String pluginKey, final String moduleKey, final PluginEventManager pluginEventManager) {
193 final ModuleDescriptor<?> module = mock(ModuleDescriptor.class, withSettings().extraInterfaces(StateAware.class));
194 when(module.getPluginKey()).thenReturn(pluginKey);
195 when(module.getCompleteKey()).thenReturn(new ModuleCompleteKey(pluginKey, moduleKey).getCompleteKey());
196 doAnswerModuleStateChangeWhen(module, true, pluginEventManager).enabled();
197 doAnswerModuleStateChangeWhen(module, false, pluginEventManager).disabled();
198 return module;
199 }
200
201 public static Matcher<PluginModuleEvent> pluginModuleStateChange(final ModuleDescriptor module, final boolean enabled) {
202 final Matcher<PluginModuleEvent> pluginModuleEventMatcher = pluginModuleEvent(PluginModuleStateMarkerEvent.class, module);
203 final Matcher<Boolean> pluginModuleStateMatcher = is(enabled);
204
205 return new TypeSafeMatcher<PluginModuleEvent>() {
206 @Override
207 protected boolean matchesSafely(final PluginModuleEvent event) {
208 return pluginModuleEventMatcher.matches(event)
209
210 && pluginModuleStateMatcher.matches(((PluginModuleStateMarkerEvent) event).isEnabled());
211 }
212
213 @Override
214 public void describeTo(final Description description) {
215 pluginModuleEventMatcher.describeTo(description);
216 description.appendText(" and .isEnabled() ");
217 pluginModuleStateMatcher.describeTo(description);
218 }
219 };
220 }
221
222
223
224
225
226
227
228
229
230 public static StateAware doAnswerModuleStateChangeWhen(
231 final ModuleDescriptor<?> module, final boolean enabled, final PluginEventManager pluginEventManager) {
232 final Answer answer = new Answer() {
233 @Override
234 public Object answer(final InvocationOnMock invocation) throws Throwable {
235 when(module.isEnabled()).thenReturn(enabled);
236 pluginEventManager.broadcast(new PluginModuleStateMarkerEvent(module, enabled));
237 return null;
238 }
239 };
240 return doAnswer(answer).when((StateAware) module);
241 }
242
243
244
245
246 public static class PluginModuleStateMarkerEvent extends PluginModuleEvent {
247 private final boolean enabled;
248
249 PluginModuleStateMarkerEvent(final ModuleDescriptor module, final boolean enabled) {
250 super(module);
251 this.enabled = enabled;
252 }
253
254 public boolean isEnabled() {
255 return enabled;
256 }
257
258 @Override
259 public String toString() {
260 return super.toString() + " with enabled " + Boolean.toString(enabled);
261 }
262 }
263
264 public static Matcher<PluginModuleEvent> pluginModuleEvent(final Class clazz, final ModuleDescriptor module) {
265 final Matcher<Class> classMatcher = instanceOf(clazz);
266 final Matcher<ModuleDescriptor> pluginModuleMatcher = is(module);
267 return new TypeSafeMatcher<PluginModuleEvent>() {
268 @Override
269 protected boolean matchesSafely(final PluginModuleEvent pluginModuleEvent) {
270 return classMatcher.matches(pluginModuleEvent) && pluginModuleMatcher.matches(pluginModuleEvent.getModule());
271 }
272
273 @Override
274 public void describeTo(final Description description) {
275 classMatcher.describeTo(description);
276 description.appendText(" for which .getModule() ");
277 pluginModuleMatcher.describeTo(description);
278 }
279 };
280 }
281
282
283
284
285 public static class PluginStateMarkerEvent extends PluginEvent {
286 private final PluginState pluginState;
287
288 PluginStateMarkerEvent(final Plugin plugin, final PluginState pluginState) {
289 super(plugin);
290 this.pluginState = pluginState;
291 }
292
293 public PluginState getPluginState() {
294 return pluginState;
295 }
296
297 @Override
298 public String toString() {
299 return super.toString() + " with pluginState " + pluginState;
300 }
301 }
302
303 public static Matcher<PluginEvent> anyPluginStateChange(final PluginState pluginState, final Plugin... plugin) {
304 final Matcher<PluginEvent> pluginEventMatcher = anyPluginEvent(PluginStateMarkerEvent.class, plugin);
305 final Matcher<PluginState> pluginStateMatcher = is(pluginState);
306
307 return new TypeSafeMatcher<PluginEvent>() {
308 @Override
309 protected boolean matchesSafely(final PluginEvent event) {
310 return pluginEventMatcher.matches(event)
311
312 && pluginStateMatcher.matches(((PluginStateMarkerEvent) event).getPluginState());
313 }
314
315 @Override
316 public void describeTo(final Description description) {
317 pluginEventMatcher.describeTo(description);
318 description.appendText(" and .getPluginState() ");
319 pluginStateMatcher.describeTo(description);
320 }
321 };
322 }
323
324 public static Matcher<PluginEvent> pluginStateChange(final Plugin plugin, final PluginState pluginState) {
325 return anyPluginStateChange(pluginState, plugin);
326 }
327
328 public static Matcher<PluginEvent> anyPluginEvent(final Class clazz, final Plugin... plugins) {
329 final Matcher<Class> classMatcher = instanceOf(clazz);
330 final Matcher<Plugin> pluginMatcher = anyOf(Arrays.stream(plugins).map(Matchers::is).collect(Collectors.toList()));
331
332 return new TypeSafeMatcher<PluginEvent>() {
333 @Override
334 protected boolean matchesSafely(final PluginEvent pluginEvent) {
335 return classMatcher.matches(pluginEvent) && pluginMatcher.matches(pluginEvent.getPlugin());
336 }
337
338 @Override
339 public void describeTo(final Description description) {
340 classMatcher.describeTo(description);
341 description.appendText(" for which .getPlugin() ");
342 pluginMatcher.describeTo(description);
343 }
344 };
345 }
346
347 public static Matcher<PluginEvent> pluginEvent(final Class clazz, final Plugin plugin) {
348 return anyPluginEvent(clazz, plugin);
349 }
350 }