View Javadoc
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              // NOTE: I know that people do not like this, but I think it is WAY BETTER than faffing around with the
50              // production code to the degree that it is UNREADABLE
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         // There is a blank line in the requiredModules file lets make sure that
152         // is not included
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         // There is a blank line in the requiredModules file lets make sure that
165         // is not included
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         // Create the package
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 }