Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
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
59 changes: 40 additions & 19 deletions src/org/labkey/test/TestProperties.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.SystemUtils;
import org.labkey.serverapi.reader.Readers;
import org.labkey.test.util.CspLogUtil;
import org.labkey.test.util.TestLogger;
import org.openqa.selenium.Dimension;

Expand All @@ -30,6 +31,7 @@
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
Expand Down Expand Up @@ -78,6 +80,7 @@ public abstract class TestProperties
public static void load()
{
/* Force static block to run */
CspLogUtil.init();
}

public static boolean isTestCleanupSkipped()
Expand Down Expand Up @@ -129,7 +132,7 @@ public static boolean isQueryCheckSkipped()

public static boolean isCspCheckSkipped()
{
return !getBooleanProperty("webtest.cspCheck", false);
return !getBooleanProperty("webtest.cspCheck", true);
}

public static boolean isNewWebDriverForEachTest()
Expand Down Expand Up @@ -264,6 +267,10 @@ public static boolean isAssayProductFeatureAvailable()
return isProductFeatureAvailable("assay");
}

/**
* Product features are assumed to be available unless the test environment (usually TeamCity) explicitly specifies
* that it is not.
*/
public static boolean isProductFeatureAvailable(String feature)
{
return "true".equals(System.getProperty("webtest.productFeature." + feature.toLowerCase(), "true"));
Expand All @@ -276,7 +283,7 @@ public static boolean ignoreDatabaseNotSupportedException()

/**
* Parses system property 'webtest.server.startup.timeout' to determine maximum allowed server startup time.
* If property is not defined or is not an integer, it defaults to 60 seconds.
* If property is not defined or is not an integer, it defaults to 120 seconds.
* @return Maximum number of seconds to wait for server startup
*/
public static int getServerStartupTimeout()
Expand All @@ -289,34 +296,48 @@ public static String getAdditionalPipelineTools()
return System.getProperty("additional.pipeline.tools");
}

private static Map<String, Boolean> _optionalFeatures = null;
public static Map<String, Boolean> getOptionalFeatures()
{
Map<String, Boolean> features = new HashMap<>();

Properties props = System.getProperties();
for (Map.Entry<Object, Object> entry : props.entrySet())
if (_optionalFeatures == null)
{
String key = String.valueOf(entry.getKey());
Boolean value = (entry.getValue() instanceof Boolean)
? (Boolean)entry.getValue()
: Boolean.valueOf(String.valueOf(entry.getValue()));
Map<String, Boolean> features = new HashMap<>();

String prefix = "webtest.experimental."; // Can be used with any optional feature flags; "experimental" is used for backward-compatibility purposes.
if (key.startsWith(prefix))
Properties props = System.getProperties();
for (Map.Entry<Object, Object> entry : props.entrySet())
{
String feature = key.substring(prefix.length());
features.put(feature, value);
String key = String.valueOf(entry.getKey());

String expPrefix = "webtest.experimental."; // "experimental" is accepted for backward-compatibility purposes.
String optPrefix = "webtest.optional."; // Preferred prefix
for (String prefix : List.of(expPrefix, optPrefix))
{
if (key.startsWith(prefix))
{
Boolean value = (entry.getValue() instanceof Boolean)
? (Boolean) entry.getValue()
: Boolean.valueOf(String.valueOf(entry.getValue()));
String feature = key.substring(prefix.length());
features.put(feature, value);
}
}
}
}

return features;
_optionalFeatures = Collections.unmodifiableMap(features);
}
return _optionalFeatures;
}

private static List<String> debugLoggingPackages = null;
public static List<String> getDebugLoggingPackages()
{
String prop = System.getProperty("webtest.debug.server.packages", "");
String[] packages = prop.split("\\s*,\\s*");
return Arrays.stream(packages).map(String::trim).filter(s -> !s.isEmpty()).collect(Collectors.toList());
if (debugLoggingPackages == null)
{
String prop = System.getProperty("webtest.debug.server.packages", "");
String[] packages = prop.split(",");
debugLoggingPackages = Arrays.stream(packages).map(String::trim).filter(s -> !s.isEmpty()).collect(Collectors.toList());
}
return debugLoggingPackages;
}

private static File dumpDir = null;
Expand Down
5 changes: 5 additions & 0 deletions src/org/labkey/test/components/html/Table.java
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,11 @@ public int getRowCount()
return elementCache().getRows().size();
}

public List<WebElement> getRows()
{
return elementCache().getRows();
}

/**
* For a well formed html table get the text from the th elements in the thead.
*
Expand Down
135 changes: 114 additions & 21 deletions src/org/labkey/test/pages/admin/ExternalSourcesPage.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package org.labkey.test.pages.admin;

import org.junit.Assert;
import org.labkey.test.Locator;
import org.labkey.test.Locators;
import org.labkey.test.WebDriverWrapper;
import org.labkey.test.WebTestHelper;
import org.labkey.test.components.html.Input;
Expand All @@ -9,18 +11,17 @@
import org.labkey.test.pages.LabKeyPage;
import org.labkey.test.util.LogMethod;
import org.labkey.test.util.LoggedParam;
import org.labkey.test.util.core.admin.CspConfigHelper.AllowedHost;
import org.openqa.selenium.NotFoundException;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Stream;

/**
* Wraps `AdminController.ExternalSourceAction`
* Wraps `AdminController.ExternalSourcesAction`
*/
public class ExternalSourcesPage extends LabKeyPage<ExternalSourcesPage.ElementCache>
{
Expand All @@ -38,7 +39,7 @@ public static ExternalSourcesPage beginAt(WebDriverWrapper webDriverWrapper)
@LogMethod
public ExternalSourcesPage ensureHost(Directive directive, String host)
{
if (!getExistingHosts().getOrDefault(directive, Collections.emptyList()).contains(host))
if (!getExistingHosts().contains(new AllowedHost(directive, host)))
{
return addHost(directive, host);
}
Expand All @@ -57,34 +58,73 @@ public ExternalSourcesPage addHost(@LoggedParam Directive directive, @LoggedPara

clickAndWait(elementCache().addButton);
clearCache();
assertNoLabKeyErrors();
return this;
}

public Map<Directive, List<String>> getExistingHosts()
@LogMethod (quiet = true)
public List<String> addHostExpectingError(@LoggedParam Directive directive, @LoggedParam String host)
{
Map<Directive, List<String>> existingHosts = new HashMap<>();
elementCache().directiveSelect.selectOption(directive);
elementCache().hostInput.set(host);

for (Map.Entry<Directive, List<Input>> entry : getExistingHostInputs().entrySet())
{
existingHosts.put(entry.getKey(), entry.getValue().stream().map(Input::getValue).toList());
}
clickAndWait(elementCache().addButton);
clearCache();

return existingHosts;
List<WebElement> errorEls = Locators.labkeyError.findElements(elementCache());
Assert.assertFalse("No errors found", errorEls.isEmpty());
return getTexts(errorEls);
}

public Map<Directive, List<Input>> getExistingHostInputs()
public ExternalSourcesPage editHost(Directive directive, String host, String newHost)
{
getExistingSourceRow(directive, host).getHostInput().set(newHost);
return this;
}

public ExternalSourcesPage deleteHost(Directive directive, String host)
{
getExistingSourceRow(directive, host).clickDelete();
return this;
}

private ExistingSourceRow getExistingSourceRow(Directive directive, String host)
{
return elementCache().getExistingSourceRows().stream()
.filter(row -> row.getDirective().equals(directive) && row.getHost().equalsIgnoreCase(host))
.findFirst().orElseThrow(() -> new NotFoundException("Host " + host + " does not exist for directive " + directive));
}

@LogMethod (quiet = true)
public ExternalSourcesPage saveChanges()
{
clickAndWait(elementCache().saveButton);
clearCache();

assertNoLabKeyErrors();
return this;
}

@LogMethod (quiet = true)
public List<String> saveChangesExpectingError()
{
List<WebElement> directiveColumn = elementCache().existingValuesTable.getColumnAsElement(1);
List<WebElement> hostsColumn = elementCache().existingValuesTable.getColumnAsElement(2);
clickAndWait(elementCache().saveButton);
clearCache();

List<WebElement> errorEls = Locators.labkeyError.findElements(elementCache());
Assert.assertFalse("No errors found", errorEls.isEmpty());
return getTexts(errorEls);
}

Map<Directive, List<Input>> existingHosts = new HashMap<>();
public List<AllowedHost> getExistingHosts()
{
List<AllowedHost> existingHosts = new ArrayList<>();

for (int i = 0; i < hostsColumn.size(); i++)
for (ExistingSourceRow row : elementCache().getExistingSourceRows())
{
WebElement directiveInput = Locator.tag("input").findElement(directiveColumn.get(i));
Directive directive = Directive.valueOf(directiveInput.getDomAttribute("data-directive"));
Input hostInput = Input.Input(Locator.tag("input"), getDriver()).find(hostsColumn.get(i));
existingHosts.computeIfAbsent(directive, d -> new ArrayList<>()).add(hostInput);
Directive directive = row.getDirective();
String host = row.getHost();
existingHosts.add(new AllowedHost(directive, host));
}

return existingHosts;
Expand All @@ -105,6 +145,59 @@ protected class ElementCache extends LabKeyPage<ElementCache>.ElementCache

final WebElement existingValuesForm = Locator.name("existingValues").findWhenNeeded(this);
final Table existingValuesTable = new Table(getDriver(), Locator.byClass("labkey-data-region-legacy").findWhenNeeded(existingValuesForm), 0);
private List<ExistingSourceRow> existingSourceRows;

protected List<ExistingSourceRow> getExistingSourceRows()
{
if (existingSourceRows == null)
{
existingSourceRows = existingValuesTable.getRows().stream().map(ExistingSourceRow::new).toList();
}
return existingSourceRows;
}

final WebElement saveButton = Locator.lkButton("Save").findWhenNeeded(existingValuesForm);
}

protected class ExistingSourceRow
{
private final WebElement directiveInput;
private final Input hostInput;
private final WebElement deleteButton;

private Directive directive;

ExistingSourceRow(WebElement row)
{
directiveInput = Locator.tag("input").withAttributeContaining("name", "directive").findWhenNeeded(row);
hostInput = Input.Input(Locator.tag("input").withAttributeContaining("name", "host"), getDriver()).findWhenNeeded(row);
deleteButton = Locator.lkButton("Delete").findWhenNeeded(row);
}

Directive getDirective()
{
if (directive == null)
{
directive = Directive.valueOf(directiveInput.getDomAttribute("data-directive"));
}
return directive;
}

public Input getHostInput()
{
return hostInput;
}

public String getHost()
{
return hostInput.get();
}

public void clickDelete()
{
clickAndWait(deleteButton);
clearCache();
}
}

public enum Directive implements OptionSelect.SelectOption
Expand Down
15 changes: 12 additions & 3 deletions src/org/labkey/test/pages/core/admin/ShowAdminPage.java
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
import org.labkey.test.components.DomainDesignerPage;
import org.labkey.test.pages.ConfigureReportsAndScriptsPage;
import org.labkey.test.pages.LabKeyPage;
import org.labkey.test.pages.admin.ExternalSourcesPage;
import org.labkey.test.pages.compliance.ComplianceSettingsAccountsPage;
import org.labkey.test.pages.core.login.LoginConfigurePage;
import org.labkey.test.util.OptionalFeatureHelper;
Expand Down Expand Up @@ -99,6 +100,13 @@ public ShowAuditLogPage clickAuditLog()
return new ShowAuditLogPage(getDriver());
}

public ExternalSourcesPage clickAllowedExternalResourceHosts()
{
goToSettingsSection();
clickAndWait(elementCache().externalResourceHostsLink);
return new ExternalSourcesPage(getDriver());
}

public AllowedFileExtensionAdminPage clickAllowedFileExtensions()
{
goToSettingsSection();
Expand Down Expand Up @@ -278,16 +286,17 @@ protected ElementCache newElementCache()
return new ElementCache();
}

protected class ElementCache extends LabKeyPage.ElementCache
protected class ElementCache extends LabKeyPage<?>.ElementCache
{
protected WebElement sectionServerInfo = Locator.linkWithText("Server Information").findWhenNeeded(this);
protected WebElement sectionSettingsLinks = Locator.linkWithText("Settings").findWhenNeeded(this);
protected WebElement sectionModuleInfo = Locator.linkWithText("Module Information").findWhenNeeded(this);
protected WebElement sectionActiveUsers = Locator.linkWithText("Active Users").findWhenNeeded(this);

protected WebElement analyticsSettingsLink = Locator.linkWithText("analytics settings").findWhenNeeded(this);
protected WebElement externalRedirectHostLink = Locator.linkWithText("allowed external redirect hosts").findElement(this);
protected WebElement allowedFileExtensionLink = Locator.linkWithText("allowed file extensions").findElement(this);
protected WebElement externalRedirectHostLink = Locator.linkWithText("allowed external redirect hosts").findWhenNeeded(this);
protected WebElement externalResourceHostsLink = Locator.linkWithText("allowed external resource hosts").findWhenNeeded(this);
protected WebElement allowedFileExtensionLink = Locator.linkWithText("allowed file extensions").findWhenNeeded(this);
protected WebElement auditLogLink = Locator.linkWithText("audit log").findWhenNeeded(this);
protected WebElement auditLogMaintenanceLink = Locator.linkWithText("Audit Log Maintenance").findWhenNeeded(this);
protected WebElement authenticationLink = Locator.linkWithText("authentication").findWhenNeeded(this);
Expand Down
Loading