From 125c11784aacb00d2ab30f8bc866bab076803dc3 Mon Sep 17 00:00:00 2001 From: labkey-jeckels Date: Wed, 11 Jun 2025 13:01:47 -0700 Subject: [PATCH 1/2] Add explicit test coverage for trigger script type conversion --- .../resources/queries/lists/People.js | 16 +++ .../labkey/test/tests/TriggerScriptTest.java | 98 +++++++++++++------ 2 files changed, 85 insertions(+), 29 deletions(-) diff --git a/modules/simpletest/resources/queries/lists/People.js b/modules/simpletest/resources/queries/lists/People.js index 65947bdcb2..e6eebe85b5 100644 --- a/modules/simpletest/resources/queries/lists/People.js +++ b/modules/simpletest/resources/queries/lists/People.js @@ -11,12 +11,26 @@ if (extraContext) var LABKEY = require("labkey"); +// Issue 52098 - do custom parsing to validate trigger script gets a chance to do type conversion +function stripPrefix(row) +{ + if (row.Age && row.Age.toString().indexOf("RemoveMe") === 0) + { + row.Age = row.Age.substring("RemoveMe".length); + } + if (row.FavoriteDateTime && row.FavoriteDateTime.toString().indexOf("RemoveMe") === 0) + { + row.FavoriteDateTime = row.FavoriteDateTime.substring("RemoveMe".length); + } +} + function beforeInsert(row, errors) { // Test row map is case-insensitive if (row.Name != row.nAmE) throw new Error("beforeInsert row properties must be case-insensitive."); + stripPrefix(row); // var result = LABKEY.Query.deleteRows({ // schemaName: "lists", @@ -42,6 +56,8 @@ function beforeUpdate(row, oldRow, errors) // Test oldRow map is case-insensitive if (oldRow.Name != oldRow.nAmE) throw new Error("beforeUpdate oldRow properties must be case-insensitive."); + + stripPrefix(row); } function afterUpdate(row, oldRow, errors) diff --git a/src/org/labkey/test/tests/TriggerScriptTest.java b/src/org/labkey/test/tests/TriggerScriptTest.java index 5aa8e7b6e7..baae17599f 100644 --- a/src/org/labkey/test/tests/TriggerScriptTest.java +++ b/src/org/labkey/test/tests/TriggerScriptTest.java @@ -86,6 +86,7 @@ public class TriggerScriptTest extends BaseWebDriverTest private static final String COMMENTS_FIELD = "Comments"; private static final String COUNTRY_FIELD = "Country"; + public static final String PEOPLE_LIST_NAME = "People"; protected final PortalHelper _portalHelper = new PortalHelper(this); @@ -171,37 +172,45 @@ public static void projectSetup() init.doSetup(); } - protected void doSetup() - { - _containerHelper.createProject(getProjectName(), null); - _containerHelper.enableModule(getProjectName(), "Query"); - _containerHelper.enableModule(getProjectName(), SIMPLE_MODULE); - _containerHelper.enableModule(getProjectName(), TRIGGER_MODULE); - - //create List - FieldDefinition[] columns = new FieldDefinition[] { - new FieldDefinition("name", ColumnType.String).setLabel("Name"), - new FieldDefinition("ssn", ColumnType.String).setLabel("SSN"), - new FieldDefinition("company", ColumnType.String).setLabel("Company") - - }; - - _listHelper.createList(getProjectName(), LIST_NAME, "Key", columns); - - log("Create list in subfolder to prevent query validation failure"); - _listHelper.createList(getProjectName(), "People", "Key", - new FieldDefinition("Name", ColumnType.String).setDescription("Name"), - new FieldDefinition("Age", ColumnType.Integer).setDescription("Age"), - new FieldDefinition("Crazy", ColumnType.Boolean).setDescription("Crazy?")); - importFolderFromZip(TestFileUtils.getSampleData("studies/LabkeyDemoStudy.zip")); - - //Add webparts for dataset, data class, sample type setup - goToProjectHome(); + @Override + protected void doCleanup(boolean afterTest) + { + // Hack to speed up repro + } - _portalHelper.addWebPart("Datasets"); - _portalHelper.addWebPart("Data Classes"); - _portalHelper.addWebPart("Sample Types"); + protected void doSetup() + { +// _containerHelper.createProject(getProjectName(), null); +// _containerHelper.enableModule(getProjectName(), "Query"); +// _containerHelper.enableModule(getProjectName(), SIMPLE_MODULE); +// _containerHelper.enableModule(getProjectName(), TRIGGER_MODULE); +// +// //create List +// FieldDefinition[] columns = new FieldDefinition[] { +// new FieldDefinition("name", ColumnType.String).setLabel("Name"), +// new FieldDefinition("ssn", ColumnType.String).setLabel("SSN"), +// new FieldDefinition("company", ColumnType.String).setLabel("Company") +// +// }; +// +// _listHelper.createList(getProjectName(), LIST_NAME, "Key", columns); +// +// log("Create the People list"); +// _listHelper.createList(getProjectName(), PEOPLE_LIST_NAME, "Key", +// new FieldDefinition("Name", ColumnType.String).setDescription("Name"), +// new FieldDefinition("Age", ColumnType.Integer).setDescription("Age"), +// new FieldDefinition("FavoriteDateTime", ColumnType.DateAndTime).setDescription("Favorite date time. Who doesn't have one?"), +// new FieldDefinition("Crazy", ColumnType.Boolean).setDescription("Crazy?")); +// +// importFolderFromZip(TestFileUtils.getSampleData("studies/LabkeyDemoStudy.zip")); +// +// //Add webparts for dataset, data class, sample type setup +// goToProjectHome(); +// +// _portalHelper.addWebPart("Datasets"); +// _portalHelper.addWebPart("Data Classes"); +// _portalHelper.addWebPart("Sample Types"); } @Before @@ -301,7 +310,38 @@ public void testListImportTriggers() cleanUpListRows(); } + /** Issue 52098 - ensure trigger scripts have a chance to do custom type conversion with the incoming row */ @Test + public void testListAPITriggerTypeConversion() throws Exception + { + Connection cn = WebTestHelper.getRemoteApiConnection(); + + // Insert a row with a value that can only be handled by the trigger script to make sure it gets a chance + // to do the conversion. People.js should strip the "RemoveMe" prefix from Age and FavoriteDateTime + InsertRowsCommand insCmd = new InsertRowsCommand(LIST_SCHEMA, PEOPLE_LIST_NAME); + insCmd.addRow(Map.of("Name", "Jimbo", "Age", "RemoveMe25", "FavoriteDateTime", "RemoveMe2025-06-11 11:42", "Crazy", "true")); + SaveRowsResponse insResp = insCmd.execute(cn, getProjectName()); + List> insertedRows = insResp.getRows(); + Assert.assertEquals(1, insertedRows.size()); + + Map insertedRow = insertedRows.get(0); + Assert.assertEquals("Jimbo", insertedRow.get("Name")); + Assert.assertEquals(25, insertedRow.get("Age")); + Assert.assertEquals("2025-06-11 11:42:00.000", insertedRow.get("FavoriteDateTime")); + + // Validate update too + UpdateRowsCommand upCmd = new UpdateRowsCommand(LIST_SCHEMA, PEOPLE_LIST_NAME); + insertedRow.put("Age", "RemoveMe26"); + upCmd.addRow(insertedRow); + SaveRowsResponse upResp = upCmd.execute(cn, getProjectName()); + List> updatedRows = upResp.getRows(); + Assert.assertEquals(1, updatedRows.size()); + + Map updatedRow = updatedRows.get(0); + Assert.assertEquals(26, updatedRow.get("Age")); + } + + @Test public void testListAPITriggers() throws Exception { String ssn1 = "111111112"; From 34bbe9386b0a07572a3487a712f18530194afe12 Mon Sep 17 00:00:00 2001 From: labkey-jeckels Date: Wed, 11 Jun 2025 14:11:41 -0700 Subject: [PATCH 2/2] Restore setup/teardown --- .../labkey/test/tests/TriggerScriptTest.java | 66 +++++++++---------- 1 file changed, 30 insertions(+), 36 deletions(-) diff --git a/src/org/labkey/test/tests/TriggerScriptTest.java b/src/org/labkey/test/tests/TriggerScriptTest.java index baae17599f..0edf072083 100644 --- a/src/org/labkey/test/tests/TriggerScriptTest.java +++ b/src/org/labkey/test/tests/TriggerScriptTest.java @@ -173,44 +173,38 @@ public static void projectSetup() } - @Override - protected void doCleanup(boolean afterTest) - { - // Hack to speed up repro - } - protected void doSetup() { -// _containerHelper.createProject(getProjectName(), null); -// _containerHelper.enableModule(getProjectName(), "Query"); -// _containerHelper.enableModule(getProjectName(), SIMPLE_MODULE); -// _containerHelper.enableModule(getProjectName(), TRIGGER_MODULE); -// -// //create List -// FieldDefinition[] columns = new FieldDefinition[] { -// new FieldDefinition("name", ColumnType.String).setLabel("Name"), -// new FieldDefinition("ssn", ColumnType.String).setLabel("SSN"), -// new FieldDefinition("company", ColumnType.String).setLabel("Company") -// -// }; -// -// _listHelper.createList(getProjectName(), LIST_NAME, "Key", columns); -// -// log("Create the People list"); -// _listHelper.createList(getProjectName(), PEOPLE_LIST_NAME, "Key", -// new FieldDefinition("Name", ColumnType.String).setDescription("Name"), -// new FieldDefinition("Age", ColumnType.Integer).setDescription("Age"), -// new FieldDefinition("FavoriteDateTime", ColumnType.DateAndTime).setDescription("Favorite date time. Who doesn't have one?"), -// new FieldDefinition("Crazy", ColumnType.Boolean).setDescription("Crazy?")); -// -// importFolderFromZip(TestFileUtils.getSampleData("studies/LabkeyDemoStudy.zip")); -// -// //Add webparts for dataset, data class, sample type setup -// goToProjectHome(); -// -// _portalHelper.addWebPart("Datasets"); -// _portalHelper.addWebPart("Data Classes"); -// _portalHelper.addWebPart("Sample Types"); + _containerHelper.createProject(getProjectName(), null); + _containerHelper.enableModule(getProjectName(), "Query"); + _containerHelper.enableModule(getProjectName(), SIMPLE_MODULE); + _containerHelper.enableModule(getProjectName(), TRIGGER_MODULE); + + //create List + FieldDefinition[] columns = new FieldDefinition[] { + new FieldDefinition("name", ColumnType.String).setLabel("Name"), + new FieldDefinition("ssn", ColumnType.String).setLabel("SSN"), + new FieldDefinition("company", ColumnType.String).setLabel("Company") + + }; + + _listHelper.createList(getProjectName(), LIST_NAME, "Key", columns); + + log("Create the People list"); + _listHelper.createList(getProjectName(), PEOPLE_LIST_NAME, "Key", + new FieldDefinition("Name", ColumnType.String).setDescription("Name"), + new FieldDefinition("Age", ColumnType.Integer).setDescription("Age"), + new FieldDefinition("FavoriteDateTime", ColumnType.DateAndTime).setDescription("Favorite date time. Who doesn't have one?"), + new FieldDefinition("Crazy", ColumnType.Boolean).setDescription("Crazy?")); + + importFolderFromZip(TestFileUtils.getSampleData("studies/LabkeyDemoStudy.zip")); + + //Add webparts for dataset, data class, sample type setup + goToProjectHome(); + + _portalHelper.addWebPart("Datasets"); + _portalHelper.addWebPart("Data Classes"); + _portalHelper.addWebPart("Sample Types"); } @Before