1 package com.atlassian.plugin.classloader;
2
3 import junit.framework.TestCase;
4 import com.mockobjects.dynamic.Mock;
5 import com.mockobjects.dynamic.C;
6 import com.atlassian.plugin.PluginAccessor;
7 import com.atlassian.plugin.Plugin;
8 import com.atlassian.plugin.MockPluginAccessor;
9 import com.atlassian.plugin.MockPlugin;
10
11 import java.net.URL;
12 import java.net.MalformedURLException;
13 import java.util.Collections;
14 import java.util.Collection;
15 import java.util.LinkedList;
16
17
18
19
20 public class TestPluginsClassLoader extends TestCase
21 {
22 private static final String TEST_RESOURCE = "log4j.properties";
23
24 private PluginsClassLoader pluginsClassLoader;
25 private Mock mockPluginAccessor;
26 private Mock mockPlugin;
27 private static final String PLUGIN_KEY = "aPluginKey";
28 private static final String TEST_CLASS = "java.lang.String";
29
30 protected void setUp() throws Exception
31 {
32 mockPluginAccessor = new Mock(PluginAccessor.class);
33 pluginsClassLoader = new PluginsClassLoader((PluginAccessor) mockPluginAccessor.proxy());
34
35 mockPlugin = new Mock(Plugin.class);
36 }
37
38 protected void tearDown() throws Exception
39 {
40 mockPluginAccessor.verify();
41 mockPlugin.verify();
42
43 mockPluginAccessor = null;
44 pluginsClassLoader = null;
45 }
46
47 public void testFindResourceWhenIndexed()
48 {
49 final StubClassLoader stubClassLoader = new StubClassLoader();
50 loadPluginResource(stubClassLoader);
51 assertTrue(stubClassLoader.getFindResourceNames().contains(TEST_RESOURCE));
52 stubClassLoader.clear();
53
54 mockPlugin.expectAndReturn("getKey", PLUGIN_KEY);
55 mockPluginAccessor.matchAndReturn("isPluginEnabled", C.args(C.eq(PLUGIN_KEY)), Boolean.TRUE);
56 mockPlugin.expectAndReturn("getClassLoader", stubClassLoader);
57 pluginsClassLoader.findResource(TEST_RESOURCE);
58
59 assertTrue(stubClassLoader.getFindResourceNames().contains(TEST_RESOURCE));
60 }
61
62 public void testFindResourceWhenNotIndexed()
63 {
64 final StubClassLoader stubClassLoader = new StubClassLoader();
65 loadPluginResource(stubClassLoader);
66
67 assertTrue(stubClassLoader.getFindResourceNames().contains(TEST_RESOURCE));
68 }
69
70 public void testFindResourceWhenIndexedAndPluginDisabled()
71 {
72 final StubClassLoader stubClassLoader = new StubClassLoader();
73 loadPluginResource(stubClassLoader);
74 assertTrue(stubClassLoader.getFindResourceNames().contains(TEST_RESOURCE));
75 stubClassLoader.clear();
76
77 mockPluginAccessor.expectAndReturn("getEnabledPlugins", Collections.emptyList());
78 mockPlugin.expectAndReturn("getKey", PLUGIN_KEY);
79 mockPluginAccessor.matchAndReturn("isPluginEnabled", C.args(C.eq(PLUGIN_KEY)), Boolean.FALSE);
80 pluginsClassLoader.findResource(TEST_RESOURCE);
81
82 assertFalse(stubClassLoader.getFindResourceNames().contains(TEST_RESOURCE));
83 }
84
85 public void testFindClassWhenIndexed() throws Exception
86 {
87 final StubClassLoader stubClassLoader = new StubClassLoader();
88 loadPluginClass(stubClassLoader);
89 assertTrue(stubClassLoader.getFindClassNames().contains(TEST_CLASS));
90 stubClassLoader.clear();
91
92 mockPlugin.expectAndReturn("getKey", PLUGIN_KEY);
93 mockPluginAccessor.matchAndReturn("isPluginEnabled", C.args(C.eq(PLUGIN_KEY)), Boolean.TRUE);
94 mockPlugin.expectAndReturn("getClassLoader", stubClassLoader);
95 pluginsClassLoader.findClass(TEST_CLASS);
96
97 assertTrue(stubClassLoader.getFindClassNames().contains(TEST_CLASS));
98 }
99
100 public void testFindClassWhenNotIndexed() throws Exception
101 {
102 final StubClassLoader stubClassLoader = new StubClassLoader();
103 loadPluginClass(stubClassLoader);
104
105 assertTrue(stubClassLoader.getFindClassNames().contains(TEST_CLASS));
106 }
107
108 public void testFindClassWhenIndexedAndPluginDisabled() throws Exception
109 {
110 final StubClassLoader stubClassLoader = new StubClassLoader();
111 loadPluginClass(stubClassLoader);
112 assertTrue(stubClassLoader.getFindClassNames().contains(TEST_CLASS));
113 stubClassLoader.clear();
114
115 mockPluginAccessor.expectAndReturn("getEnabledPlugins", Collections.emptyList());
116 mockPlugin.expectAndReturn("getKey", PLUGIN_KEY);
117 mockPluginAccessor.matchAndReturn("isPluginEnabled", C.args(C.eq(PLUGIN_KEY)), Boolean.FALSE);
118 try
119 {
120 pluginsClassLoader.findClass(TEST_CLASS);
121 fail("Plugin is disabled so its ClassLoader should throw ClassNotFoundException");
122 }
123 catch (ClassNotFoundException e)
124 {
125
126 }
127 }
128
129 public void testGetPluginForClass() throws Exception
130 {
131 final MockPluginAccessor mockPluginAccessor = new MockPluginAccessor();
132 PluginsClassLoader pluginsClassLoader = new PluginsClassLoader(mockPluginAccessor);
133
134 MockClassLoader mockClassLoaderA = new MockClassLoader();
135 mockClassLoaderA.register("com.acme.Ant", String.class);
136 mockClassLoaderA.register("com.acme.Clash", String.class);
137 MockPlugin pluginA = new MockPlugin("A", mockClassLoaderA);
138 mockPluginAccessor.addPlugin(pluginA);
139
140 MockClassLoader mockClassLoaderB = new MockClassLoader();
141 mockClassLoaderB.register("com.acme.Bat", String.class);
142 mockClassLoaderB.register("com.acme.Clash", String.class);
143 MockPlugin pluginB = new MockPlugin("B", mockClassLoaderB);
144 mockPluginAccessor.addPlugin(pluginB);
145
146
147 assertEquals(null, pluginsClassLoader.getPluginForClass("com.acme.Ant"));
148 assertEquals(null, pluginsClassLoader.getPluginForClass("com.acme.Bat"));
149 assertEquals(null, pluginsClassLoader.getPluginForClass("com.acme.Clash"));
150 assertEquals(null, pluginsClassLoader.getPluginForClass("java.lang.String"));
151
152
153 pluginB.enable();
154 pluginsClassLoader.notifyPluginOrModuleEnabled();
155 assertEquals(null, pluginsClassLoader.getPluginForClass("com.acme.Ant"));
156 assertEquals(pluginB, pluginsClassLoader.getPluginForClass("com.acme.Bat"));
157 assertEquals(pluginB, pluginsClassLoader.getPluginForClass("com.acme.Clash"));
158 assertEquals(null, pluginsClassLoader.getPluginForClass("java.lang.String"));
159
160
161 pluginA.enable();
162 pluginsClassLoader.notifyPluginOrModuleEnabled();
163 assertEquals(pluginA, pluginsClassLoader.getPluginForClass("com.acme.Ant"));
164 assertEquals(pluginB, pluginsClassLoader.getPluginForClass("com.acme.Bat"));
165 assertEquals(pluginB, pluginsClassLoader.getPluginForClass("com.acme.Clash"));
166 assertEquals(null, pluginsClassLoader.getPluginForClass("java.lang.String"));
167
168
169 pluginsClassLoader.notifyUninstallPlugin(pluginB);
170 assertEquals(pluginA, pluginsClassLoader.getPluginForClass("com.acme.Ant"));
171 assertEquals(pluginB, pluginsClassLoader.getPluginForClass("com.acme.Bat"));
172 assertEquals(pluginA, pluginsClassLoader.getPluginForClass("com.acme.Clash"));
173 assertEquals(null, pluginsClassLoader.getPluginForClass("java.lang.String"));
174 }
175
176 private void loadPluginResource(ClassLoader stubClassLoader)
177 {
178 mockPluginAccessor.expectAndReturn("getEnabledPlugins", Collections.singleton(mockPlugin.proxy()));
179 mockPlugin.expectAndReturn("getClassLoader", stubClassLoader);
180 pluginsClassLoader.findResource(TEST_RESOURCE);
181 }
182
183 private void loadPluginClass(ClassLoader stubClassLoader) throws ClassNotFoundException
184 {
185 mockPluginAccessor.expectAndReturn("getEnabledPlugins", Collections.singleton(mockPlugin.proxy()));
186 mockPlugin.expectAndReturn("getClassLoader", stubClassLoader);
187 pluginsClassLoader.findClass(TEST_CLASS);
188 }
189
190 private static final class StubClassLoader extends AbstractClassLoader
191 {
192 private final Collection<String> findResourceNames = new LinkedList<String>();
193
194 public Collection getFindClassNames()
195 {
196 return findClassNames;
197 }
198
199 private final Collection<String> findClassNames = new LinkedList<String>();
200
201 public StubClassLoader()
202 {
203 super(null);
204 }
205
206 protected URL findResource(String name)
207 {
208 findResourceNames.add(name);
209 try
210 {
211 return new URL("file://"+name);
212 }
213 catch (MalformedURLException e)
214 {
215
216 return null;
217 }
218 }
219
220
221
222
223
224 public Class loadClass(String name) throws ClassNotFoundException
225 {
226 return findClass(name);
227 }
228
229 protected Class findClass(String className) throws ClassNotFoundException
230 {
231 findClassNames.add(className);
232 return String.class;
233 }
234
235 public Collection getFindResourceNames()
236 {
237 return findResourceNames;
238 }
239
240 public void clear() {
241 findResourceNames.clear();
242 findClassNames.clear();
243 }
244 }
245 }