diff --git a/signalData/resources/views/mockSignalDataWatch.html b/signalData/resources/views/mockSignalDataWatch.html index 0d3f9681e..efa0c1d15 100644 --- a/signalData/resources/views/mockSignalDataWatch.html +++ b/signalData/resources/views/mockSignalDataWatch.html @@ -61,23 +61,23 @@ } }); - var dataRows = [], - dataInputs = []; + var dataRows = [], dataInputs = []; Ext4.each(fileSet, function(file) { + var fileName = file['FileName']; dataRows.push({ - Name: file.text, - DataFile: SIGNAL_DATA_FILE_ROOT + file.text, + Name: fileName, + DataFile: SIGNAL_DATA_FILE_ROOT + fileName, TestType: 'SMP' }); dataInputs.push({ - name: file.text, - dataFileURL: file.dataFileURL + name: fileName, + dataFileURL: file['DataFileUrl'] }); }); - run.dataRows = dataRows; run.dataInputs = dataInputs; + return run; } @@ -197,33 +197,24 @@ { if (Ext4.isFunction(callback)) { - var received = 0; - var newFiles = []; - - function done(file, results) - { - Ext4.each(files, function(f) { - if (f.text === file.text) { - f['dataFileURL'] = results['DataFileUrl']; - newFiles.push(f); - } - }); - received++; - - if (received == files.length) { - callback.call(scope || this, newFiles); - } - } + var paths = []; + var fileNames = []; + files.forEach(function (file) { + paths.push(decodeURIComponent(file.id)); + fileNames.push(file.text); + }, this); - Ext4.each(files, function(file) { - LABKEY.Ajax.request({ - url: LABKEY.ActionURL.buildURL('signaldata', 'getSignalDataResource.api'), - method: 'POST', - params: { path: decodeURIComponent(file.id), test: true }, - success: function(response) { - done(file, Ext4.decode(response.responseText)); - } - }); + LABKEY.Ajax.request({ + url: LABKEY.ActionURL.buildURL('SignalData', 'getSignalDataResource.api'), + method: 'POST', + jsonData: { + paths : paths, + files : fileNames + }, + success: LABKEY.Utils.getCallbackWrapper(function(response) { + callback.call(scope || this, response.files); + }, this), + scope: this }); } } diff --git a/signalData/resources/web/signaldata/ResultUpdate/resultupdate.js b/signalData/resources/web/signaldata/ResultUpdate/resultupdate.js index 2c4f95710..6cd9fb9f0 100644 --- a/signalData/resources/web/signaldata/ResultUpdate/resultupdate.js +++ b/signalData/resources/web/signaldata/ResultUpdate/resultupdate.js @@ -34,8 +34,8 @@ var getResultData = function(assay) { requiredVersion: 13.2, filterArray: [LABKEY.Filter.create('RowId', LABKEY.ActionURL.getParameter('rowId'))], success: function(results){ - if (results.length > 0) { - init(assay, results.getRow(0)); + if (results.rowCount > 0) { + init(assay, results.rows[0]); } else { // Use an ExtJS alert instead of a raw browser alert to avoid alarming the crawler @@ -64,12 +64,16 @@ var init = function(assay, row){ LABKEY.Ajax.request({ url: LABKEY.ActionURL.buildURL('SignalData', 'getSignalDataResource.api'), method: 'POST', - params: {path: decodeURIComponent(file.internalId), test: true}, - success: function (response) { - var fileResource = Ext4.decode(response.responseText); - var updatedRow = setRunFields(form, fileResource); - updateRunResult(updatedRow, fileResource); + params: { + paths: [decodeURIComponent(file.internalId)], + files: [file.name] }, + success: LABKEY.Utils.getCallbackWrapper(function(response) { + Ext4.each(response.files, function(file) { + var updatedRow = setRunFields(form, file); + updateRunResult(updatedRow, file); + }, this); + }, this), scope: this }); } diff --git a/signalData/resources/web/signaldata/UploadView/UploadLog.js b/signalData/resources/web/signaldata/UploadView/UploadLog.js index 643372aa8..895c7b36b 100644 --- a/signalData/resources/web/signaldata/UploadView/UploadLog.js +++ b/signalData/resources/web/signaldata/UploadView/UploadLog.js @@ -244,17 +244,56 @@ Ext4.define('LABKEY.SignalData.UploadLog', { if (Ext4.isFunction(callback)) { var me = this; var destination = this.fileSystem.concatPaths(this.fileSystem.getBaseURL(), targetDirectory); - this.fileSystem.renamePath({ - source: this.getWorkingPath(), - destination: destination, - isFile: false, - success: function () { - me.resolveFileResources(targetDirectory, callback, scope, runProperties); + + const getResourcesCallback = function(files) { + if (files && files.length > 0) { + // files currently exist, validate and resolve before creating the run + me.resolveDataFileURL(files, callback, scope, runProperties); } - }); + else { + // files need to be moved to the target directory + this.fileSystem.renamePath({ + source: this.getWorkingPath(), + destination: destination, + isFile: false, + success: function () { + me.resolveFileResources(targetDirectory, callback, scope, runProperties); + } + }); + } + }; + + // get the list of files in the target directory (if any) + this.getTargetDirResources(targetDirectory, getResourcesCallback, this); } }, + /** + * Returns the list of data files in the target directory. Uploaded run data files are moved from + * a temporary location to the target directory before the run is created. + */ + getTargetDirResources : function (targetDirectory, callback, callbackScope) { + var fileUri = this.fileSystem.concatPaths(this.fileSystem.getAbsoluteURL(), targetDirectory); + LABKEY.Ajax.request({ + url: fileUri, + method: 'GET', + params: {method: 'JSON'}, + success: function (response) { + var json = Ext4.decode(response.responseText); + var files = []; + if (Ext4.isDefined(json) && Ext4.isArray(json.files)) + files = json.files; + + callback.call(callbackScope, files); + }, + failure: function() { + // this is normal in the case where the target directory does not yet exist or + // the files have not yet been moved there + callback.call(callbackScope, []); + } + }); + }, + resolveFileResources: function (targetDirectory, callback, callbackScope, runProperties) { var fileUri = this.fileSystem.concatPaths(this.fileSystem.getAbsoluteURL(), targetDirectory); LABKEY.Ajax.request({ @@ -269,9 +308,10 @@ Ext4.define('LABKEY.SignalData.UploadLog', { } } }, - failure: function () { - } - , scope: this + failure: LABKEY.Utils.getCallbackWrapper(function(json, response, opts) { + LABKEY.Utils.alert('Error', 'Unable to resolve file resources : ' + response.exception); + }, this, true), + scope: this }, this); }, @@ -281,41 +321,42 @@ Ext4.define('LABKEY.SignalData.UploadLog', { resolveDataFileURL: function (files, callback, scope, runProperties) { if (Ext4.isFunction(callback)) { - var received = 0; - var newFiles = []; - var me = this; + var paths = []; + var fileNames = []; + files.forEach(function (file) { + paths.push(decodeURIComponent(file.id)); + fileNames.push(file.text); + }, this); - function done(file, results) { + LABKEY.Ajax.request({ + url: LABKEY.ActionURL.buildURL('SignalData', 'getSignalDataResource.api'), + method: 'POST', + jsonData: { + paths : paths, + files : fileNames + }, + success: function (response) { + let result = Ext4.decode(response.responseText); + let store = this.getStore(); - var store = me.getStore(); - var idx = store.find(me.DATA_FILE, file.text); - var process = store.getAt(idx); + Ext4.each(result.files, function(file) { - //Set upload time - process.set(me.FILENAME, results[me.DATA_FILE]); - process.set(me.FILE_URL, results['DataFileUrl']); - process.set('file', file); - newFiles.push(file); - received++; + var idx = store.find(this.DATA_FILE, file["FileName"]); + var rec = store.getAt(idx); - if (received == files.length) { - callback.call(scope || me, newFiles, runProperties); - } - } + if (rec) { + //Set upload time in the store record + rec.set(me.FILENAME, file[this.DATA_FILE]); + rec.set(me.FILE_URL, file['DataFileUrl']); + rec.set('file', true); + } + }, this); - //TODO: This should be refactored to use a single ajax call for the array - files.forEach(function (file) { - LABKEY.Ajax.request({ - url: LABKEY.ActionURL.buildURL('SignalData', 'getSignalDataResource.api'), - method: 'POST', - params: {path: decodeURIComponent(file.id), test: true}, - success: function (response) { - done(file, Ext4.decode(response.responseText)); - }, - scope: this - }); - }, this); + callback.call(scope || me, runProperties); + }, + scope: this + }); } }, diff --git a/signalData/resources/web/signaldata/UploadView/uploadResultFiles.js b/signalData/resources/web/signaldata/UploadView/uploadResultFiles.js index f51a34f37..dc0ca0f48 100644 --- a/signalData/resources/web/signaldata/UploadView/uploadResultFiles.js +++ b/signalData/resources/web/signaldata/UploadView/uploadResultFiles.js @@ -366,13 +366,13 @@ LABKEY.SignalData.initializeDataFileUploadForm = function (metadataFormId, eleme window.location = returnUrl; },this); }, - failure: function(response){ - //TODO: Should probably do something here... - } + failure: LABKEY.Utils.getCallbackWrapper(function(json, response, opts) { + LABKEY.Utils.alert('Error', 'Unable to save run : ' + response.exception); + }, this, true) }, this); } - var generateAndSaveRun = function(files, fieldValues) { + var generateAndSaveRun = function(fieldValues) { var dataRows = []; var dataInputs = []; diff --git a/signalData/src/org/labkey/signaldata/SignalDataController.java b/signalData/src/org/labkey/signaldata/SignalDataController.java index b065d3301..5fbc76a2d 100644 --- a/signalData/src/org/labkey/signaldata/SignalDataController.java +++ b/signalData/src/org/labkey/signaldata/SignalDataController.java @@ -22,7 +22,7 @@ import org.labkey.api.action.ReadOnlyApiAction; import org.labkey.api.action.SpringActionController; import org.labkey.api.data.Container; -import org.labkey.api.data.RuntimeSQLException; +import org.labkey.api.data.DbScope; import org.labkey.api.data.TableInfo; import org.labkey.api.exp.api.ExpData; import org.labkey.api.exp.api.ExperimentService; @@ -32,10 +32,11 @@ import org.labkey.api.pipeline.PipeRoot; import org.labkey.api.pipeline.PipelineService; import org.labkey.api.query.QueryUpdateService; +import org.labkey.api.query.ValidationException; import org.labkey.api.security.RequiresPermission; import org.labkey.api.security.permissions.ReadPermission; +import org.labkey.api.security.permissions.UpdatePermission; import org.labkey.api.util.FileUtil; -import org.labkey.api.util.UnexpectedException; import org.labkey.api.webdav.WebdavResource; import org.labkey.api.webdav.WebdavService; import org.labkey.signaldata.assay.SignalDataAssayDataHandler; @@ -43,9 +44,8 @@ import org.springframework.validation.BindException; import java.io.File; -import java.net.MalformedURLException; import java.net.URI; -import java.sql.SQLException; +import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.List; @@ -101,115 +101,103 @@ public ApiResponse execute(Object form, BindException errors) throws Exception public static class SignalDataResourceForm { - public String _path; - public boolean _test = false; + private List _paths; + private List _files; - public String getPath() + public List getFiles() { - return _path; + return _files; } - public void setPath(String path) + public void setFiles(List files) { - _path = path; + _files = files; } - public boolean isTest() + public List getPaths() { - return _test; + return _paths; } - public void setTest(boolean test) + public void setPaths(List paths) { - _test = test; + _paths = paths; } } - - @RequiresPermission(ReadPermission.class) + @RequiresPermission(UpdatePermission.class) public static class getSignalDataResourceAction extends MutatingApiAction { @Override - public ApiResponse execute(SignalDataResourceForm form, BindException errors) + public ApiResponse execute(SignalDataResourceForm form, BindException errors) throws Exception { - String path = form.getPath(); - WebdavResource resource = WebdavService.get().lookup(path); - Map props = new HashMap<>(); + List> results = new ArrayList<>(); Container c = getContainer(); + FileContentService svc = FileContentService.get(); + TableInfo ti = new ExpSchema(getUser(), getContainer()).getDatasTable(); + QueryUpdateService qus = ti.getUpdateService(); + int maxUrlSize = ExperimentService.get().getTinfoData().getColumn(ExpDataTable.Column.DataFileUrl.name()).getScale(); + int idx = 0; - if (null != resource) + try (DbScope.Transaction transaction = DbScope.getLabKeyScope().ensureTransaction()) { - FileContentService svc = FileContentService.get(); - ExpData data = svc.getDataObject(resource, c); - - if (form.isTest() && data == null) + for (String path : form.getPaths()) { - // Generate the data to help the test, replicating what DavController would do for us - File file = resource.getFile(); - if (null != file) - { - data = ExperimentService.get().createData(c, UPLOADED_FILE); - data.setName(file.getName()); - data.setDataFileURI(file.toURI()); + WebdavResource resource = WebdavService.get().lookup(path); + String fileName = form.getFiles().get(idx++); - int scale = ExperimentService.get().getTinfoData().getColumn("DataFileURL").getScale(); - String dataFileURL = data.getDataFileUrl(); - if (dataFileURL == null || dataFileURL.length() <= scale) - { - data.save(getUser()); - } - else + if (null != resource) + { + ExpData data = svc.getDataObject(resource, c); + if (data == null) { - // If the path is too long to store, bail out without creating an exp.data row - } - } - } - - if (null != data) - { - TableInfo ti = ExpSchema.TableType.Data.createTable(new ExpSchema(getUser(), c), ExpSchema.TableType.Data.toString(), null); - QueryUpdateService qus = ti.getUpdateService(); + // create the ExpData object if it doesn't already exist + File file = resource.getFile(); + if (null != file) + { + data = ExperimentService.get().createData(c, UPLOADED_FILE); + data.setName(file.getName()); + data.setDataFileURI(file.toURI()); - try - { - File canonicalFile = FileUtil.getAbsoluteCaseSensitiveFile(resource.getFile()); - String url = canonicalFile.toURI().toURL().toString(); - Map keys = Collections.singletonMap(ExpDataTable.Column.DataFileUrl.name(), url); - List> rows = qus.getRows(getUser(), c, Collections.singletonList(keys)); + String dataFileURL = data.getDataFileUrl(); + if (dataFileURL == null || dataFileURL.length() <= maxUrlSize) + { + data.save(getUser()); + } + else + { + throw new ValidationException(String.format("The data file URL is too long to store in the database (max %d).", maxUrlSize)); + } + } + } - if (rows.size() == 1) + if (null != data) { - for (Map.Entry entry : rows.get(0).entrySet()) - { - Object value = entry.getValue(); + File canonicalFile = FileUtil.getAbsoluteCaseSensitiveFile(resource.getFile()); + String url = canonicalFile.toURI().toURL().toString(); + List> rows = qus.getRows(getUser(), c, Collections.singletonList(Map.of(ExpDataTable.Column.DataFileUrl.name(), url))); - if (null != value) + if (rows.size() == 1) + { + Map props = new HashMap<>(); + props.put("FilePath", path); + props.put("FileName", fileName); + results.add(props); + for (Map.Entry entry : rows.get(0).entrySet()) { - props.put(entry.getKey(), String.valueOf(value)); + Object value = entry.getValue(); + if (null != value) + props.put(entry.getKey(), String.valueOf(value)); } } + else + throw new RuntimeException(String.format("Unexpected number of rows returned for DataFileUrl '%s': %d", url, rows.size())); } } - catch (MalformedURLException e) - { - throw UnexpectedException.wrap(e); - } - catch (SQLException e) - { - throw new RuntimeSQLException(e); - } - catch (RuntimeException re) - { - throw re; - } - catch (Exception e) - { - throw new RuntimeException(e); - } } + transaction.commit(); } - - return new ApiSimpleResponse(props); + return new ApiSimpleResponse(Map.of("files", results)); } } } \ No newline at end of file diff --git a/signalData/test/src/org/labkey/test/pages/signaldata/SignalDataUploadPage.java b/signalData/test/src/org/labkey/test/pages/signaldata/SignalDataUploadPage.java index fe1e6a427..ad9a313d1 100644 --- a/signalData/test/src/org/labkey/test/pages/signaldata/SignalDataUploadPage.java +++ b/signalData/test/src/org/labkey/test/pages/signaldata/SignalDataUploadPage.java @@ -18,9 +18,11 @@ import org.labkey.test.BaseWebDriverTest; import org.labkey.test.Locator; import org.labkey.test.WebDriverWrapper; +import org.labkey.test.components.bootstrap.ModalDialog; import org.labkey.test.components.ext4.Window; import org.labkey.test.util.Ext4Helper; import org.openqa.selenium.Keys; +import org.openqa.selenium.WebDriver; import org.openqa.selenium.WebElement; import org.openqa.selenium.support.ui.ExpectedConditions; @@ -111,6 +113,15 @@ public void saveRun() _test.clickAndWait(Locators.saveButton); } + public Window saveRunExpectingError(WebDriver webDriver) + { + WebElement saveButton = Locators.saveButton.findElement(_test.getDriver()); + WebDriverWrapper.waitFor(() -> !saveButton.getAttribute("class").contains("disabled"), "Unable to save, button is disabled", 1000); + _test.click(Locators.saveButton); + + return Window(_test.getDriver()).withTitle("Error").waitFor(); + } + private static class Locators { static final Locator.XPathLocator runIdentifier = Locator.input("RunIdentifier").notHidden(); diff --git a/signalData/test/src/org/labkey/test/tests/signaldata/SignalDataRawTest.java b/signalData/test/src/org/labkey/test/tests/signaldata/SignalDataRawTest.java index fd8f92cf3..8b6d9ec9f 100644 --- a/signalData/test/src/org/labkey/test/tests/signaldata/SignalDataRawTest.java +++ b/signalData/test/src/org/labkey/test/tests/signaldata/SignalDataRawTest.java @@ -23,16 +23,22 @@ import org.labkey.test.BaseWebDriverTest; import org.labkey.test.Locator; import org.labkey.test.categories.Daily; +import org.labkey.test.pages.ReactAssayDesignerPage; import org.labkey.test.pages.signaldata.SignalDataAssayBeginPage; import org.labkey.test.pages.signaldata.SignalDataRunViewerPage; import org.labkey.test.pages.signaldata.SignalDataUploadPage; +import org.labkey.test.params.FieldDefinition; import org.labkey.test.util.DataRegionTable; import org.labkey.test.util.Ext4Helper; +import org.labkey.test.components.ext4.Window; import org.labkey.test.util.PostgresOnlyTest; +import org.labkey.test.util.data.TestDataUtils; import org.labkey.test.util.signaldata.SignalDataInitializer; import org.openqa.selenium.WebElement; import java.io.File; +import java.io.IOException; +import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Map; @@ -84,14 +90,14 @@ public static void doSetup() throws Exception @Before public void preTest() { - // Reset to the original run/data file set created in the initialize - navigateToAssayLandingPage().resetUploadedData(DEFAULT_RUN); + // Reset to the original run/data file set created in the initializing + navigateToAssayLandingPage(SignalDataInitializer.RAW_SignalData_ASSAY).resetUploadedData(DEFAULT_RUN); } @Test public void testRunsSearch() { - SignalDataAssayBeginPage beginPage = navigateToAssayLandingPage(); + SignalDataAssayBeginPage beginPage = navigateToAssayLandingPage(SignalDataInitializer.RAW_SignalData_ASSAY); //Test search by file beginPage.setSearchBox(RESULT_FILENAME_1); @@ -107,7 +113,7 @@ public void testRunsSearch() public void testRunViewer() { // TODO: Test the run viewer. See FormulationsTest.qualityControlHPLCData for guidance. - SignalDataAssayBeginPage beginPage = navigateToAssayLandingPage(); + SignalDataAssayBeginPage beginPage = navigateToAssayLandingPage(SignalDataInitializer.RAW_SignalData_ASSAY); beginPage.selectData(RESULT_FILENAME_1, DEFAULT_RUN); beginPage.selectData(RESULT_FILENAME_2, DEFAULT_RUN); @@ -132,7 +138,8 @@ public void testFileImport() File metadataFile = getFile("RunsMetadata/datafiles.tsv"); Map> expectedData = Map.of("StringValue", List.of("StringOne", "StringTwo", "StringThree"), "IntegerValue", List.of("1", "2", "3")); - SignalDataAssayBeginPage beginPage = importRun("importTest1", + SignalDataAssayBeginPage beginPage = importRun(SignalDataInitializer.RAW_SignalData_ASSAY, + "importTest1", metadataFile, List.of(getFile(String.join("/", ASSAY_DATA_LOC, "BLANK235.TXT"))), List.of( @@ -150,10 +157,11 @@ public void testFileImport() uploadPage.setRunIDField("cleared run"); assertElementPresent(Ext4Helper.Locators.getGridRow()); //Check grid has elements uploadPage.clearRun(); - navigateToAssayLandingPage(); //Should not cause unload warning + navigateToAssayLandingPage(SignalDataInitializer.RAW_SignalData_ASSAY); //Should not cause unload warning // test upload of metadata file with full data file paths - importRun("importTest2", + importRun(SignalDataInitializer.RAW_SignalData_ASSAY, + "importTest2", getFile("RunsMetadata/datafiles2.tsv"), Collections.emptyList(), List.of( @@ -164,7 +172,8 @@ public void testFileImport() ), Collections.EMPTY_MAP, 4); // test import of files with a subset of the metadata files - importRun("importTest3", + importRun(SignalDataInitializer.RAW_SignalData_ASSAY, + "importTest3", getFile("RunsMetadata/datafiles.tsv"), List.of(getFile(String.join("/", ASSAY_DATA_LOC, "BLANK235.TXT"))), List.of( @@ -173,7 +182,8 @@ public void testFileImport() ), expectedData, 3); - importRun("importTest4", + importRun(SignalDataInitializer.RAW_SignalData_ASSAY, + "importTest4", getFile("RunsMetadata/datafiles2.tsv"), Collections.emptyList(), List.of( @@ -182,16 +192,126 @@ public void testFileImport() ), Collections.EMPTY_MAP, 4); } + @Test + public void testErrorConditions() throws IOException + { + + String errorAssay = "Test Errors Conditions"; + + goToProjectHome(); + + log("Defining Error Assay"); + goToManageAssays(); + + // We don't handle tricky characters well. + // Uncomment these lines once Issue 53965 is fixed. +// String strFieldName = TestDataGenerator.randomFieldName("Str"); +// String intFieldName = TestDataGenerator.randomFieldName("Int"); + String strFieldName = "Str"; + String intFieldName = "Int"; + + FieldDefinition strField = new FieldDefinition(strFieldName, FieldDefinition.ColumnType.String) + .setRequired(true); + + FieldDefinition intField = new FieldDefinition(intFieldName, FieldDefinition.ColumnType.Integer) + .setValidators(List.of(new FieldDefinition.RangeValidator("Large", "Must be greater than 5.", + "Value must be greater than 5.", + FieldDefinition.RangeType.GT, "5"))); + + ReactAssayDesignerPage assayDesigner = _assayHelper.createAssayDesign("Signal Data", errorAssay); + assayDesigner.setDescription("Testing error condition are handled correctly."); + assayDesigner.setEditableRuns(true); + assayDesigner.setEditableResults(true); + assayDesigner.goToResultsFields() + .addField(strField) + .addField(intField); + assayDesigner.clickFinish(); + + List> fileData = new ArrayList<>(); + fileData.add(List.of("Name", "DataFile", strField.getName(), intField.getName())); + fileData.add(List.of("Missing Required", RESULT_FILENAME_1, "", "123")); + fileData.add(List.of("Has All", RESULT_FILENAME_2, "DEF", "456")); + File metadataFile = TestDataUtils.writeRowsToTsv("Missing Require Result Field.tsv", fileData); + + log("Validate error condition of a required field is missing."); + uploadWithErrorAction(errorAssay, + metadataFile, + "Missing Required Run", + String.format("Missing value for required property: %s", strField.getName())); + + fileData = new ArrayList<>(); + fileData.add(List.of("Name", "DataFile", strField.getName(), intField.getName())); + fileData.add(List.of("Valid Entry", RESULT_FILENAME_1, "ABC", "123")); + fileData.add(List.of("Incompatible Data Type", RESULT_FILENAME_2, "DEF", "GHI")); + metadataFile = TestDataUtils.writeRowsToTsv("Invalid Data Type.tsv", fileData); + + log("Validate error condition when there is an invalid value (string for an int)."); + uploadWithErrorAction(errorAssay, + metadataFile, + "Invalid Data Type", + String.format("Int: Value 'GHI' for field '%s' is invalid. Value must be greater than 5.", intField.getName())); + + fileData = new ArrayList<>(); + fileData.add(List.of("Name", "DataFile", strField.getName(), intField.getName())); + fileData.add(List.of("Valid Entry Again", RESULT_FILENAME_1, "ABC", "123")); + fileData.add(List.of("Range Validation Error", RESULT_FILENAME_2, "DEF", "2")); + metadataFile = TestDataUtils.writeRowsToTsv("Range Validation Error.tsv", fileData); + + log("Validate error condition when field value fails range validation."); + uploadWithErrorAction(errorAssay, + metadataFile, + "Invalid Range", + String.format("Int: Value '2' for field '%s' is invalid. Value must be greater than 5.", intField.getName())); + + } + + private void uploadWithErrorAction(String assayName, + File metadataFile, + String runId, String expectedMsg) + { + + // If there is ever a desire to expand the error testing to include errors in the data files, then this list of + // data files should be identified in the test and passed in as a parameter. + List dataFiles = List.of( + getFile(String.join("/", ASSAY_DATA_LOC, RESULT_FILENAME_1)), + getFile(String.join("/", ASSAY_DATA_LOC, RESULT_FILENAME_2))); + + SignalDataUploadPage uploadPage = navigateToAssayLandingPage(assayName).navigateToImportPage(); + + log(String.format("Uploading metadata file: %s", metadataFile.getName())); + uploadPage.uploadMetadataFile(metadataFile); + + log("Uploading data files."); + int uploadCount = dataFiles.size(); + uploadPage.uploadFile(dataFiles); + uploadPage.waitForProgressBars(uploadCount); + + uploadPage.setRunIDField(runId); + Window dialog = uploadPage.saveRunExpectingError(getDriver()); + + String actualMsg = dialog.getBody(); + + if (checker().withScreenshot() + .verifyTrue(String.format("Error dialog message '%s' does not contain expected message: %s", actualMsg, expectedMsg), + actualMsg.contains(expectedMsg))) + { + dialog.clickButton("OK", true); + uploadPage.clearRun(); + } + + } + private SignalDataAssayBeginPage importRun( - String runName, - File metadataFile, - List unspecifiedDataFiles, - List dataFiles, - Map> expectedData, - int expectedResultRows + String assayName, + String runName, + File metadataFile, + List unspecifiedDataFiles, + List dataFiles, + Map> expectedData, + int expectedResultRows ) { - SignalDataAssayBeginPage beginPage = navigateToAssayLandingPage(); + SignalDataAssayBeginPage beginPage = navigateToAssayLandingPage(assayName); SignalDataUploadPage uploadPage = beginPage.navigateToImportPage(); log("Uploading metadata file"); @@ -236,11 +356,11 @@ private File getFile(String relativePath) return file; } - private SignalDataAssayBeginPage navigateToAssayLandingPage() + private SignalDataAssayBeginPage navigateToAssayLandingPage(String assayName) { //Navigate to Landing Page goToProjectHome(); - clickAndWait(Locator.linkWithText(SignalDataInitializer.RAW_SignalData_ASSAY)); + clickAndWait(Locator.linkWithText(assayName)); SignalDataAssayBeginPage page = new SignalDataAssayBeginPage(this); page.waitForPageLoad(); return page;