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 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              // NOTE: I know that people do not like this, but I think it is WAY BETTER than faffing around with the
47              // production code to the degree that it is UNREADABLE
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         // There is a blank line in the requiredModules file lets make sure that
171         // is not included
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         // There is a blank line in the requiredModules file lets make sure that
184         // is not included
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         // Create the package
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      * Returns the system's temp directory.
279      * <p>
280      * Be aware that some operating systems place a trailing slash and others don't.
281      *
282      * @return the system's temp directory.
283      */
284     static String getSystemTempDir()
285     {
286         return System.getProperty("java.io.tmpdir");
287     }
288 
289 }