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 com.google.common.collect.ImmutableMap;
7 import org.junit.After;
8 import org.junit.Before;
9 import org.junit.Rule;
10 import org.junit.Test;
11 import org.junit.rules.TemporaryFolder;
12
13 import java.io.ByteArrayInputStream;
14 import java.io.File;
15 import java.io.FileWriter;
16 import java.io.IOException;
17 import java.io.InputStream;
18 import java.io.UnsupportedEncodingException;
19 import java.net.URL;
20 import java.net.URLClassLoader;
21 import java.util.Collection;
22 import java.util.Collections;
23 import java.util.Map;
24
25 import static org.junit.Assert.assertFalse;
26 import static org.junit.Assert.assertTrue;
27 import static org.mockito.Mockito.mock;
28 import static org.mockito.Mockito.when;
29
30 public class TestClasspathFilePluginMetadata {
31
32 private static final String applicationProvidedPlugins = "my.plugin.a\nmy.plugin.b\nmy.plugin.c\n my.plugin.with.whitespace ";
33 private static final String applicationProvidedPlugins2 = "my.plugin.z";
34 private static final String requiredPlugins = "my.plugin.a\nmy.plugin.b";
35 private static final String requiredModules = "my.plugin.a-mod1\nmy.plugin.c-mod1\n \n #hello \nmy.plugin.c-mod2";
36
37 private final Map<String, Collection<InputStream>> testData = ImmutableMap.of(
38 ClasspathFilePluginMetadata.APPLICATION_PROVIDED_PLUGINS_FILENAME, toStreams(applicationProvidedPlugins, applicationProvidedPlugins2),
39 ClasspathFilePluginMetadata.APPLICATION_REQUIRED_PLUGINS_FILENAME, toStreams(requiredPlugins),
40 ClasspathFilePluginMetadata.APPLICATION_REQUIRED_MODULES_FILENAME, toStreams(requiredModules));
41 private PluginMetadata pluginMetadata;
42
43 @Rule
44 public final TemporaryFolder temporaryFolder = new TemporaryFolder();
45
46 @Before
47 public void setUp() {
48 pluginMetadata = new ClasspathFilePluginMetadata() {
49
50
51 @Override
52 Collection<InputStream> getInputStreamsForFilename(final String fileName) {
53 return testData.get(fileName);
54 }
55 };
56 }
57
58 @After
59 public void tearDown() {
60 pluginMetadata = null;
61 }
62
63 @Test
64 public void testIsUserInstalledPluginPluginFromUser() {
65 final Plugin plugin = mock(Plugin.class);
66 when(plugin.getKey()).thenReturn("my.plugin.d");
67 assertFalse(pluginMetadata.applicationProvided(plugin));
68 }
69
70 @Test
71 public void testIsUserInstalledPluginPluginFromSystem() {
72 final Plugin plugin = mock(Plugin.class);
73 when(plugin.getKey()).thenReturn("my.plugin.a");
74 assertTrue(pluginMetadata.applicationProvided(plugin));
75 }
76
77 @Test
78 public void testPluginRequired() {
79 final Plugin plugin = mock(Plugin.class);
80 when(plugin.getKey()).thenReturn("my.plugin.a");
81 assertTrue(pluginMetadata.required(plugin));
82 }
83
84 @Test
85 public void testPluginNotRequired() {
86 final Plugin plugin = mock(Plugin.class);
87 when(plugin.getKey()).thenReturn("my.plugin.x");
88 assertFalse(pluginMetadata.applicationProvided(plugin));
89 }
90
91 @Test
92 public void testModuleRequired() {
93 final ModuleDescriptor<?> moduleDescriptor = mock(ModuleDescriptor.class);
94 when(moduleDescriptor.getCompleteKey()).thenReturn("my.plugin.c-mod2");
95 assertTrue(pluginMetadata.required(moduleDescriptor));
96 }
97
98 @Test
99 public void testModuleNotRequired() {
100 final ModuleDescriptor<?> moduleDescriptor = mock(ModuleDescriptor.class);
101 when(moduleDescriptor.getCompleteKey()).thenReturn("my.plugin.c-mod3");
102 assertFalse(pluginMetadata.required(moduleDescriptor));
103 }
104
105 @Test
106 public void testModuleIsRequired() {
107 final ModuleDescriptor<?> moduleDescriptor = mock(ModuleDescriptor.class);
108 when(moduleDescriptor.getCompleteKey()).thenReturn("my.plugin.a-mod1");
109 assertTrue(pluginMetadata.required(moduleDescriptor));
110 }
111
112 @Test(expected = NullPointerException.class)
113 public void testApplicationProvidedPluginNullPlugin() {
114 pluginMetadata.applicationProvided(null);
115 }
116
117 @Test(expected = NullPointerException.class)
118 public void testRequiredPluginNullPlugin() {
119 pluginMetadata.required((Plugin) null);
120 }
121
122 @Test(expected = NullPointerException.class)
123 public void testRequiredModuleNullModule() {
124 pluginMetadata.required((ModuleDescriptor<?>) null);
125 }
126
127 @Test
128 public void testIsUserInstalledPluginNoFileOnClasspath() {
129 pluginMetadata = new ClasspathFilePluginMetadata() {
130 @Override
131 Collection<InputStream> getInputStreamsForFilename(final String fileName) {
132 return Collections.emptyList();
133 }
134 };
135
136 final Plugin plugin = mock(Plugin.class);
137 when(plugin.getKey()).thenReturn("my.plugin.a");
138 assertFalse(pluginMetadata.applicationProvided(plugin));
139 assertFalse(pluginMetadata.required(plugin));
140 }
141
142 @Test
143 public void testIsUserInstalledPluginPluginSpecifiedWithWhitespace() {
144 final Plugin plugin = mock(Plugin.class);
145 when(plugin.getKey()).thenReturn("my.plugin.with.whitespace");
146 assertTrue(pluginMetadata.applicationProvided(plugin));
147 }
148
149 @Test
150 public void testBlankLinesInFilesAreNotIncluded() {
151
152
153 final Plugin plugin = mock(Plugin.class);
154 final ModuleDescriptor<?> moduleDescriptor = mock(ModuleDescriptor.class);
155 when(plugin.getKey()).thenReturn("my.plugin.d");
156 when(moduleDescriptor.getCompleteKey()).thenReturn("");
157 when(moduleDescriptor.getPlugin()).thenReturn(plugin);
158
159 assertFalse(pluginMetadata.required(moduleDescriptor));
160 }
161
162 @Test
163 public void testCommentLinesInFilesAreNotIncluded() {
164
165
166 final Plugin plugin = mock(Plugin.class);
167 final ModuleDescriptor<?> moduleDescriptor = mock(ModuleDescriptor.class);
168 when(plugin.getKey()).thenReturn("my.plugin.d");
169 when(moduleDescriptor.getCompleteKey()).thenReturn("#hello");
170 when(moduleDescriptor.getPlugin()).thenReturn(plugin);
171
172 assertFalse(pluginMetadata.required(moduleDescriptor));
173 }
174
175 @Test
176 public void testPluginKeysFromSecondFileIncluded() {
177 final Plugin plugin = mock(Plugin.class);
178 when(plugin.getKey()).thenReturn("my.plugin.z");
179
180 assertTrue(pluginMetadata.applicationProvided(plugin));
181 }
182
183 @Test
184 public void testClassLoading() throws IOException {
185 ClassLoader classLoader = setupAndGetClassloader();
186
187 final Plugin plugin1 = mock(Plugin.class);
188 when(plugin1.getKey()).thenReturn("test1");
189 final Plugin plugin2 = mock(Plugin.class);
190 when(plugin2.getKey()).thenReturn("test2");
191
192 final ClasspathFilePluginMetadata pluginMetadata = new ClasspathFilePluginMetadata(classLoader);
193 assertTrue(pluginMetadata.applicationProvided(plugin1));
194 assertTrue(pluginMetadata.applicationProvided(plugin2));
195 }
196
197 @SuppressWarnings("ResultOfMethodCallIgnored")
198 private ClassLoader setupAndGetClassloader() throws IOException {
199 final File tempDir1 = temporaryFolder.newFolder("dir1");
200
201 final File packageDir1 = new File(tempDir1, "/com/atlassian/plugin/metadata/");
202 packageDir1.mkdirs();
203 packageDir1.deleteOnExit();
204 final File tempDir2 = temporaryFolder.newFolder("dir2");
205 final File packageDir2 = new File(tempDir2, "/com/atlassian/plugin/metadata/");
206 packageDir2.mkdirs();
207 packageDir2.deleteOnExit();
208
209 final File file1 = new File(packageDir1, "application-provided-plugins.txt");
210 file1.deleteOnExit();
211 final File file2 = new File(packageDir2, "application-provided-plugins.txt");
212 file2.deleteOnExit();
213 FileWriter fileWriter1 = new FileWriter(file1);
214 file1.createNewFile();
215 fileWriter1.append("test1");
216 fileWriter1.close();
217 FileWriter fileWriter2 = new FileWriter(file2);
218 file2.createNewFile();
219 fileWriter2.append("test2");
220 fileWriter2.close();
221 return new URLClassLoader(new URL[]{tempDir1.toURI().toURL(), tempDir2.toURI().toURL()});
222 }
223
224 private static Collection<InputStream> toStreams(final String... names) {
225 final ImmutableList.Builder<InputStream> builder = ImmutableList.builder();
226 for (final String name : names) {
227 try {
228 builder.add(new ByteArrayInputStream(name.getBytes("UTF-8")));
229 } catch (final UnsupportedEncodingException e) {
230 throw new Error("Unable to construct test data", e);
231 }
232 }
233 return builder.build();
234 }
235 }