1 package com.atlassian.plugin.metadata;
2
3 import com.atlassian.plugin.ModuleDescriptor;
4 import com.atlassian.plugin.Plugin;
5 import com.google.common.collect.ImmutableList;
6 import junit.framework.TestCase;
7
8 import java.io.ByteArrayInputStream;
9 import java.io.File;
10 import java.io.FileWriter;
11 import java.io.IOException;
12 import java.io.InputStream;
13 import java.io.UnsupportedEncodingException;
14 import java.net.URL;
15 import java.net.URLClassLoader;
16 import java.util.Collection;
17 import java.util.Collections;
18 import java.util.HashMap;
19 import java.util.Map;
20
21 import static org.mockito.Mockito.mock;
22 import static org.mockito.Mockito.when;
23
24 public class TestClasspathFilePluginMetadata extends TestCase
25 {
26 private final Map<String, Collection<InputStream>> testData;
27 private static final String applicationProvidedPlugins = "my.plugin.a\nmy.plugin.b\nmy.plugin.c\n my.plugin.with.whitespace ";
28 private static final String applicationProvidedPlugins2 = "my.plugin.z";
29 private static final String requiredPlugins = "my.plugin.a\nmy.plugin.b";
30 private static final String requiredModules = "my.plugin.a-mod1\nmy.plugin.c-mod1\n \n #hello \nmy.plugin.c-mod2";
31 private PluginMetadata pluginMetadata;
32
33 public TestClasspathFilePluginMetadata()
34 {
35 testData = new HashMap<String, Collection<InputStream>>();
36 testData.put(ClasspathFilePluginMetadata.APPLICATION_PROVIDED_PLUGINS_FILENAME, toStreams(applicationProvidedPlugins, applicationProvidedPlugins2));
37 testData.put(ClasspathFilePluginMetadata.APPLICATION_REQUIRED_PLUGINS_FILENAME, toStreams(requiredPlugins));
38 testData.put(ClasspathFilePluginMetadata.APPLICATION_REQUIRED_MODULES_FILENAME, toStreams(requiredModules));
39 }
40
41 @Override
42 public void setUp() throws IOException
43 {
44 pluginMetadata = new ClasspathFilePluginMetadata()
45 {
46
47
48 @Override
49 Collection<InputStream> getInputStreamsForFilename(final String fileName)
50 {
51 return testData.get(fileName);
52 }
53 };
54 }
55
56 @Override
57 public void tearDown() throws IOException
58 {
59 pluginMetadata = null;
60 }
61
62 public void testIsUserInstalledPluginPluginFromUser()
63 {
64 final Plugin plugin = mock(Plugin.class);
65 when(plugin.getKey()).thenReturn("my.plugin.d");
66 assertFalse(pluginMetadata.applicationProvided(plugin));
67 }
68
69 public void testIsUserInstalledPluginPluginFromSystem()
70 {
71 final Plugin plugin = mock(Plugin.class);
72 when(plugin.getKey()).thenReturn("my.plugin.a");
73 assertTrue(pluginMetadata.applicationProvided(plugin));
74 }
75
76 public void testPluginRequired()
77 {
78 final Plugin plugin = mock(Plugin.class);
79 when(plugin.getKey()).thenReturn("my.plugin.a");
80 assertTrue(pluginMetadata.required(plugin));
81 }
82
83 public void testPluginNotRequired()
84 {
85 final Plugin plugin = mock(Plugin.class);
86 when(plugin.getKey()).thenReturn("my.plugin.x");
87 assertFalse(pluginMetadata.applicationProvided(plugin));
88 }
89
90 public void testModuleRequired()
91 {
92 final ModuleDescriptor<?> moduleDescriptor = mock(ModuleDescriptor.class);
93 when(moduleDescriptor.getCompleteKey()).thenReturn("my.plugin.c-mod2");
94 assertTrue(pluginMetadata.required(moduleDescriptor));
95 }
96
97 public void testModuleNotRequired()
98 {
99 final ModuleDescriptor<?> moduleDescriptor = mock(ModuleDescriptor.class);
100 when(moduleDescriptor.getCompleteKey()).thenReturn("my.plugin.c-mod3");
101 assertFalse(pluginMetadata.required(moduleDescriptor));
102 }
103
104 public void testModuleIsRequired()
105 {
106 final ModuleDescriptor<?> moduleDescriptor = mock(ModuleDescriptor.class);
107 when(moduleDescriptor.getCompleteKey()).thenReturn("my.plugin.a-mod1");
108 assertTrue(pluginMetadata.required(moduleDescriptor));
109 }
110
111 public void testApplicationProvidedPluginNullPlugin()
112 {
113 try
114 {
115 pluginMetadata.applicationProvided(null);
116 fail("Expected NPE");
117 }
118 catch (final NullPointerException expected)
119 {}
120 }
121
122 public void testRequiredPluginNullPlugin()
123 {
124 try
125 {
126 pluginMetadata.required((Plugin) null);
127 fail("Expected NPE");
128 }
129 catch (final NullPointerException expected)
130 {}
131 }
132
133 public void testRequiredModuleNullModule()
134 {
135 try
136 {
137 pluginMetadata.required((ModuleDescriptor<?>) null);
138 fail("Expected NPE");
139 }
140 catch (final NullPointerException expected)
141 {}
142 }
143
144 public void testIsUserInstalledPluginNoFileOnClasspath()
145 {
146 pluginMetadata = new ClasspathFilePluginMetadata()
147 {
148 @Override
149 Collection<InputStream> getInputStreamsForFilename(final String fileName)
150 {
151 return Collections.emptyList();
152 }
153 };
154
155 final Plugin plugin = mock(Plugin.class);
156 when(plugin.getKey()).thenReturn("my.plugin.a");
157 assertFalse(pluginMetadata.applicationProvided(plugin));
158 assertFalse(pluginMetadata.required(plugin));
159 }
160
161 public void testIsUserInstalledPluginPluginSpecifiedWithWhitespace()
162 {
163 final Plugin plugin = mock(Plugin.class);
164 when(plugin.getKey()).thenReturn("my.plugin.with.whitespace");
165 assertTrue(pluginMetadata.applicationProvided(plugin));
166 }
167
168 public void testBlankLinesInFilesAreNotIncluded()
169 {
170
171
172 final Plugin plugin = mock(Plugin.class);
173 final ModuleDescriptor<?> moduleDescriptor = mock(ModuleDescriptor.class);
174 when(plugin.getKey()).thenReturn("my.plugin.d");
175 when(moduleDescriptor.getCompleteKey()).thenReturn("");
176 when(moduleDescriptor.getPlugin()).thenReturn(plugin);
177
178 assertFalse(pluginMetadata.required(moduleDescriptor));
179 }
180
181 public void testCommentLinesInFilesAreNotIncluded()
182 {
183
184
185 final Plugin plugin = mock(Plugin.class);
186 final ModuleDescriptor<?> moduleDescriptor = mock(ModuleDescriptor.class);
187 when(plugin.getKey()).thenReturn("my.plugin.d");
188 when(moduleDescriptor.getCompleteKey()).thenReturn("#hello");
189 when(moduleDescriptor.getPlugin()).thenReturn(plugin);
190
191 assertFalse(pluginMetadata.required(moduleDescriptor));
192 }
193
194 public void testPluginKeysFromSecondFileIncluded()
195 {
196 final Plugin plugin = mock(Plugin.class);
197 when(plugin.getKey()).thenReturn("my.plugin.z");
198
199 assertTrue(pluginMetadata.applicationProvided(plugin));
200 }
201
202 public void testClassLoading() throws IOException
203 {
204 ClassLoader classLoader = setupAndGetClassloader();
205
206 final Plugin plugin1 = mock(Plugin.class);
207 when(plugin1.getKey()).thenReturn("test1");
208 final Plugin plugin2 = mock(Plugin.class);
209 when(plugin2.getKey()).thenReturn("test2");
210
211 final ClasspathFilePluginMetadata pluginMetadata = new ClasspathFilePluginMetadata(classLoader);
212 assertTrue(pluginMetadata.applicationProvided(plugin1));
213 assertTrue(pluginMetadata.applicationProvided(plugin2));
214 }
215
216 private ClassLoader setupAndGetClassloader() throws IOException
217 {
218 final File tempDir1 = createTempDirectory("dir1");
219
220 final File packageDir1 = new File(tempDir1, "/com/atlassian/plugin/metadata/");
221 packageDir1.mkdirs();
222 packageDir1.deleteOnExit();
223 final File tempDir2 = createTempDirectory("dir2");
224 final File packageDir2 = new File(tempDir2, "/com/atlassian/plugin/metadata/");
225 packageDir2.mkdirs();
226 packageDir2.deleteOnExit();
227
228 final File file1 = new File(packageDir1, "application-provided-plugins.txt");
229 file1.deleteOnExit();
230 final File file2 = new File(packageDir2, "application-provided-plugins.txt");
231 file2.deleteOnExit();
232 FileWriter fileWriter1 = new FileWriter(file1);
233 file1.createNewFile();
234 fileWriter1.append("test1");
235 fileWriter1.close();
236 FileWriter fileWriter2 = new FileWriter(file2);
237 file2.createNewFile();
238 fileWriter2.append("test2");
239 fileWriter2.close();
240 ClassLoader classLoader = new URLClassLoader(new URL[] {tempDir1.toURI().toURL(), tempDir2.toURI().toURL()});
241 return classLoader;
242 }
243
244 static Collection<InputStream> toStreams(final String... names)
245 {
246 final ImmutableList.Builder<InputStream> builder = ImmutableList.builder();
247 for (final String name : names)
248 {
249 try
250 {
251 builder.add(new ByteArrayInputStream(name.getBytes("UTF-8")));
252 }
253 catch (final UnsupportedEncodingException e)
254 {
255 throw new Error("Unable to construct test data", e);
256 }
257 }
258 return builder.build();
259 }
260
261 static File createTempDirectory(final String prefix)
262 {
263 long counter = System.currentTimeMillis();
264
265 File f;
266 final String systemTempDir = getSystemTempDir();
267 do
268 {
269 f = new File(systemTempDir, prefix + counter);
270 counter++;
271 }
272 while (!f.mkdir());
273 f.deleteOnExit();
274 return f;
275 }
276
277
278
279
280
281
282
283
284 static String getSystemTempDir()
285 {
286 return System.getProperty("java.io.tmpdir");
287 }
288
289 }