diff options
author | Simon Brandhof <simon.brandhof@sonarsource.com> | 2017-12-05 18:04:06 +0100 |
---|---|---|
committer | Simon Brandhof <simon.brandhof@sonarsource.com> | 2018-01-10 06:48:47 +0100 |
commit | baccb26f1aecd27b7d7fc06a185e7fdeaf03ea83 (patch) | |
tree | f5e3cb8af2a4d355c415a0f8c7b2d459b4d0ccec /tests | |
parent | 01c3e23df232c1006344f4957bf35af92b17a985 (diff) | |
download | sonarqube-baccb26f1aecd27b7d7fc06a185e7fdeaf03ea83.tar.gz sonarqube-baccb26f1aecd27b7d7fc06a185e7fdeaf03ea83.zip |
SONAR-10117 SONAR-1018 Update measures after relevant issue changes and send webhooks
Diffstat (limited to 'tests')
9 files changed, 290 insertions, 16 deletions
diff --git a/tests/projects/measure/LiveMeasuresTest/sonar-project.properties b/tests/projects/measure/LiveMeasuresTest/sonar-project.properties new file mode 100644 index 00000000000..dbe1d71850c --- /dev/null +++ b/tests/projects/measure/LiveMeasuresTest/sonar-project.properties @@ -0,0 +1,5 @@ +sonar.projectKey=LiveMeasuresTestExample +sonar.projectName=LiveMeasuresTestExample +sonar.projectVersion=1.0-SNAPSHOT +sonar.sources=src +sonar.language=xoo diff --git a/tests/projects/measure/LiveMeasuresTest/src/file_with_one_line.xoo b/tests/projects/measure/LiveMeasuresTest/src/file_with_one_line.xoo new file mode 100644 index 00000000000..89b24ecec50 --- /dev/null +++ b/tests/projects/measure/LiveMeasuresTest/src/file_with_one_line.xoo @@ -0,0 +1 @@ +line 1 diff --git a/tests/projects/measure/LiveMeasuresTest/src/file_with_three_lines.xoo b/tests/projects/measure/LiveMeasuresTest/src/file_with_three_lines.xoo new file mode 100644 index 00000000000..a92d664bc20 --- /dev/null +++ b/tests/projects/measure/LiveMeasuresTest/src/file_with_three_lines.xoo @@ -0,0 +1,3 @@ +line 1 +line 2 +line 3 diff --git a/tests/src/test/java/org/sonarqube/tests/issue/IssueMeasureTest.java b/tests/src/test/java/org/sonarqube/tests/issue/IssueMeasureTest.java index 125d4475cb8..57c0aca0d3e 100644 --- a/tests/src/test/java/org/sonarqube/tests/issue/IssueMeasureTest.java +++ b/tests/src/test/java/org/sonarqube/tests/issue/IssueMeasureTest.java @@ -48,15 +48,15 @@ public class IssueMeasureTest extends AbstractIssueTest { ORCHESTRATOR.getServer().associateProjectToQualityProfile(MULTI_MODULE_SAMPLE_PROJECT_KEY, "xoo", "with-many-rules"); runProjectAnalysis(ORCHESTRATOR, "shared/xoo-multi-modules-sample"); - assertThat(search(IssueQuery.create().componentRoots(MULTI_MODULE_SAMPLE_PROJECT_KEY)).paging().total()).isEqualTo(136); + assertThat(search(IssueQuery.create().componentRoots(MULTI_MODULE_SAMPLE_PROJECT_KEY)).paging().total()).isEqualTo(128); Map<String, Double> measures = getMeasuresAsDoubleByMetricKey(ORCHESTRATOR, MULTI_MODULE_SAMPLE_PROJECT_KEY, "violations", "info_violations", "minor_violations", "major_violations", "blocker_violations", "critical_violations"); - assertThat(measures.get("violations")).isEqualTo(136); + assertThat(measures.get("violations")).isEqualTo(128); assertThat(measures.get("info_violations")).isEqualTo(2); assertThat(measures.get("minor_violations")).isEqualTo(61); - assertThat(measures.get("major_violations")).isEqualTo(65); + assertThat(measures.get("major_violations")).isEqualTo(57); assertThat(measures.get("blocker_violations")).isEqualTo(4); assertThat(measures.get("critical_violations")).isEqualTo(4); } diff --git a/tests/src/test/java/org/sonarqube/tests/issue/IssueSearchTest.java b/tests/src/test/java/org/sonarqube/tests/issue/IssueSearchTest.java index b8f96966eb1..0f2d03d7aac 100644 --- a/tests/src/test/java/org/sonarqube/tests/issue/IssueSearchTest.java +++ b/tests/src/test/java/org/sonarqube/tests/issue/IssueSearchTest.java @@ -55,7 +55,7 @@ public class IssueSearchTest extends AbstractIssueTest { private static final String PROJECT_KEY2 = "com.sonarsource.it.samples:multi-modules-sample2"; private static int DEFAULT_PAGINATED_RESULTS = 100; - private static int TOTAL_NB_ISSUES = 272; + private static int TOTAL_NB_ISSUES = 256; @BeforeClass public static void prepareData() { @@ -92,15 +92,15 @@ public class IssueSearchTest extends AbstractIssueTest { @Test public void search_issues_by_component_roots() { assertSearch(r -> r.setComponentRoots("com.sonarsource.it.samples:multi-modules-sample")).hasSize(DEFAULT_PAGINATED_RESULTS); - assertSearch(r -> r.setComponentRoots("com.sonarsource.it.samples:multi-modules-sample:module_a")).hasSize(82); - assertSearch(r -> r.setComponentRoots("com.sonarsource.it.samples:multi-modules-sample:module_a:module_a1")).hasSize(36); + assertSearch(r -> r.setComponentRoots("com.sonarsource.it.samples:multi-modules-sample:module_a")).hasSize(76); + assertSearch(r -> r.setComponentRoots("com.sonarsource.it.samples:multi-modules-sample:module_a:module_a1")).hasSize(35); assertThat(search(IssueQuery.create().componentRoots("unknown")).list()).isEmpty(); } @Test public void search_issues_by_components() { - assertSearch(r -> r.setComponents("com.sonarsource.it.samples:multi-modules-sample:module_a:module_a1:src/main/xoo/com/sonar/it/samples/modules/a1/HelloA1.xoo")).hasSize(34); + assertSearch(r -> r.setComponents("com.sonarsource.it.samples:multi-modules-sample:module_a:module_a1:src/main/xoo/com/sonar/it/samples/modules/a1/HelloA1.xoo")).hasSize(33); assertSearch(r -> r.setComponents("unknown")).isEmpty(); } @@ -261,7 +261,7 @@ public class IssueSearchTest extends AbstractIssueTest { @Test public void search_issues_by_types() throws IOException { assertThat(searchResponse(r -> r.setTypes(singletonList("CODE_SMELL"))).getPaging().getTotal()).isEqualTo(142); - assertThat(searchResponse(r -> r.setTypes(singletonList("BUG"))).getPaging().getTotal()).isEqualTo(122); + assertThat(searchResponse(r -> r.setTypes(singletonList("BUG"))).getPaging().getTotal()).isEqualTo(106); assertThat(searchResponse(r -> r.setTypes(singletonList("VULNERABILITY"))).getPaging().getTotal()).isEqualTo(8); } diff --git a/tests/src/test/java/org/sonarqube/tests/measure/LiveMeasuresTest.java b/tests/src/test/java/org/sonarqube/tests/measure/LiveMeasuresTest.java new file mode 100644 index 00000000000..a47587aa4b3 --- /dev/null +++ b/tests/src/test/java/org/sonarqube/tests/measure/LiveMeasuresTest.java @@ -0,0 +1,198 @@ +/* + * SonarQube + * Copyright (C) 2009-2018 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.sonarqube.tests.measure; + +import com.google.common.collect.HashBasedTable; +import com.google.common.collect.Table; +import com.sonar.orchestrator.Orchestrator; +import com.sonar.orchestrator.build.SonarScanner; +import java.util.List; +import org.junit.ClassRule; +import org.junit.Rule; +import org.junit.Test; +import org.sonarqube.qa.util.Tester; +import org.sonarqube.ws.Issues; +import org.sonarqube.ws.Measures; +import org.sonarqube.ws.Projects.CreateWsResponse.Project; +import org.sonarqube.ws.Qualitygates; +import org.sonarqube.ws.client.issues.DoTransitionRequest; +import org.sonarqube.ws.client.issues.SearchRequest; +import org.sonarqube.ws.client.issues.SetSeverityRequest; +import org.sonarqube.ws.client.issues.SetTypeRequest; +import org.sonarqube.ws.client.measures.ComponentRequest; +import org.sonarqube.ws.client.qualitygates.CreateConditionRequest; +import util.ItUtils; + +import static java.util.Arrays.asList; +import static java.util.Collections.singletonList; +import static org.assertj.core.api.Assertions.assertThat; + +public class LiveMeasuresTest { + + private static final String PROJECT_KEY = "LiveMeasuresTestExample"; + private static final String PROJECT_DIR = "measure/LiveMeasuresTest"; + private static final String FILE_WITH_ONE_LINE_KEY = PROJECT_KEY + ":src/file_with_one_line.xoo"; + private static final String FILE_WITH_THREE_LINES_KEY = PROJECT_KEY + ":src/file_with_three_lines.xoo"; + private static final String SRC_DIR_KEY = PROJECT_KEY + ":src"; + + @ClassRule + public static Orchestrator orchestrator = MeasureSuite.ORCHESTRATOR; + + @Rule + public Tester tester = new Tester(orchestrator); + + @Test + public void refresh_measures_when_touching_ws_from_web_services() { + ItUtils.restoreProfile(orchestrator, getClass().getResource("/measure/LiveMeasuresTest/one-bug-per-line-profile.xml")); + Project project = tester.projects().provision(r -> r.setProject(PROJECT_KEY).setName("LiveMeasuresTestExample")); + orchestrator.getServer().associateProjectToQualityProfile(PROJECT_KEY, "xoo", "one-bug-per-line-profile"); + // quality gate on Security Rating: Warning when greater than A and Error when greater than C + Qualitygates.CreateResponse simple = tester.qGates().generate(); + tester.qGates().service().createCondition(new CreateConditionRequest().setGateId(String.valueOf(simple.getId())) + .setMetric("security_rating").setOp("GT").setWarning("1").setError("3")); + tester.qGates().associateProject(simple, project); + scanSample(); + + expectMeasures("bugs", 1, 3, 4, 4); + expectMeasures("vulnerabilities", 0, 0, 0, 0); + expectMeasures("violations", 1, 3, 4, 4); + // highest severity is MAJOR --> rating is C (3) + expectMeasures("reliability_rating", 3, 3, 3, 3); + // zero vulnerabilities -> rating is A (1) + expectMeasures("security_rating", 1, 1, 1, 1); + assertQualityGate("OK"); + + // mark a bug as FP + Issues.Issue issue = getFirstIssue(FILE_WITH_ONE_LINE_KEY, "BUG"); + markAsFalsePositive(issue); + expectMeasures("bugs", 0, 3, 3, 3); + expectMeasures("vulnerabilities", 0, 0, 0, 0); + expectMeasures("violations", 0, 3, 3, 3); + expectMeasures("reliability_rating", 1, 3, 3, 3); + expectMeasures("security_rating", 1, 1, 1, 1); + + // convert a bug to a vulnerability + issue = getFirstIssue(FILE_WITH_THREE_LINES_KEY, "BUG"); + convertToType(issue, "VULNERABILITY"); + expectMeasures("bugs", 0, 2, 2, 2); + expectMeasures("vulnerabilities", 0, 1, 1, 1); + expectMeasures("violations", 0, 3, 3, 3); + // highest severity of bugs is still MAJOR --> C (3) + expectMeasures("reliability_rating", 1, 3, 3, 3); + // a file has now a MAJOR vulnerability --> C (3) + expectMeasures("security_rating", 1, 3, 3, 3); + assertQualityGate("WARN"); + + // increase severity of a vulnerability to BLOCKER + issue = getFirstIssue(FILE_WITH_THREE_LINES_KEY, "VULNERABILITY"); + changeSeverity(issue, "BLOCKER"); + expectMeasures("bugs", 0, 2, 2, 2); + expectMeasures("vulnerabilities", 0, 1, 1, 1); + expectMeasures("violations", 0, 3, 3, 3); + expectMeasures("reliability_rating", 1, 3, 3, 3); + // highest severity of vulnerabilities is now BLOCKER --> security rating goes E (5) + expectMeasures("security_rating", 1, 5, 5, 5); + assertQualityGate("ERROR"); + + // no changes after new analysis + MeasuresDump dumpBeforeAnalysis = dump(); + scanSample(); + MeasuresDump dumpAfterAnalysis = dump(); + dumpAfterAnalysis.assertEquals(dumpBeforeAnalysis); + } + + private void markAsFalsePositive(Issues.Issue issue) { + tester.wsClient().issues().doTransition(new DoTransitionRequest().setIssue(issue.getKey()).setTransition("falsepositive")); + } + + private void convertToType(Issues.Issue issue, String type) { + tester.wsClient().issues().setType(new SetTypeRequest().setIssue(issue.getKey()).setType(type)); + } + + private void changeSeverity(Issues.Issue issue, String severity) { + tester.wsClient().issues().setSeverity(new SetSeverityRequest().setIssue(issue.getKey()).setSeverity(severity)); + } + + private Issues.Issue getFirstIssue(String componentKey, String type) { + return tester.wsClient().issues().search(new SearchRequest() + .setResolved("false") + .setTypes(singletonList(type)) + .setComponentKeys(singletonList(componentKey))).getIssuesList().get(0); + } + + private void scanSample() { + orchestrator.executeBuildQuietly(SonarScanner.create(ItUtils.projectDir(PROJECT_DIR))); + } + + private void expectMeasures(String metric, double fileWithOneLineExpectedValue, double fileWithThreeLinesExpectedValue, double srcDirExpectedValue, double projectExpectedValue) { + assertThat(Double.parseDouble(loadMeasure(FILE_WITH_ONE_LINE_KEY, metric).getValue())) + .as("Value of measure " + metric) + .isEqualTo(fileWithOneLineExpectedValue); + assertThat(Double.parseDouble(loadMeasure(FILE_WITH_THREE_LINES_KEY, metric).getValue())) + .as("Value of measure " + metric) + .isEqualTo(fileWithThreeLinesExpectedValue); + assertThat(Double.parseDouble(loadMeasure(SRC_DIR_KEY, metric).getValue())) + .as("Value of measure " + metric) + .isEqualTo(srcDirExpectedValue); + assertThat(Double.parseDouble(loadMeasure(PROJECT_KEY, metric).getValue())) + .as("Value of measure " + metric) + .isEqualTo(projectExpectedValue); + } + + private void assertQualityGate(String expectedQualityGate) { + assertThat(loadMeasure(PROJECT_KEY, "alert_status").getValue()).isEqualTo(expectedQualityGate); + } + + private Measures.Measure loadMeasure(String componentKey, String metricKey) { + return tester.wsClient().measures().component( + new ComponentRequest() + .setMetricKeys(singletonList(metricKey)) + .setComponent(componentKey)) + .getComponent().getMeasuresList().get(0); + } + + private MeasuresDump dump() { + MeasuresDump dump = new MeasuresDump(); + + asList(FILE_WITH_ONE_LINE_KEY, FILE_WITH_THREE_LINES_KEY, SRC_DIR_KEY, PROJECT_KEY).forEach(componentKey -> { + List<Measures.Measure> measures = tester.wsClient().measures().component(new ComponentRequest() + .setComponent(componentKey) + // TODO request all metrics + .setMetricKeys(asList("bugs", "vulnerabilities", "reliability_rating", "security_rating", "sqale_rating", "major_violations", "blocker_violations")) + ).getComponent().getMeasuresList(); + measures.forEach(m -> dump.valuesByComponentAndMetric.put(m.getComponent(), m.getMetric(), m.getValue())); + }); + + return dump; + } + + private static class MeasuresDump { + private final Table<String, String, String> valuesByComponentAndMetric = HashBasedTable.create(); + + void assertEquals(MeasuresDump dump) { + assertThat(valuesByComponentAndMetric.size()).isEqualTo(dump.valuesByComponentAndMetric.size()); + for (Table.Cell<String, String, String> cell : valuesByComponentAndMetric.cellSet()) { + assertThat(dump.valuesByComponentAndMetric.get(cell.getRowKey(), cell.getColumnKey())) + .as("Measure " + cell.getColumnKey() + " on component " + cell.getRowKey()) + .isEqualTo(cell.getValue()); + } + } + } +} diff --git a/tests/src/test/java/org/sonarqube/tests/qualityModel/ReliabilityMeasureTest.java b/tests/src/test/java/org/sonarqube/tests/qualityModel/ReliabilityMeasureTest.java index 3c033f0acc6..2997929905c 100644 --- a/tests/src/test/java/org/sonarqube/tests/qualityModel/ReliabilityMeasureTest.java +++ b/tests/src/test/java/org/sonarqube/tests/qualityModel/ReliabilityMeasureTest.java @@ -66,11 +66,11 @@ public class ReliabilityMeasureTest { orchestrator.getServer().associateProjectToQualityProfile(PROJECT, "xoo", "with-many-rules"); orchestrator.executeBuild(SonarScanner.create(projectDir("shared/xoo-multi-modules-sample"))); - assertMeasures(PROJECT, 61, 305, 4); - assertMeasures(MODULE, 37, 185, 4); - assertMeasures(SUB_MODULE, 16, 80, 4); - assertMeasures(DIRECTORY, 16, 80, 4); - assertMeasures(FILE, 16, 80, 4); + assertMeasures(PROJECT, 53, 265, 4); + assertMeasures(MODULE, 31, 155, 4); + assertMeasures(SUB_MODULE, 15, 75, 4); + assertMeasures(DIRECTORY, 15, 75, 4); + assertMeasures(FILE, 15, 75, 4); } @Test diff --git a/tests/src/test/java/org/sonarqube/tests/webhook/WebhooksTest.java b/tests/src/test/java/org/sonarqube/tests/webhook/WebhooksTest.java index fcdcc89a98d..92c6bed436b 100644 --- a/tests/src/test/java/org/sonarqube/tests/webhook/WebhooksTest.java +++ b/tests/src/test/java/org/sonarqube/tests/webhook/WebhooksTest.java @@ -30,18 +30,29 @@ import org.apache.commons.lang3.StringUtils; import org.junit.After; import org.junit.Before; import org.junit.ClassRule; +import org.junit.Rule; import org.junit.Test; +import org.sonarqube.qa.util.Tester; import org.sonarqube.tests.Category3Suite; +import org.sonarqube.ws.Issues.Issue; +import org.sonarqube.ws.Organizations.Organization; +import org.sonarqube.ws.Projects.CreateWsResponse.Project; +import org.sonarqube.ws.Qualitygates; +import org.sonarqube.ws.Qualityprofiles.CreateWsResponse.QualityProfile; import org.sonarqube.ws.Webhooks; import org.sonarqube.ws.client.HttpException; import org.sonarqube.ws.client.WsClient; +import org.sonarqube.ws.client.issues.BulkChangeRequest; +import org.sonarqube.ws.client.issues.SearchRequest; import org.sonarqube.ws.client.projects.DeleteRequest; +import org.sonarqube.ws.client.qualitygates.CreateConditionRequest; import org.sonarqube.ws.client.settings.ResetRequest; import org.sonarqube.ws.client.settings.SetRequest; import org.sonarqube.ws.client.webhooks.DeliveriesRequest; import org.sonarqube.ws.client.webhooks.DeliveryRequest; import util.ItUtils; +import static java.util.Collections.singletonList; import static java.util.Objects.requireNonNull; import static java.util.stream.IntStream.range; import static org.assertj.core.api.Assertions.assertThat; @@ -57,20 +68,22 @@ public class WebhooksTest { @ClassRule public static Orchestrator orchestrator = Category3Suite.ORCHESTRATOR; - @ClassRule public static ExternalServer externalServer = new ExternalServer(); + @Rule + public Tester tester = new Tester(orchestrator); + private WsClient adminWs = ItUtils.newAdminWsClient(orchestrator); @Before - public void setUp() throws Exception { + public void setUp() { externalServer.clear(); } @Before @After - public void reset() throws Exception { + public void reset() { disableGlobalWebhooks(); try { // delete project and related properties/webhook deliveries @@ -215,6 +228,48 @@ public class WebhooksTest { assertThat(getPersistedDeliveries()).isEmpty(); } + @Test + public void send_webhook_on_issue_change() throws InterruptedException { + Organization defaultOrganization = tester.organizations().getDefaultOrganization(); + Project wsProject = tester.projects().provision(r -> r.setProject(PROJECT_KEY).setName(PROJECT_NAME)); + enableProjectWebhooks(PROJECT_KEY, new Webhook("Burgr", externalServer.urlFor("/burgr"))); + // quality profile with one issue per line + QualityProfile qualityProfile = tester.qProfiles().createXooProfile(defaultOrganization); + tester.qProfiles().activateRule(qualityProfile, "xoo:OneIssuePerLine"); + tester.qProfiles().assignQProfileToProject(qualityProfile, wsProject); + // quality gate definition + Qualitygates.CreateResponse qGate = tester.qGates().generate(); + tester.qGates().service().createCondition(new CreateConditionRequest().setGateId(String.valueOf(qGate.getId())) + .setMetric("reliability_rating").setOp("GT").setError("1")); + tester.qGates().associateProject(qGate, wsProject); + // analyze project and clear first webhook + analyseProject(); + waitUntilAllWebHooksCalled(1); + externalServer.clear(); + + // change an issue to blocker bug + Issue firstIssue = tester.wsClient().issues().search(new SearchRequest()).getIssues(0); + tester.wsClient().issues().bulkChange(new BulkChangeRequest().setIssues(singletonList(firstIssue.getKey())) + .setSetSeverity(singletonList("BLOCKER")) + .setSetType(singletonList("BUG"))); + waitUntilAllWebHooksCalled(1); + + PayloadRequest request = externalServer.getPayloadRequests().get(0); + assertThat(request.getHttpHeaders().get("X-SonarQube-Project")).isEqualTo(PROJECT_KEY); + // verify content of payload + Map<String, Object> payload = jsonToMap(request.getJson()); + assertThat(payload.get("status")).isEqualTo("SUCCESS"); + assertThat(payload.get("analysedAt")).isNotNull(); + Map<String, String> project = (Map<String, String>) payload.get("project"); + assertThat(project.get("key")).isEqualTo(PROJECT_KEY); + assertThat(project.get("name")).isEqualTo(PROJECT_NAME); + assertThat(project.get("url")).isEqualTo(orchestrator.getServer().getUrl() + "/dashboard?id=" + PROJECT_KEY); + Map<String, Object> gate = (Map<String, Object>) payload.get("qualityGate"); + assertThat(gate.get("name")).isEqualTo(qGate.getName()); + assertThat(gate.get("status")).isEqualTo("ERROR"); + assertThat(gate.get("conditions")).isNotNull(); + } + private void analyseProject() { runProjectAnalysis(orchestrator, "shared/xoo-sample", "sonar.projectKey", PROJECT_KEY, diff --git a/tests/src/test/resources/measure/LiveMeasuresTest/one-bug-per-line-profile.xml b/tests/src/test/resources/measure/LiveMeasuresTest/one-bug-per-line-profile.xml new file mode 100644 index 00000000000..162413cacb9 --- /dev/null +++ b/tests/src/test/resources/measure/LiveMeasuresTest/one-bug-per-line-profile.xml @@ -0,0 +1,12 @@ +<?xml version="1.0"?><!-- Generated by Sonar --> +<profile> + <name>one-bug-per-line-profile</name> + <language>xoo</language> + <rules> + <rule> + <repositoryKey>xoo</repositoryKey> + <key>OneBugIssuePerLine</key> + <priority>MAJOR</priority> + </rule> + </rules> +</profile> |