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); - } -}