From 899439874ab537416f40b7aa25cf5ade6792a86a Mon Sep 17 00:00:00 2001 From: Jeffrey Kinard Date: Wed, 1 May 2024 18:12:38 -0400 Subject: [PATCH] Add random suffix to IT resource IDs to avoid collision Signed-off-by: Jeffrey Kinard --- .../it/common/utils/ResourceManagerUtils.java | 42 +++++++++++++++---- .../utils/ResourceManagerUtilsTest.java | 23 +++++++--- 2 files changed, 52 insertions(+), 13 deletions(-) diff --git a/it/common/src/main/java/org/apache/beam/it/common/utils/ResourceManagerUtils.java b/it/common/src/main/java/org/apache/beam/it/common/utils/ResourceManagerUtils.java index 54f82dc7d9a0..1b05ed867ed4 100644 --- a/it/common/src/main/java/org/apache/beam/it/common/utils/ResourceManagerUtils.java +++ b/it/common/src/main/java/org/apache/beam/it/common/utils/ResourceManagerUtils.java @@ -43,6 +43,7 @@ public class ResourceManagerUtils { private static final int MAX_PROJECT_ID_LENGTH = 30; private static final Pattern ILLEGAL_PROJECT_CHARS = Pattern.compile("[^a-zA-Z0-9-!:\\.']"); private static final String TIME_ZONE = "UTC"; + private static final String DEFAULT_TIME_FORMAT = "yyyyMMdd-HHmmss"; /** * Generates a new id string from an existing one. @@ -66,8 +67,8 @@ public static String generateNewId(String id, int targetLength) { /** * Generates a generic resource id from a given string, avoiding characters specified in the - * illegalChars Pattern. The length of the generated string ID will not exceed the length - * specified by targetLength. + * illegalChars Pattern. A randomly generated suffix will be appended to ensure unique ID. The + * length of the generated string ID will not exceed the length specified by targetLength. * * @param baseString the base ID to generate the resource ID from. * @param illegalChars a pattern of characters to remove from the generated ID. @@ -75,6 +76,28 @@ public static String generateNewId(String id, int targetLength) { * @param targetLength the max length of the generated ID. * @return the generated resource ID. */ + public static String generateResourceId( + String baseString, Pattern illegalChars, String replaceChar, int targetLength) { + return generateResourceId( + baseString, + illegalChars, + replaceChar, + targetLength, + DateTimeFormatter.ofPattern(DEFAULT_TIME_FORMAT)); + } + + /** + * Generates a generic resource id from a given string, avoiding characters specified in the + * illegalChars Pattern. A randomly generated suffix will be appended to ensure unique ID. The + * length of the generated string ID will not exceed the length specified by targetLength. + * + * @param baseString the base ID to generate the resource ID from. + * @param illegalChars a pattern of characters to remove from the generated ID. + * @param replaceChar the character to replace all illegal characters with. + * @param targetLength the max length of the generated ID. + * @param timeFormat a time formatter used as part of the generated suffix. + * @return the generated resource ID. + */ public static String generateResourceId( String baseString, Pattern illegalChars, @@ -88,13 +111,18 @@ public static String generateResourceId( String illegalCharsRemoved = illegalChars.matcher(baseString.toLowerCase()).replaceAll(replaceChar); - // finally, append the date/time and return the substring that does not exceed the length limit + // finally, append the date/time and return the substring that does not exceed the length limit. + // add random characters to end to ensure minimal collision. LocalDateTime localDateTime = LocalDateTime.now(ZoneId.of(TIME_ZONE)); - String timeAddOn = localDateTime.format(timeFormat); + String timeAddOn = replaceChar + localDateTime.format(timeFormat); + String randomAddOn = replaceChar + RandomStringUtils.randomAlphanumeric(6); return illegalCharsRemoved.subSequence( - 0, min(targetLength - timeAddOn.length() - 1, illegalCharsRemoved.length())) - + replaceChar - + localDateTime.format(timeFormat); + 0, + min( + targetLength - timeAddOn.length() - randomAddOn.length(), + illegalCharsRemoved.length())) + + timeAddOn + + randomAddOn; } /** Generates random letter for padding. */ diff --git a/it/common/src/test/java/org/apache/beam/it/common/utils/ResourceManagerUtilsTest.java b/it/common/src/test/java/org/apache/beam/it/common/utils/ResourceManagerUtilsTest.java index 76a6bbc0d3dc..3fb92f63c083 100644 --- a/it/common/src/test/java/org/apache/beam/it/common/utils/ResourceManagerUtilsTest.java +++ b/it/common/src/test/java/org/apache/beam/it/common/utils/ResourceManagerUtilsTest.java @@ -34,7 +34,7 @@ public class ResourceManagerUtilsTest { private static final String REPLACE_INSTANCE_CHAR = "-"; public static final int MAX_INSTANCE_ID_LENGTH = 36; private static final DateTimeFormatter TIME_FORMAT = - DateTimeFormatter.ofPattern("yyyyMMdd-HHmmss-SSSSSS"); + DateTimeFormatter.ofPattern("yyyyMMdd-HHmmss"); @Test public void testGenerateResourceIdShouldReplaceDollarSignWithHyphen() { @@ -48,7 +48,18 @@ public void testGenerateResourceIdShouldReplaceDollarSignWithHyphen() { MAX_INSTANCE_ID_LENGTH, TIME_FORMAT); - assertThat(actual).matches("test-instance-\\d{8}-\\d{6}-\\d{6}"); + assertThat(actual).matches("test-instance-\\d{8}-\\d{6}-[a-zA-Z0-9]{6}"); + } + + @Test + public void testGenerateResourceIdShouldReplaceDollarSignWithHyphenWithoutTimeFormatter() { + String testBaseString = "test$instance"; + + String actual = + generateResourceId( + testBaseString, ILLEGAL_INSTANCE_CHARS, REPLACE_INSTANCE_CHAR, MAX_INSTANCE_ID_LENGTH); + + assertThat(actual).matches("test-instance-\\d{8}-\\d{6}-[a-zA-Z0-9]{6}"); } @Test @@ -63,7 +74,7 @@ public void testGenerateResourceIdShouldReplaceDotWithHyphen() { MAX_INSTANCE_ID_LENGTH, TIME_FORMAT); - assertThat(actual).matches("test-instance-\\d{8}-\\d{6}-\\d{6}"); + assertThat(actual).matches("test-instance-\\d{8}-\\d{6}-[a-zA-Z0-9]{6}"); } @Test @@ -78,7 +89,7 @@ public void testGenerateResourceIdShouldReplaceUnderscoreWithHyphen() { MAX_INSTANCE_ID_LENGTH, TIME_FORMAT); - assertThat(actual).matches("test-inst-\\d{8}-\\d{6}-\\d{6}"); + assertThat(actual).matches("test-inst-\\d{8}-\\d{6}-[a-zA-Z0-9]{6}"); } @Test @@ -93,7 +104,7 @@ public void testGenerateResourceIdShouldReplaceUpperCaseLettersWithLowerCase() { MAX_INSTANCE_ID_LENGTH, TIME_FORMAT); - assertThat(actual).matches("test-instance-\\d{8}-\\d{6}-\\d{6}"); + assertThat(actual).matches("test-instance-\\d{8}-\\d{6}-[a-zA-Z0-9]{6}"); } @Test @@ -138,7 +149,7 @@ public void testGenerateResourceIdWhenInputLengthIsLongerThanTargetLength() { MAX_INSTANCE_ID_LENGTH, TIME_FORMAT); - assertThat(actual).matches("test-instance-\\d{8}-\\d{6}-\\d{6}"); + assertThat(actual).matches("test-instance-\\d{8}-\\d{6}-[a-zA-Z0-9]{6}"); } @Test