1 package com.atlassian.plugin.loaders;
2
3 import java.io.File;
4 import java.io.IOException;
5 import java.net.URISyntaxException;
6 import java.util.Collection;
7 import java.util.Collections;
8 import java.util.List;
9
10 import com.atlassian.plugin.ModuleDescriptorFactory;
11 import com.atlassian.plugin.Plugin;
12 import com.atlassian.plugin.PluginArtifact;
13 import com.atlassian.plugin.PluginException;
14 import com.atlassian.plugin.event.PluginEventManager;
15 import com.atlassian.plugin.loaders.classloading.DeploymentUnit;
16 import com.atlassian.plugin.loaders.classloading.Scanner;
17 import com.atlassian.plugin.test.PluginJarBuilder;
18 import com.atlassian.plugin.factories.PluginFactory;
19 import com.atlassian.plugin.test.PluginTestUtils;
20
21 import com.google.common.base.Function;
22 import com.google.common.collect.ImmutableList;
23 import com.google.common.collect.Iterables;
24 import com.google.common.collect.Lists;
25
26 import org.apache.commons.io.FileUtils;
27 import org.junit.After;
28 import org.junit.Before;
29 import org.junit.Test;
30 import org.mockito.ArgumentCaptor;
31
32
33 import static org.hamcrest.Matchers.containsInAnyOrder;
34 import static org.hamcrest.Matchers.instanceOf;
35 import static org.junit.Assert.assertEquals;
36 import static org.junit.Assert.assertThat;
37 import static org.junit.Assert.assertTrue;
38 import static org.junit.Assert.fail;
39 import static org.mockito.Matchers.isA;
40 import static org.mockito.Matchers.same;
41 import static org.mockito.Mockito.mock;
42 import static org.mockito.Mockito.verify;
43 import static org.mockito.Mockito.when;
44
45
46 public class TestBundledPluginLoader
47 {
48 private File pluginDir;
49
50 private static final String fooXml = "foo.xml";
51
52 @Before
53 public void createTemporaryDirectory() throws IOException, URISyntaxException
54 {
55 pluginDir = PluginTestUtils.createTempDirectory(TestBundledPluginLoader.class);
56 }
57
58 @After
59 public void deleteTemporaryDirectory() throws Exception
60 {
61 FileUtils.deleteDirectory(pluginDir);
62 pluginDir = null;
63 }
64
65 @Test
66 public void loaderFromZipContainsExpectedFiles() throws IOException
67 {
68 File bundledZip = buildBundledZip();
69 final BundledPluginLoader loader = buildBundledPluginLoader(bundledZip, Collections.<PluginFactory>emptyList());
70 assertLoaderContains(loader, fooXml);
71 }
72
73 @Test
74 public void loaderFromDirectoryContainsExpectedFiles() throws IOException
75 {
76 final File dir = PluginTestUtils.createTempDirectory(TestBundledPluginLoader.class);
77 FileUtils.writeStringToFile(new File(dir, "foo.txt"), "hello");
78
79 final BundledPluginLoader loader = buildBundledPluginLoader(dir, Collections.<PluginFactory>emptyList());
80 assertLoaderContains(loader, "foo.txt");
81 }
82
83 @Test
84 public void loaderFromFileListContainsExpectedFiles() throws IOException
85 {
86 final File dir = PluginTestUtils.createTempDirectory(TestBundledPluginLoader.class);
87 FileUtils.writeStringToFile(new File(dir, "foo.txt"), "hello");
88 FileUtils.writeStringToFile(new File(dir, "bar.txt"), "world");
89 File listFile = new File(dir, "bundled-plugins.list");
90 FileUtils.writeStringToFile(listFile, "foo.txt\nbar.txt");
91
92 final BundledPluginLoader loader = buildBundledPluginLoader(listFile, Collections.<PluginFactory>emptyList());
93 assertLoaderContains(loader, "foo.txt", "bar.txt");
94 }
95
96 @Test
97 public void loaderScannerDoesNotRemoveUnderlyingFiles() throws IOException
98 {
99 File bundledZip = buildBundledZip();
100
101 final BundledPluginLoader loader = buildBundledPluginLoader(bundledZip, Collections.<PluginFactory>emptyList());
102 final Scanner scanner = loader.scanner;
103 assertLoaderContains(loader, fooXml);
104 final Collection<DeploymentUnit> units = scanner.getDeploymentUnits();
105 final int countBefore = units.size();
106 int found = 0;
107 for (DeploymentUnit unit : units)
108 {
109 final File file = unit.getPath();
110 if (fooXml.equals(file.getName()))
111 {
112 found += 1;
113 assertTrue(file.exists());
114 scanner.remove(unit);
115
116 assertTrue(file.exists());
117 }
118 }
119
120 assertEquals(1, found);
121
122 assertEquals(countBefore, scanner.getDeploymentUnits().size());
123 }
124
125 @Test
126 public void loaderRemoveDoesUninstallPlugin() throws IOException
127 {
128 File bundledZip = buildBundledZip();
129 Plugin mockPlugin = mock(Plugin.class);
130 PluginFactory pluginFactory = mock(PluginFactory.class);
131 ModuleDescriptorFactory moduleDescriptorFactory = mock(ModuleDescriptorFactory.class);
132
133 final String key = "plugin.key.foo";
134 ArgumentCaptor<PluginArtifact> pluginArtifact = ArgumentCaptor.forClass(PluginArtifact.class);
135
136 when(mockPlugin.getKey()).thenReturn(key);
137 when(mockPlugin.isDeleteable()).thenReturn(true);
138 when(mockPlugin.isUninstallable()).thenReturn(true);
139 when(pluginFactory.canCreate(isA(PluginArtifact.class))).thenReturn(key);
140 when(pluginFactory.create(pluginArtifact.capture(), same(moduleDescriptorFactory))).thenReturn(mockPlugin);
141
142 final BundledPluginLoader loader = buildBundledPluginLoader(bundledZip, ImmutableList.of(pluginFactory));
143 Collection<Plugin> plugins = Lists.newArrayList(loader.loadAllPlugins(moduleDescriptorFactory));
144 assertEquals(1, plugins.size());
145
146 Plugin bundledPlugin = Iterables.getOnlyElement(plugins);
147 assertEquals(key, bundledPlugin.getKey());
148 assertTrue(bundledPlugin.isBundledPlugin());
149 assertTrue(bundledPlugin.isDeleteable());
150 verify(mockPlugin).isDeleteable();
151
152
153 loader.removePlugin(bundledPlugin);
154 verify(mockPlugin).isUninstallable();
155 verify(mockPlugin).uninstall();
156
157 assertTrue(pluginArtifact.getValue().toFile().exists());
158
159 try
160 {
161
162
163
164
165
166
167 loader.removePlugin(bundledPlugin);
168 fail();
169 }
170 catch (PluginException pe)
171 {
172
173 }
174 }
175
176 @Test
177 public void pluginArtifactsAllowReference() throws IOException
178 {
179
180 final File dir = PluginTestUtils.createTempDirectory(TestBundledPluginLoader.class);
181 final File bundleList = new File(dir, "bundled-plugins.list");
182 FileUtils.writeStringToFile(bundleList, "some.jar\n");
183 final Plugin mockPlugin = mock(Plugin.class);
184 final PluginFactory pluginFactory = mock(PluginFactory.class);
185 final ModuleDescriptorFactory moduleDescriptorFactory = mock(ModuleDescriptorFactory.class);
186
187 final String key = "plugin.key.foo";
188 final ArgumentCaptor<PluginArtifact> pluginArtifact = ArgumentCaptor.forClass(PluginArtifact.class);
189
190 when(mockPlugin.getKey()).thenReturn(key);
191 when(pluginFactory.canCreate(isA(PluginArtifact.class))).thenReturn(key);
192 when(pluginFactory.create(pluginArtifact.capture(), same(moduleDescriptorFactory))).thenReturn(mockPlugin);
193
194 final BundledPluginLoader loader = buildBundledPluginLoader(bundleList, ImmutableList.of(pluginFactory));
195 loader.loadAllPlugins(moduleDescriptorFactory);
196 assertThat(pluginArtifact.getValue(), instanceOf(PluginArtifact.AllowsReference.class));
197 assertTrue(((PluginArtifact.AllowsReference) pluginArtifact.getValue()).allowsReference());
198 }
199
200 private File buildBundledZip() throws IOException
201 {
202 return new PluginJarBuilder("bundledPlugins")
203 .addResource(fooXml, "<foo/>")
204 .buildWithNoManifest();
205 }
206
207 private BundledPluginLoader buildBundledPluginLoader(File bundle, List<PluginFactory> pluginFactories) throws IOException
208 {
209 return new BundledPluginLoader(bundle.toURI().toURL(), pluginDir, pluginFactories, mock(PluginEventManager.class));
210 }
211
212 private void assertLoaderContains(final BundledPluginLoader loader, String ... expectedEntries)
213 {
214 final Collection<DeploymentUnit> scanned = loader.scanner.scan();
215 final Iterable<String> actualEntries = Iterables.transform(scanned, new Function<DeploymentUnit, String>()
216 {
217 @Override
218 public String apply(DeploymentUnit unit)
219 {
220 return unit.getPath().getName();
221 }
222 });
223 assertThat(actualEntries, containsInAnyOrder(expectedEntries));
224 }
225 }