*/
package org.sonar.scanner.bootstrap;
+import com.google.common.annotations.VisibleForTesting;
import java.io.BufferedInputStream;
import java.io.File;
import java.io.IOException;
import java.util.stream.Stream;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.io.FileUtils;
-import org.sonar.api.config.Configuration;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import org.sonar.api.config.Configuration;
import org.sonar.scanner.bootstrap.ScannerPluginInstaller.InstalledPlugin;
import org.sonarqube.ws.client.GetRequest;
import org.sonarqube.ws.client.HttpException;
private static final Logger LOGGER = LoggerFactory.getLogger(PluginFiles.class);
private static final String MD5_HEADER = "Sonar-MD5";
+ @VisibleForTesting
+ static final String PLUGINS_DOWNLOAD_TIMEOUT_PROPERTY = "sonar.plugins.download.timeout";
+ private static final int PLUGINS_DOWNLOAD_TIMEOUT_DEFAULT = 300;
private final DefaultScannerWsClient wsClient;
+ private final Configuration configuration;
private final File cacheDir;
private final File tempDir;
public PluginFiles(DefaultScannerWsClient wsClient, Configuration configuration) {
this.wsClient = wsClient;
+ this.configuration = configuration;
File home = locateHomeDir(configuration);
this.cacheDir = mkdir(new File(home, "cache"), "user cache");
this.tempDir = mkdir(new File(home, "_tmp"), "temp dir");
private Optional<File> download(InstalledPlugin plugin) {
GetRequest request = new GetRequest("api/plugins/download")
.setParam("plugin", plugin.key)
- .setTimeOutInMs(5 * 60_000);
+ .setTimeOutInMs(configuration.getInt(PLUGINS_DOWNLOAD_TIMEOUT_PROPERTY).orElse(PLUGINS_DOWNLOAD_TIMEOUT_DEFAULT) * 1000);
File downloadedFile = newTempFile();
LOGGER.debug("Download plugin '{}' to '{}'", plugin.key, downloadedFile);
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
+import java.net.SocketTimeoutException;
import java.util.Collections;
import java.util.Optional;
+import java.util.concurrent.TimeUnit;
import javax.annotation.Nullable;
import okhttp3.HttpUrl;
import okhttp3.mockwebserver.MockResponse;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.assertj.core.api.ThrowableAssert.ThrowingCallable;
import static org.mockito.Mockito.mock;
+import static org.sonar.scanner.bootstrap.PluginFiles.PLUGINS_DOWNLOAD_TIMEOUT_PROPERTY;
public class PluginFilesTest {
userHome = temp.newFolder();
MapSettings settings = new MapSettings();
settings.setProperty("sonar.userHome", userHome.getAbsolutePath());
+ settings.setProperty(PLUGINS_DOWNLOAD_TIMEOUT_PROPERTY, 1);
underTest = new PluginFiles(wsClient, settings.asConfig());
}
expectISE("foo", "returned code 500", () -> underTest.get(plugin));
}
+ @Test
+ public void getPlugin_whenTimeOutReached_thenDownloadFails() {
+ MockResponse response = new MockResponse().setBody("test").setBodyDelay(2, TimeUnit.SECONDS);
+ response.setHeader("Sonar-MD5", "md5");
+ server.enqueue(response);
+ InstalledPlugin plugin = newInstalledPlugin("foo", "abc");
+
+ assertThatThrownBy(() -> underTest.get(plugin))
+ .isInstanceOf(IllegalStateException.class)
+ .hasMessageStartingWith("Fail to download plugin [" + plugin.key + "]")
+ .cause().isInstanceOf(SocketTimeoutException.class);
+ }
+
@Test
public void download_a_new_version_of_plugin_during_blue_green_switch() throws IOException {
FileAndMd5 tempJar = new FileAndMd5();