@@ -28,7 +28,10 @@ import java.util.Map; | |||
* coming from sonar-project.properties). | |||
*/ | |||
public class AnalysisProperties extends UserProperties { | |||
public AnalysisProperties(Map<String, String> properties) { | |||
this(properties, null); | |||
} | |||
public AnalysisProperties(Map<String, String> properties, @Nullable String pathToSecretKey) { | |||
super(properties, pathToSecretKey); | |||
} |
@@ -42,7 +42,7 @@ public class BatchComponents { | |||
// only static stuff | |||
} | |||
public static Collection all(DefaultAnalysisMode analysisMode) { | |||
public static Collection all(GlobalMode analysisMode) { | |||
List components = Lists.newArrayList( | |||
DefaultResourceTypes.get(), | |||
// SCM |
@@ -19,14 +19,18 @@ | |||
*/ | |||
package org.sonar.batch.bootstrap; | |||
import com.google.common.io.Files; | |||
import com.google.common.annotations.VisibleForTesting; | |||
import com.google.common.collect.Lists; | |||
import java.io.File; | |||
import java.io.IOException; | |||
import java.util.Collections; | |||
import java.util.HashMap; | |||
import java.util.List; | |||
import java.util.Map; | |||
import org.apache.commons.lang.CharUtils; | |||
import org.apache.commons.lang.StringUtils; | |||
import org.sonar.api.Plugin; | |||
@@ -47,12 +51,12 @@ public class BatchPluginInstaller implements PluginInstaller { | |||
private static final Logger LOG = Loggers.get(BatchPluginInstaller.class); | |||
private static final String PLUGINS_INDEX_URL = "/deploy/plugins/index.txt"; | |||
private final ServerClient server; | |||
private final WSLoader wsLoader; | |||
private final FileCache fileCache; | |||
private final BatchPluginPredicate pluginPredicate; | |||
public BatchPluginInstaller(ServerClient server, FileCache fileCache, BatchPluginPredicate pluginPredicate) { | |||
this.server = server; | |||
public BatchPluginInstaller(WSLoader wsLoader, FileCache fileCache, BatchPluginPredicate pluginPredicate) { | |||
this.wsLoader = wsLoader; | |||
this.fileCache = fileCache; | |||
this.pluginPredicate = pluginPredicate; | |||
} | |||
@@ -95,7 +99,8 @@ public class BatchPluginInstaller implements PluginInstaller { | |||
} else { | |||
LOG.info("Download {}", file.getFilename()); | |||
} | |||
server.download(url, toFile); | |||
Files.write(wsLoader.load(url), toFile); | |||
} | |||
}); | |||
@@ -111,7 +116,7 @@ public class BatchPluginInstaller implements PluginInstaller { | |||
List<RemotePlugin> listRemotePlugins() { | |||
try { | |||
Profiler profiler = Profiler.create(LOG).startInfo("Load plugins index"); | |||
String indexContent = server.request(PLUGINS_INDEX_URL); | |||
String indexContent = wsLoader.loadString(PLUGINS_INDEX_URL); | |||
profiler.stopInfo(); | |||
String[] rows = StringUtils.split(indexContent, CharUtils.LF); | |||
List<RemotePlugin> result = Lists.newArrayList(); |
@@ -23,17 +23,19 @@ import com.google.common.base.Joiner; | |||
import com.google.common.base.Predicate; | |||
import com.google.common.base.Splitter; | |||
import com.google.common.collect.Lists; | |||
import java.text.MessageFormat; | |||
import java.util.List; | |||
import java.util.Set; | |||
import javax.annotation.Nonnull; | |||
import org.apache.commons.lang.StringUtils; | |||
import org.sonar.api.CoreProperties; | |||
import org.sonar.api.batch.BatchSide; | |||
import org.sonar.api.config.Settings; | |||
import org.sonar.api.utils.log.Logger; | |||
import org.sonar.api.utils.log.Loggers; | |||
import static com.google.common.collect.Sets.newHashSet; | |||
/** | |||
@@ -50,9 +52,9 @@ public class BatchPluginPredicate implements Predicate<String> { | |||
private final Set<String> whites = newHashSet(); | |||
private final Set<String> blacks = newHashSet(); | |||
private final DefaultAnalysisMode mode; | |||
private final GlobalMode mode; | |||
public BatchPluginPredicate(Settings settings, DefaultAnalysisMode mode) { | |||
public BatchPluginPredicate(Settings settings, GlobalMode mode) { | |||
this.mode = mode; | |||
if (mode.isPreview()) { | |||
// These default values are not supported by Settings because the class CorePlugin |
@@ -20,7 +20,9 @@ | |||
package org.sonar.batch.bootstrap; | |||
import java.util.List; | |||
import javax.annotation.Nullable; | |||
import org.sonar.api.ExtensionProvider; | |||
import org.sonar.api.Plugin; | |||
import org.sonar.batch.bootstrapper.EnvironmentInformation; | |||
@@ -32,18 +34,18 @@ public class ExtensionInstaller { | |||
private final PluginRepository pluginRepository; | |||
private final EnvironmentInformation env; | |||
private final DefaultAnalysisMode analysisMode; | |||
private final GlobalMode globalMode; | |||
public ExtensionInstaller(PluginRepository pluginRepository, EnvironmentInformation env, DefaultAnalysisMode analysisMode) { | |||
public ExtensionInstaller(PluginRepository pluginRepository, EnvironmentInformation env, GlobalMode globalMode) { | |||
this.pluginRepository = pluginRepository; | |||
this.env = env; | |||
this.analysisMode = analysisMode; | |||
this.globalMode = globalMode; | |||
} | |||
public ExtensionInstaller install(ComponentContainer container, ExtensionMatcher matcher) { | |||
// core components | |||
for (Object o : BatchComponents.all(analysisMode)) { | |||
for (Object o : BatchComponents.all(globalMode)) { | |||
doInstall(container, matcher, null, o); | |||
} | |||
@@ -21,6 +21,7 @@ package org.sonar.batch.bootstrap; | |||
import java.util.List; | |||
import java.util.Map; | |||
import org.sonar.api.CoreProperties; | |||
import org.sonar.api.Plugin; | |||
import org.sonar.api.utils.Durations; | |||
@@ -52,7 +53,6 @@ import org.sonar.core.util.DefaultHttpDownloader; | |||
public class GlobalContainer extends ComponentContainer { | |||
private final Map<String, String> bootstrapProperties; | |||
private PersistentCacheProvider persistentCacheProvider; | |||
private GlobalContainer(Map<String, String> bootstrapProperties) { | |||
super(); | |||
@@ -68,14 +68,11 @@ public class GlobalContainer extends ComponentContainer { | |||
@Override | |||
protected void doBeforeStart() { | |||
BootstrapProperties bootstrapProps = new BootstrapProperties(bootstrapProperties); | |||
DefaultAnalysisMode analysisMode = new DefaultAnalysisMode(bootstrapProps.properties()); | |||
add(bootstrapProps, analysisMode); | |||
add(bootstrapProps); | |||
addBootstrapComponents(); | |||
} | |||
private void addBootstrapComponents() { | |||
persistentCacheProvider = new PersistentCacheProvider(); | |||
add( | |||
// plugins | |||
BatchPluginRepository.class, | |||
@@ -86,6 +83,7 @@ public class GlobalContainer extends ComponentContainer { | |||
ExtensionInstaller.class, | |||
CachesManager.class, | |||
GlobalMode.class, | |||
GlobalSettings.class, | |||
ServerClient.class, | |||
Logback.class, | |||
@@ -94,7 +92,8 @@ public class GlobalContainer extends ComponentContainer { | |||
DefaultHttpDownloader.class, | |||
UriReader.class, | |||
new FileCacheProvider(), | |||
persistentCacheProvider, | |||
new PersistentCacheProvider(), | |||
new WSLoaderGlobalProvider(), | |||
System2.INSTANCE, | |||
DefaultI18n.class, | |||
Durations.class, | |||
@@ -129,7 +128,6 @@ public class GlobalContainer extends ComponentContainer { | |||
public void executeAnalysis(Map<String, String> analysisProperties, Object... components) { | |||
AnalysisProperties props = new AnalysisProperties(analysisProperties, this.getComponentByType(BootstrapProperties.class).property(CoreProperties.ENCRYPTION_SECRET_KEY_PATH)); | |||
persistentCacheProvider.reconfigure(props); | |||
new ProjectScanContainer(this, props, components).execute(); | |||
} | |||
} |
@@ -0,0 +1,51 @@ | |||
/* | |||
* SonarQube, open source software quality management tool. | |||
* Copyright (C) 2008-2014 SonarSource | |||
* mailto:contact AT sonarsource DOT com | |||
* | |||
* SonarQube is free software; you can redistribute it and/or | |||
* modify it under the terms of the GNU Lesser General Public | |||
* License as published by the Free Software Foundation; either | |||
* version 3 of the License, or (at your option) any later version. | |||
* | |||
* SonarQube is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||
* Lesser General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU Lesser General Public License | |||
* along with this program; if not, write to the Free Software Foundation, | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
package org.sonar.batch.bootstrap; | |||
import org.slf4j.Logger; | |||
import org.slf4j.LoggerFactory; | |||
import org.sonar.api.CoreProperties; | |||
import java.text.MessageFormat; | |||
public class GlobalMode { | |||
private static final Logger LOG = LoggerFactory.getLogger(GlobalMode.class); | |||
private boolean preview; | |||
public boolean isPreview() { | |||
return preview; | |||
} | |||
public GlobalMode(BootstrapProperties props) { | |||
if (props.property(CoreProperties.DRY_RUN) != null) { | |||
LOG.warn(MessageFormat.format("Property {0} is deprecated. Please use {1} instead.", CoreProperties.DRY_RUN, CoreProperties.ANALYSIS_MODE)); | |||
preview = "true".equals(props.property(CoreProperties.DRY_RUN)); | |||
} else { | |||
String mode = props.property(CoreProperties.ANALYSIS_MODE); | |||
preview = CoreProperties.ANALYSIS_MODE_PREVIEW.equals(mode) || CoreProperties.ANALYSIS_MODE_INCREMENTAL.equals(mode) || | |||
CoreProperties.ANALYSIS_MODE_QUICK.equals(mode); | |||
} | |||
if (preview) { | |||
LOG.info("Preview global mode"); | |||
} | |||
} | |||
} |
@@ -20,7 +20,9 @@ | |||
package org.sonar.batch.bootstrap; | |||
import com.google.common.collect.ImmutableMap; | |||
import java.util.Map; | |||
import org.slf4j.Logger; | |||
import org.slf4j.LoggerFactory; | |||
import org.sonar.api.CoreProperties; | |||
@@ -39,17 +41,17 @@ public class GlobalSettings extends Settings { | |||
* (what will happen, what should the user do, ...) as a value | |||
*/ | |||
private static final Map<String, String> DROPPED_PROPERTIES = ImmutableMap.of( | |||
"sonar.jdbc.url", JDBC_SPECIFIC_MESSAGE, | |||
"sonar.jdbc.username", JDBC_SPECIFIC_MESSAGE, | |||
"sonar.jdbc.password", JDBC_SPECIFIC_MESSAGE | |||
); | |||
"sonar.jdbc.url", JDBC_SPECIFIC_MESSAGE, | |||
"sonar.jdbc.username", JDBC_SPECIFIC_MESSAGE, | |||
"sonar.jdbc.password", JDBC_SPECIFIC_MESSAGE | |||
); | |||
private final BootstrapProperties bootstrapProps; | |||
private final GlobalRepositories globalReferentials; | |||
private final DefaultAnalysisMode mode; | |||
private final GlobalMode mode; | |||
public GlobalSettings(BootstrapProperties bootstrapProps, PropertyDefinitions propertyDefinitions, | |||
GlobalRepositories globalReferentials, DefaultAnalysisMode mode) { | |||
GlobalRepositories globalReferentials, GlobalMode mode) { | |||
super(propertyDefinitions); | |||
this.mode = mode; | |||
@@ -63,6 +65,12 @@ public class GlobalSettings extends Settings { | |||
private void init() { | |||
addProperties(globalReferentials.globalSettings()); | |||
addProperties(bootstrapProps.properties()); | |||
// To stay compatible with plugins that use the old property to check mode | |||
if (mode.isPreview()) { | |||
setProperty(CoreProperties.DRY_RUN, "true"); | |||
} | |||
LOG.info("Server id: " + getString(CoreProperties.SERVER_ID)); | |||
} | |||
@@ -20,7 +20,6 @@ | |||
package org.sonar.batch.bootstrap; | |||
import java.nio.file.Paths; | |||
import java.util.Map; | |||
import org.picocontainer.injectors.ProviderAdapter; | |||
import org.sonar.home.cache.PersistentCache; | |||
import org.sonar.home.cache.PersistentCacheBuilder; | |||
@@ -32,26 +31,14 @@ public class PersistentCacheProvider extends ProviderAdapter { | |||
if (cache == null) { | |||
PersistentCacheBuilder builder = new PersistentCacheBuilder(new Slf4jLogger()); | |||
builder.forceUpdate(isForceUpdate(props.properties())); | |||
String home = props.property("sonar.userHome"); | |||
if (home != null) { | |||
builder.setSonarHome(Paths.get(home)); | |||
} | |||
cache = builder.build(); | |||
} | |||
} | |||
return cache; | |||
} | |||
public void reconfigure(UserProperties props) { | |||
if (cache != null) { | |||
cache.reconfigure(isForceUpdate(props.properties())); | |||
} | |||
} | |||
private static boolean isForceUpdate(Map<String, String> props) { | |||
String enableCache = props.get("sonar.enableHttpCache"); | |||
return !"true".equals(enableCache); | |||
} | |||
} |
@@ -19,26 +19,27 @@ | |||
*/ | |||
package org.sonar.batch.bootstrap; | |||
import org.sonar.api.utils.HttpDownloader.HttpException; | |||
import com.google.common.base.Joiner; | |||
import com.google.common.base.Preconditions; | |||
import com.google.common.base.Strings; | |||
import com.google.common.io.Files; | |||
import com.google.common.io.InputSupplier; | |||
import com.google.gson.JsonArray; | |||
import com.google.gson.JsonElement; | |||
import com.google.gson.JsonObject; | |||
import com.google.gson.JsonParser; | |||
import java.io.ByteArrayInputStream; | |||
import java.io.File; | |||
import java.io.IOException; | |||
import java.io.InputStream; | |||
import java.io.UnsupportedEncodingException; | |||
import java.net.URI; | |||
import java.net.URLEncoder; | |||
import java.nio.file.Files; | |||
import java.nio.file.StandardCopyOption; | |||
import java.util.ArrayList; | |||
import java.util.List; | |||
import java.util.concurrent.Callable; | |||
import javax.annotation.Nullable; | |||
import org.apache.commons.io.IOUtils; | |||
import org.apache.commons.lang.StringEscapeUtils; | |||
import org.apache.commons.lang.StringUtils; | |||
@@ -47,7 +48,6 @@ import org.sonar.api.batch.BatchSide; | |||
import org.sonar.api.utils.HttpDownloader; | |||
import org.sonar.batch.bootstrapper.EnvironmentInformation; | |||
import org.sonar.core.util.DefaultHttpDownloader; | |||
import org.sonar.home.cache.PersistentCache; | |||
/** | |||
* Replace the deprecated org.sonar.batch.ServerMetadata | |||
@@ -60,29 +60,31 @@ public class ServerClient { | |||
private static final String GET = "GET"; | |||
private BootstrapProperties props; | |||
private PersistentCache cache; | |||
private DefaultHttpDownloader.BaseHttpDownloader downloader; | |||
private DefaultAnalysisMode mode; | |||
public ServerClient(BootstrapProperties settings, EnvironmentInformation env, PersistentCache cache, DefaultAnalysisMode mode) { | |||
public ServerClient(BootstrapProperties settings, EnvironmentInformation env) { | |||
this.props = settings; | |||
this.downloader = new DefaultHttpDownloader.BaseHttpDownloader(settings.properties(), env.toString()); | |||
this.cache = cache; | |||
this.mode = mode; | |||
} | |||
public String getURL() { | |||
return StringUtils.removeEnd(StringUtils.defaultIfBlank(props.property("sonar.host.url"), "http://localhost:9000"), "/"); | |||
} | |||
public URI getURI(String pathStartingWithSlash) { | |||
Preconditions.checkArgument(pathStartingWithSlash.startsWith("/"), "Path must start with slash /"); | |||
String path = StringEscapeUtils.escapeHtml(pathStartingWithSlash); | |||
return URI.create(getURL() + path); | |||
} | |||
public void download(String pathStartingWithSlash, File toFile) { | |||
download(pathStartingWithSlash, toFile, null); | |||
download(pathStartingWithSlash, toFile, null, null); | |||
} | |||
public void download(String pathStartingWithSlash, File toFile, @Nullable Integer readTimeoutMillis) { | |||
public void download(String pathStartingWithSlash, File toFile, @Nullable Integer connectTimeoutMillis, @Nullable Integer readTimeoutMillis) { | |||
try { | |||
InputSupplier<InputStream> inputSupplier = doRequest(pathStartingWithSlash, GET, readTimeoutMillis); | |||
Files.copy(inputSupplier, toFile); | |||
InputStream is = load(pathStartingWithSlash, GET, false, connectTimeoutMillis, readTimeoutMillis); | |||
Files.copy(is, toFile.toPath(), StandardCopyOption.REPLACE_EXISTING); | |||
} catch (HttpDownloader.HttpException he) { | |||
throw handleHttpException(he); | |||
} catch (IOException e) { | |||
@@ -90,80 +92,41 @@ public class ServerClient { | |||
} | |||
} | |||
public String request(String pathStartingWithSlash) { | |||
return request(pathStartingWithSlash, GET, true); | |||
} | |||
public String request(String pathStartingWithSlash, String requestMethod) { | |||
return request(pathStartingWithSlash, requestMethod, true); | |||
public String downloadString(String pathStartingWithSlash) { | |||
return downloadString(pathStartingWithSlash, GET, true, null); | |||
} | |||
public String request(String pathStartingWithSlash, boolean wrapHttpException) { | |||
return request(pathStartingWithSlash, GET, wrapHttpException, null); | |||
} | |||
public String request(String pathStartingWithSlash, String requestMethod, boolean wrapHttpException) { | |||
return request(pathStartingWithSlash, requestMethod, wrapHttpException, null); | |||
} | |||
public String request(String pathStartingWithSlash, String requestMethod, boolean wrapHttpException, @Nullable Integer timeoutMillis) { | |||
final byte[] buf = load(pathStartingWithSlash, requestMethod, wrapHttpException, timeoutMillis); | |||
public String downloadString(String pathStartingWithSlash, String requestMethod, boolean wrapHttpException, @Nullable Integer timeoutMillis) { | |||
InputStream is = load(pathStartingWithSlash, requestMethod, wrapHttpException, null, timeoutMillis); | |||
try { | |||
return new String(buf, "UTF-8"); | |||
} catch (UnsupportedEncodingException e) { | |||
return new String(IOUtils.toByteArray(is), "UTF-8"); | |||
} catch (IOException e) { | |||
throw new IllegalStateException(String.format("Unable to request: %s", pathStartingWithSlash), e); | |||
} | |||
} | |||
public InputSupplier<InputStream> doRequest(String pathStartingWithSlash, String requestMethod, @Nullable Integer timeoutMillis) { | |||
final byte[] buf = load(pathStartingWithSlash, requestMethod, false, timeoutMillis); | |||
return new InputSupplier<InputStream>() { | |||
@Override | |||
public InputStream getInput() throws IOException { | |||
return new ByteArrayInputStream(buf); | |||
} | |||
}; | |||
} | |||
private byte[] load(String pathStartingWithSlash, String requestMethod, boolean wrapHttpException, @Nullable Integer timeoutMillis) { | |||
Preconditions.checkArgument(pathStartingWithSlash.startsWith("/"), "Path must start with slash /"); | |||
String path = StringEscapeUtils.escapeHtml(pathStartingWithSlash); | |||
URI uri = URI.create(getURL() + path); | |||
/** | |||
* @throws IllegalStateException on I/O error, not limited to the network connection and if HTTP response code > 400 and wrapHttpException is true | |||
* @throws HttpException if HTTP response code > 400 and wrapHttpException is false | |||
*/ | |||
public InputStream load(String pathStartingWithSlash, String requestMethod, boolean wrapHttpException, @Nullable Integer connectTimeoutMs, | |||
@Nullable Integer readTimeoutMs) { | |||
URI uri = getURI(pathStartingWithSlash); | |||
try { | |||
if (GET.equals(requestMethod) && mode.isPreview()) { | |||
return cache.get(uri.toString(), new HttpValueLoader(uri, requestMethod, timeoutMillis)); | |||
if (Strings.isNullOrEmpty(getLogin())) { | |||
return downloader.newInputSupplier(uri, requestMethod, connectTimeoutMs, readTimeoutMs).getInput(); | |||
} else { | |||
return new HttpValueLoader(uri, requestMethod, timeoutMillis).call(); | |||
return downloader.newInputSupplier(uri, requestMethod, getLogin(), getPassword(), connectTimeoutMs, readTimeoutMs).getInput(); | |||
} | |||
} catch (HttpDownloader.HttpException e) { | |||
throw wrapHttpException ? handleHttpException(e) : e; | |||
} catch (Exception e) { | |||
throw new IllegalStateException(String.format("Unable to request: %s", uri), e); | |||
} | |||
} | |||
private class HttpValueLoader implements Callable<byte[]> { | |||
private URI uri; | |||
private String requestMethod; | |||
private Integer timeoutMillis; | |||
public HttpValueLoader(URI uri, String requestMethod, Integer timeoutMillis) { | |||
this.uri = uri; | |||
this.requestMethod = requestMethod; | |||
this.timeoutMillis = timeoutMillis; | |||
} | |||
@Override | |||
public byte[] call() throws Exception { | |||
InputSupplier<InputStream> inputSupplier; | |||
if (Strings.isNullOrEmpty(getLogin())) { | |||
inputSupplier = downloader.newInputSupplier(uri, requestMethod, timeoutMillis); | |||
if (wrapHttpException) { | |||
throw handleHttpException(e); | |||
} else { | |||
inputSupplier = downloader.newInputSupplier(uri, requestMethod, getLogin(), getPassword(), timeoutMillis); | |||
throw e; | |||
} | |||
return IOUtils.toByteArray(inputSupplier.getInput()); | |||
} catch (IOException e) { | |||
throw new IllegalStateException(String.format("Unable to request: %s", uri), e); | |||
} | |||
} | |||
@@ -207,14 +170,4 @@ public class ServerClient { | |||
public String getPassword() { | |||
return props.property(CoreProperties.PASSWORD); | |||
} | |||
public static String encodeForUrl(String url) { | |||
try { | |||
return URLEncoder.encode(url, "UTF-8"); | |||
} catch (UnsupportedEncodingException e) { | |||
throw new IllegalStateException("Encoding not supported", e); | |||
} | |||
} | |||
} |
@@ -0,0 +1,182 @@ | |||
/* | |||
* SonarQube, open source software quality management tool. | |||
* Copyright (C) 2008-2014 SonarSource | |||
* mailto:contact AT sonarsource DOT com | |||
* | |||
* SonarQube is free software; you can redistribute it and/or | |||
* modify it under the terms of the GNU Lesser General Public | |||
* License as published by the Free Software Foundation; either | |||
* version 3 of the License, or (at your option) any later version. | |||
* | |||
* SonarQube is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||
* Lesser General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU Lesser General Public License | |||
* along with this program; if not, write to the Free Software Foundation, | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
package org.sonar.batch.bootstrap; | |||
import javax.annotation.Nonnull; | |||
import org.sonar.api.utils.HttpDownloader; | |||
import com.google.common.io.ByteSource; | |||
import org.apache.commons.io.IOUtils; | |||
import java.io.IOException; | |||
import java.io.InputStream; | |||
import java.nio.charset.StandardCharsets; | |||
import static org.sonar.batch.bootstrap.WSLoader.ServerStatus.*; | |||
import static org.sonar.batch.bootstrap.WSLoader.LoadStrategy.*; | |||
import org.sonar.home.cache.PersistentCache; | |||
public class WSLoader { | |||
private static final String FAIL_MSG = "Server is not accessible and data is not cached"; | |||
private static final int CONNECT_TIMEOUT = 5000; | |||
private static final int READ_TIMEOUT = 10000; | |||
private static final String REQUEST_METHOD = "GET"; | |||
public enum ServerStatus { | |||
UNKNOWN, ACCESSIBLE, NOT_ACCESSIBLE; | |||
} | |||
public enum LoadStrategy { | |||
SERVER_FIRST, CACHE_FIRST; | |||
} | |||
private LoadStrategy loadStrategy; | |||
private boolean cacheEnabled; | |||
private ServerStatus serverStatus; | |||
private ServerClient client; | |||
private PersistentCache cache; | |||
public WSLoader(boolean cacheEnabled, PersistentCache cache, ServerClient client) { | |||
this.cacheEnabled = cacheEnabled; | |||
this.loadStrategy = CACHE_FIRST; | |||
this.serverStatus = UNKNOWN; | |||
this.cache = cache; | |||
this.client = client; | |||
} | |||
public WSLoader(PersistentCache cache, ServerClient client) { | |||
this(false, cache, client); | |||
} | |||
public ByteSource loadSource(String id) { | |||
return ByteSource.wrap(load(id)); | |||
} | |||
public String loadString(String id) { | |||
return new String(load(id), StandardCharsets.UTF_8); | |||
} | |||
@Nonnull | |||
public byte[] load(String id) { | |||
if (loadStrategy == CACHE_FIRST) { | |||
return loadFromCacheFirst(id); | |||
} else { | |||
return loadFromServerFirst(id); | |||
} | |||
} | |||
public void setStrategy(LoadStrategy strategy) { | |||
this.loadStrategy = strategy; | |||
} | |||
public LoadStrategy getStrategy() { | |||
return this.loadStrategy; | |||
} | |||
public void setCacheEnabled(boolean enabled) { | |||
this.cacheEnabled = enabled; | |||
} | |||
public boolean isCacheEnabled() { | |||
return this.cacheEnabled; | |||
} | |||
private void switchToOffline() { | |||
serverStatus = NOT_ACCESSIBLE; | |||
} | |||
private void switchToOnline() { | |||
serverStatus = ACCESSIBLE; | |||
} | |||
private boolean isOffline() { | |||
return serverStatus == NOT_ACCESSIBLE; | |||
} | |||
@Nonnull | |||
private byte[] loadFromCacheFirst(String id) { | |||
byte[] cached = loadFromCache(id); | |||
if (cached != null) { | |||
return cached; | |||
} | |||
try { | |||
return loadFromServer(id); | |||
} catch (Exception e) { | |||
if (e.getCause() instanceof HttpDownloader.HttpException) { | |||
throw e; | |||
} | |||
} | |||
throw new IllegalStateException(FAIL_MSG); | |||
} | |||
@Nonnull | |||
private byte[] loadFromServerFirst(String id) { | |||
try { | |||
return loadFromServer(id); | |||
} catch (Exception serverException) { | |||
if (serverException.getCause() instanceof HttpDownloader.HttpException) { | |||
// http exceptions should always be thrown (no fallback) | |||
throw serverException; | |||
} | |||
byte[] cached = loadFromCache(id); | |||
if (cached != null) { | |||
return cached; | |||
} | |||
} | |||
throw new IllegalStateException(FAIL_MSG); | |||
} | |||
private byte[] loadFromCache(String id) { | |||
if (!cacheEnabled) { | |||
return null; | |||
} | |||
try { | |||
return cache.get(client.getURI(id).toString(), null); | |||
} catch (IOException e) { | |||
throw new IllegalStateException(e); | |||
} | |||
} | |||
private byte[] loadFromServer(String id) { | |||
if (isOffline()) { | |||
throw new IllegalStateException("Server is not accessible"); | |||
} | |||
try { | |||
InputStream is = client.load(id, REQUEST_METHOD, true, CONNECT_TIMEOUT, READ_TIMEOUT); | |||
switchToOnline(); | |||
byte[] value = IOUtils.toByteArray(is); | |||
if (cacheEnabled) { | |||
cache.put(client.getURI(id).toString(), value); | |||
} | |||
return value; | |||
} catch (IllegalStateException e) { | |||
switchToOffline(); | |||
throw e; | |||
} catch (Exception e) { | |||
switchToOffline(); | |||
throw new IllegalStateException(e); | |||
} | |||
} | |||
} |
@@ -0,0 +1,46 @@ | |||
/* | |||
* SonarQube, open source software quality management tool. | |||
* Copyright (C) 2008-2014 SonarSource | |||
* mailto:contact AT sonarsource DOT com | |||
* | |||
* SonarQube is free software; you can redistribute it and/or | |||
* modify it under the terms of the GNU Lesser General Public | |||
* License as published by the Free Software Foundation; either | |||
* version 3 of the License, or (at your option) any later version. | |||
* | |||
* SonarQube is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||
* Lesser General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU Lesser General Public License | |||
* along with this program; if not, write to the Free Software Foundation, | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
package org.sonar.batch.bootstrap; | |||
import org.picocontainer.injectors.ProviderAdapter; | |||
import org.sonar.batch.bootstrap.WSLoader.LoadStrategy; | |||
import java.util.Map; | |||
import org.sonar.home.cache.PersistentCache; | |||
public class WSLoaderGlobalProvider extends ProviderAdapter { | |||
private static final LoadStrategy DEFAULT_STRATEGY = LoadStrategy.SERVER_FIRST; | |||
private WSLoader wsLoader; | |||
public WSLoader provide(BootstrapProperties props, GlobalMode mode, PersistentCache cache, ServerClient client) { | |||
if (wsLoader == null) { | |||
wsLoader = new WSLoader(isCacheEnabled(props.properties(), mode.isPreview()), cache, client); | |||
wsLoader.setStrategy(DEFAULT_STRATEGY); | |||
} | |||
return wsLoader; | |||
} | |||
private static boolean isCacheEnabled(Map<String, String> props, boolean isPreview) { | |||
String enableOffline = props.get("sonar.enableOffline"); | |||
return isPreview && "true".equals(enableOffline); | |||
} | |||
} |
@@ -19,23 +19,26 @@ | |||
*/ | |||
package org.sonar.batch.cpd.index; | |||
import org.sonar.batch.scan.ProjectAnalysisMode; | |||
import com.google.common.annotations.VisibleForTesting; | |||
import javax.annotation.Nullable; | |||
import org.apache.commons.lang.StringUtils; | |||
import org.slf4j.Logger; | |||
import org.sonar.api.CoreProperties; | |||
import org.sonar.api.batch.BatchSide; | |||
import org.sonar.api.config.Settings; | |||
import org.sonar.api.resources.Project; | |||
import org.sonar.batch.bootstrap.DefaultAnalysisMode; | |||
@BatchSide | |||
public class IndexFactory { | |||
private final Settings settings; | |||
private final DefaultAnalysisMode mode; | |||
private final ProjectAnalysisMode mode; | |||
public IndexFactory(DefaultAnalysisMode mode, Settings settings) { | |||
public IndexFactory(ProjectAnalysisMode mode, Settings settings) { | |||
this.mode = mode; | |||
this.settings = settings; | |||
} |
@@ -19,18 +19,20 @@ | |||
*/ | |||
package org.sonar.batch.issue.tracking; | |||
import org.sonar.batch.util.BatchUtils; | |||
import org.sonar.batch.bootstrap.WSLoader; | |||
import com.google.common.base.Splitter; | |||
import com.google.common.collect.Iterators; | |||
import org.sonar.api.utils.log.Loggers; | |||
import org.sonar.api.utils.log.Profiler; | |||
import org.sonar.batch.bootstrap.ServerClient; | |||
public class DefaultServerLineHashesLoader implements ServerLineHashesLoader { | |||
private final ServerClient server; | |||
private final WSLoader wsLoader; | |||
public DefaultServerLineHashesLoader(ServerClient server) { | |||
this.server = server; | |||
public DefaultServerLineHashesLoader(WSLoader wsLoader) { | |||
this.wsLoader = wsLoader; | |||
} | |||
@Override | |||
@@ -44,7 +46,7 @@ public class DefaultServerLineHashesLoader implements ServerLineHashesLoader { | |||
.addContext("file", fileKey) | |||
.startDebug("Load line hashes"); | |||
try { | |||
return server.request("/api/sources/hash?key=" + ServerClient.encodeForUrl(fileKey)); | |||
return wsLoader.loadString("/api/sources/hash?key=" + BatchUtils.encodeForUrl(fileKey)); | |||
} finally { | |||
profiler.stopDebug(); | |||
} |
@@ -190,7 +190,7 @@ public class BatchMediumTester { | |||
} | |||
TaskBuilder builder = new TaskBuilder(this); | |||
builder.property("sonar.projectBaseDir", sonarProps.getParentFile().getAbsolutePath()); | |||
for (Map.Entry entry : prop.entrySet()) { | |||
for (Map.Entry<Object, Object> entry : prop.entrySet()) { | |||
builder.property(entry.getKey().toString(), entry.getValue().toString()); | |||
} | |||
return builder; | |||
@@ -238,7 +238,7 @@ public class BatchMediumTester { | |||
return ref.globalSettings(); | |||
} | |||
public FakeGlobalRepositoriesLoader add(Metric metric) { | |||
public FakeGlobalRepositoriesLoader add(Metric<?> metric) { | |||
Boolean optimizedBestValue = metric.isOptimizedBestValue(); | |||
ref.metrics().add(new org.sonar.batch.protocol.input.Metric(metricId, | |||
metric.key(), |
@@ -19,9 +19,10 @@ | |||
*/ | |||
package org.sonar.batch.phases; | |||
import org.sonar.batch.scan.ProjectAnalysisMode; | |||
import org.sonar.api.batch.SensorContext; | |||
import org.sonar.api.resources.Project; | |||
import org.sonar.batch.bootstrap.DefaultAnalysisMode; | |||
import org.sonar.batch.events.BatchStepEvent; | |||
import org.sonar.batch.events.EventBus; | |||
import org.sonar.batch.index.DefaultIndex; | |||
@@ -48,7 +49,7 @@ public final class PhaseExecutor { | |||
private final QProfileVerifier profileVerifier; | |||
private final IssueExclusionsLoader issueExclusionsLoader; | |||
private final IssuesReports issuesReport; | |||
private final DefaultAnalysisMode analysisMode; | |||
private final ProjectAnalysisMode analysisMode; | |||
private final LocalIssueTracking localIssueTracking; | |||
public PhaseExecutor(InitializersExecutor initializersExecutor, PostJobsExecutor postJobsExecutor, SensorsExecutor sensorsExecutor, |
@@ -19,8 +19,12 @@ | |||
*/ | |||
package org.sonar.batch.report; | |||
import org.sonar.batch.scan.ProjectAnalysisMode; | |||
import org.sonar.batch.util.BatchUtils; | |||
import com.github.kevinsawicki.http.HttpRequest; | |||
import com.google.common.annotations.VisibleForTesting; | |||
import java.io.File; | |||
import java.io.FileOutputStream; | |||
import java.io.IOException; | |||
@@ -28,6 +32,7 @@ import java.net.MalformedURLException; | |||
import java.net.URISyntaxException; | |||
import java.net.URL; | |||
import java.util.Date; | |||
import org.apache.commons.io.FileUtils; | |||
import org.picocontainer.Startable; | |||
import org.slf4j.Logger; | |||
@@ -39,11 +44,9 @@ import org.sonar.api.config.Settings; | |||
import org.sonar.api.platform.Server; | |||
import org.sonar.api.utils.TempFolder; | |||
import org.sonar.api.utils.ZipUtils; | |||
import org.sonar.batch.bootstrap.DefaultAnalysisMode; | |||
import org.sonar.batch.bootstrap.ServerClient; | |||
import org.sonar.batch.protocol.output.BatchReportWriter; | |||
import org.sonar.batch.scan.ImmutableProjectReactor; | |||
import static java.lang.String.format; | |||
@BatchSide | |||
@@ -57,7 +60,7 @@ public class ReportPublisher implements Startable { | |||
private final Server server; | |||
private final Settings settings; | |||
private final ImmutableProjectReactor projectReactor; | |||
private final DefaultAnalysisMode analysisMode; | |||
private final ProjectAnalysisMode analysisMode; | |||
private final TempFolder temp; | |||
private ReportPublisherStep[] publishers; | |||
@@ -66,7 +69,7 @@ public class ReportPublisher implements Startable { | |||
private BatchReportWriter writer; | |||
public ReportPublisher(Settings settings, ServerClient serverClient, Server server, | |||
ImmutableProjectReactor projectReactor, DefaultAnalysisMode analysisMode, TempFolder temp, ReportPublisherStep[] publishers) { | |||
ImmutableProjectReactor projectReactor, ProjectAnalysisMode analysisMode, TempFolder temp, ReportPublisherStep[] publishers) { | |||
this.serverClient = serverClient; | |||
this.server = server; | |||
this.projectReactor = projectReactor; | |||
@@ -134,7 +137,7 @@ public class ReportPublisher implements Startable { | |||
void sendOrDumpReport(File report) { | |||
ProjectDefinition projectDefinition = projectReactor.getRoot(); | |||
String effectiveKey = projectDefinition.getKeyWithBranch(); | |||
String relativeUrl = "/api/computation/submit_report?projectKey=" + effectiveKey + "&projectName=" + ServerClient.encodeForUrl(projectDefinition.getName()); | |||
String relativeUrl = "/api/computation/submit_report?projectKey=" + effectiveKey + "&projectName=" + BatchUtils.encodeForUrl(projectDefinition.getName()); | |||
String dumpDirLocation = settings.getString(DUMP_REPORT_PROP_KEY); | |||
if (dumpDirLocation == null) { |
@@ -19,22 +19,23 @@ | |||
*/ | |||
package org.sonar.batch.repository; | |||
import org.sonar.batch.bootstrap.ServerClient; | |||
import org.sonar.batch.bootstrap.WSLoader; | |||
import org.sonar.batch.protocol.input.GlobalRepositories; | |||
public class DefaultGlobalRepositoriesLoader implements GlobalRepositoriesLoader { | |||
private static final String BATCH_GLOBAL_URL = "/batch/global"; | |||
private final ServerClient serverClient; | |||
private final WSLoader wsLoader; | |||
public DefaultGlobalRepositoriesLoader(ServerClient serverClient) { | |||
this.serverClient = serverClient; | |||
public DefaultGlobalRepositoriesLoader(WSLoader wsLoader) { | |||
this.wsLoader = wsLoader; | |||
} | |||
@Override | |||
public GlobalRepositories load() { | |||
return GlobalRepositories.fromJson(serverClient.request(BATCH_GLOBAL_URL)); | |||
return GlobalRepositories.fromJson(wsLoader.loadString(BATCH_GLOBAL_URL)); | |||
} | |||
} |
@@ -19,11 +19,13 @@ | |||
*/ | |||
package org.sonar.batch.repository; | |||
import org.sonar.batch.scan.ProjectAnalysisMode; | |||
import org.sonar.batch.util.BatchUtils; | |||
import org.sonar.batch.bootstrap.WSLoader; | |||
import org.slf4j.Logger; | |||
import org.slf4j.LoggerFactory; | |||
import org.sonar.api.batch.bootstrap.ProjectReactor; | |||
import org.sonar.batch.bootstrap.DefaultAnalysisMode; | |||
import org.sonar.batch.bootstrap.ServerClient; | |||
import org.sonar.batch.bootstrap.AnalysisProperties; | |||
import org.sonar.batch.protocol.input.ProjectRepositories; | |||
import org.sonar.batch.rule.ModuleQProfiles; | |||
@@ -34,25 +36,25 @@ public class DefaultProjectRepositoriesLoader implements ProjectRepositoriesLoad | |||
private static final String BATCH_PROJECT_URL = "/batch/project"; | |||
private final ServerClient serverClient; | |||
private final DefaultAnalysisMode analysisMode; | |||
private final WSLoader wsLoader; | |||
private final ProjectAnalysisMode analysisMode; | |||
public DefaultProjectRepositoriesLoader(ServerClient serverClient, DefaultAnalysisMode analysisMode) { | |||
this.serverClient = serverClient; | |||
public DefaultProjectRepositoriesLoader(WSLoader wsLoader, ProjectAnalysisMode analysisMode) { | |||
this.wsLoader = wsLoader; | |||
this.analysisMode = analysisMode; | |||
} | |||
@Override | |||
public ProjectRepositories load(ProjectReactor reactor, AnalysisProperties taskProperties) { | |||
String projectKey = reactor.getRoot().getKeyWithBranch(); | |||
String url = BATCH_PROJECT_URL + "?key=" + ServerClient.encodeForUrl(projectKey); | |||
String url = BATCH_PROJECT_URL + "?key=" + BatchUtils.encodeForUrl(projectKey); | |||
if (taskProperties.properties().containsKey(ModuleQProfiles.SONAR_PROFILE_PROP)) { | |||
LOG.warn("Ability to set quality profile from command line using '" + ModuleQProfiles.SONAR_PROFILE_PROP | |||
+ "' is deprecated and will be dropped in a future SonarQube version. Please configure quality profile used by your project on SonarQube server."); | |||
url += "&profile=" + ServerClient.encodeForUrl(taskProperties.properties().get(ModuleQProfiles.SONAR_PROFILE_PROP)); | |||
url += "&profile=" + BatchUtils.encodeForUrl(taskProperties.properties().get(ModuleQProfiles.SONAR_PROFILE_PROP)); | |||
} | |||
url += "&preview=" + analysisMode.isPreview(); | |||
return ProjectRepositories.fromJson(serverClient.request(url)); | |||
return ProjectRepositories.fromJson(wsLoader.loadString(url)); | |||
} | |||
} |
@@ -19,35 +19,32 @@ | |||
*/ | |||
package org.sonar.batch.repository; | |||
import org.sonar.batch.util.BatchUtils; | |||
import com.google.common.io.ByteSource; | |||
import org.sonar.batch.bootstrap.WSLoader; | |||
import com.google.common.base.Function; | |||
import com.google.common.io.InputSupplier; | |||
import org.sonar.batch.bootstrap.ServerClient; | |||
import org.sonar.batch.protocol.input.BatchInput.ServerIssue; | |||
import org.sonar.api.utils.HttpDownloader; | |||
import java.io.IOException; | |||
import java.io.InputStream; | |||
public class DefaultServerIssuesLoader implements ServerIssuesLoader { | |||
private final ServerClient serverClient; | |||
private final WSLoader wsLoader; | |||
public DefaultServerIssuesLoader(ServerClient serverClient) { | |||
this.serverClient = serverClient; | |||
public DefaultServerIssuesLoader(WSLoader wsLoader) { | |||
this.wsLoader = wsLoader; | |||
} | |||
@Override | |||
public void load(String componentKey, Function<ServerIssue, Void> consumer, boolean incremental) { | |||
try { | |||
InputSupplier<InputStream> request = serverClient.doRequest("/batch/issues?key=" + ServerClient.encodeForUrl(componentKey), "GET", null); | |||
parseIssues(request, consumer); | |||
} catch (HttpDownloader.HttpException e) { | |||
throw serverClient.handleHttpException(e); | |||
} | |||
ByteSource request = wsLoader.loadSource("/batch/issues?key=" + BatchUtils.encodeForUrl(componentKey)); | |||
parseIssues(request, consumer); | |||
} | |||
private static void parseIssues(InputSupplier<InputStream> input, Function<ServerIssue, Void> consumer) { | |||
try (InputStream is = input.getInput()) { | |||
private static void parseIssues(ByteSource input, Function<ServerIssue, Void> consumer) { | |||
try (InputStream is = input.openStream()) { | |||
ServerIssue previousIssue = ServerIssue.parseDelimitedFrom(is); | |||
while (previousIssue != null) { | |||
consumer.apply(previousIssue); |
@@ -19,12 +19,13 @@ | |||
*/ | |||
package org.sonar.batch.repository.user; | |||
import org.sonar.batch.util.BatchUtils; | |||
import org.sonar.batch.bootstrap.WSLoader; | |||
import com.google.common.io.ByteSource; | |||
import com.google.common.base.Function; | |||
import com.google.common.base.Joiner; | |||
import com.google.common.collect.Lists; | |||
import com.google.common.io.InputSupplier; | |||
import org.sonar.api.utils.HttpDownloader; | |||
import org.sonar.batch.bootstrap.ServerClient; | |||
import org.sonar.batch.protocol.input.BatchInput; | |||
import java.io.IOException; | |||
@@ -36,10 +37,10 @@ import java.util.List; | |||
public class UserRepository { | |||
private ServerClient serverClient; | |||
private WSLoader wsLoader; | |||
public UserRepository(ServerClient serverClient) { | |||
this.serverClient = serverClient; | |||
public UserRepository(WSLoader wsLoader) { | |||
this.wsLoader = wsLoader; | |||
} | |||
public Collection<BatchInput.User> loadFromWs(List<String> userLogins) { | |||
@@ -47,25 +48,20 @@ public class UserRepository { | |||
return Collections.emptyList(); | |||
} | |||
try { | |||
InputSupplier<InputStream> request = serverClient.doRequest("/batch/users?logins=" + Joiner.on(',').join(Lists.transform(userLogins, new Function<String, String>() { | |||
@Override | |||
public String apply(String input) { | |||
return ServerClient.encodeForUrl(input); | |||
} | |||
})), "GET", null); | |||
return parseUsers(request); | |||
ByteSource source = wsLoader.loadSource("/batch/users?logins=" + Joiner.on(',').join(Lists.transform(userLogins, new Function<String, String>() { | |||
@Override | |||
public String apply(String input) { | |||
return BatchUtils.encodeForUrl(input); | |||
} | |||
}))); | |||
} catch (HttpDownloader.HttpException e) { | |||
throw serverClient.handleHttpException(e); | |||
} | |||
return parseUsers(source); | |||
} | |||
private static Collection<BatchInput.User> parseUsers(InputSupplier<InputStream> input) { | |||
private static Collection<BatchInput.User> parseUsers(ByteSource input) { | |||
List<BatchInput.User> users = new ArrayList<>(); | |||
try (InputStream is = input.getInput()) { | |||
try (InputStream is = input.openStream()) { | |||
BatchInput.User user = BatchInput.User.parseDelimitedFrom(is); | |||
while (user != null) { | |||
users.add(user); |
@@ -20,12 +20,13 @@ | |||
package org.sonar.batch.scan; | |||
import com.google.common.collect.Lists; | |||
import java.util.List; | |||
import org.sonar.api.CoreProperties; | |||
import org.sonar.api.batch.bootstrap.ProjectDefinition; | |||
import org.sonar.api.config.Settings; | |||
import org.sonar.api.utils.MessageException; | |||
import org.sonar.batch.bootstrap.DefaultAnalysisMode; | |||
import org.sonar.batch.bootstrap.GlobalSettings; | |||
import org.sonar.batch.protocol.input.ProjectRepositories; | |||
@@ -35,10 +36,10 @@ import org.sonar.batch.protocol.input.ProjectRepositories; | |||
public class ModuleSettings extends Settings { | |||
private final ProjectRepositories projectReferentials; | |||
private DefaultAnalysisMode analysisMode; | |||
private ProjectAnalysisMode analysisMode; | |||
public ModuleSettings(GlobalSettings batchSettings, ProjectDefinition moduleDefinition, ProjectRepositories projectReferentials, | |||
DefaultAnalysisMode analysisMode) { | |||
ProjectAnalysisMode analysisMode) { | |||
super(batchSettings.getDefinitions()); | |||
this.projectReferentials = projectReferentials; | |||
this.analysisMode = analysisMode; |
@@ -17,7 +17,9 @@ | |||
* along with this program; if not, write to the Free Software Foundation, | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
package org.sonar.batch.bootstrap; | |||
package org.sonar.batch.scan; | |||
import org.sonar.batch.bootstrap.AnalysisProperties; | |||
import org.slf4j.Logger; | |||
import org.slf4j.LoggerFactory; | |||
@@ -31,21 +33,27 @@ import java.util.Map; | |||
/** | |||
* @since 4.0 | |||
*/ | |||
public class DefaultAnalysisMode implements AnalysisMode { | |||
public class ProjectAnalysisMode implements AnalysisMode { | |||
private static final Logger LOG = LoggerFactory.getLogger(DefaultAnalysisMode.class); | |||
private static final Logger LOG = LoggerFactory.getLogger(ProjectAnalysisMode.class); | |||
private boolean preview; | |||
private boolean incremental; | |||
private boolean quick; | |||
private boolean mediumTestMode; | |||
public DefaultAnalysisMode(Map<String, String> props) { | |||
init(props); | |||
public ProjectAnalysisMode(AnalysisProperties props) { | |||
init(props.properties()); | |||
} | |||
@Override | |||
public boolean isPreview() { | |||
return preview || incremental; | |||
return preview || incremental || quick; | |||
} | |||
@Override | |||
public boolean isQuick() { | |||
return quick; | |||
} | |||
@Override | |||
@@ -66,20 +74,19 @@ public class DefaultAnalysisMode implements AnalysisMode { | |||
String mode = props.get(CoreProperties.ANALYSIS_MODE); | |||
preview = CoreProperties.ANALYSIS_MODE_PREVIEW.equals(mode); | |||
incremental = CoreProperties.ANALYSIS_MODE_INCREMENTAL.equals(mode); | |||
quick = CoreProperties.ANALYSIS_MODE_QUICK.equals(mode); | |||
} | |||
mediumTestMode = "true".equals(props.get(BatchMediumTester.MEDIUM_TEST_ENABLED)); | |||
if (incremental) { | |||
LOG.info("Incremental mode"); | |||
} else if (preview) { | |||
LOG.info("Preview mode"); | |||
} else if (quick) { | |||
LOG.info("Quick mode"); | |||
} | |||
if (mediumTestMode) { | |||
LOG.info("Medium test mode"); | |||
} | |||
// To stay compatible with plugins that use the old property to check mode | |||
if (incremental || preview) { | |||
props.put(CoreProperties.DRY_RUN, "true"); | |||
} | |||
} | |||
} |
@@ -34,7 +34,6 @@ import org.sonar.batch.DefaultFileLinesContextFactory; | |||
import org.sonar.batch.DefaultProjectTree; | |||
import org.sonar.batch.ProjectConfigurator; | |||
import org.sonar.batch.bootstrap.AnalysisProperties; | |||
import org.sonar.batch.bootstrap.DefaultAnalysisMode; | |||
import org.sonar.batch.bootstrap.ExtensionInstaller; | |||
import org.sonar.batch.bootstrap.ExtensionMatcher; | |||
import org.sonar.batch.bootstrap.ExtensionUtils; | |||
@@ -83,7 +82,6 @@ public class ProjectScanContainer extends ComponentContainer { | |||
private static final Logger LOG = Loggers.get(ProjectScanContainer.class); | |||
private final DefaultAnalysisMode analysisMode; | |||
private final Object[] components; | |||
private final AnalysisProperties props; | |||
@@ -91,7 +89,6 @@ public class ProjectScanContainer extends ComponentContainer { | |||
super(globalContainer); | |||
this.props = props; | |||
this.components = components; | |||
analysisMode = globalContainer.getComponentByType(DefaultAnalysisMode.class); | |||
} | |||
@Override | |||
@@ -123,6 +120,7 @@ public class ProjectScanContainer extends ComponentContainer { | |||
private void addBatchComponents() { | |||
add( | |||
props, | |||
ProjectAnalysisMode.class, | |||
projectReactorBuilder(), | |||
new MutableProjectReactorProvider(getComponentByType(ProjectBootstrapper.class)), | |||
new ImmutableProjectReactorProvider(), | |||
@@ -134,6 +132,7 @@ public class ProjectScanContainer extends ComponentContainer { | |||
ProjectExclusions.class, | |||
ProjectReactorValidator.class, | |||
new ProjectRepositoriesProvider(), | |||
new WSLoaderProjectProvider(), | |||
DefaultResourceCreationLock.class, | |||
CodeColorizers.class, | |||
MetricProvider.class, | |||
@@ -206,7 +205,7 @@ public class ProjectScanContainer extends ComponentContainer { | |||
LOG.debug("Start recursive analysis of project modules"); | |||
DefaultProjectTree tree = getComponentByType(DefaultProjectTree.class); | |||
scanRecursively(tree.getRootProject()); | |||
if (analysisMode.isMediumTest()) { | |||
if (getComponentByType(ProjectAnalysisMode.class).isMediumTest()) { | |||
getComponentByType(ScanTaskObservers.class).notifyEndOfScanTask(); | |||
} | |||
} |
@@ -20,13 +20,14 @@ | |||
package org.sonar.batch.scan; | |||
import com.google.common.collect.ImmutableMap; | |||
import java.util.Map; | |||
import org.sonar.api.CoreProperties; | |||
import org.sonar.api.batch.bootstrap.ProjectReactor; | |||
import org.sonar.api.config.PropertyDefinitions; | |||
import org.sonar.api.config.Settings; | |||
import org.sonar.api.utils.MessageException; | |||
import org.sonar.batch.bootstrap.DefaultAnalysisMode; | |||
import org.sonar.batch.bootstrap.DroppedPropertyChecker; | |||
import org.sonar.batch.bootstrap.GlobalSettings; | |||
import org.sonar.batch.protocol.input.ProjectRepositories; | |||
@@ -43,10 +44,10 @@ public class ProjectSettings extends Settings { | |||
private final GlobalSettings globalSettings; | |||
private final ProjectRepositories projectRepositories; | |||
private final DefaultAnalysisMode mode; | |||
private final ProjectAnalysisMode mode; | |||
public ProjectSettings(ProjectReactor reactor, GlobalSettings globalSettings, PropertyDefinitions propertyDefinitions, | |||
ProjectRepositories projectRepositories, DefaultAnalysisMode mode) { | |||
ProjectRepositories projectRepositories, ProjectAnalysisMode mode) { | |||
super(propertyDefinitions); | |||
this.mode = mode; | |||
getEncryption().setPathToSecretKey(globalSettings.getString(CoreProperties.ENCRYPTION_SECRET_KEY_PATH)); |
@@ -0,0 +1,57 @@ | |||
/* | |||
* SonarQube, open source software quality management tool. | |||
* Copyright (C) 2008-2014 SonarSource | |||
* mailto:contact AT sonarsource DOT com | |||
* | |||
* SonarQube is free software; you can redistribute it and/or | |||
* modify it under the terms of the GNU Lesser General Public | |||
* License as published by the Free Software Foundation; either | |||
* version 3 of the License, or (at your option) any later version. | |||
* | |||
* SonarQube is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||
* Lesser General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU Lesser General Public License | |||
* along with this program; if not, write to the Free Software Foundation, | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
package org.sonar.batch.scan; | |||
import org.picocontainer.injectors.ProviderAdapter; | |||
import java.util.Map; | |||
import org.sonar.batch.bootstrap.AnalysisProperties; | |||
import org.sonar.batch.bootstrap.ServerClient; | |||
import org.sonar.batch.bootstrap.WSLoader; | |||
import org.sonar.home.cache.PersistentCache; | |||
import org.sonar.api.batch.AnalysisMode; | |||
import org.sonar.batch.bootstrap.WSLoader.LoadStrategy; | |||
public class WSLoaderProjectProvider extends ProviderAdapter { | |||
private WSLoader wsLoader; | |||
public WSLoader provide(AnalysisProperties props, AnalysisMode mode, PersistentCache cache, ServerClient client) { | |||
if (wsLoader == null) { | |||
cache.reconfigure(); | |||
wsLoader = new WSLoader(isCacheEnabled(props.properties(), mode.isPreview()), cache, client); | |||
wsLoader.setStrategy(getStrategy(mode)); | |||
} | |||
return wsLoader; | |||
} | |||
private static LoadStrategy getStrategy(AnalysisMode mode) { | |||
if (mode.isQuick()) { | |||
return LoadStrategy.CACHE_FIRST; | |||
} | |||
return LoadStrategy.SERVER_FIRST; | |||
} | |||
private static boolean isCacheEnabled(Map<String, String> props, boolean isPreview) { | |||
String enableOffline = props.get("sonar.enableOffline"); | |||
return isPreview && "true".equals(enableOffline); | |||
} | |||
} |
@@ -19,6 +19,8 @@ | |||
*/ | |||
package org.sonar.batch.scan.filesystem; | |||
import org.sonar.batch.scan.ProjectAnalysisMode; | |||
import org.slf4j.Logger; | |||
import org.slf4j.LoggerFactory; | |||
import org.sonar.api.CoreProperties; | |||
@@ -28,7 +30,6 @@ import org.sonar.api.batch.fs.internal.DefaultInputFile; | |||
import org.sonar.api.batch.fs.internal.FileMetadata; | |||
import org.sonar.api.config.Settings; | |||
import org.sonar.api.scan.filesystem.PathResolver; | |||
import org.sonar.batch.bootstrap.DefaultAnalysisMode; | |||
import javax.annotation.CheckForNull; | |||
@@ -43,12 +44,12 @@ class InputFileBuilder { | |||
private final LanguageDetection langDetection; | |||
private final StatusDetection statusDetection; | |||
private final DefaultModuleFileSystem fs; | |||
private final DefaultAnalysisMode analysisMode; | |||
private final ProjectAnalysisMode analysisMode; | |||
private final Settings settings; | |||
private final FileMetadata fileMetadata; | |||
InputFileBuilder(String moduleKey, PathResolver pathResolver, LanguageDetection langDetection, | |||
StatusDetection statusDetection, DefaultModuleFileSystem fs, DefaultAnalysisMode analysisMode, Settings settings, FileMetadata fileMetadata) { | |||
StatusDetection statusDetection, DefaultModuleFileSystem fs, ProjectAnalysisMode analysisMode, Settings settings, FileMetadata fileMetadata) { | |||
this.moduleKey = moduleKey; | |||
this.pathResolver = pathResolver; | |||
this.langDetection = langDetection; |
@@ -19,12 +19,13 @@ | |||
*/ | |||
package org.sonar.batch.scan.filesystem; | |||
import org.sonar.batch.scan.ProjectAnalysisMode; | |||
import org.sonar.api.batch.BatchSide; | |||
import org.sonar.api.batch.bootstrap.ProjectDefinition; | |||
import org.sonar.api.batch.fs.internal.FileMetadata; | |||
import org.sonar.api.config.Settings; | |||
import org.sonar.api.scan.filesystem.PathResolver; | |||
import org.sonar.batch.bootstrap.DefaultAnalysisMode; | |||
@BatchSide | |||
public class InputFileBuilderFactory { | |||
@@ -33,12 +34,12 @@ public class InputFileBuilderFactory { | |||
private final PathResolver pathResolver; | |||
private final LanguageDetectionFactory langDetectionFactory; | |||
private final StatusDetectionFactory statusDetectionFactory; | |||
private final DefaultAnalysisMode analysisMode; | |||
private final ProjectAnalysisMode analysisMode; | |||
private final Settings settings; | |||
private final FileMetadata fileMetadata; | |||
public InputFileBuilderFactory(ProjectDefinition def, PathResolver pathResolver, LanguageDetectionFactory langDetectionFactory, | |||
StatusDetectionFactory statusDetectionFactory, DefaultAnalysisMode analysisMode, Settings settings, FileMetadata fileMetadata) { | |||
StatusDetectionFactory statusDetectionFactory, ProjectAnalysisMode analysisMode, Settings settings, FileMetadata fileMetadata) { | |||
this.fileMetadata = fileMetadata; | |||
this.moduleKey = def.getKeyWithBranch(); | |||
this.pathResolver = pathResolver; |
@@ -19,16 +19,17 @@ | |||
*/ | |||
package org.sonar.batch.scan.report; | |||
import org.sonar.batch.scan.ProjectAnalysisMode; | |||
import org.sonar.api.batch.BatchSide; | |||
import org.sonar.batch.bootstrap.DefaultAnalysisMode; | |||
@BatchSide | |||
public class IssuesReports { | |||
private final DefaultAnalysisMode analysisMode; | |||
private final ProjectAnalysisMode analysisMode; | |||
private final Reporter[] reporters; | |||
public IssuesReports(DefaultAnalysisMode analysisMode, Reporter... reporters) { | |||
public IssuesReports(ProjectAnalysisMode analysisMode, Reporter... reporters) { | |||
this.reporters = reporters; | |||
this.analysisMode = analysisMode; | |||
} |
@@ -19,6 +19,9 @@ | |||
*/ | |||
package org.sonar.batch.util; | |||
import java.io.UnsupportedEncodingException; | |||
import java.net.URLEncoder; | |||
import org.apache.commons.lang.StringUtils; | |||
public class BatchUtils { | |||
@@ -34,4 +37,13 @@ public class BatchUtils { | |||
String cleanKey = StringUtils.deleteWhitespace(projectKey); | |||
return StringUtils.replace(cleanKey, ":", "_"); | |||
} | |||
public static String encodeForUrl(String url) { | |||
try { | |||
return URLEncoder.encode(url, "UTF-8"); | |||
} catch (UnsupportedEncodingException e) { | |||
throw new IllegalStateException("Encoding not supported", e); | |||
} | |||
} | |||
} |
@@ -50,9 +50,10 @@ public class BatchPluginInstallerTest { | |||
@Test | |||
public void listRemotePlugins() { | |||
ServerClient server = mock(ServerClient.class); | |||
when(server.request("/deploy/plugins/index.txt")).thenReturn("checkstyle\nsqale"); | |||
BatchPluginInstaller installer = new BatchPluginInstaller(server, fileCache, pluginPredicate); | |||
WSLoader wsLoader = mock(WSLoader.class); | |||
when(wsLoader.load("/deploy/plugins/index.txt")).thenReturn("checkstyle\nsqale".getBytes()); | |||
when(wsLoader.loadString("/deploy/plugins/index.txt")).thenReturn("checkstyle\nsqale"); | |||
BatchPluginInstaller installer = new BatchPluginInstaller(wsLoader, fileCache, pluginPredicate); | |||
List<RemotePlugin> remotePlugins = installer.listRemotePlugins(); | |||
assertThat(remotePlugins).extracting("key").containsOnly("checkstyle", "sqale"); | |||
@@ -63,8 +64,8 @@ public class BatchPluginInstallerTest { | |||
File pluginJar = temp.newFile(); | |||
when(fileCache.get(eq("checkstyle-plugin.jar"), eq("fakemd5_1"), any(FileCache.Downloader.class))).thenReturn(pluginJar); | |||
ServerClient server = mock(ServerClient.class); | |||
BatchPluginInstaller installer = new BatchPluginInstaller(server, fileCache, pluginPredicate); | |||
WSLoader wsLoader = mock(WSLoader.class); | |||
BatchPluginInstaller installer = new BatchPluginInstaller(wsLoader, fileCache, pluginPredicate); | |||
RemotePlugin remote = new RemotePlugin("checkstyle").setFile("checkstyle-plugin.jar", "fakemd5_1"); | |||
File file = installer.download(remote); | |||
@@ -76,9 +77,9 @@ public class BatchPluginInstallerTest { | |||
public void should_fail_to_get_plugin_index() { | |||
thrown.expect(IllegalStateException.class); | |||
ServerClient server = mock(ServerClient.class); | |||
doThrow(new IllegalStateException()).when(server).request("/deploy/plugins/index.txt"); | |||
WSLoader wsLoader = mock(WSLoader.class); | |||
doThrow(new IllegalStateException()).when(wsLoader).load("/deploy/plugins/index.txt"); | |||
new BatchPluginInstaller(server, fileCache, pluginPredicate).installRemotes(); | |||
new BatchPluginInstaller(wsLoader, fileCache, pluginPredicate).installRemotes(); | |||
} | |||
} |
@@ -22,7 +22,6 @@ package org.sonar.batch.bootstrap; | |||
import org.junit.Test; | |||
import org.sonar.api.CoreProperties; | |||
import org.sonar.api.config.Settings; | |||
import static org.assertj.core.api.Assertions.assertThat; | |||
import static org.mockito.Mockito.mock; | |||
import static org.mockito.Mockito.when; | |||
@@ -30,7 +29,7 @@ import static org.mockito.Mockito.when; | |||
public class BatchPluginPredicateTest { | |||
Settings settings = new Settings(); | |||
DefaultAnalysisMode mode = mock(DefaultAnalysisMode.class); | |||
GlobalMode mode = mock(GlobalMode.class); | |||
@Test | |||
public void accept_if_no_inclusions_nor_exclusions() { |
@@ -40,7 +40,7 @@ import static org.mockito.Mockito.when; | |||
public class ExtensionInstallerTest { | |||
DefaultAnalysisMode mode; | |||
GlobalMode mode; | |||
BatchPluginRepository pluginRepository = mock(BatchPluginRepository.class); | |||
private static Plugin newPluginInstance(final Object... extensions) { | |||
@@ -53,7 +53,7 @@ public class ExtensionInstallerTest { | |||
@Before | |||
public void setUp() { | |||
mode = mock(DefaultAnalysisMode.class); | |||
mode = mock(GlobalMode.class); | |||
} | |||
@Test |
@@ -0,0 +1,67 @@ | |||
/* | |||
* SonarQube, open source software quality management tool. | |||
* Copyright (C) 2008-2014 SonarSource | |||
* mailto:contact AT sonarsource DOT com | |||
* | |||
* SonarQube is free software; you can redistribute it and/or | |||
* modify it under the terms of the GNU Lesser General Public | |||
* License as published by the Free Software Foundation; either | |||
* version 3 of the License, or (at your option) any later version. | |||
* | |||
* SonarQube is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||
* Lesser General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU Lesser General Public License | |||
* along with this program; if not, write to the Free Software Foundation, | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
package org.sonar.batch.bootstrap; | |||
import org.sonar.api.CoreProperties; | |||
import org.junit.Test; | |||
import java.util.HashMap; | |||
import java.util.Map; | |||
import static org.assertj.core.api.Assertions.assertThat; | |||
public class GlobalModeTest { | |||
@Test | |||
public void testQuick() { | |||
GlobalMode mode = createMode(CoreProperties.ANALYSIS_MODE, CoreProperties.ANALYSIS_MODE_QUICK); | |||
assertThat(mode.isPreview()).isTrue(); | |||
} | |||
@Test | |||
public void testPreview() { | |||
GlobalMode mode = createMode(CoreProperties.ANALYSIS_MODE, CoreProperties.ANALYSIS_MODE_PREVIEW); | |||
assertThat(mode.isPreview()).isTrue(); | |||
} | |||
@Test | |||
public void testIncremental() { | |||
GlobalMode mode = createMode(CoreProperties.ANALYSIS_MODE, CoreProperties.ANALYSIS_MODE_INCREMENTAL); | |||
assertThat(mode.isPreview()).isTrue(); | |||
} | |||
@Test | |||
public void testOtherProperty() { | |||
GlobalMode mode = createMode(CoreProperties.ANALYSIS_MODE, CoreProperties.ANALYSIS_MODE_ANALYSIS); | |||
assertThat(mode.isPreview()).isFalse(); | |||
} | |||
@Test | |||
public void testDeprecatedDryRun() { | |||
GlobalMode mode = createMode(CoreProperties.DRY_RUN, "true"); | |||
assertThat(mode.isPreview()).isTrue(); | |||
} | |||
private GlobalMode createMode(String key, String value) { | |||
Map<String, String> map = new HashMap<>(); | |||
map.put(key, value); | |||
BootstrapProperties props = new BootstrapProperties(map); | |||
return new GlobalMode(props); | |||
} | |||
} |
@@ -19,7 +19,11 @@ | |||
*/ | |||
package org.sonar.batch.bootstrap; | |||
import org.sonar.api.CoreProperties; | |||
import java.util.Collections; | |||
import static org.mockito.Mockito.when; | |||
import org.junit.Before; | |||
import org.junit.Rule; | |||
import org.junit.Test; | |||
@@ -28,7 +32,6 @@ import org.sonar.api.config.PropertyDefinitions; | |||
import org.sonar.api.utils.log.LogTester; | |||
import org.sonar.api.utils.log.LoggerLevel; | |||
import org.sonar.batch.protocol.input.GlobalRepositories; | |||
import static org.assertj.core.api.Assertions.assertThat; | |||
import static org.mockito.Mockito.mock; | |||
@@ -43,13 +46,13 @@ public class GlobalSettingsTest { | |||
GlobalRepositories globalRef; | |||
BootstrapProperties bootstrapProps; | |||
private DefaultAnalysisMode mode; | |||
private GlobalMode mode; | |||
@Before | |||
public void prepare() { | |||
globalRef = new GlobalRepositories(); | |||
bootstrapProps = new BootstrapProperties(Collections.<String, String>emptyMap()); | |||
mode = mock(DefaultAnalysisMode.class); | |||
mode = mock(GlobalMode.class); | |||
} | |||
@Test | |||
@@ -60,6 +63,13 @@ public class GlobalSettingsTest { | |||
assertThat(batchSettings.getBoolean("sonar.cpd.cross")).isTrue(); | |||
} | |||
@Test | |||
public void support_deprecated_dry_run() { | |||
when(mode.isPreview()).thenReturn(true); | |||
GlobalSettings batchSettings = new GlobalSettings(bootstrapProps, new PropertyDefinitions(), globalRef, mode); | |||
assertThat(batchSettings.getString(CoreProperties.DRY_RUN)).isEqualTo("true"); | |||
} | |||
@Test | |||
public void should_log_warn_msg_for_each_jdbc_property_if_present() { |
@@ -0,0 +1,118 @@ | |||
/* | |||
* SonarQube, open source software quality management tool. | |||
* Copyright (C) 2008-2014 SonarSource | |||
* mailto:contact AT sonarsource DOT com | |||
* | |||
* SonarQube is free software; you can redistribute it and/or | |||
* modify it under the terms of the GNU Lesser General Public | |||
* License as published by the Free Software Foundation; either | |||
* version 3 of the License, or (at your option) any later version. | |||
* | |||
* SonarQube is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||
* Lesser General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU Lesser General Public License | |||
* along with this program; if not, write to the Free Software Foundation, | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
package org.sonar.batch.bootstrap; | |||
import org.apache.commons.io.IOUtils; | |||
import org.eclipse.jetty.server.Handler; | |||
import org.eclipse.jetty.server.Request; | |||
import org.eclipse.jetty.server.Server; | |||
import org.eclipse.jetty.server.handler.AbstractHandler; | |||
import javax.servlet.ServletException; | |||
import javax.servlet.http.HttpServletRequest; | |||
import javax.servlet.http.HttpServletResponse; | |||
import java.io.IOException; | |||
import static javax.servlet.http.HttpServletResponse.SC_OK; | |||
import static org.apache.commons.io.IOUtils.write; | |||
public class MockHttpServer { | |||
private Server server; | |||
private String responseBody; | |||
private String requestBody; | |||
private String mockResponseData; | |||
private int mockResponseStatus = SC_OK; | |||
private int numRequests = 0; | |||
public void start() throws Exception { | |||
server = new Server(0); | |||
server.setHandler(getMockHandler()); | |||
server.start(); | |||
} | |||
public int getNumberRequests() { | |||
return numRequests; | |||
} | |||
/** | |||
* Creates an {@link org.mortbay.jetty.handler.AbstractHandler handler} returning an arbitrary String as a response. | |||
* | |||
* @return never <code>null</code>. | |||
*/ | |||
public Handler getMockHandler() { | |||
Handler handler = new AbstractHandler() { | |||
public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { | |||
numRequests++; | |||
setResponseBody(getMockResponseData()); | |||
setRequestBody(IOUtils.toString(baseRequest.getInputStream())); | |||
response.setStatus(mockResponseStatus); | |||
response.setContentType("text/xml;charset=utf-8"); | |||
write(getResponseBody(), response.getOutputStream()); | |||
baseRequest.setHandled(true); | |||
} | |||
}; | |||
return handler; | |||
} | |||
public void stop() { | |||
try { | |||
if (server != null) { | |||
server.stop(); | |||
} | |||
} catch (Exception e) { | |||
throw new IllegalStateException("Fail to stop HTTP server", e); | |||
} | |||
} | |||
public String getResponseBody() { | |||
return responseBody; | |||
} | |||
public void setResponseBody(String responseBody) { | |||
this.responseBody = responseBody; | |||
} | |||
public String getRequestBody() { | |||
return requestBody; | |||
} | |||
public void setRequestBody(String requestBody) { | |||
this.requestBody = requestBody; | |||
} | |||
public void setMockResponseStatus(int status) { | |||
this.mockResponseStatus = status; | |||
} | |||
public String getMockResponseData() { | |||
return mockResponseData; | |||
} | |||
public void setMockResponseData(String mockResponseData) { | |||
this.mockResponseData = mockResponseData; | |||
} | |||
public int getPort() { | |||
return server.getConnectors()[0].getLocalPort(); | |||
} | |||
} |
@@ -45,19 +45,4 @@ public class PersistentCacheProviderTest { | |||
public void test_cache_dir() { | |||
assertThat(provider.provide(props).getBaseDirectory().toFile()).exists().isDirectory(); | |||
} | |||
@Test | |||
public void test_enableCache() { | |||
// normally force update (cache disabled) | |||
assertThat(provider.provide(props).isForceUpdate()).isTrue(); | |||
props.properties().put("sonar.enableHttpCache", "true"); | |||
provider = new PersistentCacheProvider(); | |||
assertThat(provider.provide(props).isForceUpdate()).isFalse(); | |||
} | |||
@Test | |||
public void test_reconfigure() { | |||
} | |||
} |
@@ -19,30 +19,18 @@ | |||
*/ | |||
package org.sonar.batch.bootstrap; | |||
import org.sonar.batch.util.BatchUtils; | |||
import java.io.File; | |||
import java.io.IOException; | |||
import java.nio.charset.StandardCharsets; | |||
import java.nio.file.Files; | |||
import javax.servlet.ServletException; | |||
import javax.servlet.http.HttpServletRequest; | |||
import javax.servlet.http.HttpServletResponse; | |||
import org.apache.commons.io.IOUtils; | |||
import org.eclipse.jetty.server.Handler; | |||
import org.eclipse.jetty.server.Request; | |||
import org.eclipse.jetty.server.Server; | |||
import org.eclipse.jetty.server.handler.AbstractHandler; | |||
import org.junit.After; | |||
import org.junit.Before; | |||
import org.junit.Rule; | |||
import org.junit.Test; | |||
import org.junit.rules.ExpectedException; | |||
import org.junit.rules.TemporaryFolder; | |||
import org.sonar.batch.bootstrapper.EnvironmentInformation; | |||
import org.sonar.home.cache.PersistentCache; | |||
import org.sonar.home.cache.PersistentCacheBuilder; | |||
import static javax.servlet.http.HttpServletResponse.SC_OK; | |||
import static org.apache.commons.io.IOUtils.write; | |||
import static org.assertj.core.api.Assertions.assertThat; | |||
import static org.mockito.Matchers.eq; | |||
import static org.mockito.Mockito.mock; | |||
@@ -53,19 +41,10 @@ public class ServerClientTest { | |||
@Rule | |||
public TemporaryFolder temp = new TemporaryFolder(); | |||
@Rule | |||
public TemporaryFolder cacheTmp = new TemporaryFolder(); | |||
@Rule | |||
public ExpectedException thrown = ExpectedException.none(); | |||
private MockHttpServer server = null; | |||
private BootstrapProperties bootstrapProps = mock(BootstrapProperties.class); | |||
private DefaultAnalysisMode mode = null; | |||
@Before | |||
public void setUp() { | |||
mode = mock(DefaultAnalysisMode.class); | |||
when(mode.isPreview()).thenReturn(true); | |||
} | |||
@After | |||
public void stopServer() { | |||
@@ -74,78 +53,30 @@ public class ServerClientTest { | |||
} | |||
} | |||
@Test | |||
public void dont_cache_post_request() throws Exception { | |||
server = new MockHttpServer(); | |||
server.start(); | |||
server.setMockResponseData("this is the content"); | |||
assertThat(newServerClient().request("/foo", "POST")).isEqualTo("this is the content"); | |||
// cache never accessed, so not even the .lock should be there | |||
assertThat(getNumFilesInCache()).isEqualTo(0); | |||
} | |||
@Test | |||
public void dont_cache_non_preview_mode() throws Exception { | |||
server = new MockHttpServer(); | |||
server.start(); | |||
server.setMockResponseData("this is the content"); | |||
when(mode.isPreview()).thenReturn(false); | |||
assertThat(newServerClient().request("/foo")).isEqualTo("this is the content"); | |||
// cache never accessed, so not even the .lock should be there | |||
assertThat(getNumFilesInCache()).isEqualTo(0); | |||
} | |||
@Test | |||
public void cache_preview_mode() throws Exception { | |||
server = new MockHttpServer(); | |||
server.start(); | |||
server.setMockResponseData("this is the content"); | |||
assertThat(newServerClient().request("/foo")).isEqualTo("this is the content"); | |||
// should have the .lock and one request cached | |||
assertThat(getNumFilesInCache()).isEqualTo(2); | |||
} | |||
@Test | |||
public void should_remove_url_ending_slash() { | |||
BootstrapProperties settings = mock(BootstrapProperties.class); | |||
when(settings.property("sonar.host.url")).thenReturn("http://localhost:8080/sonar/"); | |||
PersistentCache ps = new PersistentCacheBuilder(new Slf4jLogger()).setSonarHome(cacheTmp.getRoot().toPath()).build(); | |||
ServerClient client = new ServerClient(settings, new EnvironmentInformation("Junit", "4"), ps, mode); | |||
ServerClient client = new ServerClient(settings, new EnvironmentInformation("Junit", "4")); | |||
assertThat(client.getURL()).isEqualTo("http://localhost:8080/sonar"); | |||
} | |||
@Test | |||
public void should_request_url() throws Exception { | |||
server = new MockHttpServer(); | |||
server.start(); | |||
server.setMockResponseData("this is the content"); | |||
assertThat(newServerClient().request("/foo")).isEqualTo("this is the content"); | |||
startServer(null, "this is the content"); | |||
assertThat(newServerClient().downloadString("/foo")).isEqualTo("this is the content"); | |||
} | |||
@Test | |||
public void should_escape_html_from_url() throws Exception { | |||
server = new MockHttpServer(); | |||
server.start(); | |||
server.setMockResponseData("this is the content"); | |||
assertThat(newServerClient().request("/<foo>")).isEqualTo("this is the content"); | |||
startServer(null, "this is the content"); | |||
assertThat(newServerClient().downloadString("/<foo>")).isEqualTo("this is the content"); | |||
} | |||
@Test | |||
public void should_download_file() throws Exception { | |||
server = new MockHttpServer(); | |||
server.start(); | |||
server.setMockResponseData("this is the content"); | |||
startServer(null, "this is the content"); | |||
File file = temp.newFile(); | |||
newServerClient().download("/foo", file); | |||
assertThat(new String(Files.readAllBytes(file.toPath()), StandardCharsets.UTF_8)).isEqualTo("this is the content"); | |||
@@ -153,138 +84,55 @@ public class ServerClientTest { | |||
@Test | |||
public void should_fail_if_unauthorized_with_no_login_password() throws Exception { | |||
server = new MockHttpServer(); | |||
server.start(); | |||
server.setMockResponseStatus(401); | |||
startServer(401, null); | |||
thrown.expectMessage("Not authorized. Analyzing this project requires to be authenticated. Please provide the values of the properties sonar.login and sonar.password."); | |||
newServerClient().request("/foo"); | |||
newServerClient().downloadString("/foo"); | |||
} | |||
@Test | |||
public void should_fail_if_unauthorized_with_login_password_provided() throws Exception { | |||
server = new MockHttpServer(); | |||
server.start(); | |||
server.setMockResponseStatus(401); | |||
startServer(401, null); | |||
when(bootstrapProps.property(eq("sonar.login"))).thenReturn("login"); | |||
when(bootstrapProps.property(eq("sonar.password"))).thenReturn("password"); | |||
thrown.expectMessage("Not authorized. Please check the properties sonar.login and sonar.password"); | |||
newServerClient().request("/foo"); | |||
newServerClient().downloadString("/foo"); | |||
} | |||
@Test | |||
public void should_display_json_error_when_403() throws Exception { | |||
server = new MockHttpServer(); | |||
server.start(); | |||
server.setMockResponseStatus(403); | |||
server.setMockResponseData("{\"errors\":[{\"msg\":\"Insufficient privileges\"}]}"); | |||
startServer(403, "{\"errors\":[{\"msg\":\"Insufficient privileges\"}]}"); | |||
thrown.expectMessage("Insufficient privileges"); | |||
newServerClient().request("/foo"); | |||
newServerClient().downloadString("/foo"); | |||
} | |||
@Test | |||
public void should_fail_if_error() throws Exception { | |||
server = new MockHttpServer(); | |||
server.start(); | |||
server.setMockResponseStatus(500); | |||
startServer(500, null); | |||
thrown.expectMessage("Fail to execute request [code=500, url=http://localhost:" + server.getPort() + "/foo]"); | |||
newServerClient().request("/foo"); | |||
newServerClient().downloadString("/foo"); | |||
} | |||
@Test | |||
public void testEncode() { | |||
assertThat(ServerClient.encodeForUrl("my value")).isEqualTo("my+value"); | |||
public void string_encode() { | |||
assertThat(BatchUtils.encodeForUrl("my value")).isEqualTo("my+value"); | |||
} | |||
private ServerClient newServerClient() { | |||
when(bootstrapProps.property("sonar.host.url")).thenReturn("http://localhost:" + server.getPort()); | |||
PersistentCache ps = new PersistentCacheBuilder(new Slf4jLogger()).setSonarHome(cacheTmp.getRoot().toPath()).build(); | |||
return new ServerClient(bootstrapProps, new EnvironmentInformation("Junit", "4"), ps, mode); | |||
return new ServerClient(bootstrapProps, new EnvironmentInformation("Junit", "4")); | |||
} | |||
private int getNumFilesInCache() { | |||
return new File(cacheTmp.getRoot(), "ws_cache").listFiles().length; | |||
} | |||
static class MockHttpServer { | |||
private Server server; | |||
private String responseBody; | |||
private String requestBody; | |||
private String mockResponseData; | |||
private int mockResponseStatus = SC_OK; | |||
public void start() throws Exception { | |||
server = new Server(0); | |||
server.setHandler(getMockHandler()); | |||
server.start(); | |||
} | |||
/** | |||
* Creates an {@link org.mortbay.jetty.handler.AbstractHandler handler} returning an arbitrary String as a response. | |||
* | |||
* @return never <code>null</code>. | |||
*/ | |||
public Handler getMockHandler() { | |||
Handler handler = new AbstractHandler() { | |||
public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { | |||
setResponseBody(getMockResponseData()); | |||
setRequestBody(IOUtils.toString(baseRequest.getInputStream())); | |||
response.setStatus(mockResponseStatus); | |||
response.setContentType("text/xml;charset=utf-8"); | |||
write(getResponseBody(), response.getOutputStream()); | |||
baseRequest.setHandled(true); | |||
} | |||
}; | |||
return handler; | |||
} | |||
public void stop() { | |||
try { | |||
if (server != null) { | |||
server.stop(); | |||
} | |||
} catch (Exception e) { | |||
throw new IllegalStateException("Fail to stop HTTP server", e); | |||
} | |||
} | |||
public String getResponseBody() { | |||
return responseBody; | |||
} | |||
public void setResponseBody(String responseBody) { | |||
this.responseBody = responseBody; | |||
} | |||
public String getRequestBody() { | |||
return requestBody; | |||
} | |||
public void setRequestBody(String requestBody) { | |||
this.requestBody = requestBody; | |||
} | |||
public void setMockResponseStatus(int status) { | |||
this.mockResponseStatus = status; | |||
} | |||
public String getMockResponseData() { | |||
return mockResponseData; | |||
} | |||
public void setMockResponseData(String mockResponseData) { | |||
this.mockResponseData = mockResponseData; | |||
private void startServer(Integer responseStatus, String responseData) throws Exception { | |||
server = new MockHttpServer(); | |||
server.start(); | |||
if (responseStatus != null) { | |||
server.setMockResponseStatus(responseStatus); | |||
} | |||
public int getPort() { | |||
return server.getConnectors()[0].getLocalPort(); | |||
if (responseData != null) { | |||
server.setMockResponseData(responseData); | |||
} | |||
} | |||
} |
@@ -0,0 +1,76 @@ | |||
/* | |||
* SonarQube, open source software quality management tool. | |||
* Copyright (C) 2008-2014 SonarSource | |||
* mailto:contact AT sonarsource DOT com | |||
* | |||
* SonarQube is free software; you can redistribute it and/or | |||
* modify it under the terms of the GNU Lesser General Public | |||
* License as published by the Free Software Foundation; either | |||
* version 3 of the License, or (at your option) any later version. | |||
* | |||
* SonarQube is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||
* Lesser General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU Lesser General Public License | |||
* along with this program; if not, write to the Free Software Foundation, | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
package org.sonar.batch.bootstrap; | |||
import static org.assertj.core.api.Assertions.assertThat; | |||
import java.util.HashMap; | |||
import java.util.Map; | |||
import static org.mockito.Mockito.when; | |||
import org.sonar.batch.bootstrap.WSLoader.LoadStrategy; | |||
import org.junit.Test; | |||
import org.junit.Before; | |||
import org.sonar.home.cache.PersistentCache; | |||
import org.mockito.Mock; | |||
import org.mockito.MockitoAnnotations; | |||
public class WSLoaderGlobalProviderTest { | |||
@Mock | |||
private PersistentCache cache; | |||
@Mock | |||
private ServerClient client; | |||
@Mock | |||
private GlobalMode mode; | |||
private WSLoaderGlobalProvider loaderProvider; | |||
private Map<String, String> propMap; | |||
private BootstrapProperties props; | |||
@Before | |||
public void setUp() { | |||
MockitoAnnotations.initMocks(this); | |||
loaderProvider = new WSLoaderGlobalProvider(); | |||
} | |||
@Test | |||
public void testDefault() { | |||
propMap = new HashMap<>(); | |||
props = new BootstrapProperties(propMap); | |||
WSLoader wsLoader = loaderProvider.provide(props, mode, cache, client); | |||
assertThat(wsLoader.getStrategy()).isEqualTo(LoadStrategy.SERVER_FIRST); | |||
assertThat(wsLoader.isCacheEnabled()).isEqualTo(false); | |||
} | |||
@Test | |||
public void testOffline() { | |||
propMap = new HashMap<>(); | |||
propMap.put("sonar.enableOffline", "true"); | |||
when(mode.isPreview()).thenReturn(true); | |||
props = new BootstrapProperties(propMap); | |||
WSLoader wsLoader = loaderProvider.provide(props, mode, cache, client); | |||
assertThat(wsLoader.isCacheEnabled()).isEqualTo(true); | |||
} | |||
} |
@@ -0,0 +1,214 @@ | |||
/* | |||
* SonarQube, open source software quality management tool. | |||
* Copyright (C) 2008-2014 SonarSource | |||
* mailto:contact AT sonarsource DOT com | |||
* | |||
* SonarQube is free software; you can redistribute it and/or | |||
* modify it under the terms of the GNU Lesser General Public | |||
* License as published by the Free Software Foundation; either | |||
* version 3 of the License, or (at your option) any later version. | |||
* | |||
* SonarQube is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||
* Lesser General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU Lesser General Public License | |||
* along with this program; if not, write to the Free Software Foundation, | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
package org.sonar.batch.bootstrap; | |||
import org.sonar.api.utils.HttpDownloader; | |||
import org.mockito.invocation.InvocationOnMock; | |||
import org.mockito.stubbing.Answer; | |||
import org.apache.commons.io.IOUtils; | |||
import org.mockito.Mockito; | |||
import org.mockito.InOrder; | |||
import java.io.IOException; | |||
import java.net.URI; | |||
import static org.mockito.Mockito.mock; | |||
import static org.assertj.core.api.Assertions.assertThat; | |||
import static org.mockito.Matchers.anyBoolean; | |||
import static org.mockito.Mockito.times; | |||
import static org.mockito.Mockito.verify; | |||
import static org.mockito.Mockito.verifyNoMoreInteractions; | |||
import static org.mockito.Mockito.when; | |||
import static org.mockito.Matchers.eq; | |||
import static org.mockito.Matchers.anyString; | |||
import static org.mockito.Matchers.anyInt; | |||
import org.sonar.batch.bootstrap.WSLoader.LoadStrategy; | |||
import org.junit.Test; | |||
import org.mockito.MockitoAnnotations; | |||
import org.junit.Before; | |||
import org.sonar.home.cache.PersistentCache; | |||
import org.mockito.Mock; | |||
public class WSLoaderTest { | |||
private final static String ID = "/dummy"; | |||
private final static String cacheValue = "cache"; | |||
private final static String serverValue = "server"; | |||
@Mock | |||
private ServerClient client; | |||
@Mock | |||
private PersistentCache cache; | |||
@Before | |||
public void setUp() throws IOException { | |||
MockitoAnnotations.initMocks(this); | |||
when(client.load(anyString(), anyString(), anyBoolean(), anyInt(), anyInt())).thenReturn(IOUtils.toInputStream(serverValue)); | |||
when(cache.get(ID, null)).thenReturn(cacheValue.getBytes()); | |||
when(client.getURI(anyString())).thenAnswer(new Answer<URI>() { | |||
@Override | |||
public URI answer(InvocationOnMock invocation) throws Throwable { | |||
return new URI((String) invocation.getArguments()[0]); | |||
} | |||
}); | |||
} | |||
@Test | |||
public void dont_retry_server() throws IOException { | |||
when(client.load(anyString(), anyString(), anyBoolean(), anyInt(), anyInt())).thenThrow(new IllegalStateException()); | |||
WSLoader loader = new WSLoader(true, cache, client); | |||
loader.setStrategy(LoadStrategy.SERVER_FIRST); | |||
loader.setCacheEnabled(true); | |||
assertThat(loader.loadString(ID)).isEqualTo(cacheValue); | |||
assertThat(loader.loadString(ID)).isEqualTo(cacheValue); | |||
// only try once the server | |||
verify(client, times(1)).load(anyString(), anyString(), anyBoolean(), anyInt(), anyInt()); | |||
verify(cache, times(2)).get(ID, null); | |||
} | |||
@Test | |||
public void test_cache_strategy_fallback() throws IOException { | |||
when(cache.get(ID, null)).thenReturn(null); | |||
WSLoader loader = new WSLoader(true, cache, client); | |||
loader.setStrategy(LoadStrategy.CACHE_FIRST); | |||
loader.setCacheEnabled(true); | |||
loader.load(ID); | |||
InOrder inOrder = Mockito.inOrder(client, cache); | |||
inOrder.verify(cache).get(ID, null); | |||
inOrder.verify(client).load(eq(ID), anyString(), anyBoolean(), anyInt(), anyInt()); | |||
} | |||
@Test | |||
public void test_server_strategy_fallback() throws IOException { | |||
when(client.load(anyString(), anyString(), anyBoolean(), anyInt(), anyInt())).thenThrow(new IllegalStateException()); | |||
WSLoader loader = new WSLoader(true, cache, client); | |||
loader.setStrategy(LoadStrategy.SERVER_FIRST); | |||
loader.setCacheEnabled(true); | |||
assertThat(loader.loadString(ID)).isEqualTo(cacheValue); | |||
InOrder inOrder = Mockito.inOrder(client, cache); | |||
inOrder.verify(client).load(eq(ID), anyString(), anyBoolean(), anyInt(), anyInt()); | |||
inOrder.verify(cache).get(ID, null); | |||
} | |||
@Test | |||
public void test_put_cache() throws IOException { | |||
WSLoader loader = new WSLoader(true, cache, client); | |||
loader.setStrategy(LoadStrategy.SERVER_FIRST); | |||
loader.load(ID); | |||
verify(cache).put(ID, serverValue.getBytes()); | |||
} | |||
@Test(expected = NullPointerException.class) | |||
public void test_throw_cache_exception_fallback() throws IOException { | |||
when(client.load(anyString(), anyString(), anyBoolean(), anyInt(), anyInt())).thenThrow(new IllegalStateException()); | |||
when(cache.get(ID, null)).thenThrow(new NullPointerException()); | |||
WSLoader loader = new WSLoader(true, cache, client); | |||
loader.setStrategy(LoadStrategy.SERVER_FIRST); | |||
loader.setCacheEnabled(true); | |||
loader.load(ID); | |||
} | |||
@Test(expected = IllegalStateException.class) | |||
public void test_throw_cache_exception() throws IOException { | |||
when(cache.get(ID, null)).thenThrow(new IllegalStateException()); | |||
WSLoader loader = new WSLoader(true, cache, client); | |||
loader.setStrategy(LoadStrategy.CACHE_FIRST); | |||
loader.setCacheEnabled(true); | |||
loader.load(ID); | |||
} | |||
@Test(expected = IllegalStateException.class) | |||
public void test_throw_http_exceptions() { | |||
HttpDownloader.HttpException httpException = mock(HttpDownloader.HttpException.class); | |||
IllegalStateException wrapperException = new IllegalStateException(httpException); | |||
when(client.load(anyString(), anyString(), anyBoolean(), anyInt(), anyInt())).thenThrow(wrapperException); | |||
WSLoader loader = new WSLoader(true, cache, client); | |||
loader.setStrategy(LoadStrategy.SERVER_FIRST); | |||
try { | |||
loader.load(ID); | |||
} catch(IllegalStateException e) { | |||
// cache should not be used | |||
verifyNoMoreInteractions(cache); | |||
throw e; | |||
} | |||
} | |||
@Test | |||
public void test_server_not_accessible() throws IOException { | |||
when(client.load(anyString(), anyString(), anyBoolean(), anyInt(), anyInt())).thenThrow(new IllegalStateException()); | |||
WSLoader loader = new WSLoader(true, cache, client); | |||
loader.setStrategy(LoadStrategy.SERVER_FIRST); | |||
loader.load(ID); | |||
loader.load(ID); | |||
// only try once from server | |||
verify(client, times(1)).load(eq(ID), anyString(), anyBoolean(), anyInt(), anyInt()); | |||
verify(cache, times(2)).get(ID, null); | |||
} | |||
@Test | |||
public void test_change_strategy() throws IOException { | |||
WSLoader loader = new WSLoader(true, cache, client); | |||
loader.setStrategy(LoadStrategy.CACHE_FIRST); | |||
test_cache_strategy_fallback(); | |||
} | |||
@Test | |||
public void test_enable_cache() throws IOException { | |||
WSLoader loader = new WSLoader(true, cache, client); | |||
loader.setCacheEnabled(false); | |||
test_cache_disabled(); | |||
} | |||
@Test | |||
public void test_server_strategy() throws IOException { | |||
WSLoader loader = new WSLoader(true, cache, client); | |||
loader.setStrategy(LoadStrategy.SERVER_FIRST); | |||
loader.load(ID); | |||
// should not fetch from cache | |||
verify(cache).put(ID, serverValue.getBytes()); | |||
verifyNoMoreInteractions(cache); | |||
} | |||
@Test | |||
public void test_cache_disabled() throws IOException { | |||
WSLoader loader = new WSLoader(cache, client); | |||
loader.load(ID); | |||
// should not even put | |||
verifyNoMoreInteractions(cache); | |||
} | |||
@Test | |||
public void test_string() { | |||
WSLoader loader = new WSLoader(cache, client); | |||
assertThat(loader.loadString(ID)).isEqualTo(serverValue); | |||
} | |||
} |
@@ -0,0 +1,112 @@ | |||
/* | |||
* SonarQube, open source software quality management tool. | |||
* Copyright (C) 2008-2014 SonarSource | |||
* mailto:contact AT sonarsource DOT com | |||
* | |||
* SonarQube is free software; you can redistribute it and/or | |||
* modify it under the terms of the GNU Lesser General Public | |||
* License as published by the Free Software Foundation; either | |||
* version 3 of the License, or (at your option) any later version. | |||
* | |||
* SonarQube is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||
* Lesser General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU Lesser General Public License | |||
* along with this program; if not, write to the Free Software Foundation, | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
package org.sonar.batch.bootstrap; | |||
import static org.mockito.Mockito.mock; | |||
import org.sonar.batch.bootstrap.WSLoader.LoadStrategy; | |||
import org.junit.Rule; | |||
import org.junit.rules.TemporaryFolder; | |||
import static org.mockito.Mockito.when; | |||
import static org.assertj.core.api.Assertions.assertThat; | |||
import org.sonar.batch.bootstrapper.EnvironmentInformation; | |||
import org.sonar.home.cache.PersistentCache; | |||
import org.junit.After; | |||
import org.junit.Before; | |||
import org.junit.Test; | |||
public class WSLoaderTestWithServer { | |||
private static final String RESPONSE_STRING = "this is the content"; | |||
@Rule | |||
public TemporaryFolder temp = new TemporaryFolder(); | |||
private MockHttpServer server; | |||
private PersistentCache cache; | |||
private ServerClient client; | |||
private WSLoader loader; | |||
@Before | |||
public void setUp() throws Exception { | |||
server = new MockHttpServer(); | |||
server.start(); | |||
BootstrapProperties bootstrapProps = mock(BootstrapProperties.class); | |||
when(bootstrapProps.property("sonar.host.url")).thenReturn("http://localhost:" + server.getPort()); | |||
client = new ServerClient(bootstrapProps, new EnvironmentInformation("Junit", "4")); | |||
cache = new PersistentCache(temp.getRoot().toPath(), 1000 * 60, new Slf4jLogger()); | |||
loader = new WSLoader(cache, client); | |||
} | |||
@After | |||
public void tearDown() { | |||
if (server != null) { | |||
server.stop(); | |||
} | |||
} | |||
@Test | |||
public void testServer() { | |||
loader.setCacheEnabled(false); | |||
loader.setStrategy(LoadStrategy.SERVER_FIRST); | |||
server.setMockResponseData(RESPONSE_STRING); | |||
assertThat(loader.loadString("/foo")).isEqualTo(RESPONSE_STRING); | |||
} | |||
@Test | |||
public void testCacheDisabled() { | |||
loader.setCacheEnabled(false); | |||
loader.setStrategy(LoadStrategy.CACHE_FIRST); | |||
makeRequests(); | |||
assertThat(server.getNumberRequests()).isEqualTo(3); | |||
} | |||
@Test | |||
public void testCacheEnabled() { | |||
loader.setCacheEnabled(true); | |||
loader.setStrategy(LoadStrategy.CACHE_FIRST); | |||
makeRequests(); | |||
assertThat(server.getNumberRequests()).isEqualTo(1); | |||
} | |||
@Test | |||
public void testServerStrategy() { | |||
loader.setCacheEnabled(true); | |||
loader.setStrategy(LoadStrategy.SERVER_FIRST); | |||
makeRequests(); | |||
assertThat(server.getNumberRequests()).isEqualTo(3); | |||
} | |||
@Test | |||
public void testCacheStrategyDisabled() { | |||
loader.setCacheEnabled(false); | |||
loader.setStrategy(LoadStrategy.CACHE_FIRST); | |||
makeRequests(); | |||
assertThat(server.getNumberRequests()).isEqualTo(3); | |||
} | |||
private void makeRequests() { | |||
server.setMockResponseData(RESPONSE_STRING); | |||
assertThat(loader.loadString("/foo")).isEqualTo(RESPONSE_STRING); | |||
assertThat(loader.loadString("/foo")).isEqualTo(RESPONSE_STRING); | |||
assertThat(loader.loadString("/foo")).isEqualTo(RESPONSE_STRING); | |||
} | |||
} |
@@ -19,14 +19,14 @@ | |||
*/ | |||
package org.sonar.batch.cpd.index; | |||
import org.sonar.batch.scan.ProjectAnalysisMode; | |||
import org.junit.Before; | |||
import org.junit.Test; | |||
import org.slf4j.Logger; | |||
import org.sonar.api.CoreProperties; | |||
import org.sonar.api.config.Settings; | |||
import org.sonar.api.resources.Project; | |||
import org.sonar.batch.bootstrap.DefaultAnalysisMode; | |||
import static org.assertj.core.api.Assertions.assertThat; | |||
import static org.mockito.Mockito.mock; | |||
import static org.mockito.Mockito.verify; | |||
@@ -38,13 +38,13 @@ public class IndexFactoryTest { | |||
Settings settings; | |||
IndexFactory factory; | |||
Logger logger; | |||
private DefaultAnalysisMode analysisMode; | |||
private ProjectAnalysisMode analysisMode; | |||
@Before | |||
public void setUp() { | |||
project = new Project("foo"); | |||
settings = new Settings(); | |||
analysisMode = mock(DefaultAnalysisMode.class); | |||
analysisMode = mock(ProjectAnalysisMode.class); | |||
factory = new IndexFactory(analysisMode, settings); | |||
logger = mock(Logger.class); | |||
} |
@@ -19,12 +19,13 @@ | |||
*/ | |||
package org.sonar.batch.issue.tracking; | |||
import org.sonar.batch.bootstrap.WSLoader; | |||
import org.junit.Before; | |||
import org.junit.Rule; | |||
import org.junit.Test; | |||
import org.junit.rules.ExpectedException; | |||
import org.sonar.api.utils.HttpDownloader; | |||
import org.sonar.batch.bootstrap.ServerClient; | |||
import java.net.URI; | |||
import java.net.URISyntaxException; | |||
@@ -46,32 +47,32 @@ public class DefaultServerLineHashesLoaderTest { | |||
@Test | |||
public void should_download_source_from_ws_if_preview_mode() { | |||
ServerClient server = mock(ServerClient.class); | |||
when(server.request(anyString())).thenReturn("ae12\n\n43fb"); | |||
WSLoader wsLoader = mock(WSLoader.class); | |||
when(wsLoader.loadString(anyString())).thenReturn("ae12\n\n43fb"); | |||
ServerLineHashesLoader lastSnapshots = new DefaultServerLineHashesLoader(server); | |||
ServerLineHashesLoader lastSnapshots = new DefaultServerLineHashesLoader(wsLoader); | |||
String[] hashes = lastSnapshots.getLineHashes("myproject:org/foo/Bar.c"); | |||
assertThat(hashes).containsOnly("ae12", "", "43fb"); | |||
verify(server).request("/api/sources/hash?key=myproject%3Aorg%2Ffoo%2FBar.c"); | |||
verify(wsLoader).loadString("/api/sources/hash?key=myproject%3Aorg%2Ffoo%2FBar.c"); | |||
} | |||
@Test | |||
public void should_download_source_with_space_from_ws_if_preview_mode() { | |||
ServerClient server = mock(ServerClient.class); | |||
when(server.request(anyString())).thenReturn("ae12\n\n43fb"); | |||
WSLoader server = mock(WSLoader.class); | |||
when(server.loadString(anyString())).thenReturn("ae12\n\n43fb"); | |||
ServerLineHashesLoader lastSnapshots = new DefaultServerLineHashesLoader(server); | |||
String[] hashes = lastSnapshots.getLineHashes("myproject:org/foo/Foo Bar.c"); | |||
assertThat(hashes).containsOnly("ae12", "", "43fb"); | |||
verify(server).request("/api/sources/hash?key=myproject%3Aorg%2Ffoo%2FFoo+Bar.c"); | |||
verify(server).loadString("/api/sources/hash?key=myproject%3Aorg%2Ffoo%2FFoo+Bar.c"); | |||
} | |||
@Test | |||
public void should_fail_to_download_source_from_ws() throws URISyntaxException { | |||
ServerClient server = mock(ServerClient.class); | |||
when(server.request(anyString())).thenThrow(new HttpDownloader.HttpException(new URI(""), 500)); | |||
WSLoader server = mock(WSLoader.class); | |||
when(server.loadString(anyString())).thenThrow(new HttpDownloader.HttpException(new URI(""), 500)); | |||
ServerLineHashesLoader lastSnapshots = new DefaultServerLineHashesLoader(server); | |||
@@ -19,6 +19,8 @@ | |||
*/ | |||
package org.sonar.batch.report; | |||
import org.sonar.batch.scan.ProjectAnalysisMode; | |||
import org.junit.Before; | |||
import org.junit.Test; | |||
import org.slf4j.Logger; | |||
@@ -27,23 +29,21 @@ import org.sonar.api.batch.bootstrap.ProjectDefinition; | |||
import org.sonar.api.config.Settings; | |||
import org.sonar.api.platform.Server; | |||
import org.sonar.api.utils.TempFolder; | |||
import org.sonar.batch.bootstrap.DefaultAnalysisMode; | |||
import org.sonar.batch.bootstrap.ServerClient; | |||
import org.sonar.batch.scan.ImmutableProjectReactor; | |||
import static org.mockito.Mockito.mock; | |||
import static org.mockito.Mockito.verify; | |||
import static org.mockito.Mockito.when; | |||
public class ReportPublisherTest { | |||
private DefaultAnalysisMode mode; | |||
private ProjectAnalysisMode mode; | |||
private ImmutableProjectReactor reactor; | |||
@Before | |||
public void setUp() { | |||
mode = mock(DefaultAnalysisMode.class); | |||
mode = mock(ProjectAnalysisMode.class); | |||
reactor = mock(ImmutableProjectReactor.class); | |||
when(reactor.getRoot()).thenReturn(ProjectDefinition.create().setKey("struts")); | |||
} |
@@ -19,16 +19,16 @@ | |||
*/ | |||
package org.sonar.batch.repository; | |||
import org.sonar.batch.scan.ProjectAnalysisMode; | |||
import org.sonar.batch.bootstrap.WSLoader; | |||
import com.google.common.collect.Maps; | |||
import org.junit.Before; | |||
import org.junit.Test; | |||
import org.sonar.api.batch.bootstrap.ProjectDefinition; | |||
import org.sonar.api.batch.bootstrap.ProjectReactor; | |||
import org.sonar.batch.bootstrap.AnalysisProperties; | |||
import org.sonar.batch.bootstrap.DefaultAnalysisMode; | |||
import org.sonar.batch.bootstrap.ServerClient; | |||
import org.sonar.batch.rule.ModuleQProfiles; | |||
import static org.mockito.Matchers.anyString; | |||
import static org.mockito.Mockito.mock; | |||
import static org.mockito.Mockito.spy; | |||
@@ -38,18 +38,18 @@ import static org.mockito.Mockito.when; | |||
public class DefaultProjectRepositoriesLoaderTest { | |||
private DefaultProjectRepositoriesLoader loader; | |||
private ServerClient serverClient; | |||
private DefaultAnalysisMode analysisMode; | |||
private WSLoader wsLoader; | |||
private ProjectAnalysisMode analysisMode; | |||
private ProjectReactor reactor; | |||
private AnalysisProperties taskProperties; | |||
@Before | |||
public void prepare() { | |||
serverClient = mock(ServerClient.class); | |||
analysisMode = mock(DefaultAnalysisMode.class); | |||
loader = new DefaultProjectRepositoriesLoader(serverClient, analysisMode); | |||
wsLoader = mock(WSLoader.class); | |||
analysisMode = mock(ProjectAnalysisMode.class); | |||
loader = new DefaultProjectRepositoriesLoader(wsLoader, analysisMode); | |||
loader = spy(loader); | |||
when(serverClient.request(anyString())).thenReturn("{}"); | |||
when(wsLoader.loadString(anyString())).thenReturn("{}"); | |||
taskProperties = new AnalysisProperties(Maps.<String, String>newHashMap(), ""); | |||
} | |||
@@ -58,18 +58,18 @@ public class DefaultProjectRepositoriesLoaderTest { | |||
reactor = new ProjectReactor(ProjectDefinition.create().setKey("foo")); | |||
when(analysisMode.isPreview()).thenReturn(false); | |||
loader.load(reactor, taskProperties); | |||
verify(serverClient).request("/batch/project?key=foo&preview=false"); | |||
verify(wsLoader).loadString("/batch/project?key=foo&preview=false"); | |||
when(analysisMode.isPreview()).thenReturn(true); | |||
loader.load(reactor, taskProperties); | |||
verify(serverClient).request("/batch/project?key=foo&preview=true"); | |||
verify(wsLoader).loadString("/batch/project?key=foo&preview=true"); | |||
} | |||
@Test | |||
public void passAndEncodeProjectKeyParameter() { | |||
reactor = new ProjectReactor(ProjectDefinition.create().setKey("foo bàr")); | |||
loader.load(reactor, taskProperties); | |||
verify(serverClient).request("/batch/project?key=foo+b%C3%A0r&preview=false"); | |||
verify(wsLoader).loadString("/batch/project?key=foo+b%C3%A0r&preview=false"); | |||
} | |||
@Test | |||
@@ -77,7 +77,7 @@ public class DefaultProjectRepositoriesLoaderTest { | |||
reactor = new ProjectReactor(ProjectDefinition.create().setKey("foo")); | |||
taskProperties.properties().put(ModuleQProfiles.SONAR_PROFILE_PROP, "my-profile#2"); | |||
loader.load(reactor, taskProperties); | |||
verify(serverClient).request("/batch/project?key=foo&profile=my-profile%232&preview=false"); | |||
verify(wsLoader).loadString("/batch/project?key=foo&profile=my-profile%232&preview=false"); | |||
} | |||
} |
@@ -19,17 +19,17 @@ | |||
*/ | |||
package org.sonar.batch.repository; | |||
import com.google.common.io.ByteSource; | |||
import org.sonar.batch.bootstrap.WSLoader; | |||
import com.google.common.base.Function; | |||
import com.google.common.io.InputSupplier; | |||
import org.junit.Before; | |||
import org.junit.Test; | |||
import org.sonar.batch.bootstrap.ServerClient; | |||
import org.sonar.batch.protocol.input.BatchInput; | |||
import org.sonar.batch.protocol.input.BatchInput.ServerIssue; | |||
import java.io.ByteArrayInputStream; | |||
import java.io.ByteArrayOutputStream; | |||
import java.io.InputStream; | |||
import java.util.ArrayList; | |||
import java.util.List; | |||
@@ -39,18 +39,18 @@ import static org.mockito.Mockito.when; | |||
public class DefaultServerIssuesLoaderTest { | |||
private DefaultServerIssuesLoader loader; | |||
private ServerClient serverClient; | |||
private WSLoader wsLoader; | |||
@Before | |||
public void prepare() { | |||
serverClient = mock(ServerClient.class); | |||
loader = new DefaultServerIssuesLoader(serverClient); | |||
wsLoader = mock(WSLoader.class); | |||
loader = new DefaultServerIssuesLoader(wsLoader); | |||
} | |||
@Test | |||
public void loadFromWs() throws Exception { | |||
InputSupplier<InputStream> is = mock(InputSupplier.class); | |||
when(serverClient.doRequest("/batch/issues?key=foo", "GET", null)).thenReturn(is); | |||
ByteSource bs = mock(ByteSource.class); | |||
when(wsLoader.loadSource("/batch/issues?key=foo")).thenReturn(bs); | |||
ByteArrayOutputStream bos = new ByteArrayOutputStream(); | |||
@@ -59,7 +59,7 @@ public class DefaultServerIssuesLoaderTest { | |||
ServerIssue.newBuilder().setKey("ab2").build() | |||
.writeDelimitedTo(bos); | |||
when(is.getInput()).thenReturn(new ByteArrayInputStream(bos.toByteArray())); | |||
when(bs.openStream()).thenReturn(new ByteArrayInputStream(bos.toByteArray())); | |||
final List<ServerIssue> result = new ArrayList<>(); | |||
loader.load("foo", new Function<BatchInput.ServerIssue, Void>() { |
@@ -19,15 +19,15 @@ | |||
*/ | |||
package org.sonar.batch.repository.user; | |||
import com.google.common.io.InputSupplier; | |||
import com.google.common.io.ByteSource; | |||
import org.sonar.batch.bootstrap.WSLoader; | |||
import org.junit.Test; | |||
import org.sonar.batch.bootstrap.ServerClient; | |||
import org.sonar.batch.protocol.input.BatchInput; | |||
import java.io.ByteArrayInputStream; | |||
import java.io.ByteArrayOutputStream; | |||
import java.io.IOException; | |||
import java.io.InputStream; | |||
import java.util.Arrays; | |||
import static org.assertj.core.api.Assertions.assertThat; | |||
@@ -39,18 +39,17 @@ public class UserRepositoryTest { | |||
@Test | |||
public void testLoad() throws IOException { | |||
ServerClient serverClient = mock(ServerClient.class); | |||
UserRepository userRepo = new UserRepository(serverClient); | |||
WSLoader wsLoader = mock(WSLoader.class); | |||
UserRepository userRepo = new UserRepository(wsLoader); | |||
ByteArrayOutputStream out = new ByteArrayOutputStream(); | |||
BatchInput.User.Builder builder = BatchInput.User.newBuilder(); | |||
builder.setLogin("fmallet").setName("Freddy Mallet").build().writeDelimitedTo(out); | |||
builder.setLogin("sbrandhof").setName("Simon").build().writeDelimitedTo(out); | |||
InputSupplier<InputStream> is = mock(InputSupplier.class); | |||
when(serverClient.doRequest("/batch/users?logins=fmallet,sbrandhof", "GET", null)) | |||
.thenReturn(is); | |||
when(is.getInput()).thenReturn(new ByteArrayInputStream(out.toByteArray())); | |||
ByteSource source = mock(ByteSource.class); | |||
when(wsLoader.loadSource("/batch/users?logins=fmallet,sbrandhof")).thenReturn(source); | |||
when(source.openStream()).thenReturn(new ByteArrayInputStream(out.toByteArray())); | |||
assertThat(userRepo.loadFromWs(Arrays.asList("fmallet", "sbrandhof"))).extracting("login", "name").containsOnly(tuple("fmallet", "Freddy Mallet"), tuple("sbrandhof", "Simon")); | |||
} |
@@ -17,14 +17,15 @@ | |||
* along with this program; if not, write to the Free Software Foundation, | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
package org.sonar.batch.bootstrap; | |||
package org.sonar.batch.scan; | |||
import com.google.common.collect.ImmutableMap; | |||
import com.google.common.collect.Maps; | |||
import org.sonar.batch.bootstrap.AnalysisProperties; | |||
import org.sonar.batch.scan.ProjectAnalysisMode; | |||
import org.junit.Test; | |||
import org.sonar.api.CoreProperties; | |||
import java.util.Collections; | |||
import java.util.HashMap; | |||
import java.util.Map; | |||
import static org.assertj.core.api.Assertions.assertThat; | |||
@@ -33,12 +34,12 @@ public class DefaultAnalysisModeTest { | |||
@Test | |||
public void regular_analysis_by_default() { | |||
DefaultAnalysisMode mode = new DefaultAnalysisMode(Collections.<String, String>emptyMap()); | |||
ProjectAnalysisMode mode = new ProjectAnalysisMode(new AnalysisProperties(Collections.<String, String>emptyMap())); | |||
assertThat(mode.isPreview()).isFalse(); | |||
assertThat(mode.isIncremental()).isFalse(); | |||
mode = new DefaultAnalysisMode(ImmutableMap.of(CoreProperties.ANALYSIS_MODE, "pouet")); | |||
mode = createMode(CoreProperties.ANALYSIS_MODE, "pouet"); | |||
assertThat(mode.isPreview()).isFalse(); | |||
assertThat(mode.isIncremental()).isFalse(); | |||
@@ -46,7 +47,7 @@ public class DefaultAnalysisModeTest { | |||
@Test | |||
public void support_analysis_mode() { | |||
DefaultAnalysisMode mode = new DefaultAnalysisMode(ImmutableMap.of(CoreProperties.ANALYSIS_MODE, CoreProperties.ANALYSIS_MODE_ANALYSIS)); | |||
ProjectAnalysisMode mode = createMode(CoreProperties.ANALYSIS_MODE, CoreProperties.ANALYSIS_MODE_ANALYSIS); | |||
assertThat(mode.isPreview()).isFalse(); | |||
assertThat(mode.isIncremental()).isFalse(); | |||
@@ -54,31 +55,41 @@ public class DefaultAnalysisModeTest { | |||
@Test | |||
public void support_preview_mode() { | |||
Map<String, String> props = Maps.newHashMap(ImmutableMap.of(CoreProperties.ANALYSIS_MODE, CoreProperties.ANALYSIS_MODE_PREVIEW)); | |||
DefaultAnalysisMode mode = new DefaultAnalysisMode(props); | |||
ProjectAnalysisMode mode = createMode(CoreProperties.ANALYSIS_MODE, CoreProperties.ANALYSIS_MODE_PREVIEW); | |||
assertThat(mode.isPreview()).isTrue(); | |||
assertThat(mode.isIncremental()).isFalse(); | |||
} | |||
@Test | |||
public void support_quick_mode() { | |||
ProjectAnalysisMode mode = createMode(CoreProperties.ANALYSIS_MODE, CoreProperties.ANALYSIS_MODE_QUICK); | |||
assertThat(props.get(CoreProperties.DRY_RUN)).isEqualTo("true"); | |||
assertThat(mode.isPreview()).isTrue(); | |||
assertThat(mode.isIncremental()).isFalse(); | |||
assertThat(mode.isQuick()).isTrue(); | |||
} | |||
@Test | |||
public void support_incremental_mode() { | |||
Map<String, String> props = Maps.newHashMap(ImmutableMap.of(CoreProperties.ANALYSIS_MODE, CoreProperties.ANALYSIS_MODE_INCREMENTAL)); | |||
DefaultAnalysisMode mode = new DefaultAnalysisMode(props); | |||
ProjectAnalysisMode mode = createMode(CoreProperties.ANALYSIS_MODE, CoreProperties.ANALYSIS_MODE_INCREMENTAL); | |||
assertThat(mode.isPreview()).isTrue(); | |||
assertThat(mode.isIncremental()).isTrue(); | |||
assertThat(props.get(CoreProperties.DRY_RUN)).isEqualTo("true"); | |||
} | |||
@Test | |||
public void support_deprecated_dryrun_property() { | |||
DefaultAnalysisMode mode = new DefaultAnalysisMode(Maps.newHashMap(ImmutableMap.of(CoreProperties.DRY_RUN, "true"))); | |||
ProjectAnalysisMode mode = createMode(CoreProperties.DRY_RUN, "true"); | |||
assertThat(mode.isPreview()).isTrue(); | |||
assertThat(mode.isIncremental()).isFalse(); | |||
} | |||
private ProjectAnalysisMode createMode(String key, String value) { | |||
Map<String, String> map = new HashMap<>(); | |||
map.put(key, value); | |||
return new ProjectAnalysisMode(new AnalysisProperties(map)); | |||
} | |||
} |
@@ -27,7 +27,6 @@ import org.junit.rules.ExpectedException; | |||
import org.sonar.api.batch.bootstrap.ProjectDefinition; | |||
import org.sonar.api.config.PropertyDefinitions; | |||
import org.sonar.api.utils.MessageException; | |||
import org.sonar.batch.bootstrap.DefaultAnalysisMode; | |||
import org.sonar.batch.bootstrap.GlobalSettings; | |||
import org.sonar.batch.protocol.input.ProjectRepositories; | |||
@@ -43,12 +42,12 @@ public class ModuleSettingsTest { | |||
public ExpectedException thrown = ExpectedException.none(); | |||
ProjectRepositories projectRef; | |||
private DefaultAnalysisMode mode; | |||
private ProjectAnalysisMode mode; | |||
@Before | |||
public void before() { | |||
projectRef = new ProjectRepositories(); | |||
mode = mock(DefaultAnalysisMode.class); | |||
mode = mock(ProjectAnalysisMode.class); | |||
} | |||
@Test |
@@ -19,8 +19,12 @@ | |||
*/ | |||
package org.sonar.batch.scan; | |||
import org.sonar.batch.bootstrap.GlobalMode; | |||
import com.google.common.collect.ImmutableMap; | |||
import java.util.Collections; | |||
import org.junit.Before; | |||
import org.junit.Rule; | |||
import org.junit.Test; | |||
@@ -33,11 +37,9 @@ import org.sonar.api.utils.MessageException; | |||
import org.sonar.api.utils.log.LogTester; | |||
import org.sonar.api.utils.log.LoggerLevel; | |||
import org.sonar.batch.bootstrap.BootstrapProperties; | |||
import org.sonar.batch.bootstrap.DefaultAnalysisMode; | |||
import org.sonar.batch.bootstrap.GlobalSettings; | |||
import org.sonar.batch.protocol.input.GlobalRepositories; | |||
import org.sonar.batch.protocol.input.ProjectRepositories; | |||
import static org.assertj.core.api.Assertions.assertThat; | |||
import static org.mockito.Mockito.mock; | |||
import static org.mockito.Mockito.when; | |||
@@ -53,13 +55,15 @@ public class ProjectSettingsTest { | |||
ProjectDefinition project = ProjectDefinition.create().setKey("struts"); | |||
GlobalSettings bootstrapProps; | |||
private DefaultAnalysisMode mode; | |||
private GlobalMode globalMode; | |||
private ProjectAnalysisMode mode; | |||
@Before | |||
public void prepare() { | |||
projectRef = new ProjectRepositories(); | |||
mode = mock(DefaultAnalysisMode.class); | |||
bootstrapProps = new GlobalSettings(new BootstrapProperties(Collections.<String, String>emptyMap()), new PropertyDefinitions(), new GlobalRepositories(), mode); | |||
globalMode = mock(GlobalMode.class); | |||
mode = mock(ProjectAnalysisMode.class); | |||
bootstrapProps = new GlobalSettings(new BootstrapProperties(Collections.<String, String>emptyMap()), new PropertyDefinitions(), new GlobalRepositories(), globalMode); | |||
} | |||
@Test | |||
@@ -118,7 +122,7 @@ public class ProjectSettingsTest { | |||
@Test | |||
public void should_log_a_warning_when_a_dropper_property_is_present() { | |||
GlobalSettings settings = new GlobalSettings(new BootstrapProperties(ImmutableMap.of("sonar.qualitygate", "somevalue")), new PropertyDefinitions(), new GlobalRepositories(), mode); | |||
GlobalSettings settings = new GlobalSettings(new BootstrapProperties(ImmutableMap.of("sonar.qualitygate", "somevalue")), new PropertyDefinitions(), new GlobalRepositories(), globalMode); | |||
new ProjectSettings(new ProjectReactor(project), settings, new PropertyDefinitions(), projectRef, mode); | |||
assertThat(logTester.logs(LoggerLevel.WARN)).containsOnly("Property 'sonar.qualitygate' is not supported any more. It will be ignored."); |
@@ -0,0 +1,81 @@ | |||
/* | |||
* SonarQube, open source software quality management tool. | |||
* Copyright (C) 2008-2014 SonarSource | |||
* mailto:contact AT sonarsource DOT com | |||
* | |||
* SonarQube is free software; you can redistribute it and/or | |||
* modify it under the terms of the GNU Lesser General Public | |||
* License as published by the Free Software Foundation; either | |||
* version 3 of the License, or (at your option) any later version. | |||
* | |||
* SonarQube is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||
* Lesser General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU Lesser General Public License | |||
* along with this program; if not, write to the Free Software Foundation, | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
package org.sonar.batch.scan; | |||
import org.sonar.api.batch.AnalysisMode; | |||
import org.junit.Before; | |||
import org.junit.Test; | |||
import org.mockito.Mock; | |||
import org.mockito.MockitoAnnotations; | |||
import org.sonar.batch.bootstrap.AnalysisProperties; | |||
import org.sonar.batch.bootstrap.ServerClient; | |||
import org.sonar.batch.bootstrap.WSLoader; | |||
import org.sonar.batch.bootstrap.WSLoader.LoadStrategy; | |||
import org.sonar.home.cache.PersistentCache; | |||
import java.util.HashMap; | |||
import java.util.Map; | |||
import static org.mockito.Mockito.when; | |||
import static org.assertj.core.api.Assertions.assertThat; | |||
public class WSLoaderProjectProviderTest { | |||
@Mock | |||
private PersistentCache cache; | |||
@Mock | |||
private ServerClient client; | |||
@Mock | |||
private AnalysisMode mode; | |||
private WSLoaderProjectProvider loaderProvider; | |||
private Map<String, String> propMap; | |||
private AnalysisProperties props; | |||
@Before | |||
public void setUp() { | |||
MockitoAnnotations.initMocks(this); | |||
loaderProvider = new WSLoaderProjectProvider(); | |||
propMap = new HashMap<>(); | |||
} | |||
@Test | |||
public void testDefault() { | |||
props = new AnalysisProperties(propMap, null); | |||
WSLoader loader = loaderProvider.provide(props, mode, cache, client); | |||
assertThat(loader.getStrategy()).isEqualTo(LoadStrategy.SERVER_FIRST); | |||
assertThat(loader.isCacheEnabled()).isEqualTo(false); | |||
} | |||
@Test | |||
public void testSingleMode() { | |||
when(mode.isQuick()).thenReturn(true); | |||
when(mode.isPreview()).thenReturn(true); | |||
propMap.put("sonar.enableOffline", "true"); | |||
props = new AnalysisProperties(propMap, null); | |||
WSLoader loader = loaderProvider.provide(props, mode, cache, client); | |||
assertThat(loader.getStrategy()).isEqualTo(LoadStrategy.CACHE_FIRST); | |||
assertThat(loader.isCacheEnabled()).isEqualTo(true); | |||
} | |||
} |
@@ -19,14 +19,14 @@ | |||
*/ | |||
package org.sonar.batch.scan.filesystem; | |||
import org.sonar.batch.scan.ProjectAnalysisMode; | |||
import org.junit.Test; | |||
import org.mockito.Mockito; | |||
import org.sonar.api.batch.bootstrap.ProjectDefinition; | |||
import org.sonar.api.batch.fs.internal.FileMetadata; | |||
import org.sonar.api.config.Settings; | |||
import org.sonar.api.scan.filesystem.PathResolver; | |||
import org.sonar.batch.bootstrap.DefaultAnalysisMode; | |||
import static org.assertj.core.api.Assertions.assertThat; | |||
import static org.mockito.Mockito.mock; | |||
@@ -37,7 +37,7 @@ public class InputFileBuilderFactoryTest { | |||
LanguageDetectionFactory langDetectionFactory = mock(LanguageDetectionFactory.class, Mockito.RETURNS_MOCKS); | |||
StatusDetectionFactory statusDetectionFactory = mock(StatusDetectionFactory.class, Mockito.RETURNS_MOCKS); | |||
DefaultModuleFileSystem fs = mock(DefaultModuleFileSystem.class); | |||
DefaultAnalysisMode analysisMode = mock(DefaultAnalysisMode.class); | |||
ProjectAnalysisMode analysisMode = mock(ProjectAnalysisMode.class); | |||
InputFileBuilderFactory factory = new InputFileBuilderFactory(ProjectDefinition.create().setKey("struts"), pathResolver, langDetectionFactory, | |||
statusDetectionFactory, analysisMode, new Settings(), new FileMetadata()); |
@@ -19,6 +19,8 @@ | |||
*/ | |||
package org.sonar.batch.scan.filesystem; | |||
import org.sonar.batch.scan.ProjectAnalysisMode; | |||
import org.apache.commons.io.FileUtils; | |||
import org.junit.Rule; | |||
import org.junit.Test; | |||
@@ -29,7 +31,6 @@ import org.sonar.api.batch.fs.internal.FileMetadata; | |||
import org.sonar.api.config.Settings; | |||
import org.sonar.api.scan.filesystem.PathResolver; | |||
import org.sonar.api.utils.PathUtils; | |||
import org.sonar.batch.bootstrap.DefaultAnalysisMode; | |||
import java.io.File; | |||
import java.nio.charset.StandardCharsets; | |||
@@ -47,7 +48,7 @@ public class InputFileBuilderTest { | |||
LanguageDetection langDetection = mock(LanguageDetection.class); | |||
StatusDetection statusDetection = mock(StatusDetection.class); | |||
DefaultModuleFileSystem fs = mock(DefaultModuleFileSystem.class); | |||
DefaultAnalysisMode analysisMode = mock(DefaultAnalysisMode.class); | |||
ProjectAnalysisMode analysisMode = mock(ProjectAnalysisMode.class); | |||
@Test | |||
public void complete_input_file() throws Exception { |
@@ -19,6 +19,7 @@ | |||
*/ | |||
package org.sonar.core.util; | |||
import com.google.common.annotations.VisibleForTesting; | |||
import com.google.common.base.Joiner; | |||
import com.google.common.base.Strings; | |||
@@ -28,6 +29,7 @@ import com.google.common.io.ByteStreams; | |||
import com.google.common.io.CharStreams; | |||
import com.google.common.io.Files; | |||
import com.google.common.io.InputSupplier; | |||
import java.io.File; | |||
import java.io.IOException; | |||
import java.io.InputStream; | |||
@@ -42,7 +44,9 @@ import java.nio.charset.StandardCharsets; | |||
import java.util.List; | |||
import java.util.Map; | |||
import java.util.zip.GZIPInputStream; | |||
import javax.annotation.Nullable; | |||
import org.apache.commons.codec.binary.Base64; | |||
import org.apache.commons.io.FileUtils; | |||
import org.apache.commons.io.IOUtils; | |||
@@ -60,13 +64,19 @@ import org.sonar.api.utils.log.Loggers; | |||
public class DefaultHttpDownloader extends HttpDownloader { | |||
private final BaseHttpDownloader downloader; | |||
private final Integer readTimeout; | |||
private final Integer connectTimeout; | |||
public DefaultHttpDownloader(Server server, Settings settings) { | |||
this(server, settings, null); | |||
} | |||
public DefaultHttpDownloader(Server server, Settings settings, @Nullable Integer readTimeout) { | |||
this(server, settings, null, readTimeout); | |||
} | |||
public DefaultHttpDownloader(Server server, Settings settings, @Nullable Integer connectTimeout, @Nullable Integer readTimeout) { | |||
this.readTimeout = readTimeout; | |||
this.connectTimeout = connectTimeout; | |||
downloader = new BaseHttpDownloader(settings.getProperties(), server.getVersion()); | |||
} | |||
@@ -75,7 +85,12 @@ public class DefaultHttpDownloader extends HttpDownloader { | |||
} | |||
public DefaultHttpDownloader(Settings settings, @Nullable Integer readTimeout) { | |||
this(settings, null, readTimeout); | |||
} | |||
public DefaultHttpDownloader(Settings settings, @Nullable Integer connectTimeout, @Nullable Integer readTimeout) { | |||
this.readTimeout = readTimeout; | |||
this.connectTimeout = connectTimeout; | |||
downloader = new BaseHttpDownloader(settings.getProperties(), null); | |||
} | |||
@@ -97,7 +112,7 @@ public class DefaultHttpDownloader extends HttpDownloader { | |||
@Override | |||
protected String readString(URI uri, Charset charset) { | |||
try { | |||
return CharStreams.toString(CharStreams.newReaderSupplier(downloader.newInputSupplier(uri, this.readTimeout), charset)); | |||
return CharStreams.toString(CharStreams.newReaderSupplier(downloader.newInputSupplier(uri, this.connectTimeout, this.readTimeout), charset)); | |||
} catch (IOException e) { | |||
throw failToDownload(uri, e); | |||
} | |||
@@ -111,7 +126,7 @@ public class DefaultHttpDownloader extends HttpDownloader { | |||
@Override | |||
public byte[] download(URI uri) { | |||
try { | |||
return ByteStreams.toByteArray(downloader.newInputSupplier(uri, this.readTimeout)); | |||
return ByteStreams.toByteArray(downloader.newInputSupplier(uri, this.connectTimeout, this.readTimeout)); | |||
} catch (IOException e) { | |||
throw failToDownload(uri, e); | |||
} | |||
@@ -124,7 +139,7 @@ public class DefaultHttpDownloader extends HttpDownloader { | |||
@Override | |||
public InputStream openStream(URI uri) { | |||
try { | |||
return downloader.newInputSupplier(uri, this.readTimeout).getInput(); | |||
return downloader.newInputSupplier(uri, this.connectTimeout, this.readTimeout).getInput(); | |||
} catch (IOException e) { | |||
throw failToDownload(uri, e); | |||
} | |||
@@ -133,7 +148,7 @@ public class DefaultHttpDownloader extends HttpDownloader { | |||
@Override | |||
public void download(URI uri, File toFile) { | |||
try { | |||
Files.copy(downloader.newInputSupplier(uri, this.readTimeout), toFile); | |||
Files.copy(downloader.newInputSupplier(uri, this.connectTimeout, this.readTimeout), toFile); | |||
} catch (IOException e) { | |||
FileUtils.deleteQuietly(toFile); | |||
throw failToDownload(uri, e); | |||
@@ -213,18 +228,29 @@ public class DefaultHttpDownloader extends HttpDownloader { | |||
} | |||
public InputSupplier<InputStream> newInputSupplier(URI uri) { | |||
return new HttpInputSupplier(uri, GET, userAgent, null, null, TIMEOUT_MILLISECONDS); | |||
return newInputSupplier(uri, GET, null, null, null, null); | |||
} | |||
public InputSupplier<InputStream> newInputSupplier(URI uri, @Nullable Integer readTimeoutMillis) { | |||
return newInputSupplier(uri, GET, readTimeoutMillis); | |||
} | |||
/** | |||
* @since 5.2 | |||
*/ | |||
public InputSupplier<InputStream> newInputSupplier(URI uri, @Nullable Integer connectTimeoutMillis, @Nullable Integer readTimeoutMillis) { | |||
return newInputSupplier(uri, GET, connectTimeoutMillis, readTimeoutMillis); | |||
} | |||
/** | |||
* @since 5.2 | |||
*/ | |||
public InputSupplier<InputStream> newInputSupplier(URI uri, String requestMethod, @Nullable Integer connectTimeoutMillis, @Nullable Integer readTimeoutMillis) { | |||
return newInputSupplier(uri, requestMethod, null, null, connectTimeoutMillis, readTimeoutMillis); | |||
} | |||
public InputSupplier<InputStream> newInputSupplier(URI uri, String requestMethod, @Nullable Integer readTimeoutMillis) { | |||
if (readTimeoutMillis != null) { | |||
return new HttpInputSupplier(uri, requestMethod, userAgent, null, null, readTimeoutMillis); | |||
} | |||
return new HttpInputSupplier(uri, requestMethod, userAgent, null, null, TIMEOUT_MILLISECONDS); | |||
return newInputSupplier(uri, requestMethod, null, null, null, readTimeoutMillis); | |||
} | |||
public InputSupplier<InputStream> newInputSupplier(URI uri, String login, String password) { | |||
@@ -235,7 +261,7 @@ public class DefaultHttpDownloader extends HttpDownloader { | |||
* @since 5.0 | |||
*/ | |||
public InputSupplier<InputStream> newInputSupplier(URI uri, String requestMethod, String login, String password) { | |||
return new HttpInputSupplier(uri, requestMethod, userAgent, login, password, TIMEOUT_MILLISECONDS); | |||
return newInputSupplier(uri, requestMethod, login, password, null, null); | |||
} | |||
public InputSupplier<InputStream> newInputSupplier(URI uri, String login, String password, @Nullable Integer readTimeoutMillis) { | |||
@@ -246,10 +272,17 @@ public class DefaultHttpDownloader extends HttpDownloader { | |||
* @since 5.0 | |||
*/ | |||
public InputSupplier<InputStream> newInputSupplier(URI uri, String requestMethod, String login, String password, @Nullable Integer readTimeoutMillis) { | |||
if (readTimeoutMillis != null) { | |||
return new HttpInputSupplier(uri, requestMethod, userAgent, login, password, readTimeoutMillis); | |||
} | |||
return new HttpInputSupplier(uri, requestMethod, userAgent, login, password, TIMEOUT_MILLISECONDS); | |||
return newInputSupplier(uri, requestMethod, login, password, null, readTimeoutMillis); | |||
} | |||
/** | |||
* @since 5.2 | |||
*/ | |||
public InputSupplier<InputStream> newInputSupplier(URI uri, String requestMethod, String login, String password, @Nullable Integer connectTimeoutMillis, | |||
@Nullable Integer readTimeoutMillis) { | |||
int read = readTimeoutMillis != null ? readTimeoutMillis : TIMEOUT_MILLISECONDS; | |||
int connect = connectTimeoutMillis != null ? connectTimeoutMillis : TIMEOUT_MILLISECONDS; | |||
return new HttpInputSupplier(uri, requestMethod, userAgent, login, password, connect, read); | |||
} | |||
private static class HttpInputSupplier implements InputSupplier<InputStream> { | |||
@@ -257,22 +290,27 @@ public class DefaultHttpDownloader extends HttpDownloader { | |||
private final String password; | |||
private final URI uri; | |||
private final String userAgent; | |||
private final int connectTimeoutMillis; | |||
private final int readTimeoutMillis; | |||
private final String requestMethod; | |||
HttpInputSupplier(URI uri, String requestMethod, String userAgent, String login, String password, int readTimeoutMillis) { | |||
HttpInputSupplier(URI uri, String requestMethod, String userAgent, String login, String password, int connectTimeoutMillis, int readTimeoutMillis) { | |||
this.uri = uri; | |||
this.requestMethod = requestMethod; | |||
this.userAgent = userAgent; | |||
this.login = login; | |||
this.password = password; | |||
this.readTimeoutMillis = readTimeoutMillis; | |||
this.connectTimeoutMillis = connectTimeoutMillis; | |||
} | |||
/** | |||
* @throws IOException any I/O error, not limited to the network connection | |||
* @throws HttpException if HTTP response code > 400 | |||
*/ | |||
@Override | |||
public InputStream getInput() throws IOException { | |||
Loggers.get(getClass()).debug("Download: " + uri + " (" + getProxySynthesis(uri, ProxySelector.getDefault()) + ")"); | |||
HttpURLConnection connection = (HttpURLConnection) uri.toURL().openConnection(); | |||
connection.setRequestMethod(requestMethod); | |||
HttpsTrust.INSTANCE.trust(connection); | |||
@@ -283,7 +321,7 @@ public class DefaultHttpDownloader extends HttpDownloader { | |||
String encoded = Base64.encodeBase64String((login + ":" + password).getBytes(StandardCharsets.UTF_8)); | |||
connection.setRequestProperty("Authorization", "Basic " + encoded); | |||
} | |||
connection.setConnectTimeout(TIMEOUT_MILLISECONDS); | |||
connection.setConnectTimeout(connectTimeoutMillis); | |||
connection.setReadTimeout(readTimeoutMillis); | |||
connection.setUseCaches(true); | |||
connection.setInstanceFollowRedirects(true); |
@@ -33,6 +33,7 @@ import java.nio.charset.StandardCharsets; | |||
import java.util.Arrays; | |||
import java.util.Properties; | |||
import java.util.zip.GZIPOutputStream; | |||
import org.hamcrest.BaseMatcher; | |||
import org.hamcrest.Description; | |||
import org.junit.AfterClass; | |||
@@ -51,7 +52,6 @@ import org.simpleframework.transport.connect.SocketConnection; | |||
import org.sonar.api.config.Settings; | |||
import org.sonar.api.platform.Server; | |||
import org.sonar.api.utils.SonarException; | |||
import static org.assertj.core.api.Assertions.assertThat; | |||
import static org.mockito.Matchers.any; | |||
import static org.mockito.Mockito.mock; | |||
@@ -123,6 +123,25 @@ public class DefaultHttpDownloaderTest { | |||
} | |||
} | |||
@Test(timeout = 10000) | |||
public void readStringConnectTimeout() throws IOException, URISyntaxException { | |||
// non routable address | |||
String url = "http://10.255.255.1"; | |||
thrown.expect(new BaseMatcher<Exception>() { | |||
@Override | |||
public boolean matches(Object ex) { | |||
return ex instanceof SonarException && ((SonarException) ex).getCause() instanceof SocketTimeoutException; | |||
} | |||
@Override | |||
public void describeTo(Description arg0) { | |||
} | |||
}); | |||
DefaultHttpDownloader downloader = new DefaultHttpDownloader(new Settings(), 10, 50000); | |||
downloader.openStream(new URI(url)); | |||
} | |||
@Test | |||
public void downloadBytes() throws URISyntaxException { | |||
byte[] bytes = new DefaultHttpDownloader(new Settings()).readBytes(new URI(baseUrl)); |
@@ -32,7 +32,6 @@ import java.nio.file.Path; | |||
import java.nio.file.attribute.BasicFileAttributes; | |||
import java.security.MessageDigest; | |||
import java.security.NoSuchAlgorithmException; | |||
import java.util.concurrent.Callable; | |||
import javax.annotation.CheckForNull; | |||
import javax.annotation.Nonnull; | |||
import javax.annotation.Nullable; | |||
@@ -51,25 +50,18 @@ public class PersistentCache { | |||
// eviction strategy is to expire entries after modification once a time duration has elapsed | |||
private final long defaultDurationToExpireMs; | |||
private boolean forceUpdate; | |||
private final Logger logger; | |||
public PersistentCache(Path baseDir, long defaultDurationToExpireMs, boolean forceUpdate, Logger logger) { | |||
public PersistentCache(Path baseDir, long defaultDurationToExpireMs, Logger logger) { | |||
this.baseDir = baseDir; | |||
this.defaultDurationToExpireMs = defaultDurationToExpireMs; | |||
this.logger = logger; | |||
reconfigure(forceUpdate); | |||
reconfigure(); | |||
logger.debug("cache: " + baseDir + ", default expiration time (ms): " + defaultDurationToExpireMs); | |||
} | |||
public void reconfigure(boolean forceUpdate) { | |||
this.forceUpdate = forceUpdate; | |||
if (forceUpdate) { | |||
logger.debug("cache: forcing update"); | |||
} | |||
public void reconfigure() { | |||
try { | |||
Files.createDirectories(baseDir); | |||
} catch (IOException e) { | |||
@@ -81,16 +73,12 @@ public class PersistentCache { | |||
return baseDir; | |||
} | |||
public boolean isForceUpdate() { | |||
return forceUpdate; | |||
} | |||
@CheckForNull | |||
public synchronized String getString(@Nonnull String obj, @Nullable final Callable<String> valueLoader) throws Exception { | |||
byte[] cached = get(obj, new Callable<byte[]>() { | |||
public synchronized String getString(@Nonnull String obj, @Nullable final PersistentCacheLoader<String> valueLoader) throws IOException { | |||
byte[] cached = get(obj, new PersistentCacheLoader<byte[]>() { | |||
@Override | |||
public byte[] call() throws Exception { | |||
String s = valueLoader.call(); | |||
public byte[] get() throws IOException { | |||
String s = valueLoader.get(); | |||
if (s != null) { | |||
return s.getBytes(ENCODING); | |||
} | |||
@@ -106,26 +94,23 @@ public class PersistentCache { | |||
} | |||
@CheckForNull | |||
public synchronized byte[] get(@Nonnull String obj, @Nullable Callable<byte[]> valueLoader) throws Exception { | |||
public synchronized byte[] get(@Nonnull String obj, @Nullable PersistentCacheLoader<byte[]> valueLoader) throws IOException { | |||
String key = getKey(obj); | |||
try { | |||
lock(); | |||
if (!forceUpdate) { | |||
byte[] cached = getCache(key); | |||
if (cached != null) { | |||
logger.debug("cache hit for " + obj + " -> " + key); | |||
return cached; | |||
} | |||
byte[] cached = getCache(key); | |||
logger.debug("cache miss for " + obj + " -> " + key); | |||
} else { | |||
logger.debug("cache force update for " + obj + " -> " + key); | |||
if (cached != null) { | |||
logger.debug("cache hit for " + obj + " -> " + key); | |||
return cached; | |||
} | |||
logger.debug("cache miss for " + obj + " -> " + key); | |||
if (valueLoader != null) { | |||
byte[] value = valueLoader.call(); | |||
byte[] value = valueLoader.get(); | |||
if (value != null) { | |||
putCache(key, value); | |||
} | |||
@@ -138,6 +123,16 @@ public class PersistentCache { | |||
return null; | |||
} | |||
public synchronized void put(@Nonnull String obj, @Nonnull byte[] value) throws IOException { | |||
String key = getKey(obj); | |||
try { | |||
lock(); | |||
putCache(key, value); | |||
} finally { | |||
unlock(); | |||
} | |||
} | |||
/** | |||
* Deletes all cache entries | |||
*/ |
@@ -28,7 +28,6 @@ public class PersistentCacheBuilder { | |||
private static final long DEFAULT_EXPIRE_DURATION = TimeUnit.MILLISECONDS.convert(1L, TimeUnit.DAYS); | |||
private static final String DIR_NAME = "ws_cache"; | |||
private boolean forceUpdate = false; | |||
private Path cachePath; | |||
private final Logger logger; | |||
@@ -41,7 +40,7 @@ public class PersistentCacheBuilder { | |||
setSonarHome(findHome()); | |||
} | |||
return new PersistentCache(cachePath, DEFAULT_EXPIRE_DURATION, forceUpdate, logger); | |||
return new PersistentCache(cachePath, DEFAULT_EXPIRE_DURATION, logger); | |||
} | |||
public PersistentCacheBuilder setSonarHome(@Nullable Path p) { | |||
@@ -51,11 +50,6 @@ public class PersistentCacheBuilder { | |||
return this; | |||
} | |||
public PersistentCacheBuilder forceUpdate(boolean update) { | |||
this.forceUpdate = update; | |||
return this; | |||
} | |||
private static Path findHome() { | |||
String home = System.getenv("SONAR_USER_HOME"); | |||
@@ -0,0 +1,26 @@ | |||
/* | |||
* SonarQube, open source software quality management tool. | |||
* Copyright (C) 2008-2014 SonarSource | |||
* mailto:contact AT sonarsource DOT com | |||
* | |||
* SonarQube is free software; you can redistribute it and/or | |||
* modify it under the terms of the GNU Lesser General Public | |||
* License as published by the Free Software Foundation; either | |||
* version 3 of the License, or (at your option) any later version. | |||
* | |||
* SonarQube is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||
* Lesser General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU Lesser General Public License | |||
* along with this program; if not, write to the Free Software Foundation, | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
package org.sonar.home.cache; | |||
import java.io.IOException; | |||
public interface PersistentCacheLoader<T> { | |||
T get() throws IOException; | |||
} |
@@ -20,7 +20,6 @@ | |||
package org.sonar.home.cache; | |||
import java.io.File; | |||
import java.util.concurrent.Callable; | |||
import org.apache.commons.io.FileUtils; | |||
import org.junit.Before; | |||
import org.junit.Rule; | |||
@@ -42,7 +41,7 @@ public class PersistentCacheTest { | |||
@Before | |||
public void setUp() { | |||
cache = new PersistentCache(tmp.getRoot().toPath(), Long.MAX_VALUE, false, mock(Logger.class)); | |||
cache = new PersistentCache(tmp.getRoot().toPath(), Long.MAX_VALUE, mock(Logger.class)); | |||
} | |||
@Test | |||
@@ -59,9 +58,9 @@ public class PersistentCacheTest { | |||
@Test | |||
public void testNullValue() throws Exception { | |||
// mocks have their methods returning null by default | |||
Callable<byte[]> c = mock(Callable.class); | |||
PersistentCacheLoader<byte[]> c = mock(PersistentCacheLoader.class); | |||
assertThat(cache.get(URI, c)).isNull(); | |||
verify(c).call(); | |||
verify(c).get(); | |||
assertCacheHit(false); | |||
} | |||
@@ -78,30 +77,17 @@ public class PersistentCacheTest { | |||
assertCacheHit(true); | |||
} | |||
@Test | |||
public void testForceUpdate() throws Exception { | |||
cache = new PersistentCache(tmp.getRoot().toPath(), Long.MAX_VALUE, true, mock(Logger.class)); | |||
assertCacheHit(false); | |||
assertCacheHit(false); | |||
assertCacheHit(false); | |||
// with forceUpdate, it should still have cached the last call | |||
cache = new PersistentCache(tmp.getRoot().toPath(), Long.MAX_VALUE, false, mock(Logger.class)); | |||
assertCacheHit(true); | |||
} | |||
@Test | |||
public void testReconfigure() throws Exception { | |||
cache = new PersistentCache(tmp.getRoot().toPath(), Long.MAX_VALUE, true, mock(Logger.class)); | |||
assertCacheHit(false); | |||
cache = new PersistentCache(tmp.getRoot().toPath(), Long.MAX_VALUE, mock(Logger.class)); | |||
assertCacheHit(false); | |||
assertCacheHit(true); | |||
File root = tmp.getRoot(); | |||
FileUtils.deleteQuietly(root); | |||
// should re-create cache directory and start using the cache | |||
cache.reconfigure(false); | |||
cache.reconfigure(); | |||
assertThat(root).exists(); | |||
assertCacheHit(false); | |||
@@ -111,7 +97,7 @@ public class PersistentCacheTest { | |||
@Test | |||
public void testExpiration() throws Exception { | |||
// negative time to make sure it is expired on the second call | |||
cache = new PersistentCache(tmp.getRoot().toPath(), -100, false, mock(Logger.class)); | |||
cache = new PersistentCache(tmp.getRoot().toPath(), -100, mock(Logger.class)); | |||
assertCacheHit(false); | |||
assertCacheHit(false); | |||
} | |||
@@ -122,11 +108,11 @@ public class PersistentCacheTest { | |||
assertThat(c.wasCalled).isEqualTo(!hit); | |||
} | |||
private class CacheFillerString implements Callable<String> { | |||
private class CacheFillerString implements PersistentCacheLoader<String> { | |||
public boolean wasCalled = false; | |||
@Override | |||
public String call() throws Exception { | |||
public String get() { | |||
wasCalled = true; | |||
return VALUE; | |||
} | |||
@@ -139,8 +125,8 @@ public class PersistentCacheTest { | |||
*/ | |||
@Test(expected = ArithmeticException.class) | |||
public void testExceptions() throws Exception { | |||
Callable<byte[]> c = mock(Callable.class); | |||
when(c.call()).thenThrow(ArithmeticException.class); | |||
PersistentCacheLoader<byte[]> c = mock(PersistentCacheLoader.class); | |||
when(c.get()).thenThrow(ArithmeticException.class); | |||
cache.get(URI, c); | |||
} | |||
@@ -446,6 +446,11 @@ public interface CoreProperties { | |||
* @since 4.0 | |||
*/ | |||
String ANALYSIS_MODE_PREVIEW = "preview"; | |||
/** | |||
* @since 5.2 | |||
*/ | |||
String ANALYSIS_MODE_QUICK = "quick"; | |||
/** | |||
* @since 4.0 |
@@ -29,5 +29,7 @@ public interface AnalysisMode { | |||
boolean isPreview(); | |||
boolean isIncremental(); | |||
boolean isQuick(); | |||
} |
@@ -230,6 +230,7 @@ public class SensorContextTester implements SensorContext { | |||
public static class MockAnalysisMode implements AnalysisMode { | |||
private boolean isIncremental = false; | |||
private boolean isPreview = false; | |||
private boolean isSingle = false; | |||
@Override | |||
public boolean isIncremental() { | |||
@@ -248,6 +249,15 @@ public class SensorContextTester implements SensorContext { | |||
public void setPreview(boolean value) { | |||
this.isPreview = value; | |||
} | |||
@Override | |||
public boolean isQuick() { | |||
return this.isSingle; | |||
} | |||
public void setSingle(boolean single) { | |||
this.isSingle = single; | |||
} | |||
} | |||
private static class InMemorySensorStorage implements SensorStorage { |