From 1e1d81b84a7ef798f5bac6da1faec39b2f0cdb16 Mon Sep 17 00:00:00 2001 From: Daria Bodiakova <70635654+DariaBod@users.noreply.github.com> Date: Fri, 1 May 2026 17:14:52 -0700 Subject: [PATCH 1/9] fix known bugs --- src/org/labkey/test/util/TestDataGenerator.java | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/src/org/labkey/test/util/TestDataGenerator.java b/src/org/labkey/test/util/TestDataGenerator.java index 7d7d9343c6..e6de55ed3a 100644 --- a/src/org/labkey/test/util/TestDataGenerator.java +++ b/src/org/labkey/test/util/TestDataGenerator.java @@ -86,7 +86,7 @@ public class TestDataGenerator public static final char REPEAT_PLACEHOLDER = '\u22EF'; // '⋯' - Used to indicate that the char will be repeated public static final char ALL_CHARS_PLACEHOLDER = '\u2211'; // '∑' - Used to indicate that all characters from the charset should be used public static final String NON_LATIN_STRING = "\u0438\u0418\uC548\u306F"; // "иИ안は" - public static final String CHARSET_STRING = "ABCDEFG01234abcdefvxyz~!@#$%^&*()-+=_{}[]|\\:;\"',.<>" + NON_LATIN_STRING + WIDE_PLACEHOLDER; + public static final String CHARSET_STRING = "ABCDEFG01234abcdefvxyz~!@#$%^&*()-+=_{}[]|:;\"',.<>" + NON_LATIN_STRING + WIDE_PLACEHOLDER; public static final String ALPHANUMERIC_STRING = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvxyz"; public static final String DOMAIN_SPECIAL_STRING = "+- _.:&()/"; public static final String ILLEGAL_DOMAIN_NAME_CHARSET = "<>[]{};,`\"~!@#$%^*=|?\\"; @@ -538,7 +538,7 @@ public static String randomString(int size, @Nullable String exclusion, @Nullabl { randIndex = (int)(charSetFrom.length() * Math.random()); c = charSetFrom.charAt(randIndex); - int repeatCount = randomInt(2, 50); // repeat between 2 and 50 times + int repeatCount = randomInt(2, 5); // capped at 5: long same-char runs cause sporadic UI/DB errors val.append(StringUtils.repeat(c, repeatCount)); } else if (c == ALL_CHARS_PLACEHOLDER) @@ -548,7 +548,8 @@ else if (c == WIDE_PLACEHOLDER) else val.append(c); } - return val.toString(); + // UI collapses consecutive spaces into one; collapse here so generated strings match what tests will see + return val.toString().replaceAll(" {2,}", " "); } public static String randomMultiLineString(int size) @@ -671,7 +672,8 @@ public static String randomFieldName(@NotNull String part, @Nullable Integer num // use the characters that we know are encoded in fieldKeys plus characters that we know clients are using // Issue 53197: Field name with double byte character can cause client side exception in Firefox when trying to customize grid view. - String chars = ALL_ILLEGAL_QUERY_KEY_CHARACTERS + " %()=+-[]_|*`'\":;\\<>?!@#^" + NON_LATIN_STRING + // Backslash excluded: same Selenium UI-read issue as in CHARSET_STRING + String chars = ALL_ILLEGAL_QUERY_KEY_CHARACTERS + " %()=+-[]_|*`'\":;<>?!@#^" + NON_LATIN_STRING + WIDE_PLACEHOLDER + REPEAT_PLACEHOLDER + ALL_CHARS_PLACEHOLDER; int currentTries = 0; @@ -684,7 +686,8 @@ public static String randomFieldName(@NotNull String part, @Nullable Integer num } TestLogger.log("Generated random field name for domainKind " + _domainKind + ": " + randomFieldName); - return randomFieldName.name(); + // Consistent with randomDomainName: UI collapses multiple whitespace chars to a single space + return randomFieldName.name().replaceAll("\\s+", " "); } private static boolean isDomainAndFieldNameInvalid(DomainKind domainKind, @Nullable RandomName domainName, @Nullable RandomName fieldName) @@ -1027,7 +1030,7 @@ public static List randomSelect(List allOptions, int selectCount) List selected = new ArrayList<>(); for (int i = 0; i < selectCount; i++) { - selected.add(allOptions.get(randomInt(0, allOptions.size()))); + selected.add(allOptions.get(randomInt(0, allOptions.size() - 1))); } return selected; } From faf837cdb5dce7659832d2d67505f90a252275d6 Mon Sep 17 00:00:00 2001 From: Daria Bodiakova <70635654+DariaBod@users.noreply.github.com> Date: Mon, 4 May 2026 10:41:49 -0700 Subject: [PATCH 2/9] =?UTF-8?q?containsKey+put=20=E2=86=92=20computeIfAbse?= =?UTF-8?q?nt=20counter=20in=20randomTextChoice?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/org/labkey/test/util/TestDataGenerator.java | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/org/labkey/test/util/TestDataGenerator.java b/src/org/labkey/test/util/TestDataGenerator.java index e6de55ed3a..6c6a81699e 100644 --- a/src/org/labkey/test/util/TestDataGenerator.java +++ b/src/org/labkey/test/util/TestDataGenerator.java @@ -432,10 +432,7 @@ private Map generateRow() final Map newRow = new CaseInsensitiveHashMap<>(); for (String columnName : _columns.keySet()) { - if (!_dataSuppliers.containsKey(columnName)) - { - _dataSuppliers.put(columnName, getDefaultDataSupplier(_columns.get(columnName))); - } + _dataSuppliers.computeIfAbsent(columnName, k -> getDefaultDataSupplier(_columns.get(k))); if (_autoGeneratedFields.contains(columnName)) { @@ -507,8 +504,12 @@ public static String randomString(int size) public static List randomTextChoice(int size) { Set textChoices = new LinkedHashSet<>(); + int attempts = 0; + int maxAttempts = size * MAX_RANDOM_TRIES; while (textChoices.size() < size) { + if (++attempts > maxAttempts) + throw new IllegalStateException("Failed to generate " + size + " unique text choices after " + maxAttempts + " attempts"); String generated = randomString(randomInt(1, 25), ";").trim(); if (!generated.isEmpty()) { From 859f0bf1cba8afb9a4d47fa44f1da9b97ef6ec84 Mon Sep 17 00:00:00 2001 From: Daria Bodiakova <70635654+DariaBod@users.noreply.github.com> Date: Mon, 4 May 2026 10:43:19 -0700 Subject: [PATCH 3/9] counter in randomTextChoice --- src/org/labkey/test/util/TestDataGenerator.java | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/org/labkey/test/util/TestDataGenerator.java b/src/org/labkey/test/util/TestDataGenerator.java index 6c6a81699e..46ca175bc0 100644 --- a/src/org/labkey/test/util/TestDataGenerator.java +++ b/src/org/labkey/test/util/TestDataGenerator.java @@ -505,11 +505,10 @@ public static List randomTextChoice(int size) { Set textChoices = new LinkedHashSet<>(); int attempts = 0; - int maxAttempts = size * MAX_RANDOM_TRIES; while (textChoices.size() < size) { - if (++attempts > maxAttempts) - throw new IllegalStateException("Failed to generate " + size + " unique text choices after " + maxAttempts + " attempts"); + if (++attempts > MAX_RANDOM_TRIES) + throw new IllegalStateException("Failed to generate " + size + " unique text choices after " + MAX_RANDOM_TRIES + " attempts"); String generated = randomString(randomInt(1, 25), ";").trim(); if (!generated.isEmpty()) { From 42aa53acce819e5980f1c9bd8bae6616d8f2512e Mon Sep 17 00:00:00 2001 From: Daria Bodiakova <70635654+DariaBod@users.noreply.github.com> Date: Mon, 4 May 2026 10:57:55 -0700 Subject: [PATCH 4/9] ThreadLocalRandom instead of Random or Math.random --- src/org/labkey/test/util/TestDataGenerator.java | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/org/labkey/test/util/TestDataGenerator.java b/src/org/labkey/test/util/TestDataGenerator.java index 46ca175bc0..204e4e73ac 100644 --- a/src/org/labkey/test/util/TestDataGenerator.java +++ b/src/org/labkey/test/util/TestDataGenerator.java @@ -178,7 +178,7 @@ else if (fieldDefinition.getType().equals(FieldDefinition.ColumnType.String)) else if (fieldDefinition.getType().equals(FieldDefinition.ColumnType.TextChoice)) { FieldDefinition.TextChoiceValidator validator = - (FieldDefinition.TextChoiceValidator) fieldDefinition.getValidators().get(0); + (FieldDefinition.TextChoiceValidator) fieldDefinition.getValidators().getFirst(); List textChoices = validator.getValues(); int textChoiceIndex = i % textChoices.size(); if (forGridInsert) @@ -532,11 +532,11 @@ public static String randomString(int size, @Nullable String exclusion, @Nullabl StringBuilder val = new StringBuilder(); for (int i=0; i> ro public static List shuffleSelect(List allFields) { - int randomSize = new Random().nextInt(allFields.size()) + 1; + int randomSize = ThreadLocalRandom.current().nextInt(allFields.size()) + 1; return shuffleSelect(allFields, randomSize); } @@ -1022,7 +1022,7 @@ public static List bitmaskSelect(List allElements, int bitmask, int sa effective = bitmask & validMask; return BitSet.valueOf(new long[]{effective}).stream() .mapToObj(allElements::get) - .collect(Collectors.toList()); + .toList(); } public static List randomSelect(List allOptions, int selectCount) From ad70665f5e120c811e9e00b14b21ed778629cb68 Mon Sep 17 00:00:00 2001 From: Daria Bodiakova <70635654+DariaBod@users.noreply.github.com> Date: Mon, 4 May 2026 11:10:04 -0700 Subject: [PATCH 5/9] remove imports fix comments --- src/org/labkey/test/util/TestDataGenerator.java | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/org/labkey/test/util/TestDataGenerator.java b/src/org/labkey/test/util/TestDataGenerator.java index 204e4e73ac..b5292b2658 100644 --- a/src/org/labkey/test/util/TestDataGenerator.java +++ b/src/org/labkey/test/util/TestDataGenerator.java @@ -62,13 +62,11 @@ import java.util.List; import java.util.Map; import java.util.Objects; -import java.util.Random; import java.util.Set; import java.util.concurrent.ThreadLocalRandom; import java.util.function.Function; import java.util.function.Supplier; import java.util.regex.Pattern; -import java.util.stream.Collectors; import static org.labkey.test.BaseWebDriverTest.ALL_ILLEGAL_QUERY_KEY_CHARACTERS; import static org.labkey.test.util.data.TestDataUtils.REALISTIC_ASSAY_FIELDS; @@ -538,7 +536,7 @@ public static String randomString(int size, @Nullable String exclusion, @Nullabl { randIndex = ThreadLocalRandom.current().nextInt(charSetFrom.length()); c = charSetFrom.charAt(randIndex); - int repeatCount = randomInt(2, 5); // capped at 5: long same-char runs cause sporadic UI/DB errors + int repeatCount = randomInt(2, 5); // repeat between 2 and 5 times val.append(StringUtils.repeat(c, repeatCount)); } else if (c == ALL_CHARS_PLACEHOLDER) @@ -672,7 +670,7 @@ public static String randomFieldName(@NotNull String part, @Nullable Integer num // use the characters that we know are encoded in fieldKeys plus characters that we know clients are using // Issue 53197: Field name with double byte character can cause client side exception in Firefox when trying to customize grid view. - // Backslash excluded: same Selenium UI-read issue as in CHARSET_STRING + // Backslash excluded: Selenium UI-read issue String chars = ALL_ILLEGAL_QUERY_KEY_CHARACTERS + " %()=+-[]_|*`'\":;<>?!@#^" + NON_LATIN_STRING + WIDE_PLACEHOLDER + REPEAT_PLACEHOLDER + ALL_CHARS_PLACEHOLDER; From 1fbff7c1fb1dc7512a54c5683ec935239f50307b Mon Sep 17 00:00:00 2001 From: Daria Bodiakova <70635654+DariaBod@users.noreply.github.com> Date: Mon, 4 May 2026 11:33:08 -0700 Subject: [PATCH 6/9] back to mutable list in bitmaskSelect >= instead of > fix comment --- src/org/labkey/test/util/TestDataGenerator.java | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/org/labkey/test/util/TestDataGenerator.java b/src/org/labkey/test/util/TestDataGenerator.java index b5292b2658..64b78fbd01 100644 --- a/src/org/labkey/test/util/TestDataGenerator.java +++ b/src/org/labkey/test/util/TestDataGenerator.java @@ -67,6 +67,7 @@ import java.util.function.Function; import java.util.function.Supplier; import java.util.regex.Pattern; +import java.util.stream.Collectors; import static org.labkey.test.BaseWebDriverTest.ALL_ILLEGAL_QUERY_KEY_CHARACTERS; import static org.labkey.test.util.data.TestDataUtils.REALISTIC_ASSAY_FIELDS; @@ -505,7 +506,7 @@ public static List randomTextChoice(int size) int attempts = 0; while (textChoices.size() < size) { - if (++attempts > MAX_RANDOM_TRIES) + if (++attempts >= MAX_RANDOM_TRIES) throw new IllegalStateException("Failed to generate " + size + " unique text choices after " + MAX_RANDOM_TRIES + " attempts"); String generated = randomString(randomInt(1, 25), ";").trim(); if (!generated.isEmpty()) @@ -546,7 +547,7 @@ else if (c == WIDE_PLACEHOLDER) else val.append(c); } - // UI collapses consecutive spaces into one; collapse here so generated strings match what tests will see + // Collapse consecutive spaces into one to match what the UI displays. return val.toString().replaceAll(" {2,}", " "); } @@ -1020,7 +1021,7 @@ public static List bitmaskSelect(List allElements, int bitmask, int sa effective = bitmask & validMask; return BitSet.valueOf(new long[]{effective}).stream() .mapToObj(allElements::get) - .toList(); + .collect(Collectors.toList()); } public static List randomSelect(List allOptions, int selectCount) From 4bd74778b9b89794bc4cdc4511ed01e71da3e568 Mon Sep 17 00:00:00 2001 From: Daria Bodiakova <70635654+DariaBod@users.noreply.github.com> Date: Tue, 5 May 2026 09:35:54 -0700 Subject: [PATCH 7/9] Apply suggestion from @labkey-tchad Co-authored-by: Trey Chadick --- src/org/labkey/test/util/TestDataGenerator.java | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/org/labkey/test/util/TestDataGenerator.java b/src/org/labkey/test/util/TestDataGenerator.java index 64b78fbd01..7797c99a70 100644 --- a/src/org/labkey/test/util/TestDataGenerator.java +++ b/src/org/labkey/test/util/TestDataGenerator.java @@ -504,10 +504,11 @@ public static List randomTextChoice(int size) { Set textChoices = new LinkedHashSet<>(); int attempts = 0; - while (textChoices.size() < size) - { - if (++attempts >= MAX_RANDOM_TRIES) - throw new IllegalStateException("Failed to generate " + size + " unique text choices after " + MAX_RANDOM_TRIES + " attempts"); + final int maxTries = Math.max(MAX_RANDOM_TRIES, size * 2); +while (textChoices.size() < size) +{ + if (++attempts >= maxTries) + throw new IllegalStateException("Failed to generate " + size + " unique text choices after " + maxTries + " attempts"); String generated = randomString(randomInt(1, 25), ";").trim(); if (!generated.isEmpty()) { From 82c6b8031f0b1fd5bf41a69bf3b9df5316616c3a Mon Sep 17 00:00:00 2001 From: Daria Bodiakova <70635654+DariaBod@users.noreply.github.com> Date: Tue, 5 May 2026 11:29:01 -0700 Subject: [PATCH 8/9] fix comment --- .../tests/component/GridPanelViewTest.java | 2 +- .../labkey/test/util/TestDataGenerator.java | 20 ++++++++++++------- 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/src/org/labkey/test/tests/component/GridPanelViewTest.java b/src/org/labkey/test/tests/component/GridPanelViewTest.java index 06f0ea3466..440d9373ea 100644 --- a/src/org/labkey/test/tests/component/GridPanelViewTest.java +++ b/src/org/labkey/test/tests/component/GridPanelViewTest.java @@ -79,7 +79,7 @@ public class GridPanelViewTest extends GridPanelBaseTest private static final String COL_STRING2 = "Str2"; private static final String COL_INT = "Int"; private static final String COL_BOOL = "Bool"; - public static final List TEXT_MULTI_CHOICE_LIST = randomTextChoice(10); + public static final List TEXT_MULTI_CHOICE_LIST = randomTextChoice(10, ";"); public static final String COL_MULTITEXTCHOICE = "Multi Choice"; private static final boolean MULTI_CHOICE_ENABLED = WebTestHelper.getDatabaseType() == DatabaseType.PostgreSQL; diff --git a/src/org/labkey/test/util/TestDataGenerator.java b/src/org/labkey/test/util/TestDataGenerator.java index 7797c99a70..7b17d2d5f5 100644 --- a/src/org/labkey/test/util/TestDataGenerator.java +++ b/src/org/labkey/test/util/TestDataGenerator.java @@ -85,7 +85,7 @@ public class TestDataGenerator public static final char REPEAT_PLACEHOLDER = '\u22EF'; // '⋯' - Used to indicate that the char will be repeated public static final char ALL_CHARS_PLACEHOLDER = '\u2211'; // '∑' - Used to indicate that all characters from the charset should be used public static final String NON_LATIN_STRING = "\u0438\u0418\uC548\u306F"; // "иИ안は" - public static final String CHARSET_STRING = "ABCDEFG01234abcdefvxyz~!@#$%^&*()-+=_{}[]|:;\"',.<>" + NON_LATIN_STRING + WIDE_PLACEHOLDER; + public static final String CHARSET_STRING = "ABCDEFG01234abcdefvxyz~!@#$%^&*()-+=_{}[]|\\:;\"',.<>" + NON_LATIN_STRING + WIDE_PLACEHOLDER; public static final String ALPHANUMERIC_STRING = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvxyz"; public static final String DOMAIN_SPECIAL_STRING = "+- _.:&()/"; public static final String ILLEGAL_DOMAIN_NAME_CHARSET = "<>[]{};,`\"~!@#$%^*=|?\\"; @@ -500,16 +500,18 @@ public static String randomString(int size) return randomString(size, null); } - public static List randomTextChoice(int size) + public static List randomTextChoice(int size, @Nullable String exclusion) { Set textChoices = new LinkedHashSet<>(); int attempts = 0; final int maxTries = Math.max(MAX_RANDOM_TRIES, size * 2); -while (textChoices.size() < size) -{ + while (textChoices.size() < size) + { if (++attempts >= maxTries) + { throw new IllegalStateException("Failed to generate " + size + " unique text choices after " + maxTries + " attempts"); - String generated = randomString(randomInt(1, 25), ";").trim(); + } + String generated = randomString(randomInt(1, 25), exclusion).trim(); if (!generated.isEmpty()) { textChoices.add(generated); @@ -518,6 +520,11 @@ public static List randomTextChoice(int size) return List.copyOf(textChoices); } + public static List randomTextChoice(int size) + { + return randomTextChoice(size, null); + } + public static String randomString(int size, @Nullable String exclusion) { return randomString(size, exclusion, CHARSET_STRING); @@ -672,8 +679,7 @@ public static String randomFieldName(@NotNull String part, @Nullable Integer num // use the characters that we know are encoded in fieldKeys plus characters that we know clients are using // Issue 53197: Field name with double byte character can cause client side exception in Firefox when trying to customize grid view. - // Backslash excluded: Selenium UI-read issue - String chars = ALL_ILLEGAL_QUERY_KEY_CHARACTERS + " %()=+-[]_|*`'\":;<>?!@#^" + NON_LATIN_STRING + String chars = ALL_ILLEGAL_QUERY_KEY_CHARACTERS + " %()=+-[]_|*`'\":;\\<>?!@#^" + NON_LATIN_STRING + WIDE_PLACEHOLDER + REPEAT_PLACEHOLDER + ALL_CHARS_PLACEHOLDER; int currentTries = 0; From e090811b3a45e5d380d03173030916a07ddd225c Mon Sep 17 00:00:00 2001 From: Daria Bodiakova <70635654+DariaBod@users.noreply.github.com> Date: Tue, 5 May 2026 14:46:40 -0700 Subject: [PATCH 9/9] add comment --- src/org/labkey/test/tests/component/GridPanelViewTest.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/org/labkey/test/tests/component/GridPanelViewTest.java b/src/org/labkey/test/tests/component/GridPanelViewTest.java index 440d9373ea..8cb9b1f3aa 100644 --- a/src/org/labkey/test/tests/component/GridPanelViewTest.java +++ b/src/org/labkey/test/tests/component/GridPanelViewTest.java @@ -79,6 +79,7 @@ public class GridPanelViewTest extends GridPanelBaseTest private static final String COL_STRING2 = "Str2"; private static final String COL_INT = "Int"; private static final String COL_BOOL = "Bool"; + // Excluded semicolon due to GitHub Issue 1096 public static final List TEXT_MULTI_CHOICE_LIST = randomTextChoice(10, ";"); public static final String COL_MULTITEXTCHOICE = "Multi Choice";