/* * SonarQube * Copyright (C) 2009-2017 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.db.measure; import com.google.common.collect.Maps; import java.util.Map; import javax.annotation.Nullable; import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; import org.sonar.api.measures.Metric; import org.sonar.api.utils.System2; import org.sonar.db.DbClient; import org.sonar.db.DbSession; import org.sonar.db.DbTester; import org.sonar.db.component.ComponentDto; import org.sonar.db.component.ComponentTesting; import org.sonar.db.component.SnapshotDto; import org.sonar.db.measure.ProjectMeasuresIndexerIterator.ProjectMeasures; import org.sonar.db.metric.MetricDto; import org.sonar.db.metric.MetricTesting; import org.sonar.db.organization.OrganizationDto; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.entry; import static org.sonar.api.measures.Metric.Level.ERROR; import static org.sonar.api.measures.Metric.Level.OK; import static org.sonar.api.measures.Metric.Level.WARN; import static org.sonar.api.measures.Metric.ValueType.DATA; import static org.sonar.api.measures.Metric.ValueType.DISTRIB; import static org.sonar.api.measures.Metric.ValueType.INT; import static org.sonar.api.measures.Metric.ValueType.LEVEL; import static org.sonar.api.measures.Metric.ValueType.STRING; import static org.sonar.db.component.ComponentTesting.newPrivateProjectDto; import static org.sonar.db.component.ComponentTesting.newView; import static org.sonar.db.component.SnapshotTesting.newAnalysis; public class ProjectMeasuresIndexerIteratorTest { @Rule public ExpectedException expectedException = ExpectedException.none(); @Rule public DbTester dbTester = DbTester.create(System2.INSTANCE); private DbClient dbClient = dbTester.getDbClient(); private DbSession dbSession = dbTester.getSession(); @Test public void return_project_measure() { MetricDto metric1 = insertIntMetric("ncloc"); MetricDto metric2 = insertIntMetric("coverage"); ComponentDto project = ComponentTesting.newPrivateProjectDto(dbTester.getDefaultOrganization()).setKey("Project-Key").setName("Project Name").setTagsString("platform,java"); SnapshotDto analysis = dbTester.components().insertProjectAndSnapshot(project); insertMeasure(project, analysis, metric1, 10d); insertMeasure(project, analysis, metric2, 20d); Map<String, ProjectMeasures> docsById = createResultSetAndReturnDocsById(); assertThat(docsById).hasSize(1); ProjectMeasures doc = docsById.get(project.uuid()); assertThat(doc).isNotNull(); assertThat(doc.getProject().getUuid()).isEqualTo(project.uuid()); assertThat(doc.getProject().getKey()).isEqualTo("Project-Key"); assertThat(doc.getProject().getName()).isEqualTo("Project Name"); assertThat(doc.getProject().getTags()).containsExactly("platform", "java"); assertThat(doc.getProject().getAnalysisDate()).isNotNull().isEqualTo(analysis.getCreatedAt()); assertThat(doc.getMeasures().getNumericMeasures()).containsOnly(entry("ncloc", 10d), entry("coverage", 20d)); } @Test public void return_project_measure_having_leak() throws Exception { MetricDto metric = insertIntMetric("new_lines"); ComponentDto project = ComponentTesting.newPrivateProjectDto(dbTester.getDefaultOrganization()); SnapshotDto analysis = dbTester.components().insertProjectAndSnapshot(project); insertMeasureOnLeak(project, analysis, metric, 10d); Map<String, ProjectMeasures> docsById = createResultSetAndReturnDocsById(); assertThat(docsById.get(project.uuid()).getMeasures().getNumericMeasures()).containsOnly(entry("new_lines", 10d)); } @Test public void return_quality_gate_status_measure() throws Exception { MetricDto metric = insertMetric("alert_status", LEVEL); insertProjectAndMeasure("project1", metric, WARN.name()); insertProjectAndMeasure("project2", metric, OK.name()); insertProjectAndMeasure("project3", metric, ERROR.name()); Map<String, ProjectMeasures> docsById = createResultSetAndReturnDocsById(); assertThat(docsById.get("project1").getMeasures().getQualityGateStatus()).isEqualTo("WARN"); assertThat(docsById.get("project2").getMeasures().getQualityGateStatus()).isEqualTo("OK"); assertThat(docsById.get("project3").getMeasures().getQualityGateStatus()).isEqualTo("ERROR"); } @Test public void does_not_fail_when_quality_gate_has_no_value() throws Exception { MetricDto metric = insertMetric("alert_status", LEVEL); insertProjectAndMeasure("project", metric, null); Map<String, ProjectMeasures> docsById = createResultSetAndReturnDocsById(); assertThat(docsById.get("project").getMeasures().getNumericMeasures()).isEmpty(); } @Test public void return_language_distribution_measure() throws Exception { MetricDto metric = insertMetric("ncloc_language_distribution", DATA); ComponentDto project = ComponentTesting.newPrivateProjectDto(dbTester.getDefaultOrganization()); SnapshotDto analysis = dbTester.components().insertProjectAndSnapshot(project); insertMeasure(project, analysis, metric, "<null>=2;java=6;xoo=18"); Map<String, ProjectMeasures> docsById = createResultSetAndReturnDocsById(); assertThat(docsById.get(project.uuid()).getMeasures().getLanguages()).containsOnly("<null>", "java", "xoo"); } @Test public void does_not_return_none_numeric_metrics() throws Exception { MetricDto dataMetric = insertMetric("data", DATA); MetricDto distribMetric = insertMetric("distrib", DISTRIB); MetricDto stringMetric = insertMetric("string", STRING); ComponentDto project = ComponentTesting.newPrivateProjectDto(dbTester.getDefaultOrganization()); SnapshotDto analysis = dbTester.components().insertProjectAndSnapshot(project); insertMeasure(project, analysis, dataMetric, "dat"); insertMeasure(project, analysis, distribMetric, "dis"); insertMeasure(project, analysis, stringMetric, "str"); Map<String, ProjectMeasures> docsById = createResultSetAndReturnDocsById(); assertThat(docsById.get(project.uuid()).getMeasures().getNumericMeasures()).isEmpty(); } @Test public void does_not_return_disabled_metrics() throws Exception { MetricDto disabledMetric = insertMetric("disabled", false, false, INT); ComponentDto project = ComponentTesting.newPrivateProjectDto(dbTester.getDefaultOrganization()); SnapshotDto analysis = dbTester.components().insertProjectAndSnapshot(project); insertMeasure(project, analysis, disabledMetric, 10d); Map<String, ProjectMeasures> docsById = createResultSetAndReturnDocsById(); assertThat(docsById.get(project.uuid()).getMeasures().getNumericMeasures()).isEmpty(); } @Test public void ignore_measure_that_does_not_have_value() throws Exception { MetricDto metric1 = insertIntMetric("lines"); MetricDto metric2 = insertIntMetric("ncloc"); MetricDto leakMetric = insertIntMetric("new_lines"); ComponentDto project = ComponentTesting.newPrivateProjectDto(dbTester.getDefaultOrganization()); SnapshotDto analysis = dbTester.components().insertProjectAndSnapshot(project); MeasureDto withValue = insertMeasure(project, analysis, metric1, 10d); MeasureDto withLeakValue = insertMeasure(project, analysis, leakMetric, null, 20d); MeasureDto withoutValue = insertMeasure(project, analysis, metric2, null, null); Map<String, Double> numericMeasures = createResultSetAndReturnDocsById().get(project.uuid()).getMeasures().getNumericMeasures(); assertThat(numericMeasures).containsOnly(entry("lines", 10d), entry("new_lines", 20d)); } @Test public void ignore_numeric_measure_that_has_text_value_but_not_numeric_value() throws Exception { MetricDto metric1 = insertIntMetric("lines"); MetricDto metric2 = insertIntMetric("ncloc"); ComponentDto project = ComponentTesting.newPrivateProjectDto(dbTester.getDefaultOrganization()); SnapshotDto analysis = dbTester.components().insertProjectAndSnapshot(project); MeasureDto withNumericValue = insertMeasure(project, analysis, metric1, 10d); MeasureDto withTextValue = insertMeasure(project, analysis, metric2, "foo"); Map<String, Double> numericMeasures = createResultSetAndReturnDocsById().get(project.uuid()).getMeasures().getNumericMeasures(); assertThat(numericMeasures).containsOnly(entry("lines", 10d)); } @Test public void return_many_project_measures() { dbTester.components().insertProjectAndSnapshot(ComponentTesting.newPrivateProjectDto(dbTester.getDefaultOrganization())); dbTester.components().insertProjectAndSnapshot(ComponentTesting.newPrivateProjectDto(dbTester.getDefaultOrganization())); dbTester.components().insertProjectAndSnapshot(ComponentTesting.newPrivateProjectDto(dbTester.getDefaultOrganization())); assertThat(createResultSetAndReturnDocsById()).hasSize(3); } @Test public void return_project_without_analysis() throws Exception { ComponentDto project = dbTester.components().insertComponent(ComponentTesting.newPrivateProjectDto(dbTester.organizations().insert())); dbClient.snapshotDao().insert(dbSession, newAnalysis(project).setLast(false)); dbSession.commit(); Map<String, ProjectMeasures> docsById = createResultSetAndReturnDocsById(); assertThat(docsById).hasSize(1); ProjectMeasures doc = docsById.get(project.uuid()); assertThat(doc.getProject().getAnalysisDate()).isNull(); } @Test public void does_not_return_non_active_projects() throws Exception { // Disabled project dbTester.components().insertProjectAndSnapshot(ComponentTesting.newPrivateProjectDto(dbTester.getDefaultOrganization()).setEnabled(false)); // Disabled project with analysis ComponentDto project = dbTester.components().insertComponent(ComponentTesting.newPrivateProjectDto(dbTester.getDefaultOrganization()).setEnabled(false)); dbClient.snapshotDao().insert(dbSession, newAnalysis(project)); // A view dbTester.components().insertProjectAndSnapshot(newView(dbTester.getDefaultOrganization())); dbSession.commit(); assertResultSetIsEmpty(); } @Test public void return_only_docs_from_given_project() throws Exception { OrganizationDto organizationDto = dbTester.organizations().insert(); ComponentDto project = ComponentTesting.newPrivateProjectDto(organizationDto); SnapshotDto analysis = dbTester.components().insertProjectAndSnapshot(project); dbTester.components().insertProjectAndSnapshot(ComponentTesting.newPrivateProjectDto(organizationDto)); dbTester.components().insertProjectAndSnapshot(ComponentTesting.newPrivateProjectDto(organizationDto)); Map<String, ProjectMeasures> docsById = createResultSetAndReturnDocsById(project.uuid()); assertThat(docsById).hasSize(1); ProjectMeasures doc = docsById.get(project.uuid()); assertThat(doc).isNotNull(); assertThat(doc.getProject().getUuid()).isEqualTo(project.uuid()); assertThat(doc.getProject().getKey()).isNotNull().isEqualTo(project.getKey()); assertThat(doc.getProject().getName()).isNotNull().isEqualTo(project.name()); assertThat(doc.getProject().getAnalysisDate()).isNotNull().isEqualTo(analysis.getCreatedAt()); } @Test public void return_nothing_on_unknown_project() throws Exception { dbTester.components().insertProjectAndSnapshot(ComponentTesting.newPrivateProjectDto(dbTester.getDefaultOrganization())); Map<String, ProjectMeasures> docsById = createResultSetAndReturnDocsById("UNKNOWN"); assertThat(docsById).isEmpty(); } private Map<String, ProjectMeasures> createResultSetAndReturnDocsById() { return createResultSetAndReturnDocsById(null); } private Map<String, ProjectMeasures> createResultSetAndReturnDocsById(@Nullable String projectUuid) { ProjectMeasuresIndexerIterator it = ProjectMeasuresIndexerIterator.create(dbTester.getSession(), projectUuid); Map<String, ProjectMeasures> docsById = Maps.uniqueIndex(it, pm -> pm.getProject().getUuid()); it.close(); return docsById; } private void assertResultSetIsEmpty() { assertThat(createResultSetAndReturnDocsById()).isEmpty(); } private MetricDto insertIntMetric(String metricKey) { return insertMetric(metricKey, true, false, INT); } private MetricDto insertMetric(String metricKey, Metric.ValueType type) { return insertMetric(metricKey, true, false, type); } private MetricDto insertMetric(String metricKey, boolean enabled, boolean hidden, Metric.ValueType type) { MetricDto metric = dbClient.metricDao().insert(dbSession, MetricTesting.newMetricDto() .setKey(metricKey) .setEnabled(enabled) .setHidden(hidden) .setValueType(type.name())); dbSession.commit(); return metric; } private MeasureDto insertProjectAndMeasure(String projectUuid, MetricDto metric, String value) { ComponentDto project = newPrivateProjectDto(dbTester.getDefaultOrganization(), projectUuid); SnapshotDto analysis1 = dbTester.components().insertProjectAndSnapshot(project); return insertMeasure(project, analysis1, metric, value); } private MeasureDto insertMeasure(ComponentDto project, SnapshotDto analysis, MetricDto metric, double value) { return insertMeasure(project, analysis, metric, value, null); } private MeasureDto insertMeasureOnLeak(ComponentDto project, SnapshotDto analysis, MetricDto metric, double value) { return insertMeasure(project, analysis, metric, null, value); } private MeasureDto insertMeasure(ComponentDto project, SnapshotDto analysis, MetricDto metric, String value) { return insertMeasure(MeasureTesting.newMeasureDto(metric, project, analysis).setData(value)); } private MeasureDto insertMeasure(ComponentDto project, SnapshotDto analysis, MetricDto metric, @Nullable Double value, @Nullable Double leakValue) { return insertMeasure(MeasureTesting.newMeasureDto(metric, project, analysis).setValue(value).setVariation(leakValue)); } private MeasureDto insertMeasure(MeasureDto measure) { dbClient.measureDao().insert(dbSession, measure); dbSession.commit(); return measure; } }