]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-21290 Use UUIDs v4 for all database identifiers
authorAurelien Poscia <aurelien.poscia@sonarsource.com>
Fri, 19 Jan 2024 09:08:55 +0000 (10:08 +0100)
committersonartech <sonartech@sonarsource.com>
Thu, 25 Jan 2024 20:02:56 +0000 (20:02 +0000)
50 files changed:
server/sonar-ce-task-projectanalysis/src/it/java/org/sonar/ce/task/projectanalysis/step/LoadFileHashesAndStatusStepIT.java
server/sonar-ce-task-projectanalysis/src/it/java/org/sonar/ce/task/projectexport/file/ExportLineHashesStepIT.java
server/sonar-db-dao/src/it/java/org/sonar/db/alm/setting/AlmSettingDaoWithPersisterIT.java
server/sonar-db-dao/src/it/java/org/sonar/db/alm/setting/ProjectAlmSettingDaoIT.java
server/sonar-db-dao/src/it/java/org/sonar/db/measure/LiveMeasureDaoIT.java
server/sonar-db-dao/src/it/java/org/sonar/db/notification/NotificationQueueDaoIT.java
server/sonar-db-dao/src/it/java/org/sonar/db/permission/GroupPermissionDaoIT.java
server/sonar-db-dao/src/it/java/org/sonar/db/permission/GroupPermissionDaoWithPersisterIT.java
server/sonar-db-dao/src/it/java/org/sonar/db/purge/PurgeCommandsIT.java
server/sonar-db-dao/src/it/java/org/sonar/db/pushevent/PushEventDaoIT.java
server/sonar-db-dao/src/it/java/org/sonar/db/qualityprofile/QProfileEditGroupsDaoIT.java
server/sonar-db-dao/src/it/java/org/sonar/db/qualityprofile/QProfileEditUsersDaoIT.java
server/sonar-db-dao/src/it/java/org/sonar/db/qualityprofile/QualityProfileDaoIT.java
server/sonar-db-dao/src/it/java/org/sonar/db/user/RoleDaoIT.java
server/sonar-db-dao/src/it/java/org/sonar/db/user/UserGroupDaoIT.java
server/sonar-db-dao/src/main/java/org/sonar/db/user/UserGroupDto.java
server/sonar-db-dao/src/main/resources/org/sonar/db/measure/LiveMeasureMapper.xml
server/sonar-db-migration/src/it/java/org/sonar/server/platform/db/migration/version/v100/RemoveOrphanRulesFromQualityProfilesIT.java
server/sonar-server-common/src/main/java/org/sonar/server/platform/serverid/MacAddressProvider.java [new file with mode: 0644]
server/sonar-server-common/src/main/java/org/sonar/server/platform/serverid/ServerIdGenerator.java [new file with mode: 0644]
server/sonar-server-common/src/test/java/org/sonar/server/platform/serverid/MacAddressProviderTest.java [new file with mode: 0644]
server/sonar-server-common/src/test/java/org/sonar/server/platform/serverid/ServerIdGeneratorTest.java [new file with mode: 0644]
server/sonar-webserver-core/src/main/java/org/sonar/server/platform/serverid/ServerIdFactoryImpl.java
server/sonar-webserver-core/src/main/java/org/sonar/server/platform/serverid/ServerIdModule.java
server/sonar-webserver-core/src/main/java/org/sonar/server/platform/web/requestid/HttpRequestIdModule.java
server/sonar-webserver-core/src/main/java/org/sonar/server/platform/web/requestid/RequestIdConfiguration.java [deleted file]
server/sonar-webserver-core/src/main/java/org/sonar/server/platform/web/requestid/RequestIdGeneratorBase.java [deleted file]
server/sonar-webserver-core/src/main/java/org/sonar/server/platform/web/requestid/RequestIdGeneratorBaseImpl.java [deleted file]
server/sonar-webserver-core/src/main/java/org/sonar/server/platform/web/requestid/RequestIdGeneratorImpl.java
server/sonar-webserver-core/src/test/java/org/sonar/server/platform/serverid/ServerIdFactoryImplTest.java
server/sonar-webserver-core/src/test/java/org/sonar/server/platform/serverid/ServerIdModuleTest.java
server/sonar-webserver-core/src/test/java/org/sonar/server/platform/web/requestid/HttpRequestIdModuleTest.java
server/sonar-webserver-core/src/test/java/org/sonar/server/platform/web/requestid/RequestIdConfigurationTest.java [deleted file]
server/sonar-webserver-core/src/test/java/org/sonar/server/platform/web/requestid/RequestIdGeneratorImplTest.java
server/sonar-webserver-webapi/src/it/java/org/sonar/server/almintegration/ws/azure/SearchAzureReposActionIT.java
server/sonar-webserver-webapi/src/it/java/org/sonar/server/almintegration/ws/bitbucketserver/SearchBitbucketServerReposActionIT.java
server/sonar-webserver-webapi/src/it/java/org/sonar/server/almintegration/ws/gitlab/SearchGitlabReposActionIT.java
server/sonar-webserver-webapi/src/it/java/org/sonar/server/component/ws/SearchProjectsActionIT.java
server/sonar-webserver-webapi/src/it/java/org/sonar/server/qualitygate/ws/SearchActionIT.java
server/sonar-webserver-webapi/src/it/java/org/sonar/server/qualityprofile/ws/CopyActionIT.java
sonar-core/src/main/java/org/sonar/core/util/MacAddressProvider.java [deleted file]
sonar-core/src/main/java/org/sonar/core/util/SequenceUuidFactory.java
sonar-core/src/main/java/org/sonar/core/util/UuidFactoryFast.java
sonar-core/src/main/java/org/sonar/core/util/UuidFactoryImpl.java
sonar-core/src/main/java/org/sonar/core/util/UuidGenerator.java [deleted file]
sonar-core/src/main/java/org/sonar/core/util/UuidGeneratorImpl.java [deleted file]
sonar-core/src/test/java/org/sonar/core/platform/ServerIdTest.java
sonar-core/src/test/java/org/sonar/core/util/MacAddressProviderTest.java [deleted file]
sonar-core/src/test/java/org/sonar/core/util/SequenceUuidFactoryTest.java
sonar-core/src/test/java/org/sonar/core/util/UuidGeneratorImplTest.java [deleted file]

index 2dd7b1448856c198be406c4c34bfbf8353d88f5e..8a887c2c0589ab1578b3c825d3211b32d0f9e16c 100644 (file)
@@ -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()));
     }
   }
 }
index 3db9bfce88ddf397a8eeeb59898866136cfacea0..07c6a53a70fe4a16c8cff82133cfa1c487bdf9db 100644 (file)
@@ -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);
index c83510727e31324427835e79e76b8a3c077a3423..6ac0ba9e64c9d265cb50eaaaf453b9e92fef5843 100644 (file)
@@ -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\" }");
   }
 
index b96ba71b80248baf0b8fa7f3eb122a10621aa754..07dcc3b1b5f338506c685d3016e49f941ed08204 100644 (file)
@@ -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;
index fed6586c00cb221673d073bf19f98357a1638998..bfff26aa439ab72a57f143f24d51a1d76bca50d1 100644 (file)
@@ -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<LargestBranchNclocDto> results = underTest.getLargestBranchNclocPerProject(db.getSession(), ncloc.getUuid());
+    Map<String, LargestBranchNclocDto> 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<ProjectLocDistributionDto> 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);
   }
index 3299c2ebb84f47c0df62b515fabb517327f1b9f0..741047f03637365cd9016afeb9f47905fab8b610 100644 (file)
@@ -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<String> selectAllUuid() {
index 4fa74696581ee07e34f5176cfea0baa41bbc32f9..fb51c5a3fe04efcf185ce15afde2046e061431fa 100644 (file)
@@ -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<String> 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
index b067b087053ba2f2e7fa9e9b05f53d081144d63f..9355aca8b30efd75e852990a349b81d594e7ed22 100644 (file)
@@ -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) {
index 9c042c63edfc119d1d097eef868f79ffe128d270..a44162eb39b656fdf0c48b2296b75c46b7524ad4 100644 (file)
@@ -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<AnticipatedTransitionDto> 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
index 33d3eb075967566a2b0a3c29c778a3c7fb2986bf..8447c7b116dd4e676a0ea2f7cadc7536cce84a2b 100644 (file)
  */
 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<String> 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
index b45bc3291a96ee251c458ad47d44d9a5f9105c30..e31ea5316cb17113013e4b1f26207f8d5dc06b67 100644 (file)
@@ -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<GroupEditorNewValue> newValues = newValueCaptor.getAllValues();
-    assertThat(newValues.get(0))
+    Map<String, GroupEditorNewValue> 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();
index 6f0e94a24e61c88cfd29ce8580da76f18488dd23..10ce71b116330e2bf2c19252e3a29c169cf8751c 100644 (file)
@@ -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<UserEditorNewValue> 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<String, UserEditorNewValue> 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();
index 04fbf0678aa37ce6733fb5bc167c13a7e8de5f7d..7b9c7c993768857e0a47d6f47851d6622e9cafc8 100644 (file)
@@ -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);
index 775a2e263f5b0893651195829ac02726b510fa85..a8fff65d9e8b656cb86c06487f174477e779cd8d 100644 (file)
@@ -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<String> 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
index d1fea6009fbf5196c463e6b38852c36bfcdf6fa3..6124ee720da12351f5b8ec9e804261890b2bc178 100644 (file)
@@ -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<UserGroupDto> 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());
   }
 
index c44791a161b4e850b8b1a22a7971de8c21c846f0..378af5af47fa4642b745c87d282cc96f34ca4290 100644 (file)
@@ -73,4 +73,5 @@ public class UserGroupDto {
   public int hashCode() {
     return Objects.hash(userUuid, groupUuid);
   }
+
 }
index 33fc01d73555791aad2eed00604e25f385d0d0a1..d43d11c2db5c82315bc537eb48288f7d9b6df9ec 100644 (file)
@@ -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
     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
index 44f403ccad5a360c0f2670cec99452ba5aabb81c..663ac914ded4a51a97ac953bb99af9203695c463 100644 (file)
@@ -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 (file)
index 0000000..91b5f7d
--- /dev/null
@@ -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<NetworkInterface> 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 (file)
index 0000000..a25738b
--- /dev/null
@@ -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<byte[]> {
+
+    @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 (file)
index 0000000..6babb49
--- /dev/null
@@ -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 (file)
index 0000000..dcb13c1
--- /dev/null
@@ -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<String> ids1 = new ArrayList<>(rounds);
+    List<String> 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<String> ids = new HashSet<>(rounds * 2);
+    ids.addAll(ids1);
+    ids.addAll(ids2);
+    assertThat(ids).hasSize(rounds * 2);
+  }
+
+}
index 4ced9a60b8fdb0829800c86ec3a91186e5928fcb..2951a33ee2ca4d04260acbf03ce6dc084e2afbea 100644 (file)
@@ -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
index 1df5c1c7968c0233c2310ef01e56ab0fef2f6454..b1b76e0ad7f4c25c05b5c02ca0daab92d93230c9 100644 (file)
@@ -28,8 +28,8 @@ public class ServerIdModule extends Module {
       ServerIdFactoryImpl.class,
       JdbcUrlSanitizer.class,
       ServerIdChecksum.class,
-      ServerIdManager.class
-
+      ServerIdManager.class,
+      ServerIdGenerator.class
     );
   }
 }
index 57973cdeddaf824c0f017cc4e90c73ceedcb18bf..b52fd08ea3a3d4c8626c1a35396de3e5e0dca647 100644 (file)
@@ -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 (file)
index 5a204b5..0000000
+++ /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 (file)
index c1277ca..0000000
+++ /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 (file)
index a028489..0000000
+++ /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();
-  }
-}
index 198f3ae8373afcb8d9ed88cd4649b8db8960529c..9dbb734a0279bf15c058beab6897b1af2e5b3553 100644 (file)
  */
 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.
- * <p>
- * 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.
- * </p>
- * <p>
- * This implementation is Thread safe.
- * </p>
- */
 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)}).
-   *
-   * <p>
-   * 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.
-   * </p>
-   *
-   * <p>
-   * To keep a comfortable margin of error, 2^22 will be used.
-   * </p>
-   */
-  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.WithFixedBase> 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.
-   * <p>
-   * The value to which the counter is compared should however be chosen with caution: see {@link #UUID_GENERATOR_RENEWAL_COUNT}.
-   * </p>
-   */
-  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();
   }
 
 }
index ee3926960905f1d6cd4f8ea4931cc524884caab8..2e1c3f5cf4b2ccd4f2ab4fd259a4caa517e7b815 100644 (file)
@@ -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);
index e1e7723b05b9ce54236896543578f9c63500eac8..8660e094b1047bba7cb2973c656ea9464307043b 100644 (file)
@@ -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);
   }
 }
index d9c4674c4b86e38471674e542aa2d7434685ecda..9530702d414d5ba736e2bb15d81692cb6f5c7629 100644 (file)
@@ -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 (file)
index 98d1aaf..0000000
+++ /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);
-  }
-}
index 42a869ae1c9818b45b965df41fab268aaf726cd5..99eca9c0256b2326fdac11b46b75eb916d2168aa 100644 (file)
 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);
   }
 }
index 0e95cdfb3e3e191c60180ef00060f95f0d1466ff..5fc3dde9b64eaa276ae6198c532f4080607cd0ed 100644 (file)
@@ -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;
index e1eb6c84cf9967b30311a430c98f5462d37b3009..30268f3a4debb44db18d92d9b5e077db7c06096b 100644 (file)
@@ -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())
index 3a0ab0c5d280eafc8ae5791e22051bfd5252425a..42be74f8e87b05aef971d202f2955dc7b8e67759 100644 (file)
@@ -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()
index 317ae8dcfa945620d447813e0e1a6ed8bb1eae44..eda28adb2fe880ec5238437df282bcea77be1296 100644 (file)
@@ -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("<null>=2;java=6;xoo=18")));
+    ComponentDto project1 = insertProject(new Measure(languagesDistributionMetric,
+      c -> c.setValue(null).setData("<null>=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("<null>=1;java=5;xoo=13")));
+    ComponentDto project4 = insertProject(new Measure(languagesDistributionMetric,
+      c -> c.setValue(null).setData("<null>=1;java=5;xoo=13")));
     db.measures().insertLiveMeasure(project4, nclocMetric, m -> m.setValue(19d));
     index();
 
     SearchProjectsWsResponse result = call(request.setFilter("languages IN (java, js, <null>)"));
 
-    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("<null>=2;java=6;xoo=18")));
+    ComponentDto project1 = insertProject(new Measure(languagesDistributionMetric,
+      c -> c.setValue(null).setData("<null>=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<ComponentDto> 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<ComponentDto> componentConsumer, Measure... measures) {
index 185aeda7662217238899cc116fbf27c47580340b..cf8d8ee4a674170480aba2046c708b677c3be9de 100644 (file)
@@ -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
index d5412e3c5ad1e56e0ef336c0a88e7ab0fe9daaef..1d59852711d5a7da70fe4979ec0ca7e88739a613 100644 (file)
@@ -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 (file)
index a7ca171..0000000
+++ /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<NetworkInterface> 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;
-  }
-
-}
index f4b9021595c2c06dd00679f1d3700822fa0b7aba..32b10651ead4d9b95e049ba795fbea0c3c6b7b07 100644 (file)
  */
 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");
   }
 }
index f19744c23ca57291f7ada0e712d96215c78b155a..3159b4466841dd426e5fbbabf2b7f15e07867dc5 100644 (file)
  */
 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);
-  }
 
 }
index a80d3becd1d689f13a9477771f120278d60110cd..01d29a06563fd87c8566ca5dfc9a4767aa99905c 100644 (file)
@@ -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 (file)
index c982daa..0000000
+++ /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:
- * <ul>
- *   <li>a base, which is machine and time dependant and therefor will change with time</li>
- *   <li>an increment</li>
- * </ul>
- *
- * <p>
- * This generator can be used in two ways:
- * <ul>
- *   <li>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</li>
- *   <li>or the increment can be the only changing part (for performance boost and less concurrency) and
- *   {@link #withFixedBase()} should be used.</li>
- * </ul>
- * </p>
- *
- * <p>
- * <strong>Warning:</strong> {@link WithFixedBase#generate(int)} can be considerably faster than {@link #generate()} but
- * is limited to generate only 2^23-1 unique values.
- * </p>
- *
- * <p>
- * 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
- * </p>
- */
-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.
-     * <p>
-     * <strong>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.</strong>
-     * </p>
-     * <p>
-     * This is up to the caller to ensure that unique int values are provided to a given instance's {@link #generate(int)}
-     * method.
-     * </p>
-     * <p>
-     * This method is faster than {@link UuidGenerator#generate()} due to less computation and less internal concurrency.
-     * </p>
-     */
-    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 (file)
index 2328b29..0000000
+++ /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<byte[]> {
-
-    @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);
-    }
-  }
-}
index 97bad79bb3cd41f92fa1b2e84d37593e538c0dc2..c427f1abc8a2bd9551d7e18e3a6dd8c08e6ca58d 100644 (file)
@@ -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<String> 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 (file)
index ec0fab5..0000000
+++ /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);
-  }
-}
index 3f9bc66ec05ef25eb2caed5c0b2a1e7c48ac8d8f..ae42c493859335d143f2ccf84caa730cd9b4b87d 100644 (file)
@@ -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 (file)
index 4588976..0000000
+++ /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<String> 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<String> 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<byte[]> uuids1 = new ArrayList<>(rounds);
-    List<byte[]> 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<String> 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<String> 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<String> 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<byte[]> uuids1 = new ArrayList<>(rounds);
-    List<byte[]> 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<String> 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);
-  }
-}