diff options
author | Eric Giffon <eric.giffon@sonarsource.com> | 2024-08-29 14:37:24 +0200 |
---|---|---|
committer | sonartech <sonartech@sonarsource.com> | 2024-10-09 20:02:46 +0000 |
commit | 264769a69d03fd61c87491be3da5f101469bb60c (patch) | |
tree | ac39fd8068d8155ddb93e306fa542651bcb5facd /server/sonar-db-dao | |
parent | a4da413ce8b4eab78aadc9e492d437f45d9b7e6f (diff) | |
download | sonarqube-264769a69d03fd61c87491be3da5f101469bb60c.tar.gz sonarqube-264769a69d03fd61c87491be3da5f101469bb60c.zip |
SONAR-22872 CE step to persist measures in JSON format
Diffstat (limited to 'server/sonar-db-dao')
12 files changed, 548 insertions, 0 deletions
diff --git a/server/sonar-db-dao/src/main/java/org/sonar/db/DaoModule.java b/server/sonar-db-dao/src/main/java/org/sonar/db/DaoModule.java index f11922bff2a..c0852b111a5 100644 --- a/server/sonar-db-dao/src/main/java/org/sonar/db/DaoModule.java +++ b/server/sonar-db-dao/src/main/java/org/sonar/db/DaoModule.java @@ -51,6 +51,7 @@ import org.sonar.db.issue.IssueChangeDao; import org.sonar.db.issue.IssueDao; import org.sonar.db.issue.IssueFixedDao; import org.sonar.db.measure.LiveMeasureDao; +import org.sonar.db.measure.MeasureDao; import org.sonar.db.measure.ProjectMeasureDao; import org.sonar.db.metric.MetricDao; import org.sonar.db.newcodeperiod.NewCodePeriodDao; @@ -153,6 +154,7 @@ public class DaoModule extends Module { IssueDao.class, IssueFixedDao.class, IssuesDependencyDao.class, + MeasureDao.class, LiveMeasureDao.class, ProjectMeasureDao.class, MetricDao.class, diff --git a/server/sonar-db-dao/src/main/java/org/sonar/db/DbClient.java b/server/sonar-db-dao/src/main/java/org/sonar/db/DbClient.java index d04aff1df52..200f3547cb4 100644 --- a/server/sonar-db-dao/src/main/java/org/sonar/db/DbClient.java +++ b/server/sonar-db-dao/src/main/java/org/sonar/db/DbClient.java @@ -51,6 +51,7 @@ import org.sonar.db.issue.IssueChangeDao; import org.sonar.db.issue.IssueDao; import org.sonar.db.issue.IssueFixedDao; import org.sonar.db.measure.LiveMeasureDao; +import org.sonar.db.measure.MeasureDao; import org.sonar.db.measure.ProjectMeasureDao; import org.sonar.db.metric.MetricDao; import org.sonar.db.newcodeperiod.NewCodePeriodDao; @@ -129,6 +130,7 @@ public class DbClient { private final SnapshotDao snapshotDao; private final ComponentDao componentDao; private final ComponentKeyUpdaterDao componentKeyUpdaterDao; + private final MeasureDao measureDao; private final ProjectMeasureDao projectMeasureDao; private final UserDao userDao; private final UserGroupDao userGroupDao; @@ -225,6 +227,7 @@ public class DbClient { snapshotDao = getDao(map, SnapshotDao.class); componentDao = getDao(map, ComponentDao.class); componentKeyUpdaterDao = getDao(map, ComponentKeyUpdaterDao.class); + measureDao = getDao(map, MeasureDao.class); projectMeasureDao = getDao(map, ProjectMeasureDao.class); userDao = getDao(map, UserDao.class); userGroupDao = getDao(map, UserGroupDao.class); @@ -397,6 +400,10 @@ public class DbClient { return componentKeyUpdaterDao; } + public MeasureDao measureDao() { + return measureDao; + } + public ProjectMeasureDao projectMeasureDao() { return projectMeasureDao; } diff --git a/server/sonar-db-dao/src/main/java/org/sonar/db/MyBatis.java b/server/sonar-db-dao/src/main/java/org/sonar/db/MyBatis.java index 4191942d8d0..9aafec712ab 100644 --- a/server/sonar-db-dao/src/main/java/org/sonar/db/MyBatis.java +++ b/server/sonar-db-dao/src/main/java/org/sonar/db/MyBatis.java @@ -89,6 +89,7 @@ import org.sonar.db.issue.NewCodeReferenceIssueDto; import org.sonar.db.issue.PrIssueDto; import org.sonar.db.measure.LargestBranchNclocDto; import org.sonar.db.measure.LiveMeasureMapper; +import org.sonar.db.measure.MeasureMapper; import org.sonar.db.measure.ProjectLocDistributionDto; import org.sonar.db.measure.ProjectMeasureDto; import org.sonar.db.measure.ProjectMeasureMapper; @@ -316,6 +317,7 @@ public class MyBatis { IssueMapper.class, IssueFixedMapper.class, IssuesDependencyMapper.class, + MeasureMapper.class, ProjectMeasureMapper.class, MetricMapper.class, NewCodePeriodMapper.class, diff --git a/server/sonar-db-dao/src/main/java/org/sonar/db/measure/MeasureDao.java b/server/sonar-db-dao/src/main/java/org/sonar/db/measure/MeasureDao.java new file mode 100644 index 00000000000..eebceb810ad --- /dev/null +++ b/server/sonar-db-dao/src/main/java/org/sonar/db/measure/MeasureDao.java @@ -0,0 +1,61 @@ +/* + * SonarQube + * Copyright (C) 2009-2024 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.util.List; +import java.util.Optional; +import java.util.Set; +import org.sonar.api.utils.System2; +import org.sonar.db.Dao; +import org.sonar.db.DbSession; + +public class MeasureDao implements Dao { + + private final System2 system2; + + public MeasureDao(System2 system2) { + this.system2 = system2; + } + + public int insert(DbSession dbSession, MeasureDto dto) { + return mapper(dbSession).insert(dto, system2.now()); + } + + public int update(DbSession dbSession, MeasureDto dto) { + return mapper(dbSession).update(dto, system2.now()); + } + + public Optional<MeasureDto> selectMeasure(DbSession dbSession, String componentUuid) { + List<MeasureDto> measures = mapper(dbSession).selectByComponentUuids(List.of(componentUuid)); + if (!measures.isEmpty()) { + // component_uuid column is unique. List can't have more than 1 item. + return Optional.of(measures.get(0)); + } + return Optional.empty(); + } + + public Set<MeasureHash> selectBranchMeasureHashes(DbSession dbSession, String branchUuid) { + return mapper(dbSession).selectBranchMeasureHashes(branchUuid); + } + + private static MeasureMapper mapper(DbSession dbSession) { + return dbSession.getMapper(MeasureMapper.class); + } +} diff --git a/server/sonar-db-dao/src/main/java/org/sonar/db/measure/MeasureDto.java b/server/sonar-db-dao/src/main/java/org/sonar/db/measure/MeasureDto.java new file mode 100644 index 00000000000..8e93bd9a9a5 --- /dev/null +++ b/server/sonar-db-dao/src/main/java/org/sonar/db/measure/MeasureDto.java @@ -0,0 +1,101 @@ +/* + * SonarQube + * Copyright (C) 2009-2024 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.gson.Gson; +import com.google.gson.reflect.TypeToken; +import java.util.Map; +import java.util.TreeMap; +import org.apache.commons.codec.digest.MurmurHash3; + +import static java.nio.charset.StandardCharsets.UTF_8; + +public class MeasureDto { + + private static final Gson GSON = new Gson(); + + private String componentUuid; + private String branchUuid; + // measures are kept sorted by metric key so that the value hash is consistent + private Map<String, Object> metricValues = new TreeMap<>(); + private Long jsonValueHash; + + public MeasureDto() { + // empty constructor + } + + public String getComponentUuid() { + return componentUuid; + } + + public MeasureDto setComponentUuid(String s) { + this.componentUuid = s; + return this; + } + + public String getBranchUuid() { + return branchUuid; + } + + public MeasureDto setBranchUuid(String s) { + this.branchUuid = s; + return this; + } + + public Map<String, Object> getMetricValues() { + return metricValues; + } + + public MeasureDto addValue(String metricKey, Object value) { + metricValues.put(metricKey, value); + return this; + } + + // used by MyBatis mapper + public String getJsonValue() { + return GSON.toJson(metricValues); + } + + // used by MyBatis mapper + public MeasureDto setJsonValue(String jsonValue) { + metricValues = GSON.fromJson(jsonValue, new TypeToken<TreeMap<String, Object>>() { + }.getType()); + return this; + } + + public Long getJsonValueHash() { + return jsonValueHash; + } + + public long computeJsonValueHash() { + jsonValueHash = MurmurHash3.hash128(getJsonValue().getBytes(UTF_8))[0]; + return jsonValueHash; + } + + @Override + public String toString() { + return "MeasureDto{" + + "componentUuid='" + componentUuid + '\'' + + ", branchUuid='" + branchUuid + '\'' + + ", metricValues=" + metricValues + + ", jsonValueHash=" + jsonValueHash + + '}'; + } +} diff --git a/server/sonar-db-dao/src/main/java/org/sonar/db/measure/MeasureHash.java b/server/sonar-db-dao/src/main/java/org/sonar/db/measure/MeasureHash.java new file mode 100644 index 00000000000..65b73a665ba --- /dev/null +++ b/server/sonar-db-dao/src/main/java/org/sonar/db/measure/MeasureHash.java @@ -0,0 +1,32 @@ +/* + * SonarQube + * Copyright (C) 2009-2024 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.util.Comparator; + +public record MeasureHash(String componentUuid, Long jsonValueHash) implements Comparable<MeasureHash> { + + @Override + public int compareTo(MeasureHash o) { + return Comparator.comparing(MeasureHash::componentUuid) + .thenComparing(MeasureHash::jsonValueHash) + .compare(this, o); + } +} diff --git a/server/sonar-db-dao/src/main/java/org/sonar/db/measure/MeasureMapper.java b/server/sonar-db-dao/src/main/java/org/sonar/db/measure/MeasureMapper.java new file mode 100644 index 00000000000..69b4c2fefbe --- /dev/null +++ b/server/sonar-db-dao/src/main/java/org/sonar/db/measure/MeasureMapper.java @@ -0,0 +1,40 @@ +/* + * SonarQube + * Copyright (C) 2009-2024 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.util.Collection; +import java.util.List; +import java.util.Set; +import org.apache.ibatis.annotations.Param; + +public interface MeasureMapper { + + int insert( + @Param("dto") MeasureDto dto, + @Param("now") long now); + + int update( + @Param("dto") MeasureDto dto, + @Param("now") long now); + + List<MeasureDto> selectByComponentUuids(@Param("componentUuids") Collection<String> componentUuids); + + Set<MeasureHash> selectBranchMeasureHashes(@Param("branchUuid") String branchUuid); +} diff --git a/server/sonar-db-dao/src/main/resources/org/sonar/db/measure/MeasureMapper.xml b/server/sonar-db-dao/src/main/resources/org/sonar/db/measure/MeasureMapper.xml new file mode 100644 index 00000000000..8fc634a5f1c --- /dev/null +++ b/server/sonar-db-dao/src/main/resources/org/sonar/db/measure/MeasureMapper.xml @@ -0,0 +1,56 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "mybatis-3-mapper.dtd"> + +<mapper namespace="org.sonar.db.measure.MeasureMapper"> + + <insert id="insert" parameterType="map" useGeneratedKeys="false"> + insert into measures ( + component_uuid, + branch_uuid, + json_value, + json_value_hash, + created_at, + updated_at + ) values ( + #{dto.componentUuid, jdbcType=VARCHAR}, + #{dto.branchUuid, jdbcType=VARCHAR}, + #{dto.jsonValue, jdbcType=VARCHAR}, + #{dto.jsonValueHash, jdbcType=BIGINT}, + #{now, jdbcType=BIGINT}, + #{now, jdbcType=BIGINT} + ) + </insert> + + <update id="update" parameterType="map" useGeneratedKeys="false"> + update measures set + json_value = #{dto.jsonValue, jdbcType=VARCHAR}, + json_value_hash = #{dto.jsonValueHash, jdbcType=BIGINT}, + updated_at = #{now, jdbcType=BIGINT} + where component_uuid = #{dto.componentUuid, jdbcType=VARCHAR} + </update> + + <sql id="columns"> + m.component_uuid as componentUuid, + m.branch_uuid as branchUuid, + m.json_value as jsonValue, + m.json_value_hash as jsonValueHash + </sql> + + <select id="selectByComponentUuids" parameterType="map" resultType="org.sonar.db.measure.MeasureDto"> + select + <include refid="columns"/> + from measures m + where + m.component_uuid in + <foreach item="componentUuid" collection="componentUuids" open="(" separator="," close=")"> + #{componentUuid, jdbcType=VARCHAR} + </foreach> + </select> + + <select id="selectBranchMeasureHashes" resultType="org.sonar.db.measure.MeasureHash"> + select component_uuid, json_value_hash + from measures + where branch_uuid = #{branchUuid, jdbcType=VARCHAR} + </select> + +</mapper> diff --git a/server/sonar-db-dao/src/test/java/org/sonar/db/measure/MeasureDaoTest.java b/server/sonar-db-dao/src/test/java/org/sonar/db/measure/MeasureDaoTest.java new file mode 100644 index 00000000000..1fdd6d7b9c1 --- /dev/null +++ b/server/sonar-db-dao/src/test/java/org/sonar/db/measure/MeasureDaoTest.java @@ -0,0 +1,107 @@ +/* + * SonarQube + * Copyright (C) 2009-2024 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 org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; +import org.sonar.api.utils.System2; +import org.sonar.db.DbTester; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.sonar.db.measure.MeasureTesting.newMeasure; + +class MeasureDaoTest { + + @RegisterExtension + public final DbTester db = DbTester.create(System2.INSTANCE); + + private final MeasureDao underTest = db.getDbClient().measureDao(); + + @Test + void insert_measure() { + MeasureDto dto = newMeasure(); + int count = underTest.insert(db.getSession(), dto); + assertThat(count).isEqualTo(1); + verifyTableSize(1); + verifyPersisted(dto); + } + + @Test + void update_measure() { + MeasureDto dto = newMeasure(); + underTest.insert(db.getSession(), dto); + + dto.addValue("metric1", "value1"); + dto.computeJsonValueHash(); + int count = underTest.update(db.getSession(), dto); + + assertThat(count).isEqualTo(1); + verifyTableSize(1); + verifyPersisted(dto); + } + + @Test + void select_measure() { + MeasureDto measure1 = newMeasure(); + MeasureDto measure2 = newMeasure(); + underTest.insert(db.getSession(), measure1); + underTest.insert(db.getSession(), measure2); + + assertThat(underTest.selectMeasure(db.getSession(), measure1.getComponentUuid())) + .hasValueSatisfying(selected -> assertThat(selected).usingRecursiveComparison().isEqualTo(measure1)); + assertThat(underTest.selectMeasure(db.getSession(), "unknown-component")).isEmpty(); + } + + @Test + void select_branch_measure_hashes() { + MeasureDto measure1 = new MeasureDto() + .setComponentUuid("c1") + .setBranchUuid("b1") + .addValue("metric1", "value1"); + MeasureDto measure2 = new MeasureDto() + .setComponentUuid("c2") + .setBranchUuid("b1") + .addValue("metric2", "value2"); + MeasureDto measure3 = new MeasureDto() + .setComponentUuid("c3") + .setBranchUuid("b3") + .addValue("metric3", "value3"); + long hash1 = measure1.computeJsonValueHash(); + long hash2 = measure2.computeJsonValueHash(); + measure3.computeJsonValueHash(); + + underTest.insert(db.getSession(), measure1); + underTest.insert(db.getSession(), measure2); + underTest.insert(db.getSession(), measure3); + + assertThat(underTest.selectBranchMeasureHashes(db.getSession(), "b1")) + .containsOnly(new MeasureHash("c1", hash1), new MeasureHash("c2", hash2)); + } + + private void verifyTableSize(int expectedSize) { + assertThat(db.countRowsOfTable(db.getSession(), "measures")).isEqualTo(expectedSize); + } + + private void verifyPersisted(MeasureDto dto) { + assertThat(underTest.selectMeasure(db.getSession(), dto.getComponentUuid())).hasValueSatisfying(selected -> { + assertThat(selected).usingRecursiveComparison().isEqualTo(dto); + }); + } +} diff --git a/server/sonar-db-dao/src/test/java/org/sonar/db/measure/MeasureDtoTest.java b/server/sonar-db-dao/src/test/java/org/sonar/db/measure/MeasureDtoTest.java new file mode 100644 index 00000000000..9299402942d --- /dev/null +++ b/server/sonar-db-dao/src/test/java/org/sonar/db/measure/MeasureDtoTest.java @@ -0,0 +1,68 @@ +/* + * SonarQube + * Copyright (C) 2009-2024 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.util.Map; +import java.util.TreeMap; +import org.junit.jupiter.api.Test; + +import static org.assertj.core.api.Assertions.assertThat; + +class MeasureDtoTest { + + @Test + void compute_json_value_hash() { + MeasureDto measureDto = new MeasureDto(); + measureDto.setJsonValue("{\"key\":\"value\"}"); + assertThat(measureDto.getJsonValueHash()).isNull(); + assertThat(measureDto.computeJsonValueHash()).isEqualTo(2887272982314571750L); + assertThat(measureDto.getJsonValueHash()).isEqualTo(2887272982314571750L); + } + + @Test + void getMetricValues_returns_all_values_ordered() { + MeasureDto measureDto = new MeasureDto() + .addValue("string-metric", "value") + .addValue("int-metric", 1) + .addValue("long-metric", 2L); + assertThat(measureDto.getMetricValues()).containsExactlyEntriesOf(new TreeMap<>(Map.of( + "int-metric", 1, + "long-metric", 2L, + "string-metric", "value" + ))); + } + + @Test + void toString_prints_all_fields() { + MeasureDto measureDto = new MeasureDto() + .setBranchUuid("branch-uuid") + .setComponentUuid("component-uuid") + .addValue("int-metric", 12) + .addValue("double-metric", 34.5) + .addValue("boolean-metric", true) + .addValue("string-metric", "value"); + measureDto.computeJsonValueHash(); + + assertThat(measureDto).hasToString("MeasureDto{componentUuid='component-uuid'" + + ", branchUuid='branch-uuid'" + + ", metricValues={boolean-metric=true, double-metric=34.5, int-metric=12, string-metric=value}" + + ", jsonValueHash=-1071134275520515337}"); + } +} diff --git a/server/sonar-db-dao/src/test/java/org/sonar/db/measure/MeasureHashTest.java b/server/sonar-db-dao/src/test/java/org/sonar/db/measure/MeasureHashTest.java new file mode 100644 index 00000000000..ff11db17994 --- /dev/null +++ b/server/sonar-db-dao/src/test/java/org/sonar/db/measure/MeasureHashTest.java @@ -0,0 +1,54 @@ +/* + * SonarQube + * Copyright (C) 2009-2024 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.util.List; +import java.util.TreeSet; +import org.junit.jupiter.api.Test; + +import static org.assertj.core.api.Assertions.assertThat; + +class MeasureHashTest { + + @Test + void hashCode_depends_on_both_fields() { + MeasureHash measureHash1 = new MeasureHash("component1", 123L); + MeasureHash measureHash2 = new MeasureHash("component", 123L); + MeasureHash measureHash3 = new MeasureHash("component", 124L); + + assertThat(measureHash1) + .doesNotHaveSameHashCodeAs(measureHash2) + .doesNotHaveSameHashCodeAs(measureHash3) + .isNotEqualTo(measureHash2) + .isNotEqualTo(measureHash3); + } + + @Test + void sort_by_component_and_hash() { + MeasureHash measureHash1 = new MeasureHash("A", 1L); + MeasureHash measureHash2 = new MeasureHash("A", 2L); + MeasureHash measureHash3 = new MeasureHash("B", 1L); + MeasureHash measureHash4 = new MeasureHash("B", 2L); + + TreeSet<MeasureHash> set = new TreeSet<>(List.of(measureHash1, measureHash2, measureHash3, measureHash4)); + + assertThat(set).containsExactly(measureHash1, measureHash2, measureHash3, measureHash4); + } +} diff --git a/server/sonar-db-dao/src/testFixtures/java/org/sonar/db/measure/MeasureTesting.java b/server/sonar-db-dao/src/testFixtures/java/org/sonar/db/measure/MeasureTesting.java index a01b6d5ba26..89db3b7adc5 100644 --- a/server/sonar-db-dao/src/testFixtures/java/org/sonar/db/measure/MeasureTesting.java +++ b/server/sonar-db-dao/src/testFixtures/java/org/sonar/db/measure/MeasureTesting.java @@ -90,4 +90,22 @@ public class MeasureTesting { .setData(String.valueOf(cursor++)) .setValue((double) cursor++); } + + public static MeasureDto newMeasure() { + MeasureDto measureDto = new MeasureDto() + .setComponentUuid(String.valueOf(cursor++)) + .setBranchUuid(String.valueOf(cursor++)) + .addValue("metric" + cursor++, (double) cursor++); + measureDto.computeJsonValueHash(); + return measureDto; + } + + public static MeasureDto newMeasure(ComponentDto component, MetricDto metric, Object value) { + MeasureDto measureDto = new MeasureDto() + .setComponentUuid(component.uuid()) + .setBranchUuid(component.branchUuid()) + .addValue(metric.getKey(), value); + measureDto.computeJsonValueHash(); + return measureDto; + } } |