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
43 changes: 43 additions & 0 deletions src/org/labkey/remoteapi/SimpleFormCommand.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package org.labkey.remoteapi;

import org.apache.hc.client5.http.classic.methods.HttpPost;
import org.apache.hc.client5.http.classic.methods.HttpUriRequest;
import org.apache.hc.client5.http.entity.UrlEncodedFormEntity;
import org.apache.hc.core5.http.NameValuePair;
import org.apache.hc.core5.http.message.BasicNameValuePair;

import java.io.IOException;
import java.net.URI;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

public class SimpleFormCommand extends Command<CommandResponse, HttpUriRequest>
{
private final Map<String, String> _formData;

public SimpleFormCommand(String controller, String action, Map<String, String> formData)
{
super(controller, action);
_formData = formData;
}

public CommandResponse execute(Connection connection) throws IOException, CommandException
{
return execute(connection, null);
}

@Override
protected HttpUriRequest createRequest(URI uri)
{
HttpPost post = new HttpPost(uri);

List<NameValuePair> args = new ArrayList<>();
for (Map.Entry<String, String> reportVal : _formData.entrySet())
{
args.add(new BasicNameValuePair(reportVal.getKey(), reportVal.getValue()));
}
post.setEntity(new UrlEncodedFormEntity(args));
return post;
}
}
29 changes: 20 additions & 9 deletions src/org/labkey/test/components/core/ProjectMenu.java
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
*/
package org.labkey.test.components.core;

import org.apache.commons.lang3.StringUtils;
import org.labkey.test.Locator;
import org.labkey.test.WebDriverWrapper;
import org.labkey.test.components.Component;
Expand All @@ -28,6 +29,7 @@

import java.util.List;

import static org.labkey.test.Locators.loadingSpinner;
import static org.labkey.test.WebDriverWrapper.WAIT_FOR_JAVASCRIPT;

/**
Expand Down Expand Up @@ -68,20 +70,29 @@ public String getCurrentProject()

private boolean isOpen()
{
return elementCache().menuContainer.getAttribute("class").contains("open");
return StringUtils.trimToEmpty(elementCache().menuContainer.getAttribute("class")).contains("open") &&
!loadingSpinner.existsIn(elementCache().menuContainer);
}

public ProjectMenu open()
{
if (!isOpen())
{
getWrapper().executeScript("window.scrollTo(0,0);");
if (getWrapper().isElementPresent(Locator.css("li.dropdown.open > .lk-custom-dropdown-menu")))
getWrapper().mouseOver(elementCache().menuToggle); // Just need to hover if another menu is already open
else
elementCache().menuToggle.click();
WebDriverWrapper.waitFor(this::isOpen, "Project menu didn't open", 2000);
getWrapper().waitForElement(Locator.tagWithClass("div", "folder-nav"));
Runnable openMenu = () -> {
getWrapper().executeScript("window.scrollTo(0,0);");
if (getWrapper().isElementPresent(Locator.css("li.dropdown.open > .lk-custom-dropdown-menu")))
getWrapper().mouseOver(elementCache().menuToggle); // Just need to hover if another menu is already open
else
elementCache().menuToggle.click();
WebDriverWrapper.waitFor(this::isOpen, "Project menu didn't open", 2000);
};
openMenu.run();
if (!Locator.tagWithClass("div", "folder-nav").existsIn(this))
{
// Menu opened but the folder list didn't load
close();
openMenu.run(); // retry
}
}
return this;
}
Expand Down Expand Up @@ -222,7 +233,7 @@ protected ElementCache newElementCache()
return new ElementCache();
}

protected class ElementCache extends Component.ElementCache
protected class ElementCache extends Component<ElementCache>.ElementCache
{
final WebElement menuContainer = Locators.menuProjectNav.refindWhenNeeded(getComponentElement());
final WebElement menuToggle = Locator.tagWithAttribute("a", "data-toggle", "dropdown").refindWhenNeeded(menuContainer);
Expand Down
2 changes: 1 addition & 1 deletion src/org/labkey/test/params/FieldDefinition.java
Original file line number Diff line number Diff line change
Expand Up @@ -590,7 +590,7 @@ public boolean isMeasureByDefault()
ColumnType OntologyLookup = new ColumnTypeImpl("Ontology Lookup", "string", "http://www.labkey.org/types#conceptCode", null);
ColumnType VisitId = new ColumnTypeImpl("Visit ID", "double", "http://cpas.labkey.com/Study#VisitId", null);
ColumnType VisitDate = new ColumnTypeImpl("Visit Date", "dateTime", "http://cpas.labkey.com/Study#VisitId", null);
ColumnType VisitLabel = new ColumnTypeImpl("Visit Label", "string");
ColumnType VisitLabel = new ColumnTypeImpl("Visit Label", "string", "http://cpas.labkey.com/Study#VisitId", null);
ColumnType Sample = new ColumnTypeImpl("Sample", "int", "http://www.labkey.org/exp/xml#sample", new IntLookup( "exp", "Materials"));
ColumnType Barcode = new ColumnTypeImpl("Unique ID", "string", "http://www.labkey.org/types#storageUniqueId", null);
ColumnType TextChoice = new ColumnTypeImpl("Text Choice", "string", "http://www.labkey.org/types#textChoice", null);
Expand Down
2 changes: 1 addition & 1 deletion src/org/labkey/test/tests/AbstractKnitrReportTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -175,7 +175,7 @@ protected void htmlFormat()
Locator.tag("img").withAttribute("alt", "plot of chunk blood-pressure-scatter")), // new
Locator.tag("pre").containing("## \"1\",249318596,\"2008-05-17\",86,36,129,76,64"),
Locator.tag("pre").withText("## knitr says hello to HTML!"),
Locator.tag("pre").startsWith("## Error").containing(": non-numeric argument to binary operator"),
Locator.tag("pre").startsWith("## Error").containing("non-numeric argument to binary operator"),
Locator.tag("p").startsWith("Well, everything seems to be working. Let's ask R what is the value of \u03C0? Of course it is 3.141"),
nonceCheckSuccessLoc // Inline script should run
};
Expand Down
16 changes: 13 additions & 3 deletions src/org/labkey/test/tests/JUnitTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
import org.json.JSONException;
import org.json.JSONObject;
import org.junit.Assert;
import org.junit.Assume;
import org.junit.experimental.categories.Category;
import org.labkey.remoteapi.CommandException;
import org.labkey.remoteapi.CommandResponse;
Expand Down Expand Up @@ -69,6 +70,7 @@
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Predicate;

@Category({BVT.class, UnitTests.class})
Expand Down Expand Up @@ -318,6 +320,7 @@ else if (responseBody.contains("<title>Upgrade Status</title>") ||
boolean addedHeader = false;
for (String key : json.keySet())
{
AtomicInteger ioeCounter = new AtomicInteger(0);
TestSuite testsuite = new TestSuite(key);
JSONArray testClassArray = json.getJSONArray(key);
// Individual tests include both the class name and the requested timeout
Expand All @@ -331,7 +334,7 @@ else if (responseBody.contains("<title>Upgrade Status</title>") ||
// Timeout is represented in seconds
int timeout = testClass.getInt("timeout");
if (accept.test(testClass.toMap()))
testsuite.addTest(new RemoteTest(className, timeout));
testsuite.addTest(new RemoteTest(className, timeout, ioeCounter));
}

}
Expand Down Expand Up @@ -370,23 +373,27 @@ else if (responseBody.contains("<title>Upgrade Status</title>") ||
@SuppressWarnings("JUnitMalformedDeclaration")
public static class RemoteTest extends TestCase
{
String _remoteClass;
private final String _remoteClass;
/** Timeout in seconds to wait for the whole testcase to finish on the server */
private final int _timeout;
// Skip tests after a certain number of IOExceptions
private final AtomicInteger _ioeCounter;

/** Stash and reuse so that we can keep using the same session instead of re-authenticating with every request */
private static final Connection connection = WebTestHelper.getRemoteApiConnection();

public RemoteTest(String remoteClass, int timeout)
public RemoteTest(String remoteClass, int timeout, AtomicInteger ioeCounter)
{
super(remoteClass);
_remoteClass = remoteClass;
_timeout = timeout;
_ioeCounter = ioeCounter;
}

@Override
protected void runTest()
{
Assume.assumeTrue("Too many consecutive test timeouts", _ioeCounter.get() < 5);
long startTime = System.currentTimeMillis();
try
{
Expand All @@ -405,16 +412,19 @@ else if (resultJson.get("wasSuccessful") != Boolean.TRUE)
WebTestHelper.logToServer(getLogTestString("successful", startTime) + ", " + dump(resultJson, false), connection);
LOG.info(getLogTestString("successful", startTime));
LOG.info(dump(resultJson, true));
_ioeCounter.set(0);
}
catch (SocketTimeoutException ste)
{
_ioeCounter.incrementAndGet();
String timed_out = getLogTestString("timed out", startTime);
LOG.error(timed_out);
ArtifactCollector.dumpThreads();
throw new RuntimeException(timed_out, ste);
}
catch (IOException ioe)
{
_ioeCounter.incrementAndGet();
String message = getLogTestString("failed: " + ioe.getMessage(), startTime);
LOG.error(message);
throw new RuntimeException(message, ioe);
Expand Down
34 changes: 29 additions & 5 deletions src/org/labkey/test/tests/upgrade/BaseUpgradeTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,9 @@ public abstract class BaseUpgradeTest extends BaseWebDriverTest
{

protected static final boolean isUpgradeSetupPhase = TestProperties.getBooleanProperty("webtest.upgradeSetup", true);
protected static final Version previousVersion = Optional.ofNullable(trimToNull(System.getProperty("webtest.upgradePreviousVersion")))
.map(Version::new).orElse(TestProperties.getProductVersion());
protected static final Version setupVersion = isUpgradeSetupPhase ? TestProperties.getProductVersion() :
Optional.ofNullable(trimToNull(System.getProperty("webtest.upgradePreviousVersion"))).map(Version::new)
.orElse(TestProperties.getProductVersion());

@Override
protected boolean skipCleanup(boolean afterTest)
Expand Down Expand Up @@ -70,6 +71,29 @@ public List<String> getAssociatedModules()
return Arrays.asList();
}

/**
* Checks if the setup for the current test was performed in a version prior to the specified version.
*
* @param version The version to check against.
* @return {@code true} if the setup version is earlier than the specified version.
*/
protected boolean wasSetupBefore(String version)
{
return !wasSetupWithin(version, null);
}

/**
* Checks if the setup for the current test was performed within the specified version range (inclusive).
*
* @param earliestVersion The earliest version in the range (inclusive).
* @param latestVersion The latest version in the range (inclusive).
* @return {@code true} if the setup version is within the specified range.
*/
protected boolean wasSetupWithin(String earliestVersion, String latestVersion)
{
return VersionRange.versionRange(earliestVersion, latestVersion).contains(setupVersion);
}

/**
* Annotates test methods that should only run when upgrading from particular LabKey versions, as specified in
* {@code webtest.upgradePreviousVersion}.<br>
Expand Down Expand Up @@ -104,7 +128,7 @@ private static class UpgradeVersionCheck implements TestRule
String latestVersion = Optional.ofNullable(description.getAnnotation(LatestVersion.class))
.map(LatestVersion::value).orElse(null);

if (isUpgradeSetupPhase || previousVersion == null || (earliestVersion == null && latestVersion == null))
if (isUpgradeSetupPhase || setupVersion == null || (earliestVersion == null && latestVersion == null))
{
return base; // Run the test normally
}
Expand All @@ -114,8 +138,8 @@ private static class UpgradeVersionCheck implements TestRule
@Override
public void evaluate() throws Throwable
{
Assume.assumeTrue("Test not valid when upgrading from version: " + previousVersion,
VersionRange.versionRange(earliestVersion, latestVersion).contains(previousVersion)
Assume.assumeTrue("Test not valid when upgrading from version: " + setupVersion,
VersionRange.versionRange(earliestVersion, latestVersion).contains(setupVersion)
);
base.evaluate();
}
Expand Down
2 changes: 1 addition & 1 deletion src/org/labkey/test/util/FileBrowserHelper.java
Original file line number Diff line number Diff line change
Expand Up @@ -248,7 +248,7 @@ private void checkFileBrowserFileCheckbox(String fileName, boolean checkTheBox)
final Checkbox checkbox;
try
{
checkbox = Ext4Checkbox().locatedBy(Locators.gridRowCheckbox(fileName)).find(getDriver());
checkbox = Ext4Checkbox().locatedBy(Locators.gridRowCheckbox(fileName)).timeout(1_000).find(getDriver());
}
catch (NoSuchElementException nse)
{
Expand Down
12 changes: 6 additions & 6 deletions src/org/labkey/test/util/TestLogger.java
Original file line number Diff line number Diff line change
Expand Up @@ -138,12 +138,12 @@ public static void log(String str)
}

/**
* Format an elapsed time to be suitable for log messages.
* Over one minute:
* " &lt;1m 25s&gt;"
* Over one minute:
* " &lt;8.059s&gt;"
* Less than on second:
* Format an elapsed time to be suitable for log messages.<br>
* Over one minute:<br>
* " &lt;1m 25s&gt;"<br>
* Over one second:<br>
* " &lt;8.059s&gt;"<br>
* Less than one second:<br>
* " &lt;125ms&gt;"
* @param milliseconds Elapsed time in milliseconds
* @return Formatted time
Expand Down
50 changes: 46 additions & 4 deletions src/org/labkey/test/util/VersionRange.java
Original file line number Diff line number Diff line change
@@ -1,36 +1,78 @@
package org.labkey.test.util;

/**
* Represents a range of LabKey versions.
* Used for checking if a specific version falls within an inclusive range.
*/
public class VersionRange
{
private final Version eariestVersion;
private final Version earliestVersion;
private final Version latestVersion;

public VersionRange(Version eariestVersion, Version latestVersion)
/**
* Constructs a version range.
*
* @param earliestVersion The earliest version in the range (inclusive). If null, there is no lower bound.
* @param latestVersion The latest version in the range (inclusive). If null, there is no upper bound.
* @throws IllegalArgumentException if both versions are null, or if earliestVersion is after latestVersion.
*/
public VersionRange(Version earliestVersion, Version latestVersion)
{
this.eariestVersion = eariestVersion;
this.earliestVersion = earliestVersion;
this.latestVersion = latestVersion;

if (earliestVersion == null && latestVersion == null)
throw new IllegalArgumentException("Version range requires at least one version");
if (earliestVersion != null && latestVersion != null && earliestVersion.compareTo(latestVersion) > 0)
throw new IllegalArgumentException("%s is after %s".formatted(earliestVersion, latestVersion));

}

/**
* Creates a version range starting from the specified version with no upper bound.
*
* @param version The earliest version (inclusive).
* @return A new {@link VersionRange}.
*/
public static VersionRange from(String version)
{
return new VersionRange(new Version(version), null);
}

/**
* Creates a version range ending at the specified version with no lower bound.
*
* @param version The latest version (inclusive).
* @return A new {@link VersionRange}.
*/
public static VersionRange until(String version)
{
return new VersionRange(null, new Version(version));
}

/**
* Creates a version range with specified bounds.
*
* @param earliestVersion The earliest version (inclusive). If null, there is no lower bound.
* @param latestVersion The latest version (inclusive). If null, there is no upper bound.
* @return A new {@link VersionRange}.
*/
public static VersionRange versionRange(String earliestVersion, String latestVersion)
{
Version earliest = earliestVersion == null ? null : new Version(earliestVersion);
Version latest = latestVersion == null ? null : new Version(latestVersion);
return new VersionRange(earliest, latest);
}

/**
* Checks if the specified version is within this range (inclusive).
*
* @param version The version to check.
* @return {@code true} if the version is within the range.
*/
public boolean contains(Version version)
{
return (eariestVersion == null || eariestVersion.compareTo(version) <= 0) &&
return (earliestVersion == null || earliestVersion.compareTo(version) <= 0) &&
(latestVersion == null || latestVersion.compareTo(version) >= 0);
}
}