From da0e7d2eb596eeed136301cdaa38523ff8c86d54 Mon Sep 17 00:00:00 2001 From: Duarte Meneses Date: Thu, 6 Aug 2015 14:38:53 +0200 Subject: SONAR-6777 Project cache sync --- .../org/sonar/batch/bootstrap/GlobalContainer.java | 39 +- .../batch/bootstrap/GlobalWSLoaderProvider.java | 37 + .../org/sonar/batch/bootstrap/ServerClient.java | 2 - .../java/org/sonar/batch/bootstrap/WSLoader.java | 78 +- .../batch/bootstrap/WSLoaderGlobalProvider.java | 44 - .../java/org/sonar/batch/bootstrapper/Batch.java | 15 + .../org/sonar/batch/cache/ProjectCacheStatus.java | 83 + .../batch/cache/ProjectCacheSynchronizer.java | 118 ++ .../sonar/batch/cache/ProjectSyncContainer.java | 84 + .../batch/cache/StrategyWSLoaderProvider.java | 45 + .../sonar/batch/issue/DefaultIssueCallback.java | 10 +- .../sonar/batch/mediumtest/BatchMediumTester.java | 408 ---- .../batch/mediumtest/FakePluginInstaller.java | 1 + .../DefaultProjectRepositoriesLoader.java | 12 +- .../repository/ProjectRepositoriesLoader.java | 5 +- .../repository/ProjectRepositoriesProvider.java | 2 +- .../batch/repository/user/UserRepository.java | 88 - .../repository/user/UserRepositoryLoader.java | 107 + .../org/sonar/batch/scan/ProjectAnalysisMode.java | 5 +- .../org/sonar/batch/scan/ProjectScanContainer.java | 25 +- .../sonar/batch/scan/ProjectWSLoaderProvider.java | 15 +- .../org/sonar/batch/scan/report/JSONReport.java | 8 +- .../bootstrap/GlobalWSLoaderProviderTest.java | 63 + .../bootstrap/WSLoaderGlobalProviderTest.java | 76 - .../org/sonar/batch/bootstrap/WSLoaderTest.java | 65 +- .../batch/bootstrap/WSLoaderTestWithServer.java | 34 +- .../sonar/batch/cache/ProjectCacheStatusTest.java | 71 + .../batch/issue/DefaultIssueCallbackTest.java | 8 +- .../DefaultServerLineHashesLoaderTest.java | 4 +- .../sonar/batch/mediumtest/BatchMediumTester.java | 412 ++++ .../batch/mediumtest/cache/CacheSyncTest.java | 76 + .../batch/mediumtest/issuesmode/EmptyFileTest.java | 90 + .../issuesmode/IssueModeAndReportsMediumTest.java | 265 +++ .../batch/mediumtest/preview/EmptyFileTest.java | 90 - .../preview/IssueModeAndReportsMediumTest.java | 265 --- .../DefaultProjectRepositoriesLoaderTest.java | 41 +- .../repository/user/UserRepositoryLoaderTest.java | 80 + .../batch/repository/user/UserRepositoryTest.java | 80 - .../batch/scan/ProjectWSLoaderProviderTest.java | 66 + .../batch/scan/WSLoaderProjectProviderTest.java | 67 - .../sonar/batch/scan/report/JSONReportTest.java | 8 +- .../sample_response.json | 2093 ++++++++++++++++++++ 42 files changed, 3878 insertions(+), 1307 deletions(-) create mode 100644 sonar-batch/src/main/java/org/sonar/batch/bootstrap/GlobalWSLoaderProvider.java delete mode 100644 sonar-batch/src/main/java/org/sonar/batch/bootstrap/WSLoaderGlobalProvider.java 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 delete mode 100644 sonar-batch/src/main/java/org/sonar/batch/mediumtest/BatchMediumTester.java delete mode 100644 sonar-batch/src/main/java/org/sonar/batch/repository/user/UserRepository.java create mode 100644 sonar-batch/src/main/java/org/sonar/batch/repository/user/UserRepositoryLoader.java create mode 100644 sonar-batch/src/test/java/org/sonar/batch/bootstrap/GlobalWSLoaderProviderTest.java delete mode 100644 sonar-batch/src/test/java/org/sonar/batch/bootstrap/WSLoaderGlobalProviderTest.java create mode 100644 sonar-batch/src/test/java/org/sonar/batch/cache/ProjectCacheStatusTest.java create mode 100644 sonar-batch/src/test/java/org/sonar/batch/mediumtest/BatchMediumTester.java create mode 100644 sonar-batch/src/test/java/org/sonar/batch/mediumtest/cache/CacheSyncTest.java create mode 100644 sonar-batch/src/test/java/org/sonar/batch/mediumtest/issuesmode/EmptyFileTest.java create mode 100644 sonar-batch/src/test/java/org/sonar/batch/mediumtest/issuesmode/IssueModeAndReportsMediumTest.java delete mode 100644 sonar-batch/src/test/java/org/sonar/batch/mediumtest/preview/EmptyFileTest.java delete mode 100644 sonar-batch/src/test/java/org/sonar/batch/mediumtest/preview/IssueModeAndReportsMediumTest.java create mode 100644 sonar-batch/src/test/java/org/sonar/batch/repository/user/UserRepositoryLoaderTest.java delete mode 100644 sonar-batch/src/test/java/org/sonar/batch/repository/user/UserRepositoryTest.java create mode 100644 sonar-batch/src/test/java/org/sonar/batch/scan/ProjectWSLoaderProviderTest.java delete mode 100644 sonar-batch/src/test/java/org/sonar/batch/scan/WSLoaderProjectProviderTest.java create mode 100644 sonar-batch/src/test/resources/org/sonar/batch/repository/DefaultProjectRepositoriesLoaderTest/sample_response.json (limited to 'sonar-batch/src') 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/GlobalWSLoaderProvider.java b/sonar-batch/src/main/java/org/sonar/batch/bootstrap/GlobalWSLoaderProvider.java new file mode 100644 index 00000000000..f89c4a3afed --- /dev/null +++ b/sonar-batch/src/main/java/org/sonar/batch/bootstrap/GlobalWSLoaderProvider.java @@ -0,0 +1,37 @@ +/* + * SonarQube, open source software quality management tool. + * Copyright (C) 2008-2014 SonarSource + * mailto:contact AT sonarsource DOT com + * + * SonarQube is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * SonarQube is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.batch.bootstrap; + +import org.picocontainer.injectors.ProviderAdapter; +import org.sonar.batch.bootstrap.WSLoader.LoadStrategy; + +import org.sonar.home.cache.PersistentCache; + +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(DEFAULT_STRATEGY, cache, client); + } + return wsLoader; + } +} 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/bootstrap/WSLoaderGlobalProvider.java b/sonar-batch/src/main/java/org/sonar/batch/bootstrap/WSLoaderGlobalProvider.java deleted file mode 100644 index 71826511f1d..00000000000 --- a/sonar-batch/src/main/java/org/sonar/batch/bootstrap/WSLoaderGlobalProvider.java +++ /dev/null @@ -1,44 +0,0 @@ -/* - * SonarQube, open source software quality management tool. - * Copyright (C) 2008-2014 SonarSource - * mailto:contact AT sonarsource DOT com - * - * SonarQube is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * SonarQube is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -package org.sonar.batch.bootstrap; - -import org.picocontainer.injectors.ProviderAdapter; -import org.sonar.batch.bootstrap.WSLoader.LoadStrategy; - -import java.util.Map; - -import org.sonar.home.cache.PersistentCache; - -public class WSLoaderGlobalProvider extends ProviderAdapter { - private static final LoadStrategy DEFAULT_STRATEGY = LoadStrategy.SERVER_FIRST; - private WSLoader wsLoader; - - public WSLoader provide(BootstrapProperties props, GlobalMode mode, PersistentCache cache, ServerClient client) { - if (wsLoader == null) { - wsLoader = new WSLoader(isCacheEnabled(props.properties(), mode), cache, client); - wsLoader.setStrategy(DEFAULT_STRATEGY); - } - return wsLoader; - } - - private static boolean isCacheEnabled(Map props, GlobalMode mode) { - return mode.isIssues(); - } -} 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/BatchMediumTester.java b/sonar-batch/src/main/java/org/sonar/batch/mediumtest/BatchMediumTester.java deleted file mode 100644 index 09c41cf4dcb..00000000000 --- a/sonar-batch/src/main/java/org/sonar/batch/mediumtest/BatchMediumTester.java +++ /dev/null @@ -1,408 +0,0 @@ -/* - * 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; - -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; -import org.sonar.batch.rule.RulesLoader; -import com.google.common.base.Function; -import com.google.common.io.Files; - -import java.io.File; -import java.io.FileInputStream; -import java.io.InputStreamReader; -import java.io.Reader; -import java.nio.charset.StandardCharsets; -import java.util.ArrayList; -import java.util.Date; -import java.util.HashMap; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; -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; -import org.sonar.batch.bootstrap.AnalysisProperties; -import org.sonar.batch.bootstrapper.Batch; -import org.sonar.batch.bootstrapper.EnvironmentInformation; -import org.sonar.batch.bootstrapper.LogOutput; -import org.sonar.batch.issue.tracking.ServerLineHashesLoader; -import org.sonar.batch.protocol.input.ActiveRule; -import org.sonar.batch.protocol.input.BatchInput.ServerIssue; -import org.sonar.batch.protocol.input.FileData; -import org.sonar.batch.protocol.input.GlobalRepositories; -import org.sonar.batch.protocol.input.ProjectRepositories; -import org.sonar.batch.report.ReportPublisher; -import org.sonar.batch.repository.GlobalRepositoriesLoader; -import org.sonar.batch.repository.ProjectRepositoriesLoader; -import org.sonar.batch.repository.ServerIssuesLoader; -import org.sonar.core.component.ComponentKeys; - -/** - * Main utility class for writing batch medium tests. - * - */ -public class BatchMediumTester { - - public static final String MEDIUM_TEST_ENABLED = "sonar.mediumTest.enabled"; - private Batch batch; - - public static BatchMediumTesterBuilder builder() { - BatchMediumTesterBuilder builder = new BatchMediumTesterBuilder().registerCoreMetrics(); - builder.bootstrapProperties.put(MEDIUM_TEST_ENABLED, "true"); - builder.bootstrapProperties.put(ReportPublisher.KEEP_REPORT_PROP_KEY, "true"); - builder.bootstrapProperties.put(CoreProperties.WORKING_DIRECTORY, Files.createTempDir().getAbsolutePath()); - return builder; - } - - public static class BatchMediumTesterBuilder { - private final FakeGlobalRepositoriesLoader globalRefProvider = new FakeGlobalRepositoriesLoader(); - private final FakeProjectRepositoriesLoader projectRefProvider = new FakeProjectRepositoriesLoader(); - private final FakePluginInstaller pluginInstaller = new FakePluginInstaller(); - private final FakeServerIssuesLoader serverIssues = new FakeServerIssuesLoader(); - private final FakeServerLineHashesLoader serverLineHashes = new FakeServerLineHashesLoader(); - private final Map bootstrapProperties = new HashMap<>(); - private final FakeRulesLoader rulesLoader = new FakeRulesLoader(); - private LogOutput logOutput = null; - - public BatchMediumTester build() { - return new BatchMediumTester(this); - } - - public BatchMediumTesterBuilder setLogOutput(LogOutput logOutput) { - this.logOutput = logOutput; - return this; - } - - public BatchMediumTesterBuilder registerPlugin(String pluginKey, File location) { - pluginInstaller.add(pluginKey, location); - return this; - } - - public BatchMediumTesterBuilder registerPlugin(String pluginKey, SonarPlugin instance) { - pluginInstaller.add(pluginKey, instance); - return this; - } - - public BatchMediumTesterBuilder registerCoreMetrics() { - for (Metric m : CoreMetrics.getMetrics()) { - registerMetric(m); - } - return this; - } - - public BatchMediumTesterBuilder registerMetric(Metric metric) { - globalRefProvider.add(metric); - return this; - } - - public BatchMediumTesterBuilder addQProfile(String language, String name) { - projectRefProvider.addQProfile(language, name); - return this; - } - - public BatchMediumTesterBuilder addRule(Rule rule) { - rulesLoader.addRule(rule); - return this; - } - - public BatchMediumTesterBuilder addRule(String key, String repoKey, String internalKey, String name) { - Rule.Builder builder = Rule.newBuilder(); - builder.setKey(key); - builder.setRepository(repoKey); - if (internalKey != null) { - builder.setInternalKey(internalKey); - } - builder.setName(name); - - rulesLoader.addRule(builder.build()); - return this; - } - - public BatchMediumTesterBuilder addRules(RulesDefinition rulesDefinition) { - RulesDefinition.Context context = new RulesDefinition.Context(); - rulesDefinition.define(context); - List repositories = context.repositories(); - for (Repository repo : repositories) { - for (RulesDefinition.Rule rule : repo.rules()) { - this.addRule(rule.key(), rule.repository().key(), rule.internalKey(), rule.name()); - } - } - return this; - } - - public BatchMediumTesterBuilder addDefaultQProfile(String language, String name) { - addQProfile(language, name); - globalRefProvider.globalSettings().put("sonar.profile." + language, name); - return this; - } - - public BatchMediumTesterBuilder setPreviousAnalysisDate(Date previousAnalysis) { - projectRefProvider.ref.setLastAnalysisDate(previousAnalysis); - return this; - } - - public BatchMediumTesterBuilder bootstrapProperties(Map props) { - bootstrapProperties.putAll(props); - return this; - } - - public BatchMediumTesterBuilder activateRule(ActiveRule activeRule) { - projectRefProvider.addActiveRule(activeRule); - return this; - } - - public BatchMediumTesterBuilder addFileData(String moduleKey, String path, FileData fileData) { - projectRefProvider.addFileData(moduleKey, path, fileData); - return this; - } - - public BatchMediumTesterBuilder setLastBuildDate(Date d) { - projectRefProvider.setLastAnalysisDate(d); - return this; - } - - public BatchMediumTesterBuilder mockServerIssue(ServerIssue issue) { - serverIssues.getServerIssues().add(issue); - return this; - } - - public BatchMediumTesterBuilder mockLineHashes(String fileKey, String[] lineHashes) { - serverLineHashes.byKey.put(fileKey, lineHashes); - return this; - } - } - - public void start() { - batch.start(); - } - - public void stop() { - batch.stop(); - } - - private BatchMediumTester(BatchMediumTesterBuilder builder) { - batch = Batch.builder() - .setEnableLoggingConfiguration(true) - .addComponents( - new EnvironmentInformation("mediumTest", "1.0"), - builder.pluginInstaller, - builder.globalRefProvider, - builder.projectRefProvider, - builder.serverIssues, - builder.serverLineHashes, - builder.rulesLoader, - new DefaultDebtModel()) - .setBootstrapProperties(builder.bootstrapProperties) - .setLogOutput(builder.logOutput) - .build(); - } - - public TaskBuilder newTask() { - return new TaskBuilder(this); - } - - public TaskBuilder newScanTask(File sonarProps) { - Properties prop = new Properties(); - try (Reader reader = new InputStreamReader(new FileInputStream(sonarProps), StandardCharsets.UTF_8)) { - prop.load(reader); - } catch (Exception e) { - throw new IllegalStateException("Unable to read configuration file", e); - } - TaskBuilder builder = new TaskBuilder(this); - builder.property("sonar.projectBaseDir", sonarProps.getParentFile().getAbsolutePath()); - for (Map.Entry entry : prop.entrySet()) { - builder.property(entry.getKey().toString(), entry.getValue().toString()); - } - return builder; - } - - public static class TaskBuilder { - private final Map taskProperties = new HashMap<>(); - private BatchMediumTester tester; - private IssueListener issueListener = null; - - public TaskBuilder(BatchMediumTester tester) { - this.tester = tester; - } - - public TaskResult start() { - TaskResult result = new TaskResult(); - Map props = new HashMap<>(); - props.putAll(taskProperties); - if (issueListener != null) { - tester.batch.executeTask(props, result, issueListener); - } else { - tester.batch.executeTask(props, result); - } - return result; - } - - public TaskBuilder properties(Map props) { - taskProperties.putAll(props); - return this; - } - - public TaskBuilder property(String key, String value) { - taskProperties.put(key, value); - return this; - } - - public TaskBuilder setIssueListener(IssueListener issueListener) { - this.issueListener = issueListener; - return this; - } - } - - private static class FakeRulesLoader implements RulesLoader { - private List rules = new LinkedList<>(); - - public FakeRulesLoader addRule(Rule rule) { - rules.add(rule); - return this; - } - - @Override - public List load() { - return rules; - } - - @Override - public boolean loadedFromCache() { - return false; - } - } - - private static class FakeGlobalRepositoriesLoader implements GlobalRepositoriesLoader { - - private int metricId = 1; - - private GlobalRepositories ref = new GlobalRepositories(); - - @Override - public GlobalRepositories load() { - return ref; - } - - public Map globalSettings() { - return ref.globalSettings(); - } - - public FakeGlobalRepositoriesLoader add(Metric metric) { - Boolean optimizedBestValue = metric.isOptimizedBestValue(); - ref.metrics().add(new org.sonar.batch.protocol.input.Metric(metricId, - metric.key(), - metric.getType().name(), - metric.getDescription(), - metric.getDirection(), - metric.getName(), - metric.getQualitative(), - metric.getUserManaged(), - metric.getWorstValue(), - metric.getBestValue(), - optimizedBestValue != null ? optimizedBestValue : false)); - metricId++; - return this; - } - - @Override - public boolean loadedFromCache() { - return true; - } - } - - private static class FakeProjectRepositoriesLoader implements ProjectRepositoriesLoader { - - private ProjectRepositories ref = new ProjectRepositories(); - - @Override - public ProjectRepositories load(ProjectReactor reactor, AnalysisProperties taskProperties) { - return ref; - } - - public FakeProjectRepositoriesLoader addQProfile(String language, String name) { - // Use a fixed date to allow assertions - ref.addQProfile(new org.sonar.batch.protocol.input.QProfile(name, name, language, new Date(1234567891212L))); - return this; - } - - public FakeProjectRepositoriesLoader addActiveRule(ActiveRule activeRule) { - ref.addActiveRule(activeRule); - return this; - } - - public FakeProjectRepositoriesLoader addFileData(String moduleKey, String path, FileData fileData) { - ref.addFileData(moduleKey, path, fileData); - return this; - } - - public FakeProjectRepositoriesLoader setLastAnalysisDate(Date d) { - ref.setLastAnalysisDate(d); - return this; - } - - @Override - public boolean loadedFromCache() { - return true; - } - } - - private static class FakeServerIssuesLoader implements ServerIssuesLoader { - - private List serverIssues = new ArrayList<>(); - - public List getServerIssues() { - return serverIssues; - } - - @Override - public boolean load(String componentKey, Function consumer, boolean incremental) { - for (ServerIssue serverIssue : serverIssues) { - if (!incremental || ComponentKeys.createEffectiveKey(serverIssue.getModuleKey(), serverIssue.hasPath() ? serverIssue.getPath() : null).equals(componentKey)) { - consumer.apply(serverIssue); - } - } - return false; - } - - } - - private static class FakeServerLineHashesLoader implements ServerLineHashesLoader { - private Map byKey = new HashMap<>(); - - @Override - public String[] getLineHashes(String fileKey) { - if (byKey.containsKey(fileKey)) { - return byKey.get(fileKey); - } else { - throw new IllegalStateException("You forgot to mock line hashes for " + fileKey); - } - } - } - -} 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/UserRepository.java deleted file mode 100644 index a0e4c781290..00000000000 --- a/sonar-batch/src/main/java/org/sonar/batch/repository/user/UserRepository.java +++ /dev/null @@ -1,88 +0,0 @@ -/* - * 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.repository.user; - -import org.sonar.batch.bootstrap.WSLoaderResult; - -import org.sonar.api.utils.log.Profiler; -import org.sonar.api.utils.log.Logger; -import org.sonar.api.utils.log.Loggers; -import org.sonar.batch.util.BatchUtils; -import org.sonar.batch.bootstrap.WSLoader; -import com.google.common.io.ByteSource; -import com.google.common.base.Function; -import com.google.common.base.Joiner; -import com.google.common.collect.Lists; -import org.sonar.batch.protocol.input.BatchInput; - -import java.io.IOException; -import java.io.InputStream; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.List; - -public class UserRepository { - private static final Logger LOG = Loggers.get(UserRepository.class); - private final WSLoader wsLoader; - - public UserRepository(WSLoader wsLoader) { - this.wsLoader = wsLoader; - } - - public Collection loadFromWs(List userLogins) { - if (userLogins.isEmpty()) { - return Collections.emptyList(); - } - Profiler profiler = Profiler.create(LOG).startDebug("Load user repository"); - WSLoaderResult result = wsLoader.loadSource("/batch/users?logins=" + Joiner.on(',').join(Lists.transform(userLogins, new UserEncodingFunction()))); - if (result.isFromCache()) { - profiler.stopInfo("Load user repository (done from cache)"); - } else { - profiler.stopInfo(); - } - - return parseUsers(result.get()); - } - - private static class UserEncodingFunction implements Function { - @Override - public String apply(String input) { - return BatchUtils.encodeForUrl(input); - } - } - - private static Collection parseUsers(ByteSource input) { - List users = new ArrayList<>(); - - try (InputStream is = input.openStream()) { - BatchInput.User user = BatchInput.User.parseDelimitedFrom(is); - while (user != null) { - users.add(user); - user = BatchInput.User.parseDelimitedFrom(is); - } - } catch (IOException e) { - throw new IllegalStateException("Unable to get user details from server", e); - } - - return users; - } - -} diff --git a/sonar-batch/src/main/java/org/sonar/batch/repository/user/UserRepositoryLoader.java b/sonar-batch/src/main/java/org/sonar/batch/repository/user/UserRepositoryLoader.java new file mode 100644 index 00000000000..43d2383b50d --- /dev/null +++ b/sonar-batch/src/main/java/org/sonar/batch/repository/user/UserRepositoryLoader.java @@ -0,0 +1,107 @@ +/* + * 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.repository.user; + +import org.sonar.batch.bootstrap.WSLoaderResult; + +import org.sonar.api.utils.log.Profiler; +import org.sonar.api.utils.log.Logger; +import org.sonar.api.utils.log.Loggers; +import org.sonar.batch.util.BatchUtils; +import org.sonar.batch.bootstrap.WSLoader; +import com.google.common.io.ByteSource; +import com.google.common.base.Function; +import com.google.common.base.Joiner; +import com.google.common.collect.Lists; +import org.sonar.batch.protocol.input.BatchInput; + +import java.io.IOException; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.List; + +public class UserRepositoryLoader { + private static final Logger LOG = Loggers.get(UserRepositoryLoader.class); + private final WSLoader wsLoader; + + public UserRepositoryLoader(WSLoader wsLoader) { + this.wsLoader = wsLoader; + } + + 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=" + loginsQuery); + if (result.isFromCache()) { + profiler.stopInfo("Load user repository (done from cache)"); + } else { + profiler.stopInfo(); + } + + return result.get(); + } + + private static class UserEncodingFunction implements Function { + @Override + public String apply(String input) { + return BatchUtils.encodeForUrl(input); + } + } + + 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<>(); + + try (InputStream is = input.openStream()) { + BatchInput.User user = BatchInput.User.parseDelimitedFrom(is); + while (user != null) { + users.add(user); + user = BatchInput.User.parseDelimitedFrom(is); + } + } catch (IOException e) { + throw new IllegalStateException("Unable to get user details from server", e); + } + + return users; + } + +} 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/GlobalWSLoaderProviderTest.java b/sonar-batch/src/test/java/org/sonar/batch/bootstrap/GlobalWSLoaderProviderTest.java new file mode 100644 index 00000000000..1ae0c36ab2f --- /dev/null +++ b/sonar-batch/src/test/java/org/sonar/batch/bootstrap/GlobalWSLoaderProviderTest.java @@ -0,0 +1,63 @@ +/* + * SonarQube, open source software quality management tool. + * Copyright (C) 2008-2014 SonarSource + * mailto:contact AT sonarsource DOT com + * + * SonarQube is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * SonarQube is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.batch.bootstrap; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.util.HashMap; +import java.util.Map; + +import org.sonar.batch.bootstrap.WSLoader.LoadStrategy; +import org.junit.Test; +import org.junit.Before; +import org.sonar.home.cache.PersistentCache; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +public class GlobalWSLoaderProviderTest { + @Mock + private PersistentCache cache; + + @Mock + private ServerClient client; + + @Mock + private GlobalMode mode; + + private GlobalWSLoaderProvider loaderProvider; + private Map propMap; + private BootstrapProperties props; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + loaderProvider = new GlobalWSLoaderProvider(); + } + + @Test + public void testDefault() { + propMap = new HashMap<>(); + props = new BootstrapProperties(propMap); + + WSLoader wsLoader = loaderProvider.provide(props, mode, cache, client); + assertThat(wsLoader.getStrategy()).isEqualTo(LoadStrategy.SERVER_ONLY); + } + +} diff --git a/sonar-batch/src/test/java/org/sonar/batch/bootstrap/WSLoaderGlobalProviderTest.java b/sonar-batch/src/test/java/org/sonar/batch/bootstrap/WSLoaderGlobalProviderTest.java deleted file mode 100644 index 81a5fdb563f..00000000000 --- a/sonar-batch/src/test/java/org/sonar/batch/bootstrap/WSLoaderGlobalProviderTest.java +++ /dev/null @@ -1,76 +0,0 @@ -/* - * SonarQube, open source software quality management tool. - * Copyright (C) 2008-2014 SonarSource - * mailto:contact AT sonarsource DOT com - * - * SonarQube is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * SonarQube is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -package org.sonar.batch.bootstrap; - -import static org.assertj.core.api.Assertions.assertThat; - -import java.util.HashMap; -import java.util.Map; - -import static org.mockito.Mockito.when; - -import org.sonar.batch.bootstrap.WSLoader.LoadStrategy; -import org.junit.Test; -import org.junit.Before; -import org.sonar.home.cache.PersistentCache; -import org.mockito.Mock; -import org.mockito.MockitoAnnotations; - -public class WSLoaderGlobalProviderTest { - @Mock - private PersistentCache cache; - - @Mock - private ServerClient client; - - @Mock - private GlobalMode mode; - - private WSLoaderGlobalProvider loaderProvider; - private Map propMap; - private BootstrapProperties props; - - @Before - public void setUp() { - MockitoAnnotations.initMocks(this); - loaderProvider = new WSLoaderGlobalProvider(); - } - - @Test - public void testDefault() { - propMap = new HashMap<>(); - props = new BootstrapProperties(propMap); - - WSLoader wsLoader = loaderProvider.provide(props, mode, cache, client); - assertThat(wsLoader.getStrategy()).isEqualTo(LoadStrategy.SERVER_FIRST); - assertThat(wsLoader.isCacheEnabled()).isEqualTo(false); - } - - @Test - public void testOffline() { - propMap = new HashMap<>(); - propMap.put("sonar.enableOffline", "true"); - when(mode.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/test/java/org/sonar/batch/mediumtest/BatchMediumTester.java b/sonar-batch/src/test/java/org/sonar/batch/mediumtest/BatchMediumTester.java new file mode 100644 index 00000000000..522d8b5fa1a --- /dev/null +++ b/sonar-batch/src/test/java/org/sonar/batch/mediumtest/BatchMediumTester.java @@ -0,0 +1,412 @@ +/* + * 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; + +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; +import org.sonar.batch.rule.RulesLoader; +import com.google.common.base.Function; +import com.google.common.io.Files; + +import java.io.File; +import java.io.FileInputStream; +import java.io.InputStreamReader; +import java.io.Reader; +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.Date; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Properties; + +import org.sonar.api.CoreProperties; +import org.sonar.api.SonarPlugin; +import org.sonar.api.batch.debt.internal.DefaultDebtModel; +import org.sonar.api.measures.CoreMetrics; +import org.sonar.api.measures.Metric; +import org.sonar.batch.bootstrap.AnalysisProperties; +import org.sonar.batch.bootstrapper.Batch; +import org.sonar.batch.bootstrapper.EnvironmentInformation; +import org.sonar.batch.bootstrapper.LogOutput; +import org.sonar.batch.issue.tracking.ServerLineHashesLoader; +import org.sonar.batch.protocol.input.ActiveRule; +import org.sonar.batch.protocol.input.BatchInput.ServerIssue; +import org.sonar.batch.protocol.input.FileData; +import org.sonar.batch.protocol.input.GlobalRepositories; +import org.sonar.batch.protocol.input.ProjectRepositories; +import org.sonar.batch.report.ReportPublisher; +import org.sonar.batch.repository.GlobalRepositoriesLoader; +import org.sonar.batch.repository.ProjectRepositoriesLoader; +import org.sonar.batch.repository.ServerIssuesLoader; +import org.sonar.core.component.ComponentKeys; + +/** + * Main utility class for writing batch medium tests. + * + */ +public class BatchMediumTester { + + public static final String MEDIUM_TEST_ENABLED = "sonar.mediumTest.enabled"; + private Batch batch; + + public static BatchMediumTesterBuilder builder() { + BatchMediumTesterBuilder builder = new BatchMediumTesterBuilder().registerCoreMetrics(); + builder.bootstrapProperties.put(MEDIUM_TEST_ENABLED, "true"); + builder.bootstrapProperties.put(ReportPublisher.KEEP_REPORT_PROP_KEY, "true"); + builder.bootstrapProperties.put(CoreProperties.WORKING_DIRECTORY, Files.createTempDir().getAbsolutePath()); + return builder; + } + + public static class BatchMediumTesterBuilder { + private final FakeGlobalRepositoriesLoader globalRefProvider = new FakeGlobalRepositoriesLoader(); + private final FakeProjectRepositoriesLoader projectRefProvider = new FakeProjectRepositoriesLoader(); + private final FakePluginInstaller pluginInstaller = new FakePluginInstaller(); + private final FakeServerIssuesLoader serverIssues = new FakeServerIssuesLoader(); + private final FakeServerLineHashesLoader serverLineHashes = new FakeServerLineHashesLoader(); + private final Map bootstrapProperties = new HashMap<>(); + private final FakeRulesLoader rulesLoader = new FakeRulesLoader(); + private LogOutput logOutput = null; + + public BatchMediumTester build() { + return new BatchMediumTester(this); + } + + public BatchMediumTesterBuilder setLogOutput(LogOutput logOutput) { + this.logOutput = logOutput; + return this; + } + + public BatchMediumTesterBuilder registerPlugin(String pluginKey, File location) { + pluginInstaller.add(pluginKey, location); + return this; + } + + public BatchMediumTesterBuilder registerPlugin(String pluginKey, SonarPlugin instance) { + pluginInstaller.add(pluginKey, instance); + return this; + } + + public BatchMediumTesterBuilder registerCoreMetrics() { + for (Metric m : CoreMetrics.getMetrics()) { + registerMetric(m); + } + return this; + } + + public BatchMediumTesterBuilder registerMetric(Metric metric) { + globalRefProvider.add(metric); + return this; + } + + public BatchMediumTesterBuilder addQProfile(String language, String name) { + projectRefProvider.addQProfile(language, name); + return this; + } + + public BatchMediumTesterBuilder addRule(Rule rule) { + rulesLoader.addRule(rule); + return this; + } + + public BatchMediumTesterBuilder addRule(String key, String repoKey, String internalKey, String name) { + Rule.Builder builder = Rule.newBuilder(); + builder.setKey(key); + builder.setRepository(repoKey); + if (internalKey != null) { + builder.setInternalKey(internalKey); + } + builder.setName(name); + + rulesLoader.addRule(builder.build()); + return this; + } + + public BatchMediumTesterBuilder addRules(RulesDefinition rulesDefinition) { + RulesDefinition.Context context = new RulesDefinition.Context(); + rulesDefinition.define(context); + List repositories = context.repositories(); + for (Repository repo : repositories) { + for (RulesDefinition.Rule rule : repo.rules()) { + this.addRule(rule.key(), rule.repository().key(), rule.internalKey(), rule.name()); + } + } + return this; + } + + public BatchMediumTesterBuilder addDefaultQProfile(String language, String name) { + addQProfile(language, name); + globalRefProvider.globalSettings().put("sonar.profile." + language, name); + return this; + } + + public BatchMediumTesterBuilder setPreviousAnalysisDate(Date previousAnalysis) { + projectRefProvider.ref.setLastAnalysisDate(previousAnalysis); + return this; + } + + public BatchMediumTesterBuilder bootstrapProperties(Map props) { + bootstrapProperties.putAll(props); + return this; + } + + public BatchMediumTesterBuilder activateRule(ActiveRule activeRule) { + projectRefProvider.addActiveRule(activeRule); + return this; + } + + public BatchMediumTesterBuilder addFileData(String moduleKey, String path, FileData fileData) { + projectRefProvider.addFileData(moduleKey, path, fileData); + return this; + } + + public BatchMediumTesterBuilder setLastBuildDate(Date d) { + projectRefProvider.setLastAnalysisDate(d); + return this; + } + + public BatchMediumTesterBuilder mockServerIssue(ServerIssue issue) { + serverIssues.getServerIssues().add(issue); + return this; + } + + public BatchMediumTesterBuilder mockLineHashes(String fileKey, String[] lineHashes) { + serverLineHashes.byKey.put(fileKey, lineHashes); + return this; + } + + } + + public void start() { + batch.start(); + } + + public void stop() { + batch.stop(); + } + + public void syncProject(String projectKey) { + batch.syncProject(projectKey); + } + + private BatchMediumTester(BatchMediumTesterBuilder builder) { + batch = Batch.builder() + .setEnableLoggingConfiguration(true) + .addComponents( + new EnvironmentInformation("mediumTest", "1.0"), + builder.pluginInstaller, + builder.globalRefProvider, + builder.projectRefProvider, + builder.serverIssues, + builder.serverLineHashes, + builder.rulesLoader, + new DefaultDebtModel()) + .setBootstrapProperties(builder.bootstrapProperties) + .setLogOutput(builder.logOutput) + .build(); + } + + public TaskBuilder newTask() { + return new TaskBuilder(this); + } + + public TaskBuilder newScanTask(File sonarProps) { + Properties prop = new Properties(); + try (Reader reader = new InputStreamReader(new FileInputStream(sonarProps), StandardCharsets.UTF_8)) { + prop.load(reader); + } catch (Exception e) { + throw new IllegalStateException("Unable to read configuration file", e); + } + TaskBuilder builder = new TaskBuilder(this); + builder.property("sonar.projectBaseDir", sonarProps.getParentFile().getAbsolutePath()); + for (Map.Entry entry : prop.entrySet()) { + builder.property(entry.getKey().toString(), entry.getValue().toString()); + } + return builder; + } + + public static class TaskBuilder { + private final Map taskProperties = new HashMap<>(); + private BatchMediumTester tester; + private IssueListener issueListener = null; + + public TaskBuilder(BatchMediumTester tester) { + this.tester = tester; + } + + public TaskResult start() { + TaskResult result = new TaskResult(); + Map props = new HashMap<>(); + props.putAll(taskProperties); + if (issueListener != null) { + tester.batch.executeTask(props, result, issueListener); + } else { + tester.batch.executeTask(props, result); + } + return result; + } + + public TaskBuilder properties(Map props) { + taskProperties.putAll(props); + return this; + } + + public TaskBuilder property(String key, String value) { + taskProperties.put(key, value); + return this; + } + + public TaskBuilder setIssueListener(IssueListener issueListener) { + this.issueListener = issueListener; + return this; + } + } + + private static class FakeRulesLoader implements RulesLoader { + private List rules = new LinkedList<>(); + + public FakeRulesLoader addRule(Rule rule) { + rules.add(rule); + return this; + } + + @Override + public List load() { + return rules; + } + + @Override + public boolean loadedFromCache() { + return false; + } + } + + private static class FakeGlobalRepositoriesLoader implements GlobalRepositoriesLoader { + + private int metricId = 1; + + private GlobalRepositories ref = new GlobalRepositories(); + + @Override + public GlobalRepositories load() { + return ref; + } + + public Map globalSettings() { + return ref.globalSettings(); + } + + public FakeGlobalRepositoriesLoader add(Metric metric) { + Boolean optimizedBestValue = metric.isOptimizedBestValue(); + ref.metrics().add(new org.sonar.batch.protocol.input.Metric(metricId, + metric.key(), + metric.getType().name(), + metric.getDescription(), + metric.getDirection(), + metric.getName(), + metric.getQualitative(), + metric.getUserManaged(), + metric.getWorstValue(), + metric.getBestValue(), + optimizedBestValue != null ? optimizedBestValue : false)); + metricId++; + return this; + } + + @Override + public boolean loadedFromCache() { + return true; + } + } + + private static class FakeProjectRepositoriesLoader implements ProjectRepositoriesLoader { + + private ProjectRepositories ref = new ProjectRepositories(); + + @Override + public ProjectRepositories load(ProjectDefinition projDefinition, AnalysisProperties taskProperties) { + return ref; + } + + public FakeProjectRepositoriesLoader addQProfile(String language, String name) { + // Use a fixed date to allow assertions + ref.addQProfile(new org.sonar.batch.protocol.input.QProfile(name, name, language, new Date(1234567891212L))); + return this; + } + + public FakeProjectRepositoriesLoader addActiveRule(ActiveRule activeRule) { + ref.addActiveRule(activeRule); + return this; + } + + public FakeProjectRepositoriesLoader addFileData(String moduleKey, String path, FileData fileData) { + ref.addFileData(moduleKey, path, fileData); + return this; + } + + public FakeProjectRepositoriesLoader setLastAnalysisDate(Date d) { + ref.setLastAnalysisDate(d); + return this; + } + + @Override + public boolean loadedFromCache() { + return true; + } + } + + private static class FakeServerIssuesLoader implements ServerIssuesLoader { + + private List serverIssues = new ArrayList<>(); + + public List getServerIssues() { + return serverIssues; + } + + @Override + public boolean load(String componentKey, Function consumer, boolean incremental) { + for (ServerIssue serverIssue : serverIssues) { + if (!incremental || ComponentKeys.createEffectiveKey(serverIssue.getModuleKey(), serverIssue.hasPath() ? serverIssue.getPath() : null).equals(componentKey)) { + consumer.apply(serverIssue); + } + } + return false; + } + + } + + private static class FakeServerLineHashesLoader implements ServerLineHashesLoader { + private Map byKey = new HashMap<>(); + + @Override + public String[] getLineHashes(String fileKey) { + if (byKey.containsKey(fileKey)) { + return byKey.get(fileKey); + } else { + throw new IllegalStateException("You forgot to mock line hashes for " + fileKey); + } + } + } + +} 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/issuesmode/EmptyFileTest.java b/sonar-batch/src/test/java/org/sonar/batch/mediumtest/issuesmode/EmptyFileTest.java new file mode 100644 index 00000000000..03e11861bd0 --- /dev/null +++ b/sonar-batch/src/test/java/org/sonar/batch/mediumtest/issuesmode/EmptyFileTest.java @@ -0,0 +1,90 @@ +/* + * 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.issuesmode; + +import org.apache.commons.io.filefilter.FileFilterUtils; + +import org.apache.commons.io.FileUtils; +import org.sonar.xoo.rule.XooRulesDefinition; +import com.google.common.collect.ImmutableMap; +import org.junit.After; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.TemporaryFolder; +import org.sonar.api.CoreProperties; +import org.sonar.api.utils.log.LogTester; +import org.sonar.batch.mediumtest.BatchMediumTester; +import org.sonar.batch.mediumtest.TaskResult; +import org.sonar.batch.protocol.input.ActiveRule; +import org.sonar.xoo.XooPlugin; + +import java.io.File; +import java.util.Date; + +import static org.assertj.core.api.Assertions.assertThat; + +public class EmptyFileTest { + + @Rule + public TemporaryFolder temp = new TemporaryFolder(); + + @Rule + public LogTester logTester = new LogTester(); + + public BatchMediumTester tester = BatchMediumTester.builder() + .bootstrapProperties(ImmutableMap.of(CoreProperties.ANALYSIS_MODE, CoreProperties.ANALYSIS_MODE_ISSUES)) + .registerPlugin("xoo", new XooPlugin()) + .addRules(new XooRulesDefinition()) + .addDefaultQProfile("xoo", "Sonar Way") + .activateRule(new ActiveRule("xoo", "OneIssuePerLine", null, "One issue per line", "MAJOR", "my/internal/key", "xoo")) + .setPreviousAnalysisDate(new Date()) + .build(); + + @Before + public void prepare() { + tester.start(); + } + + @After + public void stop() { + tester.stop(); + } + + @Test + public void testIssueTrackingWithIssueOnEmptyFile() throws Exception { + File projectDir = copyProject("/mediumtest/xoo/sample-with-empty-file"); + + TaskResult result = tester + .newScanTask(new File(projectDir, "sonar-project.properties")) + .property("sonar.xoo.internalKey", "my/internal/key") + .start(); + + assertThat(result.trackedIssues()).hasSize(11); + } + + private File copyProject(String path) throws Exception { + File projectDir = temp.newFolder(); + File originalProjectDir = new File(EmptyFileTest.class.getResource(path).toURI()); + FileUtils.copyDirectory(originalProjectDir, projectDir, FileFilterUtils.notFileFilter(FileFilterUtils.nameFileFilter(".sonar"))); + return projectDir; + } + +} diff --git a/sonar-batch/src/test/java/org/sonar/batch/mediumtest/issuesmode/IssueModeAndReportsMediumTest.java b/sonar-batch/src/test/java/org/sonar/batch/mediumtest/issuesmode/IssueModeAndReportsMediumTest.java new file mode 100644 index 00000000000..9b0a4a7a643 --- /dev/null +++ b/sonar-batch/src/test/java/org/sonar/batch/mediumtest/issuesmode/IssueModeAndReportsMediumTest.java @@ -0,0 +1,265 @@ +/* + * 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.issuesmode; + +import com.google.common.collect.ImmutableMap; + +import java.io.File; +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.LinkedList; +import java.util.List; + +import org.apache.commons.codec.digest.DigestUtils; +import org.apache.commons.io.FileUtils; +import org.apache.commons.io.filefilter.FileFilterUtils; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.rules.TemporaryFolder; +import org.sonar.api.CoreProperties; +import org.sonar.api.issue.Issue; +import org.sonar.api.utils.log.LogTester; +import org.sonar.batch.bootstrapper.IssueListener; +import org.sonar.batch.mediumtest.BatchMediumTester; +import org.sonar.batch.mediumtest.TaskResult; +import org.sonar.batch.mediumtest.issues.IssuesMediumTest; +import org.sonar.batch.protocol.Constants.Severity; +import org.sonar.batch.protocol.input.ActiveRule; +import org.sonar.batch.scan.report.ConsoleReport; +import org.sonar.xoo.XooPlugin; +import org.sonar.xoo.rule.XooRulesDefinition; +import static org.assertj.core.api.Assertions.assertThat; + +public class IssueModeAndReportsMediumTest { + + @org.junit.Rule + public TemporaryFolder temp = new TemporaryFolder(); + + @org.junit.Rule + public LogTester logTester = new LogTester(); + + private static SimpleDateFormat sdf = new SimpleDateFormat("dd/MM/yyyy"); + + private static Long date(String date) { + try { + return sdf.parse(date).getTime(); + } catch (ParseException e) { + throw new IllegalStateException(e); + } + } + + public BatchMediumTester tester = BatchMediumTester.builder() + .bootstrapProperties(ImmutableMap.of(CoreProperties.ANALYSIS_MODE, CoreProperties.ANALYSIS_MODE_ISSUES)) + .registerPlugin("xoo", new XooPlugin()) + .addDefaultQProfile("xoo", "Sonar Way") + .addRules(new XooRulesDefinition()) + .addRule("manual:MyManualIssue", "manual", "MyManualIssue", "My manual issue") + .addRule("manual:MyManualIssueDup", "manual", "MyManualIssue", "My manual issue") + .activateRule(new ActiveRule("xoo", "OneIssuePerLine", null, "One issue per line", "MAJOR", null, "xoo")) + .activateRule(new ActiveRule("xoo", "OneIssueOnDirPerFile", null, "OneIssueOnDirPerFile", "MAJOR", null, "xoo")) + .activateRule(new ActiveRule("xoo", "OneIssuePerModule", null, "OneIssuePerModule", "MAJOR", null, "xoo")) + .activateRule(new ActiveRule("manual", "MyManualIssue", null, "My manual issue", "MAJOR", null, null)) + .setPreviousAnalysisDate(new Date()) + // Existing issue that is still detected + .mockServerIssue(org.sonar.batch.protocol.input.BatchInput.ServerIssue.newBuilder().setKey("xyz") + .setModuleKey("sample") + .setPath("xources/hello/HelloJava.xoo") + .setRuleRepository("xoo") + .setRuleKey("OneIssuePerLine") + .setLine(1) + .setSeverity(Severity.MAJOR) + .setCreationDate(date("14/03/2004")) + .setChecksum(DigestUtils.md5Hex("packagehello;")) + .setStatus("OPEN") + .build()) + // Existing issue that is no more detected (will be closed) + .mockServerIssue(org.sonar.batch.protocol.input.BatchInput.ServerIssue.newBuilder().setKey("resolved") + .setModuleKey("sample") + .setPath("xources/hello/HelloJava.xoo") + .setRuleRepository("xoo") + .setRuleKey("OneIssuePerLine") + .setLine(1) + .setSeverity(Severity.MAJOR) + .setCreationDate(date("14/03/2004")) + .setChecksum(DigestUtils.md5Hex("dontexist")) + .setStatus("OPEN") + .build()) + // Existing issue on project that is no more detected + .mockServerIssue(org.sonar.batch.protocol.input.BatchInput.ServerIssue.newBuilder().setKey("resolved-on-project") + .setModuleKey("sample") + .setRuleRepository("xoo") + .setRuleKey("OneIssuePerModule") + .setSeverity(Severity.CRITICAL) + .setCreationDate(date("14/03/2004")) + .setStatus("OPEN") + .build()) + // Manual issue + .mockServerIssue(org.sonar.batch.protocol.input.BatchInput.ServerIssue.newBuilder().setKey("manual") + .setModuleKey("sample") + .setPath("xources/hello/HelloJava.xoo") + .setRuleRepository("manual") + .setRuleKey("MyManualIssue") + .setLine(1) + .setSeverity(Severity.MAJOR) + .setCreationDate(date("14/03/2004")) + .setChecksum(DigestUtils.md5Hex("packagehello;")) + .setStatus("OPEN") + .build()) + .build(); + + @Before + public void prepare() { + tester.start(); + } + + @After + public void stop() { + tester.stop(); + } + + private File copyProject(String path) throws Exception { + File projectDir = temp.newFolder(); + File originalProjectDir = new File(IssueModeAndReportsMediumTest.class.getResource(path).toURI()); + FileUtils.copyDirectory(originalProjectDir, projectDir, FileFilterUtils.notFileFilter(FileFilterUtils.nameFileFilter(".sonar"))); + return projectDir; + } + + @Test + public void testIssueTracking() throws Exception { + File projectDir = copyProject("/mediumtest/xoo/sample"); + + TaskResult result = tester + .newScanTask(new File(projectDir, "sonar-project.properties")) + .start(); + + int newIssues = 0; + int openIssues = 0; + int resolvedIssue = 0; + for (Issue issue : result.trackedIssues()) { + if (issue.isNew()) { + newIssues++; + } else if (issue.resolution() != null) { + resolvedIssue++; + } else { + openIssues++; + } + } + assertThat(newIssues).isEqualTo(16); + assertThat(openIssues).isEqualTo(2); + assertThat(resolvedIssue).isEqualTo(2); + } + + @Test + public void testConsoleReport() throws Exception { + File projectDir = copyProject("/mediumtest/xoo/sample"); + + tester + .newScanTask(new File(projectDir, "sonar-project.properties")) + .property("sonar.issuesReport.console.enable", "true") + .start(); + + assertThat(getReportLog()).contains("+16 issues", "+16 major"); + } + + @Test + public void testPostJob() throws Exception { + File projectDir = copyProject("/mediumtest/xoo/sample"); + + tester + .newScanTask(new File(projectDir, "sonar-project.properties")) + .property("sonar.xoo.enablePostJob", "true") + .start(); + + assertThat(logTester.logs()).contains("Resolved issues: 2", "Open issues: 18"); + } + + private String getReportLog() { + for (String log : logTester.logs()) { + if (log.contains(ConsoleReport.HEADER)) { + return log; + } + } + throw new IllegalStateException("No console report"); + } + + @Test + public void testHtmlReport() throws Exception { + File projectDir = copyProject("/mediumtest/xoo/sample"); + + tester + .newScanTask(new File(projectDir, "sonar-project.properties")) + .property("sonar.issuesReport.html.enable", "true") + .start(); + + assertThat(new File(projectDir, ".sonar/issues-report/issues-report.html")).exists(); + assertThat(new File(projectDir, ".sonar/issues-report/issues-report-light.html")).exists(); + } + + @Test + public void testHtmlReportNoFile() throws Exception { + File baseDir = temp.newFolder(); + File srcDir = new File(baseDir, "src"); + srcDir.mkdir(); + + tester.newTask() + .properties(ImmutableMap.builder() + .put("sonar.task", "scan") + .put("sonar.projectBaseDir", baseDir.getAbsolutePath()) + .put("sonar.projectKey", "sample") + .put("sonar.projectName", "Foo Project") + .put("sonar.projectVersion", "1.0-SNAPSHOT") + .put("sonar.projectDescription", "Description of Foo Project") + .put("sonar.sources", "src") + .put("sonar.issuesReport.html.enable", "true") + .build()) + .start(); + + assertThat(FileUtils.readFileToString(new File(baseDir, ".sonar/issues-report/issues-report.html"))).contains("No file analyzed"); + assertThat(FileUtils.readFileToString(new File(baseDir, ".sonar/issues-report/issues-report-light.html"))).contains("No file analyzed"); + } + + @Test + public void testIssueCallback() throws Exception { + File projectDir = new File(IssuesMediumTest.class.getResource("/mediumtest/xoo/sample").toURI()); + File tmpDir = temp.newFolder(); + FileUtils.copyDirectory(projectDir, tmpDir); + IssueRecorder issueListener = new IssueRecorder(); + + TaskResult result = tester + .newScanTask(new File(tmpDir, "sonar-project.properties")) + .setIssueListener(issueListener) + .start(); + + assertThat(result.trackedIssues()).hasSize(20); + assertThat(issueListener.issueList).hasSize(20); + } + + private class IssueRecorder implements IssueListener { + List issueList = new LinkedList<>(); + + @Override + public void handle(Issue issue) { + issueList.add(issue); + } + } + +} 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/preview/EmptyFileTest.java deleted file mode 100644 index f6849c64756..00000000000 --- a/sonar-batch/src/test/java/org/sonar/batch/mediumtest/preview/EmptyFileTest.java +++ /dev/null @@ -1,90 +0,0 @@ -/* - * 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.preview; - -import org.apache.commons.io.filefilter.FileFilterUtils; - -import org.apache.commons.io.FileUtils; -import org.sonar.xoo.rule.XooRulesDefinition; -import com.google.common.collect.ImmutableMap; -import org.junit.After; -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.TemporaryFolder; -import org.sonar.api.CoreProperties; -import org.sonar.api.utils.log.LogTester; -import org.sonar.batch.mediumtest.BatchMediumTester; -import org.sonar.batch.mediumtest.TaskResult; -import org.sonar.batch.protocol.input.ActiveRule; -import org.sonar.xoo.XooPlugin; - -import java.io.File; -import java.util.Date; - -import static org.assertj.core.api.Assertions.assertThat; - -public class EmptyFileTest { - - @Rule - public TemporaryFolder temp = new TemporaryFolder(); - - @Rule - public LogTester logTester = new LogTester(); - - public BatchMediumTester tester = BatchMediumTester.builder() - .bootstrapProperties(ImmutableMap.of(CoreProperties.ANALYSIS_MODE, CoreProperties.ANALYSIS_MODE_ISSUES)) - .registerPlugin("xoo", new XooPlugin()) - .addRules(new XooRulesDefinition()) - .addDefaultQProfile("xoo", "Sonar Way") - .activateRule(new ActiveRule("xoo", "OneIssuePerLine", null, "One issue per line", "MAJOR", "my/internal/key", "xoo")) - .setPreviousAnalysisDate(new Date()) - .build(); - - @Before - public void prepare() { - tester.start(); - } - - @After - public void stop() { - tester.stop(); - } - - @Test - public void testIssueTrackingWithIssueOnEmptyFile() throws Exception { - File projectDir = copyProject("/mediumtest/xoo/sample-with-empty-file"); - - TaskResult result = tester - .newScanTask(new File(projectDir, "sonar-project.properties")) - .property("sonar.xoo.internalKey", "my/internal/key") - .start(); - - assertThat(result.trackedIssues()).hasSize(11); - } - - private File copyProject(String path) throws Exception { - File projectDir = temp.newFolder(); - File originalProjectDir = new File(EmptyFileTest.class.getResource(path).toURI()); - FileUtils.copyDirectory(originalProjectDir, projectDir, FileFilterUtils.notFileFilter(FileFilterUtils.nameFileFilter(".sonar"))); - return projectDir; - } - -} 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/preview/IssueModeAndReportsMediumTest.java deleted file mode 100644 index 92743b4f125..00000000000 --- a/sonar-batch/src/test/java/org/sonar/batch/mediumtest/preview/IssueModeAndReportsMediumTest.java +++ /dev/null @@ -1,265 +0,0 @@ -/* - * 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.preview; - -import com.google.common.collect.ImmutableMap; - -import java.io.File; -import java.text.ParseException; -import java.text.SimpleDateFormat; -import java.util.Date; -import java.util.LinkedList; -import java.util.List; - -import org.apache.commons.codec.digest.DigestUtils; -import org.apache.commons.io.FileUtils; -import org.apache.commons.io.filefilter.FileFilterUtils; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; -import org.junit.rules.TemporaryFolder; -import org.sonar.api.CoreProperties; -import org.sonar.api.issue.Issue; -import org.sonar.api.utils.log.LogTester; -import org.sonar.batch.bootstrapper.IssueListener; -import org.sonar.batch.mediumtest.BatchMediumTester; -import org.sonar.batch.mediumtest.TaskResult; -import org.sonar.batch.mediumtest.issues.IssuesMediumTest; -import org.sonar.batch.protocol.Constants.Severity; -import org.sonar.batch.protocol.input.ActiveRule; -import org.sonar.batch.scan.report.ConsoleReport; -import org.sonar.xoo.XooPlugin; -import org.sonar.xoo.rule.XooRulesDefinition; -import static org.assertj.core.api.Assertions.assertThat; - -public class IssueModeAndReportsMediumTest { - - @org.junit.Rule - public TemporaryFolder temp = new TemporaryFolder(); - - @org.junit.Rule - public LogTester logTester = new LogTester(); - - private static SimpleDateFormat sdf = new SimpleDateFormat("dd/MM/yyyy"); - - private static Long date(String date) { - try { - return sdf.parse(date).getTime(); - } catch (ParseException e) { - throw new IllegalStateException(e); - } - } - - public BatchMediumTester tester = BatchMediumTester.builder() - .bootstrapProperties(ImmutableMap.of(CoreProperties.ANALYSIS_MODE, CoreProperties.ANALYSIS_MODE_ISSUES)) - .registerPlugin("xoo", new XooPlugin()) - .addDefaultQProfile("xoo", "Sonar Way") - .addRules(new XooRulesDefinition()) - .addRule("manual:MyManualIssue", "manual", "MyManualIssue", "My manual issue") - .addRule("manual:MyManualIssueDup", "manual", "MyManualIssue", "My manual issue") - .activateRule(new ActiveRule("xoo", "OneIssuePerLine", null, "One issue per line", "MAJOR", null, "xoo")) - .activateRule(new ActiveRule("xoo", "OneIssueOnDirPerFile", null, "OneIssueOnDirPerFile", "MAJOR", null, "xoo")) - .activateRule(new ActiveRule("xoo", "OneIssuePerModule", null, "OneIssuePerModule", "MAJOR", null, "xoo")) - .activateRule(new ActiveRule("manual", "MyManualIssue", null, "My manual issue", "MAJOR", null, null)) - .setPreviousAnalysisDate(new Date()) - // Existing issue that is still detected - .mockServerIssue(org.sonar.batch.protocol.input.BatchInput.ServerIssue.newBuilder().setKey("xyz") - .setModuleKey("sample") - .setPath("xources/hello/HelloJava.xoo") - .setRuleRepository("xoo") - .setRuleKey("OneIssuePerLine") - .setLine(1) - .setSeverity(Severity.MAJOR) - .setCreationDate(date("14/03/2004")) - .setChecksum(DigestUtils.md5Hex("packagehello;")) - .setStatus("OPEN") - .build()) - // Existing issue that is no more detected (will be closed) - .mockServerIssue(org.sonar.batch.protocol.input.BatchInput.ServerIssue.newBuilder().setKey("resolved") - .setModuleKey("sample") - .setPath("xources/hello/HelloJava.xoo") - .setRuleRepository("xoo") - .setRuleKey("OneIssuePerLine") - .setLine(1) - .setSeverity(Severity.MAJOR) - .setCreationDate(date("14/03/2004")) - .setChecksum(DigestUtils.md5Hex("dontexist")) - .setStatus("OPEN") - .build()) - // Existing issue on project that is no more detected - .mockServerIssue(org.sonar.batch.protocol.input.BatchInput.ServerIssue.newBuilder().setKey("resolved-on-project") - .setModuleKey("sample") - .setRuleRepository("xoo") - .setRuleKey("OneIssuePerModule") - .setSeverity(Severity.CRITICAL) - .setCreationDate(date("14/03/2004")) - .setStatus("OPEN") - .build()) - // Manual issue - .mockServerIssue(org.sonar.batch.protocol.input.BatchInput.ServerIssue.newBuilder().setKey("manual") - .setModuleKey("sample") - .setPath("xources/hello/HelloJava.xoo") - .setRuleRepository("manual") - .setRuleKey("MyManualIssue") - .setLine(1) - .setSeverity(Severity.MAJOR) - .setCreationDate(date("14/03/2004")) - .setChecksum(DigestUtils.md5Hex("packagehello;")) - .setStatus("OPEN") - .build()) - .build(); - - @Before - public void prepare() { - tester.start(); - } - - @After - public void stop() { - tester.stop(); - } - - private File copyProject(String path) throws Exception { - File projectDir = temp.newFolder(); - File originalProjectDir = new File(IssueModeAndReportsMediumTest.class.getResource(path).toURI()); - FileUtils.copyDirectory(originalProjectDir, projectDir, FileFilterUtils.notFileFilter(FileFilterUtils.nameFileFilter(".sonar"))); - return projectDir; - } - - @Test - public void testIssueTracking() throws Exception { - File projectDir = copyProject("/mediumtest/xoo/sample"); - - TaskResult result = tester - .newScanTask(new File(projectDir, "sonar-project.properties")) - .start(); - - int newIssues = 0; - int openIssues = 0; - int resolvedIssue = 0; - for (Issue issue : result.trackedIssues()) { - if (issue.isNew()) { - newIssues++; - } else if (issue.resolution() != null) { - resolvedIssue++; - } else { - openIssues++; - } - } - assertThat(newIssues).isEqualTo(16); - assertThat(openIssues).isEqualTo(2); - assertThat(resolvedIssue).isEqualTo(2); - } - - @Test - public void testConsoleReport() throws Exception { - File projectDir = copyProject("/mediumtest/xoo/sample"); - - tester - .newScanTask(new File(projectDir, "sonar-project.properties")) - .property("sonar.issuesReport.console.enable", "true") - .start(); - - assertThat(getReportLog()).contains("+16 issues", "+16 major"); - } - - @Test - public void testPostJob() throws Exception { - File projectDir = copyProject("/mediumtest/xoo/sample"); - - tester - .newScanTask(new File(projectDir, "sonar-project.properties")) - .property("sonar.xoo.enablePostJob", "true") - .start(); - - assertThat(logTester.logs()).contains("Resolved issues: 2", "Open issues: 18"); - } - - private String getReportLog() { - for (String log : logTester.logs()) { - if (log.contains(ConsoleReport.HEADER)) { - return log; - } - } - throw new IllegalStateException("No console report"); - } - - @Test - public void testHtmlReport() throws Exception { - File projectDir = copyProject("/mediumtest/xoo/sample"); - - tester - .newScanTask(new File(projectDir, "sonar-project.properties")) - .property("sonar.issuesReport.html.enable", "true") - .start(); - - assertThat(new File(projectDir, ".sonar/issues-report/issues-report.html")).exists(); - assertThat(new File(projectDir, ".sonar/issues-report/issues-report-light.html")).exists(); - } - - @Test - public void testHtmlReportNoFile() throws Exception { - File baseDir = temp.newFolder(); - File srcDir = new File(baseDir, "src"); - srcDir.mkdir(); - - tester.newTask() - .properties(ImmutableMap.builder() - .put("sonar.task", "scan") - .put("sonar.projectBaseDir", baseDir.getAbsolutePath()) - .put("sonar.projectKey", "sample") - .put("sonar.projectName", "Foo Project") - .put("sonar.projectVersion", "1.0-SNAPSHOT") - .put("sonar.projectDescription", "Description of Foo Project") - .put("sonar.sources", "src") - .put("sonar.issuesReport.html.enable", "true") - .build()) - .start(); - - assertThat(FileUtils.readFileToString(new File(baseDir, ".sonar/issues-report/issues-report.html"))).contains("No file analyzed"); - assertThat(FileUtils.readFileToString(new File(baseDir, ".sonar/issues-report/issues-report-light.html"))).contains("No file analyzed"); - } - - @Test - public void testIssueCallback() throws Exception { - File projectDir = new File(IssuesMediumTest.class.getResource("/mediumtest/xoo/sample").toURI()); - File tmpDir = temp.newFolder(); - FileUtils.copyDirectory(projectDir, tmpDir); - IssueRecorder issueListener = new IssueRecorder(); - - TaskResult result = tester - .newScanTask(new File(tmpDir, "sonar-project.properties")) - .setIssueListener(issueListener) - .start(); - - assertThat(result.trackedIssues()).hasSize(20); - assertThat(issueListener.issueList).hasSize(20); - } - - private class IssueRecorder implements IssueListener { - List issueList = new LinkedList<>(); - - @Override - public void handle(Issue issue) { - issueList.add(issue); - } - } - -} 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/UserRepositoryLoaderTest.java b/sonar-batch/src/test/java/org/sonar/batch/repository/user/UserRepositoryLoaderTest.java new file mode 100644 index 00000000000..bd0b3e7af88 --- /dev/null +++ b/sonar-batch/src/test/java/org/sonar/batch/repository/user/UserRepositoryLoaderTest.java @@ -0,0 +1,80 @@ +/* + * 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.repository.user; + +import org.junit.rules.ExpectedException; + +import org.junit.Rule; +import org.mockito.Mockito; +import org.sonar.batch.bootstrap.WSLoaderResult; +import com.google.common.io.ByteSource; +import org.sonar.batch.bootstrap.WSLoader; +import org.junit.Test; +import org.sonar.batch.protocol.input.BatchInput; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.util.Arrays; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.tuple; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +public class UserRepositoryLoaderTest { + @Rule + public final ExpectedException exception = ExpectedException.none(); + + @Test + public void testLoad() throws IOException { + WSLoader wsLoader = mock(WSLoader.class); + UserRepositoryLoader userRepo = new UserRepositoryLoader(wsLoader); + + ByteArrayOutputStream out = new ByteArrayOutputStream(); + BatchInput.User.Builder builder = BatchInput.User.newBuilder(); + builder.setLogin("fmallet").setName("Freddy Mallet").build().writeDelimitedTo(out); + builder.setLogin("sbrandhof").setName("Simon").build().writeDelimitedTo(out); + + ByteSource source = mock(ByteSource.class); + when(wsLoader.loadSource("/batch/users?logins=fmallet,sbrandhof")).thenReturn(new WSLoaderResult<>(source, true)); + when(source.openStream()).thenReturn(new ByteArrayInputStream(out.toByteArray())); + + 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); + UserRepositoryLoader userRepo = new UserRepositoryLoader(wsLoader); + ByteSource source = mock(ByteSource.class); + when(wsLoader.loadSource("/batch/users?logins=fmallet,sbrandhof")).thenReturn(new WSLoaderResult<>(source, true)); + + InputStream errorInputStream = mock(InputStream.class); + Mockito.doThrow(IOException.class).when(errorInputStream).read(); + when(source.openStream()).thenReturn(errorInputStream); + + exception.expect(IllegalStateException.class); + exception.expectMessage("Unable to get user details from server"); + + 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/repository/user/UserRepositoryTest.java b/sonar-batch/src/test/java/org/sonar/batch/repository/user/UserRepositoryTest.java deleted file mode 100644 index 4aa5c91153d..00000000000 --- a/sonar-batch/src/test/java/org/sonar/batch/repository/user/UserRepositoryTest.java +++ /dev/null @@ -1,80 +0,0 @@ -/* - * 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.repository.user; - -import org.junit.rules.ExpectedException; - -import org.junit.Rule; -import org.mockito.Mockito; -import org.sonar.batch.bootstrap.WSLoaderResult; -import com.google.common.io.ByteSource; -import org.sonar.batch.bootstrap.WSLoader; -import org.junit.Test; -import org.sonar.batch.protocol.input.BatchInput; - -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.util.Arrays; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.tuple; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - -public class UserRepositoryTest { - @Rule - public final ExpectedException exception = ExpectedException.none(); - - @Test - public void testLoad() throws IOException { - WSLoader wsLoader = mock(WSLoader.class); - UserRepository userRepo = new UserRepository(wsLoader); - - ByteArrayOutputStream out = new ByteArrayOutputStream(); - BatchInput.User.Builder builder = BatchInput.User.newBuilder(); - builder.setLogin("fmallet").setName("Freddy Mallet").build().writeDelimitedTo(out); - builder.setLogin("sbrandhof").setName("Simon").build().writeDelimitedTo(out); - - ByteSource source = mock(ByteSource.class); - 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")); - } - - @Test - public void testInputStreamError() throws IOException { - WSLoader wsLoader = mock(WSLoader.class); - UserRepository userRepo = new UserRepository(wsLoader); - ByteSource source = mock(ByteSource.class); - when(wsLoader.loadSource("/batch/users?logins=fmallet,sbrandhof")).thenReturn(new WSLoaderResult<>(source, true)); - - InputStream errorInputStream = mock(InputStream.class); - Mockito.doThrow(IOException.class).when(errorInputStream).read(); - when(source.openStream()).thenReturn(errorInputStream); - - 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")); - } -} diff --git a/sonar-batch/src/test/java/org/sonar/batch/scan/ProjectWSLoaderProviderTest.java b/sonar-batch/src/test/java/org/sonar/batch/scan/ProjectWSLoaderProviderTest.java new file mode 100644 index 00000000000..d4fe0b2e109 --- /dev/null +++ b/sonar-batch/src/test/java/org/sonar/batch/scan/ProjectWSLoaderProviderTest.java @@ -0,0 +1,66 @@ +/* + * SonarQube, open source software quality management tool. + * Copyright (C) 2008-2014 SonarSource + * mailto:contact AT sonarsource DOT com + * + * SonarQube is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * SonarQube is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.batch.scan; + +import org.sonar.api.batch.AnalysisMode; +import org.junit.Before; +import org.junit.Test; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.sonar.batch.bootstrap.AnalysisProperties; +import org.sonar.batch.bootstrap.ServerClient; +import org.sonar.batch.bootstrap.WSLoader; +import org.sonar.batch.bootstrap.WSLoader.LoadStrategy; +import org.sonar.home.cache.PersistentCache; + +import java.util.HashMap; +import java.util.Map; + +import static org.assertj.core.api.Assertions.assertThat; + +public class ProjectWSLoaderProviderTest { + @Mock + private PersistentCache cache; + + @Mock + private ServerClient client; + + @Mock + private AnalysisMode mode; + + private ProjectWSLoaderProvider loaderProvider; + private Map propMap; + private AnalysisProperties props; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + loaderProvider = new ProjectWSLoaderProvider(); + propMap = new HashMap<>(); + } + + @Test + public void testDefault() { + props = new AnalysisProperties(propMap, null); + + WSLoader loader = loaderProvider.provide(props, mode, cache, client); + assertThat(loader.getStrategy()).isEqualTo(LoadStrategy.SERVER_ONLY); + } +} diff --git a/sonar-batch/src/test/java/org/sonar/batch/scan/WSLoaderProjectProviderTest.java b/sonar-batch/src/test/java/org/sonar/batch/scan/WSLoaderProjectProviderTest.java deleted file mode 100644 index c0366c40af6..00000000000 --- a/sonar-batch/src/test/java/org/sonar/batch/scan/WSLoaderProjectProviderTest.java +++ /dev/null @@ -1,67 +0,0 @@ -/* - * SonarQube, open source software quality management tool. - * Copyright (C) 2008-2014 SonarSource - * mailto:contact AT sonarsource DOT com - * - * SonarQube is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * SonarQube is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -package org.sonar.batch.scan; - -import org.sonar.api.batch.AnalysisMode; -import org.junit.Before; -import org.junit.Test; -import org.mockito.Mock; -import org.mockito.MockitoAnnotations; -import org.sonar.batch.bootstrap.AnalysisProperties; -import org.sonar.batch.bootstrap.ServerClient; -import org.sonar.batch.bootstrap.WSLoader; -import org.sonar.batch.bootstrap.WSLoader.LoadStrategy; -import org.sonar.home.cache.PersistentCache; - -import java.util.HashMap; -import java.util.Map; - -import static org.assertj.core.api.Assertions.assertThat; - -public class WSLoaderProjectProviderTest { - @Mock - private PersistentCache cache; - - @Mock - private ServerClient client; - - @Mock - private AnalysisMode mode; - - private ProjectWSLoaderProvider loaderProvider; - private Map propMap; - private AnalysisProperties props; - - @Before - public void setUp() { - MockitoAnnotations.initMocks(this); - loaderProvider = new ProjectWSLoaderProvider(); - propMap = new HashMap<>(); - } - - @Test - public void testDefault() { - props = new AnalysisProperties(propMap, null); - - WSLoader loader = loaderProvider.provide(props, mode, cache, client); - assertThat(loader.getStrategy()).isEqualTo(LoadStrategy.SERVER_FIRST); - assertThat(loader.isCacheEnabled()).isEqualTo(false); - } -} 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 -- cgit v1.2.3