From da0e7d2eb596eeed136301cdaa38523ff8c86d54 Mon Sep 17 00:00:00 2001 From: Duarte Meneses Date: Thu, 6 Aug 2015 14:38:53 +0200 Subject: [PATCH] SONAR-6777 Project cache sync --- .../protocol/input/ProjectRepositories.java | 4 + .../batch/bootstrap/GlobalContainer.java | 39 +- ...vider.java => GlobalWSLoaderProvider.java} | 13 +- .../sonar/batch/bootstrap/ServerClient.java | 2 - .../org/sonar/batch/bootstrap/WSLoader.java | 78 +- .../org/sonar/batch/bootstrapper/Batch.java | 15 + .../sonar/batch/cache/ProjectCacheStatus.java | 83 + .../batch/cache/ProjectCacheSynchronizer.java | 118 + .../batch/cache/ProjectSyncContainer.java | 84 + .../batch/cache/StrategyWSLoaderProvider.java | 45 + .../batch/issue/DefaultIssueCallback.java | 10 +- .../batch/mediumtest/FakePluginInstaller.java | 1 + .../DefaultProjectRepositoriesLoader.java | 12 +- .../repository/ProjectRepositoriesLoader.java | 5 +- .../ProjectRepositoriesProvider.java | 2 +- ...ository.java => UserRepositoryLoader.java} | 33 +- .../sonar/batch/scan/ProjectAnalysisMode.java | 5 +- .../batch/scan/ProjectScanContainer.java | 25 +- .../batch/scan/ProjectWSLoaderProvider.java | 15 +- .../sonar/batch/scan/report/JSONReport.java | 8 +- ...t.java => GlobalWSLoaderProviderTest.java} | 21 +- .../sonar/batch/bootstrap/WSLoaderTest.java | 65 +- .../bootstrap/WSLoaderTestWithServer.java | 34 +- .../batch/cache/ProjectCacheStatusTest.java | 71 + .../batch/issue/DefaultIssueCallbackTest.java | 8 +- .../DefaultServerLineHashesLoaderTest.java | 4 +- .../batch/mediumtest/BatchMediumTester.java | 10 +- .../batch/mediumtest/cache/CacheSyncTest.java | 76 + .../EmptyFileTest.java | 2 +- .../IssueModeAndReportsMediumTest.java | 2 +- .../DefaultProjectRepositoriesLoaderTest.java | 41 +- ...est.java => UserRepositoryLoaderTest.java} | 10 +- ....java => ProjectWSLoaderProviderTest.java} | 5 +- .../batch/scan/report/JSONReportTest.java | 8 +- .../sample_response.json | 2093 +++++++++++++++++ .../core/platform/ComponentContainer.java | 9 + .../java/org/sonar/api/CoreProperties.java | 4 + 37 files changed, 2824 insertions(+), 236 deletions(-) rename sonar-batch/src/main/java/org/sonar/batch/bootstrap/{WSLoaderGlobalProvider.java => GlobalWSLoaderProvider.java} (79%) create mode 100644 sonar-batch/src/main/java/org/sonar/batch/cache/ProjectCacheStatus.java create mode 100644 sonar-batch/src/main/java/org/sonar/batch/cache/ProjectCacheSynchronizer.java create mode 100644 sonar-batch/src/main/java/org/sonar/batch/cache/ProjectSyncContainer.java create mode 100644 sonar-batch/src/main/java/org/sonar/batch/cache/StrategyWSLoaderProvider.java rename sonar-batch/src/main/java/org/sonar/batch/repository/user/{UserRepository.java => UserRepositoryLoader.java} (73%) rename sonar-batch/src/test/java/org/sonar/batch/bootstrap/{WSLoaderGlobalProviderTest.java => GlobalWSLoaderProviderTest.java} (74%) create mode 100644 sonar-batch/src/test/java/org/sonar/batch/cache/ProjectCacheStatusTest.java rename sonar-batch/src/{main => test}/java/org/sonar/batch/mediumtest/BatchMediumTester.java (98%) create mode 100644 sonar-batch/src/test/java/org/sonar/batch/mediumtest/cache/CacheSyncTest.java rename sonar-batch/src/test/java/org/sonar/batch/mediumtest/{preview => issuesmode}/EmptyFileTest.java (98%) rename sonar-batch/src/test/java/org/sonar/batch/mediumtest/{preview => issuesmode}/IssueModeAndReportsMediumTest.java (99%) rename sonar-batch/src/test/java/org/sonar/batch/repository/user/{UserRepositoryTest.java => UserRepositoryLoaderTest.java} (84%) rename sonar-batch/src/test/java/org/sonar/batch/scan/{WSLoaderProjectProviderTest.java => ProjectWSLoaderProviderTest.java} (94%) create mode 100644 sonar-batch/src/test/resources/org/sonar/batch/repository/DefaultProjectRepositoriesLoaderTest/sample_response.json diff --git a/sonar-batch-protocol/src/main/java/org/sonar/batch/protocol/input/ProjectRepositories.java b/sonar-batch-protocol/src/main/java/org/sonar/batch/protocol/input/ProjectRepositories.java index 9cff3783ede..8e59ccd1be7 100644 --- a/sonar-batch-protocol/src/main/java/org/sonar/batch/protocol/input/ProjectRepositories.java +++ b/sonar-batch-protocol/src/main/java/org/sonar/batch/protocol/input/ProjectRepositories.java @@ -74,6 +74,10 @@ public class ProjectRepositories { return this; } + public Map> fileDataByModuleAndPath() { + return fileDataByModuleAndPath; + } + public Map fileDataByPath(String moduleKey) { return fileDataByModuleAndPath.containsKey(moduleKey) ? fileDataByModuleAndPath.get(moduleKey) : Collections.emptyMap(); } diff --git a/sonar-batch/src/main/java/org/sonar/batch/bootstrap/GlobalContainer.java b/sonar-batch/src/main/java/org/sonar/batch/bootstrap/GlobalContainer.java index 882aa173e48..feab390e969 100644 --- a/sonar-batch/src/main/java/org/sonar/batch/bootstrap/GlobalContainer.java +++ b/sonar-batch/src/main/java/org/sonar/batch/bootstrap/GlobalContainer.java @@ -19,8 +19,10 @@ */ package org.sonar.batch.bootstrap; -import org.sonar.batch.rule.RulesLoader; +import org.sonar.batch.scan.ProjectAnalysisMode; +import org.sonar.batch.cache.ProjectSyncContainer; +import org.sonar.batch.rule.RulesLoader; import org.sonar.batch.rule.DefaultRulesLoader; import org.sonar.batch.rule.RulesProvider; @@ -33,17 +35,10 @@ import org.sonar.api.utils.Durations; import org.sonar.api.utils.System2; import org.sonar.api.utils.UriReader; import org.sonar.batch.index.CachesManager; -import org.sonar.batch.issue.tracking.DefaultServerLineHashesLoader; -import org.sonar.batch.issue.tracking.ServerLineHashesLoader; import org.sonar.batch.platform.DefaultServer; import org.sonar.batch.repository.DefaultGlobalRepositoriesLoader; -import org.sonar.batch.repository.DefaultProjectRepositoriesLoader; -import org.sonar.batch.repository.DefaultServerIssuesLoader; import org.sonar.batch.repository.GlobalRepositoriesLoader; import org.sonar.batch.repository.GlobalRepositoriesProvider; -import org.sonar.batch.repository.ProjectRepositoriesLoader; -import org.sonar.batch.repository.ServerIssuesLoader; -import org.sonar.batch.repository.user.UserRepository; import org.sonar.batch.scan.ProjectScanContainer; import org.sonar.core.config.Logback; import org.sonar.core.i18n.DefaultI18n; @@ -99,25 +94,15 @@ public class GlobalContainer extends ComponentContainer { UriReader.class, new FileCacheProvider(), new PersistentCacheProvider(), - new WSLoaderGlobalProvider(), + new GlobalWSLoaderProvider(), System2.INSTANCE, DefaultI18n.class, Durations.class, RuleI18nManager.class, - new GlobalRepositoriesProvider(), - UserRepository.class); + new GlobalRepositoriesProvider()); addIfMissing(BatchPluginInstaller.class, PluginInstaller.class); addIfMissing(DefaultRulesLoader.class, RulesLoader.class); addIfMissing(DefaultGlobalRepositoriesLoader.class, GlobalRepositoriesLoader.class); - addIfMissing(DefaultProjectRepositoriesLoader.class, ProjectRepositoriesLoader.class); - addIfMissing(DefaultServerIssuesLoader.class, ServerIssuesLoader.class); - addIfMissing(DefaultServerLineHashesLoader.class, ServerLineHashesLoader.class); - } - - public void addIfMissing(Object object, Class objectType) { - if (getComponentByType(objectType) == null) { - add(object); - } } @Override @@ -135,6 +120,20 @@ public class GlobalContainer extends ComponentContainer { public void executeAnalysis(Map analysisProperties, Object... components) { AnalysisProperties props = new AnalysisProperties(analysisProperties, this.getComponentByType(BootstrapProperties.class).property(CoreProperties.ENCRYPTION_SECRET_KEY_PATH)); + if (isIssuesMode(props)) { + new ProjectSyncContainer(this, props, false).execute(); + } new ProjectScanContainer(this, props, components).execute(); } + + public void syncProject(Map analysisProperties, boolean force) { + AnalysisProperties props = new AnalysisProperties(analysisProperties, this.getComponentByType(BootstrapProperties.class).property(CoreProperties.ENCRYPTION_SECRET_KEY_PATH)); + new ProjectSyncContainer(this, props, force).execute(); + } + + private boolean isIssuesMode(AnalysisProperties props) { + ProjectAnalysisMode mode = new ProjectAnalysisMode(this.getComponentByType(BootstrapProperties.class), props); + return mode.isIssues(); + } + } diff --git a/sonar-batch/src/main/java/org/sonar/batch/bootstrap/WSLoaderGlobalProvider.java b/sonar-batch/src/main/java/org/sonar/batch/bootstrap/GlobalWSLoaderProvider.java similarity index 79% rename from sonar-batch/src/main/java/org/sonar/batch/bootstrap/WSLoaderGlobalProvider.java rename to sonar-batch/src/main/java/org/sonar/batch/bootstrap/GlobalWSLoaderProvider.java index 71826511f1d..f89c4a3afed 100644 --- a/sonar-batch/src/main/java/org/sonar/batch/bootstrap/WSLoaderGlobalProvider.java +++ b/sonar-batch/src/main/java/org/sonar/batch/bootstrap/GlobalWSLoaderProvider.java @@ -22,23 +22,16 @@ 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; +public class GlobalWSLoaderProvider extends ProviderAdapter { + private static final LoadStrategy DEFAULT_STRATEGY = LoadStrategy.SERVER_ONLY; private WSLoader wsLoader; public WSLoader provide(BootstrapProperties props, GlobalMode mode, PersistentCache cache, ServerClient client) { if (wsLoader == null) { - wsLoader = new WSLoader(isCacheEnabled(props.properties(), mode), cache, client); - wsLoader.setStrategy(DEFAULT_STRATEGY); + wsLoader = new WSLoader(DEFAULT_STRATEGY, cache, client); } return wsLoader; } - - private static boolean isCacheEnabled(Map props, GlobalMode mode) { - return mode.isIssues(); - } } diff --git a/sonar-batch/src/main/java/org/sonar/batch/bootstrap/ServerClient.java b/sonar-batch/src/main/java/org/sonar/batch/bootstrap/ServerClient.java index a205a01c81b..ef24962e6a8 100644 --- a/sonar-batch/src/main/java/org/sonar/batch/bootstrap/ServerClient.java +++ b/sonar-batch/src/main/java/org/sonar/batch/bootstrap/ServerClient.java @@ -19,8 +19,6 @@ */ 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; diff --git a/sonar-batch/src/main/java/org/sonar/batch/bootstrap/WSLoader.java b/sonar-batch/src/main/java/org/sonar/batch/bootstrap/WSLoader.java index e6fb470395a..f231b473a1d 100644 --- a/sonar-batch/src/main/java/org/sonar/batch/bootstrap/WSLoader.java +++ b/sonar-batch/src/main/java/org/sonar/batch/bootstrap/WSLoader.java @@ -48,27 +48,21 @@ public class WSLoader { } public enum LoadStrategy { - SERVER_FIRST, CACHE_FIRST; + SERVER_FIRST, CACHE_FIRST, SERVER_ONLY, CACHE_ONLY; } 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; + public WSLoader(LoadStrategy strategy, PersistentCache cache, ServerClient client) { + this.loadStrategy = strategy; this.serverStatus = UNKNOWN; this.cache = cache; this.client = client; } - public WSLoader(PersistentCache cache, ServerClient client) { - this(false, cache, client); - } - @Nonnull public WSLoaderResult loadSource(String id) { WSLoaderResult byteResult = load(id); @@ -83,29 +77,23 @@ public class WSLoader { @Nonnull public WSLoaderResult load(String id) { - if (loadStrategy == CACHE_FIRST) { - return loadFromCacheFirst(id); - } else { - return loadFromServerFirst(id); + switch (loadStrategy) { + case CACHE_FIRST: + return loadFromCacheFirst(id, true); + case CACHE_ONLY: + return loadFromCacheFirst(id, false); + case SERVER_FIRST: + return loadFromServerFirst(id, true); + case SERVER_ONLY: + default: + return loadFromServerFirst(id, false); } } - 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() { LOG.debug("server not available - switching to offline mode"); serverStatus = NOT_ACCESSIBLE; @@ -120,47 +108,47 @@ public class WSLoader { } private void updateCache(String id, byte[] value) { - if (cacheEnabled) { - try { - cache.put(client.getURI(id).toString(), value); - } catch (IOException e) { - LOG.warn("Error saving to WS cache", e); - } + try { + cache.put(client.getURI(id).toString(), value); + } catch (IOException e) { + LOG.warn("Error saving to WS cache", e); } } @Nonnull - private WSLoaderResult loadFromCacheFirst(String id) { + private WSLoaderResult loadFromCacheFirst(String id, boolean fallback) { try { return loadFromCache(id); } catch (NotAvailableException cacheNotAvailable) { - try { - return loadFromServer(id); - } catch (NotAvailableException serverNotAvailable) { - throw new IllegalStateException(FAIL_MSG, serverNotAvailable.getCause()); + if (fallback) { + try { + return loadFromServer(id); + } catch (NotAvailableException serverNotAvailable) { + throw new IllegalStateException(FAIL_MSG, serverNotAvailable.getCause()); + } } + throw new IllegalStateException(FAIL_MSG, cacheNotAvailable.getCause()); } } @Nonnull - private WSLoaderResult loadFromServerFirst(String id) { + private WSLoaderResult loadFromServerFirst(String id, boolean fallback) { try { return loadFromServer(id); } catch (NotAvailableException serverNotAvailable) { - try { - return loadFromCache(id); - } catch (NotAvailableException cacheNotAvailable) { - throw new IllegalStateException(FAIL_MSG, serverNotAvailable.getCause()); + if (fallback) { + try { + return loadFromCache(id); + } catch (NotAvailableException cacheNotAvailable) { + throw new IllegalStateException(FAIL_MSG, serverNotAvailable.getCause()); + } } + throw new IllegalStateException(FAIL_MSG, serverNotAvailable.getCause()); } } @Nonnull private WSLoaderResult loadFromCache(String id) throws NotAvailableException { - if (!cacheEnabled) { - throw new NotAvailableException("cache disabled"); - } - try { byte[] result = cache.get(client.getURI(id).toString(), null); if (result == null) { diff --git a/sonar-batch/src/main/java/org/sonar/batch/bootstrapper/Batch.java b/sonar-batch/src/main/java/org/sonar/batch/bootstrapper/Batch.java index d28ff6cf2ac..12e564c5fcd 100644 --- a/sonar-batch/src/main/java/org/sonar/batch/bootstrapper/Batch.java +++ b/sonar-batch/src/main/java/org/sonar/batch/bootstrapper/Batch.java @@ -19,11 +19,16 @@ */ package org.sonar.batch.bootstrapper; +import com.google.common.collect.ImmutableMap; + +import org.sonar.api.CoreProperties; import com.google.common.collect.Lists; import com.google.common.collect.Maps; + import java.util.Collections; import java.util.List; import java.util.Map; + import org.picocontainer.annotations.Nullable; import org.sonar.batch.bootstrap.GlobalContainer; @@ -120,6 +125,16 @@ public final class Batch { } } + /** + * @since 5.2 + */ + public Batch syncProject(String projectKey) { + checkStarted(); + Map props = ImmutableMap.of(CoreProperties.PROJECT_KEY_PROPERTY, projectKey); + bootstrapContainer.syncProject(props, true); + return this; + } + /** * @since 4.4 */ diff --git a/sonar-batch/src/main/java/org/sonar/batch/cache/ProjectCacheStatus.java b/sonar-batch/src/main/java/org/sonar/batch/cache/ProjectCacheStatus.java new file mode 100644 index 00000000000..d36e0b427ad --- /dev/null +++ b/sonar-batch/src/main/java/org/sonar/batch/cache/ProjectCacheStatus.java @@ -0,0 +1,83 @@ +/* + * 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.cache; + +import org.sonar.batch.bootstrap.ServerClient; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.util.Date; + +import org.sonar.home.cache.PersistentCache; + +public class ProjectCacheStatus { + private static final String STATUS_PREFIX = "cache-sync-status-"; + private PersistentCache cache; + private ServerClient client; + + public ProjectCacheStatus(PersistentCache cache, ServerClient client) { + this.cache = cache; + this.client = client; + } + + public void save(String projectKey) { + Date now = new Date(); + + try { + ByteArrayOutputStream byteOutput = new ByteArrayOutputStream(); + try (ObjectOutputStream objOutput = new ObjectOutputStream(byteOutput)) { + objOutput.writeObject(now); + } + cache.put(getKey(projectKey), byteOutput.toByteArray()); + } catch (IOException e) { + throw new IllegalStateException("Failed to write cache sync status", e); + } + } + + public void delete(String projectKey) { + try { + cache.put(getKey(projectKey), new byte[0]); + } catch (IOException e) { + throw new IllegalStateException("Failed to delete cache sync status", e); + } + } + + public Date getSyncStatus(String projectKey) { + try { + byte[] status = cache.get(getKey(projectKey), null); + if (status == null || status.length == 0) { + return null; + } + ByteArrayInputStream byteInput = new ByteArrayInputStream(status); + try (ObjectInputStream objInput = new ObjectInputStream(byteInput)) { + return (Date) objInput.readObject(); + } + } catch (IOException | ClassNotFoundException e) { + throw new IllegalStateException("Failed to read cache sync status", e); + } + } + + private String getKey(String projectKey) { + return STATUS_PREFIX + client.getURL() + projectKey; + } +} diff --git a/sonar-batch/src/main/java/org/sonar/batch/cache/ProjectCacheSynchronizer.java b/sonar-batch/src/main/java/org/sonar/batch/cache/ProjectCacheSynchronizer.java new file mode 100644 index 00000000000..2854dce0985 --- /dev/null +++ b/sonar-batch/src/main/java/org/sonar/batch/cache/ProjectCacheSynchronizer.java @@ -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.cache; + +import org.sonar.api.batch.bootstrap.ProjectReactor; + +import org.sonar.batch.bootstrap.AnalysisProperties; +import org.sonar.api.utils.log.Logger; +import org.sonar.api.utils.log.Loggers; +import org.sonar.batch.protocol.input.BatchInput.ServerIssue; +import com.google.common.base.Function; +import org.sonar.batch.protocol.input.FileData; + +import java.util.Date; +import java.util.HashSet; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; + +import org.sonar.batch.protocol.input.ProjectRepositories; +import org.sonar.api.batch.bootstrap.ProjectDefinition; +import org.sonar.batch.repository.user.UserRepositoryLoader; +import org.sonar.batch.issue.tracking.ServerLineHashesLoader; +import org.sonar.batch.repository.ServerIssuesLoader; +import org.sonar.batch.repository.ProjectRepositoriesLoader; + +public class ProjectCacheSynchronizer { + private static final Logger LOG = Loggers.get(ProjectCacheSynchronizer.class); + private ProjectDefinition project; + private AnalysisProperties properties; + private ProjectRepositoriesLoader projectRepositoryLoader; + private ServerIssuesLoader issuesLoader; + private ServerLineHashesLoader lineHashesLoader; + private UserRepositoryLoader userRepository; + private ProjectCacheStatus cacheStatus; + + public ProjectCacheSynchronizer(ProjectReactor project, ProjectRepositoriesLoader projectRepositoryLoader, AnalysisProperties properties, + ServerIssuesLoader issuesLoader, ServerLineHashesLoader lineHashesLoader, UserRepositoryLoader userRepository, ProjectCacheStatus cacheStatus) { + this.project = project.getRoot(); + this.projectRepositoryLoader = projectRepositoryLoader; + this.properties = properties; + this.issuesLoader = issuesLoader; + this.lineHashesLoader = lineHashesLoader; + this.userRepository = userRepository; + this.cacheStatus = cacheStatus; + } + + public void load(boolean force) { + Date lastSync = cacheStatus.getSyncStatus(project.getKeyWithBranch()); + + if (lastSync != null) { + LOG.debug("Found project [" + project.getKeyWithBranch() + " ] cache [" + lastSync + "]"); + + if (!force) { + return; + } + } + + cacheStatus.delete(project.getKeyWithBranch()); + ProjectRepositories projectRepo = projectRepositoryLoader.load(project, properties); + + if (projectRepo.lastAnalysisDate() == null) { + return; + } + + IssueAccumulator consumer = new IssueAccumulator(); + issuesLoader.load(project.getKeyWithBranch(), consumer, false); + + for (String login : consumer.loginSet) { + userRepository.load(login); + } + + loadLineHashes(projectRepo.fileDataByModuleAndPath()); + cacheStatus.save(project.getKeyWithBranch()); + } + + private String getComponentKey(String moduleKey, String filePath) { + return moduleKey + ":" + filePath; + } + + private void loadLineHashes(Map> fileDataByModuleAndPath) { + for (Entry> e1 : fileDataByModuleAndPath.entrySet()) { + String moduleKey = e1.getKey(); + + for (Entry e2 : e1.getValue().entrySet()) { + String filePath = e2.getKey(); + lineHashesLoader.getLineHashes(getComponentKey(moduleKey, filePath)); + } + } + } + + private static class IssueAccumulator implements Function { + Set loginSet = new HashSet<>(); + + @Override + public Void apply(ServerIssue input) { + loginSet.add(input.getAssigneeLogin()); + return null; + } + } +} diff --git a/sonar-batch/src/main/java/org/sonar/batch/cache/ProjectSyncContainer.java b/sonar-batch/src/main/java/org/sonar/batch/cache/ProjectSyncContainer.java new file mode 100644 index 00000000000..4be7ab575f4 --- /dev/null +++ b/sonar-batch/src/main/java/org/sonar/batch/cache/ProjectSyncContainer.java @@ -0,0 +1,84 @@ +/* + * 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.cache; + +import org.sonar.batch.scan.ProjectAnalysisMode; + +import org.apache.commons.lang.StringUtils; +import org.sonar.batch.bootstrap.WSLoader.LoadStrategy; +import org.sonar.api.CoreProperties; +import org.sonar.api.batch.bootstrap.ProjectReactor; +import org.sonar.batch.bootstrap.AnalysisProperties; +import org.sonar.batch.repository.user.UserRepositoryLoader; +import org.sonar.batch.issue.tracking.ServerLineHashesLoader; +import org.sonar.batch.repository.DefaultProjectRepositoriesLoader; +import org.sonar.batch.repository.DefaultServerIssuesLoader; +import org.sonar.batch.repository.ProjectRepositoriesLoader; +import org.sonar.batch.repository.ServerIssuesLoader; +import org.sonar.api.batch.bootstrap.ProjectDefinition; +import org.sonar.batch.issue.tracking.DefaultServerLineHashesLoader; +import org.sonar.core.platform.ComponentContainer; + +public class ProjectSyncContainer extends ComponentContainer { + private final boolean force; + private final AnalysisProperties properties; + + public ProjectSyncContainer(ComponentContainer globalContainer, AnalysisProperties analysisProperties, boolean force) { + super(globalContainer); + this.properties = analysisProperties; + this.force = force; + } + + @Override + protected void doBeforeStart() { + ProjectReactor projectReactor = createSimpleProjectReactor(); + add(projectReactor); + addComponents(); + } + + private ProjectReactor createSimpleProjectReactor() { + ProjectDefinition rootProjDefinition = ProjectDefinition.create(); + String projectKey = properties.property(CoreProperties.PROJECT_KEY_PROPERTY); + if (StringUtils.isEmpty(projectKey)) { + throw new IllegalStateException("Missing mandatory property: " + CoreProperties.PROJECT_KEY_PROPERTY); + } + rootProjDefinition.setKey(projectKey); + return new ProjectReactor(rootProjDefinition); + } + + @Override + public void doAfterStart() { + getComponentByType(ProjectCacheSynchronizer.class).load(force); + } + + private void addComponents() { + add(new StrategyWSLoaderProvider(LoadStrategy.SERVER_FIRST), + properties, + ProjectAnalysisMode.class, + ProjectCacheStatus.class, + ProjectCacheSynchronizer.class, + UserRepositoryLoader.class); + + addIfMissing(DefaultProjectRepositoriesLoader.class, ProjectRepositoriesLoader.class); + addIfMissing(DefaultServerIssuesLoader.class, ServerIssuesLoader.class); + addIfMissing(DefaultServerLineHashesLoader.class, ServerLineHashesLoader.class); + } + +} diff --git a/sonar-batch/src/main/java/org/sonar/batch/cache/StrategyWSLoaderProvider.java b/sonar-batch/src/main/java/org/sonar/batch/cache/StrategyWSLoaderProvider.java new file mode 100644 index 00000000000..9ebfd52034a --- /dev/null +++ b/sonar-batch/src/main/java/org/sonar/batch/cache/StrategyWSLoaderProvider.java @@ -0,0 +1,45 @@ +/* + * 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.cache; + +import org.picocontainer.injectors.ProviderAdapter; + +import org.sonar.batch.bootstrap.BootstrapProperties; +import org.sonar.batch.bootstrap.GlobalMode; +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; + +public class StrategyWSLoaderProvider extends ProviderAdapter { + private final LoadStrategy strategy; + private WSLoader wsLoader; + + public StrategyWSLoaderProvider(LoadStrategy strategy) { + this.strategy = strategy; + } + + public WSLoader provide(BootstrapProperties props, GlobalMode mode, PersistentCache cache, ServerClient client) { + if (wsLoader == null) { + wsLoader = new WSLoader(strategy, cache, client); + } + return wsLoader; + } +} diff --git a/sonar-batch/src/main/java/org/sonar/batch/issue/DefaultIssueCallback.java b/sonar-batch/src/main/java/org/sonar/batch/issue/DefaultIssueCallback.java index d4284f44e47..9973b50f612 100644 --- a/sonar-batch/src/main/java/org/sonar/batch/issue/DefaultIssueCallback.java +++ b/sonar-batch/src/main/java/org/sonar/batch/issue/DefaultIssueCallback.java @@ -31,21 +31,21 @@ import java.util.HashSet; import java.util.Map; import java.util.Set; -import org.sonar.batch.repository.user.UserRepository; +import org.sonar.batch.repository.user.UserRepositoryLoader; import org.sonar.batch.bootstrapper.IssueListener; import org.sonar.core.issue.DefaultIssue; public class DefaultIssueCallback implements IssueCallback { private final IssueCache issues; private final IssueListener listener; - private final UserRepository userRepository; + private final UserRepositoryLoader userRepository; private final Rules rules; private Set userLoginNames = new HashSet<>(); private Map userMap = new HashMap<>(); private Set ruleKeys = new HashSet<>(); - public DefaultIssueCallback(IssueCache issues, IssueListener listener, UserRepository userRepository, Rules rules) { + public DefaultIssueCallback(IssueCache issues, IssueListener listener, UserRepositoryLoader userRepository, Rules rules) { this.issues = issues; this.listener = listener; this.userRepository = userRepository; @@ -55,7 +55,7 @@ public class DefaultIssueCallback implements IssueCallback { /** * If no listener exists, this constructor will be used by pico. */ - public DefaultIssueCallback(IssueCache issues, UserRepository userRepository, Rules rules) { + public DefaultIssueCallback(IssueCache issues, UserRepositoryLoader userRepository, Rules rules) { this(issues, null, userRepository, rules); } @@ -104,7 +104,7 @@ public class DefaultIssueCallback implements IssueCallback { } private void getUsers() { - Collection users = userRepository.loadFromWs(new ArrayList<>(userLoginNames)); + Collection users = userRepository.load(new ArrayList<>(userLoginNames)); for (User user : users) { userMap.put(user.getLogin(), user.getName()); } diff --git a/sonar-batch/src/main/java/org/sonar/batch/mediumtest/FakePluginInstaller.java b/sonar-batch/src/main/java/org/sonar/batch/mediumtest/FakePluginInstaller.java index cbd837c66c9..b77f97795e9 100644 --- a/sonar-batch/src/main/java/org/sonar/batch/mediumtest/FakePluginInstaller.java +++ b/sonar-batch/src/main/java/org/sonar/batch/mediumtest/FakePluginInstaller.java @@ -28,6 +28,7 @@ import java.util.HashMap; import java.util.Map; public class FakePluginInstaller implements PluginInstaller { + public static final String MEDIUM_TEST_ENABLED = "sonar.mediumTest.enabled"; private final Map infosByKeys = new HashMap<>(); private final Map instancesByKeys = new HashMap<>(); diff --git a/sonar-batch/src/main/java/org/sonar/batch/repository/DefaultProjectRepositoriesLoader.java b/sonar-batch/src/main/java/org/sonar/batch/repository/DefaultProjectRepositoriesLoader.java index 8a5bfe64152..d358861b21d 100644 --- a/sonar-batch/src/main/java/org/sonar/batch/repository/DefaultProjectRepositoriesLoader.java +++ b/sonar-batch/src/main/java/org/sonar/batch/repository/DefaultProjectRepositoriesLoader.java @@ -19,12 +19,12 @@ */ package org.sonar.batch.repository; -import org.sonar.batch.bootstrap.AbstractServerLoader; +import org.sonar.api.batch.bootstrap.ProjectDefinition; +import org.sonar.batch.bootstrap.AbstractServerLoader; import org.sonar.batch.bootstrap.WSLoaderResult; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.sonar.api.batch.bootstrap.ProjectReactor; import org.sonar.api.utils.MessageException; import org.sonar.batch.bootstrap.AnalysisProperties; import org.sonar.batch.bootstrap.GlobalMode; @@ -47,8 +47,8 @@ public class DefaultProjectRepositoriesLoader extends AbstractServerLoader imple } @Override - public ProjectRepositories load(ProjectReactor reactor, AnalysisProperties taskProperties) { - String projectKey = reactor.getRoot().getKeyWithBranch(); + public ProjectRepositories load(ProjectDefinition projectDefinition, AnalysisProperties taskProperties) { + String projectKey = projectDefinition.getKeyWithBranch(); 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 @@ -57,7 +57,7 @@ public class DefaultProjectRepositoriesLoader extends AbstractServerLoader imple } url += "&preview=" + globalMode.isIssues(); ProjectRepositories projectRepositories = ProjectRepositories.fromJson(load(url)); - validateProjectRepositories(projectRepositories, reactor.getRoot().getKey()); + validateProjectRepositories(projectRepositories); return projectRepositories; } @@ -67,7 +67,7 @@ public class DefaultProjectRepositoriesLoader extends AbstractServerLoader imple return result.get(); } - private static void validateProjectRepositories(ProjectRepositories projectRepositories, String projectKey) { + private static void validateProjectRepositories(ProjectRepositories projectRepositories) { if (projectRepositories.qProfiles().isEmpty()) { throw MessageException.of("No quality profiles has been found this project, you probably don't have any language plugin suitable for this analysis."); } diff --git a/sonar-batch/src/main/java/org/sonar/batch/repository/ProjectRepositoriesLoader.java b/sonar-batch/src/main/java/org/sonar/batch/repository/ProjectRepositoriesLoader.java index 1dbff7350b4..dfb3b741202 100644 --- a/sonar-batch/src/main/java/org/sonar/batch/repository/ProjectRepositoriesLoader.java +++ b/sonar-batch/src/main/java/org/sonar/batch/repository/ProjectRepositoriesLoader.java @@ -19,13 +19,14 @@ */ package org.sonar.batch.repository; -import org.sonar.api.batch.bootstrap.ProjectReactor; +import org.sonar.api.batch.bootstrap.ProjectDefinition; + import org.sonar.batch.bootstrap.AnalysisProperties; import org.sonar.batch.protocol.input.ProjectRepositories; public interface ProjectRepositoriesLoader { - ProjectRepositories load(ProjectReactor reactor, AnalysisProperties taskProperties); + ProjectRepositories load(ProjectDefinition projectDefinition, AnalysisProperties taskProperties); boolean loadedFromCache(); diff --git a/sonar-batch/src/main/java/org/sonar/batch/repository/ProjectRepositoriesProvider.java b/sonar-batch/src/main/java/org/sonar/batch/repository/ProjectRepositoriesProvider.java index aa79cc382af..27be9a46b80 100644 --- a/sonar-batch/src/main/java/org/sonar/batch/repository/ProjectRepositoriesProvider.java +++ b/sonar-batch/src/main/java/org/sonar/batch/repository/ProjectRepositoriesProvider.java @@ -38,7 +38,7 @@ public class ProjectRepositoriesProvider extends ProviderAdapter { public ProjectRepositories provide(ProjectRepositoriesLoader loader, ProjectReactor reactor, AnalysisProperties taskProps, AnalysisMode analysisMode) { if (projectReferentials == null) { Profiler profiler = Profiler.create(LOG).startInfo(LOG_MSG); - projectReferentials = loader.load(reactor, taskProps); + projectReferentials = loader.load(reactor.getRoot(), taskProps); if (loader.loadedFromCache()) { profiler.stopInfo(LOG_MSG + " (done from cache)"); diff --git a/sonar-batch/src/main/java/org/sonar/batch/repository/user/UserRepository.java b/sonar-batch/src/main/java/org/sonar/batch/repository/user/UserRepositoryLoader.java similarity index 73% rename from sonar-batch/src/main/java/org/sonar/batch/repository/user/UserRepository.java rename to sonar-batch/src/main/java/org/sonar/batch/repository/user/UserRepositoryLoader.java index a0e4c781290..43d2383b50d 100644 --- a/sonar-batch/src/main/java/org/sonar/batch/repository/user/UserRepository.java +++ b/sonar-batch/src/main/java/org/sonar/batch/repository/user/UserRepositoryLoader.java @@ -39,27 +39,38 @@ import java.util.Collection; import java.util.Collections; import java.util.List; -public class UserRepository { - private static final Logger LOG = Loggers.get(UserRepository.class); +public class UserRepositoryLoader { + private static final Logger LOG = Loggers.get(UserRepositoryLoader.class); private final WSLoader wsLoader; - public UserRepository(WSLoader wsLoader) { + public UserRepositoryLoader(WSLoader wsLoader) { this.wsLoader = wsLoader; } - - public Collection loadFromWs(List userLogins) { + + public BatchInput.User load(String userLogin) { + ByteSource byteSource = loadUsers(new UserEncodingFunction().apply(userLogin)); + return parseUser(byteSource); + } + + public Collection load(List userLogins) { if (userLogins.isEmpty()) { return Collections.emptyList(); } + ByteSource byteSource = loadUsers(Joiner.on(',').join(Lists.transform(userLogins, new UserEncodingFunction()))); + + return parseUsers(byteSource); + } + + private ByteSource loadUsers(String loginsQuery) { Profiler profiler = Profiler.create(LOG).startDebug("Load user repository"); - WSLoaderResult result = wsLoader.loadSource("/batch/users?logins=" + Joiner.on(',').join(Lists.transform(userLogins, new UserEncodingFunction()))); + WSLoaderResult result = wsLoader.loadSource("/batch/users?logins=" + loginsQuery); if (result.isFromCache()) { profiler.stopInfo("Load user repository (done from cache)"); } else { profiler.stopInfo(); } - return parseUsers(result.get()); + return result.get(); } private static class UserEncodingFunction implements Function { @@ -69,6 +80,14 @@ public class UserRepository { } } + private static BatchInput.User parseUser(ByteSource input) { + try (InputStream is = input.openStream()) { + return BatchInput.User.parseFrom(is); + } catch (IOException e) { + throw new IllegalStateException("Unable to get user details from server", e); + } + } + private static Collection parseUsers(ByteSource input) { List users = new ArrayList<>(); diff --git a/sonar-batch/src/main/java/org/sonar/batch/scan/ProjectAnalysisMode.java b/sonar-batch/src/main/java/org/sonar/batch/scan/ProjectAnalysisMode.java index 864bc9ccbda..4c66441218b 100644 --- a/sonar-batch/src/main/java/org/sonar/batch/scan/ProjectAnalysisMode.java +++ b/sonar-batch/src/main/java/org/sonar/batch/scan/ProjectAnalysisMode.java @@ -19,6 +19,8 @@ */ package org.sonar.batch.scan; +import org.sonar.batch.mediumtest.FakePluginInstaller; + import org.apache.commons.lang.StringUtils; import org.sonar.batch.bootstrap.BootstrapProperties; import org.sonar.batch.bootstrap.AnalysisProperties; @@ -26,7 +28,6 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.sonar.api.CoreProperties; import org.sonar.api.batch.AnalysisMode; -import org.sonar.batch.mediumtest.BatchMediumTester; import java.util.Map; @@ -81,7 +82,7 @@ public class ProjectAnalysisMode implements AnalysisMode { validate(mode); preview = CoreProperties.ANALYSIS_MODE_PREVIEW.equals(mode); issues = CoreProperties.ANALYSIS_MODE_ISSUES.equals(mode); - mediumTestMode = "true".equals(getPropertyWithFallback(analysisProps, globalProps, BatchMediumTester.MEDIUM_TEST_ENABLED)); + mediumTestMode = "true".equals(getPropertyWithFallback(analysisProps, globalProps, FakePluginInstaller.MEDIUM_TEST_ENABLED)); if (preview) { LOG.info("Preview mode"); diff --git a/sonar-batch/src/main/java/org/sonar/batch/scan/ProjectScanContainer.java b/sonar-batch/src/main/java/org/sonar/batch/scan/ProjectScanContainer.java index 28367ee042c..6ab4474292a 100644 --- a/sonar-batch/src/main/java/org/sonar/batch/scan/ProjectScanContainer.java +++ b/sonar-batch/src/main/java/org/sonar/batch/scan/ProjectScanContainer.java @@ -19,8 +19,16 @@ */ package org.sonar.batch.scan; +import org.sonar.batch.cache.ProjectSyncContainer; + +import org.sonar.batch.repository.user.UserRepositoryLoader; +import org.sonar.batch.issue.tracking.DefaultServerLineHashesLoader; +import org.sonar.batch.issue.tracking.ServerLineHashesLoader; +import org.sonar.batch.repository.DefaultProjectRepositoriesLoader; +import org.sonar.batch.repository.DefaultServerIssuesLoader; +import org.sonar.batch.repository.ProjectRepositoriesLoader; +import org.sonar.batch.repository.ServerIssuesLoader; import org.sonar.batch.issue.DefaultIssueCallback; - import com.google.common.annotations.VisibleForTesting; import org.sonar.api.CoreProperties; import org.sonar.api.batch.InstantiationStrategy; @@ -118,6 +126,13 @@ public class ProjectScanContainer extends ComponentContainer { return env != null && "SonarRunner".equals(env.getKey()); } + private void doProjectSync() { + ProjectAnalysisMode mode = getComponentByType(ProjectAnalysisMode.class); + if (mode.isIssues()) { + new ProjectSyncContainer(getParent(), props, false).execute(); + } + } + private void addBatchComponents() { add( props, @@ -194,7 +209,12 @@ public class ProjectScanContainer extends ComponentContainer { SourcePublisher.class, TestExecutionAndCoveragePublisher.class, - ScanTaskObservers.class); + ScanTaskObservers.class, + UserRepositoryLoader.class); + + addIfMissing(DefaultProjectRepositoriesLoader.class, ProjectRepositoriesLoader.class); + addIfMissing(DefaultServerIssuesLoader.class, ServerIssuesLoader.class); + addIfMissing(DefaultServerLineHashesLoader.class, ServerLineHashesLoader.class); } private void addBatchExtensions() { @@ -230,4 +250,5 @@ public class ProjectScanContainer extends ComponentContainer { && ExtensionUtils.isInstantiationStrategy(extension, InstantiationStrategy.PER_BATCH); } } + } diff --git a/sonar-batch/src/main/java/org/sonar/batch/scan/ProjectWSLoaderProvider.java b/sonar-batch/src/main/java/org/sonar/batch/scan/ProjectWSLoaderProvider.java index 596c6df3069..7af51a25cc8 100644 --- a/sonar-batch/src/main/java/org/sonar/batch/scan/ProjectWSLoaderProvider.java +++ b/sonar-batch/src/main/java/org/sonar/batch/scan/ProjectWSLoaderProvider.java @@ -31,29 +31,22 @@ import org.sonar.api.batch.AnalysisMode; import org.sonar.batch.bootstrap.WSLoader.LoadStrategy; public class ProjectWSLoaderProvider extends ProviderAdapter { - private static final String OPTIMIZE_STRING_PROP = "sonar.optimizeForSpeed"; private WSLoader wsLoader; public WSLoader provide(AnalysisProperties props, AnalysisMode mode, PersistentCache cache, ServerClient client) { if (wsLoader == null) { // recreate cache directory if needed for this analysis cache.reconfigure(); - wsLoader = new WSLoader(isCacheEnabled(props.properties(), mode), cache, client); - wsLoader.setStrategy(getStrategy(props.properties(), mode)); + wsLoader = new WSLoader(getStrategy(props.properties(), mode), cache, client); } return wsLoader; } private static LoadStrategy getStrategy(Map props, AnalysisMode mode) { - String optimizeForSpeed = props.get(OPTIMIZE_STRING_PROP); - if (mode.isIssues() && "true".equals(optimizeForSpeed)) { - return LoadStrategy.CACHE_FIRST; + if (mode.isIssues()) { + return LoadStrategy.CACHE_ONLY; } - return LoadStrategy.SERVER_FIRST; - } - - private static boolean isCacheEnabled(Map props, AnalysisMode mode) { - return mode.isIssues(); + return LoadStrategy.SERVER_ONLY; } } diff --git a/sonar-batch/src/main/java/org/sonar/batch/scan/report/JSONReport.java b/sonar-batch/src/main/java/org/sonar/batch/scan/report/JSONReport.java index 22c02ff6e42..30c56af99d7 100644 --- a/sonar-batch/src/main/java/org/sonar/batch/scan/report/JSONReport.java +++ b/sonar-batch/src/main/java/org/sonar/batch/scan/report/JSONReport.java @@ -51,7 +51,7 @@ import org.sonar.api.utils.SonarException; import org.sonar.api.utils.text.JsonWriter; import org.sonar.batch.issue.IssueCache; import org.sonar.batch.protocol.input.BatchInput; -import org.sonar.batch.repository.user.UserRepository; +import org.sonar.batch.repository.user.UserRepositoryLoader; import org.sonar.batch.scan.filesystem.InputPathCache; import org.sonar.core.issue.DefaultIssue; @@ -74,10 +74,10 @@ public class JSONReport implements Reporter { private final IssueCache issueCache; private final InputPathCache fileCache; private final Project rootModule; - private final UserRepository userRepository; + private final UserRepositoryLoader userRepository; public JSONReport(Settings settings, FileSystem fileSystem, Server server, Rules rules, IssueCache issueCache, - Project rootModule, InputPathCache fileCache, UserRepository userRepository) { + Project rootModule, InputPathCache fileCache, UserRepositoryLoader userRepository) { this.settings = settings; this.fileSystem = fileSystem; this.server = server; @@ -120,7 +120,7 @@ public class JSONReport implements Reporter { writeJsonIssues(json, ruleKeys, userLogins); writeJsonComponents(json); writeJsonRules(json, ruleKeys); - Collection users = userRepository.loadFromWs(new ArrayList<>(userLogins)); + Collection users = userRepository.load(new ArrayList<>(userLogins)); writeUsers(json, users); json.endObject().close(); diff --git a/sonar-batch/src/test/java/org/sonar/batch/bootstrap/WSLoaderGlobalProviderTest.java b/sonar-batch/src/test/java/org/sonar/batch/bootstrap/GlobalWSLoaderProviderTest.java similarity index 74% rename from sonar-batch/src/test/java/org/sonar/batch/bootstrap/WSLoaderGlobalProviderTest.java rename to sonar-batch/src/test/java/org/sonar/batch/bootstrap/GlobalWSLoaderProviderTest.java index 81a5fdb563f..1ae0c36ab2f 100644 --- a/sonar-batch/src/test/java/org/sonar/batch/bootstrap/WSLoaderGlobalProviderTest.java +++ b/sonar-batch/src/test/java/org/sonar/batch/bootstrap/GlobalWSLoaderProviderTest.java @@ -24,8 +24,6 @@ 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; @@ -33,7 +31,7 @@ import org.sonar.home.cache.PersistentCache; import org.mockito.Mock; import org.mockito.MockitoAnnotations; -public class WSLoaderGlobalProviderTest { +public class GlobalWSLoaderProviderTest { @Mock private PersistentCache cache; @@ -43,14 +41,14 @@ public class WSLoaderGlobalProviderTest { @Mock private GlobalMode mode; - private WSLoaderGlobalProvider loaderProvider; + private GlobalWSLoaderProvider loaderProvider; private Map propMap; private BootstrapProperties props; @Before public void setUp() { MockitoAnnotations.initMocks(this); - loaderProvider = new WSLoaderGlobalProvider(); + loaderProvider = new GlobalWSLoaderProvider(); } @Test @@ -59,18 +57,7 @@ public class WSLoaderGlobalProviderTest { props = new BootstrapProperties(propMap); WSLoader wsLoader = loaderProvider.provide(props, mode, cache, client); - assertThat(wsLoader.getStrategy()).isEqualTo(LoadStrategy.SERVER_FIRST); - assertThat(wsLoader.isCacheEnabled()).isEqualTo(false); + assertThat(wsLoader.getStrategy()).isEqualTo(LoadStrategy.SERVER_ONLY); } - @Test - public void testOffline() { - propMap = new HashMap<>(); - propMap.put("sonar.enableOffline", "true"); - when(mode.isIssues()).thenReturn(true); - props = new BootstrapProperties(propMap); - - WSLoader wsLoader = loaderProvider.provide(props, mode, cache, client); - assertThat(wsLoader.isCacheEnabled()).isEqualTo(true); - } } diff --git a/sonar-batch/src/test/java/org/sonar/batch/bootstrap/WSLoaderTest.java b/sonar-batch/src/test/java/org/sonar/batch/bootstrap/WSLoaderTest.java index 31c70e85d4b..781c1ad255c 100644 --- a/sonar-batch/src/test/java/org/sonar/batch/bootstrap/WSLoaderTest.java +++ b/sonar-batch/src/test/java/org/sonar/batch/bootstrap/WSLoaderTest.java @@ -70,10 +70,9 @@ public class WSLoaderTest { } @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); + public void dont_retry_server_offline() throws IOException { + turnServerOffline(); + WSLoader loader = new WSLoader(LoadStrategy.SERVER_FIRST, cache, client); assertResult(loader.loadString(ID), cacheValue, true); assertResult(loader.loadString(ID), cacheValue, true); @@ -86,8 +85,7 @@ public class WSLoaderTest { @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); + WSLoader loader = new WSLoader(LoadStrategy.CACHE_FIRST, cache, client); assertResult(loader.load(ID), serverValue.getBytes(), false); @@ -98,9 +96,8 @@ public class WSLoaderTest { @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); + turnServerOffline(); + WSLoader loader = new WSLoader(LoadStrategy.SERVER_FIRST, cache, client); assertResult(loader.loadString(ID), cacheValue, true); @@ -111,20 +108,16 @@ public class WSLoaderTest { @Test public void test_put_cache() throws IOException { - WSLoader loader = new WSLoader(true, cache, client); - loader.setStrategy(LoadStrategy.SERVER_FIRST); + WSLoader loader = new WSLoader(LoadStrategy.SERVER_FIRST, cache, client); 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()); + turnServerOffline(); when(cache.get(ID, null)).thenThrow(new NullPointerException()); - - WSLoader loader = new WSLoader(true, cache, client); - loader.setStrategy(LoadStrategy.SERVER_FIRST); - + WSLoader loader = new WSLoader(LoadStrategy.SERVER_FIRST, cache, client); loader.load(ID); } @@ -132,9 +125,7 @@ public class WSLoaderTest { 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); - + WSLoader loader = new WSLoader(LoadStrategy.CACHE_FIRST, cache, client); loader.load(ID); } @@ -145,8 +136,7 @@ public class WSLoaderTest { when(client.load(anyString(), anyString(), anyBoolean(), anyInt(), anyInt())).thenThrow(wrapperException); - WSLoader loader = new WSLoader(true, cache, client); - loader.setStrategy(LoadStrategy.SERVER_FIRST); + WSLoader loader = new WSLoader(LoadStrategy.SERVER_FIRST, cache, client); try { loader.load(ID); @@ -157,24 +147,9 @@ public class WSLoaderTest { } } - @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); + WSLoader loader = new WSLoader(LoadStrategy.SERVER_FIRST, cache, client); assertResult(loader.load(ID), serverValue.getBytes(), false); // should not fetch from cache @@ -182,18 +157,16 @@ public class WSLoaderTest { verifyNoMoreInteractions(cache); } - @Test - public void test_cache_disabled() throws IOException { - WSLoader loader = new WSLoader(cache, client); + @Test(expected = IllegalStateException.class) + public void test_server_only() throws IOException { + turnServerOffline(); + WSLoader loader = new WSLoader(LoadStrategy.SERVER_ONLY, cache, client); loader.load(ID); - - // should not even put - verifyNoMoreInteractions(cache); } @Test public void test_string() { - WSLoader loader = new WSLoader(cache, client); + WSLoader loader = new WSLoader(LoadStrategy.SERVER_FIRST, cache, client); assertResult(loader.loadString(ID), serverValue, false); } @@ -202,4 +175,8 @@ public class WSLoaderTest { assertThat(result.get()).isEqualTo(expected); assertThat(result.isFromCache()).isEqualTo(fromCache); } + + private void turnServerOffline() { + when(client.load(anyString(), anyString(), anyBoolean(), anyInt(), anyInt())).thenThrow(new IllegalStateException()); + } } diff --git a/sonar-batch/src/test/java/org/sonar/batch/bootstrap/WSLoaderTestWithServer.java b/sonar-batch/src/test/java/org/sonar/batch/bootstrap/WSLoaderTestWithServer.java index b99d851d321..b6582883ebc 100644 --- a/sonar-batch/src/test/java/org/sonar/batch/bootstrap/WSLoaderTestWithServer.java +++ b/sonar-batch/src/test/java/org/sonar/batch/bootstrap/WSLoaderTestWithServer.java @@ -52,7 +52,6 @@ public class WSLoaderTestWithServer { client = new ServerClient(bootstrapProps, new EnvironmentInformation("Junit", "4")); cache = new PersistentCache(temp.getRoot().toPath(), 1000 * 60, new Slf4jLogger(), null); - loader = new WSLoader(cache, client); } @After @@ -63,50 +62,41 @@ public class WSLoaderTestWithServer { } @Test - public void testServer() { - loader.setCacheEnabled(false); - loader.setStrategy(LoadStrategy.SERVER_FIRST); - server.setMockResponseData(RESPONSE_STRING); - assertThat(loader.loadString("/foo")).isEqualTo(RESPONSE_STRING); - } + public void testCacheOnly() { + loader = new WSLoader(LoadStrategy.SERVER_ONLY, cache, client); + makeRequests(); - @Test - public void testCacheDisabled() { - loader.setCacheEnabled(false); - loader.setStrategy(LoadStrategy.CACHE_FIRST); + loader = new WSLoader(LoadStrategy.CACHE_ONLY, cache, client); makeRequests(); assertThat(server.getNumberRequests()).isEqualTo(3); } @Test - public void testCacheEnabled() { - loader.setCacheEnabled(true); - loader.setStrategy(LoadStrategy.CACHE_FIRST); + public void testCacheFirst() { + loader = new WSLoader(LoadStrategy.CACHE_FIRST, cache, client); makeRequests(); assertThat(server.getNumberRequests()).isEqualTo(1); } @Test - public void testServerStrategy() { - loader.setCacheEnabled(true); - loader.setStrategy(LoadStrategy.SERVER_FIRST); + public void testServerFirst() { + loader = new WSLoader(LoadStrategy.SERVER_FIRST, cache, client); makeRequests(); assertThat(server.getNumberRequests()).isEqualTo(3); } @Test public void testCacheStrategyDisabled() { - loader.setCacheEnabled(false); - loader.setStrategy(LoadStrategy.CACHE_FIRST); + loader = new WSLoader(LoadStrategy.SERVER_ONLY, cache, client); 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); + assertThat(loader.loadString("/foo").get()).isEqualTo(RESPONSE_STRING); + assertThat(loader.loadString("/foo").get()).isEqualTo(RESPONSE_STRING); + assertThat(loader.loadString("/foo").get()).isEqualTo(RESPONSE_STRING); } } diff --git a/sonar-batch/src/test/java/org/sonar/batch/cache/ProjectCacheStatusTest.java b/sonar-batch/src/test/java/org/sonar/batch/cache/ProjectCacheStatusTest.java new file mode 100644 index 00000000000..2b6c4491f62 --- /dev/null +++ b/sonar-batch/src/test/java/org/sonar/batch/cache/ProjectCacheStatusTest.java @@ -0,0 +1,71 @@ +/* + * 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.cache; + +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; +import static org.assertj.core.api.Assertions.assertThat; + +import java.util.Date; + +import org.junit.Test; +import org.sonar.home.cache.Logger; +import org.junit.rules.TemporaryFolder; +import org.junit.Rule; +import org.junit.Before; +import org.sonar.batch.bootstrap.ServerClient; +import org.sonar.home.cache.PersistentCache; + +public class ProjectCacheStatusTest { + private static final String PROJ_KEY = "project1"; + @Rule + public TemporaryFolder tmp = new TemporaryFolder(); + + ProjectCacheStatus cacheStatus; + PersistentCache cache; + ServerClient client; + + @Before + public void setUp() { + cache = new PersistentCache(tmp.getRoot().toPath(), Long.MAX_VALUE, mock(Logger.class), null); + client = mock(ServerClient.class); + when(client.getURL()).thenReturn("localhost"); + cacheStatus = new ProjectCacheStatus(cache, client); + } + + @Test + public void testSave() { + cacheStatus.save(PROJ_KEY); + assertThat(cacheStatus.getSyncStatus(PROJ_KEY)).isNotNull(); + assertThat(age(cacheStatus.getSyncStatus(PROJ_KEY))).isLessThan(2000); + assertThat(cacheStatus.getSyncStatus(PROJ_KEY+"1")).isNull(); + } + + @Test + public void testDelete() { + cacheStatus.save(PROJ_KEY); + cacheStatus.delete(PROJ_KEY); + assertThat(cacheStatus.getSyncStatus(PROJ_KEY)).isNull(); + } + + private long age(Date date) { + return (new Date().getTime()) - date.getTime(); + } +} diff --git a/sonar-batch/src/test/java/org/sonar/batch/issue/DefaultIssueCallbackTest.java b/sonar-batch/src/test/java/org/sonar/batch/issue/DefaultIssueCallbackTest.java index 1ecf5353fab..41d5bddfbca 100644 --- a/sonar-batch/src/test/java/org/sonar/batch/issue/DefaultIssueCallbackTest.java +++ b/sonar-batch/src/test/java/org/sonar/batch/issue/DefaultIssueCallbackTest.java @@ -28,7 +28,7 @@ import org.sonar.batch.protocol.input.BatchInput; import org.mockito.MockitoAnnotations; import org.mockito.Mock; import org.sonar.api.batch.rule.Rules; -import org.sonar.batch.repository.user.UserRepository; +import org.sonar.batch.repository.user.UserRepositoryLoader; import org.sonar.batch.bootstrapper.IssueListener; import org.junit.Before; import com.google.common.collect.ImmutableList; @@ -47,7 +47,7 @@ public class DefaultIssueCallbackTest { @Mock private IssueCache issueCache; @Mock - private UserRepository userRepository; + private UserRepositoryLoader userRepository; @Mock private Rules rules; @@ -68,7 +68,7 @@ public class DefaultIssueCallbackTest { BatchInput.User.Builder userBuilder = BatchInput.User.newBuilder(); userBuilder.setLogin("user"); userBuilder.setName("name"); - when(userRepository.loadFromWs(anyListOf(String.class))).thenReturn(ImmutableList.of(userBuilder.build())); + when(userRepository.load(anyListOf(String.class))).thenReturn(ImmutableList.of(userBuilder.build())); Rule r = mock(Rule.class); when(r.name()).thenReturn("rule name"); @@ -128,7 +128,7 @@ public class DefaultIssueCallbackTest { } }; - when(userRepository.loadFromWs(anyListOf(String.class))).thenReturn(new LinkedList()); + when(userRepository.load(anyListOf(String.class))).thenReturn(new LinkedList()); when(rules.find(any(RuleKey.class))).thenReturn(null); DefaultIssueCallback issueCallback = new DefaultIssueCallback(issueCache, listener, userRepository, rules); diff --git a/sonar-batch/src/test/java/org/sonar/batch/issue/tracking/DefaultServerLineHashesLoaderTest.java b/sonar-batch/src/test/java/org/sonar/batch/issue/tracking/DefaultServerLineHashesLoaderTest.java index d1880ef7d3c..c7e2a40c04e 100644 --- a/sonar-batch/src/test/java/org/sonar/batch/issue/tracking/DefaultServerLineHashesLoaderTest.java +++ b/sonar-batch/src/test/java/org/sonar/batch/issue/tracking/DefaultServerLineHashesLoaderTest.java @@ -49,7 +49,7 @@ public class DefaultServerLineHashesLoaderTest { @Test public void should_download_source_from_ws_if_preview_mode() { WSLoader wsLoader = mock(WSLoader.class); - when(wsLoader.loadString(anyString())).thenReturn(new WSLoaderResult("ae12\n\n43fb", true)); + when(wsLoader.loadString(anyString())).thenReturn(new WSLoaderResult<>("ae12\n\n43fb", true)); ServerLineHashesLoader lastSnapshots = new DefaultServerLineHashesLoader(wsLoader); @@ -61,7 +61,7 @@ public class DefaultServerLineHashesLoaderTest { @Test public void should_download_source_with_space_from_ws_if_preview_mode() { WSLoader server = mock(WSLoader.class); - when(server.loadString(anyString())).thenReturn(new WSLoaderResult("ae12\n\n43fb", true)); + when(server.loadString(anyString())).thenReturn(new WSLoaderResult<>("ae12\n\n43fb", true)); ServerLineHashesLoader lastSnapshots = new DefaultServerLineHashesLoader(server); diff --git a/sonar-batch/src/main/java/org/sonar/batch/mediumtest/BatchMediumTester.java b/sonar-batch/src/test/java/org/sonar/batch/mediumtest/BatchMediumTester.java similarity index 98% rename from sonar-batch/src/main/java/org/sonar/batch/mediumtest/BatchMediumTester.java rename to sonar-batch/src/test/java/org/sonar/batch/mediumtest/BatchMediumTester.java index 09c41cf4dcb..522d8b5fa1a 100644 --- a/sonar-batch/src/main/java/org/sonar/batch/mediumtest/BatchMediumTester.java +++ b/sonar-batch/src/test/java/org/sonar/batch/mediumtest/BatchMediumTester.java @@ -19,8 +19,8 @@ */ package org.sonar.batch.mediumtest; +import org.sonar.api.batch.bootstrap.ProjectDefinition; import org.sonarqube.ws.Rules.ListResponse.Rule; - import org.sonar.batch.bootstrapper.IssueListener; import org.sonar.api.server.rule.RulesDefinition.Repository; import org.sonar.api.server.rule.RulesDefinition; @@ -43,7 +43,6 @@ import java.util.Properties; import org.sonar.api.CoreProperties; import org.sonar.api.SonarPlugin; -import org.sonar.api.batch.bootstrap.ProjectReactor; import org.sonar.api.batch.debt.internal.DefaultDebtModel; import org.sonar.api.measures.CoreMetrics; import org.sonar.api.measures.Metric; @@ -196,6 +195,7 @@ public class BatchMediumTester { serverLineHashes.byKey.put(fileKey, lineHashes); return this; } + } public void start() { @@ -206,6 +206,10 @@ public class BatchMediumTester { batch.stop(); } + public void syncProject(String projectKey) { + batch.syncProject(projectKey); + } + private BatchMediumTester(BatchMediumTesterBuilder builder) { batch = Batch.builder() .setEnableLoggingConfiguration(true) @@ -341,7 +345,7 @@ public class BatchMediumTester { private ProjectRepositories ref = new ProjectRepositories(); @Override - public ProjectRepositories load(ProjectReactor reactor, AnalysisProperties taskProperties) { + public ProjectRepositories load(ProjectDefinition projDefinition, AnalysisProperties taskProperties) { return ref; } diff --git a/sonar-batch/src/test/java/org/sonar/batch/mediumtest/cache/CacheSyncTest.java b/sonar-batch/src/test/java/org/sonar/batch/mediumtest/cache/CacheSyncTest.java new file mode 100644 index 00000000000..581c32789dc --- /dev/null +++ b/sonar-batch/src/test/java/org/sonar/batch/mediumtest/cache/CacheSyncTest.java @@ -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.mediumtest.cache; + +import org.sonar.batch.protocol.input.FileData; + +import org.junit.Test; +import org.junit.Rule; +import com.google.common.collect.ImmutableMap; +import org.junit.After; +import org.sonar.api.CoreProperties; +import org.sonar.batch.mediumtest.BatchMediumTester; +import org.sonar.batch.protocol.input.ActiveRule; +import org.sonar.xoo.XooPlugin; +import org.sonar.xoo.rule.XooRulesDefinition; + +import java.util.Date; + +import org.junit.rules.TemporaryFolder; + +public class CacheSyncTest { + + @Rule + public TemporaryFolder temp = new TemporaryFolder(); + + public BatchMediumTester tester; + + @After + public void stop() { + if (tester != null) { + tester.stop(); + tester = null; + } + } + + @Test + public void testSyncFirstTime() { + FileData file1 = new FileData("hash", true); + String[] hashes = new String[] { + "line1", "line2" + }; + + tester = BatchMediumTester.builder() + .bootstrapProperties(ImmutableMap.of(CoreProperties.ANALYSIS_MODE, CoreProperties.ANALYSIS_MODE_ISSUES)) + .registerPlugin("xoo", new XooPlugin()) + .addRules(new XooRulesDefinition()) + .activateRule(new ActiveRule("xoo", "OneIssuePerLine", null, "One issue per line", "MAJOR", "my/internal/key", "xoo")) + .setPreviousAnalysisDate(new Date()) + .addFileData("test-project", "file1", file1) + .mockLineHashes("test-project:file1", hashes) + .build(); + + tester.start(); + tester.syncProject("test-project"); + + + } + +} diff --git a/sonar-batch/src/test/java/org/sonar/batch/mediumtest/preview/EmptyFileTest.java b/sonar-batch/src/test/java/org/sonar/batch/mediumtest/issuesmode/EmptyFileTest.java similarity index 98% rename from sonar-batch/src/test/java/org/sonar/batch/mediumtest/preview/EmptyFileTest.java rename to sonar-batch/src/test/java/org/sonar/batch/mediumtest/issuesmode/EmptyFileTest.java index f6849c64756..03e11861bd0 100644 --- a/sonar-batch/src/test/java/org/sonar/batch/mediumtest/preview/EmptyFileTest.java +++ b/sonar-batch/src/test/java/org/sonar/batch/mediumtest/issuesmode/EmptyFileTest.java @@ -17,7 +17,7 @@ * 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.mediumtest.preview; +package org.sonar.batch.mediumtest.issuesmode; import org.apache.commons.io.filefilter.FileFilterUtils; diff --git a/sonar-batch/src/test/java/org/sonar/batch/mediumtest/preview/IssueModeAndReportsMediumTest.java b/sonar-batch/src/test/java/org/sonar/batch/mediumtest/issuesmode/IssueModeAndReportsMediumTest.java similarity index 99% rename from sonar-batch/src/test/java/org/sonar/batch/mediumtest/preview/IssueModeAndReportsMediumTest.java rename to sonar-batch/src/test/java/org/sonar/batch/mediumtest/issuesmode/IssueModeAndReportsMediumTest.java index 92743b4f125..9b0a4a7a643 100644 --- a/sonar-batch/src/test/java/org/sonar/batch/mediumtest/preview/IssueModeAndReportsMediumTest.java +++ b/sonar-batch/src/test/java/org/sonar/batch/mediumtest/issuesmode/IssueModeAndReportsMediumTest.java @@ -17,7 +17,7 @@ * 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.mediumtest.preview; +package org.sonar.batch.mediumtest.issuesmode; import com.google.common.collect.ImmutableMap; diff --git a/sonar-batch/src/test/java/org/sonar/batch/repository/DefaultProjectRepositoriesLoaderTest.java b/sonar-batch/src/test/java/org/sonar/batch/repository/DefaultProjectRepositoriesLoaderTest.java index 2d667f8d039..32f5fe36f59 100644 --- a/sonar-batch/src/test/java/org/sonar/batch/repository/DefaultProjectRepositoriesLoaderTest.java +++ b/sonar-batch/src/test/java/org/sonar/batch/repository/DefaultProjectRepositoriesLoaderTest.java @@ -19,18 +19,20 @@ */ package org.sonar.batch.repository; +import org.apache.commons.io.IOUtils; import org.sonar.batch.bootstrap.WSLoaderResult; - import com.google.common.collect.Maps; +import java.io.IOException; import java.util.Date; +import static org.assertj.core.api.Assertions.assertThat; + import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; import org.sonar.api.batch.bootstrap.ProjectDefinition; -import org.sonar.api.batch.bootstrap.ProjectReactor; import org.sonar.api.utils.MessageException; import org.sonar.batch.bootstrap.AnalysisProperties; import org.sonar.batch.bootstrap.GlobalMode; @@ -52,7 +54,7 @@ public class DefaultProjectRepositoriesLoaderTest { private DefaultProjectRepositoriesLoader loader; private WSLoader wsLoader; private GlobalMode globalMode; - private ProjectReactor reactor; + private ProjectDefinition project; private AnalysisProperties taskProperties; @Before @@ -68,30 +70,43 @@ public class DefaultProjectRepositoriesLoaderTest { @Test public void passPreviewParameter() { addQualityProfile(); - reactor = new ProjectReactor(ProjectDefinition.create().setKey("foo")); - when(globalMode.isPreview()).thenReturn(false); - loader.load(reactor, taskProperties); + project = ProjectDefinition.create().setKey("foo"); + when(globalMode.isIssues()).thenReturn(false); + loader.load(project, taskProperties); verify(wsLoader).loadString("/batch/project?key=foo&preview=false"); when(globalMode.isIssues()).thenReturn(true); - loader.load(reactor, taskProperties); + loader.load(project, taskProperties); verify(wsLoader).loadString("/batch/project?key=foo&preview=true"); } + @Test + public void deserializeResponse() throws IOException { + String resourceName = this.getClass().getSimpleName() + "/sample_response.json"; + String response = IOUtils.toString(this.getClass().getResourceAsStream(resourceName)); + when(wsLoader.loadString(anyString())).thenReturn(new WSLoaderResult<>(response, false)); + project = ProjectDefinition.create().setKey("foo"); + ProjectRepositories projectRepo = loader.load(project, taskProperties); + + assertThat(projectRepo.activeRules().size()).isEqualTo(221); + assertThat(projectRepo.fileDataByPath("my:project").size()).isEqualTo(11); + + } + @Test public void passAndEncodeProjectKeyParameter() { addQualityProfile(); - reactor = new ProjectReactor(ProjectDefinition.create().setKey("foo bàr")); - loader.load(reactor, taskProperties); + project = ProjectDefinition.create().setKey("foo bàr"); + loader.load(project, taskProperties); verify(wsLoader).loadString("/batch/project?key=foo+b%C3%A0r&preview=false"); } @Test public void passAndEncodeProfileParameter() { addQualityProfile(); - reactor = new ProjectReactor(ProjectDefinition.create().setKey("foo")); + project = ProjectDefinition.create().setKey("foo"); taskProperties.properties().put(ModuleQProfiles.SONAR_PROFILE_PROP, "my-profile#2"); - loader.load(reactor, taskProperties); + loader.load(project, taskProperties); verify(wsLoader).loadString("/batch/project?key=foo&profile=my-profile%232&preview=false"); } @@ -100,10 +115,10 @@ public class DefaultProjectRepositoriesLoaderTest { thrown.expect(MessageException.class); thrown.expectMessage("No quality profiles has been found this project, you probably don't have any language plugin suitable for this analysis."); - reactor = new ProjectReactor(ProjectDefinition.create().setKey("foo")); + project = ProjectDefinition.create().setKey("foo"); when(wsLoader.loadString(anyString())).thenReturn(new WSLoaderResult<>(new ProjectRepositories().toJson(), true)); - loader.load(reactor, taskProperties); + loader.load(project, taskProperties); } private void addQualityProfile() { diff --git a/sonar-batch/src/test/java/org/sonar/batch/repository/user/UserRepositoryTest.java b/sonar-batch/src/test/java/org/sonar/batch/repository/user/UserRepositoryLoaderTest.java similarity index 84% rename from sonar-batch/src/test/java/org/sonar/batch/repository/user/UserRepositoryTest.java rename to sonar-batch/src/test/java/org/sonar/batch/repository/user/UserRepositoryLoaderTest.java index 4aa5c91153d..bd0b3e7af88 100644 --- a/sonar-batch/src/test/java/org/sonar/batch/repository/user/UserRepositoryTest.java +++ b/sonar-batch/src/test/java/org/sonar/batch/repository/user/UserRepositoryLoaderTest.java @@ -40,14 +40,14 @@ import static org.assertj.core.api.Assertions.tuple; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; -public class UserRepositoryTest { +public class UserRepositoryLoaderTest { @Rule public final ExpectedException exception = ExpectedException.none(); @Test public void testLoad() throws IOException { WSLoader wsLoader = mock(WSLoader.class); - UserRepository userRepo = new UserRepository(wsLoader); + UserRepositoryLoader userRepo = new UserRepositoryLoader(wsLoader); ByteArrayOutputStream out = new ByteArrayOutputStream(); BatchInput.User.Builder builder = BatchInput.User.newBuilder(); @@ -58,13 +58,13 @@ public class UserRepositoryTest { when(wsLoader.loadSource("/batch/users?logins=fmallet,sbrandhof")).thenReturn(new WSLoaderResult<>(source, true)); 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")); + assertThat(userRepo.load(Arrays.asList("fmallet", "sbrandhof"))).extracting("login", "name").containsOnly(tuple("fmallet", "Freddy Mallet"), tuple("sbrandhof", "Simon")); } @Test public void testInputStreamError() throws IOException { WSLoader wsLoader = mock(WSLoader.class); - UserRepository userRepo = new UserRepository(wsLoader); + UserRepositoryLoader userRepo = new UserRepositoryLoader(wsLoader); ByteSource source = mock(ByteSource.class); when(wsLoader.loadSource("/batch/users?logins=fmallet,sbrandhof")).thenReturn(new WSLoaderResult<>(source, true)); @@ -75,6 +75,6 @@ public class UserRepositoryTest { exception.expect(IllegalStateException.class); exception.expectMessage("Unable to get user details from server"); - assertThat(userRepo.loadFromWs(Arrays.asList("fmallet", "sbrandhof"))).extracting("login", "name").containsOnly(tuple("fmallet", "Freddy Mallet"), tuple("sbrandhof", "Simon")); + assertThat(userRepo.load(Arrays.asList("fmallet", "sbrandhof"))).extracting("login", "name").containsOnly(tuple("fmallet", "Freddy Mallet"), tuple("sbrandhof", "Simon")); } } diff --git a/sonar-batch/src/test/java/org/sonar/batch/scan/WSLoaderProjectProviderTest.java b/sonar-batch/src/test/java/org/sonar/batch/scan/ProjectWSLoaderProviderTest.java similarity index 94% rename from sonar-batch/src/test/java/org/sonar/batch/scan/WSLoaderProjectProviderTest.java rename to sonar-batch/src/test/java/org/sonar/batch/scan/ProjectWSLoaderProviderTest.java index c0366c40af6..d4fe0b2e109 100644 --- a/sonar-batch/src/test/java/org/sonar/batch/scan/WSLoaderProjectProviderTest.java +++ b/sonar-batch/src/test/java/org/sonar/batch/scan/ProjectWSLoaderProviderTest.java @@ -35,7 +35,7 @@ import java.util.Map; import static org.assertj.core.api.Assertions.assertThat; -public class WSLoaderProjectProviderTest { +public class ProjectWSLoaderProviderTest { @Mock private PersistentCache cache; @@ -61,7 +61,6 @@ public class WSLoaderProjectProviderTest { 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); + assertThat(loader.getStrategy()).isEqualTo(LoadStrategy.SERVER_ONLY); } } diff --git a/sonar-batch/src/test/java/org/sonar/batch/scan/report/JSONReportTest.java b/sonar-batch/src/test/java/org/sonar/batch/scan/report/JSONReportTest.java index 74f2fa77106..a5392d36288 100644 --- a/sonar-batch/src/test/java/org/sonar/batch/scan/report/JSONReportTest.java +++ b/sonar-batch/src/test/java/org/sonar/batch/scan/report/JSONReportTest.java @@ -46,7 +46,7 @@ import org.sonar.api.resources.Resource; import org.sonar.api.rule.RuleKey; import org.sonar.batch.issue.IssueCache; import org.sonar.batch.protocol.input.BatchInput; -import org.sonar.batch.repository.user.UserRepository; +import org.sonar.batch.repository.user.UserRepositoryLoader; import org.sonar.batch.scan.filesystem.InputPathCache; import org.sonar.core.issue.DefaultIssue; import org.sonar.test.JsonAssert; @@ -71,7 +71,7 @@ public class JSONReportTest { Rules rules = mock(Rules.class); Settings settings = new Settings(); IssueCache issueCache = mock(IssueCache.class); - private UserRepository userRepository; + private UserRepositoryLoader userRepository; @Before public void before() throws Exception { @@ -79,7 +79,7 @@ public class JSONReportTest { SIMPLE_DATE_FORMAT.setTimeZone(TimeZone.getTimeZone("GMT+02:00")); when(resource.getEffectiveKey()).thenReturn("Action.java"); when(server.getVersion()).thenReturn("3.6"); - userRepository = mock(UserRepository.class); + userRepository = mock(UserRepositoryLoader.class); DefaultInputDir inputDir = new DefaultInputDir("struts", "src/main/java/org/apache/struts"); DefaultInputFile inputFile = new DefaultInputFile("struts", "src/main/java/org/apache/struts/Action.java"); inputFile.setStatus(InputFile.Status.CHANGED); @@ -118,7 +118,7 @@ public class JSONReportTest { when(issueCache.all()).thenReturn(Lists.newArrayList(issue)); BatchInput.User user1 = BatchInput.User.newBuilder().setLogin("julien").setName("Julien").build(); BatchInput.User user2 = BatchInput.User.newBuilder().setLogin("simon").setName("Simon").build(); - when(userRepository.loadFromWs(anyListOf(String.class))).thenReturn(Lists.newArrayList(user1, user2)); + when(userRepository.load(anyListOf(String.class))).thenReturn(Lists.newArrayList(user1, user2)); StringWriter writer = new StringWriter(); jsonReport.writeJson(writer); diff --git a/sonar-batch/src/test/resources/org/sonar/batch/repository/DefaultProjectRepositoriesLoaderTest/sample_response.json b/sonar-batch/src/test/resources/org/sonar/batch/repository/DefaultProjectRepositoriesLoaderTest/sample_response.json new file mode 100644 index 00000000000..24522c42e15 --- /dev/null +++ b/sonar-batch/src/test/resources/org/sonar/batch/repository/DefaultProjectRepositoriesLoaderTest/sample_response.json @@ -0,0 +1,2093 @@ +{ + "timestamp": 0, + "qprofilesByLanguage": { + "java": { + "key": "java-sonar-way-95117", + "name": "Sonar way", + "language": "java", + "rulesUpdatedAt": "2015-08-06T17:02:00+0200" + } + }, + "activeRules": [ + { + "repositoryKey": "common-java", + "ruleKey": "DuplicatedBlocks", + "name": "Source files should not have any duplicated blocks", + "severity": "MAJOR", + "language": "java", + "params": {} + }, + { + "repositoryKey": "common-java", + "ruleKey": "InsufficientBranchCoverage", + "name": "Branches should have sufficient coverage by unit tests", + "severity": "MAJOR", + "language": "java", + "params": { + "minimumBranchCoverageRatio": "65.0" + } + }, + { + "repositoryKey": "squid", + "ruleKey": "S00105", + "name": "Tabulation characters should not be used", + "severity": "MINOR", + "internalKey": "S00105", + "language": "java", + "params": {} + }, + { + "repositoryKey": "squid", + "ruleKey": "MethodCyclomaticComplexity", + "name": "Methods should not be too complex", + "severity": "MAJOR", + "internalKey": "MethodCyclomaticComplexity", + "language": "java", + "params": { + "Threshold": "10" + } + }, + { + "repositoryKey": "squid", + "ruleKey": "ClassCyclomaticComplexity", + "name": "Classes should not be too complex", + "severity": "MAJOR", + "internalKey": "ClassCyclomaticComplexity", + "language": "java", + "params": { + "max": "200" + } + }, + { + "repositoryKey": "squid", + "ruleKey": "CommentedOutCodeLine", + "name": "Sections of code should not be \"commented out\"", + "severity": "MAJOR", + "internalKey": "CommentedOutCodeLine", + "language": "java", + "params": {} + }, + { + "repositoryKey": "squid", + "ruleKey": "S00108", + "name": "Nested blocks of code should not be left empty", + "severity": "MAJOR", + "internalKey": "S00108", + "language": "java", + "params": {} + }, + { + "repositoryKey": "squid", + "ruleKey": "S00107", + "name": "Methods should not have too many parameters", + "severity": "MAJOR", + "internalKey": "S00107", + "language": "java", + "params": { + "max": "7", + "constructorMax": "7" + } + }, + { + "repositoryKey": "squid", + "ruleKey": "S00112", + "name": "Generic exceptions should never be thrown", + "severity": "MAJOR", + "internalKey": "S00112", + "language": "java", + "params": {} + }, + { + "repositoryKey": "squid", + "ruleKey": "S00100", + "name": "Method names should comply with a naming convention", + "severity": "MINOR", + "internalKey": "S00100", + "language": "java", + "params": { + "format": "^[a-z][a-zA-Z0-9]*$" + } + }, + { + "repositoryKey": "squid", + "ruleKey": "S00101", + "name": "Class names should comply with a naming convention", + "severity": "MINOR", + "internalKey": "S00101", + "language": "java", + "params": { + "format": "^[A-Z][a-zA-Z0-9]*$" + } + }, + { + "repositoryKey": "squid", + "ruleKey": "S00114", + "name": "Interface names should comply with a naming convention", + "severity": "MINOR", + "internalKey": "S00114", + "language": "java", + "params": { + "format": "^[A-Z][a-zA-Z0-9]*$" + } + }, + { + "repositoryKey": "squid", + "ruleKey": "S00115", + "name": "Constant names should comply with a naming convention", + "severity": "MINOR", + "internalKey": "S00115", + "language": "java", + "params": { + "format": "^[A-Z][A-Z0-9]*(_[A-Z0-9]+)*$" + } + }, + { + "repositoryKey": "squid", + "ruleKey": "S00116", + "name": "Field names should comply with a naming convention", + "severity": "MINOR", + "internalKey": "S00116", + "language": "java", + "params": { + "format": "^[a-z][a-zA-Z0-9]*$" + } + }, + { + "repositoryKey": "squid", + "ruleKey": "S3008", + "name": "Static non-final field names should comply with a naming convention", + "severity": "MINOR", + "internalKey": "S3008", + "language": "java", + "params": { + "format": "^[a-z][a-zA-Z0-9]*$" + } + }, + { + "repositoryKey": "squid", + "ruleKey": "S00117", + "name": "Local variable and method parameter names should comply with a naming convention", + "severity": "MINOR", + "internalKey": "S00117", + "language": "java", + "params": { + "format": "^[a-z][a-zA-Z0-9]*$" + } + }, + { + "repositoryKey": "squid", + "ruleKey": "S00119", + "name": "Type parameter names should comply with a naming convention", + "severity": "MINOR", + "internalKey": "S00119", + "language": "java", + "params": { + "format": "^[A-Z][0-9]?$" + } + }, + { + "repositoryKey": "squid", + "ruleKey": "S00120", + "name": "Package names should comply with a naming convention", + "severity": "MINOR", + "internalKey": "S00120", + "language": "java", + "params": { + "format": "^[a-z]+(\\.[a-z][a-z0-9]*)*$" + } + }, + { + "repositoryKey": "squid", + "ruleKey": "S00122", + "name": "Statements should be on separate lines", + "severity": "MINOR", + "internalKey": "S00122", + "language": "java", + "params": {} + }, + { + "repositoryKey": "squid", + "ruleKey": "RightCurlyBraceStartLineCheck", + "name": "A close curly brace should be located at the beginning of a line", + "severity": "MINOR", + "internalKey": "RightCurlyBraceStartLineCheck", + "language": "java", + "params": {} + }, + { + "repositoryKey": "squid", + "ruleKey": "UselessParenthesesCheck", + "name": "Useless parentheses around expressions should be removed to prevent any misunderstanding", + "severity": "MAJOR", + "internalKey": "UselessParenthesesCheck", + "language": "java", + "params": {} + }, + { + "repositoryKey": "squid", + "ruleKey": "ObjectFinalizeCheck", + "name": "The Object.finalize() method should not be called", + "severity": "CRITICAL", + "internalKey": "ObjectFinalizeCheck", + "language": "java", + "params": {} + }, + { + "repositoryKey": "squid", + "ruleKey": "ObjectFinalizeOverridenCheck", + "name": "The Object.finalize() method should not be overriden", + "severity": "CRITICAL", + "internalKey": "ObjectFinalizeOverridenCheck", + "language": "java", + "params": {} + }, + { + "repositoryKey": "squid", + "ruleKey": "ObjectFinalizeOverridenCallsSuperFinalizeCheck", + "name": "super.finalize() should be called at the end of Object.finalize() implementations", + "severity": "BLOCKER", + "internalKey": "ObjectFinalizeOverridenCallsSuperFinalizeCheck", + "language": "java", + "params": {} + }, + { + "repositoryKey": "squid", + "ruleKey": "ClassVariableVisibilityCheck", + "name": "Class variable fields should not have public accessibility", + "severity": "MAJOR", + "internalKey": "ClassVariableVisibilityCheck", + "language": "java", + "params": {} + }, + { + "repositoryKey": "squid", + "ruleKey": "ForLoopCounterChangedCheck", + "name": "\"for\" loop stop conditions should be invariant", + "severity": "MAJOR", + "internalKey": "ForLoopCounterChangedCheck", + "language": "java", + "params": {} + }, + { + "repositoryKey": "squid", + "ruleKey": "LabelsShouldNotBeUsedCheck", + "name": "Labels should not be used", + "severity": "MAJOR", + "internalKey": "LabelsShouldNotBeUsedCheck", + "language": "java", + "params": {} + }, + { + "repositoryKey": "squid", + "ruleKey": "SwitchLastCaseIsDefaultCheck", + "name": "\"switch\" statements should end with a \"default\" clause", + "severity": "MAJOR", + "internalKey": "SwitchLastCaseIsDefaultCheck", + "language": "java", + "params": {} + }, + { + "repositoryKey": "squid", + "ruleKey": "EmptyStatementUsageCheck", + "name": "Empty statements should be removed", + "severity": "MINOR", + "internalKey": "EmptyStatementUsageCheck", + "language": "java", + "params": {} + }, + { + "repositoryKey": "squid", + "ruleKey": "ModifiersOrderCheck", + "name": "Modifiers should be declared in the correct order", + "severity": "MINOR", + "internalKey": "ModifiersOrderCheck", + "language": "java", + "params": {} + }, + { + "repositoryKey": "squid", + "ruleKey": "AssignmentInSubExpressionCheck", + "name": "Assignments should not be made from within sub-expressions", + "severity": "MAJOR", + "internalKey": "AssignmentInSubExpressionCheck", + "language": "java", + "params": {} + }, + { + "repositoryKey": "squid", + "ruleKey": "UselessImportCheck", + "name": "Useless imports should be removed", + "severity": "MINOR", + "internalKey": "UselessImportCheck", + "language": "java", + "params": {} + }, + { + "repositoryKey": "squid", + "ruleKey": "LowerCaseLongSuffixCheck", + "name": "Long suffix \"L\" should be upper case", + "severity": "MINOR", + "internalKey": "LowerCaseLongSuffixCheck", + "language": "java", + "params": {} + }, + { + "repositoryKey": "squid", + "ruleKey": "MissingDeprecatedCheck", + "name": "Deprecated elements should have both the annotation and the Javadoc tag", + "severity": "MAJOR", + "internalKey": "MissingDeprecatedCheck", + "language": "java", + "params": {} + }, + { + "repositoryKey": "squid", + "ruleKey": "HiddenFieldCheck", + "name": "Local variables should not shadow class fields", + "severity": "MAJOR", + "internalKey": "HiddenFieldCheck", + "language": "java", + "params": {} + }, + { + "repositoryKey": "squid", + "ruleKey": "S1133", + "name": "Deprecated code should be removed eventually", + "severity": "INFO", + "internalKey": "S1133", + "language": "java", + "params": {} + }, + { + "repositoryKey": "squid", + "ruleKey": "S1134", + "name": "\"FIXME\" tags should be handled", + "severity": "MAJOR", + "internalKey": "S1134", + "language": "java", + "params": {} + }, + { + "repositoryKey": "squid", + "ruleKey": "S1135", + "name": "\"TODO\" tags should be handled", + "severity": "INFO", + "internalKey": "S1135", + "language": "java", + "params": {} + }, + { + "repositoryKey": "squid", + "ruleKey": "S1118", + "name": "Utility classes should not have public constructors", + "severity": "MAJOR", + "internalKey": "S1118", + "language": "java", + "params": {} + }, + { + "repositoryKey": "squid", + "ruleKey": "S1132", + "name": "Strings literals should be placed on the left side when checking for equality", + "severity": "MAJOR", + "internalKey": "S1132", + "language": "java", + "params": {} + }, + { + "repositoryKey": "squid", + "ruleKey": "S1126", + "name": "Return of boolean expressions should not be wrapped into an \"if-then-else\" statement", + "severity": "MINOR", + "internalKey": "S1126", + "language": "java", + "params": {} + }, + { + "repositoryKey": "squid", + "ruleKey": "S1125", + "name": "Literal boolean values should not be used in condition expressions", + "severity": "MINOR", + "internalKey": "S1125", + "language": "java", + "params": {} + }, + { + "repositoryKey": "squid", + "ruleKey": "S1067", + "name": "Expressions should not be too complex", + "severity": "MAJOR", + "internalKey": "S1067", + "language": "java", + "params": { + "max": "3" + } + }, + { + "repositoryKey": "squid", + "ruleKey": "S1141", + "name": "Try-catch blocks should not be nested", + "severity": "MAJOR", + "internalKey": "S1141", + "language": "java", + "params": {} + }, + { + "repositoryKey": "squid", + "ruleKey": "S1147", + "name": "Exit methods should not be called", + "severity": "CRITICAL", + "internalKey": "S1147", + "language": "java", + "params": {} + }, + { + "repositoryKey": "squid", + "ruleKey": "S1143", + "name": "\"return\" statements should not occur in \"finally\" blocks", + "severity": "BLOCKER", + "internalKey": "S1143", + "language": "java", + "params": {} + }, + { + "repositoryKey": "squid", + "ruleKey": "S1157", + "name": "Case insensitive string comparisons should be made without intermediate upper or lower casing", + "severity": "MAJOR", + "internalKey": "S1157", + "language": "java", + "params": {} + }, + { + "repositoryKey": "squid", + "ruleKey": "S1155", + "name": "Collection.isEmpty() should be used to test for emptiness", + "severity": "MAJOR", + "internalKey": "S1155", + "language": "java", + "params": {} + }, + { + "repositoryKey": "squid", + "ruleKey": "S1149", + "name": "Synchronized classes Vector, Hashtable, Stack and StringBuffer should not be used", + "severity": "MAJOR", + "internalKey": "S1149", + "language": "java", + "params": {} + }, + { + "repositoryKey": "squid", + "ruleKey": "S1171", + "name": "Only static class initializers should be used", + "severity": "MAJOR", + "internalKey": "S1171", + "language": "java", + "params": {} + }, + { + "repositoryKey": "squid", + "ruleKey": "S1168", + "name": "Empty arrays and collections should be returned instead of null", + "severity": "MAJOR", + "internalKey": "S1168", + "language": "java", + "params": {} + }, + { + "repositoryKey": "squid", + "ruleKey": "S1170", + "name": "Public constants and fields initialized at declaration should be \"static final\" rather than merely \"final\"", + "severity": "MINOR", + "internalKey": "S1170", + "language": "java", + "params": {} + }, + { + "repositoryKey": "squid", + "ruleKey": "S1163", + "name": "Exceptions should not be thrown in finally blocks", + "severity": "MAJOR", + "internalKey": "S1163", + "language": "java", + "params": {} + }, + { + "repositoryKey": "squid", + "ruleKey": "S106", + "name": "Standard ouputs should not be used directly to log anything", + "severity": "MAJOR", + "internalKey": "S106", + "language": "java", + "params": {} + }, + { + "repositoryKey": "squid", + "ruleKey": "S1165", + "name": "Exception classes should be immutable", + "severity": "MAJOR", + "internalKey": "S1165", + "language": "java", + "params": {} + }, + { + "repositoryKey": "squid", + "ruleKey": "S1066", + "name": "Collapsible \"if\" statements should be merged", + "severity": "MAJOR", + "internalKey": "S1066", + "language": "java", + "params": {} + }, + { + "repositoryKey": "squid", + "ruleKey": "S134", + "name": "Control flow statements \"if\", \"for\", \"while\", \"switch\" and \"try\" should not be nested too deeply", + "severity": "MAJOR", + "internalKey": "S134", + "language": "java", + "params": { + "max": "3" + } + }, + { + "repositoryKey": "squid", + "ruleKey": "S1181", + "name": "Throwable and Error should not be caught", + "severity": "BLOCKER", + "internalKey": "S1181", + "language": "java", + "params": {} + }, + { + "repositoryKey": "squid", + "ruleKey": "S1150", + "name": "Enumeration should not be implemented", + "severity": "MAJOR", + "internalKey": "S1150", + "language": "java", + "params": {} + }, + { + "repositoryKey": "squid", + "ruleKey": "S1182", + "name": "Classes that override \"clone\" should be \"Cloneable\" and call \"super.clone()\"", + "severity": "MAJOR", + "internalKey": "S1182", + "language": "java", + "params": {} + }, + { + "repositoryKey": "squid", + "ruleKey": "S1151", + "name": "\"switch case\" clauses should not have too many lines", + "severity": "MAJOR", + "internalKey": "S1151", + "language": "java", + "params": { + "max": "5" + } + }, + { + "repositoryKey": "squid", + "ruleKey": "S128", + "name": "Switch cases should end with an unconditional \"break\" statement", + "severity": "CRITICAL", + "internalKey": "S128", + "language": "java", + "params": {} + }, + { + "repositoryKey": "squid", + "ruleKey": "S1166", + "name": "Exception handlers should preserve the original exception", + "severity": "CRITICAL", + "internalKey": "S1166", + "language": "java", + "params": { + "exceptions": "java.lang.InterruptedException, java.lang.NumberFormatException, java.text.ParseException, java.net.MalformedURLException" + } + }, + { + "repositoryKey": "squid", + "ruleKey": "S1190", + "name": "Future keywords should not be used as names", + "severity": "MAJOR", + "internalKey": "S1190", + "language": "java", + "params": {} + }, + { + "repositoryKey": "squid", + "ruleKey": "S1188", + "name": "Lambdas and anonymous classes should not have too many lines", + "severity": "MAJOR", + "internalKey": "S1188", + "language": "java", + "params": { + "Max": "20" + } + }, + { + "repositoryKey": "squid", + "ruleKey": "S1191", + "name": "Classes from \"sun.*\" packages should not be used", + "severity": "MAJOR", + "internalKey": "S1191", + "language": "java", + "params": {} + }, + { + "repositoryKey": "squid", + "ruleKey": "S135", + "name": "Loops should not contain more than a single \"break\" or \"continue\" statement", + "severity": "MAJOR", + "internalKey": "S135", + "language": "java", + "params": {} + }, + { + "repositoryKey": "squid", + "ruleKey": "S1186", + "name": "Methods should not be empty", + "severity": "MAJOR", + "internalKey": "S1186", + "language": "java", + "params": {} + }, + { + "repositoryKey": "squid", + "ruleKey": "S1185", + "name": "Overriding methods should do more than simply call the same method in the super class", + "severity": "MINOR", + "internalKey": "S1185", + "language": "java", + "params": {} + }, + { + "repositoryKey": "squid", + "ruleKey": "S1174", + "name": "\"Object.finalize()\" should remain protected (versus public) when overriding", + "severity": "MAJOR", + "internalKey": "S1174", + "language": "java", + "params": {} + }, + { + "repositoryKey": "squid", + "ruleKey": "S1175", + "name": "The signature of \"finalize()\" should match that of \"Object.finalize()\"", + "severity": "MAJOR", + "internalKey": "S1175", + "language": "java", + "params": {} + }, + { + "repositoryKey": "squid", + "ruleKey": "S1153", + "name": "String.valueOf() should not be appended to a String", + "severity": "MINOR", + "internalKey": "S1153", + "language": "java", + "params": {} + }, + { + "repositoryKey": "squid", + "ruleKey": "S1148", + "name": "Throwable.printStackTrace(...) should not be called", + "severity": "CRITICAL", + "internalKey": "S1148", + "language": "java", + "params": {} + }, + { + "repositoryKey": "squid", + "ruleKey": "S1195", + "name": "Array designators \"[]\" should be located after the type in method signatures", + "severity": "MINOR", + "internalKey": "S1195", + "language": "java", + "params": {} + }, + { + "repositoryKey": "squid", + "ruleKey": "S1194", + "name": "\"java.lang.Error\" should not be extended", + "severity": "MAJOR", + "internalKey": "S1194", + "language": "java", + "params": {} + }, + { + "repositoryKey": "squid", + "ruleKey": "S1193", + "name": "Exception types should not be tested using \"instanceof\" in catch blocks", + "severity": "MAJOR", + "internalKey": "S1193", + "language": "java", + "params": {} + }, + { + "repositoryKey": "squid", + "ruleKey": "S1192", + "name": "String literals should not be duplicated", + "severity": "MINOR", + "internalKey": "S1192", + "language": "java", + "params": { + "threshold": "3" + } + }, + { + "repositoryKey": "squid", + "ruleKey": "S1158", + "name": "Primitive wrappers should not be instantiated only for \"toString\" or \"compareTo\" calls", + "severity": "MAJOR", + "internalKey": "S1158", + "language": "java", + "params": {} + }, + { + "repositoryKey": "squid", + "ruleKey": "S1215", + "name": "Execution of the Garbage Collector should be triggered only by the JVM", + "severity": "CRITICAL", + "internalKey": "S1215", + "language": "java", + "params": {} + }, + { + "repositoryKey": "squid", + "ruleKey": "S1197", + "name": "Array designators \"[]\" should be on the type, not the variable", + "severity": "MINOR", + "internalKey": "S1197", + "language": "java", + "params": {} + }, + { + "repositoryKey": "squid", + "ruleKey": "S1220", + "name": "The default unnamed package should not be used", + "severity": "MINOR", + "internalKey": "S1220", + "language": "java", + "params": {} + }, + { + "repositoryKey": "squid", + "ruleKey": "S1221", + "name": "Methods should not be named \"hashcode\" or \"equal\"", + "severity": "CRITICAL", + "internalKey": "S1221", + "language": "java", + "params": {} + }, + { + "repositoryKey": "squid", + "ruleKey": "S1199", + "name": "Nested code blocks should not be used", + "severity": "MAJOR", + "internalKey": "S1199", + "language": "java", + "params": {} + }, + { + "repositoryKey": "squid", + "ruleKey": "S1214", + "name": "Constants should not be defined in interfaces", + "severity": "MINOR", + "internalKey": "S1214", + "language": "java", + "params": {} + }, + { + "repositoryKey": "squid", + "ruleKey": "S1201", + "name": "Methods named \"equals\" should override Object.equals(Object)", + "severity": "CRITICAL", + "internalKey": "S1201", + "language": "java", + "params": {} + }, + { + "repositoryKey": "squid", + "ruleKey": "S1210", + "name": "\"equals(Object obj)\" should be overridden along with the \"compareTo(T obj)\" method", + "severity": "CRITICAL", + "internalKey": "S1210", + "language": "java", + "params": {} + }, + { + "repositoryKey": "squid", + "ruleKey": "S1206", + "name": "\"equals(Object obj)\" and \"hashCode()\" should be overridden in pairs", + "severity": "BLOCKER", + "internalKey": "S1206", + "language": "java", + "params": {} + }, + { + "repositoryKey": "squid", + "ruleKey": "S1219", + "name": "\"switch\" statements should not contain non-case labels", + "severity": "CRITICAL", + "internalKey": "S1219", + "language": "java", + "params": {} + }, + { + "repositoryKey": "squid", + "ruleKey": "S1301", + "name": "\"switch\" statements should have at least 3 \"case\" clauses", + "severity": "MINOR", + "internalKey": "S1301", + "language": "java", + "params": {} + }, + { + "repositoryKey": "squid", + "ruleKey": "S1314", + "name": "Octal values should not be used", + "severity": "MAJOR", + "internalKey": "S1314", + "language": "java", + "params": {} + }, + { + "repositoryKey": "squid", + "ruleKey": "S1226", + "name": "Method parameters, caught exceptions and foreach variables should not be reassigned", + "severity": "MAJOR", + "internalKey": "S1226", + "language": "java", + "params": {} + }, + { + "repositoryKey": "squid", + "ruleKey": "S1313", + "name": "IP addresses should not be hardcoded", + "severity": "MAJOR", + "internalKey": "S1313", + "language": "java", + "params": {} + }, + { + "repositoryKey": "squid", + "ruleKey": "S1312", + "name": "Loggers should be \"private static final\" and should share a naming convention", + "severity": "MINOR", + "internalKey": "S1312", + "language": "java", + "params": { + "format": "LOG(?:GER)?" + } + }, + { + "repositoryKey": "squid", + "ruleKey": "S1223", + "name": "Non-constructor methods should not have the same name as the enclosing class", + "severity": "MAJOR", + "internalKey": "S1223", + "language": "java", + "params": {} + }, + { + "repositoryKey": "squid", + "ruleKey": "S1319", + "name": "Declarations should use Java collection interfaces such as \"List\" rather than specific implementation classes such as \"LinkedList\"", + "severity": "MAJOR", + "internalKey": "S1319", + "language": "java", + "params": {} + }, + { + "repositoryKey": "squid", + "ruleKey": "S1213", + "name": "The members of an interface declaration or class should appear in a pre-defined order", + "severity": "MINOR", + "internalKey": "S1213", + "language": "java", + "params": {} + }, + { + "repositoryKey": "squid", + "ruleKey": "S1444", + "name": ":", + "severity": "CRITICAL", + "internalKey": "S1444", + "language": "java", + "params": {} + }, + { + "repositoryKey": "squid", + "ruleKey": "S1452", + "name": "Generic wildcard types should not be used in return parameters", + "severity": "MAJOR", + "internalKey": "S1452", + "language": "java", + "params": {} + }, + { + "repositoryKey": "squid", + "ruleKey": "S1481", + "name": "Unused local variables should be removed", + "severity": "MAJOR", + "internalKey": "S1481", + "language": "java", + "params": {} + }, + { + "repositoryKey": "squid", + "ruleKey": "S1068", + "name": "Unused private fields should be removed", + "severity": "MAJOR", + "internalKey": "S1068", + "language": "java", + "params": {} + }, + { + "repositoryKey": "squid", + "ruleKey": "S1317", + "name": "\"StringBuilder\" and \"StringBuffer\" should not be instantiated with a character", + "severity": "MAJOR", + "internalKey": "S1317", + "language": "java", + "params": {} + }, + { + "repositoryKey": "squid", + "ruleKey": "S1596", + "name": "Collections.emptyList(), emptyMap() and emptySet() should be used instead of Collections.EMPTY_LIST, EMPTY_MAP and EMPTY_SET", + "severity": "MAJOR", + "internalKey": "S1596", + "language": "java", + "params": {} + }, + { + "repositoryKey": "squid", + "ruleKey": "UnusedPrivateMethod", + "name": "Unused private method should be removed", + "severity": "MAJOR", + "internalKey": "UnusedPrivateMethod", + "language": "java", + "params": {} + }, + { + "repositoryKey": "squid", + "ruleKey": "RedundantThrowsDeclarationCheck", + "name": "Throws declarations should not be superfluous", + "severity": "MINOR", + "internalKey": "RedundantThrowsDeclarationCheck", + "language": "java", + "params": {} + }, + { + "repositoryKey": "squid", + "ruleKey": "S1160", + "name": "Public methods should throw at most one checked exception", + "severity": "MAJOR", + "internalKey": "S1160", + "language": "java", + "params": {} + }, + { + "repositoryKey": "squid", + "ruleKey": "S1217", + "name": "Thread.run() and Runnable.run() should not be called directly", + "severity": "CRITICAL", + "internalKey": "S1217", + "language": "java", + "params": {} + }, + { + "repositoryKey": "squid", + "ruleKey": "S1862", + "name": "Related \"if/else if\" statements should not have the same condition", + "severity": "CRITICAL", + "internalKey": "S1862", + "language": "java", + "params": {} + }, + { + "repositoryKey": "squid", + "ruleKey": "S1488", + "name": "Local Variables should not be declared and then immediately returned or thrown", + "severity": "MINOR", + "internalKey": "S1488", + "language": "java", + "params": {} + }, + { + "repositoryKey": "squid", + "ruleKey": "S1602", + "name": "Lamdbas containing only one statement should not nest this statement in a block", + "severity": "MAJOR", + "internalKey": "S1602", + "language": "java", + "params": {} + }, + { + "repositoryKey": "squid", + "ruleKey": "S1611", + "name": "Parentheses should be removed from a single lambda input parameter when its type is inferred", + "severity": "MINOR", + "internalKey": "S1611", + "language": "java", + "params": {} + }, + { + "repositoryKey": "squid", + "ruleKey": "S1700", + "name": "A field should not duplicate the name of its containing class", + "severity": "MAJOR", + "internalKey": "S1700", + "language": "java", + "params": {} + }, + { + "repositoryKey": "squid", + "ruleKey": "S1172", + "name": "Unused method parameters should be removed", + "severity": "MAJOR", + "internalKey": "S1172", + "language": "java", + "params": {} + }, + { + "repositoryKey": "squid", + "ruleKey": "S1598", + "name": "Package declaration should match source file directory", + "severity": "MAJOR", + "internalKey": "S1598", + "language": "java", + "params": {} + }, + { + "repositoryKey": "squid", + "ruleKey": "S1873", + "name": "\"static final\" arrays should be \"private\"", + "severity": "CRITICAL", + "internalKey": "S1873", + "language": "java", + "params": {} + }, + { + "repositoryKey": "squid", + "ruleKey": "S1948", + "name": "Fields in a \"Serializable\" class should either be transient or serializable", + "severity": "CRITICAL", + "internalKey": "S1948", + "language": "java", + "params": {} + }, + { + "repositoryKey": "squid", + "ruleKey": "S1479", + "name": "\"switch\" statements should not have too many \"case\" clauses", + "severity": "MAJOR", + "internalKey": "S1479", + "language": "java", + "params": { + "maximum": "30" + } + }, + { + "repositoryKey": "squid", + "ruleKey": "S1764", + "name": "Identical expressions should not be used on both sides of a binary operator", + "severity": "CRITICAL", + "internalKey": "S1764", + "language": "java", + "params": {} + }, + { + "repositoryKey": "squid", + "ruleKey": "S1244", + "name": "Floating point numbers should not be tested for equality", + "severity": "CRITICAL", + "internalKey": "S1244", + "language": "java", + "params": {} + }, + { + "repositoryKey": "squid", + "ruleKey": "S2077", + "name": "Values passed to SQL commands should be sanitized", + "severity": "CRITICAL", + "internalKey": "S2077", + "language": "java", + "params": {} + }, + { + "repositoryKey": "squid", + "ruleKey": "S1161", + "name": "\"@Override\" annotation should be used on any method overriding (since Java 5) or implementing (since Java 6) another one", + "severity": "MAJOR", + "internalKey": "S1161", + "language": "java", + "params": {} + }, + { + "repositoryKey": "squid", + "ruleKey": "S1994", + "name": "\"for\" loop incrementers should modify the variable being tested in the loop\u0027s stop condition", + "severity": "CRITICAL", + "internalKey": "S1994", + "language": "java", + "params": {} + }, + { + "repositoryKey": "squid", + "ruleKey": "S2094", + "name": "Classes should not be empty", + "severity": "MAJOR", + "internalKey": "S2094", + "language": "java", + "params": {} + }, + { + "repositoryKey": "squid", + "ruleKey": "S1850", + "name": "\"instanceof\" operators that always return \"true\" or \"false\" should be removed", + "severity": "MAJOR", + "internalKey": "S1850", + "language": "java", + "params": {} + }, + { + "repositoryKey": "squid", + "ruleKey": "S1905", + "name": "Redundant casts should not be used", + "severity": "MINOR", + "internalKey": "S1905", + "language": "java", + "params": {} + }, + { + "repositoryKey": "squid", + "ruleKey": "S2114", + "name": "Collections should not be passed as arguments to their own methods", + "severity": "CRITICAL", + "internalKey": "S2114", + "language": "java", + "params": {} + }, + { + "repositoryKey": "squid", + "ruleKey": "S1065", + "name": "Unused labels should be removed", + "severity": "MAJOR", + "internalKey": "S1065", + "language": "java", + "params": {} + }, + { + "repositoryKey": "squid", + "ruleKey": "S2184", + "name": "Math operands should be cast before assignment", + "severity": "MAJOR", + "internalKey": "S2184", + "language": "java", + "params": {} + }, + { + "repositoryKey": "squid", + "ruleKey": "S2225", + "name": "\"toString()\" and \"clone()\" methods should not return null", + "severity": "CRITICAL", + "internalKey": "S2225", + "language": "java", + "params": {} + }, + { + "repositoryKey": "squid", + "ruleKey": "S2230", + "name": "Non-public methods should not be \"@Transactional\"", + "severity": "CRITICAL", + "internalKey": "S2230", + "language": "java", + "params": {} + }, + { + "repositoryKey": "squid", + "ruleKey": "S2200", + "name": "\"compareTo\" results should not be checked for specific values", + "severity": "MAJOR", + "internalKey": "S2200", + "language": "java", + "params": {} + }, + { + "repositoryKey": "squid", + "ruleKey": "S2092", + "name": "Cookies should be \"secure\"", + "severity": "CRITICAL", + "internalKey": "S2092", + "language": "java", + "params": {} + }, + { + "repositoryKey": "squid", + "ruleKey": "S1848", + "name": "Objects should not be created to be dropped immediately without being used", + "severity": "CRITICAL", + "internalKey": "S1848", + "language": "java", + "params": {} + }, + { + "repositoryKey": "squid", + "ruleKey": "S2235", + "name": "IllegalMonitorStateException should not be caught", + "severity": "CRITICAL", + "internalKey": "S2235", + "language": "java", + "params": {} + }, + { + "repositoryKey": "squid", + "ruleKey": "S888", + "name": "Relational operators should be used in \"for\" loop termination conditions", + "severity": "CRITICAL", + "internalKey": "S888", + "language": "java", + "params": {} + }, + { + "repositoryKey": "squid", + "ruleKey": "S2068", + "name": "Credentials should not be hard-coded", + "severity": "CRITICAL", + "internalKey": "S2068", + "language": "java", + "params": {} + }, + { + "repositoryKey": "squid", + "ruleKey": "S2232", + "name": "\"ResultSet.isLast()\" should not be used", + "severity": "CRITICAL", + "internalKey": "S2232", + "language": "java", + "params": {} + }, + { + "repositoryKey": "squid", + "ruleKey": "S1849", + "name": "\"Iterator.hasNext()\" should not call \"Iterator.next()\"", + "severity": "BLOCKER", + "internalKey": "S1849", + "language": "java", + "params": {} + }, + { + "repositoryKey": "squid", + "ruleKey": "S2236", + "name": "Methods \"wait(...)\", \"notify()\" and \"notifyAll()\" should never be called on Thread instances", + "severity": "BLOCKER", + "internalKey": "S2236", + "language": "java", + "params": {} + }, + { + "repositoryKey": "squid", + "ruleKey": "S1844", + "name": "\"Object.wait(...)\" should never be called on objects that implement \"java.util.concurrent.locks.Condition\"", + "severity": "BLOCKER", + "internalKey": "S1844", + "language": "java", + "params": {} + }, + { + "repositoryKey": "squid", + "ruleKey": "S2251", + "name": "A \"for\" loop update clause should move the counter in the right direction", + "severity": "BLOCKER", + "internalKey": "S2251", + "language": "java", + "params": {} + }, + { + "repositoryKey": "squid", + "ruleKey": "S2252", + "name": "Loop conditions should be true at least once", + "severity": "CRITICAL", + "internalKey": "S2252", + "language": "java", + "params": {} + }, + { + "repositoryKey": "squid", + "ruleKey": "S2254", + "name": "\"HttpServletRequest.getRequestedSessionId()\" should not be used", + "severity": "CRITICAL", + "internalKey": "S2254", + "language": "java", + "params": {} + }, + { + "repositoryKey": "squid", + "ruleKey": "S2250", + "name": "\"ConcurrentLinkedQueue.size()\" should not be used", + "severity": "CRITICAL", + "internalKey": "S2250", + "language": "java", + "params": {} + }, + { + "repositoryKey": "squid", + "ruleKey": "S2226", + "name": "Servlets should never have mutable instance fields", + "severity": "CRITICAL", + "internalKey": "S2226", + "language": "java", + "params": {} + }, + { + "repositoryKey": "squid", + "ruleKey": "S2111", + "name": "\"BigDecimal(double)\" should not be used", + "severity": "CRITICAL", + "internalKey": "S2111", + "language": "java", + "params": {} + }, + { + "repositoryKey": "squid", + "ruleKey": "S2109", + "name": "Reflection should not be used to check non-runtime annotations", + "severity": "BLOCKER", + "internalKey": "S2109", + "language": "java", + "params": {} + }, + { + "repositoryKey": "squid", + "ruleKey": "S2273", + "name": "\"wait(...)\", \"notify()\" and \"notifyAll()\" methods should only be called when a lock is obviously held on an object", + "severity": "CRITICAL", + "internalKey": "S2273", + "language": "java", + "params": {} + }, + { + "repositoryKey": "squid", + "ruleKey": "S2276", + "name": "\"wait(...)\" should be used instead of \"Thread.sleep(...)\" when a lock is held", + "severity": "CRITICAL", + "internalKey": "S2276", + "language": "java", + "params": {} + }, + { + "repositoryKey": "squid", + "ruleKey": "S2274", + "name": "\"Object.wait(...)\" and \"Condition.await(...)\" should be called inside a \"while\" loop", + "severity": "CRITICAL", + "internalKey": "S2274", + "language": "java", + "params": {} + }, + { + "repositoryKey": "squid", + "ruleKey": "S2272", + "name": "\"Iterator.next()\" methods should throw \"NoSuchElementException\"", + "severity": "MAJOR", + "internalKey": "S2272", + "language": "java", + "params": {} + }, + { + "repositoryKey": "squid", + "ruleKey": "S2277", + "name": "Cryptographic RSA algorithms should always incorporate OAEP (Optimal Asymmetric Encryption Padding)", + "severity": "CRITICAL", + "internalKey": "S2277", + "language": "java", + "params": {} + }, + { + "repositoryKey": "squid", + "ruleKey": "S2204", + "name": "\".equals()\" should not be used to test the values of \"Atomic\" classes", + "severity": "BLOCKER", + "internalKey": "S2204", + "language": "java", + "params": {} + }, + { + "repositoryKey": "squid", + "ruleKey": "S2178", + "name": "Short-circuit logic should be used in boolean contexts", + "severity": "CRITICAL", + "internalKey": "S2178", + "language": "java", + "params": {} + }, + { + "repositoryKey": "squid", + "ruleKey": "S2116", + "name": "\"hashCode\" and \"toString\" should not be called on array instances", + "severity": "CRITICAL", + "internalKey": "S2116", + "language": "java", + "params": {} + }, + { + "repositoryKey": "squid", + "ruleKey": "S2157", + "name": "\"Cloneables\" should implement \"clone\"", + "severity": "CRITICAL", + "internalKey": "S2157", + "language": "java", + "params": {} + }, + { + "repositoryKey": "squid", + "ruleKey": "S2275", + "name": "Printf-style format strings should not lead to unexpected behavior at runtime", + "severity": "CRITICAL", + "internalKey": "S2275", + "language": "java", + "params": {} + }, + { + "repositoryKey": "squid", + "ruleKey": "S2151", + "name": "\"runFinalizersOnExit\" should not be called", + "severity": "BLOCKER", + "internalKey": "S2151", + "language": "java", + "params": {} + }, + { + "repositoryKey": "squid", + "ruleKey": "S2127", + "name": "\"Double.longBitsToDouble\" should not be used for \"int\"", + "severity": "BLOCKER", + "internalKey": "S2127", + "language": "java", + "params": {} + }, + { + "repositoryKey": "squid", + "ruleKey": "S1860", + "name": "Synchronization should not be based on Strings or boxed primitives", + "severity": "BLOCKER", + "internalKey": "S1860", + "language": "java", + "params": {} + }, + { + "repositoryKey": "squid", + "ruleKey": "S2055", + "name": "The non-serializable super class of a \"Serializable\" class must have a no-argument constructor", + "severity": "CRITICAL", + "internalKey": "S2055", + "language": "java", + "params": {} + }, + { + "repositoryKey": "squid", + "ruleKey": "S2118", + "name": "Non-serializable classes should not be written", + "severity": "CRITICAL", + "internalKey": "S2118", + "language": "java", + "params": {} + }, + { + "repositoryKey": "squid", + "ruleKey": "S2066", + "name": "\"Serializable\" inner classes of non-serializable classes should be \"static\"", + "severity": "CRITICAL", + "internalKey": "S2066", + "language": "java", + "params": {} + }, + { + "repositoryKey": "squid", + "ruleKey": "S2065", + "name": "Fields in non-serializable classes should not be \"transient\"", + "severity": "MINOR", + "internalKey": "S2065", + "language": "java", + "params": {} + }, + { + "repositoryKey": "squid", + "ruleKey": "S2061", + "name": "Custom serialization method signatures should meet requirements", + "severity": "CRITICAL", + "internalKey": "S2061", + "language": "java", + "params": {} + }, + { + "repositoryKey": "squid", + "ruleKey": "S2176", + "name": "Class names should not shadow interfaces or superclasses", + "severity": "MAJOR", + "internalKey": "S2176", + "language": "java", + "params": {} + }, + { + "repositoryKey": "squid", + "ruleKey": "S2130", + "name": "Parsing should be used to convert \"Strings\" to primitives", + "severity": "MAJOR", + "internalKey": "S2130", + "language": "java", + "params": {} + }, + { + "repositoryKey": "squid", + "ruleKey": "S2166", + "name": "Classes named like \"Exception\" should extend \"Exception\" or a subclass", + "severity": "MAJOR", + "internalKey": "S2166", + "language": "java", + "params": {} + }, + { + "repositoryKey": "squid", + "ruleKey": "S2153", + "name": "Boxing and unboxing should not be immediately reversed", + "severity": "MAJOR", + "internalKey": "S2153", + "language": "java", + "params": {} + }, + { + "repositoryKey": "squid", + "ruleKey": "S2326", + "name": "Unused type parameters should be removed", + "severity": "MAJOR", + "internalKey": "S2326", + "language": "java", + "params": {} + }, + { + "repositoryKey": "squid", + "ruleKey": "S2386", + "name": "Interfaces should not have \"public static\" mutable fields", + "severity": "CRITICAL", + "internalKey": "S2386", + "language": "java", + "params": {} + }, + { + "repositoryKey": "squid", + "ruleKey": "S2183", + "name": "Ints and longs should not be shifted by more than their number of bits-1", + "severity": "CRITICAL", + "internalKey": "S2183", + "language": "java", + "params": {} + }, + { + "repositoryKey": "squid", + "ruleKey": "S2167", + "name": "\"compareTo\" should not return \"Integer.MIN_VALUE\"", + "severity": "CRITICAL", + "internalKey": "S2167", + "language": "java", + "params": {} + }, + { + "repositoryKey": "squid", + "ruleKey": "S2165", + "name": "\"finalize\" should not set fields to \"null\"", + "severity": "MAJOR", + "internalKey": "S2165", + "language": "java", + "params": {} + }, + { + "repositoryKey": "squid", + "ruleKey": "S2122", + "name": "\"ScheduledThreadPoolExecutor\" should not have 0 core threads", + "severity": "BLOCKER", + "internalKey": "S2122", + "language": "java", + "params": {} + }, + { + "repositoryKey": "squid", + "ruleKey": "S2134", + "name": "Classes extending java.lang.Thread should override the \"run\" method", + "severity": "MAJOR", + "internalKey": "S2134", + "language": "java", + "params": {} + }, + { + "repositoryKey": "squid", + "ruleKey": "S2175", + "name": "Inappropriate \"Collection\" calls should not be made", + "severity": "CRITICAL", + "internalKey": "S2175", + "language": "java", + "params": {} + }, + { + "repositoryKey": "squid", + "ruleKey": "S2447", + "name": "Null should not be returned from a \"Boolean\" method", + "severity": "CRITICAL", + "internalKey": "S2447", + "language": "java", + "params": {} + }, + { + "repositoryKey": "squid", + "ruleKey": "S2131", + "name": "Primitives should not be boxed just for \"String\" conversion", + "severity": "MAJOR", + "internalKey": "S2131", + "language": "java", + "params": {} + }, + { + "repositoryKey": "squid", + "ruleKey": "S2437", + "name": "Silly bit operations should not be performed", + "severity": "MAJOR", + "internalKey": "S2437", + "language": "java", + "params": {} + }, + { + "repositoryKey": "squid", + "ruleKey": "S2110", + "name": "Invalid \"Date\" values should not be used", + "severity": "CRITICAL", + "internalKey": "S2110", + "language": "java", + "params": {} + }, + { + "repositoryKey": "squid", + "ruleKey": "S2160", + "name": "Subclasses that add fields should override \"equals\"", + "severity": "MAJOR", + "internalKey": "S2160", + "language": "java", + "params": {} + }, + { + "repositoryKey": "squid", + "ruleKey": "S1872", + "name": "Classes should not be compared by name", + "severity": "CRITICAL", + "internalKey": "S1872", + "language": "java", + "params": {} + }, + { + "repositoryKey": "squid", + "ruleKey": "S2440", + "name": "Classes with only \"static\" methods should not be instantiated", + "severity": "MAJOR", + "internalKey": "S2440", + "language": "java", + "params": {} + }, + { + "repositoryKey": "squid", + "ruleKey": "S2441", + "name": "Non-serializable objects should not be stored in \"HttpSessions\"", + "severity": "CRITICAL", + "internalKey": "S2441", + "language": "java", + "params": {} + }, + { + "repositoryKey": "squid", + "ruleKey": "S2123", + "name": "Values should not be uselessly incremented", + "severity": "CRITICAL", + "internalKey": "S2123", + "language": "java", + "params": {} + }, + { + "repositoryKey": "squid", + "ruleKey": "S2133", + "name": "Objects should not be created only to \"getClass\"", + "severity": "MAJOR", + "internalKey": "S2133", + "language": "java", + "params": {} + }, + { + "repositoryKey": "squid", + "ruleKey": "S2154", + "name": "Dissimilar primitive wrappers should not be used with the ternary operator without explicit casting", + "severity": "CRITICAL", + "internalKey": "S2154", + "language": "java", + "params": {} + }, + { + "repositoryKey": "squid", + "ruleKey": "S2442", + "name": "\"Lock\" objects should not be \"synchronized\"", + "severity": "BLOCKER", + "internalKey": "S2442", + "language": "java", + "params": {} + }, + { + "repositoryKey": "squid", + "ruleKey": "S2388", + "name": "Inner class calls to super class methods should be unambiguous", + "severity": "MAJOR", + "internalKey": "S2388", + "language": "java", + "params": {} + }, + { + "repositoryKey": "squid", + "ruleKey": "S2438", + "name": "\"Threads\" should not be used where \"Runnables\" are expected", + "severity": "CRITICAL", + "internalKey": "S2438", + "language": "java", + "params": {} + }, + { + "repositoryKey": "squid", + "ruleKey": "S2259", + "name": "Null pointers should not be dereferenced", + "severity": "BLOCKER", + "internalKey": "S2259", + "language": "java", + "params": {} + }, + { + "repositoryKey": "squid", + "ruleKey": "S2583", + "name": "Conditions should not unconditionally evaluate to \"TRUE\" or to \"FALSE\"", + "severity": "BLOCKER", + "internalKey": "S2583", + "language": "java", + "params": {} + }, + { + "repositoryKey": "squid", + "ruleKey": "S2696", + "name": "Instance methods should not write to \"static\" fields", + "severity": "CRITICAL", + "internalKey": "S2696", + "language": "java", + "params": {} + }, + { + "repositoryKey": "squid", + "ruleKey": "S2674", + "name": "The value returned from a stream read should be checked", + "severity": "CRITICAL", + "internalKey": "S2674", + "language": "java", + "params": {} + }, + { + "repositoryKey": "squid", + "ruleKey": "S2695", + "name": "\"PreparedStatement\" and \"ResultSet\" methods should be called with valid indices", + "severity": "BLOCKER", + "internalKey": "S2695", + "language": "java", + "params": {} + }, + { + "repositoryKey": "squid", + "ruleKey": "S2112", + "name": "\"URL.hashCode\" and \"URL.equals\" should be avoided", + "severity": "CRITICAL", + "internalKey": "S2112", + "language": "java", + "params": {} + }, + { + "repositoryKey": "squid", + "ruleKey": "S2387", + "name": "Child class members should not shadow parent class members", + "severity": "MAJOR", + "internalKey": "S2387", + "language": "java", + "params": {} + }, + { + "repositoryKey": "squid", + "ruleKey": "S2786", + "name": "Nested \"enum\"s should not be declared static", + "severity": "MAJOR", + "internalKey": "S2786", + "language": "java", + "params": {} + }, + { + "repositoryKey": "squid", + "ruleKey": "S2095", + "name": "Resources should be closed", + "severity": "BLOCKER", + "internalKey": "S2095", + "language": "java", + "params": {} + }, + { + "repositoryKey": "squid", + "ruleKey": "S2677", + "name": "\"read\" and \"readLine\" return values should be used", + "severity": "BLOCKER", + "internalKey": "S2677", + "language": "java", + "params": {} + }, + { + "repositoryKey": "squid", + "ruleKey": "S1858", + "name": "\"toString()\" should never be called on a String object", + "severity": "MAJOR", + "internalKey": "S1858", + "language": "java", + "params": {} + }, + { + "repositoryKey": "squid", + "ruleKey": "S2864", + "name": "\"entrySet()\" should be iterated when both the key and value are needed", + "severity": "MAJOR", + "internalKey": "S2864", + "language": "java", + "params": {} + }, + { + "repositoryKey": "squid", + "ruleKey": "S2692", + "name": "\"indexOf\" checks should not be for positive numbers", + "severity": "CRITICAL", + "internalKey": "S2692", + "language": "java", + "params": {} + }, + { + "repositoryKey": "squid", + "ruleKey": "S2675", + "name": "\"readObject\" should not be \"synchronized\"", + "severity": "MAJOR", + "internalKey": "S2675", + "language": "java", + "params": {} + }, + { + "repositoryKey": "squid", + "ruleKey": "S2676", + "name": "Neither \"Math.abs\" nor negation should be used on numbers that could be \"MIN_VALUE\"", + "severity": "CRITICAL", + "internalKey": "S2676", + "language": "java", + "params": {} + }, + { + "repositoryKey": "squid", + "ruleKey": "S2885", + "name": "\"Calendars\" and \"DateFormats\" should not be static", + "severity": "CRITICAL", + "internalKey": "S2885", + "language": "java", + "params": {} + }, + { + "repositoryKey": "squid", + "ruleKey": "S2222", + "name": "Locks should be released", + "severity": "CRITICAL", + "internalKey": "S2222", + "language": "java", + "params": {} + }, + { + "repositoryKey": "squid", + "ruleKey": "S2097", + "name": "\"equals(Object obj)\" should test argument type", + "severity": "BLOCKER", + "internalKey": "S2097", + "language": "java", + "params": {} + }, + { + "repositoryKey": "squid", + "ruleKey": "S2185", + "name": "Silly math should not be performed", + "severity": "MAJOR", + "internalKey": "S2185", + "language": "java", + "params": {} + }, + { + "repositoryKey": "squid", + "ruleKey": "S2159", + "name": "Silly equality checks should not be made", + "severity": "MAJOR", + "internalKey": "S2159", + "language": "java", + "params": {} + }, + { + "repositoryKey": "squid", + "ruleKey": "S2912", + "name": "\"indexOf\" checks should use a start position", + "severity": "MAJOR", + "internalKey": "S2912", + "language": "java", + "params": {} + }, + { + "repositoryKey": "squid", + "ruleKey": "S2325", + "name": "\"private\" methods that don\u0027t access instance data should be \"static\"", + "severity": "MINOR", + "internalKey": "S2325", + "language": "java", + "params": {} + }, + { + "repositoryKey": "squid", + "ruleKey": "S1264", + "name": "A \"while\" loop should be used instead of a \"for\" loop", + "severity": "MINOR", + "internalKey": "S1264", + "language": "java", + "params": {} + }, + { + "repositoryKey": "squid", + "ruleKey": "S2681", + "name": "Multiline blocks should be enclosed in curly braces", + "severity": "CRITICAL", + "internalKey": "S2681", + "language": "java", + "params": {} + }, + { + "repositoryKey": "squid", + "ruleKey": "S1640", + "name": "Maps with keys that are enum values should be replaced with EnumMap", + "severity": "MAJOR", + "internalKey": "S1640", + "language": "java", + "params": {} + }, + { + "repositoryKey": "squid", + "ruleKey": "S2976", + "name": "\"File.createTempFile\" should not be used to create a directory", + "severity": "CRITICAL", + "internalKey": "S2976", + "language": "java", + "params": {} + }, + { + "repositoryKey": "squid", + "ruleKey": "S2188", + "name": "JUnit test cases should call super methods", + "severity": "CRITICAL", + "internalKey": "S2188", + "language": "java", + "params": {} + }, + { + "repositoryKey": "squid", + "ruleKey": "S2186", + "name": "JUnit assertions should not be used in \"run\" methods", + "severity": "CRITICAL", + "internalKey": "S2186", + "language": "java", + "params": {} + }, + { + "repositoryKey": "squid", + "ruleKey": "S2187", + "name": "TestCases should contain tests", + "severity": "MAJOR", + "internalKey": "S2187", + "language": "java", + "params": {} + }, + { + "repositoryKey": "squid", + "ruleKey": "S2391", + "name": "JUnit framework methods should be declared properly", + "severity": "CRITICAL", + "internalKey": "S2391", + "language": "java", + "params": {} + }, + { + "repositoryKey": "squid", + "ruleKey": "S2970", + "name": "Assertions should be complete", + "severity": "CRITICAL", + "internalKey": "S2970", + "language": "java", + "params": {} + } + ], + "settingsByModule": {}, + "fileDataByModuleAndPath": { + "my:project": { + "src/test/java/org/sonar/plugins/scm/jazzrtc/UTCRule.java": { + "hash": "e80b5df219bc78ed5c498988d9f23d37", + "needBlame": true + }, + "src/test/java/org/sonar/plugins/scm/jazzrtc/JazzRtcScmProviderTest.java": { + "hash": "6f4f93e1016714869a2008de7df3d207", + "needBlame": true + }, + "src/test/java/org/sonar/plugins/scm/jazzrtc/JazzRtcBlameCommandTest.java": { + "hash": "0ab25adb0ae40d826ea23998a362a7ef", + "needBlame": true + }, + "src/main/java/org/sonar/plugins/scm/jazzrtc/JazzRtcConfiguration.java": { + "hash": "23961c33f6388248ae3530dbc8988e72", + "needBlame": true + }, + "src/main/java/org/sonar/plugins/scm/jazzrtc/package-info.java": { + "hash": "afdb44120bc13f6fd36be27040408ac0", + "needBlame": true + }, + "src/test/java/org/sonar/plugins/scm/jazzrtc/JazzRtcBlameConsumerTest.java": { + "hash": "cd9f105580a53c702e0b721899314348", + "needBlame": true + }, + "src/main/java/org/sonar/plugins/scm/jazzrtc/JazzRtcBlameConsumer.java": { + "hash": "fff6441cd4193c275f12221355658883", + "needBlame": true + }, + "src/main/java/org/sonar/plugins/scm/jazzrtc/JazzRtcScmProvider.java": { + "hash": "f047b734b6653a5126f8c278dc6aa1a5", + "needBlame": true + }, + "src/test/java/org/sonar/plugins/scm/jazzrtc/JazzRtcPluginTest.java": { + "hash": "688b065dcf12a55b363acf7901f9a6de", + "needBlame": true + }, + "src/main/java/org/sonar/plugins/scm/jazzrtc/JazzRtcBlameCommand.java": { + "hash": "9646e0be0c460017af98505e8ab5578a", + "needBlame": true + }, + "src/main/java/org/sonar/plugins/scm/jazzrtc/JazzRtcPlugin.java": { + "hash": "c9fd9a67b28d610165edbb29d8975d00", + "needBlame": true + } + } + }, + "lastAnalysisDate": "2015-08-06T17:06:58+0200" +} \ No newline at end of file diff --git a/sonar-core/src/main/java/org/sonar/core/platform/ComponentContainer.java b/sonar-core/src/main/java/org/sonar/core/platform/ComponentContainer.java index 3996301bc7b..cbc738cc977 100644 --- a/sonar-core/src/main/java/org/sonar/core/platform/ComponentContainer.java +++ b/sonar-core/src/main/java/org/sonar/core/platform/ComponentContainer.java @@ -20,9 +20,12 @@ package org.sonar.core.platform; import com.google.common.collect.Iterables; + import java.util.Collection; import java.util.List; + import javax.annotation.Nullable; + import org.picocontainer.Characteristics; import org.picocontainer.ComponentAdapter; import org.picocontainer.DefaultPicoContainer; @@ -157,6 +160,12 @@ public class ComponentContainer { return this; } + public void addIfMissing(Object object, Class objectType) { + if (getComponentByType(objectType) == null) { + add(object); + } + } + public ComponentContainer addSingletons(Collection components) { for (Object component : components) { addSingleton(component); diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/CoreProperties.java b/sonar-plugin-api/src/main/java/org/sonar/api/CoreProperties.java index fbb3b2a346d..8e508b0d565 100644 --- a/sonar-plugin-api/src/main/java/org/sonar/api/CoreProperties.java +++ b/sonar-plugin-api/src/main/java/org/sonar/api/CoreProperties.java @@ -431,7 +431,9 @@ public interface CoreProperties { /** * @since 4.0 + * @deprecated since 5.2 the default mode is publish */ + @Deprecated String ANALYSIS_MODE_ANALYSIS = "analysis"; /** @@ -443,6 +445,8 @@ public interface CoreProperties { * @since 5.2 */ String ANALYSIS_MODE_ISSUES = "issues"; + + String ANALYSIS_MODE_PUBLISH = "publish"; /** * @since 5.2 -- 2.39.5