Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.

DefaultHttpDownloaderIT.java 8.6KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228
  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.Ignore;
  36. import org.junit.jupiter.api.AfterAll;
  37. import org.junit.jupiter.api.BeforeAll;
  38. import org.junit.jupiter.api.Disabled;
  39. import org.junit.jupiter.api.Test;
  40. import org.junit.jupiter.api.Timeout;
  41. import org.junit.jupiter.api.io.TempDir;
  42. import org.simpleframework.http.Request;
  43. import org.simpleframework.http.Response;
  44. import org.simpleframework.http.core.Container;
  45. import org.simpleframework.http.core.ContainerServer;
  46. import org.simpleframework.transport.connect.SocketConnection;
  47. import org.sonar.api.CoreProperties;
  48. import org.sonar.api.config.internal.MapSettings;
  49. import org.sonar.api.platform.Server;
  50. import org.sonar.api.utils.SonarException;
  51. import static org.assertj.core.api.Assertions.assertThat;
  52. import static org.assertj.core.api.Assertions.assertThatThrownBy;
  53. import static org.mockito.Mockito.mock;
  54. import static org.mockito.Mockito.when;
  55. import static org.sonar.api.utils.HttpDownloader.HttpException;
  56. class DefaultHttpDownloaderIT {
  57. @TempDir
  58. private File temporaryFolder;
  59. private static SocketConnection socketConnection;
  60. private static String baseUrl;
  61. @BeforeAll
  62. static void startServer() throws IOException {
  63. socketConnection = new SocketConnection(new ContainerServer(new Container() {
  64. public void handle(Request req, Response resp) {
  65. try {
  66. if (req.getPath().getPath().contains("/redirect/")) {
  67. resp.setCode(303);
  68. resp.setValue("Location", "/redirected");
  69. } else if (req.getPath().getPath().contains("/redirected")) {
  70. resp.getPrintStream().append("redirected");
  71. } else if (req.getPath().getPath().contains("/error")) {
  72. writeErrorResponse(req, resp);
  73. } else {
  74. writeDefaultResponse(req, resp);
  75. }
  76. } catch (IOException e) {
  77. throw new IllegalStateException(e);
  78. } finally {
  79. try {
  80. resp.close();
  81. } catch (IOException ignored) {
  82. }
  83. }
  84. }
  85. }));
  86. SocketAddress address = socketConnection.connect(new InetSocketAddress("localhost", 0));
  87. baseUrl = String.format("http://%s:%d", ((InetSocketAddress) address).getAddress().getHostAddress(), ((InetSocketAddress) address).getPort());
  88. }
  89. private static PrintStream writeDefaultResponse(Request req, Response resp) throws IOException {
  90. return resp.getPrintStream().append("agent=" + req.getValues("User-Agent").get(0));
  91. }
  92. private static void writeErrorResponse(Request req, Response resp) throws IOException {
  93. resp.setCode(500);
  94. resp.getPrintStream().append("agent=" + req.getValues("User-Agent").get(0));
  95. }
  96. @AfterAll
  97. static void stopServer() throws IOException {
  98. if (null != socketConnection) {
  99. socketConnection.close();
  100. }
  101. }
  102. @Test
  103. // To disable the timeout in debug mode, run the test with -Djunit.jupiter.execution.timeout.mode=disabled_on_debug
  104. @Timeout(10)
  105. void openStream_network_errors() throws IOException, URISyntaxException {
  106. // host not accepting connections
  107. String url = "http://127.0.0.1:1";
  108. assertThatThrownBy(() -> {
  109. DefaultHttpDownloader downloader = new DefaultHttpDownloader(mock(Server.class), new MapSettings().asConfig());
  110. downloader.openStream(new URI(url));
  111. })
  112. .isInstanceOf(SonarException.class)
  113. .isEqualToComparingFieldByField(new BaseMatcher<Exception>() {
  114. @Override
  115. public boolean matches(Object ex) {
  116. return ex instanceof SonarException && ((SonarException) ex).getCause() instanceof SocketTimeoutException;
  117. }
  118. @Override
  119. public void describeTo(Description arg0) {
  120. }
  121. });
  122. }
  123. @Test
  124. void downloadBytes() throws URISyntaxException {
  125. byte[] bytes = new DefaultHttpDownloader(mock(Server.class), new MapSettings().asConfig()).readBytes(new URI(baseUrl));
  126. assertThat(bytes).hasSizeGreaterThan(10);
  127. }
  128. @Test
  129. void readString() throws URISyntaxException {
  130. String text = new DefaultHttpDownloader(mock(Server.class), new MapSettings().asConfig()).readString(new URI(baseUrl), StandardCharsets.UTF_8);
  131. assertThat(text.length()).isGreaterThan(10);
  132. }
  133. @Test
  134. void readStringWithDefaultTimeout() throws URISyntaxException {
  135. String text = new DefaultHttpDownloader(mock(Server.class), new MapSettings().asConfig()).readString(new URI(baseUrl + "/timeout/"), StandardCharsets.UTF_8);
  136. assertThat(text.length()).isGreaterThan(10);
  137. }
  138. @Test
  139. void downloadToFile() throws URISyntaxException, IOException {
  140. File toFile = new File(temporaryFolder, "downloadToFile.txt");
  141. new DefaultHttpDownloader(mock(Server.class), new MapSettings().asConfig()).download(new URI(baseUrl), toFile);
  142. assertThat(toFile).exists();
  143. assertThat(toFile.length()).isGreaterThan(10L);
  144. }
  145. @Test
  146. void shouldNotCreateFileIfFailToDownload() throws Exception {
  147. File toFile = new File(temporaryFolder, "downloadToFile.txt");
  148. try {
  149. new DefaultHttpDownloader(mock(Server.class), new MapSettings().asConfig()).download(new URI("http://localhost:1"), toFile);
  150. } catch (SonarException e) {
  151. assertThat(toFile).doesNotExist();
  152. }
  153. }
  154. @Test
  155. void userAgent_includes_version_and_SERVER_ID_when_server_is_provided() throws URISyntaxException, IOException {
  156. Server server = mock(Server.class);
  157. when(server.getVersion()).thenReturn("2.2");
  158. MapSettings settings = new MapSettings();
  159. settings.setProperty(CoreProperties.SERVER_ID, "blablabla");
  160. InputStream stream = new DefaultHttpDownloader(server, settings.asConfig()).openStream(new URI(baseUrl));
  161. Properties props = new Properties();
  162. props.load(stream);
  163. stream.close();
  164. assertThat(props.getProperty("agent")).isEqualTo("SonarQube 2.2 # blablabla");
  165. }
  166. @Test
  167. void userAgent_includes_only_version_when_there_is_no_SERVER_ID_and_server_is_provided() throws URISyntaxException, IOException {
  168. Server server = mock(Server.class);
  169. when(server.getVersion()).thenReturn("2.2");
  170. InputStream stream = new DefaultHttpDownloader(server, new MapSettings().asConfig()).openStream(new URI(baseUrl));
  171. Properties props = new Properties();
  172. props.load(stream);
  173. stream.close();
  174. assertThat(props.getProperty("agent")).isEqualTo("SonarQube 2.2 #");
  175. }
  176. @Test
  177. void followRedirect() throws URISyntaxException {
  178. String content = new DefaultHttpDownloader(mock(Server.class), new MapSettings().asConfig()).readString(new URI(baseUrl + "/redirect/"), StandardCharsets.UTF_8);
  179. assertThat(content).isEqualTo("redirected");
  180. }
  181. @Test
  182. void supported_schemes() {
  183. assertThat(new DefaultHttpDownloader(mock(Server.class), new MapSettings().asConfig()).getSupportedSchemes()).contains("http");
  184. }
  185. @Test
  186. void uri_description() throws URISyntaxException {
  187. String description = new DefaultHttpDownloader(mock(Server.class), new MapSettings().asConfig()).description(new URI("http://sonarsource.org"));
  188. assertThat(description).isEqualTo("http://sonarsource.org");
  189. }
  190. @Test
  191. void readBytes_whenServerReturnsError_shouldThrow() throws URISyntaxException {
  192. DefaultHttpDownloader downloader = new DefaultHttpDownloader(mock(Server.class), new MapSettings().asConfig());
  193. URI errorUri = new URI(baseUrl + "/error");
  194. assertThatThrownBy(() -> downloader.readBytes(errorUri)).isInstanceOf(HttpException.class).hasMessage("Fail to download [" + errorUri + "]. Response code: 500");
  195. }
  196. }