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