diff options
author | Simon Brandhof <simon.brandhof@sonarsource.com> | 2015-02-25 22:22:20 +0100 |
---|---|---|
committer | Simon Brandhof <simon.brandhof@sonarsource.com> | 2015-03-02 11:02:08 +0100 |
commit | af3d0b3c6b555616b3f6207620dd92360a653996 (patch) | |
tree | 3f48b9d5324e89e40590a7b67c5cf514ef54839e /server | |
parent | 4ea0dd1c85069c253e4dbdc1b7c6e203b5beb082 (diff) | |
download | sonarqube-af3d0b3c6b555616b3f6207620dd92360a653996.tar.gz sonarqube-af3d0b3c6b555616b3f6207620dd92360a653996.zip |
Refactor table ANALYSIS_REPORTS because of MySQL packet size limitation
* do not store report zip in table ANALYSIS_REPORTS but in FS dir {home}/data/analysis
* do not store snapshot id in table but in protobuf report
Diffstat (limited to 'server')
60 files changed, 1207 insertions, 1212 deletions
diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/AnalysisReportQueue.java b/server/sonar-server/src/main/java/org/sonar/server/computation/AnalysisReportQueue.java deleted file mode 100644 index 3c57b1c5e91..00000000000 --- a/server/sonar-server/src/main/java/org/sonar/server/computation/AnalysisReportQueue.java +++ /dev/null @@ -1,130 +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.server.computation; - -import org.sonar.api.ServerComponent; -import org.sonar.api.utils.System2; -import org.sonar.core.computation.db.AnalysisReportDto; -import org.sonar.core.permission.GlobalPermissions; -import org.sonar.core.persistence.DbSession; -import org.sonar.core.persistence.MyBatis; -import org.sonar.server.db.DbClient; -import org.sonar.server.user.UserSession; - -import javax.annotation.CheckForNull; -import javax.annotation.Nullable; -import java.io.InputStream; -import java.util.List; - -import static com.google.common.base.Preconditions.checkArgument; -import static org.sonar.core.computation.db.AnalysisReportDto.Status.PENDING; - -public class AnalysisReportQueue implements ServerComponent { - - private final DbClient dbClient; - private final System2 system2; - - public AnalysisReportQueue(DbClient dbClient, System2 system2) { - this.dbClient = dbClient; - this.system2 = system2; - } - - /** - * Adds a report to the queue and returns the generated key - */ - public String add(String projectKey, Long snapshotId, @Nullable InputStream reportData) { - // TODO security must not be handled here - UserSession.get().checkGlobalPermission(GlobalPermissions.SCAN_EXECUTION); - - AnalysisReportDto report = newPendingAnalysisReport(projectKey) - .setSnapshotId(snapshotId) - .setData(reportData); - DbSession session = dbClient.openSession(false); - try { - checkThatProjectExistsInDatabase(projectKey, session); - return insertInDb(report, session).getKey(); - } finally { - MyBatis.closeQuietly(session); - } - } - - private AnalysisReportDto newPendingAnalysisReport(String projectKey) { - return new AnalysisReportDto() - .setProjectKey(projectKey) - .setStatus(PENDING); - } - - private void checkThatProjectExistsInDatabase(String projectKey, DbSession session) { - dbClient.componentDao().getByKey(session, projectKey); - } - - private AnalysisReportDto insertInDb(AnalysisReportDto reportTemplate, DbSession session) { - AnalysisReportDto report = dbClient.analysisReportDao().insert(session, reportTemplate); - session.commit(); - - return report; - } - - public void remove(AnalysisReportDto report) { - checkArgument(report.getStatus().isInFinalState()); - - DbSession session = dbClient.openSession(false); - try { - report.setFinishedAt(system2.now()); - dbClient.analysisReportDao().delete(session, report.getId()); - session.commit(); - } finally { - MyBatis.closeQuietly(session); - } - } - - @CheckForNull - public AnalysisReportDto pop() { - DbSession session = dbClient.openSession(false); - try { - return dbClient.analysisReportDao().pop(session); - } finally { - MyBatis.closeQuietly(session); - } - } - - public List<AnalysisReportDto> findByProjectKey(String projectKey) { - DbSession session = dbClient.openSession(false); - try { - return dbClient.analysisReportDao().selectByProjectKey(session, projectKey); - } finally { - MyBatis.closeQuietly(session); - } - } - - /** - * All the reports of the queue, whatever the status - */ - public List<AnalysisReportDto> all() { - DbSession session = dbClient.openSession(false); - try { - return dbClient.analysisReportDao().selectAll(session); - } finally { - MyBatis.closeQuietly(session); - } - } - -} diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/ComputationComponents.java b/server/sonar-server/src/main/java/org/sonar/server/computation/ComputationContainer.java index a26e06d99d4..21e9e7c9cb2 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/computation/ComputationComponents.java +++ b/server/sonar-server/src/main/java/org/sonar/server/computation/ComputationContainer.java @@ -19,25 +19,45 @@ */ package org.sonar.server.computation; +import org.sonar.api.platform.ComponentContainer; import org.sonar.core.issue.db.UpdateConflictResolver; -import org.sonar.server.computation.issue.*; +import org.sonar.server.computation.issue.IssueCache; +import org.sonar.server.computation.issue.IssueComputation; +import org.sonar.server.computation.issue.RuleCache; +import org.sonar.server.computation.issue.RuleCacheLoader; +import org.sonar.server.computation.issue.ScmAccountCache; +import org.sonar.server.computation.issue.ScmAccountCacheLoader; +import org.sonar.server.computation.issue.SourceLinesCache; import org.sonar.server.computation.step.ComputationSteps; +import org.sonar.server.platform.Platform; import org.sonar.server.view.index.ViewIndex; import java.util.Arrays; import java.util.List; -public class ComputationComponents { +public class ComputationContainer { - private ComputationComponents() { - // only static stuff + public void execute(ReportQueue.Item item) { + ComponentContainer container = Platform.getInstance().getContainer(); + ComponentContainer child = container.createChild(); + child.addSingletons(componentClasses()); + child.addSingletons(ComputationSteps.orderedStepClasses()); + child.startComponents(); + try { + child.getComponentByType(ComputationService.class).process(item); + } finally { + child.stopComponents(); + // TODO not possible to have multiple children -> will be + // a problem when we will have multiple concurrent computation workers + container.removeChild(); + } } /** - * List of all objects to be injected in the picocontainer dedicated to computation stack. + * List of all objects to be injected in the picocontainer dedicated to computation stack. * Does not contain the steps declared in {@link org.sonar.server.computation.step.ComputationSteps#orderedStepClasses()}. */ - public static List nonStepComponents() { + static List componentClasses() { return Arrays.asList( ComputationService.class, ComputationSteps.class, diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/ComputationContext.java b/server/sonar-server/src/main/java/org/sonar/server/computation/ComputationContext.java index a7709c8e139..2e314220aca 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/computation/ComputationContext.java +++ b/server/sonar-server/src/main/java/org/sonar/server/computation/ComputationContext.java @@ -20,41 +20,33 @@ package org.sonar.server.computation; -import com.google.common.base.Preconditions; import org.sonar.batch.protocol.output.BatchReport; +import org.sonar.batch.protocol.output.BatchReportReader; import org.sonar.core.component.ComponentDto; -import org.sonar.core.computation.db.AnalysisReportDto; -import org.sonar.server.computation.step.ParseReportStep; public class ComputationContext { - private final AnalysisReportDto reportDto; + private final BatchReportReader reportReader; private final ComponentDto project; - /** - * Cache of analysis date as it can be accessed several times - */ - private BatchReport.Metadata reportMetadata = null; + // cache of metadata as it's frequently accessed + private final BatchReport.Metadata reportMetadata; - public ComputationContext(AnalysisReportDto reportDto, ComponentDto project) { - this.reportDto = reportDto; + public ComputationContext(BatchReportReader reportReader, ComponentDto project) { + this.reportReader = reportReader; this.project = project; + this.reportMetadata = reportReader.readMetadata(); } - public AnalysisReportDto getReportDto() { - return reportDto; + public BatchReport.Metadata getReportMetadata() { + return reportMetadata; } public ComponentDto getProject() { return project; } - public BatchReport.Metadata getReportMetadata() { - Preconditions.checkState(reportMetadata != null, "Report metadata is available after execution of " + ParseReportStep.class); - return reportMetadata; - } - - public void setReportMetadata(BatchReport.Metadata m) { - this.reportMetadata = m; + public BatchReportReader getReportReader() { + return reportReader; } } diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/ComputationService.java b/server/sonar-server/src/main/java/org/sonar/server/computation/ComputationService.java index 77ee77fb272..8787e16ec94 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/computation/ComputationService.java +++ b/server/sonar-server/src/main/java/org/sonar/server/computation/ComputationService.java @@ -21,12 +21,16 @@ package org.sonar.server.computation; import com.google.common.base.Throwables; +import org.apache.commons.io.FileUtils; import org.apache.commons.lang.ArrayUtils; import org.sonar.api.ServerComponent; import org.sonar.api.utils.System2; +import org.sonar.api.utils.TempFolder; +import org.sonar.api.utils.ZipUtils; import org.sonar.api.utils.log.Logger; import org.sonar.api.utils.log.Loggers; import org.sonar.api.utils.log.Profiler; +import org.sonar.batch.protocol.output.BatchReportReader; import org.sonar.core.activity.Activity; import org.sonar.core.component.ComponentDto; import org.sonar.core.computation.db.AnalysisReportDto; @@ -37,6 +41,9 @@ import org.sonar.server.computation.step.ComputationStep; import org.sonar.server.computation.step.ComputationSteps; import org.sonar.server.db.DbClient; +import java.io.File; +import java.io.IOException; + public class ComputationService implements ServerComponent { private static final Logger LOG = Loggers.get(ComputationService.class); @@ -44,43 +51,67 @@ public class ComputationService implements ServerComponent { private final DbClient dbClient; private final ComputationSteps steps; private final ActivityService activityService; + private final TempFolder tempFolder; + private final System2 system; - public ComputationService(DbClient dbClient, ComputationSteps steps, ActivityService activityService) { + public ComputationService(DbClient dbClient, ComputationSteps steps, ActivityService activityService, + TempFolder tempFolder, System2 system) { this.dbClient = dbClient; this.steps = steps; this.activityService = activityService; + this.tempFolder = tempFolder; + this.system = system; } - public void process(AnalysisReportDto report) { - Profiler profiler = Profiler.create(LOG).startInfo(String.format( - "#%s - %s - processing analysis report", report.getId(), report.getProjectKey())); + public void process(ReportQueue.Item item) { + Profiler profiler = Profiler.create(LOG).startDebug(String.format( + "Analysis of project %s (report %d)", item.dto.getProjectKey(), item.dto.getId())); - ComponentDto project = loadProject(report); + ComponentDto project = loadProject(item); try { - ComputationContext context = new ComputationContext(report, project); + File reportDir = extractReportInDir(item); + BatchReportReader reader = new BatchReportReader(reportDir); + ComputationContext context = new ComputationContext(reader, project); for (ComputationStep step : steps.orderedSteps()) { if (ArrayUtils.contains(step.supportedProjectQualifiers(), context.getProject().qualifier())) { - Profiler stepProfiler = Profiler.create(LOG).startInfo(step.getDescription()); + Profiler stepProfiler = Profiler.createIfDebug(LOG).startDebug(step.getDescription()); step.execute(context); - stepProfiler.stopInfo(); + stepProfiler.stopDebug(); } } - report.succeed(); + item.dto.succeed(); } catch (Exception e) { - report.fail(); + item.dto.fail(); throw Throwables.propagate(e); } finally { - logActivity(report, project); + item.dto.setFinishedAt(system.now()); + logActivity(item.dto, project); profiler.stopInfo(); } } - private ComponentDto loadProject(AnalysisReportDto report) { + private File extractReportInDir(ReportQueue.Item item) { + File dir = tempFolder.newDir(); + try { + Profiler profiler = Profiler.createIfDebug(LOG).start(); + ZipUtils.unzip(item.zipFile, dir); + if (profiler.isDebugEnabled()) { + String message = String.format("Report extracted | size=%s | project=%s", + FileUtils.byteCountToDisplaySize(FileUtils.sizeOf(dir)), item.dto.getProjectKey()); + profiler.stopDebug(message); + } + return dir; + } catch (IOException e) { + throw new IllegalStateException(String.format("Fail to unzip %s into %s", item.zipFile, dir), e); + } + } + + private ComponentDto loadProject(ReportQueue.Item queueItem) { DbSession session = dbClient.openSession(false); try { - return dbClient.componentDao().getByKey(session, report.getProjectKey()); + return dbClient.componentDao().getByKey(session, queueItem.dto.getProjectKey()); } finally { MyBatis.closeQuietly(session); } @@ -90,7 +121,7 @@ public class ComputationService implements ServerComponent { DbSession session = dbClient.openSession(false); try { report.setFinishedAt(System2.INSTANCE.now()); - activityService.write(session, Activity.Type.ANALYSIS_REPORT, new AnalysisReportLog(report, project)); + activityService.write(session, Activity.Type.ANALYSIS_REPORT, new ReportActivity(report, project)); session.commit(); } finally { MyBatis.closeQuietly(session); diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/ComputationThread.java b/server/sonar-server/src/main/java/org/sonar/server/computation/ComputationThread.java index 07c9a23e3a0..e70b15feb73 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/computation/ComputationThread.java +++ b/server/sonar-server/src/main/java/org/sonar/server/computation/ComputationThread.java @@ -20,67 +20,56 @@ package org.sonar.server.computation; - -import org.sonar.api.platform.ComponentContainer; +import com.google.common.annotations.VisibleForTesting; import org.sonar.api.utils.log.Logger; import org.sonar.api.utils.log.Loggers; -import org.sonar.core.computation.db.AnalysisReportDto; -import org.sonar.server.computation.step.ComputationSteps; -import org.sonar.server.platform.Platform; /** - * This thread pops queue of reports and processes the report if present + * This thread pops a report from the queue and integrate it. */ public class ComputationThread implements Runnable { + private static final Logger LOG = Loggers.get(ComputationThread.class); - private final AnalysisReportQueue queue; + private final ReportQueue queue; + private final ComputationContainer container; + + public ComputationThread(ReportQueue queue) { + this.queue = queue; + this.container = new ComputationContainer(); + } - public ComputationThread(AnalysisReportQueue queue) { + @VisibleForTesting + ComputationThread(ReportQueue queue, ComputationContainer container) { this.queue = queue; + this.container = container; } @Override public void run() { - AnalysisReportDto report = null; + ReportQueue.Item item = null; try { - report = queue.pop(); + item = queue.pop(); } catch (Exception e) { LOG.error("Failed to pop the queue of analysis reports", e); } - if (report != null) { + if (item != null) { try { - process(report); + container.execute(item); } catch (Exception e) { LOG.error(String.format( - "Failed to process analysis report %d of project %s", report.getId(), report.getProjectKey()), e); + "Failed to process analysis report %d of project %s", item.dto.getId(), item.dto.getProjectKey()), e); } finally { - removeSilentlyFromQueue(report); + removeSilentlyFromQueue(item); } } } - private void removeSilentlyFromQueue(AnalysisReportDto report) { + private void removeSilentlyFromQueue(ReportQueue.Item item) { try { - queue.remove(report); + queue.remove(item); } catch (Exception e) { - LOG.error(String.format("Failed to remove analysis report %d from queue", report.getId()), e); - } - } - - private void process(AnalysisReportDto report) { - ComponentContainer container = Platform.getInstance().getContainer(); - ComponentContainer child = container.createChild(); - child.addSingletons(ComputationSteps.orderedStepClasses()); - child.addSingletons(ComputationComponents.nonStepComponents()); - child.startComponents(); - try { - child.getComponentByType(ComputationService.class).process(report); - } finally { - child.stopComponents(); - // TODO not possible to have multiple children -> will be - // a problem when we will have multiple concurrent computation workers - container.removeChild(); + LOG.error(String.format("Failed to remove analysis report %d from queue", item.dto.getId()), e); } } } diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/ComputationThreadLauncher.java b/server/sonar-server/src/main/java/org/sonar/server/computation/ComputationThreadLauncher.java index c19b80a0a7b..18bf2a35633 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/computation/ComputationThreadLauncher.java +++ b/server/sonar-server/src/main/java/org/sonar/server/computation/ComputationThreadLauncher.java @@ -36,14 +36,14 @@ public class ComputationThreadLauncher implements Startable, ServerComponent, Se public static final String THREAD_NAME_PREFIX = "computation-"; - private final AnalysisReportQueue queue; + private final ReportQueue queue; private final ScheduledExecutorService executorService; private final long delayBetweenTasks; private final long delayForFirstStart; private final TimeUnit timeUnit; - public ComputationThreadLauncher(AnalysisReportQueue queue) { + public ComputationThreadLauncher(ReportQueue queue) { this.queue = queue; this.executorService = Executors.newSingleThreadScheduledExecutor(newThreadFactory()); @@ -53,7 +53,7 @@ public class ComputationThreadLauncher implements Startable, ServerComponent, Se } @VisibleForTesting - ComputationThreadLauncher(AnalysisReportQueue queue, long delayForFirstStart, long delayBetweenTasks, TimeUnit timeUnit) { + ComputationThreadLauncher(ReportQueue queue, long delayForFirstStart, long delayBetweenTasks, TimeUnit timeUnit) { this.queue = queue; this.executorService = Executors.newSingleThreadScheduledExecutor(newThreadFactory()); diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/AnalysisReportLog.java b/server/sonar-server/src/main/java/org/sonar/server/computation/ReportActivity.java index 1b307d69171..b4d7165a82f 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/computation/AnalysisReportLog.java +++ b/server/sonar-server/src/main/java/org/sonar/server/computation/ReportActivity.java @@ -30,14 +30,14 @@ import java.util.Map; import static org.sonar.api.utils.DateUtils.formatDateTimeNullSafe; import static org.sonar.api.utils.DateUtils.longToDate; -public class AnalysisReportLog implements ActivityLog { +public class ReportActivity implements ActivityLog { private static final String ACTION = "LOG_ANALYSIS_REPORT"; private final AnalysisReportDto report; private final ComponentDto project; - public AnalysisReportLog(AnalysisReportDto report, ComponentDto project) { + public ReportActivity(AnalysisReportDto report, ComponentDto project) { this.report = report; this.project = project; } diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/ReportQueue.java b/server/sonar-server/src/main/java/org/sonar/server/computation/ReportQueue.java new file mode 100644 index 00000000000..8139db0d050 --- /dev/null +++ b/server/sonar-server/src/main/java/org/sonar/server/computation/ReportQueue.java @@ -0,0 +1,188 @@ +/* + * 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.server.computation; + +import org.apache.commons.io.FileUtils; +import org.sonar.api.ServerComponent; +import org.sonar.api.config.Settings; +import org.sonar.api.utils.internal.Uuids; +import org.sonar.api.utils.log.Loggers; +import org.sonar.core.computation.db.AnalysisReportDto; +import org.sonar.core.persistence.DbSession; +import org.sonar.core.persistence.MyBatis; +import org.sonar.process.ProcessConstants; +import org.sonar.server.db.DbClient; + +import javax.annotation.CheckForNull; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.util.List; + +import static org.sonar.core.computation.db.AnalysisReportDto.Status.PENDING; + +public class ReportQueue implements ServerComponent { + + public static class Item { + public final AnalysisReportDto dto; + public final File zipFile; + + public Item(AnalysisReportDto dto, File zipFile) { + this.dto = dto; + this.zipFile = zipFile; + } + } + + private final DbClient dbClient; + private final Settings settings; + + public ReportQueue(DbClient dbClient, Settings settings) { + this.dbClient = dbClient; + this.settings = settings; + } + + public Item add(String projectKey, InputStream reportData) { + String uuid = Uuids.create(); + File file = reportFileForUuid(uuid); + + DbSession session = dbClient.openSession(false); + try { + checkThatProjectExistsInDatabase(projectKey, session); + + // save report data on file. Directory is created if it does not exist yet. + FileUtils.copyInputStreamToFile(reportData, file); + + // add report metadata to the queue + AnalysisReportDto dto = new AnalysisReportDto() + .setProjectKey(projectKey) + .setStatus(PENDING) + .setUuid(uuid); + dbClient.analysisReportDao().insert(session, dto); + session.commit(); + return new Item(dto, file); + + } catch (Exception e) { + FileUtils.deleteQuietly(file); + throw new IllegalStateException("Fail to store analysis report of project " + projectKey, e); + } finally { + MyBatis.closeQuietly(session); + } + } + + private void checkThatProjectExistsInDatabase(String projectKey, DbSession session) { + dbClient.componentDao().getByKey(session, projectKey); + } + + public void remove(Item item) { + DbSession session = dbClient.openSession(false); + try { + FileUtils.deleteQuietly(item.zipFile); + dbClient.analysisReportDao().delete(session, item.dto.getId()); + session.commit(); + } finally { + MyBatis.closeQuietly(session); + } + } + + @CheckForNull + public Item pop() { + DbSession session = dbClient.openSession(false); + try { + AnalysisReportDto dto = dbClient.analysisReportDao().pop(session); + if (dto != null) { + File file = reportFileForUuid(dto.getUuid()); + if (file.exists()) { + return new Item(dto, file); + } + Loggers.get(getClass()).error("Analysis report not found: " + file.getAbsolutePath()); + dbClient.analysisReportDao().delete(session, dto.getId()); + session.commit(); + } + return null; + } finally { + MyBatis.closeQuietly(session); + } + } + + public List<AnalysisReportDto> findByProjectKey(String projectKey) { + DbSession session = dbClient.openSession(false); + try { + return dbClient.analysisReportDao().selectByProjectKey(session, projectKey); + } finally { + MyBatis.closeQuietly(session); + } + } + + /** + * Truncates table ANALYSIS_REPORTS and delete all files from directory {data}/analysis + */ + public void clear() { + File dir = reportsDir(); + try { + FileUtils.deleteDirectory(dir); + } catch (IOException e) { + throw new IllegalStateException("Fail to delete directory: " + dir.getAbsolutePath(), e); + } + + DbSession session = dbClient.openSession(false); + try { + dbClient.analysisReportDao().truncate(session); + session.commit(); + } finally { + MyBatis.closeQuietly(session); + } + } + + public void resetToPendingStatus() { + DbSession session = dbClient.openSession(false); + try { + dbClient.analysisReportDao().resetAllToPendingStatus(session); + session.commit(); + } finally { + MyBatis.closeQuietly(session); + } + } + + /** + * All the reports of the queue, whatever the status + */ + public List<AnalysisReportDto> all() { + DbSession session = dbClient.openSession(false); + try { + return dbClient.analysisReportDao().selectAll(session); + } finally { + MyBatis.closeQuietly(session); + } + } + + /** + * This directory is a flat list of the reports referenced in table ANALYSIS_REPORTS. + * Never return null but the directory may not exist. + */ + private File reportsDir() { + return new File(settings.getString(ProcessConstants.PATH_DATA), "analysis"); + } + + private File reportFileForUuid(String uuid) { + return new File(reportsDir(), String.format("%s.zip", uuid)); + } +} diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/AnalysisReportQueueCleaner.java b/server/sonar-server/src/main/java/org/sonar/server/computation/ReportQueueCleaner.java index 9e660b68c7e..7abc9f1953e 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/computation/AnalysisReportQueueCleaner.java +++ b/server/sonar-server/src/main/java/org/sonar/server/computation/ReportQueueCleaner.java @@ -23,10 +23,6 @@ package org.sonar.server.computation; import org.picocontainer.Startable; import org.sonar.api.ServerComponent; import org.sonar.api.platform.ServerUpgradeStatus; -import org.sonar.core.persistence.DbSession; -import org.sonar.core.persistence.MyBatis; -import org.sonar.server.computation.db.AnalysisReportDao; -import org.sonar.server.db.DbClient; /** * Clean-up queue of reports at server startup: @@ -36,30 +32,22 @@ import org.sonar.server.db.DbClient; * <li>reset reports that were in status WORKING while server stopped</li> * </ul> */ -public class AnalysisReportQueueCleaner implements Startable, ServerComponent { +public class ReportQueueCleaner implements Startable, ServerComponent { private final ServerUpgradeStatus serverUpgradeStatus; - private final DbClient dbClient; + private final ReportQueue queue; - public AnalysisReportQueueCleaner(ServerUpgradeStatus serverUpgradeStatus, DbClient dbClient) { + public ReportQueueCleaner(ServerUpgradeStatus serverUpgradeStatus, ReportQueue queue) { this.serverUpgradeStatus = serverUpgradeStatus; - this.dbClient = dbClient; + this.queue = queue; } @Override public void start() { - AnalysisReportDao dao = dbClient.analysisReportDao(); - DbSession session = dbClient.openSession(false); - try { - if (serverUpgradeStatus.isUpgraded()) { - dao.truncate(session); - } else { - dao.resetAllToPendingStatus(session); - } - - session.commit(); - } finally { - MyBatis.closeQuietly(session); + if (serverUpgradeStatus.isUpgraded()) { + queue.clear(); + } else { + queue.resetToPendingStatus(); } } diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/db/AnalysisReportDao.java b/server/sonar-server/src/main/java/org/sonar/server/computation/db/AnalysisReportDao.java index 11f22499c5f..f08edbf5b3a 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/computation/db/AnalysisReportDao.java +++ b/server/sonar-server/src/main/java/org/sonar/server/computation/db/AnalysisReportDao.java @@ -21,27 +21,14 @@ package org.sonar.server.computation.db; import com.google.common.annotations.VisibleForTesting; -import com.google.common.io.ByteStreams; -import org.apache.commons.io.IOUtils; import org.sonar.api.utils.System2; -import org.sonar.api.utils.ZipUtils; import org.sonar.core.computation.db.AnalysisReportDto; import org.sonar.core.computation.db.AnalysisReportMapper; import org.sonar.core.persistence.DaoComponent; -import org.sonar.core.persistence.DatabaseUtils; import org.sonar.core.persistence.DbSession; import javax.annotation.CheckForNull; -import javax.annotation.Nullable; - -import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.sql.Connection; -import java.sql.PreparedStatement; -import java.sql.ResultSet; -import java.sql.SQLException; -import java.sql.Types; + import java.util.List; import static org.sonar.core.computation.db.AnalysisReportDto.Status.PENDING; @@ -55,8 +42,7 @@ public class AnalysisReportDao implements DaoComponent { this(System2.INSTANCE); } - @VisibleForTesting - AnalysisReportDao(System2 system2) { + public AnalysisReportDao(System2 system2) { this.system2 = system2; } @@ -111,78 +97,10 @@ public class AnalysisReportDao implements DaoComponent { public AnalysisReportDto insert(DbSession session, AnalysisReportDto report) { report.setCreatedAt(system2.now()); report.setUpdatedAt(system2.now()); - - Connection connection = session.getConnection(); - PreparedStatement ps = null; - try { - ps = connection.prepareStatement( - "insert into analysis_reports " + - " (project_key, snapshot_id, report_status, report_data, created_at, updated_at, started_at, finished_at)" + - " values (?, ?, ?, ?, ?, ?, ?, ?)"); - ps.setString(1, report.getProjectKey()); - ps.setLong(2, report.getSnapshotId()); - ps.setString(3, report.getStatus().toString()); - setData(ps, 4, report.getData()); - ps.setLong(5, report.getCreatedAt()); - setLong(ps, 6, report.getUpdatedAt()); - setLong(ps, 7, report.getStartedAt()); - setLong(ps, 8, report.getFinishedAt()); - ps.executeUpdate(); - connection.commit(); - } catch (SQLException | IOException e) { - throw new IllegalStateException(String.format("Failed to insert %s in the database", report), e); - } finally { - DatabaseUtils.closeQuietly(ps); - } - + mapper(session).insert(report); return report; } - private void setLong(PreparedStatement ps, int index, @Nullable Long time) throws SQLException { - if (time == null) { - ps.setNull(index, Types.BIGINT); - } else { - ps.setLong(index, time); - } - } - - private void setData(PreparedStatement ps, int parameterIndex, @Nullable InputStream reportDataStream) throws IOException, SQLException { - if (reportDataStream == null) { - ps.setBytes(parameterIndex, null); - } else { - ps.setBytes(parameterIndex, ByteStreams.toByteArray(reportDataStream)); - } - } - - @CheckForNull - public void selectAndDecompressToDir(DbSession session, long id, File toDir) { - Connection connection = session.getConnection(); - InputStream stream = null; - PreparedStatement ps = null; - ResultSet rs = null; - try { - ps = connection.prepareStatement("select report_data from analysis_reports where id=?"); - ps.setLong(1, id); - - rs = ps.executeQuery(); - if (rs.next()) { - stream = rs.getBinaryStream(1); - if (stream != null) { - ZipUtils.unzip(stream, toDir); - } - } - // TODO what to do if id not found or no stream ? - } catch (SQLException e) { - throw new IllegalStateException(String.format("Failed to read report '%d' in the database", id), e); - } catch (IOException e) { - throw new IllegalStateException(String.format("Failed to decompress report '%d'", id), e); - } finally { - IOUtils.closeQuietly(stream); - DatabaseUtils.closeQuietly(rs); - DatabaseUtils.closeQuietly(ps); - } - } - public void delete(DbSession session, long id) { mapper(session).delete(id); } diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/step/ComputationSteps.java b/server/sonar-server/src/main/java/org/sonar/server/computation/step/ComputationSteps.java index d73706b7060..973c5dadf55 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/computation/step/ComputationSteps.java +++ b/server/sonar-server/src/main/java/org/sonar/server/computation/step/ComputationSteps.java @@ -21,11 +21,14 @@ package org.sonar.server.computation.step; import com.google.common.collect.Lists; -import org.sonar.server.computation.ComputationComponents; +import org.sonar.server.computation.ComputationContainer; import java.util.Arrays; import java.util.List; +/** + * Ordered list of steps to be executed + */ public class ComputationSteps { /** @@ -77,6 +80,6 @@ public class ComputationSteps { return step; } } - throw new IllegalStateException("Component not found: " + clazz + ". Check " + ComputationComponents.class); + throw new IllegalStateException("Component not found: " + clazz + ". Check " + ComputationContainer.class); } } diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/step/ParseReportStep.java b/server/sonar-server/src/main/java/org/sonar/server/computation/step/ParseReportStep.java index 9d6f4a547e4..0eff6e32988 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/computation/step/ParseReportStep.java +++ b/server/sonar-server/src/main/java/org/sonar/server/computation/step/ParseReportStep.java @@ -20,34 +20,17 @@ package org.sonar.server.computation.step; -import org.apache.commons.io.FileUtils; import org.sonar.api.resources.Qualifiers; -import org.sonar.api.utils.TempFolder; -import org.sonar.api.utils.log.Logger; -import org.sonar.api.utils.log.Loggers; -import org.sonar.batch.protocol.output.BatchOutputReader; import org.sonar.batch.protocol.output.BatchReport; -import org.sonar.core.computation.db.AnalysisReportDto; -import org.sonar.core.persistence.DbSession; -import org.sonar.core.persistence.MyBatis; import org.sonar.server.computation.ComputationContext; import org.sonar.server.computation.issue.IssueComputation; -import org.sonar.server.db.DbClient; - -import java.io.File; public class ParseReportStep implements ComputationStep { - private static final Logger LOG = Loggers.get(ParseReportStep.class); - private final IssueComputation issueComputation; - private final DbClient dbClient; - private final TempFolder tempFolder; - public ParseReportStep(IssueComputation issueComputation, DbClient dbClient, TempFolder tempFolder) { + public ParseReportStep(IssueComputation issueComputation) { this.issueComputation = issueComputation; - this.dbClient = dbClient; - this.tempFolder = tempFolder; } @Override @@ -57,45 +40,18 @@ public class ParseReportStep implements ComputationStep { @Override public void execute(ComputationContext context) { - File reportDir = tempFolder.newDir(); - try { - // extract compressed report from database and uncompress it in temporary directory - extractReport(context.getReportDto(), reportDir); - - // prepare parsing of report - BatchOutputReader reader = new BatchOutputReader(reportDir); - BatchReport.Metadata reportMetadata = reader.readMetadata(); - context.setReportMetadata(reportMetadata); - - // and parse! - int rootComponentRef = reportMetadata.getRootComponentRef(); - recursivelyProcessComponent(reader, context, rootComponentRef); - issueComputation.afterReportProcessing(); - - } finally { - FileUtils.deleteQuietly(reportDir); - } - } - - private void extractReport(AnalysisReportDto report, File toDir) { - long startTime = System.currentTimeMillis(); - DbSession session = dbClient.openSession(false); - try { - dbClient.analysisReportDao().selectAndDecompressToDir(session, report.getId(), toDir); - } finally { - MyBatis.closeQuietly(session); - } - long stopTime = System.currentTimeMillis(); - LOG.info(String.format("Report extracted in %dms | uncompressed size=%s | project=%s", - stopTime - startTime, FileUtils.byteCountToDisplaySize(FileUtils.sizeOf(toDir)), report.getProjectKey())); + int rootComponentRef = context.getReportMetadata().getRootComponentRef(); + recursivelyProcessComponent(context, rootComponentRef); + issueComputation.afterReportProcessing(); } - private void recursivelyProcessComponent(BatchOutputReader reportReader, ComputationContext context, int componentRef) { - BatchReport.Component component = reportReader.readComponent(componentRef); + private void recursivelyProcessComponent(ComputationContext context, int componentRef) { + BatchReport.Component component = context.getReportReader().readComponent(componentRef); if (component != null) { - issueComputation.processComponentIssues(context, component.getUuid(), reportReader.readComponentIssues(componentRef)); + Iterable<BatchReport.Issue> issues = context.getReportReader().readComponentIssues(componentRef); + issueComputation.processComponentIssues(context, component.getUuid(), issues); for (Integer childRef : component.getChildRefsList()) { - recursivelyProcessComponent(reportReader, context, childRef); + recursivelyProcessComponent(context, childRef); } } } diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/step/SwitchSnapshotStep.java b/server/sonar-server/src/main/java/org/sonar/server/computation/step/SwitchSnapshotStep.java index 1be36deb720..b073cd53ca1 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/computation/step/SwitchSnapshotStep.java +++ b/server/sonar-server/src/main/java/org/sonar/server/computation/step/SwitchSnapshotStep.java @@ -22,7 +22,6 @@ package org.sonar.server.computation.step; import org.sonar.api.resources.Qualifiers; import org.sonar.core.component.SnapshotDto; -import org.sonar.core.computation.db.AnalysisReportDto; import org.sonar.core.persistence.DbSession; import org.sonar.core.persistence.MyBatis; import org.sonar.server.component.db.SnapshotDao; @@ -48,8 +47,9 @@ public class SwitchSnapshotStep implements ComputationStep { public void execute(ComputationContext context) { DbSession session = dbClient.openSession(true); try { - disablePreviousSnapshot(session, context.getReportDto()); - enableCurrentSnapshot(session, context.getReportDto()); + long snapshotId = context.getReportMetadata().getSnapshotId(); + disablePreviousSnapshot(session, snapshotId); + enableCurrentSnapshot(session, snapshotId); } finally { MyBatis.closeQuietly(session); } @@ -60,16 +60,8 @@ public class SwitchSnapshotStep implements ComputationStep { return "Switch last snapshot flag"; } - private void disablePreviousSnapshot(DbSession session, AnalysisReportDto report) { - SnapshotDto referenceSnapshot; - - try { - referenceSnapshot = dbClient.snapshotDao().getByKey(session, report.getSnapshotId()); - } catch (Exception exception) { - throw new IllegalStateException(String.format("Unexpected error while trying to retrieve snapshot of analysis %s", report), exception); - } - - List<SnapshotDto> snapshots = dbClient.snapshotDao().findSnapshotAndChildrenOfProjectScope(session, referenceSnapshot); + private void disablePreviousSnapshot(DbSession session, long reportSnapshotId) { + List<SnapshotDto> snapshots = dbClient.snapshotDao().findSnapshotAndChildrenOfProjectScope(session, dbClient.snapshotDao().getByKey(session, reportSnapshotId)); for (SnapshotDto snapshot : snapshots) { SnapshotDto previousLastSnapshot = dbClient.snapshotDao().getLastSnapshot(session, snapshot); if (previousLastSnapshot != null) { @@ -79,9 +71,9 @@ public class SwitchSnapshotStep implements ComputationStep { } } - private void enableCurrentSnapshot(DbSession session, AnalysisReportDto report) { + private void enableCurrentSnapshot(DbSession session, long reportSnapshotId) { SnapshotDao dao = dbClient.snapshotDao(); - SnapshotDto snapshot = dao.getByKey(session, report.getSnapshotId()); + SnapshotDto snapshot = dao.getByKey(session, reportSnapshotId); SnapshotDto previousLastSnapshot = dao.getLastSnapshot(session, snapshot); boolean isLast = dao.isLast(snapshot, previousLastSnapshot); diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/ws/HistoryWsAction.java b/server/sonar-server/src/main/java/org/sonar/server/computation/ws/HistoryWsAction.java index b1448a53792..eec1336a157 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/computation/ws/HistoryWsAction.java +++ b/server/sonar-server/src/main/java/org/sonar/server/computation/ws/HistoryWsAction.java @@ -42,21 +42,19 @@ public class HistoryWsAction implements ComputationWsAction, RequestHandler { public static final String PARAM_TYPE = "type"; - public static final String SEARCH_ACTION = "history"; - - private final ActivityService logService; + private final ActivityService activityService; private final ActivityMapping mapping; - public HistoryWsAction(ActivityService logService, ActivityMapping mapping) { - this.logService = logService; + public HistoryWsAction(ActivityService activityService, ActivityMapping mapping) { + this.activityService = activityService; this.mapping = mapping; } @Override public void define(WebService.NewController controller) { WebService.NewAction action = controller - .createAction(SEARCH_ACTION) - .setDescription("Search for activities") + .createAction("history") + .setDescription("Past integrations of analysis reports") .setSince("5.0") .setInternal(true) .setHandler(this); @@ -70,13 +68,13 @@ public class HistoryWsAction implements ComputationWsAction, RequestHandler { public void handle(Request request, Response response) { checkUserRights(); - ActivityQuery query = logService.newActivityQuery(); + ActivityQuery query = activityService.newActivityQuery(); query.setTypes(Arrays.asList(Activity.Type.ANALYSIS_REPORT)); SearchOptions searchOptions = SearchOptions.create(request); QueryContext queryContext = mapping.newQueryOptions(searchOptions); - Result<Activity> results = logService.search(query, queryContext); + Result<Activity> results = activityService.search(query, queryContext); JsonWriter json = response.newJsonWriter().beginObject(); searchOptions.writeStatistics(json, results); diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/ws/IsQueueEmptyWebService.java b/server/sonar-server/src/main/java/org/sonar/server/computation/ws/IsQueueEmptyWebService.java index 986438a7883..611043076e6 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/computation/ws/IsQueueEmptyWebService.java +++ b/server/sonar-server/src/main/java/org/sonar/server/computation/ws/IsQueueEmptyWebService.java @@ -26,7 +26,7 @@ import org.sonar.api.server.ws.RequestHandler; import org.sonar.api.server.ws.Response; import org.sonar.api.server.ws.WebService; import org.sonar.core.computation.db.AnalysisReportDto; -import org.sonar.server.computation.AnalysisReportQueue; +import org.sonar.server.computation.ReportQueue; import java.util.List; @@ -38,7 +38,7 @@ public class IsQueueEmptyWebService implements WebService { private final IsQueueEmptyWsAction action; - public IsQueueEmptyWebService(AnalysisReportQueue queue) { + public IsQueueEmptyWebService(ReportQueue queue) { this.action = new IsQueueEmptyWsAction(queue); } @@ -52,9 +52,9 @@ public class IsQueueEmptyWebService implements WebService { } static class IsQueueEmptyWsAction implements RequestHandler { - private final AnalysisReportQueue queue; + private final ReportQueue queue; - public IsQueueEmptyWsAction(AnalysisReportQueue queue) { + public IsQueueEmptyWsAction(ReportQueue queue) { this.queue = queue; } diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/ws/QueueWsAction.java b/server/sonar-server/src/main/java/org/sonar/server/computation/ws/QueueWsAction.java index cf9f54029cc..39e6d3dcff4 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/computation/ws/QueueWsAction.java +++ b/server/sonar-server/src/main/java/org/sonar/server/computation/ws/QueueWsAction.java @@ -26,7 +26,7 @@ import org.sonar.api.server.ws.Response; import org.sonar.api.server.ws.WebService; import org.sonar.api.utils.text.JsonWriter; import org.sonar.core.computation.db.AnalysisReportDto; -import org.sonar.server.computation.AnalysisReportQueue; +import org.sonar.server.computation.ReportQueue; import java.util.List; @@ -36,9 +36,9 @@ import static org.sonar.api.utils.DateUtils.longToDate; * @since 5.0 */ public class QueueWsAction implements ComputationWsAction, RequestHandler { - private final AnalysisReportQueue queue; + private final ReportQueue queue; - public QueueWsAction(AnalysisReportQueue queue) { + public QueueWsAction(ReportQueue queue) { this.queue = queue; } diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/ws/SubmitReportWsAction.java b/server/sonar-server/src/main/java/org/sonar/server/computation/ws/SubmitReportWsAction.java index d474e73bb3b..eb3e7d93259 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/computation/ws/SubmitReportWsAction.java +++ b/server/sonar-server/src/main/java/org/sonar/server/computation/ws/SubmitReportWsAction.java @@ -20,12 +20,15 @@ package org.sonar.server.computation.ws; +import org.apache.commons.io.IOUtils; import org.sonar.api.server.ws.Request; import org.sonar.api.server.ws.RequestHandler; import org.sonar.api.server.ws.Response; import org.sonar.api.server.ws.WebService; -import org.sonar.server.computation.AnalysisReportQueue; +import org.sonar.core.permission.GlobalPermissions; import org.sonar.server.computation.ComputationThreadLauncher; +import org.sonar.server.computation.ReportQueue; +import org.sonar.server.user.UserSession; import java.io.InputStream; @@ -33,13 +36,12 @@ public class SubmitReportWsAction implements ComputationWsAction, RequestHandler public static final String ACTION = "submit_report"; public static final String PARAM_PROJECT_KEY = "projectKey"; - public static final String PARAM_SNAPSHOT = "snapshot"; public static final String PARAM_REPORT_DATA = "report"; - private final AnalysisReportQueue queue; + private final ReportQueue queue; private final ComputationThreadLauncher workerLauncher; - public SubmitReportWsAction(AnalysisReportQueue queue, ComputationThreadLauncher workerLauncher) { + public SubmitReportWsAction(ReportQueue queue, ComputationThreadLauncher workerLauncher) { this.queue = queue; this.workerLauncher = workerLauncher; } @@ -59,12 +61,6 @@ public class SubmitReportWsAction implements ComputationWsAction, RequestHandler .setExampleValue("org.codehaus.sonar:sonar"); action - .createParam(PARAM_SNAPSHOT) - .setRequired(true) - .setDescription("Snapshot ID") - .setExampleValue("123"); - - action .createParam(PARAM_REPORT_DATA) .setRequired(false) .setDescription("Report file. Format is not an API, it changes among SonarQube versions."); @@ -72,16 +68,21 @@ public class SubmitReportWsAction implements ComputationWsAction, RequestHandler @Override public void handle(Request request, Response response) throws Exception { + UserSession.get().checkGlobalPermission(GlobalPermissions.SCAN_EXECUTION); String projectKey = request.mandatoryParam(PARAM_PROJECT_KEY); - long snapshotId = request.mandatoryParamAsLong(PARAM_SNAPSHOT); - try (InputStream reportData = request.paramAsInputStream(PARAM_REPORT_DATA)) { - String reportKey = queue.add(projectKey, snapshotId, reportData); + InputStream reportData = request.paramAsInputStream(PARAM_REPORT_DATA); + try { + ReportQueue.Item item = queue.add(projectKey, reportData); workerLauncher.startAnalysisTaskNow(); response.newJsonWriter() .beginObject() - .prop("key", reportKey) + // do not write integer for forward-compatibility, for example + // if we want to write UUID later + .prop("key", String.valueOf(item.dto.getId())) .endObject() .close(); + } finally { + IOUtils.closeQuietly(reportData); } } } diff --git a/server/sonar-server/src/main/java/org/sonar/server/platform/ServerComponents.java b/server/sonar-server/src/main/java/org/sonar/server/platform/ServerComponents.java index 959fe205322..cf8302be667 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/platform/ServerComponents.java +++ b/server/sonar-server/src/main/java/org/sonar/server/platform/ServerComponents.java @@ -53,7 +53,12 @@ import org.sonar.core.measure.db.MeasureFilterDao; import org.sonar.core.metric.DefaultMetricFinder; import org.sonar.core.notification.DefaultNotificationManager; import org.sonar.core.permission.PermissionFacade; -import org.sonar.core.persistence.*; +import org.sonar.core.persistence.DaoUtils; +import org.sonar.core.persistence.DatabaseVersion; +import org.sonar.core.persistence.DefaultDatabase; +import org.sonar.core.persistence.MyBatis; +import org.sonar.core.persistence.SemaphoreUpdater; +import org.sonar.core.persistence.SemaphoresImpl; import org.sonar.core.purge.PurgeProfiler; import org.sonar.core.qualitygate.db.ProjectQgateAssociationDao; import org.sonar.core.qualitygate.db.QualityGateConditionDao; @@ -77,7 +82,12 @@ import org.sonar.server.activity.index.ActivityNormalizer; import org.sonar.server.activity.ws.ActivitiesWebService; import org.sonar.server.activity.ws.ActivityMapping; import org.sonar.server.authentication.ws.AuthenticationWs; -import org.sonar.server.batch.*; +import org.sonar.server.batch.BatchIndex; +import org.sonar.server.batch.BatchWs; +import org.sonar.server.batch.GlobalRepositoryAction; +import org.sonar.server.batch.IssuesAction; +import org.sonar.server.batch.ProjectRepositoryAction; +import org.sonar.server.batch.ProjectRepositoryLoader; import org.sonar.server.charts.ChartFactory; import org.sonar.server.component.ComponentCleanerService; import org.sonar.server.component.ComponentService; @@ -86,12 +96,20 @@ import org.sonar.server.component.DefaultRubyComponentService; import org.sonar.server.component.db.ComponentDao; import org.sonar.server.component.db.ComponentIndexDao; import org.sonar.server.component.db.SnapshotDao; -import org.sonar.server.component.ws.*; -import org.sonar.server.computation.AnalysisReportQueue; -import org.sonar.server.computation.AnalysisReportQueueCleaner; +import org.sonar.server.component.ws.ComponentAppAction; +import org.sonar.server.component.ws.ComponentsWs; +import org.sonar.server.component.ws.EventsWs; +import org.sonar.server.component.ws.ProjectsWs; +import org.sonar.server.component.ws.ResourcesWs; import org.sonar.server.computation.ComputationThreadLauncher; +import org.sonar.server.computation.ReportQueue; +import org.sonar.server.computation.ReportQueueCleaner; import org.sonar.server.computation.db.AnalysisReportDao; -import org.sonar.server.computation.ws.*; +import org.sonar.server.computation.ws.ComputationWebService; +import org.sonar.server.computation.ws.HistoryWsAction; +import org.sonar.server.computation.ws.IsQueueEmptyWebService; +import org.sonar.server.computation.ws.QueueWsAction; +import org.sonar.server.computation.ws.SubmitReportWsAction; import org.sonar.server.config.ws.PropertiesWs; import org.sonar.server.dashboard.db.DashboardDao; import org.sonar.server.dashboard.db.WidgetDao; @@ -103,7 +121,14 @@ import org.sonar.server.db.DbClient; import org.sonar.server.db.EmbeddedDatabaseFactory; import org.sonar.server.db.migrations.DatabaseMigrations; import org.sonar.server.db.migrations.DatabaseMigrator; -import org.sonar.server.debt.*; +import org.sonar.server.debt.DebtCharacteristicsXMLImporter; +import org.sonar.server.debt.DebtModelBackup; +import org.sonar.server.debt.DebtModelLookup; +import org.sonar.server.debt.DebtModelOperations; +import org.sonar.server.debt.DebtModelPluginRepository; +import org.sonar.server.debt.DebtModelService; +import org.sonar.server.debt.DebtModelXMLExporter; +import org.sonar.server.debt.DebtRulesXMLImporter; import org.sonar.server.design.FileDesignWidget; import org.sonar.server.duplication.ws.DuplicationsJsonWriter; import org.sonar.server.duplication.ws.DuplicationsParser; @@ -111,7 +136,22 @@ import org.sonar.server.duplication.ws.DuplicationsWs; import org.sonar.server.es.EsClient; import org.sonar.server.es.IndexCreator; import org.sonar.server.es.IndexRegistry; -import org.sonar.server.issue.*; +import org.sonar.server.issue.ActionService; +import org.sonar.server.issue.AddTagsAction; +import org.sonar.server.issue.AssignAction; +import org.sonar.server.issue.CommentAction; +import org.sonar.server.issue.InternalRubyIssueService; +import org.sonar.server.issue.IssueBulkChangeService; +import org.sonar.server.issue.IssueChangelogFormatter; +import org.sonar.server.issue.IssueChangelogService; +import org.sonar.server.issue.IssueCommentService; +import org.sonar.server.issue.IssueQueryService; +import org.sonar.server.issue.IssueService; +import org.sonar.server.issue.PlanAction; +import org.sonar.server.issue.RemoveTagsAction; +import org.sonar.server.issue.ServerIssueStorage; +import org.sonar.server.issue.SetSeverityAction; +import org.sonar.server.issue.TransitionAction; import org.sonar.server.issue.actionplan.ActionPlanService; import org.sonar.server.issue.actionplan.ActionPlanWs; import org.sonar.server.issue.db.IssueDao; @@ -122,8 +162,16 @@ import org.sonar.server.issue.index.IssueAuthorizationIndexer; import org.sonar.server.issue.index.IssueIndex; import org.sonar.server.issue.index.IssueIndexDefinition; import org.sonar.server.issue.index.IssueIndexer; -import org.sonar.server.issue.notification.*; -import org.sonar.server.issue.ws.*; +import org.sonar.server.issue.notification.ChangesOnMyIssueNotificationDispatcher; +import org.sonar.server.issue.notification.IssueChangesEmailTemplate; +import org.sonar.server.issue.notification.NewFalsePositiveNotificationDispatcher; +import org.sonar.server.issue.notification.NewIssuesEmailTemplate; +import org.sonar.server.issue.notification.NewIssuesNotificationDispatcher; +import org.sonar.server.issue.ws.ComponentTagsAction; +import org.sonar.server.issue.ws.IssueActionsWriter; +import org.sonar.server.issue.ws.IssueShowAction; +import org.sonar.server.issue.ws.IssuesWs; +import org.sonar.server.issue.ws.SetTagsAction; import org.sonar.server.language.ws.LanguageWs; import org.sonar.server.language.ws.ListAction; import org.sonar.server.measure.MeasureFilterEngine; @@ -140,44 +188,141 @@ import org.sonar.server.permission.InternalPermissionService; import org.sonar.server.permission.InternalPermissionTemplateService; import org.sonar.server.permission.PermissionFinder; import org.sonar.server.permission.ws.PermissionsWs; -import org.sonar.server.platform.monitoring.*; -import org.sonar.server.platform.ws.*; -import org.sonar.server.plugins.*; +import org.sonar.server.platform.monitoring.DatabaseMonitor; +import org.sonar.server.platform.monitoring.EsMonitor; +import org.sonar.server.platform.monitoring.JvmPropertiesMonitor; +import org.sonar.server.platform.monitoring.PluginsMonitor; +import org.sonar.server.platform.monitoring.SonarQubeMonitor; +import org.sonar.server.platform.monitoring.SystemMonitor; +import org.sonar.server.platform.ws.L10nWs; +import org.sonar.server.platform.ws.ServerWs; +import org.sonar.server.platform.ws.SystemInfoWsAction; +import org.sonar.server.platform.ws.SystemRestartWsAction; +import org.sonar.server.platform.ws.SystemWs; +import org.sonar.server.plugins.InstalledPluginReferentialFactory; +import org.sonar.server.plugins.PluginDownloader; +import org.sonar.server.plugins.ServerExtensionInstaller; +import org.sonar.server.plugins.ServerPluginJarInstaller; +import org.sonar.server.plugins.ServerPluginJarsInstaller; +import org.sonar.server.plugins.ServerPluginRepository; +import org.sonar.server.plugins.UpdateCenterClient; +import org.sonar.server.plugins.UpdateCenterMatrixFactory; import org.sonar.server.properties.ProjectSettingsFactory; import org.sonar.server.qualitygate.QgateProjectFinder; import org.sonar.server.qualitygate.QualityGates; import org.sonar.server.qualitygate.RegisterQualityGates; -import org.sonar.server.qualitygate.ws.*; -import org.sonar.server.qualityprofile.*; +import org.sonar.server.qualitygate.ws.QGatesAppAction; +import org.sonar.server.qualitygate.ws.QGatesCopyAction; +import org.sonar.server.qualitygate.ws.QGatesCreateAction; +import org.sonar.server.qualitygate.ws.QGatesCreateConditionAction; +import org.sonar.server.qualitygate.ws.QGatesDeleteConditionAction; +import org.sonar.server.qualitygate.ws.QGatesDeselectAction; +import org.sonar.server.qualitygate.ws.QGatesDestroyAction; +import org.sonar.server.qualitygate.ws.QGatesListAction; +import org.sonar.server.qualitygate.ws.QGatesRenameAction; +import org.sonar.server.qualitygate.ws.QGatesSearchAction; +import org.sonar.server.qualitygate.ws.QGatesSelectAction; +import org.sonar.server.qualitygate.ws.QGatesSetAsDefaultAction; +import org.sonar.server.qualitygate.ws.QGatesShowAction; +import org.sonar.server.qualitygate.ws.QGatesUnsetDefaultAction; +import org.sonar.server.qualitygate.ws.QGatesUpdateConditionAction; +import org.sonar.server.qualitygate.ws.QGatesWs; +import org.sonar.server.qualityprofile.BuiltInProfiles; +import org.sonar.server.qualityprofile.QProfileBackuper; +import org.sonar.server.qualityprofile.QProfileCopier; +import org.sonar.server.qualityprofile.QProfileExporters; +import org.sonar.server.qualityprofile.QProfileFactory; +import org.sonar.server.qualityprofile.QProfileLoader; +import org.sonar.server.qualityprofile.QProfileLookup; +import org.sonar.server.qualityprofile.QProfileProjectLookup; +import org.sonar.server.qualityprofile.QProfileProjectOperations; +import org.sonar.server.qualityprofile.QProfileReset; +import org.sonar.server.qualityprofile.QProfileService; +import org.sonar.server.qualityprofile.QProfiles; +import org.sonar.server.qualityprofile.RegisterQualityProfiles; +import org.sonar.server.qualityprofile.RuleActivator; +import org.sonar.server.qualityprofile.RuleActivatorContextFactory; import org.sonar.server.qualityprofile.db.ActiveRuleDao; import org.sonar.server.qualityprofile.index.ActiveRuleIndex; import org.sonar.server.qualityprofile.index.ActiveRuleNormalizer; -import org.sonar.server.qualityprofile.ws.*; -import org.sonar.server.rule.*; +import org.sonar.server.qualityprofile.ws.BulkRuleActivationActions; +import org.sonar.server.qualityprofile.ws.ProfilesWs; +import org.sonar.server.qualityprofile.ws.QProfileRestoreBuiltInAction; +import org.sonar.server.qualityprofile.ws.QProfilesWs; +import org.sonar.server.qualityprofile.ws.RuleActivationActions; +import org.sonar.server.rule.DefaultRuleFinder; +import org.sonar.server.rule.DeprecatedRulesDefinitionLoader; +import org.sonar.server.rule.RegisterRules; +import org.sonar.server.rule.RubyRuleService; +import org.sonar.server.rule.RuleCreator; +import org.sonar.server.rule.RuleDefinitionsLoader; +import org.sonar.server.rule.RuleDeleter; +import org.sonar.server.rule.RuleOperations; +import org.sonar.server.rule.RuleRepositories; +import org.sonar.server.rule.RuleService; +import org.sonar.server.rule.RuleUpdater; import org.sonar.server.rule.db.RuleDao; import org.sonar.server.rule.index.RuleIndex; import org.sonar.server.rule.index.RuleNormalizer; -import org.sonar.server.rule.ws.*; +import org.sonar.server.rule.ws.ActiveRuleCompleter; +import org.sonar.server.rule.ws.AppAction; +import org.sonar.server.rule.ws.DeleteAction; +import org.sonar.server.rule.ws.RepositoriesAction; +import org.sonar.server.rule.ws.RuleMapping; +import org.sonar.server.rule.ws.RulesWebService; import org.sonar.server.rule.ws.SearchAction; import org.sonar.server.rule.ws.TagsAction; -import org.sonar.server.search.*; +import org.sonar.server.rule.ws.UpdateAction; +import org.sonar.server.search.IndexClient; +import org.sonar.server.search.IndexQueue; +import org.sonar.server.search.IndexSynchronizer; +import org.sonar.server.search.SearchClient; import org.sonar.server.source.HtmlSourceDecorator; import org.sonar.server.source.SourceService; import org.sonar.server.source.index.SourceLineIndex; import org.sonar.server.source.index.SourceLineIndexDefinition; import org.sonar.server.source.index.SourceLineIndexer; -import org.sonar.server.source.ws.*; +import org.sonar.server.source.ws.HashAction; +import org.sonar.server.source.ws.IndexAction; +import org.sonar.server.source.ws.LinesAction; +import org.sonar.server.source.ws.RawAction; +import org.sonar.server.source.ws.ScmAction; +import org.sonar.server.source.ws.ScmWriter; import org.sonar.server.source.ws.ShowAction; -import org.sonar.server.startup.*; +import org.sonar.server.source.ws.SourcesWs; +import org.sonar.server.startup.CopyRequirementsFromCharacteristicsToRules; +import org.sonar.server.startup.GeneratePluginIndex; +import org.sonar.server.startup.JdbcDriverDeployer; +import org.sonar.server.startup.LogServerId; +import org.sonar.server.startup.RegisterDashboards; +import org.sonar.server.startup.RegisterDebtModel; +import org.sonar.server.startup.RegisterMetrics; +import org.sonar.server.startup.RegisterNewMeasureFilters; +import org.sonar.server.startup.RegisterPermissionTemplates; +import org.sonar.server.startup.RegisterServletFilters; +import org.sonar.server.startup.RenameDeprecatedPropertyKeys; +import org.sonar.server.startup.ServerMetadataPersister; import org.sonar.server.test.CoverageService; -import org.sonar.server.test.ws.*; +import org.sonar.server.test.ws.CoverageShowAction; +import org.sonar.server.test.ws.CoverageWs; +import org.sonar.server.test.ws.TestsCoveredFilesAction; +import org.sonar.server.test.ws.TestsShowAction; +import org.sonar.server.test.ws.TestsTestCasesAction; +import org.sonar.server.test.ws.TestsWs; import org.sonar.server.text.MacroInterpreter; import org.sonar.server.text.RubyTextService; import org.sonar.server.ui.JRubyI18n; import org.sonar.server.ui.PageDecorations; import org.sonar.server.ui.Views; import org.sonar.server.updatecenter.ws.UpdateCenterWs; -import org.sonar.server.user.*; +import org.sonar.server.user.DefaultUserService; +import org.sonar.server.user.DoPrivileged; +import org.sonar.server.user.GroupMembershipFinder; +import org.sonar.server.user.GroupMembershipService; +import org.sonar.server.user.NewUserNotifier; +import org.sonar.server.user.SecurityRealmFactory; +import org.sonar.server.user.UserService; +import org.sonar.server.user.UserUpdater; import org.sonar.server.user.db.GroupDao; import org.sonar.server.user.db.UserDao; import org.sonar.server.user.db.UserGroupDao; @@ -187,7 +332,13 @@ import org.sonar.server.user.index.UserIndexer; import org.sonar.server.user.ws.FavoritesWs; import org.sonar.server.user.ws.UserPropertiesWs; import org.sonar.server.user.ws.UsersWs; -import org.sonar.server.util.*; +import org.sonar.server.util.BooleanTypeValidation; +import org.sonar.server.util.FloatTypeValidation; +import org.sonar.server.util.IntegerTypeValidation; +import org.sonar.server.util.StringListTypeValidation; +import org.sonar.server.util.StringTypeValidation; +import org.sonar.server.util.TextTypeValidation; +import org.sonar.server.util.TypeValidations; import org.sonar.server.view.index.ViewIndex; import org.sonar.server.view.index.ViewIndexDefinition; import org.sonar.server.view.index.ViewIndexer; @@ -642,10 +793,10 @@ class ServerComponents { PluginsMonitor.class, JvmPropertiesMonitor.class, DatabaseMonitor.class - )); + )); // Compute engine - pico.addSingleton(AnalysisReportQueue.class); + pico.addSingleton(ReportQueue.class); pico.addSingleton(ComputationThreadLauncher.class); pico.addSingleton(ComputationWebService.class); pico.addSingleton(IsQueueEmptyWebService.class); @@ -688,7 +839,7 @@ class ServerComponents { startupContainer.addSingleton(LogServerId.class); startupContainer.addSingleton(RegisterServletFilters.class); startupContainer.addSingleton(CopyRequirementsFromCharacteristicsToRules.class); - startupContainer.addSingleton(AnalysisReportQueueCleaner.class); + startupContainer.addSingleton(ReportQueueCleaner.class); DoPrivileged.execute(new DoPrivileged.Task() { @Override diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/AnalysisReportQueueMediumTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/AnalysisReportQueueMediumTest.java deleted file mode 100644 index 2b76903a7ca..00000000000 --- a/server/sonar-server/src/test/java/org/sonar/server/computation/AnalysisReportQueueMediumTest.java +++ /dev/null @@ -1,179 +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.server.computation; - -import org.apache.commons.io.IOUtils; -import org.junit.After; -import org.junit.Before; -import org.junit.ClassRule; -import org.junit.Test; -import org.sonar.api.security.DefaultGroups; -import org.sonar.api.web.UserRole; -import org.sonar.core.component.ComponentDto; -import org.sonar.core.computation.db.AnalysisReportDto; -import org.sonar.core.permission.GlobalPermissions; -import org.sonar.core.permission.PermissionFacade; -import org.sonar.core.persistence.DbSession; -import org.sonar.core.persistence.MyBatis; -import org.sonar.core.user.UserDto; -import org.sonar.server.db.DbClient; -import org.sonar.server.exceptions.ForbiddenException; -import org.sonar.server.tester.ServerTester; -import org.sonar.server.user.MockUserSession; - -import java.io.InputStream; -import java.util.List; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.sonar.core.computation.db.AnalysisReportDto.Status.SUCCESS; -import static org.sonar.core.computation.db.AnalysisReportDto.Status.WORKING; - -public class AnalysisReportQueueMediumTest { - private static final String DEFAULT_PROJECT_KEY = "123456789-987654321"; - - @ClassRule - public static ServerTester tester = new ServerTester(); - - private AnalysisReportQueue sut; - - private DbClient db; - private DbSession session; - private MockUserSession userSession; - - @Before - public void setUp() throws Exception { - tester.clearDbAndIndexes(); - db = tester.get(DbClient.class); - session = db.openSession(false); - - sut = tester.get(AnalysisReportQueue.class); - - UserDto connectedUser = new UserDto().setLogin("gandalf").setName("Gandalf"); - db.userDao().insert(session, connectedUser); - - userSession = MockUserSession.set() - .setLogin(connectedUser.getLogin()) - .setUserId(connectedUser.getId().intValue()) - .setGlobalPermissions(GlobalPermissions.SCAN_EXECUTION); - - session.commit(); - } - - @After - public void after() { - MyBatis.closeQuietly(session); - } - - @Test - public void create_analysis_report_and_retrieve_it() { - insertPermissionsForProject(DEFAULT_PROJECT_KEY); - sut.add(DEFAULT_PROJECT_KEY, 123L, defaultReportData()); - - List<AnalysisReportDto> reports = sut.findByProjectKey(DEFAULT_PROJECT_KEY); - AnalysisReportDto report = reports.get(0); - - assertThat(reports).hasSize(1); - assertThat(report.getProjectKey()).isEqualTo(DEFAULT_PROJECT_KEY); - assertThat(report.getSnapshotId()).isEqualTo(123L); - assertThat(report.getCreatedAt()).isNotNull(); - } - - private ComponentDto insertPermissionsForProject(String projectKey) { - ComponentDto project = new ComponentDto().setKey(projectKey); - db.componentDao().insert(session, project); - - tester.get(PermissionFacade.class).insertGroupPermission(project.getId(), DefaultGroups.ANYONE, UserRole.USER, session); - userSession.addProjectPermissions(UserRole.USER, project.key()); - - session.commit(); - - return project; - } - - @Test - public void create_and_book_oldest_available_analysis_report_thrice() { - insertPermissionsForProject(DEFAULT_PROJECT_KEY); - insertPermissionsForProject("2"); - insertPermissionsForProject("3"); - - sut.add(DEFAULT_PROJECT_KEY, 123L, defaultReportData()); - sut.add("2", 123L, defaultReportData()); - sut.add("3", 123L, defaultReportData()); - - AnalysisReportDto firstBookedReport = sut.pop(); - AnalysisReportDto secondBookedReport = sut.pop(); - AnalysisReportDto thirdBookedReport = sut.pop(); - - assertThat(firstBookedReport.getProjectKey()).isEqualTo(DEFAULT_PROJECT_KEY); - assertThat(firstBookedReport.getStatus()).isEqualTo(WORKING); - assertThat(firstBookedReport.getStartedAt()).isNotNull(); - assertThat(secondBookedReport.getProjectKey()).isEqualTo("2"); - assertThat(thirdBookedReport.getProjectKey()).isEqualTo("3"); - } - - @Test - public void search_for_available_report_when_no_report_available() { - AnalysisReportDto nullAnalysisReport = sut.pop(); - - assertThat(nullAnalysisReport).isNull(); - } - - @Test - public void all() { - insertPermissionsForProject(DEFAULT_PROJECT_KEY); - - sut.add(DEFAULT_PROJECT_KEY, 123L, defaultReportData()); - sut.add(DEFAULT_PROJECT_KEY, 123L, defaultReportData()); - sut.add(DEFAULT_PROJECT_KEY, 123L, defaultReportData()); - - List<AnalysisReportDto> reports = sut.all(); - - assertThat(reports).hasSize(3); - } - - @Test - public void remove_remove_from_queue() { - insertPermissionsForProject(DEFAULT_PROJECT_KEY); - sut.add(DEFAULT_PROJECT_KEY, 123L, defaultReportData()); - AnalysisReportDto report = sut.pop(); - report.setStatus(SUCCESS); - - sut.remove(report); - - assertThat(sut.all()).isEmpty(); - } - - @Test(expected = ForbiddenException.class) - public void cannot_add_report_when_not_the_right_rights() { - ComponentDto project = new ComponentDto() - .setKey("MyProject"); - db.componentDao().insert(session, project); - session.commit(); - - MockUserSession.set().setLogin("gandalf").addProjectPermissions(UserRole.USER, project.key()); - - sut.add(project.getKey(), 123L, defaultReportData()); - } - - private InputStream defaultReportData() { - return IOUtils.toInputStream("default-project"); - } -} diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/ComputationComponentsTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/ComputationContainerTest.java index ae7590ce6fe..bd391ffbed2 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/computation/ComputationComponentsTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/computation/ComputationContainerTest.java @@ -20,19 +20,13 @@ package org.sonar.server.computation; import org.junit.Test; -import org.sonar.test.TestUtils; import static org.assertj.core.api.Assertions.assertThat; -public class ComputationComponentsTest { +public class ComputationContainerTest { @Test - public void nonStepComponents() throws Exception { - assertThat(ComputationComponents.nonStepComponents()).isNotEmpty(); - } - - @Test - public void util_class() throws Exception { - assertThat(TestUtils.hasOnlyPrivateConstructors(ComputationComponents.class)).isTrue(); + public void componentClasses() throws Exception { + assertThat(ComputationContainer.componentClasses()).isNotEmpty(); } } diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/ComputationServiceTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/ComputationServiceTest.java index e983b901cef..61d9cc7ab88 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/computation/ComputationServiceTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/computation/ComputationServiceTest.java @@ -17,13 +17,41 @@ * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ +/* + * 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.server.computation; +import org.apache.commons.io.FileUtils; import org.apache.commons.lang.RandomStringUtils; import org.junit.Before; import org.junit.ClassRule; +import org.junit.Rule; import org.junit.Test; import org.sonar.api.resources.Qualifiers; +import org.sonar.api.utils.System2; +import org.sonar.api.utils.ZipUtils; +import org.sonar.api.utils.internal.JUnitTempFolder; +import org.sonar.api.utils.log.LogTester; +import org.sonar.api.utils.log.LoggerLevel; +import org.sonar.batch.protocol.output.BatchOutputWriter; +import org.sonar.batch.protocol.output.BatchReport; import org.sonar.core.activity.Activity; import org.sonar.core.computation.db.AnalysisReportDto; import org.sonar.core.persistence.DbSession; @@ -34,6 +62,8 @@ import org.sonar.server.computation.step.ComputationStep; import org.sonar.server.computation.step.ComputationSteps; import org.sonar.server.db.DbClient; +import java.io.File; +import java.io.IOException; import java.util.Arrays; import static org.assertj.core.api.Assertions.assertThat; @@ -46,62 +76,97 @@ public class ComputationServiceTest { @ClassRule public static DbTester dbTester = new DbTester(); + @Rule + public JUnitTempFolder tempFolder = new JUnitTempFolder(); + + @Rule + public LogTester logTester = new LogTester(); + ComputationStep projectStep1 = mockStep(Qualifiers.PROJECT); ComputationStep projectStep2 = mockStep(Qualifiers.PROJECT); ComputationStep viewStep = mockStep(Qualifiers.VIEW); ComputationSteps steps = mock(ComputationSteps.class); ActivityService activityService = mock(ActivityService.class); + System2 system = mock(System2.class); + ComputationService sut; @Before public void setUp() throws Exception { - dbTester.truncateTables(); + DbClient dbClient = new DbClient(dbTester.database(), dbTester.myBatis(), new ComponentDao()); + sut = new ComputationService(dbClient, steps, activityService, tempFolder, system); + + // db contains project with key "P1" + dbTester.prepareDbUnit(getClass(), "shared.xml"); } @Test public void process_project() throws Exception { - // db contains project with key "PROJECT_KEY" - dbTester.prepareDbUnit(getClass(), "shared.xml"); - DbClient dbClient = new DbClient(dbTester.database(), dbTester.myBatis(), new ComponentDao()); + logTester.setLevel(LoggerLevel.INFO); + // view step is not supposed to be executed when(steps.orderedSteps()).thenReturn(Arrays.asList(projectStep1, projectStep2, viewStep)); + AnalysisReportDto dto = AnalysisReportDto.newForTests(1L).setProjectKey("P1").setUuid("U1"); + File zip = generateZip(); + + sut.process(new ReportQueue.Item(dto, zip)); - // load report from db and parse it - ComputationService sut = new ComputationService(dbClient, steps, activityService); - AnalysisReportDto report = AnalysisReportDto.newForTests(1L); - report.setProjectKey("PROJECT_KEY"); - assertThat(report.getStatus()).isNull(); - sut.process(report); + // report is integrated -> status is set to SUCCESS + assertThat(dto.getStatus()).isEqualTo(AnalysisReportDto.Status.SUCCESS); + assertThat(dto.getFinishedAt()).isNotNull(); - // status of report is set - assertThat(report.getStatus()).isEqualTo(AnalysisReportDto.Status.SUCCESS); + // one info log at the end + assertThat(logTester.logs(LoggerLevel.INFO)).hasSize(1); + assertThat(logTester.logs(LoggerLevel.INFO).get(0)).startsWith("Analysis of project P1 (report 1) (done) | time="); // execute only the steps supporting the project qualifier verify(projectStep1).execute(any(ComputationContext.class)); verify(projectStep2).execute(any(ComputationContext.class)); verify(viewStep, never()).execute(any(ComputationContext.class)); - verify(activityService).write(any(DbSession.class), eq(Activity.Type.ANALYSIS_REPORT), any(AnalysisReportLog.class)); + verify(activityService).write(any(DbSession.class), eq(Activity.Type.ANALYSIS_REPORT), any(ReportActivity.class)); } @Test - public void fail_to_parse_report() throws Exception { - // db contains project with key "PROJECT_KEY" - dbTester.prepareDbUnit(getClass(), "shared.xml"); - DbClient dbClient = new DbClient(dbTester.database(), dbTester.myBatis(), new ComponentDao()); + public void debug_logs() throws Exception { + logTester.setLevel(LoggerLevel.DEBUG); + + AnalysisReportDto dto = AnalysisReportDto.newForTests(1L).setProjectKey("P1").setUuid("U1"); + File zip = generateZip(); + sut.process(new ReportQueue.Item(dto, zip)); + assertThat(logTester.logs(LoggerLevel.DEBUG)).isNotEmpty(); + } + + @Test + public void fail_if_corrupted_zip() throws Exception { + AnalysisReportDto dto = AnalysisReportDto.newForTests(1L).setProjectKey("P1").setUuid("U1"); + File zip = tempFolder.newFile(); + FileUtils.write(zip, "not a file"); + + try { + sut.process(new ReportQueue.Item(dto, zip)); + fail(); + } catch (IllegalStateException e) { + assertThat(e.getMessage()).startsWith("Fail to unzip " + zip.getAbsolutePath() + " into "); + assertThat(dto.getStatus()).isEqualTo(AnalysisReportDto.Status.FAILED); + assertThat(dto.getFinishedAt()).isNotNull(); + } + } + + @Test + public void step_error() throws Exception { when(steps.orderedSteps()).thenReturn(Arrays.asList(projectStep1)); - doThrow(new UnsupportedOperationException()).when(projectStep1).execute(any(ComputationContext.class)); + doThrow(new IllegalStateException("pb")).when(projectStep1).execute(any(ComputationContext.class)); + + AnalysisReportDto dto = AnalysisReportDto.newForTests(1L).setProjectKey("P1").setUuid("U1"); + File zip = generateZip(); - // load report from db and parse it - ComputationService sut = new ComputationService(dbClient, steps, activityService); - AnalysisReportDto report = AnalysisReportDto.newForTests(1L); - report.setProjectKey("PROJECT_KEY"); try { - sut.process(report); + sut.process(new ReportQueue.Item(dto, zip)); fail(); - } catch (UnsupportedOperationException e) { - // status of report is set - assertThat(report.getStatus()).isEqualTo(AnalysisReportDto.Status.FAILED); - verify(activityService).write(any(DbSession.class), eq(Activity.Type.ANALYSIS_REPORT), any(AnalysisReportLog.class)); + } catch (IllegalStateException e) { + assertThat(e.getMessage()).isEqualTo("pb"); + assertThat(dto.getStatus()).isEqualTo(AnalysisReportDto.Status.FAILED); + assertThat(dto.getFinishedAt()).isNotNull(); } } @@ -111,4 +176,17 @@ public class ComputationServiceTest { when(step.getDescription()).thenReturn(RandomStringUtils.randomAscii(5)); return step; } + + private File generateZip() throws IOException { + File dir = tempFolder.newDir(); + BatchOutputWriter writer = new BatchOutputWriter(dir); + writer.writeMetadata(BatchReport.Metadata.newBuilder() + .setRootComponentRef(1) + .setProjectKey("PROJECT_KEY") + .setAnalysisDate(150000000L) + .build()); + File zip = tempFolder.newFile(); + ZipUtils.zipDir(dir, zip); + return zip; + } } diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/ComputationThreadLauncherTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/ComputationThreadLauncherTest.java index 61379a03b03..09f80a61872 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/computation/ComputationThreadLauncherTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/computation/ComputationThreadLauncherTest.java @@ -39,11 +39,11 @@ public class ComputationThreadLauncherTest { public TestRule timeout = new DisableOnDebug(Timeout.seconds(5)); ComputationThreadLauncher sut; - AnalysisReportQueue queue; + ReportQueue queue; @Before public void before() { - this.queue = mock(AnalysisReportQueue.class); + this.queue = mock(ReportQueue.class); } @After @@ -74,6 +74,12 @@ public class ComputationThreadLauncherTest { verify(queue, atLeastOnce()).pop(); } + @Test + public void test_real_constructor() throws Exception { + sut = new ComputationThreadLauncher(queue); + sut.start(); + } + private void sleep() throws InterruptedException { TimeUnit.MILLISECONDS.sleep(500L); } diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/ComputationThreadTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/ComputationThreadTest.java index d3ecf46306e..43cac0b1700 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/computation/ComputationThreadTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/computation/ComputationThreadTest.java @@ -20,44 +20,81 @@ package org.sonar.server.computation; -import org.junit.Before; +import org.junit.Rule; import org.junit.Test; +import org.junit.rules.TemporaryFolder; +import org.sonar.api.utils.log.LogTester; import org.sonar.core.computation.db.AnalysisReportDto; +import java.io.IOException; + +import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.Mockito.*; public class ComputationThreadTest { - private ComputationThread sut; - private AnalysisReportQueue queue; + @Rule + public TemporaryFolder temp = new TemporaryFolder(); - @Before - public void before() { - this.queue = mock(AnalysisReportQueue.class); - this.sut = new ComputationThread(queue); - } + @Rule + public LogTester logTester = new LogTester(); + + ComputationContainer container = mock(ComputationContainer.class); + ReportQueue queue = mock(ReportQueue.class); + ComputationThread sut = new ComputationThread(queue, container); @Test - public void call_findAndBook_and_no_call_to_analyze_if_no_report_found() { + public void do_nothing_if_queue_empty() { + when(queue.pop()).thenReturn(null); + sut.run(); verify(queue).pop(); + verifyZeroInteractions(container); } @Test - public void call_findAndBook_and_then_analyze_if_there_is_a_report() { + public void pop_queue_and_integrate_report() throws IOException { AnalysisReportDto report = AnalysisReportDto.newForTests(1L); - when(queue.pop()).thenReturn(report); + ReportQueue.Item item = new ReportQueue.Item(report, temp.newFile()); + when(queue.pop()).thenReturn(item); sut.run(); verify(queue).pop(); + verify(container).execute(item); } @Test - public void when_the_analysis_throws_an_exception_it_does_not_break_the_task() throws Exception { + public void handle_error_during_queue_pop() throws Exception { when(queue.pop()).thenThrow(new IllegalStateException()); sut.run(); + + assertThat(logTester.logs()).contains("Failed to pop the queue of analysis reports"); + } + + @Test + public void handle_error_during_integration() throws Exception { + AnalysisReportDto report = AnalysisReportDto.newForTests(1L).setProjectKey("P1"); + ReportQueue.Item item = new ReportQueue.Item(report, temp.newFile()); + when(queue.pop()).thenReturn(item); + doThrow(new IllegalStateException("pb")).when(container).execute(item); + + sut.run(); + + assertThat(logTester.logs()).contains("Failed to process analysis report 1 of project P1"); + } + + @Test + public void handle_error_during_removal_from_queue() throws Exception { + AnalysisReportDto report = AnalysisReportDto.newForTests(1L).setProjectKey("P1"); + ReportQueue.Item item = new ReportQueue.Item(report, temp.newFile()); + when(queue.pop()).thenReturn(item); + doThrow(new IllegalStateException("pb")).when(queue).remove(item); + + sut.run(); + + assertThat(logTester.logs()).contains("Failed to remove analysis report 1 from queue"); } } diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/AnalysisReportLogMediumTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/ReportActivityTest.java index 986a364c59c..82ca71f828a 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/computation/AnalysisReportLogMediumTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/computation/ReportActivityTest.java @@ -20,48 +20,18 @@ package org.sonar.server.computation; -import com.google.common.collect.Iterables; -import org.junit.After; -import org.junit.Before; -import org.junit.ClassRule; import org.junit.Test; import org.sonar.api.utils.DateUtils; -import org.sonar.core.activity.Activity; import org.sonar.core.component.ComponentDto; import org.sonar.core.computation.db.AnalysisReportDto; -import org.sonar.core.persistence.DbSession; -import org.sonar.server.activity.ActivityService; -import org.sonar.server.activity.index.ActivityIndex; import org.sonar.server.component.ComponentTesting; -import org.sonar.server.db.DbClient; -import org.sonar.server.tester.ServerTester; import java.util.Map; import static org.assertj.core.api.Assertions.assertThat; -import static org.sonar.core.activity.Activity.Type.ANALYSIS_REPORT; import static org.sonar.core.computation.db.AnalysisReportDto.Status.FAILED; -public class AnalysisReportLogMediumTest { - @ClassRule - public static ServerTester tester = new ServerTester(); - - private ActivityService service = tester.get(ActivityService.class); - private ActivityIndex index = tester.get(ActivityIndex.class); - private DbSession dbSession; - - private AnalysisReportLog sut; - - @Before - public void before() { - tester.clearDbAndIndexes(); - dbSession = tester.get(DbClient.class).openSession(false); - } - - @After - public void after() { - dbSession.close(); - } +public class ReportActivityTest { @Test public void insert_find_analysis_report_log() { @@ -74,15 +44,9 @@ public class AnalysisReportLogMediumTest { .setFinishedAt(DateUtils.parseDate("2014-10-18").getTime()); ComponentDto project = ComponentTesting.newProjectDto(); - service.write(dbSession, ANALYSIS_REPORT, new AnalysisReportLog(report, project)); - dbSession.commit(); - - // 0. AssertBase case - assertThat(index.findAll().getHits()).hasSize(1); + ReportActivity activity = new ReportActivity(report, project); - Activity activity = Iterables.getFirst(index.findAll().getHits(), null); - assertThat(activity).isNotNull(); - Map<String, String> details = activity.details(); + Map<String, String> details = activity.getDetails(); assertThat(details.get("key")).isEqualTo(String.valueOf(report.getId())); assertThat(details.get("projectKey")).isEqualTo(project.key()); assertThat(details.get("projectName")).isEqualTo(project.name()); diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/AnalysisReportQueueCleanerTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/ReportQueueCleanerTest.java index 1a8f5aa55ad..dde45514bd4 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/computation/AnalysisReportQueueCleanerTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/computation/ReportQueueCleanerTest.java @@ -20,48 +20,29 @@ package org.sonar.server.computation; -import org.junit.Before; import org.junit.Test; import org.sonar.api.platform.ServerUpgradeStatus; -import org.sonar.core.persistence.DbSession; -import org.sonar.server.computation.db.AnalysisReportDao; -import org.sonar.server.db.DbClient; import static org.mockito.Mockito.*; -public class AnalysisReportQueueCleanerTest { +public class ReportQueueCleanerTest { - AnalysisReportQueueCleaner sut; - ServerUpgradeStatus serverUpgradeStatus; - DbClient dbClient; - AnalysisReportDao analysisReportDao; - DbSession session; - - @Before - public void before() { - analysisReportDao = mock(AnalysisReportDao.class); - serverUpgradeStatus = mock(ServerUpgradeStatus.class); - dbClient = mock(DbClient.class); - session = mock(DbSession.class); - - when(dbClient.analysisReportDao()).thenReturn(analysisReportDao); - when(dbClient.openSession(false)).thenReturn(session); - - sut = new AnalysisReportQueueCleaner(serverUpgradeStatus, dbClient); - } + ServerUpgradeStatus serverUpgradeStatus = mock(ServerUpgradeStatus.class); + ReportQueue queue = mock(ReportQueue.class); + ReportQueueCleaner sut = new ReportQueueCleaner(serverUpgradeStatus, queue); @Test - public void start_must_call_dao_clean_update_to_pending_by_default() { + public void reset_reports_on_restart() { sut.start(); - verify(analysisReportDao).resetAllToPendingStatus(any(DbSession.class)); + verify(queue).resetToPendingStatus(); sut.stop(); } @Test - public void start_must_call_dao_truncate_when_upgrading() { + public void delete_all_reports_on_upgrade() { when(serverUpgradeStatus.isUpgraded()).thenReturn(Boolean.TRUE); sut.start(); - verify(analysisReportDao).truncate(any(DbSession.class)); + verify(queue).clear(); sut.stop(); } } diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/ReportQueueTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/ReportQueueTest.java new file mode 100644 index 00000000000..6db7d0c9eb8 --- /dev/null +++ b/server/sonar-server/src/test/java/org/sonar/server/computation/ReportQueueTest.java @@ -0,0 +1,205 @@ +/* + * 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.server.computation; + +import org.apache.commons.io.FileUtils; +import org.apache.commons.io.IOUtils; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.experimental.categories.Category; +import org.junit.rules.TemporaryFolder; +import org.sonar.api.config.Settings; +import org.sonar.api.utils.System2; +import org.sonar.core.computation.db.AnalysisReportDto; +import org.sonar.core.persistence.DbSession; +import org.sonar.core.persistence.DbTester; +import org.sonar.process.ProcessConstants; +import org.sonar.server.component.ComponentTesting; +import org.sonar.server.component.db.ComponentDao; +import org.sonar.server.computation.db.AnalysisReportDao; +import org.sonar.server.db.DbClient; +import org.sonar.test.DbTests; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; +import static org.sonar.core.computation.db.AnalysisReportDto.Status.PENDING; +import static org.sonar.core.computation.db.AnalysisReportDto.Status.WORKING; + +@Category(DbTests.class) +public class ReportQueueTest { + + static final long NOW = 1_500_000_000_000L; + + @Rule + public DbTester dbTester = new DbTester(); + + @Rule + public TemporaryFolder temp = new TemporaryFolder(); + + Settings settings = new Settings(); + File dataDir; + System2 system = mock(System2.class); + ReportQueue sut; + + @Before + public void setUp() throws Exception { + dataDir = temp.newFolder(); + settings.setProperty(ProcessConstants.PATH_DATA, dataDir.getAbsolutePath()); + when(system.now()).thenReturn(NOW); + + DbClient dbClient = new DbClient(dbTester.database(), dbTester.myBatis(), new ComponentDao(), new AnalysisReportDao(system)); + sut = new ReportQueue(dbClient, settings); + + try (DbSession session = dbClient.openSession(false)) { + dbClient.componentDao().insert(session, ComponentTesting.newProjectDto().setKey("P1")); + dbClient.componentDao().insert(session, ComponentTesting.newProjectDto().setKey("P2")); + dbClient.componentDao().insert(session, ComponentTesting.newProjectDto().setKey("P3")); + session.commit(); + } + } + + @Test + public void add_report_to_queue() throws IOException { + // must: + // 1. insert metadata in db + // 2. copy report content to directory /data/analysis + ReportQueue.Item item = sut.add("P1", generateData()); + + assertThat(item).isNotNull(); + assertThat(item.zipFile).isFile().exists().hasContent("some data").hasParent(new File(dataDir, "analysis")); + assertThat(item.dto.getUuid()).isNotEmpty(); + assertThat(item.dto.getId()).isGreaterThan(0L); + + List<AnalysisReportDto> reports = sut.findByProjectKey("P1"); + assertThat(reports).hasSize(1); + AnalysisReportDto report = reports.get(0); + + assertThat(reports).hasSize(1); + assertThat(report.getStatus()).isEqualTo(PENDING); + assertThat(report.getProjectKey()).isEqualTo("P1"); + assertThat(report.getUuid()).isNotEmpty(); + assertThat(report.getId()).isGreaterThan(0L); + assertThat(report.getCreatedAt()).isEqualTo(NOW); + assertThat(report.getUpdatedAt()).isEqualTo(NOW); + assertThat(report.getStartedAt()).isNull(); + assertThat(report.getFinishedAt()).isNull(); + + assertThat(FileUtils.listFiles(analysisDir(), new String[] {"zip"}, false)).hasSize(1); + } + + @Test + public void find_by_project_key() throws Exception { + sut.add("P1", generateData()); + assertThat(sut.findByProjectKey("P1")).hasSize(1).extracting("projectKey").containsExactly("P1"); + assertThat(sut.findByProjectKey("P2")).isEmpty(); + } + + @Test + public void pop_pending_items_in_fifo_order() { + sut.add("P1", generateData()); + sut.add("P2", generateData()); + sut.add("P3", generateData()); + + ReportQueue.Item item = sut.pop(); + assertThat(item.dto.getProjectKey()).isEqualTo("P1"); + assertThat(item.zipFile).exists().isFile().hasExtension("zip"); + + // status changed from PENDING to WORKING + assertThat(item.dto.getStatus()).isEqualTo(WORKING); + + assertThat(sut.pop().dto.getProjectKey()).isEqualTo("P2"); + assertThat(sut.pop().dto.getProjectKey()).isEqualTo("P3"); + + // queue is empty + assertThat(sut.pop()).isNull(); + + // items are still in db, but in WORKING status + List<AnalysisReportDto> reports = sut.all(); + assertThat(reports).hasSize(3); + assertThat(reports).extracting("status").containsOnly(WORKING); + } + + @Test + public void remove() { + ReportQueue.Item item = sut.add("P1", generateData()); + assertThat(dbTester.countRowsOfTable("analysis_reports")).isEqualTo(1); + + sut.remove(item); + assertThat(dbTester.countRowsOfTable("analysis_reports")).isEqualTo(0); + assertThat(item.zipFile).doesNotExist(); + } + + @Test + public void do_not_pop_corrupted_item() throws Exception { + ReportQueue.Item item = sut.add("P1", generateData()); + + // emulate corruption: file is missing on FS + FileUtils.deleteQuietly(item.zipFile); + + assertThat(sut.pop()).isNull(); + + // table sanitized + assertThat(dbTester.countRowsOfTable("analysis_reports")).isEqualTo(0); + } + + @Test + public void clear() throws Exception { + sut.add("P1", generateData()); + sut.add("P2", generateData()); + assertThat(analysisDir()).exists().isDirectory(); + + sut.clear(); + + assertThat(dbTester.countRowsOfTable("analysis_reports")).isEqualTo(0); + assertThat(analysisDir()).doesNotExist(); + } + + @Test + public void reset_to_pending_status() throws Exception { + // 2 pending + sut.add("P1", generateData()); + sut.add("P2", generateData()); + + // pop 1 -> 1 pending and 1 working + ReportQueue.Item workingItem = sut.pop(); + assertThat(workingItem.dto.getStatus()).isEqualTo(WORKING); + assertThat(sut.all()).extracting("status").contains(PENDING, WORKING); + + sut.resetToPendingStatus(); + assertThat(sut.all()).extracting("status").containsOnly(PENDING).hasSize(2); + + } + + private InputStream generateData() { + return IOUtils.toInputStream("some data"); + } + + private File analysisDir() { + return new File(dataDir, "analysis"); + } +} diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/db/AnalysisReportDaoTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/db/AnalysisReportDaoTest.java index eddb4326798..bf4456f66ab 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/computation/db/AnalysisReportDaoTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/computation/db/AnalysisReportDaoTest.java @@ -20,8 +20,11 @@ package org.sonar.server.computation.db; -import org.apache.commons.io.IOUtils; -import org.junit.*; +import org.junit.After; +import org.junit.Before; +import org.junit.ClassRule; +import org.junit.Rule; +import org.junit.Test; import org.junit.experimental.categories.Category; import org.junit.rules.TemporaryFolder; import org.sonar.api.utils.System2; @@ -31,8 +34,6 @@ import org.sonar.core.persistence.DbTester; import org.sonar.core.persistence.MyBatis; import org.sonar.test.DbTests; -import java.io.File; -import java.io.InputStream; import java.util.List; import static org.assertj.core.api.Assertions.assertThat; @@ -46,7 +47,6 @@ import static org.sonar.core.computation.db.AnalysisReportDto.Status.WORKING; public class AnalysisReportDaoTest { private static final String DEFAULT_PROJECT_KEY = "123456789-987654321"; - private static final long DEFAULT_SNAPSHOT_ID = 123L; @ClassRule public static DbTester db = new DbTester(); @@ -54,13 +54,12 @@ public class AnalysisReportDaoTest { @Rule public TemporaryFolder temp = new TemporaryFolder(); - private AnalysisReportDao sut; - private DbSession session; - private System2 system2; + AnalysisReportDao sut; + DbSession session; + System2 system2; @Before public void before() { - db.truncateTables(); this.session = db.myBatis().openSession(false); this.system2 = mock(System2.class); this.sut = new AnalysisReportDao(system2); @@ -78,8 +77,8 @@ public class AnalysisReportDaoTest { public void insert_multiple_reports() throws Exception { db.prepareDbUnit(getClass(), "empty.xml"); - AnalysisReportDto report1 = newDefaultAnalysisReport(); - AnalysisReportDto report2 = newDefaultAnalysisReport(); + AnalysisReportDto report1 = newDefaultAnalysisReport().setUuid("UUID_1"); + AnalysisReportDto report2 = newDefaultAnalysisReport().setUuid("UUID_2"); sut.insert(session, report1); sut.insert(session, report2); @@ -89,15 +88,6 @@ public class AnalysisReportDaoTest { } @Test - public void insert_report_data_do_not_throw_exception() throws Exception { - db.prepareDbUnit(getClass(), "empty.xml"); - AnalysisReportDto report = newDefaultAnalysisReport() - .setData(getClass().getResource("/org/sonar/server/computation/db/AnalysisReportDaoTest/zip.zip").openStream()); - - sut.insert(session, report); - } - - @Test public void resetAllToPendingStatus() { db.prepareDbUnit(getClass(), "update-all-to-status-pending.xml"); @@ -171,8 +161,6 @@ public class AnalysisReportDaoTest { assertThat(report.getStartedAt()).isEqualTo(parseDate("2014-09-26").getTime()); assertThat(report.getFinishedAt()).isEqualTo(parseDate("2014-09-27").getTime()); assertThat(report.getStatus()).isEqualTo(WORKING); - assertThat(report.getData()).isNull(); - assertThat(report.getKey()).isEqualTo("1"); } @Test @@ -221,31 +209,10 @@ public class AnalysisReportDaoTest { assertThat(reports).hasSize(3); } - @Test - public void insert_and_then_retrieve_report_data_with_decompressed_files_medium_test() throws Exception { - // ARRANGE - db.prepareDbUnit(getClass(), "empty.xml"); - AnalysisReportDto report = newDefaultAnalysisReport(); - InputStream zip = getClass().getResource("/org/sonar/server/computation/db/AnalysisReportDaoTest/zip.zip").openStream(); - report.setData(zip); - - File toDir = temp.newFolder(); - sut.insert(session, report); - session.commit(); - IOUtils.closeQuietly(zip); - - // ACT - sut.selectAndDecompressToDir(session, 1L, toDir); - - // ASSERT - assertThat(toDir.list()).hasSize(3); - } - private AnalysisReportDto newDefaultAnalysisReport() { return AnalysisReportDto.newForTests(1L) .setProjectKey(DEFAULT_PROJECT_KEY) - .setSnapshotId(DEFAULT_SNAPSHOT_ID) - .setData(null) + .setUuid("REPORT_UUID") .setStatus(PENDING); } } diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/step/ApplyPermissionsStepTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/step/ApplyPermissionsStepTest.java index a7554148090..938a2d49d48 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/computation/step/ApplyPermissionsStepTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/computation/step/ApplyPermissionsStepTest.java @@ -20,17 +20,25 @@ package org.sonar.server.computation.step; import org.junit.Test; +import org.sonar.server.computation.ComputationContext; import org.sonar.server.issue.index.IssueAuthorizationIndexer; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; -public class ApplyPermissionsStepTest { +public class ApplyPermissionsStepTest extends BaseStepTest { + + IssueAuthorizationIndexer indexer = mock(IssueAuthorizationIndexer.class); + ApplyPermissionsStep step = new ApplyPermissionsStep(indexer); @Test public void index_issue_permissions() throws Exception { - IssueAuthorizationIndexer indexer = mock(IssueAuthorizationIndexer.class); - new ApplyPermissionsStep(indexer).execute(null); + step.execute(mock(ComputationContext.class)); verify(indexer).index(); } + + @Override + protected ComputationStep step() { + return step; + } } diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/step/BaseStepTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/step/BaseStepTest.java new file mode 100644 index 00000000000..6515c697fe7 --- /dev/null +++ b/server/sonar-server/src/test/java/org/sonar/server/computation/step/BaseStepTest.java @@ -0,0 +1,42 @@ +/* + * 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.server.computation.step; + +import org.junit.Test; + +import java.io.IOException; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Temporary solution to test metadata. Should be replaced by a medium test of + * all computation stack + */ +public abstract class BaseStepTest { + + protected abstract ComputationStep step() throws IOException; + + @Test + public void test_metadata() throws Exception { + assertThat(step().toString()).isNotEmpty(); + assertThat(step().supportedProjectQualifiers().length).isGreaterThan(0); + + } +} diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/step/IndexComponentsStepTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/step/IndexComponentsStepTest.java index bd6fb0263d8..ccb4223c2a5 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/computation/step/IndexComponentsStepTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/computation/step/IndexComponentsStepTest.java @@ -20,10 +20,9 @@ package org.sonar.server.computation.step; -import org.junit.Before; import org.junit.Test; +import org.sonar.batch.protocol.output.BatchReportReader; import org.sonar.core.component.ComponentDto; -import org.sonar.core.computation.db.AnalysisReportDto; import org.sonar.core.resource.ResourceIndexerDao; import org.sonar.server.computation.ComputationContext; @@ -31,26 +30,24 @@ import java.io.IOException; import static org.mockito.Mockito.*; -public class IndexComponentsStepTest { +public class IndexComponentsStepTest extends BaseStepTest { - IndexComponentsStep sut; - ResourceIndexerDao resourceIndexerDao; - - @Before - public void before() { - this.resourceIndexerDao = mock(ResourceIndexerDao.class); - this.sut = new IndexComponentsStep(resourceIndexerDao); - } + ResourceIndexerDao resourceIndexerDao = mock(ResourceIndexerDao.class); + IndexComponentsStep sut = new IndexComponentsStep(resourceIndexerDao); @Test public void call_indexProject_of_dao() throws IOException { ComponentDto project = mock(ComponentDto.class); when(project.getId()).thenReturn(123L); - ComputationContext context = new ComputationContext(mock(AnalysisReportDto.class), project); + ComputationContext context = new ComputationContext(mock(BatchReportReader.class), project); sut.execute(context); verify(resourceIndexerDao).indexProject(123L); } + @Override + protected ComputationStep step() { + return sut; + } } diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/step/IndexSourceLinesStepTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/step/IndexSourceLinesStepTest.java new file mode 100644 index 00000000000..fb0042ba9ea --- /dev/null +++ b/server/sonar-server/src/test/java/org/sonar/server/computation/step/IndexSourceLinesStepTest.java @@ -0,0 +1,40 @@ +/* + * 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.server.computation.step; + +import org.junit.Test; +import org.sonar.server.source.index.SourceLineIndexer; + +import java.io.IOException; + +import static org.mockito.Mockito.mock; + +public class IndexSourceLinesStepTest extends BaseStepTest { + + @Test + public void supportedProjectQualifiers() throws Exception { + + } + + @Override + protected ComputationStep step() throws IOException { + return new IndexSourceLinesStep(mock(SourceLineIndexer.class)); + } +} diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/step/IndexViewsStepTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/step/IndexViewsStepTest.java index 8c8fbd5409f..fc1c913232a 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/computation/step/IndexViewsStepTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/computation/step/IndexViewsStepTest.java @@ -28,7 +28,7 @@ import org.sonar.server.view.index.ViewIndexer; import static org.mockito.Mockito.*; -public class IndexViewsStepTest { +public class IndexViewsStepTest extends BaseStepTest { ComputationContext context = mock(ComputationContext.class); ViewIndexer indexer = mock(ViewIndexer.class); @@ -43,4 +43,8 @@ public class IndexViewsStepTest { verify(indexer).index("ABCD"); } + @Override + protected ComputationStep step() { + return sut; + } } diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/step/ParseReportStepTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/step/ParseReportStepTest.java index 2d3c8204029..fe354e79ff7 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/computation/step/ParseReportStepTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/computation/step/ParseReportStepTest.java @@ -19,27 +19,20 @@ */ package org.sonar.server.computation.step; -import org.junit.Before; import org.junit.ClassRule; import org.junit.Rule; import org.junit.Test; import org.junit.rules.TemporaryFolder; -import org.sonar.api.utils.ZipUtils; -import org.sonar.api.utils.internal.DefaultTempFolder; import org.sonar.batch.protocol.Constants; import org.sonar.batch.protocol.output.BatchOutputWriter; import org.sonar.batch.protocol.output.BatchReport; +import org.sonar.batch.protocol.output.BatchReportReader; import org.sonar.core.component.ComponentDto; -import org.sonar.core.computation.db.AnalysisReportDto; -import org.sonar.core.persistence.DbSession; import org.sonar.core.persistence.DbTester; import org.sonar.server.computation.ComputationContext; -import org.sonar.server.computation.db.AnalysisReportDao; import org.sonar.server.computation.issue.IssueComputation; -import org.sonar.server.db.DbClient; import java.io.File; -import java.io.FileInputStream; import java.io.IOException; import java.util.Collections; @@ -47,7 +40,7 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; -public class ParseReportStepTest { +public class ParseReportStepTest extends BaseStepTest { @Rule public TemporaryFolder temp = new TemporaryFolder(); @@ -55,21 +48,15 @@ public class ParseReportStepTest { @ClassRule public static DbTester dbTester = new DbTester(); - @Before - public void setUp() throws Exception { - dbTester.truncateTables(); - } + IssueComputation issueComputation = mock(IssueComputation.class); + ParseReportStep sut = new ParseReportStep(issueComputation); @Test public void extract_report_from_db_and_browse_components() throws Exception { - AnalysisReportDto reportDto = prepareAnalysisReportInDb(); - + File reportDir = generateReport(); - IssueComputation issueComputation = mock(IssueComputation.class); - DbClient dbClient = new DbClient(dbTester.database(), dbTester.myBatis(), new AnalysisReportDao()); - ParseReportStep step = new ParseReportStep(issueComputation, dbClient, new DefaultTempFolder(temp.newFolder())); - ComputationContext context = new ComputationContext(reportDto, mock(ComponentDto.class)); - step.execute(context); + ComputationContext context = new ComputationContext(new BatchReportReader(reportDir), mock(ComponentDto.class)); + sut.execute(context); // verify that all components are processed (currently only for issues) verify(issueComputation).processComponentIssues(context, "PROJECT_UUID", Collections.<BatchReport.Issue>emptyList()); @@ -79,7 +66,7 @@ public class ParseReportStepTest { assertThat(context.getReportMetadata().getRootComponentRef()).isEqualTo(1); } - private AnalysisReportDto prepareAnalysisReportInDb() throws IOException { + private File generateReport() throws IOException { File dir = temp.newFolder(); // project and 2 files BatchOutputWriter writer = new BatchOutputWriter(dir); @@ -105,28 +92,11 @@ public class ParseReportStepTest { .setType(Constants.ComponentType.FILE) .setUuid("FILE2_UUID") .build()); - File zipFile = temp.newFile(); - ZipUtils.zipDir(dir, zipFile); - - AnalysisReportDto dto = new AnalysisReportDto(); - DbSession dbSession = dbTester.myBatis().openSession(false); - try { - dto.setProjectKey("PROJECT_KEY"); - dto.setCreatedAt(System.currentTimeMillis()); - dto.setSnapshotId(1L); - dto.setStatus(AnalysisReportDto.Status.PENDING); - FileInputStream inputStream = new FileInputStream(zipFile); - dto.setData(inputStream); - AnalysisReportDao dao = new AnalysisReportDao(); - dao.insert(dbSession, dto); - inputStream.close(); - dbSession.commit(); + return dir; + } - // dao#insert() does not set the generated id, so the row - // is loaded again to get its id - return dao.selectByProjectKey(dbSession, "PROJECT_KEY").get(0); - } finally { - dbSession.close(); - } + @Override + protected ComputationStep step() { + return sut; } } diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/step/PurgeDatastoresStepMediumTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/step/PurgeDatastoresStepMediumTest.java deleted file mode 100644 index 004265d841c..00000000000 --- a/server/sonar-server/src/test/java/org/sonar/server/computation/step/PurgeDatastoresStepMediumTest.java +++ /dev/null @@ -1,144 +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.server.computation.step; - -import org.junit.After; -import org.junit.Before; -import org.junit.ClassRule; -import org.junit.Test; -import org.sonar.api.utils.DateUtils; -import org.sonar.core.component.ComponentDto; -import org.sonar.core.component.SnapshotDto; -import org.sonar.core.computation.db.AnalysisReportDto; -import org.sonar.core.computation.db.AnalysisReportDto.Status; -import org.sonar.core.computation.dbcleaner.DbCleanerConstants; -import org.sonar.core.computation.dbcleaner.ProjectCleaner; -import org.sonar.core.persistence.DbSession; -import org.sonar.core.persistence.MyBatis; -import org.sonar.core.properties.PropertyDto; -import org.sonar.server.component.ComponentTesting; -import org.sonar.server.component.SnapshotTesting; -import org.sonar.server.computation.ComputationContext; -import org.sonar.server.db.DbClient; -import org.sonar.server.tester.ServerTester; - -import java.util.Date; - -import static org.assertj.core.api.Assertions.assertThat; - -public class PurgeDatastoresStepMediumTest { - - @ClassRule - public static ServerTester tester = new ServerTester(); - - private PurgeDatastoresStep sut; - private DbClient dbClient; - private DbSession dbSession; - private ProjectCleaner purgeTask; - - @Before - public void before() throws Exception { - this.dbClient = tester.get(DbClient.class); - this.dbSession = dbClient.openSession(false); - - this.purgeTask = tester.get(ProjectCleaner.class); - - this.sut = new PurgeDatastoresStep(dbClient, purgeTask); - } - - @After - public void after() throws Exception { - MyBatis.closeQuietly(dbSession); - } - - @Test - public void use_global_settings_when_no_other_specified() throws Exception { - // ARRANGE - Date now = new Date(); - Date aWeekAgo = DateUtils.addDays(now, -7); - - ComponentDto project = ComponentTesting.newProjectDto() - .setId(1L) - .setKey("123") - .setCreatedAt(aWeekAgo) - .setUpdatedAt(aWeekAgo); - dbClient.componentDao().insert(dbSession, project); - - SnapshotDto snapshot = SnapshotTesting.createForProject(project) - .setCreatedAt(aWeekAgo.getTime()); - dbClient.snapshotDao().insert(dbSession, snapshot); - - AnalysisReportDto report = AnalysisReportDto.newForTests(1L) - .setProjectKey("123") - .setSnapshotId(snapshot.getId()) - .setStatus(Status.PENDING); - dbClient.analysisReportDao().insert(dbSession, report); - - dbClient.propertiesDao().setProperty(new PropertyDto().setKey(DbCleanerConstants.WEEKS_BEFORE_DELETING_ALL_SNAPSHOTS).setValue("52")); - dbSession.commit(); - ComputationContext context = new ComputationContext(report, project); - - // ACT - sut.execute(context); - - // ASSERT - assertThat(dbClient.snapshotDao().getNullableByKey(dbSession, snapshot.getId())).isNotNull(); - } - - @Test - public void use_project_settings_if_specified() throws Exception { - // ARRANGE - Date now = new Date(); - Date twoWeeksAgo = DateUtils.addDays(now, -2 * 7); - Date aLongTimeAgo = DateUtils.addDays(now, -365 * 7); - - ComponentDto project = ComponentTesting.newProjectDto() - .setKey("123") - .setCreatedAt(aLongTimeAgo) - .setUpdatedAt(aLongTimeAgo); - dbClient.componentDao().insert(dbSession, project); - - SnapshotDto snapshot = SnapshotTesting.createForProject(project) - .setCreatedAt(twoWeeksAgo.getTime()) - .setStatus("P") - .setLast(true); - - dbClient.snapshotDao().insert(dbSession, snapshot); - - AnalysisReportDto report = new AnalysisReportDto() - .setProjectKey("123") - .setSnapshotId(snapshot.getId()) - .setStatus(Status.PENDING); - dbClient.analysisReportDao().insert(dbSession, report); - - dbClient.propertiesDao().setProperty(new PropertyDto().setKey(DbCleanerConstants.WEEKS_BEFORE_DELETING_ALL_SNAPSHOTS).setValue("4")); - dbClient.propertiesDao().setProperty(new PropertyDto().setKey(DbCleanerConstants.WEEKS_BEFORE_DELETING_ALL_SNAPSHOTS).setValue("1").setResourceId(project.getId())); - dbSession.commit(); - ComputationContext context = new ComputationContext(report, project); - - // ACT - sut.execute(context); - dbSession.commit(); - - // ASSERT - assertThat(dbClient.snapshotDao().getNullableByKey(dbSession, snapshot.getId())).isNull(); - } -} diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/step/PurgeDatastoresStepTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/step/PurgeDatastoresStepTest.java index a98bb1ddb00..bcf9fccc33c 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/computation/step/PurgeDatastoresStepTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/computation/step/PurgeDatastoresStepTest.java @@ -20,13 +20,12 @@ package org.sonar.server.computation.step; -import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.junit.rules.TemporaryFolder; import org.mockito.Mockito; +import org.sonar.batch.protocol.output.BatchReportReader; import org.sonar.core.component.ComponentDto; -import org.sonar.core.computation.db.AnalysisReportDto; import org.sonar.core.computation.dbcleaner.ProjectCleaner; import org.sonar.core.persistence.DbSession; import org.sonar.core.purge.IdUuidPair; @@ -38,30 +37,28 @@ import java.io.IOException; import static org.mockito.Matchers.any; import static org.mockito.Mockito.*; -public class PurgeDatastoresStepTest { +public class PurgeDatastoresStepTest extends BaseStepTest { - PurgeDatastoresStep sut; - ProjectCleaner projectCleaner; + ProjectCleaner projectCleaner = mock(ProjectCleaner.class);; + PurgeDatastoresStep sut = new PurgeDatastoresStep(mock(DbClient.class, Mockito.RETURNS_DEEP_STUBS), projectCleaner); @Rule public TemporaryFolder temp = new TemporaryFolder(); - @Before - public void before() { - this.projectCleaner = mock(ProjectCleaner.class); - - this.sut = new PurgeDatastoresStep(mock(DbClient.class, Mockito.RETURNS_DEEP_STUBS), projectCleaner); - } - @Test public void call_purge_method_of_the_purge_task() throws IOException { ComponentDto project = mock(ComponentDto.class); when(project.getId()).thenReturn(123L); when(project.uuid()).thenReturn("UUID-1234"); - ComputationContext context = new ComputationContext(mock(AnalysisReportDto.class), project); + ComputationContext context = new ComputationContext(mock(BatchReportReader.class), project); sut.execute(context); verify(projectCleaner).purge(any(DbSession.class), any(IdUuidPair.class)); } + + @Override + protected ComputationStep step() { + return sut; + } } diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/step/PurgeRemovedViewsStepTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/step/PurgeRemovedViewsStepTest.java index 0fd843bf5ca..a490894a654 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/computation/step/PurgeRemovedViewsStepTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/computation/step/PurgeRemovedViewsStepTest.java @@ -23,6 +23,7 @@ package org.sonar.server.computation.step; import org.junit.After; import org.junit.Before; import org.junit.ClassRule; +import org.junit.Rule; import org.junit.Test; import org.sonar.api.config.Settings; import org.sonar.api.resources.Qualifiers; @@ -45,31 +46,25 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; -public class PurgeRemovedViewsStepTest { +public class PurgeRemovedViewsStepTest extends BaseStepTest { @ClassRule public static EsTester esTester = new EsTester().addDefinitions(new ViewIndexDefinition(new Settings())); - @ClassRule - public static DbTester db = new DbTester(); - - ComputationContext context; + @Rule + public DbTester db = new DbTester(); + ComputationContext context = mock(ComputationContext.class); DbSession session; - DbClient dbClient; - - PurgeRemovedViewsStep step; + PurgeRemovedViewsStep sut; @Before public void setUp() { esTester.truncateIndices(); - db.truncateTables(); - - context = mock(ComputationContext.class); session = db.myBatis().openSession(false); dbClient = new DbClient(db.database(), db.myBatis(), new IssueDao(db.myBatis()), new ComponentDao()); - step = new PurgeRemovedViewsStep(new ViewIndex(esTester.client()), dbClient); + sut = new PurgeRemovedViewsStep(new ViewIndex(esTester.client()), dbClient); } @After @@ -92,7 +87,7 @@ public class PurgeRemovedViewsStepTest { dbClient.componentDao().insert(session, view, subView); session.commit(); - step.execute(context); + sut.execute(context); List<String> viewUuids = esTester.getDocumentFields(ViewIndexDefinition.INDEX, ViewIndexDefinition.TYPE_VIEW, ViewIndexDefinition.FIELD_UUID); assertThat(viewUuids).containsOnly("ABCD", "BCDE"); @@ -100,7 +95,11 @@ public class PurgeRemovedViewsStepTest { @Test public void only_support_views() throws Exception { - assertThat(step.supportedProjectQualifiers()).containsOnly(Qualifiers.VIEW); + assertThat(sut.supportedProjectQualifiers()).containsOnly(Qualifiers.VIEW); } + @Override + protected ComputationStep step() { + return sut; + } } diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/step/SendIssueNotificationsStepTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/step/SendIssueNotificationsStepTest.java index 9f0f7b982d7..e0797f9ee94 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/computation/step/SendIssueNotificationsStepTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/computation/step/SendIssueNotificationsStepTest.java @@ -19,6 +19,7 @@ */ package org.sonar.server.computation.step; +import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.junit.rules.TemporaryFolder; @@ -35,10 +36,12 @@ import org.sonar.server.issue.notification.IssueChangeNotification; import org.sonar.server.issue.notification.NewIssuesNotification; import org.sonar.server.notifications.NotificationService; +import java.io.IOException; + import static org.mockito.Matchers.any; import static org.mockito.Mockito.*; -public class SendIssueNotificationsStepTest { +public class SendIssueNotificationsStepTest extends BaseStepTest { @Rule public TemporaryFolder temp = new TemporaryFolder(); @@ -46,32 +49,41 @@ public class SendIssueNotificationsStepTest { RuleCache ruleCache = mock(RuleCache.class); NotificationService notifService = mock(NotificationService.class); ComputationContext context = mock(ComputationContext.class, Mockito.RETURNS_DEEP_STUBS); + IssueCache issueCache; + SendIssueNotificationsStep sut; + + @Before + public void setUp() throws Exception { + issueCache = new IssueCache(temp.newFile(), System2.INSTANCE); + sut = new SendIssueNotificationsStep(issueCache, ruleCache, notifService); + } @Test public void do_not_send_notifications_if_no_subscribers() throws Exception { - IssueCache issueCache = new IssueCache(temp.newFile(), System2.INSTANCE); when(context.getProject().uuid()).thenReturn("PROJECT_UUID"); when(notifService.hasProjectSubscribersForTypes("PROJECT_UUID", SendIssueNotificationsStep.NOTIF_TYPES)).thenReturn(false); - SendIssueNotificationsStep step = new SendIssueNotificationsStep(issueCache, ruleCache, notifService); - step.execute(context); + sut.execute(context); verify(notifService, never()).deliver(any(Notification.class)); } @Test public void send_notifications_if_subscribers() throws Exception { - IssueCache issueCache = new IssueCache(temp.newFile(), System2.INSTANCE); issueCache.newAppender().append(new DefaultIssue().setSeverity(Severity.BLOCKER)).close(); when(context.getProject().uuid()).thenReturn("PROJECT_UUID"); when(context.getReportMetadata()).thenReturn(BatchReport.Metadata.newBuilder().build()); when(notifService.hasProjectSubscribersForTypes("PROJECT_UUID", SendIssueNotificationsStep.NOTIF_TYPES)).thenReturn(true); - SendIssueNotificationsStep step = new SendIssueNotificationsStep(issueCache, ruleCache, notifService); - step.execute(context); + sut.execute(context); verify(notifService).deliver(any(NewIssuesNotification.class)); verify(notifService, atLeastOnce()).deliver(any(IssueChangeNotification.class)); } + + @Override + protected ComputationStep step() throws IOException { + return sut; + } } diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/step/SwitchSnapshotStepTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/step/SwitchSnapshotStepTest.java index dbf46f40a74..cc4dfa9be6b 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/computation/step/SwitchSnapshotStepTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/computation/step/SwitchSnapshotStepTest.java @@ -26,9 +26,8 @@ import org.junit.Test; import org.junit.experimental.categories.Category; import org.sonar.api.utils.DateUtils; import org.sonar.api.utils.System2; -import org.sonar.core.computation.db.AnalysisReportDto; +import org.sonar.batch.protocol.output.BatchReport; import org.sonar.core.persistence.DbTester; -import org.sonar.server.component.ComponentTesting; import org.sonar.server.component.db.SnapshotDao; import org.sonar.server.computation.ComputationContext; import org.sonar.server.db.DbClient; @@ -58,20 +57,14 @@ public class SwitchSnapshotStepTest { @Test public void one_switch_with_a_snapshot_and_his_children() throws IOException { db.prepareDbUnit(getClass(), "snapshots.xml"); - ComputationContext context = new ComputationContext(AnalysisReportDto.newForTests(1L).setSnapshotId(1L), - ComponentTesting.newProjectDto()); + + BatchReport.Metadata metadata = BatchReport.Metadata.newBuilder() + .setSnapshotId(1L).build(); + ComputationContext context = mock(ComputationContext.class); + when(context.getReportMetadata()).thenReturn(metadata); sut.execute(context); db.assertDbUnit(getClass(), "snapshots-result.xml", "snapshots"); } - - @Test(expected = IllegalStateException.class) - public void throw_IllegalStateException_when_not_finding_snapshot() throws IOException { - db.prepareDbUnit(getClass(), "empty.xml"); - ComputationContext context = new ComputationContext(AnalysisReportDto.newForTests(1L).setSnapshotId(1L), - ComponentTesting.newProjectDto()); - - sut.execute(context); - } } diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/ws/HistoryWsActionMediumTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/ws/HistoryWsActionMediumTest.java index 51e8ca6c117..6852087e43f 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/computation/ws/HistoryWsActionMediumTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/computation/ws/HistoryWsActionMediumTest.java @@ -37,8 +37,8 @@ import org.sonar.core.persistence.MyBatis; import org.sonar.core.user.UserDto; import org.sonar.server.activity.ActivityService; import org.sonar.server.component.ComponentTesting; -import org.sonar.server.computation.AnalysisReportLog; -import org.sonar.server.computation.AnalysisReportQueue; +import org.sonar.server.computation.ReportActivity; +import org.sonar.server.computation.ReportQueue; import org.sonar.server.db.DbClient; import org.sonar.server.exceptions.ForbiddenException; import org.sonar.server.tester.ServerTester; @@ -50,8 +50,8 @@ import java.util.List; import static org.assertj.core.api.Assertions.assertThat; /** - * TODO replace this medium test by a small test - */ +* TODO replace this medium test by a small test +*/ public class HistoryWsActionMediumTest { private static final String DEFAULT_PROJECT_KEY = "DefaultProjectKey"; private static final String DEFAULT_PROJECT_NAME = "DefaultProjectName"; @@ -63,7 +63,7 @@ public class HistoryWsActionMediumTest { private DbClient dbClient; private DbSession session; private WsTester wsTester; - private AnalysisReportQueue queue; + private ReportQueue queue; private MockUserSession userSession; private ActivityService activityService; @@ -73,7 +73,7 @@ public class HistoryWsActionMediumTest { dbClient = tester.get(DbClient.class); wsTester = tester.get(WsTester.class); session = dbClient.openSession(false); - queue = tester.get(AnalysisReportQueue.class); + queue = tester.get(ReportQueue.class); activityService = tester.get(ActivityService.class); UserDto connectedUser = new UserDto().setLogin("gandalf").setName("Gandalf"); @@ -93,9 +93,9 @@ public class HistoryWsActionMediumTest { @Test public void add_and_try_to_retrieve_activities() throws Exception { insertPermissionsForProject(DEFAULT_PROJECT_KEY); - queue.add(DEFAULT_PROJECT_KEY, 123L, IOUtils.toInputStream(DEFAULT_REPORT_DATA)); - queue.add(DEFAULT_PROJECT_KEY, 123L, IOUtils.toInputStream(DEFAULT_REPORT_DATA)); - queue.add(DEFAULT_PROJECT_KEY, 123L, IOUtils.toInputStream(DEFAULT_REPORT_DATA)); + queue.add(DEFAULT_PROJECT_KEY, IOUtils.toInputStream(DEFAULT_REPORT_DATA)); + queue.add(DEFAULT_PROJECT_KEY, IOUtils.toInputStream(DEFAULT_REPORT_DATA)); + queue.add(DEFAULT_PROJECT_KEY, IOUtils.toInputStream(DEFAULT_REPORT_DATA)); List<AnalysisReportDto> reports = queue.all(); ComponentDto project = ComponentTesting.newProjectDto() @@ -103,13 +103,13 @@ public class HistoryWsActionMediumTest { .setKey(DEFAULT_PROJECT_KEY); for (AnalysisReportDto report : reports) { report.succeed(); - activityService.write(session, Activity.Type.ANALYSIS_REPORT, new AnalysisReportLog(report, project)); + activityService.write(session, Activity.Type.ANALYSIS_REPORT, new ReportActivity(report, project)); } session.commit(); userSession.setGlobalPermissions(GlobalPermissions.SYSTEM_ADMIN); - WsTester.TestRequest request = wsTester.newGetRequest(ComputationWebService.API_ENDPOINT, HistoryWsAction.SEARCH_ACTION); + WsTester.TestRequest request = wsTester.newGetRequest(ComputationWebService.API_ENDPOINT, "history"); WsTester.Result result = request.execute(); assertThat(result).isNotNull(); @@ -132,14 +132,14 @@ public class HistoryWsActionMediumTest { @Test(expected = ForbiddenException.class) public void user_rights_is_not_enough_throw_ForbiddenException() throws Exception { insertPermissionsForProject(DEFAULT_PROJECT_KEY); - queue.add(DEFAULT_PROJECT_KEY, 123L, IOUtils.toInputStream(DEFAULT_REPORT_DATA)); + queue.add(DEFAULT_PROJECT_KEY, IOUtils.toInputStream(DEFAULT_REPORT_DATA)); AnalysisReportDto report = queue.all().get(0); report.succeed(); - queue.remove(report); + // queue.remove(report); userSession.setGlobalPermissions(GlobalPermissions.SCAN_EXECUTION); - WsTester.TestRequest sut = wsTester.newGetRequest(ComputationWebService.API_ENDPOINT, HistoryWsAction.SEARCH_ACTION); + WsTester.TestRequest sut = wsTester.newGetRequest(ComputationWebService.API_ENDPOINT, "history"); sut.execute(); } } diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/ws/IsQueueEmptyWebServiceTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/ws/IsQueueEmptyWebServiceTest.java index 346d871631f..2be42fa3111 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/computation/ws/IsQueueEmptyWebServiceTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/computation/ws/IsQueueEmptyWebServiceTest.java @@ -26,7 +26,7 @@ import org.junit.Test; import org.sonar.api.server.ws.Request; import org.sonar.api.server.ws.Response; import org.sonar.core.computation.db.AnalysisReportDto; -import org.sonar.server.computation.AnalysisReportQueue; +import org.sonar.server.computation.ReportQueue; import java.io.ByteArrayOutputStream; import java.io.OutputStream; @@ -39,12 +39,12 @@ import static org.mockito.Mockito.when; public class IsQueueEmptyWebServiceTest { IsQueueEmptyWebService.IsQueueEmptyWsAction sut; - AnalysisReportQueue queue; + ReportQueue queue; Response response; @Before public void before() throws Exception { - queue = mock(AnalysisReportQueue.class); + queue = mock(ReportQueue.class); sut = new IsQueueEmptyWebService.IsQueueEmptyWsAction(queue); response = mock(Response.class); diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/ws/QueueWsActionTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/ws/QueueWsActionTest.java index f3821946deb..846f8d095b3 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/computation/ws/QueueWsActionTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/computation/ws/QueueWsActionTest.java @@ -25,7 +25,7 @@ import org.junit.Before; import org.junit.Test; import org.sonar.api.utils.DateUtils; import org.sonar.core.computation.db.AnalysisReportDto; -import org.sonar.server.computation.AnalysisReportQueue; +import org.sonar.server.computation.ReportQueue; import org.sonar.server.ws.WsTester; import java.util.List; @@ -38,11 +38,11 @@ import static org.sonar.core.computation.db.AnalysisReportDto.Status.PENDING; public class QueueWsActionTest { WsTester tester; - private AnalysisReportQueue queue; + private ReportQueue queue; @Before public void setup() throws Exception { - queue = mock(AnalysisReportQueue.class); + queue = mock(ReportQueue.class); tester = new WsTester(new ComputationWebService(new QueueWsAction(queue))); } @@ -52,7 +52,7 @@ public class QueueWsActionTest { .newForTests(1L) .setProjectKey("project-key") .setStatus(PENDING) - .setData(null) + .setUuid("PROJECT_UUID") .setCreatedAt(DateUtils.parseDateTime("2014-10-13T00:00:00+0200").getTime()) .setStartedAt(DateUtils.parseDateTime("2014-10-13T00:00:00+0200").getTime()) .setFinishedAt(DateUtils.parseDateTime("2014-10-13T00:00:00+0200").getTime()); diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/ws/SubmitReportWsActionTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/ws/SubmitReportWsActionTest.java index 44e5bfe2936..e88d651d591 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/computation/ws/SubmitReportWsActionTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/computation/ws/SubmitReportWsActionTest.java @@ -23,8 +23,12 @@ package org.sonar.server.computation.ws; import org.junit.Before; import org.junit.Test; import org.sonar.api.server.ws.WebService; -import org.sonar.server.computation.AnalysisReportQueue; +import org.sonar.core.computation.db.AnalysisReportDto; +import org.sonar.core.permission.GlobalPermissions; import org.sonar.server.computation.ComputationThreadLauncher; +import org.sonar.server.computation.ReportQueue; +import org.sonar.server.exceptions.ForbiddenException; +import org.sonar.server.user.MockUserSession; import org.sonar.server.ws.WsTester; import java.io.InputStream; @@ -34,16 +38,13 @@ import static org.mockito.Mockito.*; public class SubmitReportWsActionTest { - private static final String DEFAULT_PROJECT_KEY = "123456789-987654321"; - private SubmitReportWsAction sut; - - private WsTester wsTester; - private ComputationThreadLauncher workerLauncher = mock(ComputationThreadLauncher.class); - private AnalysisReportQueue queue; + ComputationThreadLauncher workerLauncher = mock(ComputationThreadLauncher.class); + ReportQueue queue = mock(ReportQueue.class); + WsTester wsTester; + SubmitReportWsAction sut; @Before public void before() { - queue = mock(AnalysisReportQueue.class); sut = new SubmitReportWsAction(queue, workerLauncher); wsTester = new WsTester(new ComputationWebService(sut)); } @@ -57,33 +58,36 @@ public class SubmitReportWsActionTest { WebService.Action action = context.controller("api/computation").action("submit_report"); assertThat(action).isNotNull(); - assertThat(action.params()).hasSize(3); + assertThat(action.params()).hasSize(2); } @Test public void add_element_to_queue_and_launch_analysis_task() throws Exception { - when(queue.add(any(String.class), anyLong(), any(InputStream.class))).thenReturn("P1"); + MockUserSession.set().setGlobalPermissions(GlobalPermissions.SCAN_EXECUTION); + AnalysisReportDto dto = mock(AnalysisReportDto.class); + when(dto.getId()).thenReturn(42L); + when(queue.add(any(String.class), any(InputStream.class))).thenReturn(new ReportQueue.Item(dto, null)); WsTester.TestRequest request = wsTester .newGetRequest(ComputationWebService.API_ENDPOINT, "submit_report") .setParam(SubmitReportWsAction.PARAM_PROJECT_KEY, "P1") - .setParam(SubmitReportWsAction.PARAM_SNAPSHOT, "456") .setParam(SubmitReportWsAction.PARAM_REPORT_DATA, null); - request.execute(); + WsTester.Result response = request.execute(); - verify(queue).add(eq("P1"), eq(456L), any(InputStream.class)); + verify(queue).add(eq("P1"), any(InputStream.class)); verify(workerLauncher).startAnalysisTaskNow(); + assertThat(response.outputAsString()).isEqualTo("{\"key\":\"42\"}"); } - @Test - public void return_report_key() throws Exception { - when(queue.add(any(String.class), anyLong(), any(InputStream.class))).thenReturn("P1"); + @Test(expected = ForbiddenException.class) + public void requires_scan_permission() throws Exception { + MockUserSession.set().setGlobalPermissions(GlobalPermissions.DASHBOARD_SHARING); WsTester.TestRequest request = wsTester - .newPostRequest(ComputationWebService.API_ENDPOINT, "submit_report") + .newGetRequest(ComputationWebService.API_ENDPOINT, "submit_report") .setParam(SubmitReportWsAction.PARAM_PROJECT_KEY, "P1") - .setParam(SubmitReportWsAction.PARAM_SNAPSHOT, "456") .setParam(SubmitReportWsAction.PARAM_REPORT_DATA, null); - request.execute().assertJson(getClass(), "submit_report.json", false); + request.execute(); + } } diff --git a/server/sonar-server/src/test/java/org/sonar/server/tester/ServerTester.java b/server/sonar-server/src/test/java/org/sonar/server/tester/ServerTester.java index 3d8f2e1ccdd..ea8f9785964 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/tester/ServerTester.java +++ b/server/sonar-server/src/test/java/org/sonar/server/tester/ServerTester.java @@ -85,6 +85,7 @@ public class ServerTester extends ExternalResource { properties.setProperty(ProcessConstants.CLUSTER_NODE_NAME, esServerHolder.getNodeName()); properties.setProperty(ProcessConstants.SEARCH_PORT, String.valueOf(esServerHolder.getPort())); properties.setProperty(ProcessConstants.PATH_HOME, homeDir.getAbsolutePath()); + properties.setProperty(ProcessConstants.PATH_DATA, new File(homeDir, "data").getAbsolutePath()); properties.setProperty(DatabaseProperties.PROP_URL, "jdbc:h2:" + homeDir.getAbsolutePath() + "/h2"); for (Map.Entry<Object, Object> entry : System.getProperties().entrySet()) { String key = entry.getKey().toString(); diff --git a/server/sonar-server/src/test/resources/org/sonar/server/computation/ComputationServiceTest/shared.xml b/server/sonar-server/src/test/resources/org/sonar/server/computation/ComputationServiceTest/shared.xml index d01512aa559..66bd86524aa 100644 --- a/server/sonar-server/src/test/resources/org/sonar/server/computation/ComputationServiceTest/shared.xml +++ b/server/sonar-server/src/test/resources/org/sonar/server/computation/ComputationServiceTest/shared.xml @@ -1,3 +1,3 @@ <dataset> - <projects id="10" kee="PROJECT_KEY" qualifier="TRK"/> + <projects id="10" kee="P1" qualifier="TRK"/> </dataset> diff --git a/server/sonar-server/src/test/resources/org/sonar/server/computation/db/AnalysisReportDaoTest/any-analysis-reports.xml b/server/sonar-server/src/test/resources/org/sonar/server/computation/db/AnalysisReportDaoTest/any-analysis-reports.xml index b72284f5d10..dba17d047a4 100644 --- a/server/sonar-server/src/test/resources/org/sonar/server/computation/db/AnalysisReportDaoTest/any-analysis-reports.xml +++ b/server/sonar-server/src/test/resources/org/sonar/server/computation/db/AnalysisReportDaoTest/any-analysis-reports.xml @@ -1,29 +1,26 @@ <dataset> <analysis_reports id="1" + uuid="REPORT_1" project_key="123456789-987654321" - snapshot_id="123" - report_data="data-project" report_status="WORKING" created_at="1411509600000" updated_at="1411509600000" /> <analysis_reports id="2" + uuid="REPORT_2" project_key="123456789-987654321" - snapshot_id="123" - report_data="data-project" report_status="WORKING" created_at="1411596000000" updated_at="1411596000000" /> <analysis_reports id="3" + uuid="REPORT_3" project_key="123456789-987654321" - snapshot_id="123" - report_data="data-project" report_status="PENDING" created_at="1411682400000" updated_at="1411682400000" /> -</dataset>
\ No newline at end of file +</dataset> diff --git a/server/sonar-server/src/test/resources/org/sonar/server/computation/db/AnalysisReportDaoTest/book_available_report_analysis_while_having_one_working_on_another_project.xml b/server/sonar-server/src/test/resources/org/sonar/server/computation/db/AnalysisReportDaoTest/book_available_report_analysis_while_having_one_working_on_another_project.xml index 26126affff8..ae28befd603 100644 --- a/server/sonar-server/src/test/resources/org/sonar/server/computation/db/AnalysisReportDaoTest/book_available_report_analysis_while_having_one_working_on_another_project.xml +++ b/server/sonar-server/src/test/resources/org/sonar/server/computation/db/AnalysisReportDaoTest/book_available_report_analysis_while_having_one_working_on_another_project.xml @@ -2,8 +2,7 @@ <analysis_reports id="1" project_key="123456789-987654321" - snapshot_id="123" - report_data="data-project" + uuid="REPORT_1" report_status="PENDING" created_at="1411509600000" updated_at="1411596000000" @@ -11,10 +10,9 @@ <analysis_reports id="2" project_key="987654321-123456789" - snapshot_id="123" - report_data="data-project" + uuid="REPORT_2" report_status="WORKING" created_at="1411423200000" updated_at="1411682400000" /> -</dataset>
\ No newline at end of file +</dataset> diff --git a/server/sonar-server/src/test/resources/org/sonar/server/computation/db/AnalysisReportDaoTest/insert-result.xml b/server/sonar-server/src/test/resources/org/sonar/server/computation/db/AnalysisReportDaoTest/insert-result.xml index a3043ec3238..bc6bbc5b63e 100644 --- a/server/sonar-server/src/test/resources/org/sonar/server/computation/db/AnalysisReportDaoTest/insert-result.xml +++ b/server/sonar-server/src/test/resources/org/sonar/server/computation/db/AnalysisReportDaoTest/insert-result.xml @@ -3,8 +3,7 @@ id="1" project_key="123456789-987654321" project_name="[null]" - snapshot_id="123" - report_data="[null]" + uuid="UUID_1" report_status="PENDING" started_at="[null]" finished_at="[null]" @@ -15,8 +14,7 @@ id="2" project_key="123456789-987654321" project_name="[null]" - snapshot_id="123" - report_data="[null]" + uuid="UUID_2" report_status="PENDING" started_at="[null]" finished_at="[null]" diff --git a/server/sonar-server/src/test/resources/org/sonar/server/computation/db/AnalysisReportDaoTest/one_analysis_report.xml b/server/sonar-server/src/test/resources/org/sonar/server/computation/db/AnalysisReportDaoTest/one_analysis_report.xml index ca3013e2f84..a4e07b73029 100644 --- a/server/sonar-server/src/test/resources/org/sonar/server/computation/db/AnalysisReportDaoTest/one_analysis_report.xml +++ b/server/sonar-server/src/test/resources/org/sonar/server/computation/db/AnalysisReportDaoTest/one_analysis_report.xml @@ -2,12 +2,11 @@ <analysis_reports id="1" project_key="123456789-987654321" - snapshot_id="123" - report_data="data-project" + uuid="REPORT_1" report_status="WORKING" created_at="1411509600000" updated_at="1411596000000" started_at="1411682400000" finished_at="1411768800000" /> -</dataset>
\ No newline at end of file +</dataset> diff --git a/server/sonar-server/src/test/resources/org/sonar/server/computation/db/AnalysisReportDaoTest/one_available_analysis.xml b/server/sonar-server/src/test/resources/org/sonar/server/computation/db/AnalysisReportDaoTest/one_available_analysis.xml deleted file mode 100644 index b26ec14839a..00000000000 --- a/server/sonar-server/src/test/resources/org/sonar/server/computation/db/AnalysisReportDaoTest/one_available_analysis.xml +++ /dev/null @@ -1,20 +0,0 @@ -<dataset> - <analysis_reports - id="1" - project_key="123456789-987654321" - snapshot_id="123" - report_data="data-project" - report_status="PENDING" - created_at="1411509600000" - updated_at="1411596000000" - /> - <analysis_reports - id="2" - project_key="123456789-987654321" - snapshot_id="123" - report_data="data-project" - report_status="PENDING" - created_at="1411509600000" - updated_at="1411596000000" - /> -</dataset> diff --git a/server/sonar-server/src/test/resources/org/sonar/server/computation/db/AnalysisReportDaoTest/one_available_analysis_but_another_busy_on_same_project.xml b/server/sonar-server/src/test/resources/org/sonar/server/computation/db/AnalysisReportDaoTest/one_available_analysis_but_another_busy_on_same_project.xml deleted file mode 100644 index f48e5e111b1..00000000000 --- a/server/sonar-server/src/test/resources/org/sonar/server/computation/db/AnalysisReportDaoTest/one_available_analysis_but_another_busy_on_same_project.xml +++ /dev/null @@ -1,20 +0,0 @@ -<dataset> - <analysis_reports - id="1" - project_key="123456789-987654321" - snapshot_id="123" - report_data="data-project" - report_status="PENDING" - created_at="1411509600000" - updated_at="1411596000000" - /> - <analysis_reports - id="2" - project_key="123456789-987654321" - snapshot_id="123" - report_data="data-project" - report_status="WORKING" - created_at="1411423200000" - updated_at="1411682400000" - /> -</dataset>
\ No newline at end of file diff --git a/server/sonar-server/src/test/resources/org/sonar/server/computation/db/AnalysisReportDaoTest/one_busy_report_analysis.xml b/server/sonar-server/src/test/resources/org/sonar/server/computation/db/AnalysisReportDaoTest/one_busy_report_analysis.xml deleted file mode 100644 index f853e443a39..00000000000 --- a/server/sonar-server/src/test/resources/org/sonar/server/computation/db/AnalysisReportDaoTest/one_busy_report_analysis.xml +++ /dev/null @@ -1,11 +0,0 @@ -<dataset> - <analysis_reports - id="1" - project_key="123456789-987654321" - snapshot_id="123" - report_data="data-project" - report_status="WORKING" - created_at="1411509600000" - updated_at="1411596000000" - /> -</dataset> diff --git a/server/sonar-server/src/test/resources/org/sonar/server/computation/db/AnalysisReportDaoTest/pop_null_if_no_pending_reports.xml b/server/sonar-server/src/test/resources/org/sonar/server/computation/db/AnalysisReportDaoTest/pop_null_if_no_pending_reports.xml index 21eb7f1fb43..82f93e9fec5 100644 --- a/server/sonar-server/src/test/resources/org/sonar/server/computation/db/AnalysisReportDaoTest/pop_null_if_no_pending_reports.xml +++ b/server/sonar-server/src/test/resources/org/sonar/server/computation/db/AnalysisReportDaoTest/pop_null_if_no_pending_reports.xml @@ -2,8 +2,7 @@ <analysis_reports id="1" project_key="111111111-987654321" - snapshot_id="123" - report_data="data-project" + uuid="UUID_1" report_status="WORKING" created_at="1411596000000" updated_at="1411682400000" @@ -11,8 +10,7 @@ <analysis_reports id="2" project_key="123456789-987654321" - snapshot_id="123" - report_data="data-project" + uuid="UUID_2" report_status="WORKING" created_at="1411509600000" updated_at="1411682400000" @@ -21,10 +19,9 @@ <analysis_reports id="3" project_key="123456789-987654321" - snapshot_id="123" - report_data="data-project" + uuid="UUID_3" report_status="PENDING" created_at="1411596000000" updated_at="1411682400000" /> -</dataset>
\ No newline at end of file +</dataset> diff --git a/server/sonar-server/src/test/resources/org/sonar/server/computation/db/AnalysisReportDaoTest/pop_oldest_pending.xml b/server/sonar-server/src/test/resources/org/sonar/server/computation/db/AnalysisReportDaoTest/pop_oldest_pending.xml index cae6dec371c..972fde88fd7 100644 --- a/server/sonar-server/src/test/resources/org/sonar/server/computation/db/AnalysisReportDaoTest/pop_oldest_pending.xml +++ b/server/sonar-server/src/test/resources/org/sonar/server/computation/db/AnalysisReportDaoTest/pop_oldest_pending.xml @@ -3,8 +3,7 @@ <analysis_reports id="1" project_key="P1" - snapshot_id="1" - report_data="data-project" + uuid="UUID_1" report_status="WORKING" created_at="1411596000000" updated_at="1411682400000" @@ -14,8 +13,7 @@ <analysis_reports id="2" project_key="P1" - snapshot_id="2" - report_data="data-project" + uuid="UUID_2" report_status="PENDING" created_at="1411509600000" updated_at="1411682400000" @@ -23,8 +21,7 @@ <analysis_reports id="3" project_key="P2" - snapshot_id="3" - report_data="data-project" + uuid="UUID_3" report_status="PENDING" created_at="1411596000000" updated_at="1411682400000" @@ -32,8 +29,7 @@ <analysis_reports id="4" project_key="P2" - snapshot_id="4" - report_data="data-project" + uuid="UUID_4" report_status="PENDING" created_at="1420066800000" updated_at="1420066800000" diff --git a/server/sonar-server/src/test/resources/org/sonar/server/computation/db/AnalysisReportDaoTest/select.xml b/server/sonar-server/src/test/resources/org/sonar/server/computation/db/AnalysisReportDaoTest/select.xml index 8fff6461280..c1e3284f108 100644 --- a/server/sonar-server/src/test/resources/org/sonar/server/computation/db/AnalysisReportDaoTest/select.xml +++ b/server/sonar-server/src/test/resources/org/sonar/server/computation/db/AnalysisReportDaoTest/select.xml @@ -2,8 +2,7 @@ <analysis_reports id="1" project_key="123456789-987654321" - snapshot_id="123" - report_data="data-project" + uuid="UUID_1" report_status="WORKING" created_at="1411509600000" updated_at="1411596000000" @@ -11,8 +10,7 @@ <analysis_reports id="2" project_key="987654321-123456789" - snapshot_id="123" - report_data="data-project" + uuid="UUID_2" report_status="WORKING" created_at="1411596000000" updated_at="1411596000000" @@ -20,10 +18,9 @@ <analysis_reports id="3" project_key="987654321-123456789" - snapshot_id="123" - report_data="data-project" + uuid="UUID_3" report_status="PENDING" created_at="1411682400000" updated_at="1411682400000" /> -</dataset>
\ No newline at end of file +</dataset> diff --git a/server/sonar-server/src/test/resources/org/sonar/server/computation/db/AnalysisReportDaoTest/select_oldest_available_report_with_working_reports_older.xml b/server/sonar-server/src/test/resources/org/sonar/server/computation/db/AnalysisReportDaoTest/select_oldest_available_report_with_working_reports_older.xml deleted file mode 100644 index 282458ef695..00000000000 --- a/server/sonar-server/src/test/resources/org/sonar/server/computation/db/AnalysisReportDaoTest/select_oldest_available_report_with_working_reports_older.xml +++ /dev/null @@ -1,29 +0,0 @@ -<dataset> - <analysis_reports - id="1" - project_key="111111111-987654321" - snapshot_id="123" - report_data="data-project" - report_status="WORKING" - created_at="1411423200000" - updated_at="1411682400000" - /> - <analysis_reports - id="2" - project_key="123456789-987654321" - snapshot_id="123" - report_data="data-project" - report_status="PENDING" - created_at="1411509600000" - updated_at="1411682400000" - /> - <analysis_reports - id="3" - project_key="333333333-123456789" - snapshot_id="123" - report_data="data-project" - report_status="WORKING" - created_at="1411596000000" - updated_at="1411682400000" - /> -</dataset>
\ No newline at end of file diff --git a/server/sonar-server/src/test/resources/org/sonar/server/computation/db/AnalysisReportDaoTest/three_analysis_reports.xml b/server/sonar-server/src/test/resources/org/sonar/server/computation/db/AnalysisReportDaoTest/three_analysis_reports.xml index 8fff6461280..c1e3284f108 100644 --- a/server/sonar-server/src/test/resources/org/sonar/server/computation/db/AnalysisReportDaoTest/three_analysis_reports.xml +++ b/server/sonar-server/src/test/resources/org/sonar/server/computation/db/AnalysisReportDaoTest/three_analysis_reports.xml @@ -2,8 +2,7 @@ <analysis_reports id="1" project_key="123456789-987654321" - snapshot_id="123" - report_data="data-project" + uuid="UUID_1" report_status="WORKING" created_at="1411509600000" updated_at="1411596000000" @@ -11,8 +10,7 @@ <analysis_reports id="2" project_key="987654321-123456789" - snapshot_id="123" - report_data="data-project" + uuid="UUID_2" report_status="WORKING" created_at="1411596000000" updated_at="1411596000000" @@ -20,10 +18,9 @@ <analysis_reports id="3" project_key="987654321-123456789" - snapshot_id="123" - report_data="data-project" + uuid="UUID_3" report_status="PENDING" created_at="1411682400000" updated_at="1411682400000" /> -</dataset>
\ No newline at end of file +</dataset> diff --git a/server/sonar-server/src/test/resources/org/sonar/server/computation/db/AnalysisReportDaoTest/update-all-to-status-pending-result.xml b/server/sonar-server/src/test/resources/org/sonar/server/computation/db/AnalysisReportDaoTest/update-all-to-status-pending-result.xml index a57c6282dd1..2c240ea4bc4 100644 --- a/server/sonar-server/src/test/resources/org/sonar/server/computation/db/AnalysisReportDaoTest/update-all-to-status-pending-result.xml +++ b/server/sonar-server/src/test/resources/org/sonar/server/computation/db/AnalysisReportDaoTest/update-all-to-status-pending-result.xml @@ -4,8 +4,7 @@ id="1" project_key="P1" project_name="Project1" - snapshot_id="1" - report_data="data-project" + uuid="UUID_1" report_status="PENDING" created_at="1411509600000" updated_at="1411682400000" @@ -16,8 +15,7 @@ id="2" project_key="P2" project_name="Project2" - snapshot_id="123" - report_data="data-project" + uuid="UUID_2" report_status="PENDING" created_at="1411596000000" updated_at="1411682400000" @@ -28,8 +26,7 @@ id="3" project_key="P1" project_name="Project1" - snapshot_id="123" - report_data="data-project" + uuid="UUID_3" report_status="PENDING" created_at="1411682400000" updated_at="1411682400000" diff --git a/server/sonar-server/src/test/resources/org/sonar/server/computation/db/AnalysisReportDaoTest/update-all-to-status-pending.xml b/server/sonar-server/src/test/resources/org/sonar/server/computation/db/AnalysisReportDaoTest/update-all-to-status-pending.xml index 50edcc5da97..a630cb4ec4b 100644 --- a/server/sonar-server/src/test/resources/org/sonar/server/computation/db/AnalysisReportDaoTest/update-all-to-status-pending.xml +++ b/server/sonar-server/src/test/resources/org/sonar/server/computation/db/AnalysisReportDaoTest/update-all-to-status-pending.xml @@ -3,8 +3,7 @@ id="1" project_key="P1" project_name="Project1" - snapshot_id="1" - report_data="data-project" + uuid="UUID_1" report_status="WORKING" created_at="1411509600000" updated_at="1411509600000" @@ -15,8 +14,7 @@ id="2" project_key="P2" project_name="Project2" - snapshot_id="123" - report_data="data-project" + uuid="UUID_2" report_status="WORKING" created_at="1411596000000" updated_at="1411596000000" @@ -27,8 +25,7 @@ id="3" project_key="P1" project_name="Project1" - snapshot_id="123" - report_data="data-project" + uuid="UUID_3" report_status="PENDING" created_at="1411682400000" updated_at="1411682400000" diff --git a/server/sonar-server/src/test/resources/org/sonar/server/computation/ws/SubmitReportWsActionTest/submit_report.json b/server/sonar-server/src/test/resources/org/sonar/server/computation/ws/SubmitReportWsActionTest/submit_report.json deleted file mode 100644 index 40062f5b580..00000000000 --- a/server/sonar-server/src/test/resources/org/sonar/server/computation/ws/SubmitReportWsActionTest/submit_report.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "key": "P1" -} diff --git a/server/sonar-web/src/main/webapp/WEB-INF/db/migrate/796_add_uuid_to_analysis_reports.rb b/server/sonar-web/src/main/webapp/WEB-INF/db/migrate/796_add_uuid_to_analysis_reports.rb new file mode 100644 index 00000000000..06fba16976d --- /dev/null +++ b/server/sonar-web/src/main/webapp/WEB-INF/db/migrate/796_add_uuid_to_analysis_reports.rb @@ -0,0 +1,32 @@ +# +# 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. +# + +# +# SonarQube 5.1 +# +class AddUuidToAnalysisReports < ActiveRecord::Migration + + def self.up + add_column 'analysis_reports', 'uuid', :string, :limit => 50, :null => false + remove_column 'analysis_reports', 'report_data' + remove_column 'analysis_reports', 'snapshot_id' + end + +end |