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.

DefaultHttpDownloaderIT.java 9.5KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246
  1. /*
  2. * SonarQube
  3. * Copyright (C) 2009-2024 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.core.util;
  21. import java.io.File;
  22. import java.io.IOException;
  23. import java.io.InputStream;
  24. import java.io.PrintStream;
  25. import java.net.InetSocketAddress;
  26. import java.net.SocketAddress;
  27. import java.net.SocketTimeoutException;
  28. import java.net.URI;
  29. import java.net.URISyntaxException;
  30. import java.nio.charset.StandardCharsets;
  31. import java.util.Properties;
  32. import java.util.zip.GZIPOutputStream;
  33. import org.hamcrest.BaseMatcher;
  34. import org.hamcrest.Description;
  35. import org.junit.AfterClass;
  36. import org.junit.BeforeClass;
  37. import org.junit.Rule;
  38. import org.junit.Test;
  39. import org.junit.rules.DisableOnDebug;
  40. import org.junit.rules.TemporaryFolder;
  41. import org.junit.rules.TestRule;
  42. import org.junit.rules.Timeout;
  43. import org.simpleframework.http.Request;
  44. import org.simpleframework.http.Response;
  45. import org.simpleframework.http.core.Container;
  46. import org.simpleframework.http.core.ContainerServer;
  47. import org.simpleframework.transport.connect.SocketConnection;
  48. import org.sonar.api.CoreProperties;
  49. import org.sonar.api.config.internal.MapSettings;
  50. import org.sonar.api.platform.Server;
  51. import org.sonar.api.utils.SonarException;
  52. import static org.assertj.core.api.Assertions.assertThat;
  53. import static org.assertj.core.api.Assertions.assertThatThrownBy;
  54. import static org.mockito.Mockito.mock;
  55. import static org.mockito.Mockito.when;
  56. import static org.sonar.api.utils.HttpDownloader.HttpException;
  57. public class DefaultHttpDownloaderIT {
  58. @Rule
  59. public TemporaryFolder temporaryFolder = new TemporaryFolder();
  60. @Rule
  61. public TestRule safeguardTimeout = new DisableOnDebug(Timeout.seconds(60));
  62. private static SocketConnection socketConnection;
  63. private static String baseUrl;
  64. @BeforeClass
  65. public static void startServer() throws IOException {
  66. socketConnection = new SocketConnection(new ContainerServer(new Container() {
  67. public void handle(Request req, Response resp) {
  68. try {
  69. if (req.getPath().getPath().contains("/redirect/")) {
  70. resp.setCode(303);
  71. resp.setValue("Location", "/redirected");
  72. } else if (req.getPath().getPath().contains("/gzip/")) {
  73. if (!"gzip".equals(req.getValue("Accept-Encoding"))) {
  74. throw new IllegalStateException("Should accept gzip");
  75. }
  76. resp.setValue("Content-Encoding", "gzip");
  77. GZIPOutputStream gzipOutputStream = new GZIPOutputStream(resp.getOutputStream());
  78. gzipOutputStream.write("GZIP response".getBytes());
  79. gzipOutputStream.close();
  80. } else if (req.getPath().getPath().contains("/redirected")) {
  81. resp.getPrintStream().append("redirected");
  82. } else if (req.getPath().getPath().contains("/error")) {
  83. writeErrorResponse(req, resp);
  84. } else {
  85. writeDefaultResponse(req, resp);
  86. }
  87. } catch (IOException e) {
  88. throw new IllegalStateException(e);
  89. } finally {
  90. try {
  91. resp.close();
  92. } catch (IOException ignored) {
  93. }
  94. }
  95. }
  96. }));
  97. SocketAddress address = socketConnection.connect(new InetSocketAddress("localhost", 0));
  98. baseUrl = String.format("http://%s:%d", ((InetSocketAddress) address).getAddress().getHostAddress(), ((InetSocketAddress) address).getPort());
  99. }
  100. private static PrintStream writeDefaultResponse(Request req, Response resp) throws IOException {
  101. return resp.getPrintStream().append("agent=" + req.getValues("User-Agent").get(0));
  102. }
  103. private static void writeErrorResponse(Request req, Response resp) throws IOException {
  104. resp.setCode(500);
  105. resp.getPrintStream().append("agent=" + req.getValues("User-Agent").get(0));
  106. }
  107. @AfterClass
  108. public static void stopServer() throws IOException {
  109. if (null != socketConnection) {
  110. socketConnection.close();
  111. }
  112. }
  113. @Test(timeout = 10000)
  114. public void openStream_network_errors() throws IOException, URISyntaxException {
  115. // host not accepting connections
  116. String url = "http://127.0.0.1:1";
  117. assertThatThrownBy(() -> {
  118. DefaultHttpDownloader downloader = new DefaultHttpDownloader(mock(Server.class), new MapSettings().asConfig());
  119. downloader.openStream(new URI(url));
  120. })
  121. .isInstanceOf(SonarException.class)
  122. .isEqualToComparingFieldByField(new BaseMatcher<Exception>() {
  123. @Override
  124. public boolean matches(Object ex) {
  125. return ex instanceof SonarException && ((SonarException) ex).getCause() instanceof SocketTimeoutException;
  126. }
  127. @Override
  128. public void describeTo(Description arg0) {
  129. }
  130. });
  131. }
  132. @Test
  133. public void downloadBytes() throws URISyntaxException {
  134. byte[] bytes = new DefaultHttpDownloader(mock(Server.class), new MapSettings().asConfig()).readBytes(new URI(baseUrl));
  135. assertThat(bytes).hasSizeGreaterThan(10);
  136. }
  137. @Test
  138. public void readString() throws URISyntaxException {
  139. String text = new DefaultHttpDownloader(mock(Server.class), new MapSettings().asConfig()).readString(new URI(baseUrl), StandardCharsets.UTF_8);
  140. assertThat(text.length()).isGreaterThan(10);
  141. }
  142. @Test
  143. public void readGzipString() throws URISyntaxException {
  144. String text = new DefaultHttpDownloader(mock(Server.class), new MapSettings().asConfig()).readString(new URI(baseUrl + "/gzip/"), StandardCharsets.UTF_8);
  145. assertThat(text).isEqualTo("GZIP response");
  146. }
  147. @Test
  148. public void readStringWithDefaultTimeout() throws URISyntaxException {
  149. String text = new DefaultHttpDownloader(mock(Server.class), new MapSettings().asConfig()).readString(new URI(baseUrl + "/timeout/"), StandardCharsets.UTF_8);
  150. assertThat(text.length()).isGreaterThan(10);
  151. }
  152. @Test
  153. public void downloadToFile() throws URISyntaxException, IOException {
  154. File toDir = temporaryFolder.newFolder();
  155. File toFile = new File(toDir, "downloadToFile.txt");
  156. new DefaultHttpDownloader(mock(Server.class), new MapSettings().asConfig()).download(new URI(baseUrl), toFile);
  157. assertThat(toFile).exists();
  158. assertThat(toFile.length()).isGreaterThan(10L);
  159. }
  160. @Test
  161. public void shouldNotCreateFileIfFailToDownload() throws Exception {
  162. File toDir = temporaryFolder.newFolder();
  163. File toFile = new File(toDir, "downloadToFile.txt");
  164. try {
  165. new DefaultHttpDownloader(mock(Server.class), new MapSettings().asConfig()).download(new URI("http://localhost:1"), toFile);
  166. } catch (SonarException e) {
  167. assertThat(toFile).doesNotExist();
  168. }
  169. }
  170. @Test
  171. public void userAgent_includes_version_and_SERVER_ID_when_server_is_provided() throws URISyntaxException, IOException {
  172. Server server = mock(Server.class);
  173. when(server.getVersion()).thenReturn("2.2");
  174. MapSettings settings = new MapSettings();
  175. settings.setProperty(CoreProperties.SERVER_ID, "blablabla");
  176. InputStream stream = new DefaultHttpDownloader(server, settings.asConfig()).openStream(new URI(baseUrl));
  177. Properties props = new Properties();
  178. props.load(stream);
  179. stream.close();
  180. assertThat(props.getProperty("agent")).isEqualTo("SonarQube 2.2 # blablabla");
  181. }
  182. @Test
  183. public void userAgent_includes_only_version_when_there_is_no_SERVER_ID_and_server_is_provided() throws URISyntaxException, IOException {
  184. Server server = mock(Server.class);
  185. when(server.getVersion()).thenReturn("2.2");
  186. InputStream stream = new DefaultHttpDownloader(server, new MapSettings().asConfig()).openStream(new URI(baseUrl));
  187. Properties props = new Properties();
  188. props.load(stream);
  189. stream.close();
  190. assertThat(props.getProperty("agent")).isEqualTo("SonarQube 2.2 #");
  191. }
  192. @Test
  193. public void followRedirect() throws URISyntaxException {
  194. String content = new DefaultHttpDownloader(mock(Server.class), new MapSettings().asConfig()).readString(new URI(baseUrl + "/redirect/"), StandardCharsets.UTF_8);
  195. assertThat(content).isEqualTo("redirected");
  196. }
  197. @Test
  198. public void supported_schemes() {
  199. assertThat(new DefaultHttpDownloader(mock(Server.class), new MapSettings().asConfig()).getSupportedSchemes()).contains("http");
  200. }
  201. @Test
  202. public void uri_description() throws URISyntaxException {
  203. String description = new DefaultHttpDownloader(mock(Server.class), new MapSettings().asConfig()).description(new URI("http://sonarsource.org"));
  204. assertThat(description).isEqualTo("http://sonarsource.org");
  205. }
  206. @Test
  207. public void readBytes_whenServerReturnsError_shouldThrow() throws URISyntaxException {
  208. DefaultHttpDownloader downloader = new DefaultHttpDownloader(mock(Server.class), new MapSettings().asConfig());
  209. URI errorUri = new URI(baseUrl + "/error");
  210. assertThatThrownBy(() -> downloader.readBytes(errorUri)).isInstanceOf(HttpException.class).hasMessage("Fail to download [" + errorUri + "]. Response code: 500");
  211. }
  212. }