/* * SonarQube * Copyright (C) 2009-2025 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 java.time.Instant; import java.util.Arrays; import java.util.HashMap; import java.util.Map; import java.util.concurrent.ThreadLocalRandom; import java.util.function.BiConsumer; import java.util.function.Consumer; import org.sonar.api.measures.CoreMetrics; import org.sonar.db.DbClient; import org.sonar.db.DbTester; import org.sonar.db.component.BranchDto; import org.sonar.db.component.ComponentDto; import org.sonar.db.component.ProjectData; import org.sonar.db.component.SnapshotDto; import org.sonar.db.metric.MetricDto; import static org.sonar.db.measure.MeasureTesting.newMeasure; import static org.sonar.db.measure.MeasureTesting.newProjectMeasureDto; import static org.sonar.db.metric.MetricTesting.newMetricDto; public class MeasureDbTester { private final DbClient dbClient; private final DbTester db; public MeasureDbTester(DbTester db) { this.dbClient = db.getDbClient(); this.db = db; } @SafeVarargs public final ProjectMeasureDto insertProjectMeasureWithSensibleValues(ComponentDto component, SnapshotDto analysis, MetricDto metricDto, Consumer... consumers) { ProjectMeasureDto measureDto = createProjectMeasure(metricDto, analysis, component); Arrays.stream(consumers).forEach(c -> c.accept(measureDto)); dbClient.projectMeasureDao().insert(db.getSession(), measureDto); db.commit(); return measureDto; } @SafeVarargs public final ProjectMeasureDto insertProjectMeasure(ComponentDto component, SnapshotDto analysis, MetricDto metricDto, Consumer... consumers) { ProjectMeasureDto projectMeasureDto = newProjectMeasureDto(metricDto, component, analysis); Arrays.stream(consumers).forEach(c -> c.accept(projectMeasureDto)); dbClient.projectMeasureDao().insert(db.getSession(), projectMeasureDto); db.commit(); return projectMeasureDto; } @SafeVarargs public final ProjectMeasureDto insertProjectMeasure(BranchDto branchDto, SnapshotDto analysis, MetricDto metricDto, Consumer... consumers) { ProjectMeasureDto projectMeasureDto = MeasureTesting.newProjectMeasureDto(metricDto, branchDto.getUuid(), analysis); Arrays.stream(consumers).forEach(c -> c.accept(projectMeasureDto)); dbClient.projectMeasureDao().insert(db.getSession(), projectMeasureDto); db.commit(); return projectMeasureDto; } @SafeVarargs public final MeasureDto insertMeasureWithSensibleValues(ComponentDto component, MetricDto metric, Consumer... consumers) { MeasureDto dto = createMeasure(metric, component); Arrays.stream(consumers).forEach(c -> c.accept(dto)); dbClient.measureDao().insertOrUpdate(db.getSession(), dto); db.commit(); return dto; } @SafeVarargs public final MeasureDto insertMeasure(ComponentDto component, Consumer... consumers) { return insertMeasure(component.uuid(), component.branchUuid(), consumers); } @SafeVarargs public final MeasureDto insertMeasure(BranchDto branch, Consumer... consumers) { return insertMeasure(branch.getUuid(), branch.getUuid(), consumers); } @SafeVarargs public final MeasureDto insertMeasure(ProjectData projectData, Consumer... consumers) { ComponentDto component = projectData.getMainBranchComponent(); return insertMeasure(component.uuid(), component.branchUuid(), consumers); } @SafeVarargs private MeasureDto insertMeasure(String componentUuid, String branchUuid, Consumer... consumers) { MeasureDto dto = new MeasureDto() .setComponentUuid(componentUuid) .setBranchUuid(branchUuid); Arrays.stream(consumers).forEach(c -> c.accept(dto)); dbClient.measureDao().insertOrUpdate(db.getSession(), dto); db.getSession().commit(); return dto; } @SafeVarargs public final MetricDto insertMetric(Consumer... consumers) { MetricDto metricDto = newMetricDto(); Arrays.stream(consumers).forEach(c -> c.accept(metricDto)); dbClient.metricDao().insert(db.getSession(), metricDto); db.commit(); return metricDto; } public static MeasureDto createMeasure(MetricDto metricDto, ComponentDto componentDto) { BiConsumer populator = specificLiveMeasurePopulator.getOrDefault(metricDto.getKey(), defaultLiveMeasurePopulator); MeasureDto measureDto = newMeasure(componentDto); populator.accept(metricDto, new MeasureAdapter(measureDto, metricDto.getKey())); return measureDto; } public static ProjectMeasureDto createProjectMeasure(MetricDto metricDto, SnapshotDto snapshotDto, ComponentDto projectComponentDto) { BiConsumer populator = specificLiveMeasurePopulator.getOrDefault(metricDto.getKey(), defaultLiveMeasurePopulator); ProjectMeasureDto measureDto = newProjectMeasureDto(metricDto, projectComponentDto, snapshotDto); populator.accept(metricDto, new MeasureAdapter(measureDto)); return measureDto; } private static final Consumer ratingMeasurePopulator = m -> m.setValue((double) ThreadLocalRandom.current().nextInt(1, 5)); private static final Map> specificLiveMeasurePopulator = new HashMap<>() { { put(CoreMetrics.DEVELOPMENT_COST_KEY, (metric, m) -> m.setData("" + Math.round(ThreadLocalRandom.current().nextDouble(100, 10_000)))); put(CoreMetrics.LAST_COMMIT_DATE_KEY, (metric, m) -> m.setValue((double) Instant.now().minusSeconds(Math.round(ThreadLocalRandom.current().nextDouble(100_000, 1_000_000))).toEpochMilli())); put(CoreMetrics.SQALE_RATING_KEY, (metric, m) -> ratingMeasurePopulator.accept(m)); put(CoreMetrics.RELIABILITY_RATING_KEY, (metric, m) -> ratingMeasurePopulator.accept(m)); put(CoreMetrics.SECURITY_REVIEW_RATING_KEY, (metric, m) -> ratingMeasurePopulator.accept(m)); put(CoreMetrics.SECURITY_RATING_KEY, (metric, m) -> ratingMeasurePopulator.accept(m)); put(CoreMetrics.ALERT_STATUS_KEY, (metric, m) -> { boolean isOk = ThreadLocalRandom.current().nextDouble() > 0.5; m.setData(isOk ? "OK" : "ERROR"); m.setAlert(isOk ? "OK" : "ERROR"); }); put(CoreMetrics.QUALITY_GATE_DETAILS_KEY, (metric, m) -> m.setData("{\"level\":\"OK\",\"conditions\":[],\"ignoredConditions\":false}")); put(CoreMetrics.QUALITY_PROFILES_KEY, (metric, m) -> m.setData("[{\"key\":\"62969160-dcda-40a0-9981-772b7820d587\",\"language\":\"xml\",\"name\":\"Sonar way\",\"rulesUpdatedAt\":\"2024-09-11T14:40:55+0000\"}]")); put(CoreMetrics.RELIABILITY_ISSUES_KEY, (metric, m) -> m.setData("{\"LOW\":0,\"MEDIUM\":1,\"HIGH\":0,\"total\":1}")); put(CoreMetrics.MAINTAINABILITY_ISSUES_KEY, (metric, m) -> m.setData("{\"LOW\":0,\"MEDIUM\":1,\"HIGH\":0,\"total\":1}")); put(CoreMetrics.SECURITY_ISSUES_KEY, (metric, m) -> m.setData("{\"LOW\":0,\"MEDIUM\":1,\"HIGH\":0,\"total\":1}")); put(CoreMetrics.NCLOC_LANGUAGE_DISTRIBUTION_KEY, (metric, m) -> m.setData("java=123;xml=10")); } }; private static final BiConsumer defaultLiveMeasurePopulator = (metric, m) -> { int min, max; if (metric.getWorstValue() != null && metric.getBestValue() != null) { min = (int) Math.min(metric.getBestValue(), metric.getWorstValue()); max = (int) Math.max(metric.getBestValue(), metric.getWorstValue()); } else if (metric.getDirection() != 0) { int worst, best; if (metric.getWorstValue() != null) { worst = metric.getWorstValue().intValue(); best = -metric.getDirection() * 100; } else if (metric.getBestValue() != null) { best = metric.getBestValue().intValue(); worst = best - metric.getDirection() * 100; } else { worst = 0; best = -metric.getDirection() * 100; } min = Math.min(best, worst); max = Math.max(best, worst); } else { min = 0; max = 100; } m.setValue((double) Math.round(ThreadLocalRandom.current().nextDouble(min, max))); }; private static class MeasureAdapter { private final ProjectMeasureDto projectMeasure; private final MeasureDto measure; private String metricKey; private MeasureAdapter(MeasureDto measure, String metricKey) { this.projectMeasure = null; this.metricKey = metricKey; this.measure = measure; } private MeasureAdapter(ProjectMeasureDto projectMeasure) { this.projectMeasure = projectMeasure; this.measure = null; } public MeasureAdapter setValue(Double value) { if (projectMeasure != null) { projectMeasure.setValue(value); } else if (measure != null) { measure.addValue(metricKey, value); } return this; } public MeasureAdapter setData(String data) { if (projectMeasure != null) { projectMeasure.setData(data); } else if (measure != null) { measure.addValue(metricKey, data); } return this; } public MeasureAdapter setAlert(String value) { if (projectMeasure != null) { projectMeasure.setAlertText(value).setAlertStatus(value); } return this; } } }