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
151 changes: 128 additions & 23 deletions src/org/labkey/test/AssayAPITest.java

Large diffs are not rendered by default.

53 changes: 53 additions & 0 deletions src/org/labkey/test/tests/AttachmentFieldTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
import org.labkey.test.components.DomainDesignerPage;
import org.labkey.test.components.domain.DomainFieldRow;
import org.labkey.test.components.domain.DomainFormPanel;
import org.labkey.test.pages.admin.FileRootsManagementPage;
import org.labkey.test.pages.experiment.UpdateSampleTypePage;
import org.labkey.test.params.FieldDefinition;
import org.labkey.test.params.experiment.SampleTypeDefinition;
Expand Down Expand Up @@ -81,6 +82,15 @@ public void testFileFieldInSampleType()
setFormElement(Locator.name("quf_" + fieldName), SAMPLE_FILE);
clickButton("Submit");

assertElementPresent(Locator.tagWithAttribute("a", "title", "Download attached file"));

clickAndWait(Locator.tagWithText("a", "S1"));
clickAndWait(Locator.tagWithClass("a", "labkey-text-link").withText("edit"));
waitForElement(Locator.tagContainingText("div", "sampletype/jpg_sample.jpg"));
// Issue 53200: Update form incorrectly shows that a file is not available
assertTextNotPresent("sampletype/jpg_sample.jpg (unavailable)");
clickButton("Cancel");

log("Verifying view in browser works");
clickAndWait(Locator.tagWithAttributeContaining("img", "title", SAMPLE_FILE.getName()));
Assertions.assertThat(getDriver().getCurrentUrl()).as("File field view URL.").contains("core-downloadFileLink.view");
Expand All @@ -92,6 +102,49 @@ public void testFileFieldInSampleType()

File downloadedFile = doAndWaitForDownload(() -> Locator.tagWithAttributeContaining("img", "title", SAMPLE_FILE.getName()).findElement(getDriver()).click());
Assert.assertTrue("Downloaded file is empty", downloadedFile.length() > 0);

// create a subfolder and set the Project file root to child folder file root, to simulate sample file path not under current file root
String subFolder = "ChildFolder";
_containerHelper.createSubfolder(getProjectName(), subFolder);
clickFolder(subFolder);
FileRootsManagementPage fileRootsManagementPage = goToFolderManagement().goToFilesTab();
String childFileRoot = fileRootsManagementPage.getRootPath();
goToProjectHome();
fileRootsManagementPage = goToFolderManagement().goToFilesTab();
fileRootsManagementPage.useCustomFileRoot(childFileRoot).clickSave();

// verify file path display for files that's present but outside of current file root
verifyUnavailableFile();

// reset file root to default
goToFolderManagement()
.goToFilesTab()
.selectFileRootType(FileRootsManagementPage.FileRootOption.siteDefault)
.clickSave();
goToProjectHome();
clickAndWait(Locator.linkWithText(sampleTypeName));
assertElementPresent(Locator.tagWithAttribute("a", "title", "Download attached file"));

// delete the file and verify file path that doesn't exist
goToModule("FileContent");
_fileBrowserHelper.deleteFile("sampletype");
verifyUnavailableFile();
}

private void verifyUnavailableFile()
{
String sampleTypeName = "Sample type with attachment";
goToProjectHome();
clickAndWait(Locator.linkWithText(sampleTypeName));
waitForElement(Locator.tagContainingText("td", "jpg_sample.jpg (unavailable)"));
assertElementNotPresent(Locator.tagWithAttribute("a", "title", "Download attached file"));

// "(unavailable)" suffix is present in update view
clickAndWait(Locator.tagWithText("a", "S1"));
clickAndWait(Locator.tagWithClass("a", "labkey-text-link").withText("edit"));
waitForElement(Locator.tagContainingText("div", "jpg_sample.jpg (unavailable)"));
assertElementNotPresent(Locator.tagWithAttributeContaining("img", "src", "/_icons/image.png"));

}

@Test
Expand Down
203 changes: 168 additions & 35 deletions src/org/labkey/test/tests/SampleTypeTest.java

Large diffs are not rendered by default.

64 changes: 58 additions & 6 deletions src/org/labkey/test/util/APIAssayHelper.java
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@
import java.util.List;
import java.util.Map;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.fail;

public class APIAssayHelper extends AbstractAssayHelper
Expand Down Expand Up @@ -83,14 +84,44 @@ public ImportRunResponse importAssay(int assayID, String runFilePath, String pro

@LogMethod(quiet = true)
public ImportRunResponse importAssay(int assayID, String runName, List<Map<String, Object>> dataRows, String projectPath,
Map<String, Object> runProperties, Map<String, Object> batchProperties) throws CommandException, IOException
Map<String, Object> runProperties, Map<String, Object> batchProperties, String errorMsg) throws CommandException, IOException
{
ImportRunCommand irc = new ImportRunCommand(assayID, dataRows);
irc.setName(runName);
irc.setProperties(runProperties);
irc.setBatchProperties(batchProperties);
irc.setTimeout(180000); // Wait 3 minutes for assay import
return irc.execute(_test.createDefaultConnection(), projectPath);
if (errorMsg != null)
{
try
{
irc.execute(_test.createDefaultConnection(), projectPath);
throw new Exception("This should have failed");
}
catch (CommandException e)
{
Map<String, Object> responseJson = e.getProperties();
if (!responseJson.containsKey("exception"))
throw new CommandException("Response lacks exception");

String exception = responseJson.get("exception").toString();
assertEquals("Invalid file path message not as expected", errorMsg, exception);
return null;
}
catch (Exception e)
{
throw new CommandException(e.getMessage());
}
}
else
return irc.execute(_test.createDefaultConnection(), projectPath);
}

@LogMethod(quiet = true)
public ImportRunResponse importAssay(int assayID, String runName, List<Map<String, Object>> dataRows, String projectPath,
Map<String, Object> runProperties, Map<String, Object> batchProperties) throws CommandException, IOException
{
return importAssay(assayID, runName, dataRows, projectPath, runProperties, batchProperties, null);
}

@LogMethod(quiet = true)
Expand Down Expand Up @@ -280,7 +311,7 @@ public static Map<String, Integer> getProtocolIds(String containerPath, Connecti
return resultData;
}

public void saveBatch(String assayName, String runName, Map<String, Object> runProperties, List<Map<String, Object>> resultRows, String projectName) throws IOException, CommandException
public void saveBatch(String assayName, String runName, Map<String, Object> runProperties, List<Map<String, Object>> resultRows, String projectName, @Nullable String errorMsg) throws Exception
{
int assayId = getIdFromAssayName(assayName, projectName);

Expand All @@ -294,14 +325,35 @@ public void saveBatch(String assayName, String runName, Map<String, Object> runP
runs.add(run);
batch.setRuns(runs);

saveBatch(assayId, batch, projectName);
saveBatch(assayId, batch, projectName, errorMsg);
}

public void saveBatch(int assayId, Batch batch, String projectPath) throws IOException, CommandException
public void saveBatch(int assayId, Batch batch, String projectPath, @Nullable String errorMsg) throws Exception
{
SaveAssayBatchCommand cmd = new SaveAssayBatchCommand(assayId, batch);
cmd.setTimeout(180000); // Wait 3 minutes for assay import
cmd.execute(_test.createDefaultConnection(), projectPath);
if (errorMsg != null)
{
try
{
var result = cmd.execute(_test.createDefaultConnection(), projectPath);
throw new Exception("This should have failed");
}
catch (CommandException e)
{
Map<String, Object> responseJson = e.getProperties();
if (!responseJson.containsKey("exception"))
throw new Exception("Response lacks exception");

String exception = responseJson.get("exception").toString();
assertEquals("Invalid file path message not as expected", errorMsg, exception);
}
}
else
cmd.execute(_test.createDefaultConnection(), projectPath);



}

public Protocol createAssayDesignWithDefaults(String containerPath, String providerName, String assayName) throws IOException, CommandException
Expand Down
30 changes: 30 additions & 0 deletions src/org/labkey/test/util/APITestHelper.java
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.regex.Pattern;

import static org.junit.Assert.fail;
Expand Down Expand Up @@ -206,6 +207,35 @@ public static void injectCookies(@NotNull String username, HttpUriRequest method
method.setHeader(session.getName(), session.getValue());
}

/*
reads a script result object, returns a string representation of an exception if it exists.
calling code should check the result and assert accordingly.
an exception means there was a server-side exception, rather than a script error.
*/
static public String parseScriptResult(Map<String, Object> scriptResult)
{
if (scriptResult.containsKey("exception"))
{
String exType = (String)scriptResult.get("exception");
if (exType.contains("ERROR:"))
return exType; // not an exception, but a friendly error message

ArrayList<String> frames = (ArrayList<String>)scriptResult.get("stackTrace");

StringBuilder builder = new StringBuilder();
if (null != frames)
{
for (String frame : frames)
{
builder.append(frame + "\n");
}
return "An exception of type [" + exType + "] occurred while executing the script.\n[ " + builder + " ]";
}
}

return null;
}

public static class ApiTestCase
{
private String _name;
Expand Down
25 changes: 25 additions & 0 deletions src/org/labkey/test/util/EscapeUtil.java
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,31 @@

public class EscapeUtil
{
static public String toJSONStr(String str)
{
if (str == null) return null;
StringBuilder escaped = new StringBuilder();
for (char c : str.toCharArray()) {
switch (c) {
case '"': escaped.append("\\\""); break;
case '\\': escaped.append("\\\\"); break;
case '\b': escaped.append("\\b"); break;
case '\f': escaped.append("\\f"); break;
case '\n': escaped.append("\\n"); break;
case '\r': escaped.append("\\r"); break;
case '\t': escaped.append("\\t"); break;
default:
// Escape control characters (ASCII 0-31) and ensure Unicode compatibility
if (c < 32) {
escaped.append(String.format("\\u%04x", (int) c));
} else {
escaped.append(c);
}
}
}
return escaped.toString();
}

static public String jsString(String s)
{
if (s == null)
Expand Down
59 changes: 59 additions & 0 deletions src/org/labkey/test/util/FileBrowserHelper.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,17 @@
import org.apache.commons.lang3.mutable.MutableObject;
import org.jetbrains.annotations.Nullable;
import org.junit.Assert;
import org.labkey.remoteapi.CommandException;
import org.labkey.remoteapi.Connection;
import org.labkey.remoteapi.query.Filter;
import org.labkey.remoteapi.query.SelectRowsCommand;
import org.labkey.remoteapi.query.SelectRowsResponse;
import org.labkey.test.BaseWebDriverTest;
import org.labkey.test.Locator;
import org.labkey.test.SortDirection;
import org.labkey.test.TestProperties;
import org.labkey.test.WebDriverWrapper;
import org.labkey.test.WebTestHelper;
import org.labkey.test.components.DomainDesignerPage;
import org.labkey.test.components.ext4.Checkbox;
import org.labkey.test.components.ext4.RadioButton;
Expand All @@ -40,6 +46,7 @@
import org.openqa.selenium.support.ui.WebDriverWait;

import java.io.File;
import java.io.IOException;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.time.Duration;
Expand Down Expand Up @@ -873,6 +880,58 @@ public void openFolderTree()
}
}

private String stringOrNull(Object value)
{
if (value == null)
return null;
return (String) value;
}

public record FileDetailInfo(String fileName, String absoluteFilePath, String dataFileUrl, String webDavUrl, String webDavUrlRelative)
{
}

public FileDetailInfo getFileDetailInfo(String containerPath, String fileName)
{
List<String> filePathColumns = List.of("AbsoluteFilePath", "FileExists", "DataFileUrl", "WebDavUrl", "WebDavUrlRelative");
try
{
Connection cn = WebTestHelper.getRemoteApiConnection();
SelectRowsCommand cmd = new SelectRowsCommand("exp", "files");
cmd.addFilter("Name", fileName, Filter.Operator.EQUAL);
cmd.setColumns(filePathColumns);
SelectRowsResponse response = cmd.execute(cn, "/" + containerPath);

for (Map<String, Object> row: response.getRows())
{
if (!(Boolean) row.get("FileExists"))
continue;
Object absoluteFilePath = row.get("AbsoluteFilePath");
Object dataFileUrl = row.get("DataFileUrl");
Object webDavUrl = row.get("WebDavUrl");
Object webDavUrlRelative = row.get("WebDavUrlRelative");
return new FileDetailInfo(fileName, stringOrNull(absoluteFilePath), stringOrNull(dataFileUrl), stringOrNull(webDavUrl), stringOrNull(webDavUrlRelative));
}
}
catch (CommandException ce)
{
if (ce.getStatusCode() == 404)
{
return null;
}
else
{
throw new RuntimeException(ce);
}
}
catch (IOException ioe)
{
throw new RuntimeException(ioe);
}

return null;
}

// See PageFlowUtil.encodeURIComponent()
private static final Map<String, String> DECODE_UNRESERVED_MARKS = Map.of(
"!", "%21",
Expand Down
13 changes: 12 additions & 1 deletion src/org/labkey/test/util/data/TestDataUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@
import org.labkey.serverapi.reader.TabLoader;
import org.labkey.test.TestFileUtils;
import org.labkey.test.params.FieldDefinition;
import org.labkey.test.util.EscapeUtil;
import org.labkey.test.util.TestDataGenerator;
import org.labkey.test.util.TestLogger;

Expand Down Expand Up @@ -296,6 +295,12 @@ public static String tsvStringFromRowMaps(List<Map<String, Object>> rowMaps, Lis
return stringFromRowMaps(rowMaps, columns, includeHeaders, CSVFormat.TDF);
}

public static String tsvStringFromRowMapsEscapeBackslash(List<Map<String, Object>> rowMaps, List<String> columns,
boolean includeHeaders)
{
return stringFromRowMaps(rowMaps, columns, includeHeaders, CSVFormat.MYSQL);
}

public static <T> List<Map<String, T>> mapsFromRows(List<List<T>> allRows)
{
List<Map<String, T>> rowMaps = new ArrayList<>();
Expand Down Expand Up @@ -439,6 +444,12 @@ public static <T> File writeRowsToTsv(String fileName, List<List<T>> rows) throw
return writeRowsToFile(fileName, rows, CSVFormat.TDF);
}

public static <T> File writeRowsToTsvEscapeBackslash(String fileName, List<List<T>> rows) throws IOException
{
return writeRowsToFile(fileName, rows, CSVFormat.MYSQL);
}


public static <T> File writeRowsToCsv(String fileName, List<List<T>> rows) throws IOException
{
return writeRowsToFile(fileName, rows, CSVFormat.DEFAULT);
Expand Down