From: Aurelien Poscia
Date: Fri, 19 Jan 2024 09:08:55 +0000 (+0100)
Subject: SONAR-21290 Use UUIDs v4 for all database identifiers
X-Git-Tag: 10.4.0.87286~113
X-Git-Url: https://source.dussan.org/?a=commitdiff_plain;h=858b1023bba599c5aa44119469d8451301434abb;p=sonarqube.git
SONAR-21290 Use UUIDs v4 for all database identifiers
---
diff --git a/server/sonar-ce-task-projectanalysis/src/it/java/org/sonar/ce/task/projectanalysis/step/LoadFileHashesAndStatusStepIT.java b/server/sonar-ce-task-projectanalysis/src/it/java/org/sonar/ce/task/projectanalysis/step/LoadFileHashesAndStatusStepIT.java
index 2dd7b144885..8a887c2c058 100644
--- a/server/sonar-ce-task-projectanalysis/src/it/java/org/sonar/ce/task/projectanalysis/step/LoadFileHashesAndStatusStepIT.java
+++ b/server/sonar-ce-task-projectanalysis/src/it/java/org/sonar/ce/task/projectanalysis/step/LoadFileHashesAndStatusStepIT.java
@@ -87,10 +87,10 @@ public class LoadFileHashesAndStatusStepIT {
assertThat(previousFileHashesRepository.getMap()).hasSize(2);
assertThat(previousFileHashesRepository.getDbFile(reportFile1).get())
.extracting(FileHashesDto::getSrcHash, FileHashesDto::getRevision, FileHashesDto::getDataHash)
- .containsOnly("srcHash" + dbFile1.getKey(), "revision" + dbFile1.getKey(), "dataHash" + dbFile1.getKey());
+ .containsOnly("SH" + dbFile1.getKey(), "revision" + dbFile1.getKey(), "DH" + dbFile1.getKey());
assertThat(previousFileHashesRepository.getDbFile(reportFile2).get())
.extracting(FileHashesDto::getSrcHash, FileHashesDto::getRevision, FileHashesDto::getDataHash)
- .containsOnly("srcHash" + dbFile2.getKey(), "revision" + dbFile2.getKey(), "dataHash" + dbFile2.getKey());
+ .containsOnly("SH" + dbFile2.getKey(), "revision" + dbFile2.getKey(), "DH" + dbFile2.getKey());
assertThat(previousFileHashesRepository.getDbFile(reportFile3)).isEmpty();
}
@@ -118,9 +118,9 @@ public class LoadFileHashesAndStatusStepIT {
private void insertFileSources(ComponentDto... files) {
for (ComponentDto file : files) {
db.fileSources().insertFileSource(file, f -> f
- .setSrcHash("srcHash" + file.getKey())
+ .setSrcHash("SH" + file.getKey())
.setRevision("revision" + file.getKey())
- .setDataHash("dataHash" + file.getKey()));
+ .setDataHash("DH" + file.getKey()));
}
}
}
diff --git a/server/sonar-ce-task-projectanalysis/src/it/java/org/sonar/ce/task/projectexport/file/ExportLineHashesStepIT.java b/server/sonar-ce-task-projectanalysis/src/it/java/org/sonar/ce/task/projectexport/file/ExportLineHashesStepIT.java
index 3db9bfce88d..07c6a53a70f 100644
--- a/server/sonar-ce-task-projectanalysis/src/it/java/org/sonar/ce/task/projectexport/file/ExportLineHashesStepIT.java
+++ b/server/sonar-ce-task-projectanalysis/src/it/java/org/sonar/ce/task/projectexport/file/ExportLineHashesStepIT.java
@@ -34,7 +34,6 @@ import org.sonar.ce.task.projectexport.component.MutableComponentRepository;
import org.sonar.ce.task.projectexport.steps.DumpElement;
import org.sonar.ce.task.projectexport.steps.FakeDumpWriter;
import org.sonar.ce.task.step.TestComputationStepContext;
-import org.sonar.core.util.Uuids;
import org.sonar.db.DbClient;
import org.sonar.db.DbSession;
import org.sonar.db.DbTester;
@@ -63,6 +62,7 @@ public class ExportLineHashesStepIT {
private final DbSession dbSession = dbClient.openSession(false);
private final FakeDumpWriter dumpWriter = new FakeDumpWriter();
private final MutableComponentRepository componentRepository = new ComponentRepositoryImpl();
+ private int fileId = 0;
private final ExportLineHashesStep underTest = new ExportLineHashesStep(dbClient, dumpWriter, componentRepository);
@Before
@@ -188,7 +188,7 @@ public class ExportLineHashesStepIT {
private FileSourceDto createDto(String fileUuid, String componentUuid, String hashes) {
FileSourceDto fileSourceDto = new FileSourceDto()
- .setUuid(Uuids.createFast())
+ .setUuid("file_uuid_" + fileId++)
.setFileUuid(fileUuid)
.setProjectUuid(componentUuid);
fileSourceDto.setRawLineHashes(hashes);
diff --git a/server/sonar-db-dao/src/it/java/org/sonar/db/alm/setting/AlmSettingDaoWithPersisterIT.java b/server/sonar-db-dao/src/it/java/org/sonar/db/alm/setting/AlmSettingDaoWithPersisterIT.java
index c83510727e3..6ac0ba9e64c 100644
--- a/server/sonar-db-dao/src/it/java/org/sonar/db/alm/setting/AlmSettingDaoWithPersisterIT.java
+++ b/server/sonar-db-dao/src/it/java/org/sonar/db/alm/setting/AlmSettingDaoWithPersisterIT.java
@@ -35,6 +35,7 @@ import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
+import static org.sonar.core.util.SequenceUuidFactory.UUID_1;
import static org.sonar.db.almsettings.AlmSettingsTesting.newGithubAlmSettingDto;
public class AlmSettingDaoWithPersisterIT {
@@ -71,7 +72,8 @@ public class AlmSettingDaoWithPersisterIT {
.extracting("devOpsPlatformSettingUuid", "key")
.containsExactly(almSettingDto.getUuid(), almSettingDto.getKey());
assertThat(newValue)
- .hasToString("{\"devOpsPlatformSettingUuid\": \"1\", \"key\": \"key\", \"devOpsPlatformName\": \"id1\", \"url\": \"url\", \"appId\": \"id1\", \"clientId\": \"cid1\" }");
+ .hasToString("{\"devOpsPlatformSettingUuid\": \"" + UUID_1 + "\", \"key\": \"key\", " +
+ "\"devOpsPlatformName\": \"id1\", \"url\": \"url\", \"appId\": \"id1\", \"clientId\": \"cid1\" }");
almSettingDto.setPrivateKey("updated private key");
almSettingDto.setAppId("updated app id");
@@ -89,8 +91,10 @@ public class AlmSettingDaoWithPersisterIT {
newValue = newValueCaptor.getValue();
assertThat(newValue)
.extracting("devOpsPlatformSettingUuid", "key", "appId", "devOpsPlatformName", "url", "clientId")
- .containsExactly(almSettingDto.getUuid(), almSettingDto.getKey(), almSettingDto.getAppId(), almSettingDto.getAppId(), almSettingDto.getUrl(), almSettingDto.getClientId());
- assertThat(newValue).hasToString("{\"devOpsPlatformSettingUuid\": \"1\", \"key\": \"updated key\", \"devOpsPlatformName\": \"updated app id\", "
+ .containsExactly(almSettingDto.getUuid(), almSettingDto.getKey(), almSettingDto.getAppId(), almSettingDto.getAppId(),
+ almSettingDto.getUrl(), almSettingDto.getClientId());
+ assertThat(newValue).hasToString("{\"devOpsPlatformSettingUuid\": \"" + UUID_1 + "\", " +
+ "\"key\": \"updated key\", \"devOpsPlatformName\": \"updated app id\", "
+ "\"url\": \"updated url\", \"appId\": \"updated app id\", \"clientId\": \"cid1\" }");
}
diff --git a/server/sonar-db-dao/src/it/java/org/sonar/db/alm/setting/ProjectAlmSettingDaoIT.java b/server/sonar-db-dao/src/it/java/org/sonar/db/alm/setting/ProjectAlmSettingDaoIT.java
index b96ba71b802..07dcc3b1b5f 100644
--- a/server/sonar-db-dao/src/it/java/org/sonar/db/alm/setting/ProjectAlmSettingDaoIT.java
+++ b/server/sonar-db-dao/src/it/java/org/sonar/db/alm/setting/ProjectAlmSettingDaoIT.java
@@ -126,7 +126,7 @@ public class ProjectAlmSettingDaoIT {
private ProjectAlmSettingDto createAlmProject(AlmSettingDto almSettingsDto) {
ProjectDto project = db.components().insertPrivateProject().getProjectDto();
- when(uuidFactory.create()).thenReturn(project.getUuid() + "_forSetting");
+ when(uuidFactory.create()).thenReturn(project.getUuid() + "_set");
ProjectAlmSettingDto githubProjectAlmSettingDto = newGithubProjectAlmSettingDto(almSettingsDto, project);
underTest.insertOrUpdate(dbSession, githubProjectAlmSettingDto, almSettingsDto.getKey(), project.getName(), project.getKey());
return githubProjectAlmSettingDto;
diff --git a/server/sonar-db-dao/src/it/java/org/sonar/db/measure/LiveMeasureDaoIT.java b/server/sonar-db-dao/src/it/java/org/sonar/db/measure/LiveMeasureDaoIT.java
index fed6586c00c..bfff26aa439 100644
--- a/server/sonar-db-dao/src/it/java/org/sonar/db/measure/LiveMeasureDaoIT.java
+++ b/server/sonar-db-dao/src/it/java/org/sonar/db/measure/LiveMeasureDaoIT.java
@@ -44,6 +44,8 @@ import static java.util.Arrays.asList;
import static java.util.Collections.emptyList;
import static java.util.Collections.singleton;
import static java.util.Collections.singletonList;
+import static java.util.function.Function.identity;
+import static java.util.stream.Collectors.toMap;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.groups.Tuple.tuple;
import static org.sonar.api.measures.Metric.ValueType.DATA;
@@ -61,6 +63,8 @@ public class LiveMeasureDaoIT {
private final LiveMeasureDao underTest = db.getDbClient().liveMeasureDao();
private MetricDto metric;
+ private int branchId = 0;
+
@Before
public void setUp() {
metric = db.measures().insertMetric();
@@ -398,14 +402,17 @@ public class LiveMeasureDaoIT {
MetricDto ncloc = metrics.get("ncloc");
setupProjectsWithLoc(ncloc, metrics.get("ncloc_language_distribution"), metrics.get("lines"));
- List results = underTest.getLargestBranchNclocPerProject(db.getSession(), ncloc.getUuid());
+ Map results = underTest.getLargestBranchNclocPerProject(db.getSession(), ncloc.getUuid())
+ .stream()
+ .collect(toMap(largestBranchNclocDto -> largestBranchNclocDto.getProjectKey() + " " + largestBranchNclocDto.getBranchName(),
+ identity(), (a, b) -> a));
assertThat(results).hasSize(5);
- assertLocForProject(results.get(0), "projectWithTieOnBranchSize", DEFAULT_MAIN_BRANCH_NAME, 250);
- assertLocForProject(results.get(1), "projectWithTieOnOtherBranches", "tieBranch1", 230);
- assertLocForProject(results.get(2), "projectWithBranchBiggerThanMaster", "notMasterBranch", 200);
- assertLocForProject(results.get(3), "simpleProject", DEFAULT_MAIN_BRANCH_NAME, 10);
- assertLocForProject(results.get(4), "projectWithLinesButNoLoc", DEFAULT_MAIN_BRANCH_NAME, 0);
+ assertLocForProject(results.get("projectWithTieOnBranchSize main"), DEFAULT_MAIN_BRANCH_NAME, 250);
+ assertLocForProject(results.get("projectWithTieOnOtherBranches tieBranch1"), "tieBranch1", 230);
+ assertLocForProject(results.get("projectWithBranchBiggerThanMaster notMasterBranch"), "notMasterBranch", 200);
+ assertLocForProject(results.get("simpleProject main"), DEFAULT_MAIN_BRANCH_NAME, 10);
+ assertLocForProject(results.get("projectWithLinesButNoLoc main"), DEFAULT_MAIN_BRANCH_NAME, 0);
}
@Test
@@ -417,10 +424,16 @@ public class LiveMeasureDaoIT {
List results = underTest.selectLargestBranchesLocDistribution(db.getSession(), ncloc.getUuid(), nclocLanguageDistribution.getUuid());
+ String firstBranchOfProjectUuid = db.getDbClient().branchDao().selectByProjectUuid(db.getSession(), "projectWithTieOnOtherBranches").stream()
+ .filter(branchDto -> !branchDto.isMain())
+ .map(BranchDto::getUuid)
+ .sorted()
+ .findFirst().orElseThrow();
+
assertThat(results)
.containsExactlyInAnyOrder(
new ProjectLocDistributionDto("projectWithTieOnBranchSize", getMainBranchUuid("projectWithTieOnBranchSize"), "java=250;js=0"),
- new ProjectLocDistributionDto("projectWithTieOnOtherBranches", getBranchUuid("projectWithTieOnOtherBranches", "tieBranch1"), "java=230;js=0"),
+ new ProjectLocDistributionDto("projectWithTieOnOtherBranches", firstBranchOfProjectUuid, "java=230;js=0"),
new ProjectLocDistributionDto("projectWithBranchBiggerThanMaster", getBranchUuid("projectWithBranchBiggerThanMaster", "notMasterBranch"), "java=100;js=100"),
new ProjectLocDistributionDto("simpleProject", getMainBranchUuid("simpleProject"), "java=10;js=0"),
new ProjectLocDistributionDto("projectWithLinesButNoLoc", getMainBranchUuid("projectWithLinesButNoLoc"), "java=0;js=0"));
@@ -775,13 +788,13 @@ public class LiveMeasureDaoIT {
private BranchDto addBranchToProjectWithMeasure(ProjectData project, String branchKey, MetricDto metric, double metricValue) {
BranchDto branch = db.components()
- .insertProjectBranch(project.getProjectDto(), b -> b.setBranchType(BranchType.BRANCH).setKey(branchKey));
+ .insertProjectBranch(project.getProjectDto(), b -> b.setBranchType(BranchType.BRANCH).setKey(branchKey),
+ branchDto -> branchDto.setUuid("uuid_" + branchId++));
addMeasureToBranch(branch, metric, metricValue, true);
return branch;
}
- private void assertLocForProject(LargestBranchNclocDto result, String projectKey, String branchKey, long linesOfCode) {
- assertThat(result.getProjectKey()).isEqualTo(projectKey);
+ private void assertLocForProject(LargestBranchNclocDto result, String branchKey, long linesOfCode) {
assertThat(result.getBranchName()).isEqualTo(branchKey);
assertThat(result.getLoc()).isEqualTo(linesOfCode);
}
diff --git a/server/sonar-db-dao/src/it/java/org/sonar/db/notification/NotificationQueueDaoIT.java b/server/sonar-db-dao/src/it/java/org/sonar/db/notification/NotificationQueueDaoIT.java
index 3299c2ebb84..741047f0363 100644
--- a/server/sonar-db-dao/src/it/java/org/sonar/db/notification/NotificationQueueDaoIT.java
+++ b/server/sonar-db-dao/src/it/java/org/sonar/db/notification/NotificationQueueDaoIT.java
@@ -19,9 +19,6 @@
*/
package org.sonar.db.notification;
-import java.util.Arrays;
-import java.util.List;
-import java.util.stream.IntStream;
import org.junit.Rule;
import org.junit.Test;
import org.mockito.invocation.InvocationOnMock;
@@ -30,10 +27,15 @@ import org.sonar.api.notifications.Notification;
import org.sonar.api.utils.System2;
import org.sonar.db.DbTester;
+import java.util.Arrays;
+import java.util.List;
+import java.util.stream.IntStream;
+
import static java.util.stream.Collectors.toList;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
+import static org.sonar.core.util.SequenceUuidFactory.*;
import static org.sonar.db.notification.NotificationQueueDto.toNotificationQueueDto;
public class NotificationQueueDaoIT {
@@ -101,7 +103,7 @@ public class NotificationQueueDaoIT {
assertThat(dao.selectOldest(3))
.extracting(NotificationQueueDto::getUuid)
- .containsExactlyElementsOf(Arrays.asList("1", "2", "3"));
+ .containsExactlyElementsOf(List.of(UUID_1, UUID_2, UUID_3));
}
private List selectAllUuid() {
diff --git a/server/sonar-db-dao/src/it/java/org/sonar/db/permission/GroupPermissionDaoIT.java b/server/sonar-db-dao/src/it/java/org/sonar/db/permission/GroupPermissionDaoIT.java
index 4fa74696581..fb51c5a3fe0 100644
--- a/server/sonar-db-dao/src/it/java/org/sonar/db/permission/GroupPermissionDaoIT.java
+++ b/server/sonar-db-dao/src/it/java/org/sonar/db/permission/GroupPermissionDaoIT.java
@@ -25,6 +25,7 @@ import java.util.Collections;
import java.util.List;
import java.util.Random;
import java.util.Set;
+import java.util.TreeSet;
import java.util.stream.IntStream;
import java.util.stream.Stream;
import org.junit.Rule;
@@ -453,8 +454,10 @@ public class GroupPermissionDaoIT {
db.users().insertEntityPermissionOnAnyone("perm1", project1);
db.users().insertEntityPermissionOnAnyone("perm1", project2);
db.users().insertEntityPermissionOnAnyone("perm1", project3);
+
+ TreeSet sortedProjectKeys = new TreeSet<>(Set.of(project1.getKey(), project2.getKey(), project3.getKey()));
assertThat(underTest.selectProjectKeysWithAnyonePermissions(dbSession, 3))
- .containsExactly(project1.getKey(), project2.getKey(), project3.getKey());
+ .containsExactlyElementsOf(sortedProjectKeys);
}
@Test
diff --git a/server/sonar-db-dao/src/it/java/org/sonar/db/permission/GroupPermissionDaoWithPersisterIT.java b/server/sonar-db-dao/src/it/java/org/sonar/db/permission/GroupPermissionDaoWithPersisterIT.java
index b067b087053..9355aca8b30 100644
--- a/server/sonar-db-dao/src/it/java/org/sonar/db/permission/GroupPermissionDaoWithPersisterIT.java
+++ b/server/sonar-db-dao/src/it/java/org/sonar/db/permission/GroupPermissionDaoWithPersisterIT.java
@@ -39,6 +39,7 @@ import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoInteractions;
import static org.sonar.api.web.UserRole.ADMIN;
+import static org.sonar.core.util.SequenceUuidFactory.UUID_1;
public class GroupPermissionDaoWithPersisterIT {
private final AuditPersister auditPersister = mock(AuditPersister.class);
@@ -62,7 +63,8 @@ public class GroupPermissionDaoWithPersisterIT {
verify(auditPersister).addGroupPermission(eq(dbSession), newValueCaptor.capture());
GroupPermissionNewValue newValue = newValueCaptor.getValue();
assertNewValue(newValue, dto.getUuid(), group.getUuid(), group.getName(), null, dto.getRole(), null, null, null);
- assertThat(newValue).hasToString("{\"permissionUuid\": \"1\", \"permission\": \"admin\", \"groupUuid\": \"guuid\", \"groupName\": \"gname\" }");
+ assertThat(newValue).hasToString("{\"permissionUuid\": \"" + UUID_1 + "\", \"permission\": \"admin\", \"groupUuid\": \"guuid\", " +
+ "\"groupName\": \"gname\" }");
underTest.delete(dbSession, ADMIN, group.getUuid(), group.getName(), null);
@@ -88,7 +90,8 @@ public class GroupPermissionDaoWithPersisterIT {
assertNewValue(newValue, dto.getUuid(), group.getUuid(), group.getName(), project.projectUuid(), dto.getRole(), project.projectKey(),
project.getProjectDto().getName(), "TRK");
- assertThat(newValue).hasToString("{\"permissionUuid\": \"1\", \"permission\": \"admin\", \"groupUuid\": \"guuid\", \"groupName\": \"gname\"," +
+ assertThat(newValue).hasToString("{\"permissionUuid\": \"" + UUID_1 + "\", \"permission\": \"admin\", \"groupUuid\": \"guuid\", \"groupName\": " +
+ "\"gname\"," +
" \"componentUuid\": \"projectUuid\", \"componentKey\": \"cKey\", \"componentName\": \"cname\", \"qualifier\": \"project\" }");
underTest.deleteByEntityUuid(dbSession, project.getProjectDto());
@@ -97,7 +100,8 @@ public class GroupPermissionDaoWithPersisterIT {
newValue = newValueCaptor.getValue();
assertNewValue(newValue, null, null, null, project.projectUuid(), null, project.projectKey(), project.getProjectDto().getName(), "TRK");
- assertThat(newValue).hasToString("{\"componentUuid\": \"projectUuid\", \"componentKey\": \"cKey\", \"componentName\": \"cname\", \"qualifier\": \"project\" }");
+ assertThat(newValue).hasToString("{\"componentUuid\": \"projectUuid\", \"componentKey\": \"cKey\", \"componentName\": \"cname\", " +
+ "\"qualifier\": \"project\" }");
}
@Test
@@ -116,8 +120,9 @@ public class GroupPermissionDaoWithPersisterIT {
verify(auditPersister).addGroupPermission(eq(dbSession), newValueCaptor.capture());
GroupPermissionNewValue newValue = newValueCaptor.getValue();
- assertNewValue(newValue, dto.getUuid(), null, null, project.projectUuid(), dto.getRole(), project.projectKey(), project.getProjectDto().getName(), "TRK");
- assertThat(newValue).hasToString("{\"permissionUuid\": \"1\", \"permission\": \"admin\", \"componentUuid\": \"projectUuid\", "
+ assertNewValue(newValue, dto.getUuid(), null, null, project.projectUuid(), dto.getRole(), project.projectKey(),
+ project.getProjectDto().getName(), "TRK");
+ assertThat(newValue).hasToString("{\"permissionUuid\": \"" + UUID_1 + "\", \"permission\": \"admin\", \"componentUuid\": \"projectUuid\", "
+ "\"componentKey\": \"cKey\", \"componentName\": \"cname\", \"qualifier\": \"project\" }");
underTest.deleteByEntityUuidForAnyOne(dbSession, project.getProjectDto());
@@ -145,15 +150,18 @@ public class GroupPermissionDaoWithPersisterIT {
verify(auditPersister).addGroupPermission(eq(dbSession), newValueCaptor.capture());
GroupPermissionNewValue newValue = newValueCaptor.getValue();
- assertNewValue(newValue, dto.getUuid(), group.getUuid(), group.getName(), project.projectUuid(), dto.getRole(), project.projectKey(), project.getProjectDto().getName(), "TRK");
- assertThat(newValue).hasToString("{\"permissionUuid\": \"1\", \"permission\": \"admin\", \"groupUuid\": \"guuid\", \"groupName\": \"gname\", "
+ assertNewValue(newValue, dto.getUuid(), group.getUuid(), group.getName(), project.projectUuid(), dto.getRole(), project.projectKey(),
+ project.getProjectDto().getName(), "TRK");
+ assertThat(newValue).hasToString("{\"permissionUuid\": \"" + UUID_1 + "\", \"permission\": \"admin\", \"groupUuid\": \"guuid\", \"groupName\": " +
+ "\"gname\", "
+ "\"componentUuid\": \"projectUuid\", \"componentKey\": \"cKey\", \"componentName\": \"cname\", \"qualifier\": \"project\" }");
underTest.deleteByEntityAndPermission(dbSession, dto.getRole(), project.getProjectDto());
verify(auditPersister).deleteGroupPermission(eq(dbSession), newValueCaptor.capture());
newValue = newValueCaptor.getValue();
- assertNewValue(newValue, null, null, null, project.projectUuid(), ADMIN, project.projectKey(), project.getProjectDto().getName(), "TRK");
+ assertNewValue(newValue, null, null, null, project.projectUuid(), ADMIN, project.projectKey(), project.getProjectDto().getName(),
+ "TRK");
assertThat(newValue).hasToString("{\"permission\": \"admin\", \"componentUuid\": \"projectUuid\", \"componentKey\": \"cKey\"," +
" \"componentName\": \"cname\", \"qualifier\": \"project\" }");
}
@@ -169,7 +177,8 @@ public class GroupPermissionDaoWithPersisterIT {
verifyNoInteractions(auditPersister);
}
- private void assertNewValue(GroupPermissionNewValue newValue, String uuid, String groupUuid, String groupName, String cUuid, String permission,
+ private void assertNewValue(GroupPermissionNewValue newValue, String uuid, String groupUuid, String groupName, String cUuid,
+ String permission,
String componentKey, String cName, String qualifier) {
assertThat(newValue)
.extracting("permissionUuid", "groupUuid", "groupName", "componentUuid", "permission", "componentKey", "componentName", "qualifier")
@@ -202,7 +211,7 @@ public class GroupPermissionDaoWithPersisterIT {
.setGroupName(group != null ? group.getName() : null)
.setRole(ADMIN)
.setEntityUuid(project != null ? project.getUuid() : null)
- .setEntityName(project != null ? project.getName(): null);
+ .setEntityName(project != null ? project.getName() : null);
}
private GroupPermissionDto getGroupPermission(GroupDto group) {
diff --git a/server/sonar-db-dao/src/it/java/org/sonar/db/purge/PurgeCommandsIT.java b/server/sonar-db-dao/src/it/java/org/sonar/db/purge/PurgeCommandsIT.java
index 9c042c63edf..a44162eb39b 100644
--- a/server/sonar-db-dao/src/it/java/org/sonar/db/purge/PurgeCommandsIT.java
+++ b/server/sonar-db-dao/src/it/java/org/sonar/db/purge/PurgeCommandsIT.java
@@ -815,15 +815,15 @@ public class PurgeCommandsIT {
Instant okCreationDate = Instant.now().minus(29, ChronoUnit.DAYS);
Instant oldCreationDate = Instant.now().minus(31, ChronoUnit.DAYS);
- dbTester.getDbClient().anticipatedTransitionDao().insert(dbTester.getSession(), getAnticipatedTransitionsDto(projectDto.uuid() + "okTransition", projectDto.uuid(), okCreationDate));
- dbTester.getDbClient().anticipatedTransitionDao().insert(dbTester.getSession(), getAnticipatedTransitionsDto(projectDto.uuid() + "oldTransition", projectDto.uuid(), oldCreationDate));
+ dbTester.getDbClient().anticipatedTransitionDao().insert(dbTester.getSession(), getAnticipatedTransitionsDto(projectDto.uuid() + "ok", projectDto.uuid(), okCreationDate));
+ dbTester.getDbClient().anticipatedTransitionDao().insert(dbTester.getSession(), getAnticipatedTransitionsDto(projectDto.uuid() + "old", projectDto.uuid(), oldCreationDate));
underTest.deleteAnticipatedTransitions(projectDto.uuid(), Instant.now().minus(30, ChronoUnit.DAYS).toEpochMilli());
List anticipatedTransitionDtos = dbTester.getDbClient().anticipatedTransitionDao().selectByProjectUuid(dbTester.getSession(), projectDto.uuid());
assertThat(anticipatedTransitionDtos).hasSize(1);
- assertThat(anticipatedTransitionDtos.get(0).getUuid()).isEqualTo(projectDto.uuid() + "okTransition");
+ assertThat(anticipatedTransitionDtos.get(0).getUuid()).isEqualTo(projectDto.uuid() + "ok");
}
@Test
diff --git a/server/sonar-db-dao/src/it/java/org/sonar/db/pushevent/PushEventDaoIT.java b/server/sonar-db-dao/src/it/java/org/sonar/db/pushevent/PushEventDaoIT.java
index 33d3eb07596..8447c7b116d 100644
--- a/server/sonar-db-dao/src/it/java/org/sonar/db/pushevent/PushEventDaoIT.java
+++ b/server/sonar-db-dao/src/it/java/org/sonar/db/pushevent/PushEventDaoIT.java
@@ -19,8 +19,11 @@
*/
package org.sonar.db.pushevent;
+import java.util.Comparator;
+import java.util.List;
import java.util.Set;
import java.util.stream.IntStream;
+import java.util.stream.Stream;
import org.junit.Rule;
import org.junit.Test;
import org.sonar.api.impl.utils.TestSystem2;
@@ -69,7 +72,8 @@ public class PushEventDaoIT {
assertThat(underTest.selectByUuid(session, generatedUuid.getUuid()))
.extracting(PushEventDto::getUuid, PushEventDto::getProjectUuid, PushEventDto::getPayload, PushEventDto::getCreatedAt)
- .containsExactly(eventDtoSecond.getUuid(), eventDtoSecond.getProjectUuid(), eventDtoSecond.getPayload(), eventDtoSecond.getCreatedAt());
+ .containsExactly(eventDtoSecond.getUuid(), eventDtoSecond.getProjectUuid(), eventDtoSecond.getPayload(),
+ eventDtoSecond.getCreatedAt());
}
@@ -147,7 +151,12 @@ public class PushEventDaoIT {
var eventDto7 = generatePushEvent("proj2");
events = underTest.selectChunkByProjectUuids(session, Set.of("proj1", "proj2"), eventDto4.getCreatedAt(), eventDto4.getUuid(), 10);
- assertThat(events).extracting(PushEventDto::getUuid).containsExactly(eventDto5.getUuid(), eventDto6.getUuid(), eventDto7.getUuid());
+ List sortedUuids = Stream.of(eventDto5, eventDto6, eventDto7)
+ .sorted(Comparator.comparing(PushEventDto::getCreatedAt).thenComparing(PushEventDto::getUuid))
+ .map(PushEventDto::getUuid)
+ .toList();
+
+ assertThat(events).extracting(PushEventDto::getUuid).containsExactlyElementsOf(sortedUuids);
}
@Test
diff --git a/server/sonar-db-dao/src/it/java/org/sonar/db/qualityprofile/QProfileEditGroupsDaoIT.java b/server/sonar-db-dao/src/it/java/org/sonar/db/qualityprofile/QProfileEditGroupsDaoIT.java
index b45bc3291a9..e31ea5316cb 100644
--- a/server/sonar-db-dao/src/it/java/org/sonar/db/qualityprofile/QProfileEditGroupsDaoIT.java
+++ b/server/sonar-db-dao/src/it/java/org/sonar/db/qualityprofile/QProfileEditGroupsDaoIT.java
@@ -19,7 +19,7 @@
*/
package org.sonar.db.qualityprofile;
-import java.util.List;
+import java.util.Map;
import org.junit.Rule;
import org.junit.Test;
import org.mockito.ArgumentCaptor;
@@ -35,6 +35,8 @@ import org.sonar.db.user.SearchGroupMembershipDto;
import static java.util.Arrays.asList;
import static java.util.Collections.emptyList;
import static java.util.Collections.singletonList;
+import static java.util.function.Function.identity;
+import static java.util.stream.Collectors.toMap;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.entry;
import static org.assertj.core.api.Assertions.tuple;
@@ -282,17 +284,19 @@ public class QProfileEditGroupsDaoIT {
verify(auditPersister, times(2)).deleteQualityProfileEditor(eq(db.getSession()), newValueCaptor.capture());
- List newValues = newValueCaptor.getAllValues();
- assertThat(newValues.get(0))
+ Map newValues = newValueCaptor.getAllValues().stream()
+ .collect(toMap(GroupEditorNewValue::getQualityProfileName, identity()));
+
+ assertThat(newValues.get(profile1.getName()))
.extracting(GroupEditorNewValue::getQualityProfileName, GroupEditorNewValue::getQualityProfileUuid,
GroupEditorNewValue::getGroupName, GroupEditorNewValue::getGroupUuid)
.containsExactly(profile1.getName(), profile1.getKee(), null, null);
- assertThat(newValues.get(0).toString()).contains("\"qualityProfileName\"").doesNotContain("\"groupName\"");
- assertThat(newValues.get(1))
+ assertThat(newValues.get(profile1.getName()).toString()).contains("\"qualityProfileName\"").doesNotContain("\"groupName\"");
+ assertThat(newValues.get(profile2.getName()))
.extracting(GroupEditorNewValue::getQualityProfileName, GroupEditorNewValue::getQualityProfileUuid,
GroupEditorNewValue::getGroupName, GroupEditorNewValue::getGroupUuid)
.containsExactly(profile2.getName(), profile2.getKee(), null, null);
- assertThat(newValues.get(1).toString()).contains("\"qualityProfileName\"").doesNotContain("\"groupName\"");
+ assertThat(newValues.get(profile2.getName()).toString()).contains("\"qualityProfileName\"").doesNotContain("\"groupName\"");
assertThat(underTest.exists(db.getSession(), profile1, group1)).isFalse();
assertThat(underTest.exists(db.getSession(), profile2, group2)).isFalse();
diff --git a/server/sonar-db-dao/src/it/java/org/sonar/db/qualityprofile/QProfileEditUsersDaoIT.java b/server/sonar-db-dao/src/it/java/org/sonar/db/qualityprofile/QProfileEditUsersDaoIT.java
index 6f0e94a24e6..10ce71b1163 100644
--- a/server/sonar-db-dao/src/it/java/org/sonar/db/qualityprofile/QProfileEditUsersDaoIT.java
+++ b/server/sonar-db-dao/src/it/java/org/sonar/db/qualityprofile/QProfileEditUsersDaoIT.java
@@ -20,7 +20,7 @@
package org.sonar.db.qualityprofile;
import java.sql.SQLException;
-import java.util.List;
+import java.util.Map;
import org.junit.Rule;
import org.junit.Test;
import org.mockito.ArgumentCaptor;
@@ -34,6 +34,8 @@ import org.sonar.db.user.SearchUserMembershipDto;
import org.sonar.db.user.UserDto;
import static java.util.Arrays.asList;
+import static java.util.function.Function.identity;
+import static java.util.stream.Collectors.toMap;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.entry;
import static org.assertj.core.api.Assertions.tuple;
@@ -302,17 +304,16 @@ public class QProfileEditUsersDaoIT {
verify(auditPersister, times(2)).deleteQualityProfileEditor(eq(db.getSession()), newValueCaptor.capture());
- List newValues = newValueCaptor.getAllValues();
- assertThat(newValues.get(0))
- .extracting(UserEditorNewValue::getQualityProfileName, UserEditorNewValue::getQualityProfileUuid,
- UserEditorNewValue::getUserLogin, UserEditorNewValue::getUserUuid)
- .containsExactly(profile1.getName(), profile1.getKee(), null, null);
- assertThat(newValues.get(0).toString()).contains("\"qualityProfileName\"").doesNotContain("\"groupName\"");
- assertThat(newValues.get(1))
- .extracting(UserEditorNewValue::getQualityProfileName, UserEditorNewValue::getQualityProfileUuid,
- UserEditorNewValue::getUserLogin, UserEditorNewValue::getUserUuid)
- .containsExactly(profile2.getName(), profile2.getKee(), null, null);
- assertThat(newValues.get(1).toString()).contains("\"qualityProfileName\"").doesNotContain("\"groupName\"");
+ Map newValues = newValueCaptor.getAllValues().stream()
+ .collect(toMap(UserEditorNewValue::getQualityProfileName, identity()));
+ assertThat(newValues.get(profile1.getName()))
+ .extracting(UserEditorNewValue::getQualityProfileUuid, UserEditorNewValue::getUserLogin, UserEditorNewValue::getUserUuid)
+ .containsExactly(profile1.getKee(), null, null);
+ assertThat(newValues.get(profile1.getName()).toString()).contains("\"qualityProfileName\"").doesNotContain("\"groupName\"");
+ assertThat(newValues.get(profile2.getName()))
+ .extracting(UserEditorNewValue::getQualityProfileUuid, UserEditorNewValue::getUserLogin, UserEditorNewValue::getUserUuid)
+ .containsExactly(profile2.getKee(), null, null);
+ assertThat(newValues.get(profile2.getName()).toString()).contains("\"qualityProfileName\"").doesNotContain("\"groupName\"");
assertThat(underTest.exists(db.getSession(), profile1, user1)).isFalse();
assertThat(underTest.exists(db.getSession(), profile2, user2)).isFalse();
diff --git a/server/sonar-db-dao/src/it/java/org/sonar/db/qualityprofile/QualityProfileDaoIT.java b/server/sonar-db-dao/src/it/java/org/sonar/db/qualityprofile/QualityProfileDaoIT.java
index 04fbf0678aa..7b9c7c99376 100644
--- a/server/sonar-db-dao/src/it/java/org/sonar/db/qualityprofile/QualityProfileDaoIT.java
+++ b/server/sonar-db-dao/src/it/java/org/sonar/db/qualityprofile/QualityProfileDaoIT.java
@@ -699,7 +699,7 @@ public class QualityProfileDaoIT {
db.qualityProfiles().associateWithProject(project2, jsProfile);
assertThat(underTest.selectQProfilesByProjectUuid(dbSession, project1.getUuid()))
- .containsExactly(javaProfile, cProfile);
+ .containsExactlyInAnyOrder(javaProfile, cProfile);
assertThat(underTest.selectQProfilesByProjectUuid(dbSession, project2.getUuid()))
.containsExactly(jsProfile);
diff --git a/server/sonar-db-dao/src/it/java/org/sonar/db/user/RoleDaoIT.java b/server/sonar-db-dao/src/it/java/org/sonar/db/user/RoleDaoIT.java
index 775a2e263f5..a8fff65d9e8 100644
--- a/server/sonar-db-dao/src/it/java/org/sonar/db/user/RoleDaoIT.java
+++ b/server/sonar-db-dao/src/it/java/org/sonar/db/user/RoleDaoIT.java
@@ -57,8 +57,8 @@ public class RoleDaoIT {
public void setUp() {
user1 = db.users().insertUser();
user2 = db.users().insertUser();
- project1 = db.components().insertPrivateProject().getProjectDto();
- project2 = db.components().insertPrivateProject().getProjectDto();
+ project1 = db.components().insertPrivateProject(project -> project.setName("project1")).getProjectDto();
+ project2 = db.components().insertPrivateProject(project -> project.setName("project2")).getProjectDto();
}
@Test
@@ -111,7 +111,7 @@ public class RoleDaoIT {
List result = underTest.selectEntityUuidsByPermissionAndUserUuidAndQualifier(dbSession, UserRole.ADMIN, user1.getUuid(), PROJECT_QUALIFIER);
- assertThat(result).containsExactly(project1.getUuid(), project2.getUuid());
+ assertThat(result).containsExactlyInAnyOrder(project1.getUuid(), project2.getUuid());
}
@Test
diff --git a/server/sonar-db-dao/src/it/java/org/sonar/db/user/UserGroupDaoIT.java b/server/sonar-db-dao/src/it/java/org/sonar/db/user/UserGroupDaoIT.java
index d1fea6009fb..6124ee720da 100644
--- a/server/sonar-db-dao/src/it/java/org/sonar/db/user/UserGroupDaoIT.java
+++ b/server/sonar-db-dao/src/it/java/org/sonar/db/user/UserGroupDaoIT.java
@@ -32,6 +32,9 @@ import org.sonar.db.DbSession;
import org.sonar.db.DbTester;
import static org.assertj.core.api.Assertions.assertThat;
+import static org.sonar.core.util.SequenceUuidFactory.UUID_1;
+import static org.sonar.core.util.SequenceUuidFactory.UUID_2;
+import static org.sonar.core.util.SequenceUuidFactory.UUID_3;
@RunWith(DataProviderRunner.class)
public class UserGroupDaoIT {
@@ -129,40 +132,40 @@ public class UserGroupDaoIT {
return new Object[][] {
{new UserGroupQuery(null, null, null),
List.of(
- new UserGroupDto().setUuid("3").setGroupUuid("group_a").setUserUuid("1"),
- new UserGroupDto().setUuid("4").setGroupUuid("group_a").setUserUuid("2"),
- new UserGroupDto().setUuid("5").setGroupUuid("group_b").setUserUuid("1"),
- new UserGroupDto().setUuid("6").setGroupUuid("group_b").setUserUuid("2")
+ new UserGroupDto().setUuid("3").setGroupUuid("group_a").setUserUuid(UUID_1),
+ new UserGroupDto().setUuid("4").setGroupUuid("group_a").setUserUuid(UUID_2),
+ new UserGroupDto().setUuid("5").setGroupUuid("group_b").setUserUuid(UUID_1),
+ new UserGroupDto().setUuid("6").setGroupUuid("group_b").setUserUuid(UUID_2)
)},
- {new UserGroupQuery("3", null, null),
+ {new UserGroupQuery(UUID_3, null, null),
List.of(
- new UserGroupDto().setUuid("3").setGroupUuid("group_a").setUserUuid("1")
+ new UserGroupDto().setUuid(UUID_3).setGroupUuid("group_a").setUserUuid(UUID_1)
)},
- {new UserGroupQuery("3", "group_a", "1"),
+ {new UserGroupQuery(UUID_3, "group_a", UUID_1),
List.of(
- new UserGroupDto().setUuid("3").setGroupUuid("group_a").setUserUuid("1")
+ new UserGroupDto().setUuid(UUID_3).setGroupUuid("group_a").setUserUuid(UUID_1)
)},
- {new UserGroupQuery("3", "group_b", "1"),
+ {new UserGroupQuery(UUID_3, "group_b", UUID_1),
List.of()},
{new UserGroupQuery(null,"group_b", null),
List.of(
- new UserGroupDto().setUuid("5").setGroupUuid("group_b").setUserUuid("1"),
- new UserGroupDto().setUuid("6").setGroupUuid("group_b").setUserUuid("2")
+ new UserGroupDto().setUuid("5").setGroupUuid("group_b").setUserUuid(UUID_1),
+ new UserGroupDto().setUuid("6").setGroupUuid("group_b").setUserUuid(UUID_2)
)},
- {new UserGroupQuery(null,null, "2"),
+ {new UserGroupQuery(null,null, UUID_2),
List.of(
- new UserGroupDto().setUuid("4").setGroupUuid("group_a").setUserUuid("2"),
- new UserGroupDto().setUuid("6").setGroupUuid("group_b").setUserUuid("2")
+ new UserGroupDto().setUuid("4").setGroupUuid("group_a").setUserUuid(UUID_2),
+ new UserGroupDto().setUuid("6").setGroupUuid("group_b").setUserUuid(UUID_2)
)},
- {new UserGroupQuery(null,"group_a", "2"),
+ {new UserGroupQuery(null,"group_a", UUID_2),
List.of(
- new UserGroupDto().setUuid("4").setGroupUuid("group_a").setUserUuid("2")
+ new UserGroupDto().setUuid("4").setGroupUuid("group_a").setUserUuid(UUID_2)
)},
{new UserGroupQuery(null,"group_c", null),
List.of()},
- {new UserGroupQuery(null,"group_c", "2"),
+ {new UserGroupQuery(null,"group_c", UUID_2),
List.of()},
- {new UserGroupQuery(null,"group_a", "3"),
+ {new UserGroupQuery(null,"group_a", UUID_3),
List.of()}
};
}
@@ -174,7 +177,7 @@ public class UserGroupDaoIT {
List userGroupDtos = underTest.selectByQuery(dbTester.getSession(), userQuery, 1, 100);
- assertThat(userGroupDtos).usingRecursiveFieldByFieldElementComparator().isEqualTo(expectedUserGroupDtos);
+ assertThat(userGroupDtos).usingRecursiveFieldByFieldElementComparatorIgnoringFields("uuid").isEqualTo(expectedUserGroupDtos);
assertThat(underTest.countByQuery(dbTester.getSession(), userQuery)).isEqualTo(expectedUserGroupDtos.size());
}
diff --git a/server/sonar-db-dao/src/main/java/org/sonar/db/user/UserGroupDto.java b/server/sonar-db-dao/src/main/java/org/sonar/db/user/UserGroupDto.java
index c44791a161b..378af5af47f 100644
--- a/server/sonar-db-dao/src/main/java/org/sonar/db/user/UserGroupDto.java
+++ b/server/sonar-db-dao/src/main/java/org/sonar/db/user/UserGroupDto.java
@@ -73,4 +73,5 @@ public class UserGroupDto {
public int hashCode() {
return Objects.hash(userUuid, groupUuid);
}
+
}
diff --git a/server/sonar-db-dao/src/main/resources/org/sonar/db/measure/LiveMeasureMapper.xml b/server/sonar-db-dao/src/main/resources/org/sonar/db/measure/LiveMeasureMapper.xml
index 33fc01d7355..d43d11c2db5 100644
--- a/server/sonar-db-dao/src/main/resources/org/sonar/db/measure/LiveMeasureMapper.xml
+++ b/server/sonar-db-dao/src/main/resources/org/sonar/db/measure/LiveMeasureMapper.xml
@@ -91,7 +91,7 @@
pb.kee as branchName,
pb.branch_type as branchType,
lm.value as ncloc,
- row_number() over (partition by pb.project_uuid order by lm.value desc, pb.uuid asc) row_number
+ row_number() over (partition by pb.project_uuid order by lm.value desc, pb.is_main desc, pb.uuid asc) row_number
from live_measures lm
inner join project_branches pb on pb.uuid = lm.component_uuid
inner join projects p on p.uuid = pb.project_uuid
@@ -109,7 +109,7 @@
SELECT loc_grouped_branches.uuid, loc_grouped_branches.project_uuid
FROM (
SELECT b.uuid, b.project_uuid, ROW_NUMBER() OVER (PARTITION BY
- b.project_uuid ORDER BY lm.value desc, b.uuid asc) row_number
+ b.project_uuid ORDER BY lm.value desc, b.is_main desc, b.uuid asc) row_number
from live_measures lm
inner join project_branches b on b.uuid = lm.component_uuid
inner join projects p on p.uuid = b.project_uuid
diff --git a/server/sonar-db-migration/src/it/java/org/sonar/server/platform/db/migration/version/v100/RemoveOrphanRulesFromQualityProfilesIT.java b/server/sonar-db-migration/src/it/java/org/sonar/server/platform/db/migration/version/v100/RemoveOrphanRulesFromQualityProfilesIT.java
index 44f403ccad5..663ac914ded 100644
--- a/server/sonar-db-migration/src/it/java/org/sonar/server/platform/db/migration/version/v100/RemoveOrphanRulesFromQualityProfilesIT.java
+++ b/server/sonar-db-migration/src/it/java/org/sonar/server/platform/db/migration/version/v100/RemoveOrphanRulesFromQualityProfilesIT.java
@@ -35,6 +35,7 @@ import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.tuple;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
+import static org.sonar.core.util.SequenceUuidFactory.UUID_1;
public class RemoveOrphanRulesFromQualityProfilesIT {
@@ -121,7 +122,7 @@ public class RemoveOrphanRulesFromQualityProfilesIT {
private void assertQualityProfileChanges() {
assertThat(db.select("SELECT * from qprofile_changes"))
.extracting(r -> r.get("KEE"), r -> r.get("RULES_PROFILE_UUID"), r -> r.get("CHANGE_TYPE"), r -> r.get("USER_UUID"), r -> r.get("CHANGE_DATA"), r -> r.get("CREATED_AT"))
- .containsExactly(tuple("1", "uuid-profile-1", "DEACTIVATED", null, "ruleUuid=uuid-rule-2", 1L));
+ .containsExactly(tuple(UUID_1, "uuid-profile-1", "DEACTIVATED", null, "ruleUuid=uuid-rule-2", 1L));
}
diff --git a/server/sonar-server-common/src/main/java/org/sonar/server/platform/serverid/MacAddressProvider.java b/server/sonar-server-common/src/main/java/org/sonar/server/platform/serverid/MacAddressProvider.java
new file mode 100644
index 00000000000..91b5f7d99c1
--- /dev/null
+++ b/server/sonar-server-common/src/main/java/org/sonar/server/platform/serverid/MacAddressProvider.java
@@ -0,0 +1,109 @@
+/*
+ * 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.server.platform.serverid;
+
+import com.google.common.annotations.VisibleForTesting;
+import java.net.NetworkInterface;
+import java.net.SocketException;
+import java.security.SecureRandom;
+import java.util.Enumeration;
+import javax.annotation.CheckForNull;
+import javax.annotation.Nullable;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.sonar.core.util.UuidFactoryImpl;
+
+/**
+ * Used by {@link UuidFactoryImpl}. Heavily inspired by https://github.com/elastic/elasticsearch/blob/master/core/src/main/java/org/elasticsearch/common/MacAddressProvider.java
+ */
+class MacAddressProvider {
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(MacAddressProvider.class);
+ public static final int BYTE_SIZE = 6;
+
+ private MacAddressProvider() {
+ // only static stuff
+ }
+
+ public static byte[] getSecureMungedAddress() {
+ byte[] address = null;
+ try {
+ address = getMacAddress();
+ } catch (SocketException se) {
+ LOGGER.warn("Unable to get mac address, will use a dummy address", se);
+ // address will be set below
+ }
+
+ if (!isValidAddress(address)) {
+ LOGGER.warn("Unable to get a valid mac address, will use a dummy address");
+ address = constructDummyMulticastAddress();
+ }
+
+ byte[] mungedBytes = new byte[BYTE_SIZE];
+ new SecureRandom().nextBytes(mungedBytes);
+ for (int i = 0; i < BYTE_SIZE; ++i) {
+ mungedBytes[i] ^= address[i];
+ }
+
+ return mungedBytes;
+ }
+
+ private static boolean isValidAddress(@Nullable byte[] address) {
+ if (address == null || address.length != BYTE_SIZE) {
+ return false;
+ }
+ for (byte b : address) {
+ if (b != 0x00) {
+ // If any of the bytes are non zero assume a good address
+ return true;
+ }
+ }
+ return false;
+ }
+
+ @CheckForNull
+ private static byte[] getMacAddress() throws SocketException {
+ Enumeration en = NetworkInterface.getNetworkInterfaces();
+ if (en != null) {
+ while (en.hasMoreElements()) {
+ NetworkInterface nint = en.nextElement();
+ if (!nint.isLoopback()) {
+ // Pick the first valid non loopback address we find
+ byte[] address = nint.getHardwareAddress();
+ if (isValidAddress(address)) {
+ return address;
+ }
+ }
+ }
+ }
+ // Could not find a mac address
+ return null;
+ }
+
+ @VisibleForTesting
+ static byte[] constructDummyMulticastAddress() {
+ byte[] dummy = new byte[BYTE_SIZE];
+ new SecureRandom().nextBytes(dummy);
+ // Set the broadcast bit to indicate this is not a _real_ mac address
+ dummy[0] |= (byte) 0x01;
+ return dummy;
+ }
+
+}
diff --git a/server/sonar-server-common/src/main/java/org/sonar/server/platform/serverid/ServerIdGenerator.java b/server/sonar-server-common/src/main/java/org/sonar/server/platform/serverid/ServerIdGenerator.java
new file mode 100644
index 00000000000..a25738b3392
--- /dev/null
+++ b/server/sonar-server-common/src/main/java/org/sonar/server/platform/serverid/ServerIdGenerator.java
@@ -0,0 +1,99 @@
+/*
+ * 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.server.platform.serverid;
+
+import java.security.SecureRandom;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.function.Supplier;
+import org.apache.commons.codec.binary.Base64;
+
+public final class ServerIdGenerator {
+
+ private final FullNewIdGenerator fullNewIdGenerator = new FullNewIdGenerator();
+
+ public String generate() {
+ return Base64.encodeBase64URLSafeString(fullNewIdGenerator.get());
+ }
+
+ private static class IdGeneratorBase {
+ // We only use bottom 3 bytes for the sequence number. Paranoia: init with random int so that if JVM/OS/machine goes down, clock slips
+ // backwards, and JVM comes back up, we are less likely to be on the same sequenceNumber at the same time:
+ private final AtomicInteger sequenceNumber = new AtomicInteger(new SecureRandom().nextInt());
+ private final byte[] secureMungedAddress = MacAddressProvider.getSecureMungedAddress();
+ // Used to ensure clock moves forward
+ private long lastTimestamp = 0L;
+
+ void initBase(byte[] buffer, int sequenceId) {
+ long timestamp = System.currentTimeMillis();
+
+ synchronized (this) {
+ // Don't let timestamp go backwards, at least "on our watch" (while this JVM is running). We are still vulnerable if we are
+ // shut down, clock goes backwards, and we restart... for this we randomize the sequenceNumber on init to decrease chance of
+ // collision:
+ timestamp = Math.max(lastTimestamp, timestamp);
+
+ if (sequenceId == 0) {
+ // Always force the clock to increment whenever sequence number is 0, in case we have a long time-slip backwards:
+ timestamp++;
+ }
+
+ lastTimestamp = timestamp;
+ }
+
+ // Only use lower 6 bytes of the timestamp (this will suffice beyond the year 10000):
+ putLong(buffer, timestamp, 0, 6);
+
+ // MAC address adds 6 bytes:
+ System.arraycopy(secureMungedAddress, 0, buffer, 6, secureMungedAddress.length);
+ }
+
+ protected byte[] generate(byte[] buffer, int increment) {
+ // Sequence number adds 3 bytes
+ putLong(buffer, increment, 12, 3);
+
+ return buffer;
+ }
+
+ int getSequenceId() {
+ return sequenceNumber.incrementAndGet() & 0xffffff;
+ }
+
+ /**
+ * Puts the lower numberOfLongBytes from l into the array, starting index pos.
+ */
+ private static void putLong(byte[] array, long l, int pos, int numberOfLongBytes) {
+ for (int i = 0; i < numberOfLongBytes; ++i) {
+ array[pos + numberOfLongBytes - i - 1] = (byte) (l >>> (i * 8));
+ }
+ }
+ }
+
+ private static final class FullNewIdGenerator extends IdGeneratorBase implements Supplier {
+
+ @Override
+ public byte[] get() {
+ byte[] buffer = new byte[15];
+ int sequenceId = getSequenceId();
+ initBase(buffer, sequenceId);
+ return super.generate(buffer, sequenceId);
+ }
+ }
+
+}
diff --git a/server/sonar-server-common/src/test/java/org/sonar/server/platform/serverid/MacAddressProviderTest.java b/server/sonar-server-common/src/test/java/org/sonar/server/platform/serverid/MacAddressProviderTest.java
new file mode 100644
index 00000000000..6babb49a4cb
--- /dev/null
+++ b/server/sonar-server-common/src/test/java/org/sonar/server/platform/serverid/MacAddressProviderTest.java
@@ -0,0 +1,43 @@
+/*
+ * 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.server.platform.serverid;
+
+import org.junit.Test;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+public class MacAddressProviderTest {
+
+ @Test
+ public void getSecureMungedAddress() {
+ byte[] address = MacAddressProvider.getSecureMungedAddress();
+ assertThat(address)
+ .isNotEmpty()
+ .hasSize(6);
+ }
+
+ @Test
+ public void constructDummyMulticastAddress() {
+ byte[] address = MacAddressProvider.constructDummyMulticastAddress();
+ assertThat(address)
+ .isNotEmpty()
+ .hasSize(6);
+ }
+}
diff --git a/server/sonar-server-common/src/test/java/org/sonar/server/platform/serverid/ServerIdGeneratorTest.java b/server/sonar-server-common/src/test/java/org/sonar/server/platform/serverid/ServerIdGeneratorTest.java
new file mode 100644
index 00000000000..dcb13c12b60
--- /dev/null
+++ b/server/sonar-server-common/src/test/java/org/sonar/server/platform/serverid/ServerIdGeneratorTest.java
@@ -0,0 +1,59 @@
+/*
+ * 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.server.platform.serverid;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import org.junit.Test;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+public class ServerIdGeneratorTest {
+ private final ServerIdGenerator underTest = new ServerIdGenerator();
+
+ @Test
+ public void generate_concurrent_test() throws InterruptedException {
+ int rounds = 500;
+ List ids1 = new ArrayList<>(rounds);
+ List ids2 = new ArrayList<>(rounds);
+ Thread t1 = new Thread(() -> {
+ for (int i = 0; i < rounds; i++) {
+ ids1.add(underTest.generate());
+ }
+ });
+ Thread t2 = new Thread(() -> {
+ for (int i = 0; i < rounds; i++) {
+ ids2.add(underTest.generate());
+ }
+ });
+ t1.start();
+ t2.start();
+ t1.join();
+ t2.join();
+
+ Set ids = new HashSet<>(rounds * 2);
+ ids.addAll(ids1);
+ ids.addAll(ids2);
+ assertThat(ids).hasSize(rounds * 2);
+ }
+
+}
diff --git a/server/sonar-webserver-core/src/main/java/org/sonar/server/platform/serverid/ServerIdFactoryImpl.java b/server/sonar-webserver-core/src/main/java/org/sonar/server/platform/serverid/ServerIdFactoryImpl.java
index 4ced9a60b8f..2951a33ee2c 100644
--- a/server/sonar-webserver-core/src/main/java/org/sonar/server/platform/serverid/ServerIdFactoryImpl.java
+++ b/server/sonar-webserver-core/src/main/java/org/sonar/server/platform/serverid/ServerIdFactoryImpl.java
@@ -26,25 +26,24 @@ import java.util.zip.CRC32;
import org.apache.commons.lang.StringUtils;
import org.sonar.api.config.Configuration;
import org.sonar.core.platform.ServerId;
-import org.sonar.core.util.UuidFactory;
import static org.sonar.process.ProcessProperties.Property.JDBC_URL;
public class ServerIdFactoryImpl implements ServerIdFactory {
private final Configuration config;
- private final UuidFactory uuidFactory;
+ private final ServerIdGenerator serverIdGenerator;
private final JdbcUrlSanitizer jdbcUrlSanitizer;
- public ServerIdFactoryImpl(Configuration config, UuidFactory uuidFactory, JdbcUrlSanitizer jdbcUrlSanitizer) {
+ public ServerIdFactoryImpl(Configuration config, ServerIdGenerator serverIdGenerator, JdbcUrlSanitizer jdbcUrlSanitizer) {
this.config = config;
- this.uuidFactory = uuidFactory;
+ this.serverIdGenerator = serverIdGenerator;
this.jdbcUrlSanitizer = jdbcUrlSanitizer;
}
@Override
public ServerId create() {
- return ServerId.of(computeDatabaseId(), uuidFactory.create());
+ return ServerId.of(computeDatabaseId(), serverIdGenerator.generate());
}
@Override
diff --git a/server/sonar-webserver-core/src/main/java/org/sonar/server/platform/serverid/ServerIdModule.java b/server/sonar-webserver-core/src/main/java/org/sonar/server/platform/serverid/ServerIdModule.java
index 1df5c1c7968..b1b76e0ad7f 100644
--- a/server/sonar-webserver-core/src/main/java/org/sonar/server/platform/serverid/ServerIdModule.java
+++ b/server/sonar-webserver-core/src/main/java/org/sonar/server/platform/serverid/ServerIdModule.java
@@ -28,8 +28,8 @@ public class ServerIdModule extends Module {
ServerIdFactoryImpl.class,
JdbcUrlSanitizer.class,
ServerIdChecksum.class,
- ServerIdManager.class
-
+ ServerIdManager.class,
+ ServerIdGenerator.class
);
}
}
diff --git a/server/sonar-webserver-core/src/main/java/org/sonar/server/platform/web/requestid/HttpRequestIdModule.java b/server/sonar-webserver-core/src/main/java/org/sonar/server/platform/web/requestid/HttpRequestIdModule.java
index 57973cdedda..b52fd08ea3a 100644
--- a/server/sonar-webserver-core/src/main/java/org/sonar/server/platform/web/requestid/HttpRequestIdModule.java
+++ b/server/sonar-webserver-core/src/main/java/org/sonar/server/platform/web/requestid/HttpRequestIdModule.java
@@ -24,8 +24,6 @@ import org.sonar.core.platform.Module;
public class HttpRequestIdModule extends Module {
@Override
protected void configureModule() {
- add(new RequestIdConfiguration(RequestIdGeneratorImpl.UUID_GENERATOR_RENEWAL_COUNT),
- RequestIdGeneratorBaseImpl.class,
- RequestIdGeneratorImpl.class);
+ add(RequestIdGeneratorImpl.class);
}
}
diff --git a/server/sonar-webserver-core/src/main/java/org/sonar/server/platform/web/requestid/RequestIdConfiguration.java b/server/sonar-webserver-core/src/main/java/org/sonar/server/platform/web/requestid/RequestIdConfiguration.java
deleted file mode 100644
index 5a204b5a082..00000000000
--- a/server/sonar-webserver-core/src/main/java/org/sonar/server/platform/web/requestid/RequestIdConfiguration.java
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * 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.server.platform.web.requestid;
-
-public class RequestIdConfiguration {
- /**
- * @see RequestIdGeneratorImpl#mustRenewUuidGenerator(long)
- */
- private final long uuidGeneratorRenewalCount;
-
- public RequestIdConfiguration(long uuidGeneratorRenewalCount) {
- this.uuidGeneratorRenewalCount = uuidGeneratorRenewalCount;
- }
-
- public long getUidGeneratorRenewalCount() {
- return uuidGeneratorRenewalCount;
- }
-}
diff --git a/server/sonar-webserver-core/src/main/java/org/sonar/server/platform/web/requestid/RequestIdGeneratorBase.java b/server/sonar-webserver-core/src/main/java/org/sonar/server/platform/web/requestid/RequestIdGeneratorBase.java
deleted file mode 100644
index c1277cad542..00000000000
--- a/server/sonar-webserver-core/src/main/java/org/sonar/server/platform/web/requestid/RequestIdGeneratorBase.java
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * 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.server.platform.web.requestid;
-
-import org.sonar.core.util.UuidGenerator;
-
-public interface RequestIdGeneratorBase {
- /**
- * Provides a new instance of {@link UuidGenerator.WithFixedBase} to be used by {@link RequestIdGeneratorImpl}.
- */
- UuidGenerator.WithFixedBase createNew();
-}
diff --git a/server/sonar-webserver-core/src/main/java/org/sonar/server/platform/web/requestid/RequestIdGeneratorBaseImpl.java b/server/sonar-webserver-core/src/main/java/org/sonar/server/platform/web/requestid/RequestIdGeneratorBaseImpl.java
deleted file mode 100644
index a0284897edd..00000000000
--- a/server/sonar-webserver-core/src/main/java/org/sonar/server/platform/web/requestid/RequestIdGeneratorBaseImpl.java
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * 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.server.platform.web.requestid;
-
-import org.sonar.core.util.UuidGenerator;
-import org.sonar.core.util.UuidGeneratorImpl;
-
-public class RequestIdGeneratorBaseImpl implements RequestIdGeneratorBase {
-
- @Override
- public UuidGenerator.WithFixedBase createNew() {
- return new UuidGeneratorImpl().withFixedBase();
- }
-}
diff --git a/server/sonar-webserver-core/src/main/java/org/sonar/server/platform/web/requestid/RequestIdGeneratorImpl.java b/server/sonar-webserver-core/src/main/java/org/sonar/server/platform/web/requestid/RequestIdGeneratorImpl.java
index 198f3ae8373..9dbb734a027 100644
--- a/server/sonar-webserver-core/src/main/java/org/sonar/server/platform/web/requestid/RequestIdGeneratorImpl.java
+++ b/server/sonar-webserver-core/src/main/java/org/sonar/server/platform/web/requestid/RequestIdGeneratorImpl.java
@@ -19,78 +19,13 @@
*/
package org.sonar.server.platform.web.requestid;
-import java.util.Base64;
-import java.util.concurrent.atomic.AtomicLong;
-import java.util.concurrent.atomic.AtomicReference;
-import org.sonar.core.util.UuidGenerator;
+import java.util.UUID;
-/**
- * This implementation of {@link RequestIdGenerator} creates unique identifiers for HTTP requests leveraging
- * {@link UuidGenerator.WithFixedBase#generate(int)} and a counter of HTTP requests.
- *
- * To work around the limit of unique values produced by {@link UuidGenerator.WithFixedBase#generate(int)}, the
- * {@link UuidGenerator.WithFixedBase} instance will be renewed every
- * {@link RequestIdConfiguration#getUidGeneratorRenewalCount() RequestIdConfiguration#uidGeneratorRenewalCount}
- * HTTP requests.
- *
- *
- * This implementation is Thread safe.
- *
- */
public class RequestIdGeneratorImpl implements RequestIdGenerator {
- /**
- * The value to which the HTTP request count will be compared to (using a modulo operator,
- * see {@link #mustRenewUuidGenerator(long)}).
- *
- *
- * This value can't be the last value before {@link UuidGenerator.WithFixedBase#generate(int)} returns a non unique
- * value, ie. 2^23-1 because there is no guarantee the renewal will happen before any other thread calls
- * {@link UuidGenerator.WithFixedBase#generate(int)} method of the deplated {@link UuidGenerator.WithFixedBase} instance.
- *
- *
- *
- * To keep a comfortable margin of error, 2^22 will be used.
- *
- */
- public static final long UUID_GENERATOR_RENEWAL_COUNT = 4_194_304;
-
- private final AtomicLong counter = new AtomicLong();
- private final RequestIdGeneratorBase requestIdGeneratorBase;
- private final RequestIdConfiguration requestIdConfiguration;
- private final AtomicReference uuidGenerator;
-
- public RequestIdGeneratorImpl(RequestIdGeneratorBase requestIdGeneratorBase, RequestIdConfiguration requestIdConfiguration) {
- this.requestIdGeneratorBase = requestIdGeneratorBase;
- this.uuidGenerator = new AtomicReference<>(requestIdGeneratorBase.createNew());
- this.requestIdConfiguration = requestIdConfiguration;
- }
@Override
public String generate() {
- UuidGenerator.WithFixedBase currentUuidGenerator = this.uuidGenerator.get();
- long counterValue = counter.getAndIncrement();
- if (counterValue != 0 && mustRenewUuidGenerator(counterValue)) {
- UuidGenerator.WithFixedBase newUuidGenerator = requestIdGeneratorBase.createNew();
- uuidGenerator.set(newUuidGenerator);
- return generate(newUuidGenerator, counterValue);
- }
- return generate(currentUuidGenerator, counterValue);
- }
-
- /**
- * Since renewal of {@link UuidGenerator.WithFixedBase} instance is based on the HTTP request counter, only a single
- * thread can get the right value which will make this method return true. So, this is thread-safe by design, therefor
- * this method doesn't need external synchronization.
- *
- * The value to which the counter is compared should however be chosen with caution: see {@link #UUID_GENERATOR_RENEWAL_COUNT}.
- *
- */
- private boolean mustRenewUuidGenerator(long counter) {
- return counter % requestIdConfiguration.getUidGeneratorRenewalCount() == 0;
- }
-
- private static String generate(UuidGenerator.WithFixedBase uuidGenerator, long increment) {
- return Base64.getEncoder().encodeToString(uuidGenerator.generate((int) increment));
+ return UUID.randomUUID().toString();
}
}
diff --git a/server/sonar-webserver-core/src/test/java/org/sonar/server/platform/serverid/ServerIdFactoryImplTest.java b/server/sonar-webserver-core/src/test/java/org/sonar/server/platform/serverid/ServerIdFactoryImplTest.java
index ee392696090..2e1c3f5cf4b 100644
--- a/server/sonar-webserver-core/src/test/java/org/sonar/server/platform/serverid/ServerIdFactoryImplTest.java
+++ b/server/sonar-webserver-core/src/test/java/org/sonar/server/platform/serverid/ServerIdFactoryImplTest.java
@@ -30,13 +30,12 @@ import org.junit.runner.RunWith;
import org.sonar.api.config.Configuration;
import org.sonar.api.config.internal.MapSettings;
import org.sonar.core.platform.ServerId;
-import org.sonar.core.util.UuidFactory;
-import org.sonar.core.util.Uuids;
import static org.apache.commons.lang.RandomStringUtils.randomAlphabetic;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.when;
import static org.sonar.core.platform.ServerId.DATABASE_ID_LENGTH;
import static org.sonar.core.platform.ServerId.NOT_UUID_DATASET_ID_LENGTH;
@@ -48,12 +47,11 @@ import static org.sonar.server.platform.serverid.ServerIdFactoryImpl.crc32Hex;
public class ServerIdFactoryImplTest {
private static final ServerId A_SERVERID = ServerId.of(randomAlphabetic(DATABASE_ID_LENGTH), randomAlphabetic(UUID_DATASET_ID_LENGTH));
-
private MapSettings settings = new MapSettings();
private Configuration config = settings.asConfig();
- private UuidFactory uuidFactory = mock(UuidFactory.class);
+ private ServerIdGenerator serverIdGenerator = spy(new ServerIdGenerator());
private JdbcUrlSanitizer jdbcUrlSanitizer = mock(JdbcUrlSanitizer.class);
- private ServerIdFactoryImpl underTest = new ServerIdFactoryImpl(config, uuidFactory, jdbcUrlSanitizer);
+ private ServerIdFactoryImpl underTest = new ServerIdFactoryImpl(config, serverIdGenerator, jdbcUrlSanitizer);
@Test
public void create_from_scratch_fails_with_ISE_if_JDBC_property_not_set() {
@@ -63,10 +61,12 @@ public class ServerIdFactoryImplTest {
@Test
public void create_from_scratch_creates_ServerId_from_JDBC_URL_and_new_uuid() {
String jdbcUrl = "jdbc";
- String uuid = Uuids.create();
String sanitizedJdbcUrl = "sanitized_jdbc";
+
+ String uuid = serverIdGenerator.generate();
+ when(serverIdGenerator.generate()).thenReturn(uuid);
+
settings.setProperty(JDBC_URL.getKey(), jdbcUrl);
- when(uuidFactory.create()).thenReturn(uuid);
when(jdbcUrlSanitizer.sanitize(jdbcUrl)).thenReturn(sanitizedJdbcUrl);
ServerId serverId = underTest.create();
@@ -86,7 +86,7 @@ public class ServerIdFactoryImplTest {
String jdbcUrl = "jdbc";
String sanitizedJdbcUrl = "sanitized_jdbc";
settings.setProperty(JDBC_URL.getKey(), jdbcUrl);
- when(uuidFactory.create()).thenThrow(new IllegalStateException("UuidFactory.create() should not be called"));
+ when(serverIdGenerator.generate()).thenThrow(new IllegalStateException("generate should not be called"));
when(jdbcUrlSanitizer.sanitize(jdbcUrl)).thenReturn(sanitizedJdbcUrl);
ServerId serverId = underTest.create(currentServerId);
diff --git a/server/sonar-webserver-core/src/test/java/org/sonar/server/platform/serverid/ServerIdModuleTest.java b/server/sonar-webserver-core/src/test/java/org/sonar/server/platform/serverid/ServerIdModuleTest.java
index e1e7723b05b..8660e094b10 100644
--- a/server/sonar-webserver-core/src/test/java/org/sonar/server/platform/serverid/ServerIdModuleTest.java
+++ b/server/sonar-webserver-core/src/test/java/org/sonar/server/platform/serverid/ServerIdModuleTest.java
@@ -31,6 +31,6 @@ public class ServerIdModuleTest {
public void verify_count_of_added_components() {
ListContainer container = new ListContainer();
underTest.configure(container);
- assertThat(container.getAddedObjects()).hasSize(4);
+ assertThat(container.getAddedObjects()).hasSize(5);
}
}
diff --git a/server/sonar-webserver-core/src/test/java/org/sonar/server/platform/web/requestid/HttpRequestIdModuleTest.java b/server/sonar-webserver-core/src/test/java/org/sonar/server/platform/web/requestid/HttpRequestIdModuleTest.java
index d9c4674c4b8..9530702d414 100644
--- a/server/sonar-webserver-core/src/test/java/org/sonar/server/platform/web/requestid/HttpRequestIdModuleTest.java
+++ b/server/sonar-webserver-core/src/test/java/org/sonar/server/platform/web/requestid/HttpRequestIdModuleTest.java
@@ -31,6 +31,6 @@ public class HttpRequestIdModuleTest {
public void count_components_in_module() {
ListContainer container = new ListContainer();
underTest.configure(container);
- assertThat(container.getAddedObjects()).hasSize(3);
+ assertThat(container.getAddedObjects()).hasSize(1);
}
}
diff --git a/server/sonar-webserver-core/src/test/java/org/sonar/server/platform/web/requestid/RequestIdConfigurationTest.java b/server/sonar-webserver-core/src/test/java/org/sonar/server/platform/web/requestid/RequestIdConfigurationTest.java
deleted file mode 100644
index 98d1aaf845a..00000000000
--- a/server/sonar-webserver-core/src/test/java/org/sonar/server/platform/web/requestid/RequestIdConfigurationTest.java
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * 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.server.platform.web.requestid;
-
-import org.junit.Test;
-
-import static org.assertj.core.api.Assertions.assertThat;
-
-public class RequestIdConfigurationTest {
- private RequestIdConfiguration underTest = new RequestIdConfiguration(50);
-
- @Test
- public void getUidGeneratorRenewalCount_returns_value_provided_from_constructor() {
- assertThat(underTest.getUidGeneratorRenewalCount()).isEqualTo(50);
- }
-}
diff --git a/server/sonar-webserver-core/src/test/java/org/sonar/server/platform/web/requestid/RequestIdGeneratorImplTest.java b/server/sonar-webserver-core/src/test/java/org/sonar/server/platform/web/requestid/RequestIdGeneratorImplTest.java
index 42a869ae1c9..99eca9c0256 100644
--- a/server/sonar-webserver-core/src/test/java/org/sonar/server/platform/web/requestid/RequestIdGeneratorImplTest.java
+++ b/server/sonar-webserver-core/src/test/java/org/sonar/server/platform/web/requestid/RequestIdGeneratorImplTest.java
@@ -20,69 +20,19 @@
package org.sonar.server.platform.web.requestid;
import org.junit.Test;
-import org.sonar.core.util.UuidGenerator;
import static org.assertj.core.api.Assertions.assertThat;
-import static org.assertj.core.api.Assertions.assertThatThrownBy;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
public class RequestIdGeneratorImplTest {
- private UuidGenerator.WithFixedBase generator1 = increment -> new byte[] {124, 22, 66, 96, 55, 88, 2, 9};
- private UuidGenerator.WithFixedBase generator2 = increment -> new byte[] {0, 5, 88, 81, 8, 6, 44, 19};
- private UuidGenerator.WithFixedBase generator3 = increment -> new byte[] {126, 9, 35, 76, 2, 1, 2};
- private RequestIdGeneratorBase uidGeneratorBase = mock(RequestIdGeneratorBase.class);
- private IllegalStateException expected = new IllegalStateException("Unexpected third call to createNew");
+ RequestIdGeneratorImpl requestIdGenerator = new RequestIdGeneratorImpl();
@Test
- public void generate_renews_inner_UuidGenerator_instance_every_number_of_calls_to_generate_specified_in_RequestIdConfiguration_supports_2() {
- when(uidGeneratorBase.createNew())
- .thenReturn(generator1)
- .thenReturn(generator2)
- .thenReturn(generator3)
- .thenThrow(expected);
+ public void generate_shouldGenerateUniqueIds() {
+ String requestId1 = requestIdGenerator.generate();
+ String requestId2 = requestIdGenerator.generate();
+ String requestId3 = requestIdGenerator.generate();
- RequestIdGeneratorImpl underTest = new RequestIdGeneratorImpl(uidGeneratorBase, new RequestIdConfiguration(2));
-
- assertThat(underTest.generate()).isEqualTo("fBZCYDdYAgk="); // using generator1
- assertThat(underTest.generate()).isEqualTo("fBZCYDdYAgk="); // still using generator1
- assertThat(underTest.generate()).isEqualTo("AAVYUQgGLBM="); // renewing generator and using generator2
- assertThat(underTest.generate()).isEqualTo("AAVYUQgGLBM="); // still using generator2
- assertThat(underTest.generate()).isEqualTo("fgkjTAIBAg=="); // renewing generator and using generator3
- assertThat(underTest.generate()).isEqualTo("fgkjTAIBAg=="); // using generator3
-
- assertThatThrownBy(() -> {
- underTest.generate(); // renewing generator and failing
- })
- .isInstanceOf(IllegalStateException.class)
- .hasMessage(expected.getMessage());
- }
-
- @Test
- public void generate_renews_inner_UuidGenerator_instance_every_number_of_calls_to_generate_specified_in_RequestIdConfiguration_supports_3() {
- when(uidGeneratorBase.createNew())
- .thenReturn(generator1)
- .thenReturn(generator2)
- .thenReturn(generator3)
- .thenThrow(expected);
-
- RequestIdGeneratorImpl underTest = new RequestIdGeneratorImpl(uidGeneratorBase, new RequestIdConfiguration(3));
-
- assertThat(underTest.generate()).isEqualTo("fBZCYDdYAgk="); // using generator1
- assertThat(underTest.generate()).isEqualTo("fBZCYDdYAgk="); // still using generator1
- assertThat(underTest.generate()).isEqualTo("fBZCYDdYAgk="); // still using generator1
- assertThat(underTest.generate()).isEqualTo("AAVYUQgGLBM="); // renewing generator and using it
- assertThat(underTest.generate()).isEqualTo("AAVYUQgGLBM="); // still using generator2
- assertThat(underTest.generate()).isEqualTo("AAVYUQgGLBM="); // still using generator2
- assertThat(underTest.generate()).isEqualTo("fgkjTAIBAg=="); // renewing generator and using it
- assertThat(underTest.generate()).isEqualTo("fgkjTAIBAg=="); // using generator3
- assertThat(underTest.generate()).isEqualTo("fgkjTAIBAg=="); // using generator3
-
- assertThatThrownBy(() -> {
- underTest.generate(); // renewing generator and failing
- })
- .isInstanceOf(IllegalStateException.class)
- .hasMessage(expected.getMessage());
+ assertThat(requestId1).isNotEqualTo(requestId2).isNotEqualTo(requestId3);
}
}
diff --git a/server/sonar-webserver-webapi/src/it/java/org/sonar/server/almintegration/ws/azure/SearchAzureReposActionIT.java b/server/sonar-webserver-webapi/src/it/java/org/sonar/server/almintegration/ws/azure/SearchAzureReposActionIT.java
index 0e95cdfb3e3..5fc3dde9b64 100644
--- a/server/sonar-webserver-webapi/src/it/java/org/sonar/server/almintegration/ws/azure/SearchAzureReposActionIT.java
+++ b/server/sonar-webserver-webapi/src/it/java/org/sonar/server/almintegration/ws/azure/SearchAzureReposActionIT.java
@@ -64,6 +64,7 @@ public class SearchAzureReposActionIT {
private final AzureDevOpsHttpClient azureDevOpsHttpClient = mock(AzureDevOpsHttpClient.class);
private final Encryption encryption = mock(Encryption.class);
private final WsActionTester ws = new WsActionTester(new SearchAzureReposAction(db.getDbClient(), userSession, azureDevOpsHttpClient));
+ private int projectId = 0;
@Before
public void before() {
@@ -334,7 +335,8 @@ public class SearchAzureReposActionIT {
}
private ProjectDto insertProject(AlmSettingDto almSetting, String repoName, String projectName) {
- ProjectDto projectDto1 = db.components().insertPrivateProject().getProjectDto();
+ ProjectDto projectDto1 =
+ db.components().insertPrivateProject(dto -> dto.setKey("key_" + projectId).setName("name" + projectId++)).getProjectDto();
db.almSettings().insertAzureProjectAlmSetting(almSetting, projectDto1, projectAlmSettingDto -> projectAlmSettingDto.setAlmRepo(repoName),
projectAlmSettingDto -> projectAlmSettingDto.setAlmSlug(projectName));
return projectDto1;
diff --git a/server/sonar-webserver-webapi/src/it/java/org/sonar/server/almintegration/ws/bitbucketserver/SearchBitbucketServerReposActionIT.java b/server/sonar-webserver-webapi/src/it/java/org/sonar/server/almintegration/ws/bitbucketserver/SearchBitbucketServerReposActionIT.java
index e1eb6c84cf9..30268f3a4de 100644
--- a/server/sonar-webserver-webapi/src/it/java/org/sonar/server/almintegration/ws/bitbucketserver/SearchBitbucketServerReposActionIT.java
+++ b/server/sonar-webserver-webapi/src/it/java/org/sonar/server/almintegration/ws/bitbucketserver/SearchBitbucketServerReposActionIT.java
@@ -86,7 +86,7 @@ public class SearchBitbucketServerReposActionIT {
dto.setAlmSettingUuid(almSetting.getUuid());
dto.setUserUuid(user.getUuid());
});
- ProjectDto projectDto = db.components().insertPrivateProject().getProjectDto();
+ ProjectDto projectDto = db.components().insertPrivateProject(dto -> dto.setKey("proj_key_1").setName("proj_name_1")).getProjectDto();
db.almSettings().insertBitbucketProjectAlmSetting(almSetting, projectDto, s -> s.setAlmRepo("projectKey2"), s -> s.setAlmSlug("repo-slug-2"));
AlmIntegrations.SearchBitbucketserverReposWsResponse response = ws.newRequest()
@@ -135,9 +135,9 @@ public class SearchBitbucketServerReposActionIT {
dto.setAlmSettingUuid(almSetting.getUuid());
dto.setUserUuid(user.getUuid());
});
- ProjectDto projectDto = db.components().insertPrivateProject().getProjectDto();
+ ProjectDto projectDto = db.components().insertPrivateProject(dto -> dto.setName("proj_1").setKey("proj_key_1")).getProjectDto();
db.almSettings().insertBitbucketProjectAlmSetting(almSetting, projectDto, s -> s.setAlmRepo("projectKey2"), s -> s.setAlmSlug("repo-slug-2"));
- db.almSettings().insertBitbucketProjectAlmSetting(almSetting, db.components().insertPrivateProject().getProjectDto(), s -> s.setAlmRepo("projectKey2"), s -> s.setAlmSlug("repo-slug-2"));
+ db.almSettings().insertBitbucketProjectAlmSetting(almSetting, db.components().insertPrivateProject(dto -> dto.setName("proj_2").setKey("proj_key_2")).getProjectDto(), s -> s.setAlmRepo("projectKey2"), s -> s.setAlmSlug("repo-slug-2"));
AlmIntegrations.SearchBitbucketserverReposWsResponse response = ws.newRequest()
.setParam("almSetting", almSetting.getKey())
diff --git a/server/sonar-webserver-webapi/src/it/java/org/sonar/server/almintegration/ws/gitlab/SearchGitlabReposActionIT.java b/server/sonar-webserver-webapi/src/it/java/org/sonar/server/almintegration/ws/gitlab/SearchGitlabReposActionIT.java
index 3a0ab0c5d28..42be74f8e87 100644
--- a/server/sonar-webserver-webapi/src/it/java/org/sonar/server/almintegration/ws/gitlab/SearchGitlabReposActionIT.java
+++ b/server/sonar-webserver-webapi/src/it/java/org/sonar/server/almintegration/ws/gitlab/SearchGitlabReposActionIT.java
@@ -124,16 +124,16 @@ public class SearchGitlabReposActionIT {
dto.setUserUuid(user.getUuid());
dto.setPersonalAccessToken("some-pat");
});
- ProjectDto projectDto1 = db.components().insertPrivateProject().getProjectDto();
+ ProjectDto projectDto1 = db.components().insertPrivateProject(dto -> dto.setKey("proj_key_1").setName("proj_name_1")).getProjectDto();
db.almSettings().insertGitlabProjectAlmSetting(almSetting, projectDto1);
- ProjectDto projectDto2 = db.components().insertPrivateProject().getProjectDto();
+ ProjectDto projectDto2 = db.components().insertPrivateProject(dto -> dto.setKey("proj_key_2").setName("proj_name_2")).getProjectDto();
db.almSettings().insertGitlabProjectAlmSetting(almSetting, projectDto2, projectAlmSettingDto -> projectAlmSettingDto.setAlmRepo("2"));
- ProjectDto projectDto3 = db.components().insertPrivateProject().getProjectDto();
+ ProjectDto projectDto3 = db.components().insertPrivateProject(dto -> dto.setKey("proj_key_3").setName("proj_name_3")).getProjectDto();
db.almSettings().insertGitlabProjectAlmSetting(almSetting, projectDto3, projectAlmSettingDto -> projectAlmSettingDto.setAlmRepo("3"));
- ProjectDto projectDto4 = db.components().insertPrivateProject().getProjectDto();
+ ProjectDto projectDto4 = db.components().insertPrivateProject(dto -> dto.setKey("proj_key_4").setName("proj_name_4")).getProjectDto();
db.almSettings().insertGitlabProjectAlmSetting(almSetting, projectDto4, projectAlmSettingDto -> projectAlmSettingDto.setAlmRepo("3"));
AlmIntegrations.SearchGitlabReposWsResponse response = ws.newRequest()
diff --git a/server/sonar-webserver-webapi/src/it/java/org/sonar/server/component/ws/SearchProjectsActionIT.java b/server/sonar-webserver-webapi/src/it/java/org/sonar/server/component/ws/SearchProjectsActionIT.java
index 317ae8dcfa9..eda28adb2fe 100644
--- a/server/sonar-webserver-webapi/src/it/java/org/sonar/server/component/ws/SearchProjectsActionIT.java
+++ b/server/sonar-webserver-webapi/src/it/java/org/sonar/server/component/ws/SearchProjectsActionIT.java
@@ -123,27 +123,27 @@ public class SearchProjectsActionIT {
@DataProvider
public static Object[][] rating_metric_keys() {
- return new Object[][] {{SQALE_RATING_KEY}, {RELIABILITY_RATING_KEY}, {SECURITY_RATING_KEY}};
+ return new Object[][]{{SQALE_RATING_KEY}, {RELIABILITY_RATING_KEY}, {SECURITY_RATING_KEY}};
}
@DataProvider
public static Object[][] new_rating_metric_keys() {
- return new Object[][] {{NEW_MAINTAINABILITY_RATING_KEY}, {NEW_RELIABILITY_RATING_KEY}, {NEW_SECURITY_RATING_KEY}};
+ return new Object[][]{{NEW_MAINTAINABILITY_RATING_KEY}, {NEW_RELIABILITY_RATING_KEY}, {NEW_SECURITY_RATING_KEY}};
}
@DataProvider
public static Object[][] component_qualifiers_for_valid_editions() {
- return new Object[][] {
- {new String[] {Qualifiers.PROJECT}, Edition.COMMUNITY},
- {new String[] {Qualifiers.APP, Qualifiers.PROJECT}, Edition.DEVELOPER},
- {new String[] {Qualifiers.APP, Qualifiers.PROJECT}, Edition.ENTERPRISE},
- {new String[] {Qualifiers.APP, Qualifiers.PROJECT}, Edition.DATACENTER},
+ return new Object[][]{
+ {new String[]{Qualifiers.PROJECT}, Edition.COMMUNITY},
+ {new String[]{Qualifiers.APP, Qualifiers.PROJECT}, Edition.DEVELOPER},
+ {new String[]{Qualifiers.APP, Qualifiers.PROJECT}, Edition.ENTERPRISE},
+ {new String[]{Qualifiers.APP, Qualifiers.PROJECT}, Edition.DATACENTER},
};
}
@DataProvider
public static Object[][] community_or_developer_edition() {
- return new Object[][] {
+ return new Object[][]{
{Edition.COMMUNITY},
{Edition.DEVELOPER},
};
@@ -151,7 +151,7 @@ public class SearchProjectsActionIT {
@DataProvider
public static Object[][] enterprise_or_datacenter_edition() {
- return new Object[][] {
+ return new Object[][]{
{Edition.ENTERPRISE},
{Edition.DATACENTER},
};
@@ -161,8 +161,10 @@ public class SearchProjectsActionIT {
private DbSession dbSession = db.getSession();
private PlatformEditionProvider editionProviderMock = mock(PlatformEditionProvider.class);
- private PermissionIndexerTester authorizationIndexerTester = new PermissionIndexerTester(es, new ProjectMeasuresIndexer(dbClient, es.client()));
- private ProjectMeasuresIndex index = new ProjectMeasuresIndex(es.client(), new WebAuthorizationTypeSupport(userSession), System2.INSTANCE);
+ private PermissionIndexerTester authorizationIndexerTester = new PermissionIndexerTester(es, new ProjectMeasuresIndexer(dbClient,
+ es.client()));
+ private ProjectMeasuresIndex index = new ProjectMeasuresIndex(es.client(), new WebAuthorizationTypeSupport(userSession),
+ System2.INSTANCE);
private ProjectMeasuresIndexer projectMeasuresIndexer = new ProjectMeasuresIndexer(db.getDbClient(), es.client());
private WsActionTester ws = new WsActionTester(new SearchProjectsAction(dbClient, index, userSession, editionProviderMock));
@@ -217,8 +219,10 @@ public class SearchProjectsActionIT {
Param facets = def.param("facets");
assertThat(facets.defaultValue()).isNull();
- assertThat(facets.possibleValues()).containsOnly("ncloc", "duplicated_lines_density", "coverage", "sqale_rating", "reliability_rating", "security_rating", "alert_status",
- "languages", "tags", "qualifier", "new_reliability_rating", "new_security_rating", "new_maintainability_rating", "new_coverage", "new_duplicated_lines_density", "new_lines",
+ assertThat(facets.possibleValues()).containsOnly("ncloc", "duplicated_lines_density", "coverage", "sqale_rating", "reliability_rating"
+ , "security_rating", "alert_status",
+ "languages", "tags", "qualifier", "new_reliability_rating", "new_security_rating", "new_maintainability_rating", "new_coverage",
+ "new_duplicated_lines_density", "new_lines",
"security_review_rating", "security_hotspots_reviewed", "new_security_hotspots_reviewed", "new_security_review_rating");
}
@@ -343,19 +347,22 @@ public class SearchProjectsActionIT {
userSession.logIn();
MetricDto nclocMetric = db.measures().insertMetric(c -> c.setKey(NCLOC).setValueType(INT.name()));
MetricDto languagesDistributionMetric = db.measures().insertMetric(c -> c.setKey(NCLOC_LANGUAGE_DISTRIBUTION_KEY).setValueType("DATA"));
- ComponentDto project1 = insertProject(new Measure(languagesDistributionMetric, c -> c.setValue(null).setData("=2;java=6;xoo=18")));
+ ComponentDto project1 = insertProject(new Measure(languagesDistributionMetric,
+ c -> c.setValue(null).setData("=2;java=6;xoo=18")));
db.measures().insertLiveMeasure(project1, nclocMetric, m -> m.setValue(26d));
ComponentDto project2 = insertProject(new Measure(languagesDistributionMetric, c -> c.setValue(null).setData("java=3;xoo=9")));
db.measures().insertLiveMeasure(project2, nclocMetric, m -> m.setValue(12d));
ComponentDto project3 = insertProject(new Measure(languagesDistributionMetric, c -> c.setValue(null).setData("xoo=1")));
db.measures().insertLiveMeasure(project3, nclocMetric, m -> m.setValue(1d));
- ComponentDto project4 = insertProject(new Measure(languagesDistributionMetric, c -> c.setValue(null).setData("=1;java=5;xoo=13")));
+ ComponentDto project4 = insertProject(new Measure(languagesDistributionMetric,
+ c -> c.setValue(null).setData("=1;java=5;xoo=13")));
db.measures().insertLiveMeasure(project4, nclocMetric, m -> m.setValue(19d));
index();
SearchProjectsWsResponse result = call(request.setFilter("languages IN (java, js, )"));
- assertThat(result.getComponentsList()).extracting(Component::getKey).containsExactlyInAnyOrder(project1.getKey(), project2.getKey(), project4.getKey());
+ assertThat(result.getComponentsList()).extracting(Component::getKey).containsExactlyInAnyOrder(project1.getKey(), project2.getKey(),
+ project4.getKey());
}
@Test
@@ -522,10 +529,13 @@ public class SearchProjectsActionIT {
insertProject(c -> c.setKey("sonarqube").setName("Sonar Qube"));
index();
- assertThat(call(request.setFilter("query = \"Groovy\"")).getComponentsList()).extracting(Component::getName).containsOnly("Sonar Groovy");
- assertThat(call(request.setFilter("query = \"oNar\"")).getComponentsList()).extracting(Component::getName).containsOnly("Sonar Java", "Sonar Groovy", "Sonar Markdown",
+ assertThat(call(request.setFilter("query = \"Groovy\"")).getComponentsList()).extracting(Component::getName).containsOnly("Sonar " +
+ "Groovy");
+ assertThat(call(request.setFilter("query = \"oNar\"")).getComponentsList()).extracting(Component::getName).containsOnly("Sonar Java",
+ "Sonar Groovy", "Sonar Markdown",
"Sonar Qube");
- assertThat(call(request.setFilter("query = \"sonar-java\"")).getComponentsList()).extracting(Component::getName).containsOnly("Sonar Java");
+ assertThat(call(request.setFilter("query = \"sonar-java\"")).getComponentsList()).extracting(Component::getName).containsOnly("Sonar " +
+ "Java");
}
@Test
@@ -769,7 +779,8 @@ public class SearchProjectsActionIT {
userSession.logIn();
MetricDto nclocMetric = db.measures().insertMetric(c -> c.setKey(NCLOC).setValueType(INT.name()));
MetricDto languagesDistributionMetric = db.measures().insertMetric(c -> c.setKey(NCLOC_LANGUAGE_DISTRIBUTION_KEY).setValueType("DATA"));
- ComponentDto project1 = insertProject(new Measure(languagesDistributionMetric, c -> c.setValue(null).setData("=2;java=6;xoo=18")));
+ ComponentDto project1 = insertProject(new Measure(languagesDistributionMetric,
+ c -> c.setValue(null).setData("=2;java=6;xoo=18")));
db.measures().insertLiveMeasure(project1, nclocMetric, m -> m.setValue(26d));
ComponentDto project2 = insertProject(new Measure(languagesDistributionMetric, c -> c.setValue(null).setData("java=5;xoo=19")));
db.measures().insertLiveMeasure(project2, nclocMetric, m -> m.setValue(24d));
@@ -1116,7 +1127,8 @@ public class SearchProjectsActionIT {
SearchProjectsWsResponse result = call(request);
- assertThat(result.getComponentsList()).extracting(Component::getName).containsExactly("Sonar Groovy", "Sonar Java", "Sonar Markdown", "Sonar Qube");
+ assertThat(result.getComponentsList()).extracting(Component::getName).containsExactly("Sonar Groovy", "Sonar Java", "Sonar Markdown",
+ "Sonar Qube");
}
@Test
@@ -1154,10 +1166,14 @@ public class SearchProjectsActionIT {
public void sort_by_quality_gate_then_by_name() {
userSession.logIn();
MetricDto qualityGateStatus = db.measures().insertMetric(c -> c.setKey(QUALITY_GATE_STATUS).setValueType(LEVEL.name()));
- ComponentDto project1 = insertProject(c -> c.setName("Sonar Java"), new Measure(qualityGateStatus, c -> c.setValue(null).setData("ERROR")));
- ComponentDto project2 = insertProject(c -> c.setName("Sonar Groovy"), new Measure(qualityGateStatus, c -> c.setValue(null).setData("ERROR")));
- ComponentDto project3 = insertProject(c -> c.setName("Sonar Markdown"), new Measure(qualityGateStatus, c -> c.setValue(null).setData("OK")));
- ComponentDto project4 = insertProject(c -> c.setName("Sonar Qube"), new Measure(qualityGateStatus, c -> c.setValue(null).setData("OK")));
+ ComponentDto project1 = insertProject(c -> c.setName("Sonar Java"), new Measure(qualityGateStatus, c -> c.setValue(null).setData(
+ "ERROR")));
+ ComponentDto project2 = insertProject(c -> c.setName("Sonar Groovy"), new Measure(qualityGateStatus, c -> c.setValue(null).setData(
+ "ERROR")));
+ ComponentDto project3 = insertProject(c -> c.setName("Sonar Markdown"), new Measure(qualityGateStatus, c -> c.setValue(null).setData(
+ "OK")));
+ ComponentDto project4 = insertProject(c -> c.setName("Sonar Qube"), new Measure(qualityGateStatus,
+ c -> c.setValue(null).setData("OK")));
index();
assertThat(call(request.setSort(QUALITY_GATE_STATUS).setAsc(true)).getComponentsList()).extracting(Component::getKey)
@@ -1235,7 +1251,8 @@ public class SearchProjectsActionIT {
MetricDto leakProjects = db.measures().insertMetric(c -> c.setKey(LEAK_PROJECTS_KEY).setValueType(DATA.name()));
ComponentDto application1 = insertApplication(
- new Measure(leakProjects, c -> c.setData("{\"leakProjects\":[{\"id\": 1, \"leak\":20000000000}, {\"id\": 2, \"leak\":10000000000}]}")));
+ new Measure(leakProjects, c -> c.setData("{\"leakProjects\":[{\"id\": 1, \"leak\":20000000000}, {\"id\": 2, " +
+ "\"leak\":10000000000}]}")));
db.components().insertSnapshot(application1);
authorizationIndexerTester.allowOnlyAnyone(db.components().getProjectDtoByMainBranch(application1));
@@ -1254,9 +1271,9 @@ public class SearchProjectsActionIT {
@Test
public void return_visibility_flag() {
userSession.logIn();
- ProjectDto privateProject = db.components().insertPublicProject().getProjectDto();
+ ProjectDto privateProject = db.components().insertPublicProject(componentDto -> componentDto.setName("proj_A")).getProjectDto();
authorizationIndexerTester.allowOnlyAnyone(privateProject);
- ProjectDto publicProject = db.components().insertPrivateProject().getProjectDto();
+ ProjectDto publicProject = db.components().insertPrivateProject(componentDto -> componentDto.setName("proj_B")).getProjectDto();
authorizationIndexerTester.allowOnlyAnyone(publicProject);
index();
@@ -1328,14 +1345,17 @@ public class SearchProjectsActionIT {
addFavourite(project.getUuid(), project.getKey(), project.getName(), project.getQualifier());
}
- private void addFavourite(@Nullable String entityUuid, @Nullable String entityKey, @Nullable String entityName, @Nullable String qualifier) {
+ private void addFavourite(@Nullable String entityUuid, @Nullable String entityKey, @Nullable String entityName,
+ @Nullable String qualifier) {
dbClient.propertiesDao().saveProperty(dbSession, new PropertyDto().setKey("favourite")
.setEntityUuid(entityUuid).setUserUuid(userSession.getUuid()), userSession.getLogin(), entityKey, entityName, qualifier);
dbSession.commit();
}
+ private int projectCount = 0;
+
private ComponentDto insertProject(Measure... measures) {
- return insertProject(defaults(), defaults(), measures);
+ return insertProject(defaults(), projectDto -> projectDto.setName("project_" + projectCount++), measures);
}
private ComponentDto insertProject(Consumer componentConsumer, Measure... measures) {
@@ -1348,8 +1368,10 @@ public class SearchProjectsActionIT {
return project;
}
+ private int applicationCount = 0;
+
private ComponentDto insertApplication(Measure... measures) {
- return insertApplication(defaults(), measures);
+ return insertApplication(componentDto -> componentDto.setName("app_" + applicationCount++), measures);
}
private ComponentDto insertApplication(Consumer componentConsumer, Measure... measures) {
diff --git a/server/sonar-webserver-webapi/src/it/java/org/sonar/server/qualitygate/ws/SearchActionIT.java b/server/sonar-webserver-webapi/src/it/java/org/sonar/server/qualitygate/ws/SearchActionIT.java
index 185aeda7662..cf8d8ee4a67 100644
--- a/server/sonar-webserver-webapi/src/it/java/org/sonar/server/qualitygate/ws/SearchActionIT.java
+++ b/server/sonar-webserver-webapi/src/it/java/org/sonar/server/qualitygate/ws/SearchActionIT.java
@@ -167,9 +167,9 @@ public class SearchActionIT {
@Test
public void test_paging() {
QualityGateDto qualityGate = db.qualityGates().insertQualityGate();
- ProjectDto project1 = db.components().insertPublicProject().getProjectDto();
- ProjectDto project2 = db.components().insertPublicProject().getProjectDto();
- ProjectDto project3 = db.components().insertPublicProject().getProjectDto();
+ ProjectDto project1 = db.components().insertPublicProject(dto -> dto.setName("proj_1")).getProjectDto();
+ ProjectDto project2 = db.components().insertPublicProject(dto -> dto.setName("proj_2")).getProjectDto();
+ ProjectDto project3 = db.components().insertPublicProject(dto -> dto.setName("proj_3")).getProjectDto();
db.qualityGates().associateProjectToQualityGate(project1, qualityGate);
// Return partial result on first page
diff --git a/server/sonar-webserver-webapi/src/it/java/org/sonar/server/qualityprofile/ws/CopyActionIT.java b/server/sonar-webserver-webapi/src/it/java/org/sonar/server/qualityprofile/ws/CopyActionIT.java
index d5412e3c5ad..1d59852711d 100644
--- a/server/sonar-webserver-webapi/src/it/java/org/sonar/server/qualityprofile/ws/CopyActionIT.java
+++ b/server/sonar-webserver-webapi/src/it/java/org/sonar/server/qualityprofile/ws/CopyActionIT.java
@@ -49,6 +49,7 @@ import org.sonar.server.ws.WsActionTester;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.mockito.Mockito.mock;
+import static org.sonar.core.util.SequenceUuidFactory.UUID_1;
import static org.sonar.db.permission.GlobalPermission.ADMINISTER_QUALITY_PROFILES;
import static org.sonar.test.JsonAssert.assertJson;
@@ -116,9 +117,8 @@ public class CopyActionIT {
.setParam("toName", "target-name")
.execute();
- String generatedUuid = "1";
assertJson(response.getInput()).isSimilarTo("{" +
- " \"key\": \"" + generatedUuid + "\"," +
+ " \"key\": \"" + UUID_1 + "\"," +
" \"name\": \"target-name\"," +
" \"language\": \"lang1\"," +
" \"languageName\": \"Lang1\"," +
@@ -126,13 +126,13 @@ public class CopyActionIT {
" \"isInherited\": false" +
"}");
QProfileDto loadedProfile = db.getDbClient().qualityProfileDao().selectByNameAndLanguage(db.getSession(), "target-name", sourceProfile.getLanguage());
- assertThat(loadedProfile.getKee()).isEqualTo(generatedUuid);
+ assertThat(loadedProfile.getKee()).isEqualTo(UUID_1);
assertThat(loadedProfile.getParentKee()).isNull();
assertThat(backuper.copiedProfile.getKee()).isEqualTo(sourceProfile.getKee());
assertThat(backuper.toProfile.getLanguage()).isEqualTo(sourceProfile.getLanguage());
assertThat(backuper.toProfile.getName()).isEqualTo("target-name");
- assertThat(backuper.toProfile.getKee()).isEqualTo(generatedUuid);
+ assertThat(backuper.toProfile.getKee()).isEqualTo(UUID_1);
assertThat(backuper.toProfile.getParentKee()).isNull();
}
@@ -176,9 +176,8 @@ public class CopyActionIT {
.setParam("toName", "target-name")
.execute();
- String generatedUuid = "1";
assertJson(response.getInput()).isSimilarTo("{" +
- " \"key\": \"" + generatedUuid + "\"," +
+ " \"key\": \"" + UUID_1 + "\"," +
" \"name\": \"target-name\"," +
" \"language\": \"lang1\"," +
" \"languageName\": \"Lang1\"," +
@@ -186,13 +185,13 @@ public class CopyActionIT {
" \"isInherited\": true" +
"}");
QProfileDto loadedProfile = db.getDbClient().qualityProfileDao().selectByNameAndLanguage(db.getSession(), "target-name", sourceProfile.getLanguage());
- assertThat(loadedProfile.getKee()).isEqualTo(generatedUuid);
+ assertThat(loadedProfile.getKee()).isEqualTo(UUID_1);
assertThat(loadedProfile.getParentKee()).isEqualTo(parentProfile.getKee());
assertThat(backuper.copiedProfile.getKee()).isEqualTo(sourceProfile.getKee());
assertThat(backuper.toProfile.getLanguage()).isEqualTo(sourceProfile.getLanguage());
assertThat(backuper.toProfile.getName()).isEqualTo("target-name");
- assertThat(backuper.toProfile.getKee()).isEqualTo(generatedUuid);
+ assertThat(backuper.toProfile.getKee()).isEqualTo(UUID_1);
assertThat(backuper.toProfile.getParentKee()).isEqualTo(parentProfile.getKee());
}
diff --git a/sonar-core/src/main/java/org/sonar/core/util/MacAddressProvider.java b/sonar-core/src/main/java/org/sonar/core/util/MacAddressProvider.java
deleted file mode 100644
index a7ca1717641..00000000000
--- a/sonar-core/src/main/java/org/sonar/core/util/MacAddressProvider.java
+++ /dev/null
@@ -1,108 +0,0 @@
-/*
- * 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.core.util;
-
-import com.google.common.annotations.VisibleForTesting;
-import java.net.NetworkInterface;
-import java.net.SocketException;
-import java.security.SecureRandom;
-import java.util.Enumeration;
-import javax.annotation.CheckForNull;
-import javax.annotation.Nullable;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-/**
- * Used by {@link UuidFactoryImpl}. Heavily inspired by https://github.com/elastic/elasticsearch/blob/master/core/src/main/java/org/elasticsearch/common/MacAddressProvider.java
- */
-class MacAddressProvider {
-
- private static final Logger LOGGER = LoggerFactory.getLogger(MacAddressProvider.class);
- public static final int BYTE_SIZE = 6;
-
- private MacAddressProvider() {
- // only static stuff
- }
-
- public static byte[] getSecureMungedAddress() {
- byte[] address = null;
- try {
- address = getMacAddress();
- } catch (SocketException se) {
- LOGGER.warn("Unable to get mac address, will use a dummy address", se);
- // address will be set below
- }
-
- if (!isValidAddress(address)) {
- LOGGER.warn("Unable to get a valid mac address, will use a dummy address");
- address = constructDummyMulticastAddress();
- }
-
- byte[] mungedBytes = new byte[BYTE_SIZE];
- new SecureRandom().nextBytes(mungedBytes);
- for (int i = 0; i < BYTE_SIZE; ++i) {
- mungedBytes[i] ^= address[i];
- }
-
- return mungedBytes;
- }
-
- private static boolean isValidAddress(@Nullable byte[] address) {
- if (address == null || address.length != BYTE_SIZE) {
- return false;
- }
- for (byte b : address) {
- if (b != 0x00) {
- // If any of the bytes are non zero assume a good address
- return true;
- }
- }
- return false;
- }
-
- @CheckForNull
- private static byte[] getMacAddress() throws SocketException {
- Enumeration en = NetworkInterface.getNetworkInterfaces();
- if (en != null) {
- while (en.hasMoreElements()) {
- NetworkInterface nint = en.nextElement();
- if (!nint.isLoopback()) {
- // Pick the first valid non loopback address we find
- byte[] address = nint.getHardwareAddress();
- if (isValidAddress(address)) {
- return address;
- }
- }
- }
- }
- // Could not find a mac address
- return null;
- }
-
- @VisibleForTesting
- static byte[] constructDummyMulticastAddress() {
- byte[] dummy = new byte[BYTE_SIZE];
- new SecureRandom().nextBytes(dummy);
- // Set the broadcast bit to indicate this is not a _real_ mac address
- dummy[0] |= (byte) 0x01;
- return dummy;
- }
-
-}
diff --git a/sonar-core/src/main/java/org/sonar/core/util/SequenceUuidFactory.java b/sonar-core/src/main/java/org/sonar/core/util/SequenceUuidFactory.java
index f4b9021595c..32b10651ead 100644
--- a/sonar-core/src/main/java/org/sonar/core/util/SequenceUuidFactory.java
+++ b/sonar-core/src/main/java/org/sonar/core/util/SequenceUuidFactory.java
@@ -19,18 +19,28 @@
*/
package org.sonar.core.util;
+import com.google.common.annotations.VisibleForTesting;
+import org.apache.commons.lang.StringUtils;
+
import java.util.concurrent.atomic.AtomicInteger;
/**
* Only for tests. This implementation of {@link UuidFactory} generates
- * ids as a sequence of integers ("1", "2", ...). It starts with "1".
+ * ids with the structure of a UUID v4, but containing a sequence of integers ("1", "2", ...). It starts with "1".
*/
+@VisibleForTesting
public class SequenceUuidFactory implements UuidFactory {
+ private static final String UUID_PREFIX = "00000000-0000-0000-0000-";
+
+ public static final String UUID_1 = UUID_PREFIX + "000000000001";
+ public static final String UUID_2 = UUID_PREFIX + "000000000002";
+ public static final String UUID_3 = UUID_PREFIX + "000000000003";
private final AtomicInteger id = new AtomicInteger(1);
@Override
public String create() {
- return String.valueOf(id.getAndIncrement());
+ int currentId = id.getAndIncrement();
+ return UUID_PREFIX + StringUtils.leftPad(String.valueOf(currentId), 12, "0");
}
}
diff --git a/sonar-core/src/main/java/org/sonar/core/util/UuidFactoryFast.java b/sonar-core/src/main/java/org/sonar/core/util/UuidFactoryFast.java
index f19744c23ca..3159b446684 100644
--- a/sonar-core/src/main/java/org/sonar/core/util/UuidFactoryFast.java
+++ b/sonar-core/src/main/java/org/sonar/core/util/UuidFactoryFast.java
@@ -19,17 +19,23 @@
*/
package org.sonar.core.util;
-import java.security.SecureRandom;
+import com.google.common.annotations.VisibleForTesting;
/**
* NOT thread safe
* About 10x faster than {@link UuidFactoryImpl}
* It does not take into account the MAC address to calculate the ids, so it is machine-independent.
+ * This class must only be used for testing.
+ * @deprecated use {@link UuidFactoryImpl} or {@link SequenceUuidFactory} instead.
*/
+@VisibleForTesting
+@Deprecated(since = "10.4")
public class UuidFactoryFast implements UuidFactory {
private static UuidFactoryFast instance = new UuidFactoryFast();
- private static final char[] HEX_ARRAY = "0123456789ABCDEF".toCharArray();
- private static int sequenceNumber = new SecureRandom().nextInt();
+
+ public static UuidFactoryFast getInstance() {
+ return instance;
+ }
private UuidFactoryFast() {
//
@@ -37,42 +43,8 @@ public class UuidFactoryFast implements UuidFactory {
@Override
public String create() {
- long timestamp = System.currentTimeMillis();
-
- byte[] uuidBytes = new byte[9];
-
- // Only use lower 6 bytes of the timestamp (this will suffice beyond the year 10000):
- putLong(uuidBytes, timestamp, 0, 6);
-
- // Sequence number adds 3 bytes:
- putLong(uuidBytes, getSequenceNumber(), 6, 3);
-
- return byteArrayToHex(uuidBytes);
+ return UuidFactoryImpl.INSTANCE.create();
}
- public static UuidFactoryFast getInstance() {
- return instance;
- }
-
- private static int getSequenceNumber() {
- return sequenceNumber++;
- }
-
- /** Puts the lower numberOfLongBytes from l into the array, starting index pos. */
- private static void putLong(byte[] array, long l, int pos, int numberOfLongBytes) {
- for (int i = 0; i < numberOfLongBytes; ++i) {
- array[pos + numberOfLongBytes - i - 1] = (byte) (l >>> (i * 8));
- }
- }
-
- public static String byteArrayToHex(byte[] bytes) {
- char[] hexChars = new char[bytes.length * 2];
- for (int j = 0; j < bytes.length; j++) {
- int v = bytes[j] & 0xFF;
- hexChars[j * 2] = HEX_ARRAY[v >>> 4];
- hexChars[j * 2 + 1] = HEX_ARRAY[v & 0x0F];
- }
- return new String(hexChars);
- }
}
diff --git a/sonar-core/src/main/java/org/sonar/core/util/UuidFactoryImpl.java b/sonar-core/src/main/java/org/sonar/core/util/UuidFactoryImpl.java
index a80d3becd1d..01d29a06563 100644
--- a/sonar-core/src/main/java/org/sonar/core/util/UuidFactoryImpl.java
+++ b/sonar-core/src/main/java/org/sonar/core/util/UuidFactoryImpl.java
@@ -19,7 +19,7 @@
*/
package org.sonar.core.util;
-import org.apache.commons.codec.binary.Base64;
+import java.util.UUID;
/**
*/
@@ -31,11 +31,9 @@ public enum UuidFactoryImpl implements UuidFactory {
*/
INSTANCE;
- private final UuidGenerator uuidGenerator = new UuidGeneratorImpl();
-
@Override
public String create() {
- return Base64.encodeBase64URLSafeString(uuidGenerator.generate());
+ return UUID.randomUUID().toString();
}
}
diff --git a/sonar-core/src/main/java/org/sonar/core/util/UuidGenerator.java b/sonar-core/src/main/java/org/sonar/core/util/UuidGenerator.java
deleted file mode 100644
index c982daaea49..00000000000
--- a/sonar-core/src/main/java/org/sonar/core/util/UuidGenerator.java
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
- * 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.core.util;
-
-/**
- * A generator of UUID as a byte array which is made of two parts:
- *
- * - a base, which is machine and time dependant and therefor will change with time
- * - an increment
- *
- *
- *
- * This generator can be used in two ways:
- *
- * - either the base and the increment are changed for each UUID (with time for the base, with each call to
- * {@link #generate()} for the increment) and {@link #generate()} should be used
- * - or the increment can be the only changing part (for performance boost and less concurrency) and
- * {@link #withFixedBase()} should be used.
- *
- *
- *
- *
- * Warning: {@link WithFixedBase#generate(int)} can be considerably faster than {@link #generate()} but
- * is limited to generate only 2^23-1 unique values.
- *
- *
- *
- * Heavily inspired from Elasticsearch {@code TimeBasedUUIDGenerator}, which could be directly
- * used the day {@code UuidFactoryImpl} is moved outside module sonar-core.
- * See https://github.com/elastic/elasticsearch/blob/master/core/src/main/java/org/elasticsearch/common/TimeBasedUUIDGenerator.java
- *
- */
-public interface UuidGenerator {
- /**
- * Generates a UUID which base and increment are always different from any other value provided by this method.
- */
- byte[] generate();
-
- /**
- * Provide a new UUID generating instance which will allow generation of UUIDs which base is constant and can
- * vary according to a provided increment value (see {@link WithFixedBase#generate(int)}).
- */
- WithFixedBase withFixedBase();
-
- @FunctionalInterface
- interface WithFixedBase {
- /**
- * Generate a new unique universal identifier using the last 3 bytes of the specified int.
- *
- * This implies that this method of a given {@link WithFixedBase} instance can only generate up to
- * 2^23-1 unique values if provided with unique int arguments.
- *
- *
- * This is up to the caller to ensure that unique int values are provided to a given instance's {@link #generate(int)}
- * method.
- *
- *
- * This method is faster than {@link UuidGenerator#generate()} due to less computation and less internal concurrency.
- *
- */
- byte[] generate(int increment);
- }
-}
diff --git a/sonar-core/src/main/java/org/sonar/core/util/UuidGeneratorImpl.java b/sonar-core/src/main/java/org/sonar/core/util/UuidGeneratorImpl.java
deleted file mode 100644
index 2328b29184d..00000000000
--- a/sonar-core/src/main/java/org/sonar/core/util/UuidGeneratorImpl.java
+++ /dev/null
@@ -1,117 +0,0 @@
-/*
- * 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.core.util;
-
-import java.security.SecureRandom;
-import java.util.concurrent.atomic.AtomicInteger;
-import java.util.function.Supplier;
-
-public final class UuidGeneratorImpl implements UuidGenerator {
-
- private final FullNewUuidGenerator fullNewUuidGenerator = new FullNewUuidGenerator();
-
- @Override
- public byte[] generate() {
- return fullNewUuidGenerator.get();
- }
-
- @Override
- public WithFixedBase withFixedBase() {
- return new FixedBasedUuidGenerator();
- }
-
- private static class UuidGeneratorBase {
- // We only use bottom 3 bytes for the sequence number. Paranoia: init with random int so that if JVM/OS/machine goes down, clock slips
- // backwards, and JVM comes back up, we are less likely to be on the same sequenceNumber at the same time:
- private final AtomicInteger sequenceNumber = new AtomicInteger(new SecureRandom().nextInt());
- private final byte[] secureMungedAddress = MacAddressProvider.getSecureMungedAddress();
- // Used to ensure clock moves forward
- private long lastTimestamp = 0L;
-
- void initBase(byte[] buffer, int sequenceId) {
- long timestamp = System.currentTimeMillis();
-
- synchronized (this) {
- // Don't let timestamp go backwards, at least "on our watch" (while this JVM is running). We are still vulnerable if we are
- // shut down, clock goes backwards, and we restart... for this we randomize the sequenceNumber on init to decrease chance of
- // collision:
- timestamp = Math.max(lastTimestamp, timestamp);
-
- if (sequenceId == 0) {
- // Always force the clock to increment whenever sequence number is 0, in case we have a long time-slip backwards:
- timestamp++;
- }
-
- lastTimestamp = timestamp;
- }
-
- // Only use lower 6 bytes of the timestamp (this will suffice beyond the year 10000):
- putLong(buffer, timestamp, 0, 6);
-
- // MAC address adds 6 bytes:
- System.arraycopy(secureMungedAddress, 0, buffer, 6, secureMungedAddress.length);
- }
-
- protected byte[] generate(byte[] buffer, int increment) {
- // Sequence number adds 3 bytes
- putLong(buffer, increment, 12, 3);
-
- return buffer;
- }
-
- int getSequenceId() {
- return sequenceNumber.incrementAndGet() & 0xffffff;
- }
-
- /** Puts the lower numberOfLongBytes from l into the array, starting index pos. */
- private static void putLong(byte[] array, long l, int pos, int numberOfLongBytes) {
- for (int i = 0; i < numberOfLongBytes; ++i) {
- array[pos + numberOfLongBytes - i - 1] = (byte) (l >>> (i * 8));
- }
- }
- }
-
- private static final class FullNewUuidGenerator extends UuidGeneratorBase implements Supplier {
-
- @Override
- public byte[] get() {
- byte[] buffer = new byte[15];
- int sequenceId = getSequenceId();
- initBase(buffer, sequenceId);
- return super.generate(buffer, sequenceId);
- }
- }
-
- private static class FixedBasedUuidGenerator extends UuidGeneratorBase implements WithFixedBase {
- private final byte[] base = new byte[15];
-
- FixedBasedUuidGenerator() {
- int sequenceId = getSequenceId();
- initBase(base, sequenceId);
- }
-
- @Override
- public byte[] generate(int increment) {
- byte[] buffer = new byte[15];
- System.arraycopy(base, 0, buffer, 0, buffer.length);
- return super.generate(buffer, increment);
- }
- }
-}
diff --git a/sonar-core/src/test/java/org/sonar/core/platform/ServerIdTest.java b/sonar-core/src/test/java/org/sonar/core/platform/ServerIdTest.java
index 97bad79bb3c..c427f1abc8a 100644
--- a/sonar-core/src/test/java/org/sonar/core/platform/ServerIdTest.java
+++ b/sonar-core/src/test/java/org/sonar/core/platform/ServerIdTest.java
@@ -29,7 +29,6 @@ import java.util.stream.IntStream;
import java.util.stream.Stream;
import org.junit.Test;
import org.junit.runner.RunWith;
-import org.sonar.core.util.UuidFactoryImpl;
import static org.apache.commons.lang.RandomStringUtils.randomAlphabetic;
import static org.apache.commons.lang.StringUtils.repeat;
@@ -47,6 +46,8 @@ import static org.sonar.core.platform.ServerId.UUID_DATASET_ID_LENGTH;
@RunWith(DataProviderRunner.class)
public class ServerIdTest {
+ private static final String OLD_UUID_FORMAT = "AY0XR6neBaNHvsTBjkC2";
+
@Test
public void parse_throws_NPE_if_argument_is_null() {
assertThatThrownBy(() -> ServerId.parse(null))
@@ -84,7 +85,7 @@ public class ServerIdTest {
String startWithSplitChar = SPLIT_CHARACTER + randomAlphabetic(DATABASE_ID_LENGTH - 1);
Stream databaseIds = Stream.of(
- UuidFactoryImpl.INSTANCE.create(),
+ OLD_UUID_FORMAT,
randomAlphabetic(NOT_UUID_DATASET_ID_LENGTH),
randomAlphabetic(UUID_DATASET_ID_LENGTH),
repeat(SPLIT_CHARACTER + "", NOT_UUID_DATASET_ID_LENGTH),
@@ -130,7 +131,7 @@ public class ServerIdTest {
@DataProvider
public static Object[][] validOldFormatServerIds() {
return new Object[][] {
- {UuidFactoryImpl.INSTANCE.create()},
+ {OLD_UUID_FORMAT},
{randomAlphabetic(NOT_UUID_DATASET_ID_LENGTH)},
{repeat(SPLIT_CHARACTER + "", NOT_UUID_DATASET_ID_LENGTH)},
{randomAlphabetic(UUID_DATASET_ID_LENGTH)},
@@ -158,7 +159,7 @@ public class ServerIdTest {
{randomAlphabetic(DATABASE_ID_LENGTH), randomAlphabetic(UUID_DATASET_ID_LENGTH)},
{randomAlphabetic(DATABASE_ID_LENGTH), repeat(SPLIT_CHARACTER + "", NOT_UUID_DATASET_ID_LENGTH)},
{randomAlphabetic(DATABASE_ID_LENGTH), repeat(SPLIT_CHARACTER + "", UUID_DATASET_ID_LENGTH)},
- {randomAlphabetic(DATABASE_ID_LENGTH), UuidFactoryImpl.INSTANCE.create()},
+ {randomAlphabetic(DATABASE_ID_LENGTH), OLD_UUID_FORMAT},
};
}
diff --git a/sonar-core/src/test/java/org/sonar/core/util/MacAddressProviderTest.java b/sonar-core/src/test/java/org/sonar/core/util/MacAddressProviderTest.java
deleted file mode 100644
index ec0fab5f1de..00000000000
--- a/sonar-core/src/test/java/org/sonar/core/util/MacAddressProviderTest.java
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * 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.core.util;
-
-import org.junit.Test;
-
-import static org.assertj.core.api.Assertions.assertThat;
-
-public class MacAddressProviderTest {
-
- @Test
- public void getSecureMungedAddress() {
- byte[] address = MacAddressProvider.getSecureMungedAddress();
- assertThat(address)
- .isNotEmpty()
- .hasSize(6);
- }
-
- @Test
- public void constructDummyMulticastAddress() {
- byte[] address = MacAddressProvider.constructDummyMulticastAddress();
- assertThat(address)
- .isNotEmpty()
- .hasSize(6);
- }
-}
diff --git a/sonar-core/src/test/java/org/sonar/core/util/SequenceUuidFactoryTest.java b/sonar-core/src/test/java/org/sonar/core/util/SequenceUuidFactoryTest.java
index 3f9bc66ec05..ae42c493859 100644
--- a/sonar-core/src/test/java/org/sonar/core/util/SequenceUuidFactoryTest.java
+++ b/sonar-core/src/test/java/org/sonar/core/util/SequenceUuidFactoryTest.java
@@ -26,12 +26,20 @@ import static org.assertj.core.api.Assertions.assertThat;
public class SequenceUuidFactoryTest {
- private SequenceUuidFactory underTest = new SequenceUuidFactory();
+ private final SequenceUuidFactory underTest = new SequenceUuidFactory();
@Test
public void generate_sequence_of_integer_ids() {
- for (int i = 1; i < 10; i++) {
- assertThat(underTest.create()).isEqualTo(String.valueOf(i));
- }
+ assertThat(underTest.create()).isEqualTo("00000000-0000-0000-0000-000000000001");
+ assertThat(underTest.create()).isEqualTo("00000000-0000-0000-0000-000000000002");
+ assertThat(underTest.create()).isEqualTo("00000000-0000-0000-0000-000000000003");
+ assertThat(underTest.create()).isEqualTo("00000000-0000-0000-0000-000000000004");
+ assertThat(underTest.create()).isEqualTo("00000000-0000-0000-0000-000000000005");
+ assertThat(underTest.create()).isEqualTo("00000000-0000-0000-0000-000000000006");
+ assertThat(underTest.create()).isEqualTo("00000000-0000-0000-0000-000000000007");
+ assertThat(underTest.create()).isEqualTo("00000000-0000-0000-0000-000000000008");
+ assertThat(underTest.create()).isEqualTo("00000000-0000-0000-0000-000000000009");
+ assertThat(underTest.create()).isEqualTo("00000000-0000-0000-0000-000000000010");
}
+
}
diff --git a/sonar-core/src/test/java/org/sonar/core/util/UuidGeneratorImplTest.java b/sonar-core/src/test/java/org/sonar/core/util/UuidGeneratorImplTest.java
deleted file mode 100644
index 45889766ab1..00000000000
--- a/sonar-core/src/test/java/org/sonar/core/util/UuidGeneratorImplTest.java
+++ /dev/null
@@ -1,130 +0,0 @@
-/*
- * 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.core.util;
-
-import java.util.ArrayList;
-import java.util.Base64;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Set;
-import java.util.concurrent.atomic.AtomicInteger;
-import org.junit.Test;
-
-import static org.assertj.core.api.Assertions.assertThat;
-
-public class UuidGeneratorImplTest {
- private UuidGeneratorImpl underTest = new UuidGeneratorImpl();
-
- @Test
- public void generate_returns_unique_values_without_common_initial_letter_given_more_than_one_millisecond_between_generate_calls() throws InterruptedException {
- Base64.Encoder encoder = Base64.getEncoder();
- int count = 30;
- Set uuids = new HashSet<>(count);
- for (int i = 0; i < count; i++) {
- Thread.sleep(5);
- uuids.add(encoder.encodeToString(underTest.generate()));
- }
- assertThat(uuids).hasSize(count);
-
- Iterator iterator = uuids.iterator();
- String firstUuid = iterator.next();
- String base = firstUuid.substring(0, firstUuid.length() - 4);
- for (int i = 1; i < count; i++) {
- assertThat(iterator.next()).describedAs("i=" + i).doesNotStartWith(base);
- }
- }
-
- @Test
- public void generate_concurrent_test() throws InterruptedException {
- int rounds = 500;
- List uuids1 = new ArrayList<>(rounds);
- List uuids2 = new ArrayList<>(rounds);
- Thread t1 = new Thread(() -> {
- for (int i = 0; i < rounds; i++) {
- uuids1.add(underTest.generate());
- }
- });
- Thread t2 = new Thread(() -> {
- for (int i = 0; i < rounds; i++) {
- uuids2.add(underTest.generate());
- }
- });
- t1.start();
- t2.start();
- t1.join();
- t2.join();
-
- Base64.Encoder encoder = Base64.getEncoder();
- Set uuids = new HashSet<>(rounds * 2);
- uuids1.forEach(bytes -> uuids.add(encoder.encodeToString(bytes)));
- uuids2.forEach(bytes -> uuids.add(encoder.encodeToString(bytes)));
- assertThat(uuids).hasSize(rounds * 2);
- }
-
- @Test
- public void generate_from_FixedBase_returns_unique_values_where_only_last_4_later_letter_change() {
- Base64.Encoder encoder = Base64.getEncoder();
- int count = 100_000;
- Set uuids = new HashSet<>(count);
-
- UuidGenerator.WithFixedBase withFixedBase = underTest.withFixedBase();
- for (int i = 0; i < count; i++) {
- uuids.add(encoder.encodeToString(withFixedBase.generate(i)));
- }
- assertThat(uuids).hasSize(count);
-
- Iterator iterator = uuids.iterator();
- String firstUuid = iterator.next();
- String base = firstUuid.substring(0, firstUuid.length() - 4);
- while (iterator.hasNext()) {
- assertThat(iterator.next()).startsWith(base);
- }
- }
-
- @Test
- public void generate_from_FixedBase_concurrent_test() throws InterruptedException {
- UuidGenerator.WithFixedBase withFixedBase = underTest.withFixedBase();
- int rounds = 500;
- List uuids1 = new ArrayList<>(rounds);
- List uuids2 = new ArrayList<>(rounds);
- AtomicInteger cnt = new AtomicInteger();
- Thread t1 = new Thread(() -> {
- for (int i = 0; i < rounds; i++) {
- uuids1.add(withFixedBase.generate(cnt.getAndIncrement()));
- }
- });
- Thread t2 = new Thread(() -> {
- for (int i = 0; i < rounds; i++) {
- uuids2.add(withFixedBase.generate(cnt.getAndIncrement()));
- }
- });
- t1.start();
- t2.start();
- t1.join();
- t2.join();
-
- Base64.Encoder encoder = Base64.getEncoder();
- Set uuids = new HashSet<>(rounds * 2);
- uuids1.forEach(bytes -> uuids.add(encoder.encodeToString(bytes)));
- uuids2.forEach(bytes -> uuids.add(encoder.encodeToString(bytes)));
- assertThat(uuids).hasSize(rounds * 2);
- }
-}