1 package com.atlassian.plugin.web.descriptors;
2
3 import com.atlassian.plugin.Plugin;
4 import com.atlassian.plugin.PluginAccessor;
5 import com.atlassian.plugin.PluginParseException;
6 import com.atlassian.plugin.hostcontainer.HostContainer;
7 import com.atlassian.plugin.impl.AbstractPlugin;
8 import com.atlassian.plugin.module.ModuleFactory;
9 import com.atlassian.plugin.web.NoOpContextProvider;
10 import com.atlassian.plugin.web.WebFragmentHelper;
11 import com.atlassian.plugin.web.WebInterfaceManager;
12 import com.atlassian.plugin.web.model.EmbeddedTemplateWebPanel;
13 import com.atlassian.plugin.web.model.ResourceTemplateWebPanel;
14 import com.atlassian.plugin.web.model.WebPanel;
15 import com.atlassian.plugin.web.renderer.RendererException;
16 import com.atlassian.plugin.web.renderer.WebPanelRenderer;
17 import com.google.common.collect.ImmutableList;
18 import junit.framework.TestCase;
19 import org.dom4j.Document;
20 import org.dom4j.DocumentException;
21 import org.dom4j.DocumentHelper;
22 import org.dom4j.Element;
23
24 import java.io.IOException;
25 import java.io.InputStream;
26 import java.io.StringWriter;
27 import java.io.Writer;
28 import java.net.URL;
29 import java.util.HashMap;
30 import java.util.Map;
31
32 import static org.mockito.Matchers.any;
33 import static org.mockito.Mockito.*;
34
35 public class TestDefaultWebPanelModuleDescriptor extends TestCase
36 {
37 private WebPanelModuleDescriptor descriptor;
38 private final Plugin plugin = new MockPlugin(this.getClass().getName());
39 private HostContainer hostContainer = mock(HostContainer.class);
40 private WebInterfaceManager webInterfaceManager = spy(new MockWebInterfaceManager());
41 private ModuleFactory moduleClassFactory = mock(ModuleFactory.class);
42 private PluginAccessor pluginAccessor = mock(PluginAccessor.class);
43 private Map<String, Object> context = new HashMap<String, Object>();
44
45 @Override
46 protected void setUp() throws Exception
47 {
48 when(hostContainer.create(EmbeddedTemplateWebPanel.class)).thenReturn(new EmbeddedTemplateWebPanel(pluginAccessor));
49 when(hostContainer.create(ResourceTemplateWebPanel.class)).thenReturn(new ResourceTemplateWebPanel(pluginAccessor));
50
51 descriptor = new DefaultWebPanelModuleDescriptor(hostContainer, moduleClassFactory, webInterfaceManager);
52 }
53
54 public void testMissingResource() throws DocumentException, PluginParseException
55 {
56 final String webPanelXml = "<web-panel key=\"myPanel\" location=\"atl.header\"/>";
57 try
58 {
59 descriptor.init(plugin, createElement(webPanelXml));
60 fail("Descriptor should check for a resource with name 'view'");
61 }
62 catch (PluginParseException e)
63 {
64
65 }
66 }
67
68 public void testMissingLocation() throws DocumentException, PluginParseException
69 {
70 final String webPanelXml = "<web-panel key=\"myPanel\">\n" +
71 " <resource name=\"view\" type=\"static\"><![CDATA[<b>Hello World!</b>]]></resource>\n" +
72 "</web-panel>";
73 try
74 {
75 descriptor.init(plugin, createElement(webPanelXml));
76 fail("Descriptor should check for a location attribute");
77 }
78 catch (PluginParseException e)
79 {
80
81 }
82 }
83
84 public void testGetEmbeddedTemplate() throws DocumentException, PluginParseException
85 {
86 final String webPanelXml = "<web-panel key=\"myPanel\" location=\"atl.header\">\n" +
87 " <resource name=\"view\" type=\"static\"><![CDATA[<b>Hello World!</b>]]></resource>\n" +
88 "</web-panel>";
89 descriptor.init(plugin, createElement(webPanelXml));
90 descriptor.enabled();
91
92 assertEquals("atl.header", descriptor.getLocation());
93 assertContextProvider(NoOpContextProvider.class);
94 assertEquals("<b>Hello World!</b>", descriptor.getModule().getHtml(context));
95 }
96
97 public void testGetEmbeddedTemplateWithContextProvider() throws DocumentException, PluginParseException
98 {
99 final String webPanelXml = "<web-panel key=\"myPanel\" location=\"atl.header\">\n" +
100 " <resource name=\"view\" type=\"velocity\"><![CDATA[$addedToContext]]></resource>\n" +
101 " <context-provider class=\"com.atlassian.plugin.web.descriptors.MockContextProvider\" />\n" +
102 "</web-panel>";
103 descriptor.init(plugin, createElement(webPanelXml));
104 descriptor.enabled();
105
106 final WebPanelRenderer renderer = new MockVelocityRenderer();
107 when(pluginAccessor.getEnabledModulesByClass(WebPanelRenderer.class)).thenReturn(ImmutableList.of(renderer));
108
109 HashMap<String, Object> originalContext = new HashMap<String, Object>();
110 assertRendered(MockContextProvider.DATA_ADDED_TO_CONTEXT, originalContext);
111 assertEquals(0, originalContext.size());
112 }
113
114 public void testGetResourceTemplate() throws DocumentException, PluginParseException
115 {
116 final String webPanelXml = "<web-panel key=\"myPanel\" location=\"atl.header\">\n" +
117 " <resource name=\"view\" type=\"static\" location=\"ResourceTemplateWebPanelTest.txt\"/>\n" +
118 "</web-panel>";
119
120 descriptor.init(plugin, createElement(webPanelXml));
121 descriptor.enabled();
122
123 assertContextProvider(NoOpContextProvider.class);
124
125 String html = descriptor.getModule().getHtml(context);
126 assertTrue(html.startsWith("This <file> is used as web panel contents in unit tests"));
127 }
128
129 public void testGetResourceTemplateWithContextProvider() throws DocumentException, PluginParseException
130 {
131 final String webPanelXml = "<web-panel key=\"myPanel\" location=\"atl.header\">\n" +
132 " <resource name=\"view\" type=\"velocity\" location=\"ResourceTemplateWebPanelTest.txt\"/>\n" +
133 " <context-provider class=\"com.atlassian.plugin.web.descriptors.MockContextProvider\" />\n" +
134 "</web-panel>";
135 descriptor.init(plugin, createElement(webPanelXml));
136 descriptor.enabled();
137
138 final WebPanelRenderer renderer = new MockVelocityRenderer();
139 when(pluginAccessor.getEnabledModulesByClass(WebPanelRenderer.class)).thenReturn(ImmutableList.of(renderer));
140
141 HashMap<String, Object> originalContext = new HashMap<String, Object>();
142 assertRendered(MockContextProvider.DATA_ADDED_TO_CONTEXT, originalContext);
143 assertEquals(0, originalContext.size());
144 }
145
146 public void testWebPanelClass() throws DocumentException, PluginParseException
147 {
148 when(moduleClassFactory.createModule(eq("com.atlassian.plugin.web.descriptors.MockWebPanel"), any(DefaultWebPanelModuleDescriptor.class))).thenReturn(new MockWebPanel());
149
150 final String webPanelXml = "<web-panel key=\"myPanel\" location=\"atl.header\" class=\"com.atlassian.plugin.web.descriptors.MockWebPanel\"/>";
151 descriptor.init(plugin, createElement(webPanelXml));
152 descriptor.enabled();
153
154 assertRendered(MockWebPanel.NOTHING_IN_CONTEXT, new HashMap<String, Object>());
155 }
156
157 public void testWebPanelClassWithContextProvider() throws DocumentException, PluginParseException
158 {
159 when(moduleClassFactory.createModule(eq("com.atlassian.plugin.web.descriptors.MockWebPanel"), any(DefaultWebPanelModuleDescriptor.class))).thenReturn(new MockWebPanel());
160
161 final String webPanelXml = "<web-panel key=\"myPanel\" location=\"atl.header\" class=\"com.atlassian.plugin.web.descriptors.MockWebPanel\">\n" +
162 " <context-provider class=\"com.atlassian.plugin.web.descriptors.MockContextProvider\" />\n" +
163 "</web-panel>";
164 descriptor.init(plugin, createElement(webPanelXml));
165 descriptor.enabled();
166
167 HashMap<String, Object> originalContext = new HashMap<String, Object>();
168 assertRendered(MockContextProvider.DATA_ADDED_TO_CONTEXT, originalContext);
169
170
171 assertEquals(0, originalContext.size());
172 }
173
174 public void testSimpleLabelTemplate() throws DocumentException, PluginParseException
175 {
176 WebFragmentHelper fragmentHelper = spy(webInterfaceManager.getWebFragmentHelper());
177 when(webInterfaceManager.getWebFragmentHelper()).thenReturn(fragmentHelper);
178
179 when(fragmentHelper.renderVelocityFragment(eq("Hello ${x}"), any(Map.class))).thenReturn("It Worked!");
180
181 final String webPanelXml = "<web-panel key=\"myPanel\" location=\"atl.header\">\n" +
182 " <resource name=\"view\" type=\"static\"><![CDATA[<b>Hello World!</b>]]></resource>\n" +
183 " <label>Hello ${x}</label>" +
184 "</web-panel>";
185 descriptor.init(plugin, createElement(webPanelXml));
186 descriptor.enabled();
187
188 assertContextProvider(NoOpContextProvider.class);
189 Map<String,Object> ctx = new HashMap<String, Object>();
190 ctx.put("x", "foo");
191 assertEquals("It Worked!", descriptor.getWebLabel().getDisplayableLabel(null, ctx));
192 }
193
194 private void assertRendered(String expectedHtml, Map<String, Object> originalContext)
195 {
196 WebPanel webPanel = descriptor.getModule();
197 String renderedHtml = webPanel.getHtml(originalContext);
198 assertEquals(expectedHtml, renderedHtml);
199 }
200
201 private void assertContextProvider(Class expectedContextProviderClass)
202 {
203 assertEquals(expectedContextProviderClass, descriptor.getContextProvider().getClass());
204 }
205
206 private Element createElement(final String childElement) throws DocumentException
207 {
208 final Document document = DocumentHelper.parseText(childElement);
209 final Element element = document.getRootElement();
210 return element;
211 }
212
213 private class MockPlugin extends AbstractPlugin
214 {
215 MockPlugin(final String key)
216 {
217 setKey(key);
218 setName(key);
219 }
220
221 public boolean isUninstallable()
222 {
223 return false;
224 }
225
226 public boolean isDeleteable()
227 {
228 return false;
229 }
230
231 public boolean isDynamicallyLoaded()
232 {
233 return false;
234 }
235
236 public <T> Class<T> loadClass(final String clazz, final Class<?> callingClass) throws ClassNotFoundException
237 {
238 return null;
239 }
240
241 public ClassLoader getClassLoader()
242 {
243 return this.getClass().getClassLoader();
244 }
245
246 public URL getResource(final String path)
247 {
248 return null;
249 }
250
251 public InputStream getResourceAsStream(final String name)
252 {
253 return null;
254 }
255 }
256
257 private class MockVelocityRenderer implements WebPanelRenderer
258 {
259 static final String NOTHING_IN_CONTEXT = "nothing in context";
260
261 public String getResourceType()
262 {
263 return "velocity";
264 }
265
266 public void render(String templateName, Plugin plugin,
267 Map<String, Object> context, Writer writer)
268 throws RendererException, IOException
269 {
270 if (!context.isEmpty())
271 {
272 for (Object value : context.values())
273 {
274 writer.append(value.toString());
275 }
276 }
277 else
278 {
279 writer.append(NOTHING_IN_CONTEXT);
280 }
281 }
282
283 public String renderFragment(String fragment, Plugin plugin,
284 Map<String, Object> context) throws RendererException
285 {
286 try
287 {
288 StringWriter out = new StringWriter();
289 renderFragment(out, fragment, plugin, context);
290 return out.toString();
291 }
292 catch (IOException e)
293 {
294 throw new RuntimeException(e);
295 }
296 }
297
298 @Override
299 public void renderFragment(Writer writer, String fragment, Plugin plugin, Map<String, Object> context)
300 throws RendererException, IOException
301 {
302 if (!context.isEmpty())
303 {
304 for (Object value : context.values())
305 {
306 writer.write(value.toString());
307 }
308 }
309 else
310 {
311 writer.write(NOTHING_IN_CONTEXT);
312 }
313 }
314 }
315 }