]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-12629 unit and integration tests + minor fixes
authorJacek <jacek.poreda@sonarsource.com>
Thu, 31 Oct 2019 12:11:32 +0000 (13:11 +0100)
committerSonarTech <sonartech@sonarsource.com>
Fri, 8 Nov 2019 19:21:13 +0000 (20:21 +0100)
sonar-scanner-engine/src/main/java/org/sonar/scanner/qualitygate/QualityGateCheck.java
sonar-scanner-engine/src/main/java/org/sonar/scanner/report/CeTaskReportDataHolder.java
sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/ProjectScanContainer.java
sonar-scanner-engine/src/test/java/org/sonar/scanner/qualitygate/QualityGateCheckTest.java [new file with mode: 0644]

index 871ba195b746ac9996f84ecc53d7229d03dc5e13..9b320f86f8a67f1b59b54bdab6de3e8d0dc78a18 100644 (file)
@@ -74,15 +74,15 @@ 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");
       return;
     }
 
+    if (analysisMode.isMediumTest()) {
+      throw new IllegalStateException("Quality Gate check not available in medium test mode");
+    }
+
     String taskId = reportMetadataHolder.getCeTaskId();
 
     Ce.Task task = waitForCeTaskToFinish(taskId);
@@ -95,8 +95,6 @@ public class QualityGateCheck implements Startable {
 
     if (Status.OK.equals(qualityGateStatus)) {
       LOG.info("Quality Gate - OK");
-    } else if (Status.NONE.equals(qualityGateStatus)) {
-      LOG.info("No Quality Gate is associated with the analysis - skipping");
     } else {
       throw MessageException.of("Quality Gate - FAILED");
     }
@@ -124,17 +122,17 @@ public class QualityGateCheck implements Startable {
         throw MessageException.of(String.format("Failed to get CE Task status - %s", DefaultScannerWsClient.createErrorMessage(e)));
       } catch (InterruptedException e) {
         Thread.currentThread().interrupt();
-        throw MessageException.of("Quality Gate Check has been interrupted", e);
+        throw MessageException.of("Quality Gate check has been interrupted", e);
       }
     }
-    throw MessageException.of("Quality Gate Check timeout exceeded");
+    throw MessageException.of("Quality Gate check timeout exceeded");
   }
 
   private static Ce.Task parseCeTaskResponse(WsResponse response) {
     try (InputStream protobuf = response.contentStream()) {
       return Ce.TaskResponse.parser().parseFrom(protobuf).getTask();
     } catch (Exception e) {
-      throw new RuntimeException(e);
+      throw new IllegalStateException("Failed to parse response from " + response.requestUrl(), e);
     }
   }
 
@@ -155,7 +153,7 @@ public class QualityGateCheck implements Startable {
     try (InputStream protobuf = response.contentStream()) {
       return Qualitygates.ProjectStatusResponse.parser().parseFrom(protobuf).getProjectStatus();
     } catch (Exception e) {
-      throw new RuntimeException(e);
+      throw new IllegalStateException("Failed to parse response from " + response.requestUrl(), e);
     }
   }
 }
index a64bf79a855e69279e586e2ed5451c7c047e18ce..2d657c4105708a997f19cb6b8a311cbc81b6f0db 100644 (file)
@@ -23,9 +23,9 @@ import static java.util.Objects.requireNonNull;
 
 public class CeTaskReportDataHolder {
   private boolean initialized = false;
-  private String ceTaskId;
-  private String ceTaskUrl;
-  private String dashboardUrl;
+  private String ceTaskId = null;
+  private String ceTaskUrl = null;
+  private String dashboardUrl= null;
 
   public void init(String ceTaskId, String ceTaskUrl, String dashboardUrl) {
     requireNonNull(ceTaskId, "CE task id must not be null");
index 45b63ec6cc101047daa4cac4d8c55d9f54262c6f..6092d065016f56bfafb53487114871c178e3430d 100644 (file)
@@ -81,6 +81,7 @@ import org.sonar.scanner.qualitygate.QualityGateCheck;
 import org.sonar.scanner.report.ActiveRulesPublisher;
 import org.sonar.scanner.report.AnalysisContextReportPublisher;
 import org.sonar.scanner.report.AnalysisWarningsPublisher;
+import org.sonar.scanner.report.CeTaskReportDataHolder;
 import org.sonar.scanner.report.ChangedLinesPublisher;
 import org.sonar.scanner.report.ComponentsPublisher;
 import org.sonar.scanner.report.ContextPropertiesPublisher;
@@ -251,6 +252,8 @@ public class ProjectScanContainer extends ComponentContainer {
       ChangedLinesPublisher.class,
       AnalysisResultReporter.class,
 
+      CeTaskReportDataHolder.class,
+
       //QualityGate check
       QualityGateCheck.class,
 
diff --git a/sonar-scanner-engine/src/test/java/org/sonar/scanner/qualitygate/QualityGateCheckTest.java b/sonar-scanner-engine/src/test/java/org/sonar/scanner/qualitygate/QualityGateCheckTest.java
new file mode 100644 (file)
index 0000000..49165a4
--- /dev/null
@@ -0,0 +1,358 @@
+/*
+ * 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.qualitygate;
+
+import com.tngtech.java.junit.dataprovider.DataProvider;
+import com.tngtech.java.junit.dataprovider.DataProviderRunner;
+import com.tngtech.java.junit.dataprovider.UseDataProvider;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentMatcher;
+import org.mockito.Mockito;
+import org.sonar.api.utils.MessageException;
+import org.sonar.api.utils.log.LogTester;
+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;
+import org.sonarqube.ws.Qualitygates;
+import org.sonarqube.ws.Qualitygates.ProjectStatusResponse.Status;
+import org.sonarqube.ws.client.HttpException;
+import org.sonarqube.ws.client.MockWsResponse;
+import org.sonarqube.ws.client.WsRequest;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.ArgumentMatchers.argThat;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.doThrow;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+@RunWith(DataProviderRunner.class)
+public class QualityGateCheckTest {
+  private DefaultScannerWsClient wsClient = mock(DefaultScannerWsClient.class, Mockito.RETURNS_DEEP_STUBS);
+  private GlobalAnalysisMode analysisMode = mock(GlobalAnalysisMode.class);
+  private CeTaskReportDataHolder reportMetadataHolder = mock(CeTaskReportDataHolder.class);
+  private ScanProperties properties = mock(ScanProperties.class);
+
+  @Rule
+  public LogTester logTester = new LogTester();
+
+  @Rule
+  public ExpectedException exception = ExpectedException.none();
+
+  QualityGateCheck underTest = new QualityGateCheck(wsClient, analysisMode, reportMetadataHolder, properties);
+
+  @Test
+  public void should_pass_if_quality_gate_ok() {
+    when(properties.shouldWaitForQualityGate()).thenReturn(true);
+    when(properties.qualityGateWaitTimeout()).thenReturn(5);
+
+    when(reportMetadataHolder.getCeTaskId()).thenReturn("task-1234");
+
+    MockWsResponse ceTaskWsResponse = getCeTaskWsResponse(TaskStatus.SUCCESS);
+    doReturn(ceTaskWsResponse).when(wsClient).call(newGetCeTaskRequest());
+
+    MockWsResponse qualityGateResponse = getQualityGateWsResponse(Status.OK);
+    doReturn(qualityGateResponse).when(wsClient).call(newGetQualityGateRequest());
+
+    underTest.start();
+
+    underTest.await();
+
+    underTest.stop();
+
+    assertThat(logTester.logs())
+      .containsOnly("Quality Gate - OK");
+  }
+
+  @Test
+  public void should_wait_and_then_pass_if_quality_gate_ok() {
+    when(properties.shouldWaitForQualityGate()).thenReturn(true);
+    when(properties.qualityGateWaitTimeout()).thenReturn(10);
+
+    when(reportMetadataHolder.getCeTaskId()).thenReturn("task-1234");
+
+    MockWsResponse pendingTask = getCeTaskWsResponse(TaskStatus.PENDING);
+    MockWsResponse successTask = getCeTaskWsResponse(TaskStatus.SUCCESS);
+    doReturn(pendingTask, successTask).when(wsClient).call(newGetCeTaskRequest());
+
+    MockWsResponse qualityGateResponse = getQualityGateWsResponse(Status.OK);
+    doReturn(qualityGateResponse).when(wsClient).call(newGetQualityGateRequest());
+
+    underTest.start();
+
+    underTest.await();
+
+    assertThat(logTester.logs())
+      .contains("Quality Gate - OK");
+  }
+
+  @Test
+  public void should_fail_if_quality_gate_none() {
+    when(properties.shouldWaitForQualityGate()).thenReturn(true);
+    when(properties.qualityGateWaitTimeout()).thenReturn(5);
+
+    when(reportMetadataHolder.getCeTaskId()).thenReturn("task-1234");
+
+    MockWsResponse ceTaskWsResponse = getCeTaskWsResponse(TaskStatus.SUCCESS);
+    doReturn(ceTaskWsResponse).when(wsClient).call(newGetCeTaskRequest());
+
+    MockWsResponse qualityGateResponse = getQualityGateWsResponse(Status.ERROR);
+    doReturn(qualityGateResponse).when(wsClient).call(newGetQualityGateRequest());
+
+    underTest.start();
+
+    exception.expect(MessageException.class);
+    exception.expectMessage("Quality Gate - FAILED");
+    underTest.await();
+  }
+
+  @Test
+  public void should_fail_if_quality_gate_error() {
+    when(properties.shouldWaitForQualityGate()).thenReturn(true);
+    when(properties.qualityGateWaitTimeout()).thenReturn(5);
+
+    when(reportMetadataHolder.getCeTaskId()).thenReturn("task-1234");
+
+    MockWsResponse ceTaskWsResponse = getCeTaskWsResponse(TaskStatus.SUCCESS);
+    doReturn(ceTaskWsResponse).when(wsClient).call(newGetCeTaskRequest());
+
+    MockWsResponse qualityGateResponse = getQualityGateWsResponse(Status.ERROR);
+    doReturn(qualityGateResponse).when(wsClient).call(newGetQualityGateRequest());
+
+    underTest.start();
+
+    exception.expect(MessageException.class);
+    exception.expectMessage("Quality Gate - FAILED");
+    underTest.await();
+  }
+
+  @Test
+  public void should_wait_and_then_fail_if_quality_gate_error() {
+    when(properties.shouldWaitForQualityGate()).thenReturn(true);
+    when(properties.qualityGateWaitTimeout()).thenReturn(10);
+
+    when(reportMetadataHolder.getCeTaskId()).thenReturn("task-1234");
+
+    MockWsResponse pendingTask = getCeTaskWsResponse(TaskStatus.PENDING);
+    MockWsResponse successTask = getCeTaskWsResponse(TaskStatus.SUCCESS);
+    doReturn(pendingTask, successTask).when(wsClient).call(newGetCeTaskRequest());
+
+    MockWsResponse qualityGateResponse = getQualityGateWsResponse(Status.ERROR);
+    doReturn(qualityGateResponse).when(wsClient).call(newGetQualityGateRequest());
+
+    underTest.start();
+
+    exception.expect(MessageException.class);
+    exception.expectMessage("Quality Gate - FAILED");
+
+    underTest.await();
+  }
+
+  @Test
+  public void should_fail_if_quality_gate_timeout_exceeded() {
+    when(properties.shouldWaitForQualityGate()).thenReturn(true);
+    when(properties.qualityGateWaitTimeout()).thenReturn(1);
+
+    when(reportMetadataHolder.getCeTaskId()).thenReturn("task-1234");
+
+    MockWsResponse ceTaskWsResponse = getCeTaskWsResponse(TaskStatus.PENDING);
+    doReturn(ceTaskWsResponse).when(wsClient).call(newGetCeTaskRequest());
+
+    underTest.start();
+
+    exception.expect(MessageException.class);
+    exception.expectMessage("Quality Gate check timeout exceeded");
+    underTest.await();
+  }
+
+  @Test
+  public void should_fail_if_cant_call_ws_for_quality_gate() {
+    when(properties.shouldWaitForQualityGate()).thenReturn(true);
+    when(properties.qualityGateWaitTimeout()).thenReturn(5);
+
+    when(reportMetadataHolder.getCeTaskId()).thenReturn("task-1234");
+
+    MockWsResponse ceTaskWsResponse = getCeTaskWsResponse(TaskStatus.SUCCESS);
+    doReturn(ceTaskWsResponse).when(wsClient).call(newGetCeTaskRequest());
+
+    doThrow(new HttpException("quality-gate-url", 400, "content")).when(wsClient).call(newGetQualityGateRequest());
+
+    underTest.start();
+
+    exception.expect(MessageException.class);
+    exception.expectMessage("Failed to get Quality Gate status - HTTP code 400: content");
+    underTest.await();
+  }
+
+  @Test
+  public void should_fail_if_invalid_response_from_quality_gate_ws() {
+    when(properties.shouldWaitForQualityGate()).thenReturn(true);
+    when(properties.qualityGateWaitTimeout()).thenReturn(5);
+
+    when(reportMetadataHolder.getCeTaskId()).thenReturn("task-1234");
+
+    MockWsResponse ceTaskWsResponse = getCeTaskWsResponse(TaskStatus.SUCCESS);
+    doReturn(ceTaskWsResponse).when(wsClient).call(newGetCeTaskRequest());
+
+    MockWsResponse qualityGateResponse = new MockWsResponse();
+    qualityGateResponse.setRequestUrl("quality-gate-url");
+    qualityGateResponse.setContent("blabla");
+    doReturn(qualityGateResponse).when(wsClient).call(newGetQualityGateRequest());
+
+    underTest.start();
+
+    exception.expect(IllegalStateException.class);
+    exception.expectMessage("Failed to parse response from quality-gate-url");
+    underTest.await();
+  }
+
+  @Test
+  public void should_fail_if_cant_call_ws_for_task() {
+    when(properties.shouldWaitForQualityGate()).thenReturn(true);
+    when(properties.qualityGateWaitTimeout()).thenReturn(5);
+
+    when(reportMetadataHolder.getCeTaskId()).thenReturn("task-1234");
+
+    when(wsClient.call(newGetCeTaskRequest())).thenThrow(new HttpException("task-url", 400, "content"));
+
+    underTest.start();
+
+    exception.expect(MessageException.class);
+    exception.expectMessage("Failed to get CE Task status - HTTP code 400: content");
+    underTest.await();
+  }
+
+  @Test
+  public void should_fail_if_invalid_response_from_ws_task() {
+    when(properties.shouldWaitForQualityGate()).thenReturn(true);
+    when(properties.qualityGateWaitTimeout()).thenReturn(5);
+
+    when(reportMetadataHolder.getCeTaskId()).thenReturn("task-1234");
+
+    MockWsResponse getCeTaskRequest = new MockWsResponse();
+    getCeTaskRequest.setRequestUrl("ce-task-url");
+    getCeTaskRequest.setContent("blabla");
+
+    when(wsClient.call(newGetCeTaskRequest())).thenReturn(getCeTaskRequest);
+
+    underTest.start();
+
+    exception.expect(IllegalStateException.class);
+    exception.expectMessage("Failed to parse response from ce-task-url");
+    underTest.await();
+  }
+
+  @Test
+  @UseDataProvider("ceTaskNotSucceededStatuses")
+  public void should_fail_if_task_not_succeeded(TaskStatus taskStatus) {
+    when(properties.shouldWaitForQualityGate()).thenReturn(true);
+    when(properties.qualityGateWaitTimeout()).thenReturn(5);
+
+    when(reportMetadataHolder.getCeTaskId()).thenReturn("task-1234");
+
+    MockWsResponse ceTaskWsResponse = getCeTaskWsResponse(taskStatus);
+    when(wsClient.call(newGetCeTaskRequest())).thenReturn(ceTaskWsResponse);
+
+    underTest.start();
+
+    exception.expect(MessageException.class);
+    exception.expectMessage("CE Task finished abnormally with status: " + taskStatus.name());
+    underTest.await();
+  }
+
+  private WsRequest newGetCeTaskRequest() {
+    return argThat(new WsRequestPathMatcher("api/ce/task"));
+  }
+
+  private MockWsResponse getCeTaskWsResponse(TaskStatus status) {
+    MockWsResponse submitMockResponse = new MockWsResponse();
+    submitMockResponse.setContent(Ce.TaskResponse.newBuilder()
+      .setTask(Ce.Task.newBuilder().setStatus(status))
+      .build()
+      .toByteArray());
+    return submitMockResponse;
+  }
+
+  @Test
+  public void should_skip_wait_if_disabled() {
+    when(properties.shouldWaitForQualityGate()).thenReturn(false);
+
+    underTest.start();
+
+    underTest.await();
+
+    assertThat(logTester.logs())
+      .contains("Quality Gate check disabled - skipping");
+  }
+
+  @Test
+  public void should_fail_if_enabled_with_medium_test() {
+    when(properties.shouldWaitForQualityGate()).thenReturn(true);
+    when(analysisMode.isMediumTest()).thenReturn(true);
+
+    underTest.start();
+
+    exception.expect(IllegalStateException.class);
+
+    underTest.await();
+  }
+
+  private WsRequest newGetQualityGateRequest() {
+    return argThat(new WsRequestPathMatcher("api/qualitygates/project_status"));
+  }
+
+  private MockWsResponse getQualityGateWsResponse(Status status) {
+    MockWsResponse qualityGateWsResponse = new MockWsResponse();
+    qualityGateWsResponse.setContent(Qualitygates.ProjectStatusResponse.newBuilder()
+      .setProjectStatus(Qualitygates.ProjectStatusResponse.ProjectStatus.newBuilder()
+        .setStatus(status)
+        .build())
+      .build()
+      .toByteArray());
+    return qualityGateWsResponse;
+  }
+
+  @DataProvider
+  public static Object[][] ceTaskNotSucceededStatuses() {
+    return new Object[][] {
+      {TaskStatus.CANCELED},
+      {TaskStatus.FAILED},
+    };
+  }
+
+  private static class WsRequestPathMatcher implements ArgumentMatcher<WsRequest> {
+    String path;
+
+    WsRequestPathMatcher(String path) {
+      this.path = path;
+    }
+
+    @Override
+    public boolean matches(WsRequest right) {
+      return path.equals(right.getPath());
+    }
+  }
+}