aboutsummaryrefslogtreecommitdiffstats
path: root/sonar-core
diff options
context:
space:
mode:
authorSébastien Lesaint <sebastien.lesaint@sonarsource.com>2018-06-20 17:15:44 +0200
committerSonarTech <sonartech@sonarsource.com>2018-07-05 20:21:54 +0200
commit45f6d410d36e999607e306dcf4374d739d58677b (patch)
tree2412b212c0ebf0a0ec8765f874aa315857c37a49 /sonar-core
parent69afc80d1a5f641c4b27c84aa4a050ad10a13222 (diff)
downloadsonarqube-45f6d410d36e999607e306dcf4374d739d58677b.tar.gz
sonarqube-45f6d410d36e999607e306dcf4374d739d58677b.zip
LICENSE-96 implement support for staging and new server id format
Diffstat (limited to 'sonar-core')
-rw-r--r--sonar-core/src/main/java/org/sonar/core/platform/ServerId.java164
-rw-r--r--sonar-core/src/test/java/org/sonar/core/platform/ServerIdTest.java309
2 files changed, 473 insertions, 0 deletions
diff --git a/sonar-core/src/main/java/org/sonar/core/platform/ServerId.java b/sonar-core/src/main/java/org/sonar/core/platform/ServerId.java
new file mode 100644
index 00000000000..b30ee8130e8
--- /dev/null
+++ b/sonar-core/src/main/java/org/sonar/core/platform/ServerId.java
@@ -0,0 +1,164 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 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.platform;
+
+import com.google.common.collect.ImmutableSet;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.Objects;
+import java.util.Optional;
+import java.util.Set;
+import javax.annotation.Nullable;
+import javax.annotation.concurrent.Immutable;
+import org.sonar.api.CoreProperties;
+import org.sonar.core.util.UuidFactory;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static org.sonar.core.platform.ServerId.Format.DEPRECATED;
+import static org.sonar.core.platform.ServerId.Format.NO_DATABASE_ID;
+import static org.sonar.core.platform.ServerId.Format.WITH_DATABASE_ID;
+
+@Immutable
+public final class ServerId {
+
+ public static final char SPLIT_CHARACTER = '-';
+ public static final int DATABASE_ID_LENGTH = 8;
+ public static final int DEPRECATED_SERVER_ID_LENGTH = 14;
+ public static final int NOT_UUID_DATASET_ID_LENGTH = 15;
+ public static final int UUID_DATASET_ID_LENGTH = 20;
+ private static final Set<Integer> ALLOWED_LENGTHS = ImmutableSet.of(
+ DEPRECATED_SERVER_ID_LENGTH,
+ NOT_UUID_DATASET_ID_LENGTH,
+ NOT_UUID_DATASET_ID_LENGTH + 1 + DATABASE_ID_LENGTH,
+ UUID_DATASET_ID_LENGTH,
+ UUID_DATASET_ID_LENGTH + 1 + DATABASE_ID_LENGTH);
+
+ public enum Format {
+ /* server id format before 6.1 (see SONAR-6992) */
+ DEPRECATED,
+ /* server id format before 6.7.5 and 7.3 (see LICENSE-96) */
+ NO_DATABASE_ID,
+ WITH_DATABASE_ID
+ }
+
+ private final String databaseId;
+ private final String datasetId;
+ private final Format format;
+
+ private ServerId(@Nullable String databaseId, String datasetId) {
+ this.databaseId = databaseId;
+ this.datasetId = datasetId;
+ this.format = computeFormat(databaseId, datasetId);
+ }
+
+ public Optional<String> getDatabaseId() {
+ return Optional.ofNullable(databaseId);
+ }
+
+ public String getDatasetId() {
+ return datasetId;
+ }
+
+ public Format getFormat() {
+ return format;
+ }
+
+ private static Format computeFormat(@Nullable String databaseId, String datasetId) {
+ if (databaseId != null) {
+ return WITH_DATABASE_ID;
+ }
+ if (isDate(datasetId)) {
+ return DEPRECATED;
+ }
+ return NO_DATABASE_ID;
+ }
+
+ public static ServerId parse(String serverId) {
+ String trimmed = serverId.trim();
+
+ int length = trimmed.length();
+ checkArgument(length > 0, "serverId can't be empty");
+ checkArgument(ALLOWED_LENGTHS.contains(length), "serverId does not have a supported length");
+ if (length == DEPRECATED_SERVER_ID_LENGTH || length == UUID_DATASET_ID_LENGTH || length == NOT_UUID_DATASET_ID_LENGTH) {
+ return new ServerId(null, trimmed);
+ }
+
+ int splitCharIndex = trimmed.indexOf(SPLIT_CHARACTER);
+ if (splitCharIndex == -1) {
+ return new ServerId(null, trimmed);
+ }
+ checkArgument(splitCharIndex == DATABASE_ID_LENGTH, "Unrecognized serverId format. Parts have wrong length");
+ return of(trimmed.substring(0, splitCharIndex), trimmed.substring(splitCharIndex + 1));
+ }
+
+ public static ServerId of(@Nullable String databaseId, String datasetId) {
+ if (databaseId != null) {
+ int databaseIdLength = databaseId.length();
+ checkArgument(databaseIdLength == DATABASE_ID_LENGTH, "Illegal databaseId length (%s)", databaseIdLength);
+ }
+ int datasetIdLength = datasetId.length();
+ checkArgument(datasetIdLength == DEPRECATED_SERVER_ID_LENGTH
+ || datasetIdLength == NOT_UUID_DATASET_ID_LENGTH
+ || datasetIdLength == UUID_DATASET_ID_LENGTH, "Illegal datasetId length (%s)", datasetIdLength);
+ return new ServerId(databaseId, datasetId);
+ }
+
+ public static ServerId create(UuidFactory uuidFactory) {
+ return new ServerId(null, uuidFactory.create());
+ }
+
+ /**
+ * Checks whether the specified value is a date according to the old format of the {@link CoreProperties#SERVER_ID}.
+ */
+ private static boolean isDate(String value) {
+ try {
+ new SimpleDateFormat("yyyyMMddHHmmss").parse(value);
+ return true;
+ } catch (ParseException e) {
+ return false;
+ }
+ }
+
+ @Override
+ public String toString() {
+ if (databaseId == null) {
+ return datasetId;
+ }
+ return databaseId + SPLIT_CHARACTER + datasetId;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ ServerId serverId = (ServerId) o;
+ return Objects.equals(databaseId, serverId.databaseId) &&
+ Objects.equals(datasetId, serverId.datasetId);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(databaseId, datasetId);
+ }
+}
diff --git a/sonar-core/src/test/java/org/sonar/core/platform/ServerIdTest.java b/sonar-core/src/test/java/org/sonar/core/platform/ServerIdTest.java
new file mode 100644
index 00000000000..f6f15d22bab
--- /dev/null
+++ b/sonar-core/src/test/java/org/sonar/core/platform/ServerIdTest.java
@@ -0,0 +1,309 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 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.platform;
+
+import com.tngtech.java.junit.dataprovider.DataProvider;
+import com.tngtech.java.junit.dataprovider.DataProviderRunner;
+import com.tngtech.java.junit.dataprovider.UseDataProvider;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.Random;
+import java.util.stream.IntStream;
+import java.util.stream.Stream;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+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;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.sonar.core.platform.ServerId.DATABASE_ID_LENGTH;
+import static org.sonar.core.platform.ServerId.DEPRECATED_SERVER_ID_LENGTH;
+import static org.sonar.core.platform.ServerId.NOT_UUID_DATASET_ID_LENGTH;
+import static org.sonar.core.platform.ServerId.SPLIT_CHARACTER;
+import static org.sonar.core.platform.ServerId.UUID_DATASET_ID_LENGTH;
+import static org.sonar.core.platform.ServerId.Format.DEPRECATED;
+import static org.sonar.core.platform.ServerId.Format.NO_DATABASE_ID;
+import static org.sonar.core.platform.ServerId.Format.WITH_DATABASE_ID;
+
+@RunWith(DataProviderRunner.class)
+public class ServerIdTest {
+ @Rule
+ public ExpectedException expectedException = ExpectedException.none();
+
+ @Test
+ public void parse_throws_NPE_if_argument_is_null() {
+ expectedException.expect(NullPointerException.class);
+
+ ServerId.parse(null);
+ }
+
+ @Test
+ @UseDataProvider("emptyAfterTrim")
+ public void parse_throws_IAE_if_parameter_is_empty_after_trim(String serverId) {
+ expectedException.expect(IllegalArgumentException.class);
+ expectedException.expectMessage("serverId can't be empty");
+
+ ServerId.parse(serverId);
+ }
+
+ @DataProvider
+ public static Object[][] emptyAfterTrim() {
+ return new Object[][] {
+ {""},
+ {" "},
+ {" "}
+ };
+ }
+
+ @Test
+ @UseDataProvider("wrongFormatWithDatabaseId")
+ public void parse_throws_IAE_if_split_char_is_at_wrong_position(String emptyDatabaseId) {
+ expectedException.expect(IllegalArgumentException.class);
+ expectedException.expectMessage("Unrecognized serverId format. Parts have wrong length");
+
+ ServerId.parse(emptyDatabaseId);
+ }
+
+ @DataProvider
+ public static Object[][] wrongFormatWithDatabaseId() {
+ String onlySplitChar = repeat(SPLIT_CHARACTER + "", DATABASE_ID_LENGTH);
+ String startWithSplitChar = SPLIT_CHARACTER + randomAlphabetic(DATABASE_ID_LENGTH - 1);
+
+ Stream<String> databaseIds = Stream.of(
+ UuidFactoryImpl.INSTANCE.create(),
+ randomAlphabetic(NOT_UUID_DATASET_ID_LENGTH),
+ randomAlphabetic(UUID_DATASET_ID_LENGTH),
+ repeat(SPLIT_CHARACTER + "", NOT_UUID_DATASET_ID_LENGTH),
+ repeat(SPLIT_CHARACTER + "", UUID_DATASET_ID_LENGTH));
+
+ return databaseIds
+ .flatMap(datasetId -> Stream.of(
+ startWithSplitChar + SPLIT_CHARACTER + datasetId,
+ onlySplitChar + SPLIT_CHARACTER + datasetId,
+ startWithSplitChar + randomAlphabetic(1) + datasetId,
+ onlySplitChar + randomAlphabetic(1) + datasetId))
+ .flatMap(serverId -> Stream.of(
+ serverId,
+ " " + serverId,
+ " " + serverId))
+ .map(t -> new Object[] {t})
+ .toArray(Object[][]::new);
+ }
+
+ @Test
+ public void parse_parses_deprecated_format_serverId() {
+ String deprecated = new SimpleDateFormat("yyyyMMddHHmmss").format(new Date());
+
+ ServerId serverId = ServerId.parse(deprecated);
+
+ assertThat(serverId.getFormat()).isEqualTo(DEPRECATED);
+ assertThat(serverId.getDatasetId()).isEqualTo(deprecated);
+ assertThat(serverId.getDatabaseId()).isEmpty();
+ assertThat(serverId.toString()).isEqualTo(deprecated);
+ }
+
+ @Test
+ @UseDataProvider("validOldFormatServerIds")
+ public void parse_parses_no_databaseId_format_serverId(String noDatabaseId) {
+ ServerId serverId = ServerId.parse(noDatabaseId);
+
+ assertThat(serverId.getFormat()).isEqualTo(NO_DATABASE_ID);
+ assertThat(serverId.getDatasetId()).isEqualTo(noDatabaseId);
+ assertThat(serverId.getDatabaseId()).isEmpty();
+ assertThat(serverId.toString()).isEqualTo(noDatabaseId);
+ }
+
+ @DataProvider
+ public static Object[][] validOldFormatServerIds() {
+ return new Object[][] {
+ {UuidFactoryImpl.INSTANCE.create()},
+ {randomAlphabetic(NOT_UUID_DATASET_ID_LENGTH)},
+ {repeat(SPLIT_CHARACTER + "", NOT_UUID_DATASET_ID_LENGTH)},
+ {randomAlphabetic(UUID_DATASET_ID_LENGTH)},
+ {repeat(SPLIT_CHARACTER + "", UUID_DATASET_ID_LENGTH)}
+ };
+ }
+
+ @Test
+ @UseDataProvider("validServerIdWithDatabaseId")
+ public void parse_parses_serverId_with_database_id(String databaseId, String datasetId) {
+ String rawServerId = databaseId + SPLIT_CHARACTER + datasetId;
+
+ ServerId serverId = ServerId.parse(rawServerId);
+
+ assertThat(serverId.getFormat()).isEqualTo(WITH_DATABASE_ID);
+ assertThat(serverId.getDatasetId()).isEqualTo(datasetId);
+ assertThat(serverId.getDatabaseId()).contains(databaseId);
+ assertThat(serverId.toString()).isEqualTo(rawServerId);
+ }
+
+ @DataProvider
+ public static Object[][] validServerIdWithDatabaseId() {
+ return new Object[][] {
+ {randomAlphabetic(DATABASE_ID_LENGTH), randomAlphabetic(NOT_UUID_DATASET_ID_LENGTH)},
+ {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()},
+ };
+ }
+
+ @Test
+ public void parse_does_not_support_deprecated_server_id_with_database_id() {
+ expectedException.expect(IllegalArgumentException.class);
+ expectedException.expectMessage("serverId does not have a supported length");
+
+ ServerId.parse(randomAlphabetic(DATABASE_ID_LENGTH) + SPLIT_CHARACTER + randomAlphabetic(DEPRECATED_SERVER_ID_LENGTH));
+ }
+
+ @Test
+ public void of_throws_NPE_if_datasetId_is_null() {
+ expectedException.expect(NullPointerException.class);
+
+ ServerId.of(randomAlphabetic(DATABASE_ID_LENGTH), null);
+ }
+
+ @Test
+ public void of_throws_IAE_if_datasetId_is_empty() {
+ expectedException.expect(IllegalArgumentException.class);
+ expectedException.expectMessage("Illegal datasetId length (0)");
+
+ ServerId.of(randomAlphabetic(DATABASE_ID_LENGTH), "");
+ }
+
+ @Test
+ public void of_throws_IAE_if_databaseId_is_empty() {
+ expectedException.expect(IllegalArgumentException.class);
+ expectedException.expectMessage("Illegal databaseId length (0)");
+
+ ServerId.of("", randomAlphabetic(UUID_DATASET_ID_LENGTH));
+ }
+
+ @Test
+ @UseDataProvider("datasetIdSupportedLengths")
+ public void of_accepts_null_databaseId(int datasetIdLength) {
+ String datasetId = randomAlphabetic(datasetIdLength);
+ ServerId serverId = ServerId.of(null, datasetId);
+
+ assertThat(serverId.getDatabaseId()).isEmpty();
+ assertThat(serverId.getDatasetId()).isEqualTo(datasetId);
+ }
+
+ @Test
+ @UseDataProvider("illegalDatabaseIdLengths")
+ public void of_throws_IAE_if_databaseId_length_is_not_8(int illegalDatabaseIdLengths) {
+ String databaseId = randomAlphabetic(illegalDatabaseIdLengths);
+ String datasetId = randomAlphabetic(UUID_DATASET_ID_LENGTH);
+
+ expectedException.expect(IllegalArgumentException.class);
+ expectedException.expectMessage("Illegal databaseId length (" + illegalDatabaseIdLengths + ")");
+
+ ServerId.of(databaseId, datasetId);
+ }
+
+ @DataProvider
+ public static Object[][] illegalDatabaseIdLengths() {
+ return IntStream.range(1, 8 + new Random().nextInt(5))
+ .filter(i -> i != DATABASE_ID_LENGTH)
+ .mapToObj(i -> new Object[] {i})
+ .toArray(Object[][]::new);
+ }
+
+ @Test
+ @UseDataProvider("illegalDatasetIdLengths")
+ public void of_throws_IAE_if_datasetId_length_is_not_8(int illegalDatasetIdLengths) {
+ String datasetId = randomAlphabetic(illegalDatasetIdLengths);
+ String databaseId = randomAlphabetic(DATABASE_ID_LENGTH);
+
+ expectedException.expect(IllegalArgumentException.class);
+ expectedException.expectMessage("Illegal datasetId length (" + illegalDatasetIdLengths + ")");
+
+ ServerId.of(databaseId, datasetId);
+ }
+
+ @DataProvider
+ public static Object[][] illegalDatasetIdLengths() {
+ return IntStream.range(1, UUID_DATASET_ID_LENGTH + new Random().nextInt(5))
+ .filter(i -> i != UUID_DATASET_ID_LENGTH)
+ .filter(i -> i != NOT_UUID_DATASET_ID_LENGTH)
+ .filter(i -> i != DEPRECATED_SERVER_ID_LENGTH)
+ .mapToObj(i -> new Object[] {i})
+ .toArray(Object[][]::new);
+ }
+
+ @Test
+ @UseDataProvider("datasetIdSupportedLengths")
+ public void equals_is_based_on_databaseId_and_datasetId(int datasetIdLength) {
+ String databaseId = randomAlphabetic(DATABASE_ID_LENGTH - 1) + 'a';
+ String otherDatabaseId = randomAlphabetic(DATABASE_ID_LENGTH - 1) + 'b';
+ String datasetId = randomAlphabetic(datasetIdLength - 1) + 'a';
+ String otherDatasetId = randomAlphabetic(datasetIdLength - 1) + 'b';
+
+ ServerId newServerId = ServerId.of(databaseId, datasetId);
+ assertThat(newServerId).isEqualTo(newServerId);
+ assertThat(newServerId).isEqualTo(ServerId.of(databaseId, datasetId));
+ assertThat(newServerId).isNotEqualTo(new Object());
+ assertThat(newServerId).isNotEqualTo(null);
+ assertThat(newServerId).isNotEqualTo(ServerId.of(otherDatabaseId, datasetId));
+ assertThat(newServerId).isNotEqualTo(ServerId.of(databaseId, otherDatasetId));
+ assertThat(newServerId).isNotEqualTo(ServerId.of(otherDatabaseId, otherDatasetId));
+
+ ServerId oldServerId = ServerId.parse(datasetId);
+ assertThat(oldServerId).isEqualTo(oldServerId);
+ assertThat(oldServerId).isEqualTo(ServerId.parse(datasetId));
+ assertThat(oldServerId).isNotEqualTo(ServerId.parse(otherDatasetId));
+ assertThat(oldServerId).isNotEqualTo(ServerId.of(databaseId, datasetId));
+ }
+
+ @Test
+ @UseDataProvider("datasetIdSupportedLengths")
+ public void hashcode_is_based_on_databaseId_and_datasetId(int datasetIdLength) {
+ String databaseId = randomAlphabetic(DATABASE_ID_LENGTH - 1) + 'a';
+ String otherDatabaseId = randomAlphabetic(DATABASE_ID_LENGTH - 1) + 'b';
+ String datasetId = randomAlphabetic(datasetIdLength - 1) + 'a';
+ String otherDatasetId = randomAlphabetic(datasetIdLength - 1) + 'b';
+
+ ServerId newServerId = ServerId.of(databaseId, datasetId);
+ assertThat(newServerId.hashCode()).isEqualTo(newServerId.hashCode());
+ assertThat(newServerId.hashCode()).isEqualTo(ServerId.of(databaseId, datasetId).hashCode());
+ assertThat(newServerId.hashCode()).isNotEqualTo(new Object().hashCode());
+ assertThat(newServerId.hashCode()).isNotEqualTo(null);
+ assertThat(newServerId.hashCode()).isNotEqualTo(ServerId.of(otherDatabaseId, datasetId).hashCode());
+ assertThat(newServerId.hashCode()).isNotEqualTo(ServerId.of(databaseId, otherDatasetId).hashCode());
+ assertThat(newServerId.hashCode()).isNotEqualTo(ServerId.of(otherDatabaseId, otherDatasetId).hashCode());
+
+ ServerId oldServerId = ServerId.parse(datasetId);
+ assertThat(oldServerId.hashCode()).isEqualTo(oldServerId.hashCode());
+ assertThat(oldServerId.hashCode()).isEqualTo(ServerId.parse(datasetId).hashCode());
+ assertThat(oldServerId.hashCode()).isNotEqualTo(ServerId.parse(otherDatasetId).hashCode());
+ assertThat(oldServerId.hashCode()).isNotEqualTo(ServerId.of(databaseId, datasetId).hashCode());
+ }
+
+ @DataProvider
+ public static Object[][] datasetIdSupportedLengths() {
+ return new Object[][] {
+ {ServerId.NOT_UUID_DATASET_ID_LENGTH},
+ {UUID_DATASET_ID_LENGTH},
+ };
+ }
+}