Bladeren bron

SONAR-21290 Use UUIDs v4 for all database identifiers

tags/10.4.0.87286
Aurelien Poscia 4 maanden geleden
bovenliggende
commit
858b1023bb
46 gewijzigde bestanden met toevoegingen van 318 en 670 verwijderingen
  1. 4
    4
      server/sonar-ce-task-projectanalysis/src/it/java/org/sonar/ce/task/projectanalysis/step/LoadFileHashesAndStatusStepIT.java
  2. 2
    2
      server/sonar-ce-task-projectanalysis/src/it/java/org/sonar/ce/task/projectexport/file/ExportLineHashesStepIT.java
  3. 7
    3
      server/sonar-db-dao/src/it/java/org/sonar/db/alm/setting/AlmSettingDaoWithPersisterIT.java
  4. 1
    1
      server/sonar-db-dao/src/it/java/org/sonar/db/alm/setting/ProjectAlmSettingDaoIT.java
  5. 23
    10
      server/sonar-db-dao/src/it/java/org/sonar/db/measure/LiveMeasureDaoIT.java
  6. 6
    4
      server/sonar-db-dao/src/it/java/org/sonar/db/notification/NotificationQueueDaoIT.java
  7. 4
    1
      server/sonar-db-dao/src/it/java/org/sonar/db/permission/GroupPermissionDaoIT.java
  8. 19
    10
      server/sonar-db-dao/src/it/java/org/sonar/db/permission/GroupPermissionDaoWithPersisterIT.java
  9. 3
    3
      server/sonar-db-dao/src/it/java/org/sonar/db/purge/PurgeCommandsIT.java
  10. 11
    2
      server/sonar-db-dao/src/it/java/org/sonar/db/pushevent/PushEventDaoIT.java
  11. 10
    6
      server/sonar-db-dao/src/it/java/org/sonar/db/qualityprofile/QProfileEditGroupsDaoIT.java
  12. 13
    12
      server/sonar-db-dao/src/it/java/org/sonar/db/qualityprofile/QProfileEditUsersDaoIT.java
  13. 1
    1
      server/sonar-db-dao/src/it/java/org/sonar/db/qualityprofile/QualityProfileDaoIT.java
  14. 3
    3
      server/sonar-db-dao/src/it/java/org/sonar/db/user/RoleDaoIT.java
  15. 22
    19
      server/sonar-db-dao/src/it/java/org/sonar/db/user/UserGroupDaoIT.java
  16. 1
    0
      server/sonar-db-dao/src/main/java/org/sonar/db/user/UserGroupDto.java
  17. 2
    2
      server/sonar-db-dao/src/main/resources/org/sonar/db/measure/LiveMeasureMapper.xml
  18. 2
    1
      server/sonar-db-migration/src/it/java/org/sonar/server/platform/db/migration/version/v100/RemoveOrphanRulesFromQualityProfilesIT.java
  19. 2
    1
      server/sonar-server-common/src/main/java/org/sonar/server/platform/serverid/MacAddressProvider.java
  20. 11
    29
      server/sonar-server-common/src/main/java/org/sonar/server/platform/serverid/ServerIdGenerator.java
  21. 1
    1
      server/sonar-server-common/src/test/java/org/sonar/server/platform/serverid/MacAddressProviderTest.java
  22. 31
    5
      server/sonar-server-common/src/test/java/org/sonar/server/platform/serverid/ServerIdGeneratorTest.java
  23. 4
    5
      server/sonar-webserver-core/src/main/java/org/sonar/server/platform/serverid/ServerIdFactoryImpl.java
  24. 2
    2
      server/sonar-webserver-core/src/main/java/org/sonar/server/platform/serverid/ServerIdModule.java
  25. 1
    3
      server/sonar-webserver-core/src/main/java/org/sonar/server/platform/web/requestid/HttpRequestIdModule.java
  26. 0
    35
      server/sonar-webserver-core/src/main/java/org/sonar/server/platform/web/requestid/RequestIdConfiguration.java
  27. 0
    29
      server/sonar-webserver-core/src/main/java/org/sonar/server/platform/web/requestid/RequestIdGeneratorBase.java
  28. 0
    31
      server/sonar-webserver-core/src/main/java/org/sonar/server/platform/web/requestid/RequestIdGeneratorBaseImpl.java
  29. 2
    67
      server/sonar-webserver-core/src/main/java/org/sonar/server/platform/web/requestid/RequestIdGeneratorImpl.java
  30. 8
    8
      server/sonar-webserver-core/src/test/java/org/sonar/server/platform/serverid/ServerIdFactoryImplTest.java
  31. 1
    1
      server/sonar-webserver-core/src/test/java/org/sonar/server/platform/serverid/ServerIdModuleTest.java
  32. 1
    1
      server/sonar-webserver-core/src/test/java/org/sonar/server/platform/web/requestid/HttpRequestIdModuleTest.java
  33. 6
    56
      server/sonar-webserver-core/src/test/java/org/sonar/server/platform/web/requestid/RequestIdGeneratorImplTest.java
  34. 3
    1
      server/sonar-webserver-webapi/src/it/java/org/sonar/server/almintegration/ws/azure/SearchAzureReposActionIT.java
  35. 3
    3
      server/sonar-webserver-webapi/src/it/java/org/sonar/server/almintegration/ws/bitbucketserver/SearchBitbucketServerReposActionIT.java
  36. 4
    4
      server/sonar-webserver-webapi/src/it/java/org/sonar/server/almintegration/ws/gitlab/SearchGitlabReposActionIT.java
  37. 53
    31
      server/sonar-webserver-webapi/src/it/java/org/sonar/server/component/ws/SearchProjectsActionIT.java
  38. 3
    3
      server/sonar-webserver-webapi/src/it/java/org/sonar/server/qualitygate/ws/SearchActionIT.java
  39. 7
    8
      server/sonar-webserver-webapi/src/it/java/org/sonar/server/qualityprofile/ws/CopyActionIT.java
  40. 12
    2
      sonar-core/src/main/java/org/sonar/core/util/SequenceUuidFactory.java
  41. 10
    38
      sonar-core/src/main/java/org/sonar/core/util/UuidFactoryFast.java
  42. 2
    4
      sonar-core/src/main/java/org/sonar/core/util/UuidFactoryImpl.java
  43. 0
    80
      sonar-core/src/main/java/org/sonar/core/util/UuidGenerator.java
  44. 5
    4
      sonar-core/src/test/java/org/sonar/core/platform/ServerIdTest.java
  45. 12
    4
      sonar-core/src/test/java/org/sonar/core/util/SequenceUuidFactoryTest.java
  46. 0
    130
      sonar-core/src/test/java/org/sonar/core/util/UuidGeneratorImplTest.java

+ 4
- 4
server/sonar-ce-task-projectanalysis/src/it/java/org/sonar/ce/task/projectanalysis/step/LoadFileHashesAndStatusStepIT.java Bestand weergeven

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

+ 2
- 2
server/sonar-ce-task-projectanalysis/src/it/java/org/sonar/ce/task/projectexport/file/ExportLineHashesStepIT.java Bestand weergeven

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

+ 7
- 3
server/sonar-db-dao/src/it/java/org/sonar/db/alm/setting/AlmSettingDaoWithPersisterIT.java Bestand weergeven

@@ -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\" }");
}


+ 1
- 1
server/sonar-db-dao/src/it/java/org/sonar/db/alm/setting/ProjectAlmSettingDaoIT.java Bestand weergeven

@@ -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;

+ 23
- 10
server/sonar-db-dao/src/it/java/org/sonar/db/measure/LiveMeasureDaoIT.java Bestand weergeven

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

+ 6
- 4
server/sonar-db-dao/src/it/java/org/sonar/db/notification/NotificationQueueDaoIT.java Bestand weergeven

@@ -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() {

+ 4
- 1
server/sonar-db-dao/src/it/java/org/sonar/db/permission/GroupPermissionDaoIT.java Bestand weergeven

@@ -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

+ 19
- 10
server/sonar-db-dao/src/it/java/org/sonar/db/permission/GroupPermissionDaoWithPersisterIT.java Bestand weergeven

@@ -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) {

+ 3
- 3
server/sonar-db-dao/src/it/java/org/sonar/db/purge/PurgeCommandsIT.java Bestand weergeven

@@ -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

+ 11
- 2
server/sonar-db-dao/src/it/java/org/sonar/db/pushevent/PushEventDaoIT.java Bestand weergeven

@@ -19,8 +19,11 @@
*/
package org.sonar.db.pushevent;

import java.util.Comparator;
import java.util.List;
import java.util.Set;
import java.util.stream.IntStream;
import java.util.stream.Stream;
import org.junit.Rule;
import org.junit.Test;
import org.sonar.api.impl.utils.TestSystem2;
@@ -69,7 +72,8 @@ public class PushEventDaoIT {

assertThat(underTest.selectByUuid(session, generatedUuid.getUuid()))
.extracting(PushEventDto::getUuid, PushEventDto::getProjectUuid, PushEventDto::getPayload, PushEventDto::getCreatedAt)
.containsExactly(eventDtoSecond.getUuid(), eventDtoSecond.getProjectUuid(), eventDtoSecond.getPayload(), eventDtoSecond.getCreatedAt());
.containsExactly(eventDtoSecond.getUuid(), eventDtoSecond.getProjectUuid(), eventDtoSecond.getPayload(),
eventDtoSecond.getCreatedAt());

}

@@ -147,7 +151,12 @@ public class PushEventDaoIT {
var eventDto7 = generatePushEvent("proj2");

events = underTest.selectChunkByProjectUuids(session, Set.of("proj1", "proj2"), eventDto4.getCreatedAt(), eventDto4.getUuid(), 10);
assertThat(events).extracting(PushEventDto::getUuid).containsExactly(eventDto5.getUuid(), eventDto6.getUuid(), eventDto7.getUuid());
List<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

+ 10
- 6
server/sonar-db-dao/src/it/java/org/sonar/db/qualityprofile/QProfileEditGroupsDaoIT.java Bestand weergeven

@@ -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();

+ 13
- 12
server/sonar-db-dao/src/it/java/org/sonar/db/qualityprofile/QProfileEditUsersDaoIT.java Bestand weergeven

@@ -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();

+ 1
- 1
server/sonar-db-dao/src/it/java/org/sonar/db/qualityprofile/QualityProfileDaoIT.java Bestand weergeven

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

+ 3
- 3
server/sonar-db-dao/src/it/java/org/sonar/db/user/RoleDaoIT.java Bestand weergeven

@@ -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

+ 22
- 19
server/sonar-db-dao/src/it/java/org/sonar/db/user/UserGroupDaoIT.java Bestand weergeven

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


+ 1
- 0
server/sonar-db-dao/src/main/java/org/sonar/db/user/UserGroupDto.java Bestand weergeven

@@ -73,4 +73,5 @@ public class UserGroupDto {
public int hashCode() {
return Objects.hash(userUuid, groupUuid);
}

}

+ 2
- 2
server/sonar-db-dao/src/main/resources/org/sonar/db/measure/LiveMeasureMapper.xml Bestand weergeven

@@ -91,7 +91,7 @@
pb.kee as branchName,
pb.branch_type as branchType,
lm.value as ncloc,
row_number() over (partition by pb.project_uuid order by lm.value desc, pb.uuid asc) row_number
row_number() over (partition by pb.project_uuid order by lm.value desc, pb.is_main desc, pb.uuid asc) row_number
from live_measures lm
inner join project_branches pb on pb.uuid = lm.component_uuid
inner join projects p on p.uuid = pb.project_uuid
@@ -109,7 +109,7 @@
SELECT loc_grouped_branches.uuid, loc_grouped_branches.project_uuid
FROM (
SELECT b.uuid, b.project_uuid, ROW_NUMBER() OVER (PARTITION BY
b.project_uuid ORDER BY lm.value desc, b.uuid asc) row_number
b.project_uuid ORDER BY lm.value desc, b.is_main desc, b.uuid asc) row_number
from live_measures lm
inner join project_branches b on b.uuid = lm.component_uuid
inner join projects p on p.uuid = b.project_uuid

+ 2
- 1
server/sonar-db-migration/src/it/java/org/sonar/server/platform/db/migration/version/v100/RemoveOrphanRulesFromQualityProfilesIT.java Bestand weergeven

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



sonar-core/src/main/java/org/sonar/core/util/MacAddressProvider.java → server/sonar-server-common/src/main/java/org/sonar/server/platform/serverid/MacAddressProvider.java Bestand weergeven

@@ -17,7 +17,7 @@
* 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;
package org.sonar.server.platform.serverid;

import com.google.common.annotations.VisibleForTesting;
import java.net.NetworkInterface;
@@ -28,6 +28,7 @@ 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

sonar-core/src/main/java/org/sonar/core/util/UuidGeneratorImpl.java → server/sonar-server-common/src/main/java/org/sonar/server/platform/serverid/ServerIdGenerator.java Bestand weergeven

@@ -17,27 +17,22 @@
* 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;
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 UuidGeneratorImpl implements UuidGenerator {
public final class ServerIdGenerator {

private final FullNewUuidGenerator fullNewUuidGenerator = new FullNewUuidGenerator();
private final FullNewIdGenerator fullNewIdGenerator = new FullNewIdGenerator();

@Override
public byte[] generate() {
return fullNewUuidGenerator.get();
public String generate() {
return Base64.encodeBase64URLSafeString(fullNewIdGenerator.get());
}

@Override
public WithFixedBase withFixedBase() {
return new FixedBasedUuidGenerator();
}

private static class UuidGeneratorBase {
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());
@@ -80,7 +75,9 @@ public final class UuidGeneratorImpl implements UuidGenerator {
return sequenceNumber.incrementAndGet() & 0xffffff;
}

/** Puts the lower numberOfLongBytes from l into the array, starting index pos. */
/**
* 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));
@@ -88,7 +85,7 @@ public final class UuidGeneratorImpl implements UuidGenerator {
}
}

private static final class FullNewUuidGenerator extends UuidGeneratorBase implements Supplier<byte[]> {
private static final class FullNewIdGenerator extends IdGeneratorBase implements Supplier<byte[]> {

@Override
public byte[] get() {
@@ -99,19 +96,4 @@ public final class UuidGeneratorImpl implements UuidGenerator {
}
}

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

sonar-core/src/test/java/org/sonar/core/util/MacAddressProviderTest.java → server/sonar-server-common/src/test/java/org/sonar/server/platform/serverid/MacAddressProviderTest.java Bestand weergeven

@@ -17,7 +17,7 @@
* 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;
package org.sonar.server.platform.serverid;

import org.junit.Test;


server/sonar-webserver-core/src/test/java/org/sonar/server/platform/web/requestid/RequestIdConfigurationTest.java → server/sonar-server-common/src/test/java/org/sonar/server/platform/serverid/ServerIdGeneratorTest.java Bestand weergeven

@@ -17,17 +17,43 @@
* 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;
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 RequestIdConfigurationTest {
private RequestIdConfiguration underTest = new RequestIdConfiguration(50);
public class ServerIdGeneratorTest {
private final ServerIdGenerator underTest = new ServerIdGenerator();

@Test
public void getUidGeneratorRenewalCount_returns_value_provided_from_constructor() {
assertThat(underTest.getUidGeneratorRenewalCount()).isEqualTo(50);
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);
}

}

+ 4
- 5
server/sonar-webserver-core/src/main/java/org/sonar/server/platform/serverid/ServerIdFactoryImpl.java Bestand weergeven

@@ -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

+ 2
- 2
server/sonar-webserver-core/src/main/java/org/sonar/server/platform/serverid/ServerIdModule.java Bestand weergeven

@@ -28,8 +28,8 @@ public class ServerIdModule extends Module {
ServerIdFactoryImpl.class,
JdbcUrlSanitizer.class,
ServerIdChecksum.class,
ServerIdManager.class
ServerIdManager.class,
ServerIdGenerator.class
);
}
}

+ 1
- 3
server/sonar-webserver-core/src/main/java/org/sonar/server/platform/web/requestid/HttpRequestIdModule.java Bestand weergeven

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

+ 0
- 35
server/sonar-webserver-core/src/main/java/org/sonar/server/platform/web/requestid/RequestIdConfiguration.java Bestand weergeven

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

+ 0
- 29
server/sonar-webserver-core/src/main/java/org/sonar/server/platform/web/requestid/RequestIdGeneratorBase.java Bestand weergeven

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

+ 0
- 31
server/sonar-webserver-core/src/main/java/org/sonar/server/platform/web/requestid/RequestIdGeneratorBaseImpl.java Bestand weergeven

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

+ 2
- 67
server/sonar-webserver-core/src/main/java/org/sonar/server/platform/web/requestid/RequestIdGeneratorImpl.java Bestand weergeven

@@ -19,78 +19,13 @@
*/
package org.sonar.server.platform.web.requestid;

import java.util.Base64;
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.atomic.AtomicReference;
import org.sonar.core.util.UuidGenerator;
import java.util.UUID;

/**
* This implementation of {@link RequestIdGenerator} creates unique identifiers for HTTP requests leveraging
* {@link UuidGenerator.WithFixedBase#generate(int)} and a counter of HTTP requests.
* <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();
}

}

+ 8
- 8
server/sonar-webserver-core/src/test/java/org/sonar/server/platform/serverid/ServerIdFactoryImplTest.java Bestand weergeven

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

+ 1
- 1
server/sonar-webserver-core/src/test/java/org/sonar/server/platform/serverid/ServerIdModuleTest.java Bestand weergeven

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

+ 1
- 1
server/sonar-webserver-core/src/test/java/org/sonar/server/platform/web/requestid/HttpRequestIdModuleTest.java Bestand weergeven

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

+ 6
- 56
server/sonar-webserver-core/src/test/java/org/sonar/server/platform/web/requestid/RequestIdGeneratorImplTest.java Bestand weergeven

@@ -20,69 +20,19 @@
package org.sonar.server.platform.web.requestid;

import org.junit.Test;
import org.sonar.core.util.UuidGenerator;

import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;

public class RequestIdGeneratorImplTest {

private UuidGenerator.WithFixedBase generator1 = increment -> new byte[] {124, 22, 66, 96, 55, 88, 2, 9};
private UuidGenerator.WithFixedBase generator2 = increment -> new byte[] {0, 5, 88, 81, 8, 6, 44, 19};
private UuidGenerator.WithFixedBase generator3 = increment -> new byte[] {126, 9, 35, 76, 2, 1, 2};
private RequestIdGeneratorBase uidGeneratorBase = mock(RequestIdGeneratorBase.class);
private IllegalStateException expected = new IllegalStateException("Unexpected third call to createNew");
RequestIdGeneratorImpl requestIdGenerator = new RequestIdGeneratorImpl();

@Test
public void generate_renews_inner_UuidGenerator_instance_every_number_of_calls_to_generate_specified_in_RequestIdConfiguration_supports_2() {
when(uidGeneratorBase.createNew())
.thenReturn(generator1)
.thenReturn(generator2)
.thenReturn(generator3)
.thenThrow(expected);
public void generate_shouldGenerateUniqueIds() {
String requestId1 = requestIdGenerator.generate();
String requestId2 = requestIdGenerator.generate();
String requestId3 = requestIdGenerator.generate();

RequestIdGeneratorImpl underTest = new RequestIdGeneratorImpl(uidGeneratorBase, new RequestIdConfiguration(2));

assertThat(underTest.generate()).isEqualTo("fBZCYDdYAgk="); // using generator1
assertThat(underTest.generate()).isEqualTo("fBZCYDdYAgk="); // still using generator1
assertThat(underTest.generate()).isEqualTo("AAVYUQgGLBM="); // renewing generator and using generator2
assertThat(underTest.generate()).isEqualTo("AAVYUQgGLBM="); // still using generator2
assertThat(underTest.generate()).isEqualTo("fgkjTAIBAg=="); // renewing generator and using generator3
assertThat(underTest.generate()).isEqualTo("fgkjTAIBAg=="); // using generator3

assertThatThrownBy(() -> {
underTest.generate(); // renewing generator and failing
})
.isInstanceOf(IllegalStateException.class)
.hasMessage(expected.getMessage());
}

@Test
public void generate_renews_inner_UuidGenerator_instance_every_number_of_calls_to_generate_specified_in_RequestIdConfiguration_supports_3() {
when(uidGeneratorBase.createNew())
.thenReturn(generator1)
.thenReturn(generator2)
.thenReturn(generator3)
.thenThrow(expected);

RequestIdGeneratorImpl underTest = new RequestIdGeneratorImpl(uidGeneratorBase, new RequestIdConfiguration(3));

assertThat(underTest.generate()).isEqualTo("fBZCYDdYAgk="); // using generator1
assertThat(underTest.generate()).isEqualTo("fBZCYDdYAgk="); // still using generator1
assertThat(underTest.generate()).isEqualTo("fBZCYDdYAgk="); // still using generator1
assertThat(underTest.generate()).isEqualTo("AAVYUQgGLBM="); // renewing generator and using it
assertThat(underTest.generate()).isEqualTo("AAVYUQgGLBM="); // still using generator2
assertThat(underTest.generate()).isEqualTo("AAVYUQgGLBM="); // still using generator2
assertThat(underTest.generate()).isEqualTo("fgkjTAIBAg=="); // renewing generator and using it
assertThat(underTest.generate()).isEqualTo("fgkjTAIBAg=="); // using generator3
assertThat(underTest.generate()).isEqualTo("fgkjTAIBAg=="); // using generator3

assertThatThrownBy(() -> {
underTest.generate(); // renewing generator and failing
})
.isInstanceOf(IllegalStateException.class)
.hasMessage(expected.getMessage());
assertThat(requestId1).isNotEqualTo(requestId2).isNotEqualTo(requestId3);
}
}

+ 3
- 1
server/sonar-webserver-webapi/src/it/java/org/sonar/server/almintegration/ws/azure/SearchAzureReposActionIT.java Bestand weergeven

@@ -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;

+ 3
- 3
server/sonar-webserver-webapi/src/it/java/org/sonar/server/almintegration/ws/bitbucketserver/SearchBitbucketServerReposActionIT.java Bestand weergeven

@@ -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())

+ 4
- 4
server/sonar-webserver-webapi/src/it/java/org/sonar/server/almintegration/ws/gitlab/SearchGitlabReposActionIT.java Bestand weergeven

@@ -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()

+ 53
- 31
server/sonar-webserver-webapi/src/it/java/org/sonar/server/component/ws/SearchProjectsActionIT.java Bestand weergeven

@@ -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) {

+ 3
- 3
server/sonar-webserver-webapi/src/it/java/org/sonar/server/qualitygate/ws/SearchActionIT.java Bestand weergeven

@@ -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

+ 7
- 8
server/sonar-webserver-webapi/src/it/java/org/sonar/server/qualityprofile/ws/CopyActionIT.java Bestand weergeven

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


+ 12
- 2
sonar-core/src/main/java/org/sonar/core/util/SequenceUuidFactory.java Bestand weergeven

@@ -19,18 +19,28 @@
*/
package org.sonar.core.util;

import com.google.common.annotations.VisibleForTesting;
import org.apache.commons.lang.StringUtils;

import java.util.concurrent.atomic.AtomicInteger;

/**
* Only for tests. This implementation of {@link UuidFactory} generates
* ids as a sequence of integers ("1", "2", ...). It starts with "1".
* ids with the structure of a UUID v4, but containing a sequence of integers ("1", "2", ...). It starts with "1".
*/
@VisibleForTesting
public class SequenceUuidFactory implements UuidFactory {
private static final String UUID_PREFIX = "00000000-0000-0000-0000-";

public static final String UUID_1 = UUID_PREFIX + "000000000001";
public static final String UUID_2 = UUID_PREFIX + "000000000002";
public static final String UUID_3 = UUID_PREFIX + "000000000003";

private final AtomicInteger id = new AtomicInteger(1);

@Override
public String create() {
return String.valueOf(id.getAndIncrement());
int currentId = id.getAndIncrement();
return UUID_PREFIX + StringUtils.leftPad(String.valueOf(currentId), 12, "0");
}
}

+ 10
- 38
sonar-core/src/main/java/org/sonar/core/util/UuidFactoryFast.java Bestand weergeven

@@ -19,17 +19,23 @@
*/
package org.sonar.core.util;

import java.security.SecureRandom;
import com.google.common.annotations.VisibleForTesting;

/**
* NOT thread safe
* About 10x faster than {@link UuidFactoryImpl}
* It does not take into account the MAC address to calculate the ids, so it is machine-independent.
* This class must only be used for testing.
* @deprecated use {@link UuidFactoryImpl} or {@link SequenceUuidFactory} instead.
*/
@VisibleForTesting
@Deprecated(since = "10.4")
public class UuidFactoryFast implements UuidFactory {
private static UuidFactoryFast instance = new UuidFactoryFast();
private static final char[] HEX_ARRAY = "0123456789ABCDEF".toCharArray();
private static int sequenceNumber = new SecureRandom().nextInt();

public static UuidFactoryFast getInstance() {
return instance;
}

private UuidFactoryFast() {
//
@@ -37,42 +43,8 @@ public class UuidFactoryFast implements UuidFactory {

@Override
public String create() {
long timestamp = System.currentTimeMillis();

byte[] uuidBytes = new byte[9];

// Only use lower 6 bytes of the timestamp (this will suffice beyond the year 10000):
putLong(uuidBytes, timestamp, 0, 6);

// Sequence number adds 3 bytes:
putLong(uuidBytes, getSequenceNumber(), 6, 3);

return byteArrayToHex(uuidBytes);
return UuidFactoryImpl.INSTANCE.create();
}

public static UuidFactoryFast getInstance() {
return instance;
}
private static int getSequenceNumber() {
return sequenceNumber++;
}

/** Puts the lower numberOfLongBytes from l into the array, starting index pos. */
private static void putLong(byte[] array, long l, int pos, int numberOfLongBytes) {
for (int i = 0; i < numberOfLongBytes; ++i) {
array[pos + numberOfLongBytes - i - 1] = (byte) (l >>> (i * 8));
}
}

public static String byteArrayToHex(byte[] bytes) {
char[] hexChars = new char[bytes.length * 2];
for (int j = 0; j < bytes.length; j++) {
int v = bytes[j] & 0xFF;
hexChars[j * 2] = HEX_ARRAY[v >>> 4];
hexChars[j * 2 + 1] = HEX_ARRAY[v & 0x0F];
}
return new String(hexChars);
}

}

+ 2
- 4
sonar-core/src/main/java/org/sonar/core/util/UuidFactoryImpl.java Bestand weergeven

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

}

+ 0
- 80
sonar-core/src/main/java/org/sonar/core/util/UuidGenerator.java Bestand weergeven

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

+ 5
- 4
sonar-core/src/test/java/org/sonar/core/platform/ServerIdTest.java Bestand weergeven

@@ -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},
};
}


+ 12
- 4
sonar-core/src/test/java/org/sonar/core/util/SequenceUuidFactoryTest.java Bestand weergeven

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

}

+ 0
- 130
sonar-core/src/test/java/org/sonar/core/util/UuidGeneratorImplTest.java Bestand weergeven

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

Laden…
Annuleren
Opslaan