1 package it.com.atlassian.plugin.manager;
2
3 import com.atlassian.plugin.DefaultModuleDescriptorFactory;
4 import com.atlassian.plugin.ModuleDescriptor;
5 import com.atlassian.plugin.PluginAccessor;
6 import com.atlassian.plugin.PluginException;
7 import com.atlassian.plugin.PluginInternal;
8 import com.atlassian.plugin.PluginParseException;
9 import com.atlassian.plugin.descriptors.AbstractModuleDescriptor;
10 import com.atlassian.plugin.descriptors.UnrecognisedModuleDescriptor;
11 import com.atlassian.plugin.event.PluginEventListener;
12 import com.atlassian.plugin.event.PluginEventManager;
13 import com.atlassian.plugin.event.events.PluginModuleDisabledEvent;
14 import com.atlassian.plugin.event.events.PluginModuleDisablingEvent;
15 import com.atlassian.plugin.event.events.PluginModuleEnabledEvent;
16 import com.atlassian.plugin.event.events.PluginModuleEnablingEvent;
17 import com.atlassian.plugin.event.impl.DefaultPluginEventManager;
18 import com.atlassian.plugin.factories.LegacyDynamicPluginFactory;
19 import com.atlassian.plugin.factories.PluginFactory;
20 import com.atlassian.plugin.hostcontainer.DefaultHostContainer;
21 import com.atlassian.plugin.loaders.ClassPathPluginLoader;
22 import com.atlassian.plugin.loaders.DirectoryPluginLoader;
23 import com.atlassian.plugin.loaders.PluginLoader;
24 import com.atlassian.plugin.loaders.SinglePluginLoader;
25 import com.atlassian.plugin.manager.DefaultPluginManager;
26 import com.atlassian.plugin.manager.store.MemoryPluginPersistentStateStore;
27 import com.atlassian.plugin.module.ModuleFactory;
28 import com.atlassian.plugin.test.PluginJarBuilder;
29 import com.google.common.base.Function;
30 import com.google.common.collect.ImmutableList;
31 import org.dom4j.Element;
32 import org.dom4j.dom.DOMElement;
33 import org.hamcrest.Matchers;
34 import org.junit.After;
35 import org.junit.Before;
36 import org.junit.Rule;
37 import org.junit.Test;
38 import org.junit.rules.ExpectedException;
39 import org.junit.runner.RunWith;
40 import org.junit.runners.Parameterized;
41
42 import java.io.File;
43 import java.nio.file.Files;
44 import java.util.ArrayList;
45 import java.util.Collection;
46 import java.util.Collections;
47 import java.util.List;
48
49 import static org.hamcrest.Matchers.containsString;
50 import static org.hamcrest.Matchers.instanceOf;
51 import static org.hamcrest.Matchers.nullValue;
52 import static org.hamcrest.collection.IsEmptyCollection.empty;
53 import static org.hamcrest.collection.IsEmptyIterable.emptyIterable;
54 import static org.hamcrest.core.Is.is;
55 import static org.junit.Assert.assertThat;
56 import static org.mockito.Mockito.mock;
57 import static org.mockito.Mockito.when;
58
59
60
61
62 @RunWith(Parameterized.class)
63 public class TestDefaultPluginManagerDynamicModules {
64 protected static final String PLUGIN_KEY = "pluginKey";
65 protected static final String PLUGIN_NAME = "pluginName";
66 protected static final String PLUGIN_VERSION = "3.2.1";
67
68 private static final String MODULE_TYPE = "moduleType";
69 private static final String MODULE_KEY = "moduleKey";
70 private static final String MODULE_CLASS = "moduleClass";
71
72 @Rule
73 public final ExpectedException expectedException = ExpectedException.none();
74
75 private PluginLoader pluginLoader;
76
77 protected PluginEventManager pluginEventManager;
78
79 private DefaultPluginManager defaultPluginManager;
80
81 private PluginInternal plugin;
82
83 private List<Class> moduleEvents;
84
85 @Parameterized.Parameters(name = "{0}")
86 public static Collection<Object[]> data() {
87 return ImmutableList.of(
88 new Object[]{"ClassPathPluginLoader", new Function<PluginEventManager, PluginLoader>() {
89 @Override
90 public PluginLoader apply(final PluginEventManager pluginEventManager) {
91 return new ClassPathPluginLoader("test-plugin-dynamic-modules.xml");
92 }
93 }},
94 new Object[]{"SinglePluginLoader", new Function<PluginEventManager, PluginLoader>() {
95 @Override
96 public PluginLoader apply(final PluginEventManager pluginEventManager) {
97 return new SinglePluginLoader("test-plugin-dynamic-modules.xml");
98 }
99 }},
100 new Object[]{"ScanningPluginLoader (DirectoryPluginLoader) <-> LegacyDynamicPluginFactory", new Function<PluginEventManager, PluginLoader>() {
101 @Override
102 public PluginLoader apply(final PluginEventManager pluginEventManager) {
103 try {
104
105 final File pluginDir = Files.createTempDirectory(null).toFile();
106
107
108 new PluginJarBuilder(PLUGIN_NAME)
109 .addPluginInformation(PLUGIN_KEY, PLUGIN_NAME, PLUGIN_VERSION, 1)
110 .build(pluginDir);
111
112
113 final PluginFactory pluginFactory = new LegacyDynamicPluginFactory(PluginAccessor.Descriptor.FILENAME);
114 return new DirectoryPluginLoader(pluginDir, ImmutableList.of(pluginFactory), pluginEventManager);
115 } catch (Exception e) {
116 throw new RuntimeException(e);
117 }
118 }
119 }}
120 );
121 }
122
123 public TestDefaultPluginManagerDynamicModules(final String bleh, final Function<PluginEventManager, PluginLoader> function) {
124
125 pluginEventManager = new DefaultPluginEventManager();
126 pluginEventManager.register(this);
127
128 this.pluginLoader = function.apply(pluginEventManager);
129 }
130
131 @Before
132 public void setUp() throws Exception {
133
134 final DefaultModuleDescriptorFactory moduleDescriptorFactory = new DefaultModuleDescriptorFactory(new DefaultHostContainer());
135 moduleDescriptorFactory.addModuleDescriptor(MODULE_TYPE, DummyModuleDescriptor.class);
136
137
138 defaultPluginManager = new DefaultPluginManager(new MemoryPluginPersistentStateStore(), ImmutableList.of(pluginLoader), moduleDescriptorFactory, pluginEventManager);
139 defaultPluginManager.init();
140
141
142 assertThat(defaultPluginManager.getPlugin(PLUGIN_KEY), instanceOf(PluginInternal.class));
143 plugin = (PluginInternal) defaultPluginManager.getPlugin(PLUGIN_KEY);
144
145
146 moduleEvents = Collections.synchronizedList(new ArrayList<Class>());
147 }
148
149 @After
150 public void tearDown() throws Exception {
151 pluginEventManager.unregister(this);
152 }
153
154 @Test
155 public void removeNonExistent() {
156 final ModuleDescriptor moduleDescriptor = mock(ModuleDescriptor.class);
157 when(moduleDescriptor.getKey()).thenReturn("dodgeyModuleKey");
158
159 expectedException.expect(PluginException.class);
160 expectedException.expectMessage(containsString("dodgeyModuleKey"));
161 expectedException.expectMessage(containsString(PLUGIN_KEY));
162
163 defaultPluginManager.removeDynamicModule(plugin, moduleDescriptor);
164 }
165
166 @Test
167 public void addRemove() throws Exception {
168
169 assertThat(plugin.getModuleDescriptors(), emptyIterable());
170 assertThat(plugin.getDynamicModuleDescriptors(), emptyIterable());
171 assertThat(plugin.getModuleDescriptor(MODULE_KEY), nullValue());
172 assertThat(moduleEvents, empty());
173
174 final ModuleDescriptor moduleDescriptor = addModule();
175
176
177 assertThat(plugin.getDynamicModuleDescriptors(), Matchers.<ModuleDescriptor<?>>containsInAnyOrder(moduleDescriptor));
178 assertThat(plugin.getModuleDescriptors(), Matchers.<ModuleDescriptor<?>>containsInAnyOrder(moduleDescriptor));
179 assertThat(plugin.getModuleDescriptor(MODULE_KEY), Matchers.<ModuleDescriptor<?>>is(moduleDescriptor));
180
181
182 assertThat(moduleDescriptor.isEnabled(), is(true));
183
184
185 assertThat(moduleEvents, Matchers.<Class>contains(PluginModuleEnablingEvent.class, PluginModuleEnabledEvent.class));
186
187
188 defaultPluginManager.removeDynamicModule(plugin, moduleDescriptor);
189
190
191 assertThat(plugin.getModuleDescriptors(), emptyIterable());
192 assertThat(plugin.getDynamicModuleDescriptors(), emptyIterable());
193 assertThat(plugin.getModuleDescriptor(MODULE_KEY), nullValue());
194
195
196 assertThat(moduleEvents, Matchers.<Class>contains(PluginModuleEnablingEvent.class, PluginModuleEnabledEvent.class, PluginModuleDisablingEvent.class, PluginModuleDisabledEvent.class));
197 }
198
199 @Test
200 public void addTwice() {
201 addModule();
202
203
204 assertThat(moduleEvents, Matchers.<Class>contains(PluginModuleEnablingEvent.class, PluginModuleEnabledEvent.class));
205
206 expectedException.expect(PluginException.class);
207 expectedException.expectMessage(containsString(MODULE_KEY));
208
209 addModule();
210
211
212 assertThat(moduleEvents, Matchers.<Class>contains(PluginModuleEnablingEvent.class, PluginModuleEnabledEvent.class));
213 }
214
215 @Test
216 public void addDisabled() {
217
218 final Element e = new DOMElement("bazza");
219 e.addAttribute("key", "mckenzie");
220 final ModuleDescriptor moduleDescriptor = defaultPluginManager.addDynamicModule(plugin, e);
221
222
223 assertThat(moduleDescriptor.isEnabled(), is(false));
224 assertThat(moduleDescriptor, is(instanceOf(UnrecognisedModuleDescriptor.class)));
225
226
227 assertThat(moduleEvents, empty());
228 }
229
230 private ModuleDescriptor addModule() {
231
232 final Element e = new DOMElement(MODULE_TYPE);
233 e.addAttribute("key", MODULE_KEY);
234 e.addAttribute("class", MODULE_CLASS);
235 return defaultPluginManager.addDynamicModule(plugin, e);
236 }
237
238 @PluginEventListener
239 public void onBeforePluginModuleEnabledEvent(PluginModuleEnablingEvent event) {
240 if (MODULE_KEY.equals(event.getModule().getKey())) {
241 moduleEvents.add(PluginModuleEnablingEvent.class);
242 }
243 }
244
245 @PluginEventListener
246 public void onPluginModuleEnabledEvent(PluginModuleEnabledEvent event) {
247 if (MODULE_KEY.equals(event.getModule().getKey())) {
248 moduleEvents.add(PluginModuleEnabledEvent.class);
249 }
250 }
251
252 @PluginEventListener
253 public void onBeforePluginModuleDisabledEvent(PluginModuleDisablingEvent event) {
254 if (MODULE_KEY.equals(event.getModule().getKey())) {
255 moduleEvents.add(PluginModuleDisablingEvent.class);
256 }
257 }
258
259 @PluginEventListener
260 public void onPluginModuleDisableEvent(PluginModuleDisabledEvent event) {
261 if (MODULE_KEY.equals(event.getModule().getKey())) {
262 moduleEvents.add(PluginModuleDisabledEvent.class);
263 }
264 }
265
266 public static class DummyModuleDescriptor extends AbstractModuleDescriptor<Object> {
267 public DummyModuleDescriptor() {
268 super(new DummyModuleFactory());
269 }
270
271 @Override
272 public Object getModule() {
273 return null;
274 }
275 }
276
277 public static class DummyModuleFactory implements ModuleFactory {
278 @Override
279 public <T> T createModule(final String name, final ModuleDescriptor<T> moduleDescriptor)
280 throws PluginParseException {
281 return null;
282 }
283 }
284 }