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