Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package org.labkey.test.components.ui.entities;

import org.awaitility.Awaitility;
import org.hamcrest.CoreMatchers;
import org.junit.Assert;
import org.labkey.test.BootstrapLocators;
import org.labkey.test.Locator;
Expand All @@ -14,6 +16,7 @@
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.ui.ExpectedConditions;

import java.time.Duration;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
Expand Down Expand Up @@ -185,11 +188,16 @@ public void clickSave(int waitTime)
Panel<?> detailsPanel = new Panel.PanelFinder(getDriver()).withTitle(parentType).waitFor(getDriver());
if (!selections.isEmpty())
{
for (String selection : selections)
{
getWrapper().quickWait().until(ExpectedConditions.visibilityOf(
Locator.linkWithText(selection).findWhenNeeded(detailsPanel)));
}
// Just wait for the correct number of parents/sources to appear for now.
Locator.CssLocator rowLocator = Locator.css(".grid-panel tbody tr");
Awaitility.await("Total " + parentType + " grid rows").atMost(Duration.ofSeconds(2))
.until(() -> rowLocator.findElements(detailsPanel).size(), CoreMatchers.equalTo(selections.size()));
// Issue 53915: Lineage panel grids don't show IDs or links for parent sequences and molecules in Biologics
// for (String selection : selections)
// {
// getWrapper().quickWait().until(ExpectedConditions.visibilityOf(
// Locator.linkWithText(selection).findWhenNeeded(detailsPanel)));
// }
}
else
{
Expand Down
2 changes: 1 addition & 1 deletion src/org/labkey/test/params/ContainerInfo.java
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ protected ContainerInfo(String name, ContainerInfo parentContainer, String folde
{
if (TestProperties.isTestRunningOnTeamCity())
{
String name = TestDataGenerator.randomName(folderName, TestDataGenerator.randomInt(0, 5), 5, RANDOM_CHARSET, null);
String name = TestDataGenerator.randomName(folderName, TestDataGenerator.randomInt(0, 5), 5, RANDOM_CHARSET, null).name();
if (name.startsWith("@"))
{
// Folder name may not begin with '@'
Expand Down
4 changes: 2 additions & 2 deletions src/org/labkey/test/tests/LinkedSchemaTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -1051,15 +1051,15 @@ private void createExperiment(String externalProject, String subFolder, String s
goToProjectHome(externalProject);
clickTab("Experiment");
waitAndClickAndWait(Locator.linkContainingText("Create Run Group"));
setFormElement(Locator.name("name"), "Parent Run Group");
setFormElement(Locator.name("Name"), "Parent Run Group");
clickButton("Submit");

_containerHelper.createSubfolder(externalProject, subFolder);

// Create a RunGroup in the subfolder.
clickTab("Experiment");
waitAndClickAndWait(Locator.linkContainingText("Create Run Group"));
setFormElement(Locator.name("name"), subFolderRunGroup);
setFormElement(Locator.name("Name"), subFolderRunGroup);
clickButton("Submit");

}
Expand Down
26 changes: 26 additions & 0 deletions src/org/labkey/test/util/RandomName.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package org.labkey.test.util;

import org.jetbrains.annotations.NotNull;

import java.util.Objects;

/**
* Record for a randomly generated name
*
* @param part The test-provided portion of the name
* @param name The full, randomly generated name
*/
public record RandomName(String part, String name)
{
public RandomName(String part, String name)
{
this.part = part == null ? "" : part; // Don't trim
this.name = Objects.requireNonNull(name);
}

@Override
public @NotNull String toString()
{
return name;
}
}
52 changes: 30 additions & 22 deletions src/org/labkey/test/util/TestDataGenerator.java
Original file line number Diff line number Diff line change
Expand Up @@ -546,9 +546,9 @@ public static String randomMultiLineString(int size, @Nullable String exclusion)
* @param exclusions characters that are to be excluded from the random parts of the name
* @return a name with given characters that will be displayed as returned in the UI.
*/
public static String randomName(@NotNull String part, int numStartChars, int numEndChars, String charSet, @Nullable String exclusions)
public static RandomName randomName(@NotNull String part, int numStartChars, int numEndChars, String charSet, @Nullable String exclusions)
{
return (randomString(numStartChars, exclusions, charSet) + part + randomString(numEndChars, exclusions, charSet)).trim();
return new RandomName(part, (randomString(numStartChars, exclusions, charSet) + part + randomString(numEndChars, exclusions, charSet)).trim());
}

public static String randomDomainName()
Expand All @@ -563,7 +563,7 @@ public static String randomDomainName(@Nullable String part)

public static String randomInvalidDomainName(@Nullable String namePart, int numStartChars, int numEndChars)
{
String domainName = randomName(namePart == null ? "" : namePart, numStartChars, numEndChars, ILLEGAL_DOMAIN_NAME_CHARSET, null);
String domainName = randomName(namePart == null ? "" : namePart, numStartChars, numEndChars, ILLEGAL_DOMAIN_NAME_CHARSET, null).name();
TestLogger.log("Generated random invalid domain name: " + domainName);
return domainName;
}
Expand All @@ -583,20 +583,20 @@ public static String randomDomainName(@Nullable String namePart, @Nullable Domai
*/
public static String randomDomainName(@Nullable String namePart, @Nullable Integer numStartChars, @Nullable Integer numEndChars, @Nullable DomainKind domainKind)
{
String _namePart = namePart == null ? "" : namePart;
namePart = namePart == null ? "" : namePart;
DomainKind _domainKind = domainKind == null ? DomainKind.SampleSet : domainKind;
String charSet = ALPHANUMERIC_STRING + DOMAIN_SPECIAL_STRING;
int currentTries = 0;
String domainName = randomName(_namePart, getNumChars(numStartChars, 5), getNumChars(numEndChars, 50), charSet, null);
while (isDomainAndFieldNameInvalid(_domainKind, domainName, null))
RandomName randomName = randomName(namePart, getNumChars(numStartChars, 5), getNumChars(numEndChars, 50), charSet, null);
while (isDomainAndFieldNameInvalid(_domainKind, randomName, null))
{
domainName = randomName(_namePart, getNumChars(numStartChars, 5), getNumChars(numEndChars, 50), charSet, null);
randomName = randomName(namePart, getNumChars(numStartChars, 5), getNumChars(numEndChars, 50), charSet, null);
if (++currentTries >= MAX_RANDOM_TRIES)
throw new IllegalStateException("Failed to generate a valid domain name after " + MAX_RANDOM_TRIES + " tries. Last generated name: " + domainName);
throw new IllegalStateException("Failed to generate a valid domain name after " + MAX_RANDOM_TRIES + " tries. Last generated name: " + randomName);
}

// Multiple spaces in the UI are collapsed into a single space. If we need to test for handling of multiple spaces, we'll not use this generator
domainName = domainName.replaceAll("\\s+", " ");
String domainName = randomName.name().replaceAll("\\s+", " ");

TestLogger.log("Generated random domain name for domainKind " + _domainKind + ": " + domainName);
return domainName;
Expand Down Expand Up @@ -632,7 +632,7 @@ public static String randomFieldName(@NotNull String part, @Nullable Integer num
+ WIDE_PLACEHOLDER + REPEAT_PLACEHOLDER + ALL_CHARS_PLACEHOLDER;

int currentTries = 0;
String randomFieldName = randomName(part, getNumChars(numStartChars, 5), getNumChars(numEndChars, 50), chars, exclusion);
RandomName randomFieldName = randomName(part, getNumChars(numStartChars, 5), getNumChars(numEndChars, 50), chars, exclusion);
while (isDomainAndFieldNameInvalid(_domainKind, null, randomFieldName))
{
randomFieldName = randomName(part, getNumChars(numStartChars, 5), getNumChars(numEndChars, 50), chars, exclusion);
Expand All @@ -641,14 +641,11 @@ public static String randomFieldName(@NotNull String part, @Nullable Integer num
}

TestLogger.log("Generated random field name for domainKind " + _domainKind + ": " + randomFieldName);
return randomFieldName;
return randomFieldName.name();
}

private static boolean isDomainAndFieldNameInvalid(DomainKind domainKind, @Nullable String domainName, @Nullable String fieldName)
private static boolean isDomainAndFieldNameInvalid(DomainKind domainKind, @Nullable RandomName domainName, @Nullable RandomName fieldName)
{
if (fieldName != null && fieldName.length() > 64 && fieldName.toLowerCase().contains("key")) // Not guaranteed but likely a list key
return true; // Issue 53706: List key field name length is limited to 64 characters

if (TestProperties.isRemoteNameValidationEnabled())
{
return isNameInvalidRemote(domainKind, domainName, fieldName);
Expand All @@ -659,7 +656,7 @@ private static boolean isDomainAndFieldNameInvalid(DomainKind domainKind, @Nulla
}
}

private static boolean isNameInvalidRemote(DomainKind domainKind, @Nullable String domainName, @Nullable String fieldName)
private static boolean isNameInvalidRemote(DomainKind domainKind, @Nullable RandomName domainName, @Nullable RandomName fieldName)
{
SimplePostCommand command = new SimplePostCommand("property", "validateDomainAndFieldNames");
JSONObject domainDesign = new JSONObject();
Expand Down Expand Up @@ -696,13 +693,16 @@ private static boolean isNameInvalidRemote(DomainKind domainKind, @Nullable Stri
}
}

public static boolean isNameInvalidLocal(DomainKind domainKind, @Nullable String domainName, @Nullable String fieldName)
private static final Pattern COLON_NAME_PATTERN = Pattern.compile(":[a-zA-Z]{3}"); // Avoid illegal patterns like ":Date"
private static boolean isNameInvalidLocal(DomainKind domainKind, @Nullable RandomName domainName, @Nullable RandomName fieldName)
{
if (domainName != null)
{
if (!Character.isLetterOrDigit(domainName.charAt(0)))
if (domainName.name().isBlank())
return true;
if (!Character.isLetterOrDigit(domainName.name().charAt(0)))
return true; // domain needs to start with alphanumeric char
if (Pattern.matches("(.*\\s--[^ ].*)|(.*\\s-[^- ].*)", domainName))
if (Pattern.matches("(.*\\s--[^ ].*)|(.*\\s-[^- ].*)", domainName.name()))
return true; // domain name must not contain space followed by dash. (command like: Issue 49161)

int maxLength = switch (domainKind)
Expand All @@ -711,14 +711,22 @@ public static boolean isNameInvalidLocal(DomainKind domainKind, @Nullable String
case SampleSet -> 100;
default -> 200; // Sources, lists, and datasets allow 200 character names
};
if (domainName.length() > maxLength)
if (domainName.name().length() > maxLength)
return true;
if (COLON_NAME_PATTERN.matcher(domainName.name())
.results().map(mr -> mr.group(0))
.anyMatch(s -> !domainName.part().contains(s))) // Only check random portion of the name
return true;
}
if (fieldName != null)
{
if (fieldName.length() > 200)
if (fieldName.name().isBlank())
return true;
if (fieldName.name().length() > 200)
return true;
if (Pattern.matches(".*:[a-zA-Z]{3}.*", fieldName)) // Avoid illegal patterns like ":Date"
if (COLON_NAME_PATTERN.matcher(fieldName.name())
.results().map(mr -> mr.group(0))
.anyMatch(s -> !fieldName.part().contains(s))) // Only check random portion of the name
return true;
}

Expand Down