]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-12630 reorganize log results
authorJacek <jacek.poreda@sonarsource.com>
Thu, 31 Oct 2019 09:36:24 +0000 (10:36 +0100)
committerSonarTech <sonartech@sonarsource.com>
Fri, 8 Nov 2019 19:21:13 +0000 (20:21 +0100)
sonar-plugin-api-impl/src/main/java/org/sonar/api/impl/utils/JUnitTempFolder.java
sonar-scanner-engine/src/main/java/org/sonar/scanner/analysis/AnalysisResultReporter.java [new file with mode: 0644]
sonar-scanner-engine/src/main/java/org/sonar/scanner/qualitygate/QualityGateCheck.java
sonar-scanner-engine/src/main/java/org/sonar/scanner/report/CeTaskReportDataHolder.java [new file with mode: 0644]
sonar-scanner-engine/src/main/java/org/sonar/scanner/report/ReportPublisher.java
sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/ProjectScanContainer.java
sonar-scanner-engine/src/test/java/org/sonar/scanner/analysis/AnalysisResultReporterTest.java [new file with mode: 0644]
sonar-scanner-engine/src/test/java/org/sonar/scanner/mediumtest/ScannerMediumTester.java
sonar-scanner-engine/src/test/java/org/sonar/scanner/report/CeTaskReportDataHolderTest.java [new file with mode: 0644]
sonar-scanner-engine/src/test/java/org/sonar/scanner/report/ReportPublisherTest.java

index a52da93ca7cf997223e5919cc0ddefb9529d000c..08eb33266b1f435422d655604cc15fbc54f0c9b5 100644 (file)
@@ -19,6 +19,9 @@
  */
 package org.sonar.api.impl.utils;
 
+import java.io.File;
+import java.io.IOException;
+import javax.annotation.Nullable;
 import org.apache.commons.lang.StringUtils;
 import org.junit.rules.ExternalResource;
 import org.junit.rules.TemporaryFolder;
@@ -26,11 +29,6 @@ import org.junit.runner.Description;
 import org.junit.runners.model.Statement;
 import org.sonar.api.utils.TempFolder;
 
-import javax.annotation.Nullable;
-
-import java.io.File;
-import java.io.IOException;
-
 /**
  * Implementation of {@link org.sonar.api.utils.TempFolder} to be used
  * only in JUnit tests. It wraps {@link org.junit.rules.TemporaryFolder}.
@@ -105,4 +103,8 @@ public class JUnitTempFolder extends ExternalResource implements TempFolder {
       throw new IllegalStateException("Fail to create temp file", e);
     }
   }
+
+  public File getRoot() {
+    return junit.getRoot();
+  }
 }
diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/analysis/AnalysisResultReporter.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/analysis/AnalysisResultReporter.java
new file mode 100644 (file)
index 0000000..20c32d0
--- /dev/null
@@ -0,0 +1,54 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program 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.
+ *
+ * This program 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.scanner.analysis;
+
+import org.sonar.api.utils.log.Logger;
+import org.sonar.api.utils.log.Loggers;
+import org.sonar.scanner.bootstrap.GlobalAnalysisMode;
+import org.sonar.scanner.report.CeTaskReportDataHolder;
+import org.sonar.scanner.scan.ScanProperties;
+
+public class AnalysisResultReporter {
+
+  private static final Logger LOG = Loggers.get(AnalysisResultReporter.class);
+
+  private final CeTaskReportDataHolder ceTaskReportDataHolder;
+  private final GlobalAnalysisMode analysisMode;
+  private final ScanProperties scanProperties;
+
+  public AnalysisResultReporter(GlobalAnalysisMode analysisMode, CeTaskReportDataHolder ceTaskReportDataHolder,
+    ScanProperties scanProperties) {
+    this.analysisMode = analysisMode;
+    this.ceTaskReportDataHolder = ceTaskReportDataHolder;
+    this.scanProperties = scanProperties;
+  }
+
+  public void report() {
+    if (analysisMode.isMediumTest()) {
+      LOG.info("ANALYSIS SUCCESSFUL");
+    } else {
+      LOG.info("ANALYSIS SUCCESSFUL, you can browse {}", ceTaskReportDataHolder.getDashboardUrl());
+      if (!scanProperties.shouldWaitForQualityGate()) {
+        LOG.info("Note that you will be able to access the updated dashboard once the server has processed the submitted analysis report");
+      }
+      LOG.info("More about the report processing at {}", ceTaskReportDataHolder.getCeTaskUrl());
+    }
+  }
+}
index bae3d39b6346fc983aeed5bc8568f057671ecbe4..871ba195b746ac9996f84ecc53d7229d03dc5e13 100644 (file)
  */
 package org.sonar.scanner.qualitygate;
 
-import java.io.IOException;
 import java.io.InputStream;
-import java.io.Reader;
-import java.nio.charset.StandardCharsets;
-import java.nio.file.Files;
-import java.nio.file.Path;
 import java.time.Duration;
 import java.time.temporal.ChronoUnit;
 import java.util.EnumSet;
-import java.util.Properties;
 import org.picocontainer.Startable;
 import org.sonar.api.utils.MessageException;
 import org.sonar.api.utils.log.Logger;
 import org.sonar.api.utils.log.Loggers;
 import org.sonar.scanner.bootstrap.DefaultScannerWsClient;
+import org.sonar.scanner.bootstrap.GlobalAnalysisMode;
+import org.sonar.scanner.report.CeTaskReportDataHolder;
 import org.sonar.scanner.scan.ScanProperties;
 import org.sonarqube.ws.Ce;
 import org.sonarqube.ws.Ce.TaskStatus;
@@ -51,14 +47,19 @@ public class QualityGateCheck implements Startable {
   private static final int POLLING_INTERVAL_IN_MS = 5000;
 
   private final DefaultScannerWsClient wsClient;
+  private final GlobalAnalysisMode analysisMode;
+  private final CeTaskReportDataHolder reportMetadataHolder;
   private final ScanProperties properties;
 
   private long qualityGateTimeoutInMs;
   private boolean enabled;
 
-  public QualityGateCheck(ScanProperties properties, DefaultScannerWsClient wsClient) {
+  public QualityGateCheck(DefaultScannerWsClient wsClient, GlobalAnalysisMode analysisMode, CeTaskReportDataHolder reportMetadataHolder,
+    ScanProperties properties) {
     this.wsClient = wsClient;
     this.properties = properties;
+    this.reportMetadataHolder = reportMetadataHolder;
+    this.analysisMode = analysisMode;
   }
 
   @Override
@@ -73,12 +74,16 @@ public class QualityGateCheck implements Startable {
   }
 
   public void await() {
+    if (!analysisMode.isMediumTest()) {
+      throw new IllegalStateException("Quality Gate check not available in medium test mode");
+    }
+
     if (!enabled) {
-      LOG.debug("Quality Gate Check disabled - skipping");
+      LOG.debug("Quality Gate check disabled - skipping");
       return;
     }
 
-    String taskId = readTaskIdFromMetaDataFile();
+    String taskId = reportMetadataHolder.getCeTaskId();
 
     Ce.Task task = waitForCeTaskToFinish(taskId);
 
@@ -93,22 +98,10 @@ public class QualityGateCheck implements Startable {
     } else if (Status.NONE.equals(qualityGateStatus)) {
       LOG.info("No Quality Gate is associated with the analysis - skipping");
     } else {
-      LOG.info("Quality Gate - FAILED");
       throw MessageException.of("Quality Gate - FAILED");
     }
   }
 
-  private String readTaskIdFromMetaDataFile() {
-    Path file = properties.metadataFilePath();
-    try (Reader reader = Files.newBufferedReader(file, StandardCharsets.UTF_8)) {
-      Properties metadata = new Properties();
-      metadata.load(reader);
-      return metadata.getProperty("ceTaskId");
-    } catch (IOException e) {
-      throw new IllegalStateException("Unable to read metadata file: " + file, e);
-    }
-  }
-
   private Ce.Task waitForCeTaskToFinish(String taskId) {
     GetRequest getTaskResultReq = new GetRequest("api/ce/task")
       .setMediaType(MediaTypes.PROTOBUF)
diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/report/CeTaskReportDataHolder.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/report/CeTaskReportDataHolder.java
new file mode 100644 (file)
index 0000000..a64bf79
--- /dev/null
@@ -0,0 +1,62 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program 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.
+ *
+ * This program 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.scanner.report;
+
+import static java.util.Objects.requireNonNull;
+
+public class CeTaskReportDataHolder {
+  private boolean initialized = false;
+  private String ceTaskId;
+  private String ceTaskUrl;
+  private String dashboardUrl;
+
+  public void init(String ceTaskId, String ceTaskUrl, String dashboardUrl) {
+    requireNonNull(ceTaskId, "CE task id must not be null");
+    requireNonNull(ceTaskUrl, "CE task url must not be null");
+    requireNonNull(dashboardUrl, "Dashboard url map must not be null");
+
+    this.ceTaskId = ceTaskId;
+    this.ceTaskUrl = ceTaskUrl;
+    this.dashboardUrl = dashboardUrl;
+
+    this.initialized = true;
+  }
+
+  private void verifyInitialized() {
+    if (!initialized) {
+      throw new IllegalStateException("Scan report hasn't been published yet");
+    }
+  }
+
+  public String getCeTaskId() {
+    verifyInitialized();
+    return ceTaskId;
+  }
+
+  public String getDashboardUrl() {
+    verifyInitialized();
+    return dashboardUrl;
+  }
+
+  public String getCeTaskUrl() {
+    verifyInitialized();
+    return ceTaskUrl;
+  }
+}
index ca0c8f5c1cf85fee64ccd6da2503f8cbe639b969..1c6ce3987b1d319531d39cac21130ce02af9a1e3 100644 (file)
@@ -40,8 +40,8 @@ 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.scanner.bootstrap.GlobalAnalysisMode;
 import org.sonar.scanner.bootstrap.DefaultScannerWsClient;
+import org.sonar.scanner.bootstrap.GlobalAnalysisMode;
 import org.sonar.scanner.fs.InputModuleHierarchy;
 import org.sonar.scanner.protocol.output.ScannerReportReader;
 import org.sonar.scanner.protocol.output.ScannerReportWriter;
@@ -79,13 +79,15 @@ public class ReportPublisher implements Startable {
   private final Server server;
   private final BranchConfiguration branchConfiguration;
   private final ScanProperties properties;
+  private final CeTaskReportDataHolder ceTaskReportDataHolder;
 
   private Path reportDir;
   private ScannerReportWriter writer;
   private ScannerReportReader reader;
 
   public ReportPublisher(ScanProperties properties, DefaultScannerWsClient wsClient, Server server, AnalysisContextReportPublisher contextPublisher,
-    InputModuleHierarchy moduleHierarchy, GlobalAnalysisMode analysisMode, TempFolder temp, ReportPublisherStep[] publishers, BranchConfiguration branchConfiguration) {
+    InputModuleHierarchy moduleHierarchy, GlobalAnalysisMode analysisMode, TempFolder temp, ReportPublisherStep[] publishers, BranchConfiguration branchConfiguration,
+    CeTaskReportDataHolder ceTaskReportDataHolder) {
     this.wsClient = wsClient;
     this.server = server;
     this.contextPublisher = contextPublisher;
@@ -95,6 +97,7 @@ public class ReportPublisher implements Startable {
     this.publishers = publishers;
     this.branchConfiguration = branchConfiguration;
     this.properties = properties;
+    this.ceTaskReportDataHolder = ceTaskReportDataHolder;
   }
 
   @Override
@@ -132,15 +135,14 @@ public class ReportPublisher implements Startable {
   }
 
   public void execute() {
-    String taskId = null;
     File report = generateReportFile();
     if (properties.shouldKeepReport()) {
       LOG.info("Analysis report generated in " + reportDir);
     }
     if (!analysisMode.isMediumTest()) {
-      taskId = upload(report);
+      String taskId = upload(report);
+      prepareAndDumpMetadata(taskId);
     }
-    logSuccess(taskId);
   }
 
   private File generateReportFile() {
@@ -204,36 +206,28 @@ public class ReportPublisher implements Startable {
     }
   }
 
-  void logSuccess(@Nullable String taskId) {
-    if (taskId == null) {
-      LOG.info("ANALYSIS SUCCESSFUL");
-    } else {
+  void prepareAndDumpMetadata(String taskId) {
+    Map<String, String> metadata = new LinkedHashMap<>();
 
-      Map<String, String> metadata = new LinkedHashMap<>();
+    properties.organizationKey().ifPresent(org -> metadata.put("organization", org));
+    metadata.put("projectKey", moduleHierarchy.root().key());
+    metadata.put("serverUrl", server.getPublicRootUrl());
+    metadata.put("serverVersion", server.getVersion());
+    properties.branch().ifPresent(branch -> metadata.put("branch", branch));
 
-      properties.organizationKey().ifPresent(org -> metadata.put("organization", org));
-      metadata.put("projectKey", moduleHierarchy.root().key());
-      metadata.put("serverUrl", server.getPublicRootUrl());
-      metadata.put("serverVersion", server.getVersion());
-      properties.branch().ifPresent(branch -> metadata.put("branch", branch));
+    URL dashboardUrl = buildDashboardUrl(server.getPublicRootUrl(), moduleHierarchy.root().key());
+    metadata.put("dashboardUrl", dashboardUrl.toExternalForm());
 
-      URL dashboardUrl = buildDashboardUrl(server.getPublicRootUrl(), moduleHierarchy.root().key());
-      metadata.put("dashboardUrl", dashboardUrl.toExternalForm());
+    URL taskUrl = HttpUrl.parse(server.getPublicRootUrl()).newBuilder()
+      .addPathSegment("api").addPathSegment("ce").addPathSegment("task")
+      .addQueryParameter(ID, taskId)
+      .build()
+      .url();
+    metadata.put("ceTaskId", taskId);
+    metadata.put("ceTaskUrl", taskUrl.toExternalForm());
 
-      URL taskUrl = HttpUrl.parse(server.getPublicRootUrl()).newBuilder()
-        .addPathSegment("api").addPathSegment("ce").addPathSegment("task")
-        .addQueryParameter(ID, taskId)
-        .build()
-        .url();
-      metadata.put("ceTaskId", taskId);
-      metadata.put("ceTaskUrl", taskUrl.toExternalForm());
-
-      LOG.info("ANALYSIS SUCCESSFUL, you can browse {}", dashboardUrl);
-      LOG.info("Note that you will be able to access the updated dashboard once the server has processed the submitted analysis report");
-      LOG.info("More about the report processing at {}", taskUrl);
-
-      dumpMetadata(metadata);
-    }
+    ceTaskReportDataHolder.init(taskId, taskUrl.toExternalForm(), dashboardUrl.toExternalForm());
+    dumpMetadata(metadata);
   }
 
   private URL buildDashboardUrl(String publicUrl, String effectiveKey) {
index 5ab47b36755d51425300ea25320cb65d5532cc16..45b63ec6cc101047daa4cac4d8c55d9f54262c6f 100644 (file)
@@ -37,6 +37,7 @@ import org.sonar.core.metric.ScannerMetrics;
 import org.sonar.core.platform.ComponentContainer;
 import org.sonar.scanner.DefaultFileLinesContextFactory;
 import org.sonar.scanner.ProjectInfo;
+import org.sonar.scanner.analysis.AnalysisResultReporter;
 import org.sonar.scanner.analysis.AnalysisTempFolderProvider;
 import org.sonar.scanner.analysis.DefaultAnalysisMode;
 import org.sonar.scanner.bootstrap.ExtensionInstaller;
@@ -248,6 +249,7 @@ public class ProjectScanContainer extends ComponentContainer {
       TestExecutionPublisher.class,
       SourcePublisher.class,
       ChangedLinesPublisher.class,
+      AnalysisResultReporter.class,
 
       //QualityGate check
       QualityGateCheck.class,
@@ -360,6 +362,8 @@ public class ProjectScanContainer extends ComponentContainer {
       getComponentByType(QualityGateCheck.class).await();
     }
 
+    getComponentByType(AnalysisResultReporter.class).report();
+
     getComponentByType(PostJobsExecutor.class).execute();
 
     if (analysisMode.isMediumTest()) {
diff --git a/sonar-scanner-engine/src/test/java/org/sonar/scanner/analysis/AnalysisResultReporterTest.java b/sonar-scanner-engine/src/test/java/org/sonar/scanner/analysis/AnalysisResultReporterTest.java
new file mode 100644 (file)
index 0000000..f5c9d89
--- /dev/null
@@ -0,0 +1,85 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program 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.
+ *
+ * This program 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.scanner.analysis;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.sonar.api.utils.log.LogTester;
+import org.sonar.api.utils.log.LoggerLevel;
+import org.sonar.scanner.bootstrap.GlobalAnalysisMode;
+import org.sonar.scanner.report.CeTaskReportDataHolder;
+import org.sonar.scanner.scan.ScanProperties;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+public class AnalysisResultReporterTest {
+  @Rule
+  public LogTester logTester = new LogTester();
+
+  private CeTaskReportDataHolder ceTaskReportDataHolder = mock(CeTaskReportDataHolder.class);
+  private GlobalAnalysisMode analysisMode = mock(GlobalAnalysisMode.class);
+  private ScanProperties scanProperties = mock(ScanProperties.class);
+
+  private AnalysisResultReporter underTest = new AnalysisResultReporter(analysisMode, ceTaskReportDataHolder, scanProperties);
+
+  @Test
+  public void should_log_simple_success_message() {
+    when(analysisMode.isMediumTest()).thenReturn(true);
+    underTest.report();
+
+    assertThat(logTester.logs(LoggerLevel.INFO))
+      .containsOnly("ANALYSIS SUCCESSFUL");
+  }
+
+  @Test
+  public void should_log_success_message_with_urls() {
+    String ceTaskUrl = "http://sonarqube/taskurl";
+    String dashboardUrl = "http://sonarqube/dashboardurl";
+    when(ceTaskReportDataHolder.getCeTaskUrl()).thenReturn(ceTaskUrl);
+    when(ceTaskReportDataHolder.getDashboardUrl()).thenReturn(dashboardUrl);
+
+    underTest.report();
+
+    assertThat(logTester.logs(LoggerLevel.INFO))
+      .containsExactly(
+        "ANALYSIS SUCCESSFUL, you can browse " + dashboardUrl,
+        "Note that you will be able to access the updated dashboard once the server has processed the submitted analysis report",
+        "More about the report processing at " + ceTaskUrl);
+  }
+
+  @Test
+  public void should_log_short_success_message_with_urls_if_quality_gate_wait_enabled() {
+    String ceTaskUrl = "http://sonarqube/taskurl";
+    String dashboardUrl = "http://sonarqube/dashboardurl";
+    when(ceTaskReportDataHolder.getCeTaskUrl()).thenReturn(ceTaskUrl);
+    when(ceTaskReportDataHolder.getDashboardUrl()).thenReturn(dashboardUrl);
+
+    when(scanProperties.shouldWaitForQualityGate()).thenReturn(true);
+
+    underTest.report();
+
+    assertThat(logTester.logs(LoggerLevel.INFO))
+      .containsExactly(
+        "ANALYSIS SUCCESSFUL, you can browse " + dashboardUrl,
+        "More about the report processing at " + ceTaskUrl);
+  }
+}
index a8769acd7a595c5b4d7116a45404d9045429b19d..be6be13b72741910e740954e1a1959a167078d0c 100644 (file)
@@ -57,6 +57,7 @@ import org.sonar.batch.bootstrapper.Batch;
 import org.sonar.batch.bootstrapper.EnvironmentInformation;
 import org.sonar.batch.bootstrapper.LogOutput;
 import org.sonar.scanner.bootstrap.GlobalAnalysisMode;
+import org.sonar.scanner.report.CeTaskReportDataHolder;
 import org.sonar.scanner.repository.FileData;
 import org.sonar.scanner.repository.MetricsRepository;
 import org.sonar.scanner.repository.MetricsRepositoryLoader;
@@ -95,6 +96,7 @@ public class ScannerMediumTester extends ExternalResource {
   private final FakeQualityProfileLoader qualityProfiles = new FakeQualityProfileLoader();
   private final FakeActiveRulesLoader activeRules = new FakeActiveRulesLoader();
   private final FakeSonarRuntime sonarRuntime = new FakeSonarRuntime();
+  private final CeTaskReportDataHolder reportMetadataHolder = new CeTaskReportDataHolder();
   private LogOutput logOutput = null;
 
   private static void createWorkingDirs() throws IOException {
@@ -294,6 +296,7 @@ public class ScannerMediumTester extends ExternalResource {
           tester.globalSettingsLoader,
           tester.projectSettingsLoader,
           tester.sonarRuntime,
+          tester.reportMetadataHolder,
           result)
         .setLogOutput(tester.logOutput)
         .build().execute();
diff --git a/sonar-scanner-engine/src/test/java/org/sonar/scanner/report/CeTaskReportDataHolderTest.java b/sonar-scanner-engine/src/test/java/org/sonar/scanner/report/CeTaskReportDataHolderTest.java
new file mode 100644 (file)
index 0000000..4d18429
--- /dev/null
@@ -0,0 +1,63 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program 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.
+ *
+ * This program 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.scanner.report;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+public class CeTaskReportDataHolderTest {
+
+  @Rule
+  public ExpectedException exception = ExpectedException.none();
+
+  CeTaskReportDataHolder underTest = new CeTaskReportDataHolder();
+
+  @Test
+  public void should_initialize_field() {
+    String ceTaskId = "ceTaskId";
+    String ceTaskUrl = "ceTaskUrl";
+    String dashboardUrl = "dashboardUrl";
+    underTest.init(ceTaskId, ceTaskUrl, dashboardUrl);
+    assertThat(underTest.getCeTaskId()).isEqualTo(ceTaskId);
+    assertThat(underTest.getCeTaskUrl()).isEqualTo(ceTaskUrl);
+    assertThat(underTest.getDashboardUrl()).isEqualTo(dashboardUrl);
+  }
+
+  @Test
+  public void getCeTaskId_should_fail_if_not_initialized() {
+    exception.expect(IllegalStateException.class);
+    underTest.getCeTaskId();
+  }
+
+  @Test
+  public void getCeTaskUrl_should_fail_if_not_initialized() {
+    exception.expect(IllegalStateException.class);
+    underTest.getCeTaskUrl();
+  }
+
+  @Test
+  public void getDashboardUrl_should_fail_if_not_initialized() {
+    exception.expect(IllegalStateException.class);
+    underTest.getDashboardUrl();
+  }
+}
index 11781cc6b2533f50f8d184f6cc6d2d47dff2c845..3fc00a31110e7733406742b3aacffb9e6a84d01b 100644 (file)
@@ -30,23 +30,24 @@ import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.rules.ExpectedException;
-import org.junit.rules.TemporaryFolder;
 import org.mockito.ArgumentCaptor;
 import org.mockito.Mockito;
 import org.sonar.api.batch.bootstrap.ProjectDefinition;
+import org.sonar.api.batch.fs.internal.DefaultInputModule;
+import org.sonar.api.impl.utils.JUnitTempFolder;
 import org.sonar.api.platform.Server;
 import org.sonar.api.utils.MessageException;
 import org.sonar.api.utils.TempFolder;
 import org.sonar.api.utils.log.LogTester;
 import org.sonar.api.utils.log.LoggerLevel;
-import org.sonar.scanner.bootstrap.GlobalAnalysisMode;
 import org.sonar.scanner.bootstrap.DefaultScannerWsClient;
-import org.sonar.api.batch.fs.internal.DefaultInputModule;
+import org.sonar.scanner.bootstrap.GlobalAnalysisMode;
 import org.sonar.scanner.fs.InputModuleHierarchy;
 import org.sonar.scanner.scan.ScanProperties;
 import org.sonar.scanner.scan.branch.BranchConfiguration;
 import org.sonarqube.ws.Ce;
 import org.sonarqube.ws.client.HttpException;
+import org.sonarqube.ws.client.MockWsResponse;
 import org.sonarqube.ws.client.WsRequest;
 import org.sonarqube.ws.client.WsResponse;
 
@@ -66,7 +67,7 @@ public class ReportPublisherTest {
   public LogTester logTester = new LogTester();
 
   @Rule
-  public TemporaryFolder temp = new TemporaryFolder();
+  public JUnitTempFolder reportTempFolder = new JUnitTempFolder();
 
   @Rule
   public ExpectedException exception = ExpectedException.none();
@@ -79,29 +80,26 @@ public class ReportPublisherTest {
   DefaultInputModule root;
   AnalysisContextReportPublisher contextPublisher = mock(AnalysisContextReportPublisher.class);
   BranchConfiguration branchConfiguration = mock(BranchConfiguration.class);
-  ReportPublisher underTest = new ReportPublisher(properties, wsClient, server, contextPublisher, moduleHierarchy, mode, mock(TempFolder.class),
-    new ReportPublisherStep[0], branchConfiguration);
+  CeTaskReportDataHolder reportMetadataHolder = mock(CeTaskReportDataHolder.class);
+  ReportPublisher underTest = new ReportPublisher(properties, wsClient, server, contextPublisher, moduleHierarchy, mode, reportTempFolder,
+    new ReportPublisherStep[0], branchConfiguration, reportMetadataHolder);
 
   @Before
-  public void setUp() throws IOException {
-    root = new DefaultInputModule(ProjectDefinition.create().setKey("org.sonarsource.sonarqube:sonarqube").setBaseDir(temp.newFolder()).setWorkDir(temp.getRoot()));
+  public void setUp() {
+    root = new DefaultInputModule(
+      ProjectDefinition.create().setKey("org.sonarsource.sonarqube:sonarqube").setBaseDir(reportTempFolder.newDir()).setWorkDir(reportTempFolder.getRoot()));
     when(moduleHierarchy.root()).thenReturn(root);
     when(server.getPublicRootUrl()).thenReturn("https://localhost");
     when(server.getVersion()).thenReturn("6.4");
-    when(properties.metadataFilePath()).thenReturn(temp.newFolder().toPath()
+    when(properties.metadataFilePath()).thenReturn(reportTempFolder.newDir().toPath()
       .resolve("folder")
       .resolve("report-task.txt"));
   }
 
   @Test
-  public void log_and_dump_information_about_report_uploading() throws IOException {
+  public void dump_information_about_report_uploading() throws IOException {
     when(properties.organizationKey()).thenReturn(Optional.of("MyOrg"));
-    underTest.logSuccess("TASK-123");
-
-    assertThat(logTester.logs(LoggerLevel.INFO))
-      .contains("ANALYSIS SUCCESSFUL, you can browse https://localhost/dashboard?id=org.sonarsource.sonarqube%3Asonarqube")
-      .contains("Note that you will be able to access the updated dashboard once the server has processed the submitted analysis report")
-      .contains("More about the report processing at https://localhost/api/ce/task?id=TASK-123");
+    underTest.prepareAndDumpMetadata("TASK-123");
 
     assertThat(readFileToString(properties.metadataFilePath().toFile(), StandardCharsets.UTF_8)).isEqualTo(
       "organization=MyOrg\n" +
@@ -114,7 +112,7 @@ public class ReportPublisherTest {
   }
 
   @Test
-  public void parse_upload_error_message() throws IOException {
+  public void parse_upload_error_message() {
     HttpException ex = new HttpException("url", 404, "{\"errors\":[{\"msg\":\"Organization with key 'MyOrg' does not exist\"}]}");
     WsResponse response = mock(WsResponse.class);
     when(response.failIfNotSuccessful()).thenThrow(ex);
@@ -122,18 +120,14 @@ public class ReportPublisherTest {
 
     exception.expect(MessageException.class);
     exception.expectMessage("Failed to upload report - Organization with key 'MyOrg' does not exist");
-    underTest.upload(temp.newFile());
+    underTest.upload(reportTempFolder.newFile());
   }
 
   @Test
-  public void log_public_url_if_defined_for_main_branch() throws IOException {
+  public void dump_public_url_if_defined_for_main_branch() throws IOException {
     when(server.getPublicRootUrl()).thenReturn("https://publicserver/sonarqube");
 
-    underTest.logSuccess("TASK-123");
-
-    assertThat(logTester.logs(LoggerLevel.INFO))
-      .contains("ANALYSIS SUCCESSFUL, you can browse https://publicserver/sonarqube/dashboard?id=org.sonarsource.sonarqube%3Asonarqube")
-      .contains("More about the report processing at https://publicserver/sonarqube/api/ce/task?id=TASK-123");
+    underTest.prepareAndDumpMetadata("TASK-123");
 
     assertThat(readFileToString(properties.metadataFilePath().toFile(), StandardCharsets.UTF_8)).isEqualTo(
       "projectKey=org.sonarsource.sonarqube:sonarqube\n" +
@@ -145,17 +139,14 @@ public class ReportPublisherTest {
   }
 
   @Test
-  public void log_public_url_if_defined_for_long_living_branches() throws IOException {
+  public void dump_public_url_if_defined_for_long_living_branches() throws IOException {
     when(server.getPublicRootUrl()).thenReturn("https://publicserver/sonarqube");
     when(branchConfiguration.branchType()).thenReturn(LONG);
     when(branchConfiguration.branchName()).thenReturn("branch-6.7");
     ReportPublisher underTest = new ReportPublisher(properties, wsClient, server, contextPublisher, moduleHierarchy, mode, mock(TempFolder.class),
-      new ReportPublisherStep[0], branchConfiguration);
+      new ReportPublisherStep[0], branchConfiguration, reportMetadataHolder);
 
-    underTest.logSuccess("TASK-123");
-    assertThat(logTester.logs(LoggerLevel.INFO))
-      .contains("ANALYSIS SUCCESSFUL, you can browse https://publicserver/sonarqube/dashboard?id=org.sonarsource.sonarqube%3Asonarqube&branch=branch-6.7")
-      .contains("More about the report processing at https://publicserver/sonarqube/api/ce/task?id=TASK-123");
+    underTest.prepareAndDumpMetadata("TASK-123");
 
     assertThat(readFileToString(properties.metadataFilePath().toFile(), StandardCharsets.UTF_8)).isEqualTo(
       "projectKey=org.sonarsource.sonarqube:sonarqube\n" +
@@ -167,17 +158,14 @@ public class ReportPublisherTest {
   }
 
   @Test
-  public void log_public_url_if_defined_for_short_living_branches() throws IOException {
+  public void dump_public_url_if_defined_for_short_living_branches() throws IOException {
     when(server.getPublicRootUrl()).thenReturn("https://publicserver/sonarqube");
     when(branchConfiguration.branchType()).thenReturn(SHORT);
     when(branchConfiguration.branchName()).thenReturn("branch-6.7");
     ReportPublisher underTest = new ReportPublisher(properties, wsClient, server, contextPublisher, moduleHierarchy, mode, mock(TempFolder.class),
-      new ReportPublisherStep[0], branchConfiguration);
+      new ReportPublisherStep[0], branchConfiguration, reportMetadataHolder);
 
-    underTest.logSuccess("TASK-123");
-    assertThat(logTester.logs(LoggerLevel.INFO))
-      .contains("ANALYSIS SUCCESSFUL, you can browse https://publicserver/sonarqube/dashboard?id=org.sonarsource.sonarqube%3Asonarqube&branch=branch-6.7&resolved=false")
-      .contains("More about the report processing at https://publicserver/sonarqube/api/ce/task?id=TASK-123");
+    underTest.prepareAndDumpMetadata("TASK-123");
 
     assertThat(readFileToString(properties.metadataFilePath().toFile(), StandardCharsets.UTF_8)).isEqualTo(
       "projectKey=org.sonarsource.sonarqube:sonarqube\n" +
@@ -189,20 +177,16 @@ public class ReportPublisherTest {
   }
 
   @Test
-  public void log_public_url_if_defined_for_pull_request() throws IOException {
+  public void dump_public_url_if_defined_for_pull_request() throws IOException {
     when(server.getPublicRootUrl()).thenReturn("https://publicserver/sonarqube");
     when(branchConfiguration.branchName()).thenReturn("Bitbucket cloud Widget");
     when(branchConfiguration.branchType()).thenReturn(PULL_REQUEST);
     when(branchConfiguration.pullRequestKey()).thenReturn("105");
 
     ReportPublisher underTest = new ReportPublisher(properties, wsClient, server, contextPublisher, moduleHierarchy, mode, mock(TempFolder.class),
-      new ReportPublisherStep[0], branchConfiguration);
+      new ReportPublisherStep[0], branchConfiguration, reportMetadataHolder);
 
-    underTest.logSuccess("TASK-123");
-
-    assertThat(logTester.logs(LoggerLevel.INFO))
-      .contains("ANALYSIS SUCCESSFUL, you can browse https://publicserver/sonarqube/dashboard?id=org.sonarsource.sonarqube%3Asonarqube&pullRequest=105")
-      .contains("More about the report processing at https://publicserver/sonarqube/api/ce/task?id=TASK-123");
+    underTest.prepareAndDumpMetadata("TASK-123");
 
     assertThat(readFileToString(properties.metadataFilePath().toFile(), StandardCharsets.UTF_8)).isEqualTo(
       "projectKey=org.sonarsource.sonarqube:sonarqube\n" +
@@ -223,19 +207,28 @@ public class ReportPublisherTest {
   }
 
   @Test
-  public void log_but_not_dump_information_when_report_is_not_uploaded() throws IOException {
-    underTest.logSuccess(/* report not uploaded, no server task */null);
+  public void should_not_dump_information_when_medium_test_enabled() {
+    when(mode.isMediumTest()).thenReturn(true);
+    underTest.start();
+    underTest.execute();
+    assertThat(properties.metadataFilePath()).doesNotExist();
+  }
 
-    assertThat(logTester.logs(LoggerLevel.INFO))
-      .contains("ANALYSIS SUCCESSFUL")
-      .doesNotContain("dashboard/index");
+  @Test
+  public void should_upload_and_dump_information() {
+    MockWsResponse submitMockResponse = new MockWsResponse();
+    submitMockResponse.setContent(Ce.SubmitResponse.newBuilder().setTaskId("task-1234").build().toByteArray());
+    when(wsClient.call(any())).thenReturn(submitMockResponse);
+    underTest.start();
+    underTest.execute();
 
-    assertThat(properties.metadataFilePath()).doesNotExist();
+    assertThat(properties.metadataFilePath()).exists();
+    assertThat(logTester.logs(LoggerLevel.DEBUG)).contains("Report metadata written to " + properties.metadataFilePath());
   }
 
   @Test
-  public void log_and_dump_information_to_custom_path() throws IOException {
-    underTest.logSuccess("TASK-123");
+  public void dump_information_to_custom_path() {
+    underTest.prepareAndDumpMetadata("TASK-123");
 
     assertThat(properties.metadataFilePath()).exists();
     assertThat(logTester.logs(LoggerLevel.DEBUG)).contains("Report metadata written to " + properties.metadataFilePath());
@@ -244,7 +237,7 @@ public class ReportPublisherTest {
   @Test
   public void should_not_delete_report_if_property_is_set() throws IOException {
     when(properties.shouldKeepReport()).thenReturn(true);
-    Path reportDir = temp.getRoot().toPath().resolve("scanner-report");
+    Path reportDir = reportTempFolder.getRoot().toPath().resolve("scanner-report");
     Files.createDirectory(reportDir);
 
     underTest.start();
@@ -254,7 +247,7 @@ public class ReportPublisherTest {
 
   @Test
   public void should_delete_report_by_default() throws IOException {
-    Path reportDir = temp.getRoot().toPath().resolve("scanner-report");
+    Path reportDir = reportTempFolder.getRoot().toPath().resolve("scanner-report");
     Files.createDirectory(reportDir);
 
     underTest.start();
@@ -277,7 +270,7 @@ public class ReportPublisherTest {
     when(response.contentStream()).thenReturn(in);
 
     when(wsClient.call(any(WsRequest.class))).thenReturn(response);
-    underTest.upload(temp.newFile());
+    underTest.upload(reportTempFolder.newFile());
 
     ArgumentCaptor<WsRequest> capture = ArgumentCaptor.forClass(WsRequest.class);
     verify(wsClient).call(capture.capture());
@@ -308,7 +301,7 @@ public class ReportPublisherTest {
     when(response.contentStream()).thenReturn(in);
 
     when(wsClient.call(any(WsRequest.class))).thenReturn(response);
-    underTest.upload(temp.newFile());
+    underTest.upload(reportTempFolder.newFile());
 
     ArgumentCaptor<WsRequest> capture = ArgumentCaptor.forClass(WsRequest.class);
     verify(wsClient).call(capture.capture());
@@ -343,7 +336,7 @@ public class ReportPublisherTest {
     when(response.contentStream()).thenReturn(in);
 
     when(wsClient.call(any(WsRequest.class))).thenReturn(response);
-    underTest.upload(temp.newFile());
+    underTest.upload(reportTempFolder.newFile());
 
     ArgumentCaptor<WsRequest> capture = ArgumentCaptor.forClass(WsRequest.class);
     verify(wsClient).call(capture.capture());