View Javadoc
1   package com.atlassian.plugin.loaders;
2   
3   import com.atlassian.plugin.ModuleDescriptor;
4   import com.atlassian.plugin.ModuleDescriptorFactory;
5   import com.atlassian.plugin.Permissions;
6   import com.atlassian.plugin.Plugin;
7   import com.atlassian.plugin.PluginArtifact;
8   import com.atlassian.plugin.PluginException;
9   import com.atlassian.plugin.PluginInformation;
10  import com.atlassian.plugin.PluginInternal;
11  import com.atlassian.plugin.impl.UnloadablePlugin;
12  import com.google.common.collect.ImmutableList;
13  import com.google.common.collect.ImmutableSet;
14  import com.google.common.collect.Iterables;
15  import org.junit.Before;
16  import org.junit.Test;
17  import org.junit.runner.RunWith;
18  import org.mockito.Mock;
19  import org.mockito.junit.MockitoJUnitRunner;
20  
21  import java.util.Set;
22  
23  import static org.hamcrest.Matchers.instanceOf;
24  import static org.junit.Assert.assertEquals;
25  import static org.junit.Assert.assertSame;
26  import static org.junit.Assert.assertThat;
27  import static org.junit.Assert.assertTrue;
28  import static org.mockito.ArgumentMatchers.any;
29  import static org.mockito.Mockito.doThrow;
30  import static org.mockito.Mockito.mock;
31  import static org.mockito.Mockito.times;
32  import static org.mockito.Mockito.verify;
33  import static org.mockito.Mockito.when;
34  
35  @RunWith(MockitoJUnitRunner.Silent.class)
36  public final class PermissionCheckingPluginLoaderTest {
37  
38      private PermissionCheckingPluginLoader permissionCheckingPluginLoader;
39      @Mock
40      private PluginLoader pluginLoader;
41      @Mock
42      private ModuleDescriptorFactory moduleDescriptorFactory;
43  
44      @Before
45      public void setUp() {
46          permissionCheckingPluginLoader = new PermissionCheckingPluginLoader(pluginLoader);
47      }
48  
49      @Test
50      public void loadAllPluginsWithEmptyCollectionOfPlugins() {
51          when(pluginLoader.loadAllPlugins(moduleDescriptorFactory)).thenReturn(ImmutableList.of());
52          final Iterable<Plugin> plugins = permissionCheckingPluginLoader.loadAllPlugins(moduleDescriptorFactory);
53          assertTrue(Iterables.isEmpty(plugins));
54      }
55  
56      @Test
57      public void loadFoundPluginsWithEmptyCollectionOfPlugins() {
58          when(pluginLoader.loadFoundPlugins(moduleDescriptorFactory)).thenReturn(ImmutableList.of());
59          final Iterable<Plugin> plugins = permissionCheckingPluginLoader.loadFoundPlugins(moduleDescriptorFactory);
60          assertTrue(Iterables.isEmpty(plugins));
61      }
62  
63      @Test
64      public void loadFoundPluginsWithPluginWithoutExecuteJavaPermissionAndNoJava() {
65          final Plugin plugin = newPlugin(ImmutableSet.of(), false, false);
66  
67          when(pluginLoader.loadFoundPlugins(moduleDescriptorFactory)).thenReturn(ImmutableList.of(plugin));
68          final Iterable<Plugin> plugins = permissionCheckingPluginLoader.loadFoundPlugins(moduleDescriptorFactory);
69  
70          assertEquals(1, Iterables.size(plugins));
71          assertSame(plugin, Iterables.get(plugins, 0));
72      }
73  
74      @Test
75      public void loadAllPluginsWithPluginWithoutExecuteJavaPermissionAndNoJava() {
76          final Plugin plugin = newPlugin(ImmutableSet.of(), false, false);
77  
78          when(pluginLoader.loadAllPlugins(moduleDescriptorFactory)).thenReturn(ImmutableList.of(plugin));
79          final Iterable<Plugin> plugins = permissionCheckingPluginLoader.loadAllPlugins(moduleDescriptorFactory);
80  
81          assertEquals(1, Iterables.size(plugins));
82          assertSame(plugin, Iterables.get(plugins, 0));
83      }
84  
85      @Test
86      public void loadFoundPluginsWithPluginWithoutExecuteJavaPermissionAndSomeJava() {
87          final Plugin plugin = newPlugin(ImmutableSet.of(), true, false);
88  
89          when(pluginLoader.loadFoundPlugins(moduleDescriptorFactory)).thenReturn(ImmutableList.of(plugin));
90          final Iterable<Plugin> plugins = permissionCheckingPluginLoader.loadFoundPlugins(moduleDescriptorFactory);
91  
92          assertEquals(1, Iterables.size(plugins));
93          assertTrue(Iterables.get(plugins, 0) instanceof UnloadablePlugin);
94      }
95  
96      @Test
97      public void loadAllPluginsWithPluginWithoutExecuteJavaPermissionAndSomeJava() {
98          final Plugin plugin = newPlugin(ImmutableSet.of(), true, false);
99  
100         when(pluginLoader.loadAllPlugins(moduleDescriptorFactory)).thenReturn(ImmutableList.of(plugin));
101         final Iterable<Plugin> plugins = permissionCheckingPluginLoader.loadAllPlugins(moduleDescriptorFactory);
102 
103         assertEquals(1, Iterables.size(plugins));
104         assertTrue(Iterables.get(plugins, 0) instanceof UnloadablePlugin);
105     }
106 
107     @Test
108     public void loadAllPluginsWithUnloadablePluginThenRemoved() {
109         final Plugin plugin = newPlugin(ImmutableSet.of(), true, false);
110 
111         doThrow(new PluginException("cannot find plugin")).when(pluginLoader).removePlugin(any(Plugin.class));
112         when(pluginLoader.loadAllPlugins(moduleDescriptorFactory)).thenReturn(ImmutableList.of(plugin));
113         final Iterable<Plugin> plugins = permissionCheckingPluginLoader.loadAllPlugins(moduleDescriptorFactory);
114 
115         assertEquals(1, Iterables.size(plugins));
116         Plugin loadedPlugin = Iterables.get(plugins, 0);
117         assertTrue(loadedPlugin instanceof UnloadablePlugin);
118         permissionCheckingPluginLoader.removePlugin(loadedPlugin);
119     }
120 
121     @Test
122     public void loadAllPluginsWithGoodPluginThenDiscarded() throws Exception {
123         // We need to replace the object under test with a discardable loader. This could be structured better.
124         final DiscardablePluginLoader discardablePluginLoader = mock(DiscardablePluginLoader.class);
125         permissionCheckingPluginLoader = new PermissionCheckingPluginLoader(discardablePluginLoader);
126 
127         final Plugin plugin = newPlugin(ImmutableSet.of(), true, true);
128 
129         when(discardablePluginLoader.loadAllPlugins(moduleDescriptorFactory)).thenReturn(ImmutableList.of(plugin));
130         final Iterable<Plugin> plugins = permissionCheckingPluginLoader.loadAllPlugins(moduleDescriptorFactory);
131         permissionCheckingPluginLoader.discardPlugin(plugin);
132         verify(discardablePluginLoader).discardPlugin(plugin);
133     }
134 
135     @Test
136     public void loadAllPluginsWithUnloadablePluginThenDiscarded() {
137         // We need to replace the object under test with a discardable loader. This could be structured better.
138         final DiscardablePluginLoader discardablePluginLoader = mock(DiscardablePluginLoader.class);
139         permissionCheckingPluginLoader = new PermissionCheckingPluginLoader(discardablePluginLoader);
140 
141         final Plugin containsJavaButNoPermission = newPlugin(ImmutableSet.of(), true, false);
142         final Plugin hasSystemButNoPermission = newPlugin(ImmutableSet.of(), false, false);
143         addModuleDescriptor(hasSystemButNoPermission, true);
144 
145 
146         final Iterable<Plugin> pluginsToLoad = ImmutableList.of(containsJavaButNoPermission, hasSystemButNoPermission);
147         when(discardablePluginLoader.loadAllPlugins(moduleDescriptorFactory)).thenReturn(pluginsToLoad);
148 
149         final Iterable<Plugin> loadedPlugins = permissionCheckingPluginLoader.loadAllPlugins(moduleDescriptorFactory);
150         // The actual plugin should be discarded when loadAllPlugins ignores it
151         for (final Plugin plugin : pluginsToLoad) {
152             verify(discardablePluginLoader).discardPlugin(plugin);
153         }
154 
155         assertEquals(Iterables.size(loadedPlugins), Iterables.size(pluginsToLoad));
156         for (final Plugin plugin : loadedPlugins) {
157             assertThat(plugin, instanceOf(UnloadablePlugin.class));
158             permissionCheckingPluginLoader.discardPlugin(plugin);
159         }
160         // I know .times() is frowned on, but i can't find another good way to do this in Mockito - i want to say
161         // the only discard calls were from the loadAllPlugins() above.
162         verify(discardablePluginLoader, times(Iterables.size(pluginsToLoad))).discardPlugin(any(Plugin.class));
163     }
164 
165     @Test
166     public void loadFoundPluginsWithGoodPluginThenDiscarded() throws Exception {
167         // We need to replace the object under test with a discardable loader. This could be structured better.
168         final DiscardablePluginLoader discardablePluginLoader = mock(DiscardablePluginLoader.class);
169         permissionCheckingPluginLoader = new PermissionCheckingPluginLoader(discardablePluginLoader);
170 
171         final Plugin plugin = newPlugin(ImmutableSet.of(), true, true);
172 
173         when(discardablePluginLoader.loadFoundPlugins(moduleDescriptorFactory)).thenReturn(ImmutableList.of(plugin));
174         final Iterable<Plugin> plugins = permissionCheckingPluginLoader.loadFoundPlugins(moduleDescriptorFactory);
175         permissionCheckingPluginLoader.discardPlugin(plugin);
176         verify(discardablePluginLoader).discardPlugin(plugin);
177     }
178 
179     @Test
180     public void loadFoundPluginsWithUnloadablePluginThenDiscarded() {
181         // We need to replace the object under test with a discardable loader. This could be structured better.
182         final DiscardablePluginLoader discardablePluginLoader = mock(DiscardablePluginLoader.class);
183         permissionCheckingPluginLoader = new PermissionCheckingPluginLoader(discardablePluginLoader);
184 
185         final Plugin containsJavaButNoPermission = newPlugin(ImmutableSet.of(), true, false);
186         final Plugin hasSystemButNoPermission = newPlugin(ImmutableSet.of(), false, false);
187         addModuleDescriptor(hasSystemButNoPermission, true);
188 
189 
190         final Iterable<Plugin> pluginsToLoad = ImmutableList.of(containsJavaButNoPermission, hasSystemButNoPermission);
191         when(discardablePluginLoader.loadFoundPlugins(moduleDescriptorFactory)).thenReturn(pluginsToLoad);
192 
193         final Iterable<Plugin> loadedPlugins = permissionCheckingPluginLoader.loadFoundPlugins(moduleDescriptorFactory);
194         // The actual plugin should be discarded when loadFoundPlugins ignores it
195         for (final Plugin plugin : pluginsToLoad) {
196             verify(discardablePluginLoader).discardPlugin(plugin);
197         }
198 
199         assertEquals(Iterables.size(loadedPlugins), Iterables.size(pluginsToLoad));
200         for (final Plugin plugin : loadedPlugins) {
201             assertThat(plugin, instanceOf(UnloadablePlugin.class));
202             permissionCheckingPluginLoader.discardPlugin(plugin);
203         }
204         // I know .times() is frowned on, but i can't find another good way to do this in Mockito - i want to say
205         // the only discard calls were from the loadFoundPlugins() above.
206         verify(discardablePluginLoader, times(Iterables.size(pluginsToLoad))).discardPlugin(any(Plugin.class));
207     }
208 
209     @Test
210     public void loadAllPluginsWithPluginWithNoPermissionsAndSystemModules() throws Exception {
211         final Plugin plugin = newPlugin(ImmutableSet.of(), false, false);
212 
213         addModuleDescriptor(plugin, true);
214 
215         when(pluginLoader.loadAllPlugins(moduleDescriptorFactory)).thenReturn(ImmutableList.of(plugin));
216         final Iterable<Plugin> plugins = permissionCheckingPluginLoader.loadAllPlugins(moduleDescriptorFactory);
217 
218         assertEquals(1, Iterables.size(plugins));
219         assertTrue(Iterables.get(plugins, 0) instanceof UnloadablePlugin);
220     }
221 
222     @Test
223     public void loadAllPluginsWithPluginWithNoPermissionsAndNoSystemModules() throws Exception {
224         final Plugin plugin = newPlugin(ImmutableSet.of(), false, false);
225 
226         addModuleDescriptor(plugin, false);
227 
228         when(pluginLoader.loadAllPlugins(moduleDescriptorFactory)).thenReturn(ImmutableList.of(plugin));
229         final Iterable<Plugin> plugins = permissionCheckingPluginLoader.loadAllPlugins(moduleDescriptorFactory);
230 
231         assertEquals(1, Iterables.size(plugins));
232         assertSame(plugin, Iterables.get(plugins, 0));
233     }
234 
235     @Test
236     public void loadFoundPluginsWithPluginWithJavaPermissionAndSomeJava() throws Exception {
237         final Plugin plugin = newPlugin(ImmutableSet.of(Permissions.EXECUTE_JAVA), true, false);
238 
239         when(pluginLoader.loadFoundPlugins(moduleDescriptorFactory)).thenReturn(ImmutableList.of(plugin));
240         final Iterable<Plugin> plugins = permissionCheckingPluginLoader.loadFoundPlugins(moduleDescriptorFactory);
241 
242         assertEquals(1, Iterables.size(plugins));
243         assertSame(plugin, Iterables.get(plugins, 0));
244     }
245 
246     @Test
247     public void loadAllPluginsWithPluginWithCreateSystemModulePermissionsAndSystemModules() throws Exception {
248         final Plugin plugin = newPlugin(ImmutableSet.of(Permissions.CREATE_SYSTEM_MODULES), false, false);
249 
250         addModuleDescriptor(plugin, true);
251 
252         when(pluginLoader.loadAllPlugins(moduleDescriptorFactory)).thenReturn(ImmutableList.of(plugin));
253         final Iterable<Plugin> plugins = permissionCheckingPluginLoader.loadAllPlugins(moduleDescriptorFactory);
254 
255         assertEquals(1, Iterables.size(plugins));
256         assertSame(plugin, Iterables.get(plugins, 0));
257     }
258 
259     @Test
260     public void loadAllPluginsWithPluginWithCreateSystemModulePermissionsAndNoSystemModules() throws Exception {
261         final Plugin plugin = newPlugin(ImmutableSet.of(Permissions.CREATE_SYSTEM_MODULES), false, false);
262 
263         addModuleDescriptor(plugin, false);
264 
265         when(pluginLoader.loadAllPlugins(moduleDescriptorFactory)).thenReturn(ImmutableList.of(plugin));
266         final Iterable<Plugin> plugins = permissionCheckingPluginLoader.loadAllPlugins(moduleDescriptorFactory);
267 
268         assertEquals(1, Iterables.size(plugins));
269         assertSame(plugin, Iterables.get(plugins, 0));
270     }
271 
272     @Test
273     public void loadFoundPluginsWithPluginWithJavaPermissionAndNoJava() throws Exception {
274         final Plugin plugin = newPlugin(ImmutableSet.of(Permissions.EXECUTE_JAVA), false, false);
275 
276         when(pluginLoader.loadFoundPlugins(moduleDescriptorFactory)).thenReturn(ImmutableList.of(plugin));
277         final Iterable<Plugin> plugins = permissionCheckingPluginLoader.loadFoundPlugins(moduleDescriptorFactory);
278 
279         assertEquals(1, Iterables.size(plugins));
280         assertSame(plugin, Iterables.get(plugins, 0));
281     }
282 
283     @Test
284     public void loadAllPluginsWithPluginWithJavaPermissionAndNoJava() throws Exception {
285         final Plugin plugin = newPlugin(ImmutableSet.of(Permissions.EXECUTE_JAVA), false, false);
286 
287         when(pluginLoader.loadAllPlugins(moduleDescriptorFactory)).thenReturn(ImmutableList.of(plugin));
288         final Iterable<Plugin> plugins = permissionCheckingPluginLoader.loadAllPlugins(moduleDescriptorFactory);
289 
290         assertEquals(1, Iterables.size(plugins));
291         assertSame(plugin, Iterables.get(plugins, 0));
292     }
293 
294     @Test
295     public void loadFoundPluginsWithPluginWithAllPermissionsAndSomeJava() throws Exception {
296         final Plugin plugin = newPlugin(ImmutableSet.of(), true, true);
297 
298         when(pluginLoader.loadFoundPlugins(moduleDescriptorFactory)).thenReturn(ImmutableList.of(plugin));
299         final Iterable<Plugin> plugins = permissionCheckingPluginLoader.loadFoundPlugins(moduleDescriptorFactory);
300 
301         assertEquals(1, Iterables.size(plugins));
302         assertSame(plugin, Iterables.get(plugins, 0));
303     }
304 
305     @Test
306     public void loadAllPluginsWithPluginWithAllPermissionsAndSomeJava() throws Exception {
307         final Plugin plugin = newPlugin(ImmutableSet.of(), true, true);
308 
309         when(pluginLoader.loadAllPlugins(moduleDescriptorFactory)).thenReturn(ImmutableList.of(plugin));
310         final Iterable<Plugin> plugins = permissionCheckingPluginLoader.loadAllPlugins(moduleDescriptorFactory);
311 
312         assertEquals(1, Iterables.size(plugins));
313         assertSame(plugin, Iterables.get(plugins, 0));
314     }
315 
316     @Test
317     public void loadAllPluginsWithPluginWithAllPermissionsAndSystemModules() throws Exception {
318         final Plugin plugin = newPlugin(ImmutableSet.of(), false, true);
319         addModuleDescriptor(plugin, true);
320 
321         when(pluginLoader.loadAllPlugins(moduleDescriptorFactory)).thenReturn(ImmutableList.of(plugin));
322         final Iterable<Plugin> plugins = permissionCheckingPluginLoader.loadAllPlugins(moduleDescriptorFactory);
323 
324         assertEquals(1, Iterables.size(plugins));
325         assertSame(plugin, Iterables.get(plugins, 0));
326     }
327 
328     private void addModuleDescriptor(Plugin plugin, boolean system) {
329         ModuleDescriptor descriptor = mock(ModuleDescriptor.class);
330         when(descriptor.getKey()).thenReturn("foo");
331         when(descriptor.isSystemModule()).thenReturn(system);
332         when(plugin.getModuleDescriptors()).thenReturn(ImmutableList.of(descriptor));
333     }
334 
335     private Plugin newPlugin(Set<String> permissions, boolean hasJava, boolean hasAllPermissions) {
336         final PluginInternal plugin = mockPlugin(PluginInternal.class);
337         final PluginArtifact pluginArtifact = mock(PluginArtifact.class);
338         when(plugin.hasAllPermissions()).thenReturn(hasAllPermissions);
339         when(plugin.getActivePermissions()).thenReturn(permissions);
340         when(plugin.getPluginArtifact()).thenReturn(pluginArtifact);
341         when(pluginArtifact.containsJavaExecutableCode()).thenReturn(hasJava);
342         return plugin;
343     }
344 
345     private <P extends Plugin> P mockPlugin(Class<P> type) {
346         P mock = mock(type);
347         when(mock.getKey()).thenReturn("test-plugin-key");
348         when(mock.getName()).thenReturn("Test Plugin");
349         PluginInformation pluginInformation = mock(PluginInformation.class);
350         when(mock.getPluginInformation()).thenReturn(pluginInformation);
351         return mock;
352     }
353 }