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
6 changes: 6 additions & 0 deletions src/org/labkey/test/components/ui/files/AttachmentCard.java
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,11 @@ public boolean isFileUnavailable()
return elementCache().unavailableWarning.isPresent();
}

public String getDescription()
{
return elementCache().description.getText();
}

public boolean canRemove()
{
return getRemoveOption() != null;
Expand Down Expand Up @@ -146,6 +151,7 @@ protected ElementCache newElementCache()
protected class ElementCache extends Component<?>.ElementCache
{
final WebElement fileSize = Locator.byClass("attachment-card__size").findWhenNeeded(this);
final WebElement description = Locator.byClass("attachment-card__description").refindWhenNeeded(this);
final WebElement icon = Locator.byClass("attachment-card__icon_img").findWhenNeeded(this);
Optional<BootstrapMenu> menu = BootstrapMenu.finder(getDriver())
.locatedBy(Locator.tagWithClass("div", "attachment-card__menu"))
Expand Down
39 changes: 38 additions & 1 deletion src/org/labkey/test/pages/ReactAssayDesignerPage.java
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,9 @@
import org.labkey.test.components.ui.files.AttachmentCard;
import org.labkey.test.pages.assay.plate.PlateTemplateListPage;
import org.labkey.test.util.Maps;
import org.labkey.test.util.TestLogger;
import org.labkey.test.util.core.webdav.WebDavUploadHelper;
import org.labkey.test.util.core.webdav.WebDavUrlFactory;
import org.labkey.test.util.selenium.WebElementUtils;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
Expand Down Expand Up @@ -256,7 +259,7 @@ public boolean getStatus()

public ReactAssayDesignerPage addTransformScript(File transformScript)
{
return setTransformScript(transformScript, false, null);
return setTransformScript(transformScript, true, null);
}

public ReactAssayDesignerPage addTransformScript(File transformScript, boolean usingFileUpload)
Expand All @@ -278,6 +281,11 @@ private ReactAssayDesignerPage setTransformScript(File transformScript, boolean
String targetPath = transformScript.getAbsolutePath();
if (usingFileUpload)
{
// GitHub Issue #159: The upload fails if a file of the same name is already in the assay's "@scripts" dir,
// so remove any leftover file first.
if (expectedError == null)
removeExistingScriptFile(transformScript.getName());

getWrapper().setFormElement(Locator.tagWithClass("input", "file-upload__input"), transformScript);
targetPath = "/@scripts/" + transformScript.getName();
}
Expand All @@ -304,6 +312,22 @@ private ReactAssayDesignerPage setTransformScript(File transformScript, boolean
return this;
}

/**
* Remove a file from the "@scripts" dir of the container that this assay design lives in, if it is present. Uses
* WebDav directly instead of the "Manage script files" UI, which opens in a separate browser tab.
* @param fileName Name of the transform script file to remove
*/
private void removeExistingScriptFile(String fileName)
{
String manageScriptsUrl = elementCache().manageScriptFilesLink.getDomProperty("href");
WebDavUploadHelper webDavHelper = new WebDavUploadHelper(WebDavUrlFactory.fromDirectoryUrl(manageScriptsUrl));
if (webDavHelper.fileExists(fileName))
{
TestLogger.log("Removing existing transform script file: " + fileName);
webDavHelper.deleteFile(fileName);
}
}

public ReactAssayDesignerPage removeTransformScript(String fileName)
{
AttachmentCard card = new AttachmentCard.FileAttachmentCardFinder(getDriver()).withTitle(fileName).waitFor(this);
Expand All @@ -314,6 +338,17 @@ public ReactAssayDesignerPage removeTransformScript(String fileName)
return this;
}

/**
* The server side path of a transform script configured on this assay design, as shown on the script's card. This
* is the same value as the card's "Copy path" menu option, read from the DOM to avoid a clipboard round trip.
* @param fileName Name of the transform script file
*/
public String getTransformScriptPath(String fileName)
{
AttachmentCard card = new AttachmentCard.FileAttachmentCardFinder(getDriver()).withTitle(fileName).waitFor(this);
return card.getDescription();
}

public enum MetadataInputFormat implements OptionSelect.SelectOption
{
MANUAL,
Expand Down Expand Up @@ -388,6 +423,8 @@ Locator runOnActionCheckboxLoc(String fileName, ScriptFileEvent scriptFileEvent)
final Checkbox qcEnabledCheckbox = Checkbox(Locator.checkboxById("assay-design-qcEnabled")).findWhenNeeded(propertiesPanel);
final Checkbox plateTemplateCheckbox = Checkbox(Locator.checkboxById("assay-design-plateMetadata")).findWhenNeeded(propertiesPanel);
final Checkbox activeStatusCheckBox = Checkbox(Locator.checkboxById("assay-design-status")).findWhenNeeded(propertiesPanel);
final WebElement manageScriptFilesLink = Locator.tagWithClass("div", "transform-script--manage-link")
.child(Locator.linkWithText("Manage script files")).refindWhenNeeded(propertiesPanel);

final WebElement hitSelectionCriteriaBtn = Locator.tagWithClass("div", "filter-criteria-input__button")
.child(Locator.button("Edit Criteria")).findWhenNeeded(propertiesPanel);
Expand Down
16 changes: 16 additions & 0 deletions src/org/labkey/test/tests/GpatAssayTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -282,6 +282,22 @@ private ReactAssayDesignerPage startCreateGpatAssay(File dataFile, @LoggedParam
return assayDesignerPage;
}

@Test // GitHub Issue #159
public void testAssayTransformScriptPathError()
{
File trialData = TestFileUtils.getSampleData("GPAT/renameAssayTrial.xls");
String assayName = TestDataGenerator.randomDomainName();
log(String.format("Create an assay named '%s'.", assayName));
ReactAssayDesignerPage assayDesignerPage = startCreateGpatAssay(trialData, assayName);

log("Verify error message when trying to add transform script with path outside of @scripts dir");
assayDesignerPage.addTransformScript(RTRANSFORM_SCRIPT_FILE_NOOP, false);
List<String> errors = assayDesignerPage.clickSaveExpectingErrors();
Assert.assertTrue("Error msg not as expected during assay creation",
errors.contains("The transform script must exist within this folder's @scripts directory."));
assayDesignerPage.clickCancel();
}

@Test
public void testMultipleFileUploadInAssayRun()
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,9 @@
*/
package org.labkey.test.tests.assay;

import org.apache.commons.io.FileUtils;
import org.junit.Test;
import org.junit.experimental.categories.Category;
import org.labkey.api.util.FileUtil;
import org.labkey.test.Locator;
import org.labkey.test.TestFileUtils;
import org.labkey.test.categories.Assays;
Expand All @@ -26,11 +26,10 @@
import org.labkey.test.pages.ReactAssayDesignerPage;
import org.labkey.test.pages.assay.AssayImportPage;
import org.labkey.test.pages.assay.AssayRunsPage;
import org.labkey.test.pages.files.WebDavPage;
import org.labkey.test.params.assay.GeneralAssayDesign;

import java.io.File;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.List;

/**
Expand All @@ -40,53 +39,63 @@
@Category({Assays.class, Daily.class})
public class AssayTransformMissingParentDirTest extends AbstractAssayTransformTest
{
private static final File RTRANSFORM_SCRIPT_FILE_NOOP = TestFileUtils.getSampleData("qc/noopTransform.R");

@Test
public void testMissingParentDirectoryRegression() throws Exception
{
// Create a nested directory and an R transform script within it
// create a General assay and add the transform
String assayName = "missingParentDirAssay";
Path parentDir = Files.createTempDirectory("assay-transform-parent-");
Path nestedDir = FileUtil.createDirectories(parentDir.resolve("child"), false);
String scriptName = "transformMissingParent.R";
String transformContent = "library(Rlabkey);";
File transformFile = nestedDir.resolve(scriptName).toFile();
TestFileUtils.writeFile(transformFile, transformContent);

// Create a General assay and add the transform by absolute path (not upload)
String transformFileName = RTRANSFORM_SCRIPT_FILE_NOOP.getName();
var protocolResponse = new GeneralAssayDesign(assayName).setBatchFields(List.of(), false).createAssay(getProjectName(), createDefaultConnection());
var assayDesignerPage = ReactAssayDesignerPage.beginAt(this, getProjectName(), protocolResponse.getProtocolId(),
"general", "");
// add by path so the absolute path is stored; this allows reproducing the missing parent dir scenario
assayDesignerPage.addTransformScript(transformFile);
assayDesignerPage.addTransformScript(RTRANSFORM_SCRIPT_FILE_NOOP);
String transformScriptPath = assayDesignerPage.getTransformScriptPath(transformFileName);
assayDesignerPage.clickSave();

// move the script into a nested directory in the @scripts webdav path
WebDavPage webDavPage = WebDavPage.beginAt(this, getProjectName() + "/@scripts");
webDavPage.getFileBrowserHelper().createFolder("child");
File transformFile = new File(transformScriptPath);
File destinationFile = new File(transformFile.getParent() + "/child", transformFileName);
FileUtils.moveFile(transformFile, destinationFile);

// update the assay design with the new nested dir file path
assayDesignerPage = ReactAssayDesignerPage.beginAt(this, getProjectName(), protocolResponse.getProtocolId(),
"general", "");
assayDesignerPage.removeTransformScript(transformFileName);
assayDesignerPage.addTransformScript(destinationFile, false);
assayDesignerPage.clickSave();

// Now delete the parent dir to ensure we handle it reasonably
TestFileUtils.deleteDirWithRetry(parentDir.toFile());
// Now delete the nested dir to ensure we handle it reasonably
File destinationDir = new File(transformFile.getParent() + "/child");
FileUtils.deleteDirectory(destinationDir);

// Attempt to import data and verify a reasonable error message is shown
String importData = """
VisitID\tParticipantID\tComment
1\tP1\timport after parent deleted
""";

new AssayRunsPage(getDriver()).getTable().clickHeaderButtonAndWait("Import Data");
AssayRunsPage.beginAt(this, getProjectName(), protocolResponse.getProtocolId())
.getTable().clickHeaderButtonAndWait("Import Data");
var importPage = new AssayImportPage(getDriver());
importPage.setNamedInputText("Name", "missingParentImport");
importPage.setNamedTextAreaValue(AssayConstants.TEXT_AREA_DATA_COLLECTOR_TEXT_AREA_NAME, importData);
importPage.clickSaveAndFinish();

// Expect an error page/message indicating the transform script path cannot be used
// Be tolerant to platform-specific phrasing; assert any of these appear
String expectedPath = transformFile.getAbsolutePath();
checker().withScreenshot("missing-parent-error")
.verifyTrue("Expect an error message about the transform script path not being found",
isTextPresent("transformMissingParent.R, configured for this assay does not exist."));
isTextPresent(transformFileName + ", configured for this assay does not exist."));

// Fix the assay design by removing the transform script
goToProjectHome();
assayDesignerPage = ReactAssayDesignerPage.beginAt(this, getProjectName(), protocolResponse.getProtocolId(),
"general", getURL().toString());
assayDesignerPage.removeTransformScript(scriptName);
assayDesignerPage.removeTransformScript(transformFileName);
assayDesignerPage.clickSave();

// Retry the import and verify it succeeds without the transform
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -310,7 +310,6 @@ public void testTransformScriptValidation()

// verify check for valid script engine defined for the file extension
assayDesignerPage.addTransformScript(JAVA_INVALID_TRANSFORM_SCRIPT, true, "Script engine for the extension '.java' has not been registered.");
assayDesignerPage.addTransformScript(JAVA_INVALID_TRANSFORM_SCRIPT, false, "Script engine for the extension '.java' has not been registered.");

// verify check for duplicate file in @scripts dir
assayDesignerPage.addTransformScript(R_TRANSFORM_ERROR_SCRIPT, true);
Expand Down
10 changes: 10 additions & 0 deletions src/org/labkey/test/util/core/webdav/WebDavUrlFactory.java
Original file line number Diff line number Diff line change
Expand Up @@ -55,5 +55,15 @@ public static WebDavUrlFactory webFilesUrlFactory(String containerPath)
{
return new WebDavUrlFactory(buildBaseWebfilesUrl(containerPath));
}

/**
* For cases where the WebDav directory URL is already known (e.g. taken from the 'href' of a link rendered by the
* server or a React component) and doesn't need to be constructed from a container path.
* @param directoryUrl Absolute URL of a WebDav directory
*/
public static WebDavUrlFactory fromDirectoryUrl(String directoryUrl)
{
return new WebDavUrlFactory(directoryUrl);
}
}