3 * Copyright (C) 2009-2023 SonarSource SA
4 * mailto:info AT sonarsource DOT com
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 3 of the License, or (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public License
17 * along with this program; if not, write to the Free Software Foundation,
18 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20 package org.sonar.server.measure.live;
22 import com.tngtech.java.junit.dataprovider.DataProviderRunner;
23 import java.util.List;
25 import javax.annotation.Nullable;
26 import org.junit.Before;
27 import org.junit.Rule;
28 import org.junit.Test;
29 import org.junit.runner.RunWith;
30 import org.sonar.api.config.Configuration;
31 import org.sonar.api.config.PropertyDefinitions;
32 import org.sonar.api.config.internal.MapSettings;
33 import org.sonar.api.measures.Metric;
34 import org.sonar.api.resources.Qualifiers;
35 import org.sonar.api.utils.System2;
36 import org.sonar.core.config.CorePropertyDefinitions;
37 import org.sonar.db.DbSession;
38 import org.sonar.db.DbTester;
39 import org.sonar.db.component.BranchDto;
40 import org.sonar.db.component.ComponentDto;
41 import org.sonar.db.component.SnapshotDto;
42 import org.sonar.db.metric.MetricDto;
43 import org.sonar.server.es.TestProjectIndexers;
44 import org.sonar.server.qualitygate.EvaluatedQualityGate;
45 import org.sonar.server.qualitygate.QualityGate;
46 import org.sonar.server.qualitygate.changeevent.QGChangeEvent;
47 import org.sonar.server.setting.ProjectConfigurationLoader;
48 import org.sonar.server.setting.TestProjectConfigurationLoader;
50 import static org.assertj.core.api.Assertions.assertThat;
51 import static org.mockito.ArgumentMatchers.any;
52 import static org.mockito.ArgumentMatchers.eq;
53 import static org.mockito.Mockito.mock;
54 import static org.mockito.Mockito.verify;
55 import static org.mockito.Mockito.when;
56 import static org.sonar.api.measures.CoreMetrics.ALERT_STATUS_KEY;
58 @RunWith(DataProviderRunner.class)
59 public class LiveMeasureComputerImplIT {
62 public DbTester db = DbTester.create(true);
64 private final TestProjectIndexers projectIndexer = new TestProjectIndexers();
65 private MetricDto metric1;
66 private MetricDto metric2;
67 private ComponentDto project;
69 private final LiveQualityGateComputer qGateComputer = mock(LiveQualityGateComputer.class);
70 private final QualityGate qualityGate = mock(QualityGate.class);
71 private final EvaluatedQualityGate newQualityGate = mock(EvaluatedQualityGate.class);
72 private final Configuration configuration = new MapSettings(new PropertyDefinitions(System2.INSTANCE, CorePropertyDefinitions.all())).asConfig();
73 private final ProjectConfigurationLoader configurationLoader = new TestProjectConfigurationLoader(configuration);
74 private final MeasureUpdateFormulaFactory measureUpdateFormulaFactory = mock(MeasureUpdateFormulaFactory.class);
75 private final ComponentIndexFactory componentIndexFactory = mock(ComponentIndexFactory.class);
76 private final ComponentIndex componentIndex = mock(ComponentIndex.class);
77 private final FakeLiveMeasureTreeUpdater treeUpdater = new FakeLiveMeasureTreeUpdater();
78 private final LiveMeasureComputerImpl liveMeasureComputer = new LiveMeasureComputerImpl(db.getDbClient(), measureUpdateFormulaFactory, componentIndexFactory,
79 qGateComputer, configurationLoader, projectIndexer, treeUpdater);
80 private BranchDto branch;
84 metric1 = db.measures().insertMetric();
85 metric2 = db.measures().insertMetric();
87 project = db.components().insertPublicProject().getMainBranchComponent();
88 branch = db.getDbClient().branchDao().selectByUuid(db.getSession(), project.uuid()).get();
89 db.measures().insertLiveMeasure(project, metric2, lm -> lm.setValue(1d));
91 when(componentIndexFactory.create(any(), any())).thenReturn(componentIndex);
92 when(measureUpdateFormulaFactory.getFormulaMetrics()).thenReturn(Set.of(toMetric(metric1), toMetric(metric2)));
93 when(componentIndex.getBranch()).thenReturn(project);
97 public void loads_measure_matrix_and_calls_tree_updater() {
98 SnapshotDto snapshot = markProjectAsAnalyzed(project);
99 when(componentIndex.getAllUuids()).thenReturn(Set.of(project.uuid()));
101 liveMeasureComputer.refresh(db.getSession(), List.of(project));
103 // tree updater was called
104 assertThat(treeUpdater.getMeasureMatrix()).isNotNull();
106 // measure matrix was loaded with formula's metrics and measures
107 assertThat(treeUpdater.getMeasureMatrix().getMetricByUuid(metric2.getUuid())).isNotNull();
108 assertThat(treeUpdater.getMeasureMatrix().getMeasure(project, metric2.getKey()).get().getValue()).isEqualTo(1d);
110 // new measures were persisted
111 assertThat(db.getDbClient().liveMeasureDao().selectMeasure(db.getSession(), project.uuid(), metric1.getKey()).get().getValue()).isEqualTo(2d);
115 public void refreshes_quality_gate() {
116 SnapshotDto snapshot = markProjectAsAnalyzed(project);
117 when(componentIndex.getAllUuids()).thenReturn(Set.of(project.uuid()));
118 when(qGateComputer.loadQualityGate(db.getSession(), db.components().getProjectDtoByMainBranch(project), branch)).thenReturn(qualityGate);
120 liveMeasureComputer.refresh(db.getSession(), List.of(project));
122 verify(qGateComputer).refreshGateStatus(eq(project), eq(qualityGate), any(MeasureMatrix.class), eq(configuration));
126 public void return_if_no_analysis_found() {
127 liveMeasureComputer.refresh(db.getSession(), List.of(project));
128 assertThat(treeUpdater.getMeasureMatrix()).isNull();
132 public void returns_qgate_event() {
133 SnapshotDto snapshot = markProjectAsAnalyzed(project);
134 when(componentIndex.getAllUuids()).thenReturn(Set.of(project.uuid()));
136 MetricDto alertStatusMetric = db.measures().insertMetric(m -> m.setKey(ALERT_STATUS_KEY));
137 db.measures().insertLiveMeasure(project, alertStatusMetric, lm -> lm.setData("OK"));
139 when(qGateComputer.loadQualityGate(db.getSession(), db.components().getProjectDtoByMainBranch(project), branch)).thenReturn(qualityGate);
140 when(qGateComputer.refreshGateStatus(eq(project), eq(qualityGate), any(MeasureMatrix.class), eq(configuration))).thenReturn(newQualityGate);
142 List<QGChangeEvent> qgChangeEvents = liveMeasureComputer.refresh(db.getSession(), List.of(project));
144 assertThat(qgChangeEvents).hasSize(1);
145 assertThat(qgChangeEvents.get(0).getBranch()).isEqualTo(branch);
146 assertThat(qgChangeEvents.get(0).getAnalysis()).isEqualTo(snapshot);
147 assertThat(qgChangeEvents.get(0).getProject()).isEqualTo(db.components().getProjectDtoByMainBranch(project));
148 assertThat(qgChangeEvents.get(0).getPreviousStatus()).contains(Metric.Level.OK);
149 assertThat(qgChangeEvents.get(0).getProjectConfiguration()).isEqualTo(configuration);
150 assertThat(qgChangeEvents.get(0).getQualityGateSupplier().get()).contains(newQualityGate);
153 private SnapshotDto markProjectAsAnalyzed(ComponentDto p) {
154 return markProjectAsAnalyzed(p, 1_490_000_000L);
157 private SnapshotDto markProjectAsAnalyzed(ComponentDto p, @Nullable Long periodDate) {
158 assertThat(p.qualifier()).isEqualTo(Qualifiers.PROJECT);
159 return db.components().insertSnapshot(p, s -> s.setPeriodDate(periodDate));
162 private static Metric<?> toMetric(MetricDto metric) {
163 return new Metric.Builder(metric.getKey(), metric.getShortName(), Metric.ValueType.valueOf(metric.getValueType())).create();
166 private class FakeLiveMeasureTreeUpdater implements LiveMeasureTreeUpdater {
167 private MeasureMatrix measureMatrix;
170 public void update(DbSession dbSession, SnapshotDto lastAnalysis, Configuration config, ComponentIndex components, BranchDto branch, MeasureMatrix measures) {
171 this.measureMatrix = measures;
172 measures.setValue(project, metric1.getKey(), 2d);
175 public MeasureMatrix getMeasureMatrix() {
176 return measureMatrix;