Du kan inte välja fler än 25 ämnen Ämnen måste starta med en bokstav eller siffra, kan innehålla bindestreck ('-') och vara max 35 tecken långa.

StaticResourcesServletTest.java 12KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312
  1. /*
  2. * SonarQube
  3. * Copyright (C) 2009-2019 SonarSource SA
  4. * mailto:info AT sonarsource DOT com
  5. *
  6. * This program is free software; you can redistribute it and/or
  7. * modify it under the terms of the GNU Lesser General Public
  8. * License as published by the Free Software Foundation; either
  9. * version 3 of the License, or (at your option) any later version.
  10. *
  11. * This program is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  14. * Lesser General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU Lesser General Public License
  17. * along with this program; if not, write to the Free Software Foundation,
  18. * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  19. */
  20. package org.sonar.server.platform.web;
  21. import java.io.IOException;
  22. import java.io.InputStream;
  23. import javax.annotation.CheckForNull;
  24. import javax.annotation.Nullable;
  25. import javax.servlet.http.HttpServletResponse;
  26. import okhttp3.OkHttpClient;
  27. import okhttp3.Request;
  28. import okhttp3.Response;
  29. import org.apache.catalina.connector.ClientAbortException;
  30. import org.apache.commons.io.IOUtils;
  31. import org.eclipse.jetty.server.Server;
  32. import org.eclipse.jetty.servlet.ServletContextHandler;
  33. import org.eclipse.jetty.servlet.ServletHolder;
  34. import org.junit.After;
  35. import org.junit.Before;
  36. import org.junit.Rule;
  37. import org.junit.Test;
  38. import org.sonar.api.utils.log.LogTester;
  39. import org.sonar.api.utils.log.LoggerLevel;
  40. import org.sonar.core.platform.PluginInfo;
  41. import org.sonar.core.platform.PluginRepository;
  42. import org.sonar.core.extension.CoreExtensionRepository;
  43. import static org.assertj.core.api.Assertions.assertThat;
  44. import static org.mockito.Mockito.mock;
  45. import static org.mockito.Mockito.when;
  46. public class StaticResourcesServletTest {
  47. @Rule
  48. public LogTester logTester = new LogTester();
  49. private Server jetty;
  50. private PluginRepository pluginRepository = mock(PluginRepository.class);
  51. private CoreExtensionRepository coreExtensionRepository = mock(CoreExtensionRepository.class);
  52. private TestSystem system = new TestSystem(pluginRepository, coreExtensionRepository);
  53. @Before
  54. public void setUp() throws Exception {
  55. jetty = new Server(0);
  56. ServletContextHandler context = new ServletContextHandler(ServletContextHandler.SESSIONS);
  57. context.setContextPath("/");
  58. ServletHolder servletHolder = new ServletHolder(new StaticResourcesServlet(system));
  59. context.addServlet(servletHolder, "/static/*");
  60. jetty.setHandler(context);
  61. jetty.start();
  62. }
  63. @After
  64. public void tearDown() throws Exception {
  65. if (jetty != null) {
  66. jetty.stop();
  67. }
  68. }
  69. private Response call(String path) throws Exception {
  70. OkHttpClient client = new OkHttpClient();
  71. Request request = new Request.Builder()
  72. .url(jetty.getURI().resolve(path).toString())
  73. .build();
  74. return client.newCall(request).execute();
  75. }
  76. @Test
  77. public void return_content_if_exists_in_installed_plugin() throws Exception {
  78. system.pluginStream = IOUtils.toInputStream("bar");
  79. when(pluginRepository.hasPlugin("myplugin")).thenReturn(true);
  80. Response response = call("/static/myplugin/foo.txt");
  81. assertThat(response.isSuccessful()).isTrue();
  82. assertThat(response.body().string()).isEqualTo("bar");
  83. assertThat(system.pluginResource).isEqualTo("static/foo.txt");
  84. }
  85. @Test
  86. public void return_content_of_folder_of_installed_plugin() throws Exception {
  87. system.pluginStream = IOUtils.toInputStream("bar");
  88. when(pluginRepository.hasPlugin("myplugin")).thenReturn(true);
  89. Response response = call("/static/myplugin/foo/bar.txt");
  90. assertThat(response.isSuccessful()).isTrue();
  91. assertThat(response.body().string()).isEqualTo("bar");
  92. assertThat(system.pluginResource).isEqualTo("static/foo/bar.txt");
  93. }
  94. @Test
  95. public void return_content_of_folder_of_installed_core_extension() throws Exception {
  96. system.coreExtensionStream = IOUtils.toInputStream("bar");
  97. when(coreExtensionRepository.isInstalled("coreext")).thenReturn(true);
  98. Response response = call("/static/coreext/foo/bar.txt");
  99. assertThat(response.isSuccessful()).isTrue();
  100. assertThat(response.body().string()).isEqualTo("bar");
  101. assertThat(system.coreExtensionResource).isEqualTo("static/foo/bar.txt");
  102. }
  103. @Test
  104. public void return_content_of_folder_of_installed_core_extension_over_installed_plugin_in_case_of_key_conflict() throws Exception {
  105. system.coreExtensionStream = IOUtils.toInputStream("bar of plugin");
  106. when(coreExtensionRepository.isInstalled("samekey")).thenReturn(true);
  107. system.coreExtensionStream = IOUtils.toInputStream("bar of core extension");
  108. when(coreExtensionRepository.isInstalled("samekey")).thenReturn(true);
  109. Response response = call("/static/samekey/foo/bar.txt");
  110. assertThat(response.isSuccessful()).isTrue();
  111. assertThat(response.body().string()).isEqualTo("bar of core extension");
  112. assertThat(system.pluginResource).isNull();
  113. assertThat(system.coreExtensionResource).isEqualTo("static/foo/bar.txt");
  114. }
  115. @Test
  116. public void mime_type_is_set_on_response() throws Exception {
  117. system.pluginStream = IOUtils.toInputStream("bar");
  118. when(pluginRepository.hasPlugin("myplugin")).thenReturn(true);
  119. Response response = call("/static/myplugin/foo.css");
  120. assertThat(response.header("Content-Type")).isEqualTo("text/css");
  121. assertThat(response.body().string()).isEqualTo("bar");
  122. }
  123. @Test
  124. public void return_404_if_resource_not_found_in_installed_plugin() throws Exception {
  125. system.pluginStream = null;
  126. when(pluginRepository.hasPlugin("myplugin")).thenReturn(true);
  127. Response response = call("/static/myplugin/foo.css");
  128. assertThat(response.code()).isEqualTo(404);
  129. assertThat(logTester.logs(LoggerLevel.ERROR)).isEmpty();
  130. assertThat(logTester.logs(LoggerLevel.WARN)).isEmpty();
  131. }
  132. @Test
  133. public void return_404_if_plugin_does_not_exist() throws Exception {
  134. system.pluginStream = null;
  135. when(pluginRepository.hasPlugin("myplugin")).thenReturn(false);
  136. Response response = call("/static/myplugin/foo.css");
  137. assertThat(response.code()).isEqualTo(404);
  138. assertThat(logTester.logs(LoggerLevel.ERROR)).isEmpty();
  139. assertThat(logTester.logs(LoggerLevel.WARN)).isEmpty();
  140. }
  141. @Test
  142. public void return_resource_if_exists_in_requested_plugin() throws Exception {
  143. system.pluginStream = IOUtils.toInputStream("bar");
  144. when(pluginRepository.hasPlugin("myplugin")).thenReturn(true);
  145. when(pluginRepository.getPluginInfo("myplugin")).thenReturn(new PluginInfo("myplugin"));
  146. Response response = call("/static/myplugin/foo.css");
  147. assertThat(response.isSuccessful()).isTrue();
  148. assertThat(response.body().string()).isEqualTo("bar");
  149. assertThat(logTester.logs(LoggerLevel.ERROR)).isEmpty();
  150. assertThat(logTester.logs(LoggerLevel.WARN)).isEmpty();
  151. }
  152. @Test
  153. public void do_not_fail_nor_log_ERROR_when_response_is_already_committed_and_plugin_does_not_exist() throws Exception {
  154. system.pluginStream = null;
  155. system.isCommitted = true;
  156. when(pluginRepository.hasPlugin("myplugin")).thenReturn(false);
  157. Response response = call("/static/myplugin/foo.css");
  158. assertThat(response.code()).isEqualTo(200);
  159. assertThat(logTester.logs(LoggerLevel.ERROR)).isEmpty();
  160. assertThat(logTester.logs(LoggerLevel.TRACE)).contains("Response is committed. Cannot send error response code 404");
  161. }
  162. @Test
  163. public void do_not_fail_nor_log_ERROR_when_sendError_throws_IOException_and_plugin_does_not_exist() throws Exception {
  164. system.sendErrorException = new IOException("Simulating sendError throwing IOException");
  165. when(pluginRepository.hasPlugin("myplugin")).thenReturn(false);
  166. Response response = call("/static/myplugin/foo.css");
  167. assertThat(response.code()).isEqualTo(200);
  168. assertThat(logTester.logs(LoggerLevel.ERROR)).isEmpty();
  169. assertThat(logTester.logs(LoggerLevel.TRACE)).contains("Failed to send error code 404: java.io.IOException: Simulating sendError throwing IOException");
  170. }
  171. @Test
  172. public void do_not_fail_nor_log_ERROR_when_response_is_already_committed_and_resource_does_not_exist_in_installed_plugin() throws Exception {
  173. system.isCommitted = true;
  174. system.pluginStream = null;
  175. when(pluginRepository.hasPlugin("myplugin")).thenReturn(true);
  176. Response response = call("/static/myplugin/foo.css");
  177. assertThat(response.code()).isEqualTo(200);
  178. assertThat(logTester.logs(LoggerLevel.ERROR)).isEmpty();
  179. assertThat(logTester.logs(LoggerLevel.TRACE)).contains("Response is committed. Cannot send error response code 404");
  180. }
  181. @Test
  182. public void do_not_fail_nor_log_not_attempt_to_send_error_if_ClientAbortException_is_raised() throws Exception {
  183. system.pluginStreamException = new ClientAbortException("Simulating ClientAbortException");
  184. when(pluginRepository.hasPlugin("myplugin")).thenReturn(true);
  185. Response response = call("/static/myplugin/foo.css");
  186. assertThat(response.code()).isEqualTo(200);
  187. assertThat(logTester.logs(LoggerLevel.ERROR)).isEmpty();
  188. assertThat(logTester.logs(LoggerLevel.TRACE)).contains(
  189. "Client canceled loading resource [static/foo.css] from plugin [myplugin]: org.apache.catalina.connector.ClientAbortException: Simulating ClientAbortException");
  190. }
  191. @Test
  192. public void do_not_fail_when_response_is_committed_after_other_error() throws Exception {
  193. system.isCommitted = true;
  194. system.pluginStreamException = new RuntimeException("Simulating a error");
  195. when(pluginRepository.hasPlugin("myplugin")).thenReturn(true);
  196. Response response = call("/static/myplugin/foo.css");
  197. assertThat(response.code()).isEqualTo(200);
  198. assertThat(logTester.logs(LoggerLevel.ERROR)).contains("Unable to load resource [static/foo.css] from plugin [myplugin]");
  199. }
  200. private static class TestSystem extends StaticResourcesServlet.System {
  201. private final PluginRepository pluginRepository;
  202. private final CoreExtensionRepository coreExtensionRepository;
  203. @Nullable
  204. private InputStream pluginStream;
  205. private Exception pluginStreamException = null;
  206. @Nullable
  207. private String pluginResource;
  208. @Nullable
  209. private InputStream coreExtensionStream;
  210. private Exception coreExtensionStreamException = null;
  211. private String coreExtensionResource;
  212. private boolean isCommitted = false;
  213. private IOException sendErrorException = null;
  214. TestSystem(PluginRepository pluginRepository, CoreExtensionRepository coreExtensionRepository) {
  215. this.pluginRepository = pluginRepository;
  216. this.coreExtensionRepository = coreExtensionRepository;
  217. }
  218. @Override
  219. PluginRepository getPluginRepository() {
  220. return pluginRepository;
  221. }
  222. @Override
  223. CoreExtensionRepository getCoreExtensionRepository() {
  224. return this.coreExtensionRepository;
  225. }
  226. @CheckForNull
  227. @Override
  228. InputStream openPluginResourceStream(String pluginKey, String resource, PluginRepository pluginRepository) throws Exception {
  229. pluginResource = resource;
  230. if (pluginStreamException != null) {
  231. throw pluginStreamException;
  232. }
  233. return pluginStream;
  234. }
  235. @CheckForNull
  236. @Override
  237. InputStream openCoreExtensionResourceStream(String resource) throws Exception {
  238. coreExtensionResource = resource;
  239. if (coreExtensionStreamException != null) {
  240. throw coreExtensionStreamException;
  241. }
  242. return coreExtensionStream;
  243. }
  244. @Override
  245. boolean isCommitted(HttpServletResponse response) {
  246. return isCommitted;
  247. }
  248. @Override
  249. void sendError(HttpServletResponse response, int error) throws IOException {
  250. if (sendErrorException != null) {
  251. throw sendErrorException;
  252. } else {
  253. super.sendError(response, error);
  254. }
  255. }
  256. }
  257. }