aboutsummaryrefslogtreecommitdiffstats
path: root/sonar-scanner-engine
diff options
context:
space:
mode:
authorJacek <jacek.poreda@sonarsource.com>2019-10-31 13:11:32 +0100
committerSonarTech <sonartech@sonarsource.com>2019-11-08 20:21:13 +0100
commit10e04a8aafbabd665f1f668395b97fd43555c757 (patch)
tree5c3f29c5029f1d0827d3cfc0480c35f3c3ec1abc /sonar-scanner-engine
parent27d2f9f67e536f4186d3b763aa8c88e147a31eb0 (diff)
downloadsonarqube-10e04a8aafbabd665f1f668395b97fd43555c757.tar.gz
sonarqube-10e04a8aafbabd665f1f668395b97fd43555c757.zip
SONAR-12629 unit and integration tests + minor fixes
Diffstat (limited to 'sonar-scanner-engine')
-rw-r--r--sonar-scanner-engine/src/main/java/org/sonar/scanner/qualitygate/QualityGateCheck.java18
-rw-r--r--sonar-scanner-engine/src/main/java/org/sonar/scanner/report/CeTaskReportDataHolder.java6
-rw-r--r--sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/ProjectScanContainer.java3
-rw-r--r--sonar-scanner-engine/src/test/java/org/sonar/scanner/qualitygate/QualityGateCheckTest.java358
4 files changed, 372 insertions, 13 deletions
diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/qualitygate/QualityGateCheck.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/qualitygate/QualityGateCheck.java
index 871ba195b74..9b320f86f8a 100644
--- a/sonar-scanner-engine/src/main/java/org/sonar/scanner/qualitygate/QualityGateCheck.java
+++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/qualitygate/QualityGateCheck.java
@@ -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);
}
}
}
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
index a64bf79a855..2d657c41057 100644
--- 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
@@ -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");
diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/ProjectScanContainer.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/ProjectScanContainer.java
index 45b63ec6cc1..6092d065016 100644
--- a/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/ProjectScanContainer.java
+++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/ProjectScanContainer.java
@@ -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
index 00000000000..49165a44ea3
--- /dev/null
+++ b/sonar-scanner-engine/src/test/java/org/sonar/scanner/qualitygate/QualityGateCheckTest.java
@@ -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());
+ }
+ }
+}