PageRenderTime 39ms CodeModel.GetById 13ms RepoModel.GetById 0ms app.codeStats 0ms

/atlassian-plugins-servlet/src/test/java/com/atlassian/plugin/servlet/filter/TestDelegatingPluginFilter.java

https://bitbucket.org/purewind/atlassian-plugins
Java | 199 lines | 174 code | 21 blank | 4 comment | 0 complexity | d90b8e71a98d3a6fd5ded1e8c4f23151 MD5 | raw file
  1. package com.atlassian.plugin.servlet.filter;
  2. import com.atlassian.plugin.IllegalPluginStateException;
  3. import com.atlassian.plugin.Plugin;
  4. import com.atlassian.plugin.PluginArtifact;
  5. import com.atlassian.plugin.classloader.PluginClassLoader;
  6. import com.atlassian.plugin.impl.DefaultDynamicPlugin;
  7. import com.atlassian.plugin.servlet.descriptors.ServletFilterModuleDescriptor;
  8. import com.atlassian.plugin.servlet.descriptors.ServletFilterModuleDescriptorBuilder;
  9. import com.atlassian.plugin.servlet.filter.FilterTestUtils.FilterAdapter;
  10. import com.atlassian.plugin.test.PluginJarBuilder;
  11. import org.junit.Before;
  12. import org.junit.Rule;
  13. import org.junit.Test;
  14. import org.junit.rules.ExpectedException;
  15. import org.junit.runner.RunWith;
  16. import org.mockito.Mock;
  17. import org.mockito.runners.MockitoJUnitRunner;
  18. import javax.servlet.Filter;
  19. import javax.servlet.FilterChain;
  20. import javax.servlet.ServletException;
  21. import javax.servlet.ServletRequest;
  22. import javax.servlet.ServletResponse;
  23. import javax.servlet.http.HttpServletRequest;
  24. import javax.servlet.http.HttpServletResponse;
  25. import java.io.File;
  26. import java.io.IOException;
  27. import static com.atlassian.plugin.servlet.filter.FilterTestUtils.emptyChain;
  28. import static com.atlassian.plugin.servlet.filter.FilterTestUtils.newList;
  29. import static com.atlassian.plugin.test.PluginTestUtils.getFileForResource;
  30. import static org.hamcrest.MatcherAssert.assertThat;
  31. import static org.hamcrest.Matchers.is;
  32. import static org.mockito.Mockito.mock;
  33. import static org.mockito.Mockito.when;
  34. @RunWith(MockitoJUnitRunner.class)
  35. public class TestDelegatingPluginFilter {
  36. @Rule
  37. public ExpectedException expectedException = ExpectedException.none();
  38. @Mock
  39. private HttpServletRequest httpServletRequest;
  40. @Mock
  41. private HttpServletResponse httpServletResponse;
  42. @Before
  43. public void setUp() throws Exception {
  44. when(httpServletRequest.getPathInfo()).thenReturn("/servlet");
  45. }
  46. @Test
  47. public void testPluginClassLoaderIsThreadContextClassLoaderWhenFiltering() throws Exception {
  48. createClassLoaderCheckingFilter("filter").doFilter(httpServletRequest, httpServletResponse, emptyChain);
  49. }
  50. @Test
  51. public void testClassLoaderResetDuringFilterChainExecution() throws Exception {
  52. final ClassLoader initialClassLoader = Thread.currentThread().getContextClassLoader();
  53. final FilterChain chain = new FilterChain() {
  54. public void doFilter(final ServletRequest servletRequest, final ServletResponse servletResponse)
  55. throws IOException, ServletException {
  56. assertThat(Thread.currentThread().getContextClassLoader(), is(initialClassLoader));
  57. }
  58. };
  59. createClassLoaderCheckingFilter("filter").doFilter(httpServletRequest, httpServletResponse, chain);
  60. }
  61. @Test
  62. public void testPluginClassLoaderIsThreadContextLoaderWhenFiltersInChainAreFromDifferentPlugins() throws Exception {
  63. final Iterable<Filter> filters = newList(
  64. createClassLoaderCheckingFilter("filter-1"),
  65. createClassLoaderCheckingFilter("filter-2"),
  66. createClassLoaderCheckingFilter("filter-3")
  67. );
  68. final FilterChain chain = new IteratingFilterChain(filters.iterator(), emptyChain);
  69. chain.doFilter(httpServletRequest, httpServletResponse);
  70. }
  71. @Test
  72. public void testPluginClassLoaderIsRestoredProperlyWhenAnExceptionIsThrownFromFilter() throws Exception {
  73. final Iterable<Filter> filters = newList(
  74. createClassLoaderCheckingFilter("filter-1"),
  75. createClassLoaderCheckingFilter("filter-2"),
  76. createExceptionThrowingFilter("exception-filter"),
  77. createClassLoaderCheckingFilter("filter-3")
  78. );
  79. final FilterChain chain = new IteratingFilterChain(filters.iterator(), new FilterChain() {
  80. public void doFilter(final ServletRequest request, final ServletResponse response)
  81. throws IOException, ServletException {
  82. throw new ServletException("Exception should be thrown before reaching here.");
  83. }
  84. });
  85. expectedException.expect(ServletException.class);
  86. expectedException.expectMessage("exception-filter");
  87. chain.doFilter(httpServletRequest, httpServletResponse);
  88. }
  89. @Test
  90. public void pluginCanBeUninstalledFromFilterChain() throws Exception {
  91. final Plugin plugin = mock(Plugin.class);
  92. when(plugin.getClassLoader()).thenReturn(Thread.currentThread().getContextClassLoader());
  93. final FilterAdapter filter = new FilterAdapter() {
  94. @Override
  95. public void doFilter(final ServletRequest request, final ServletResponse response, final FilterChain chain)
  96. throws IOException, ServletException {
  97. chain.doFilter(request, response);
  98. }
  99. };
  100. final ServletFilterModuleDescriptor servletFilterModuleDescriptor = mock(ServletFilterModuleDescriptor.class);
  101. when(servletFilterModuleDescriptor.getPlugin()).thenReturn(plugin);
  102. when(servletFilterModuleDescriptor.getModule()).thenReturn(filter);
  103. // This boolean is a poor man's spy to check that the meat of the test is called. There doesn't seem to be a
  104. // natural mock to verify, and adding a spy for it feels perverse when the code is just here.
  105. final boolean chainCalled[] = {false};
  106. final FilterChain chain = new FilterChain() {
  107. public void doFilter(final ServletRequest servletRequest, final ServletResponse servletResponse)
  108. throws IOException, ServletException {
  109. // Pretend this chain uninstalls the plugin, which means, among other things, that you
  110. // can't get the classloader any more
  111. when(plugin.getClassLoader()).thenThrow(new IllegalPluginStateException("Plugin Uninstalled"));
  112. chainCalled[0] = true;
  113. }
  114. };
  115. final DelegatingPluginFilter delegatingPluginFilter = new DelegatingPluginFilter(servletFilterModuleDescriptor);
  116. delegatingPluginFilter.doFilter(httpServletRequest, httpServletResponse, chain);
  117. assertThat(chainCalled[0], is(true));
  118. }
  119. private Filter createClassLoaderCheckingFilter(final String name) throws Exception {
  120. final File pluginFile = new PluginJarBuilder()
  121. .addFormattedJava("my.SimpleFilter",
  122. "package my;" +
  123. "import java.io.IOException;" +
  124. "import javax.servlet.Filter;" +
  125. "import javax.servlet.FilterChain;" +
  126. "import javax.servlet.FilterConfig;" +
  127. "import javax.servlet.ServletException;" +
  128. "import javax.servlet.ServletRequest;" +
  129. "import javax.servlet.ServletResponse;" +
  130. "" +
  131. "public class SimpleFilter implements Filter" +
  132. "{" +
  133. " String name;" +
  134. " public void init(FilterConfig filterConfig) throws ServletException" +
  135. " {" +
  136. " name = filterConfig.getInitParameter('name');" +
  137. " }" +
  138. "" +
  139. " public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException" +
  140. " {" +
  141. " response.getWriter().write('entered: ' + name + '\');" +
  142. " chain.doFilter(request, response);" +
  143. " response.getWriter().write('exiting: ' + name + '\');" +
  144. " }" +
  145. " public void destroy() {}" +
  146. "}")
  147. .addFile("atlassian-plugin.xml", getFileForResource("com/atlassian/plugin/servlet/filter/atlassian-plugin-filter.xml"))
  148. .build();
  149. final PluginClassLoader pluginClassLoader = new PluginClassLoader(pluginFile);
  150. final PluginArtifact pluginArtifact = mock(PluginArtifact.class);
  151. final Plugin plugin = new DefaultDynamicPlugin(pluginArtifact, pluginClassLoader);
  152. final FilterAdapter testFilter = new FilterAdapter() {
  153. @Override
  154. public void doFilter(final ServletRequest request, final ServletResponse response, final FilterChain chain)
  155. throws IOException, ServletException {
  156. assertThat(name + " plugin ClassLoader should be current when entering",
  157. Thread.currentThread().getContextClassLoader(), is((ClassLoader) pluginClassLoader));
  158. chain.doFilter(request, response);
  159. assertThat(name + " plugin ClassLoader should be current when exiting",
  160. Thread.currentThread().getContextClassLoader(), is((ClassLoader) pluginClassLoader));
  161. }
  162. };
  163. final ServletFilterModuleDescriptor filterDescriptor = new ServletFilterModuleDescriptorBuilder()
  164. .with(testFilter)
  165. .with(plugin)
  166. .build();
  167. return new DelegatingPluginFilter(filterDescriptor);
  168. }
  169. private Filter createExceptionThrowingFilter(final String name) {
  170. return new FilterAdapter() {
  171. @Override
  172. public void doFilter(final ServletRequest request, final ServletResponse response, final FilterChain chain)
  173. throws IOException, ServletException {
  174. throw new ServletException(name);
  175. }
  176. };
  177. }
  178. }