From 5b2416cd87b4536c2d51d1f167de6d0b29f09428 Mon Sep 17 00:00:00 2001 From: XingY Date: Wed, 20 Aug 2025 19:11:58 -0700 Subject: [PATCH 1/6] Selenium test --- src/org/labkey/test/BaseWebDriverTest.java | 8 ++++++++ src/org/labkey/test/util/AuditLogHelper.java | 7 +++++++ 2 files changed, 15 insertions(+) diff --git a/src/org/labkey/test/BaseWebDriverTest.java b/src/org/labkey/test/BaseWebDriverTest.java index 6b34832353..aff9ef103f 100644 --- a/src/org/labkey/test/BaseWebDriverTest.java +++ b/src/org/labkey/test/BaseWebDriverTest.java @@ -75,6 +75,7 @@ import org.labkey.test.util.AbstractContainerHelper; import org.labkey.test.util.ApiPermissionsHelper; import org.labkey.test.util.ArtifactCollector; +import org.labkey.test.util.AuditLogHelper; import org.labkey.test.util.ComponentQuery; import org.labkey.test.util.Crawler; import org.labkey.test.util.CspLogUtil; @@ -2743,14 +2744,21 @@ public void dismissReleaseBanner(String productName, boolean dismiss) } protected void verifyQueryAPI(String schema, String dataType, Map row, boolean isInsert, String... errorMsg) + { + verifyQueryAPI(schema, dataType, null, row, isInsert, errorMsg); + } + + protected void verifyQueryAPI(String schema, String dataType, @Nullable AuditLogHelper.AuditBehaviorType auditBehavior, Map row, boolean isInsert, String... errorMsg) { String action = isInsert ? "insertRows" : "updateRows"; String updateScript = "LABKEY.Query." + action + "({ schemaName: \"" + schema + "\", "+ "queryName: " + EscapeUtil.toJSONStr(dataType) + ", " + + (auditBehavior == null ? "" : "auditBehavior: " + EscapeUtil.toJSONStr(auditBehavior.name())) + ", " + "success: callback," + "failure: callback," + "rows: [" + EscapeUtil.toJSONRow(row) + "]" + "})"; + log(updateScript); executeAndVerifyScript(updateScript, errorMsg); } diff --git a/src/org/labkey/test/util/AuditLogHelper.java b/src/org/labkey/test/util/AuditLogHelper.java index a91b5c377f..3aa8b66606 100644 --- a/src/org/labkey/test/util/AuditLogHelper.java +++ b/src/org/labkey/test/util/AuditLogHelper.java @@ -67,6 +67,13 @@ public AuditLogHelper(WebDriverWrapper wrapper) this(wrapper, wrapper::createDefaultConnection); } + public enum AuditBehaviorType + { + NONE, + DETAILED, + SUMMARY; + } + public enum AuditEvent { SAMPLE_TIMELINE_EVENT("SampleTimelineEvent"), From 8d983f046424fb1ddde92d1ceadda2bb435dde09 Mon Sep 17 00:00:00 2001 From: XingY Date: Fri, 22 Aug 2025 15:07:32 -0700 Subject: [PATCH 2/6] Add selenium tests --- .../query/ImportExperimentDataCommand.java | 78 +++++++++++++++++++ src/org/labkey/test/BaseWebDriverTest.java | 2 +- src/org/labkey/test/util/AuditLogHelper.java | 41 ++++++++-- .../test/util/query/QueryApiHelper.java | 17 +++- 4 files changed, 131 insertions(+), 7 deletions(-) create mode 100644 src/org/labkey/remoteapi/query/ImportExperimentDataCommand.java diff --git a/src/org/labkey/remoteapi/query/ImportExperimentDataCommand.java b/src/org/labkey/remoteapi/query/ImportExperimentDataCommand.java new file mode 100644 index 0000000000..9b5ac8b915 --- /dev/null +++ b/src/org/labkey/remoteapi/query/ImportExperimentDataCommand.java @@ -0,0 +1,78 @@ +package org.labkey.remoteapi.query; + +import org.apache.hc.client5.http.classic.methods.HttpPost; +import org.labkey.test.WebTestHelper; +import org.labkey.test.util.AuditLogHelper; + +import java.net.URI; +import java.net.URISyntaxException; +import java.util.HashMap; +import java.util.Map; + +public class ImportExperimentDataCommand extends ImportDataCommand +{ + private AuditLogHelper.AuditBehaviorType _auditBehavior; + private Boolean _crossTypeImport; + private Boolean _crossFolderImport; + private String _containerPath; + + public ImportExperimentDataCommand(String schemaName, String queryName, String containerPath) + { + super(schemaName, queryName); + _containerPath = containerPath; + } + + public AuditLogHelper.AuditBehaviorType getAuditBehavior() + { + return _auditBehavior; + } + + public void setAuditBehavior(AuditLogHelper.AuditBehaviorType auditBehavior) + { + _auditBehavior = auditBehavior; + } + + public Boolean getCrossTypeImport() + { + return _crossTypeImport; + } + + public void setCrossTypeImport(Boolean crossTypeImport) + { + _crossTypeImport = crossTypeImport; + } + + public Boolean getCrossFolderImport() + { + return _crossFolderImport; + } + + public void setCrossFolderImport(Boolean crossFolderImport) + { + _crossFolderImport = crossFolderImport; + } + + @Override + protected HttpPost createRequest(URI uri) { + HttpPost post = super.createRequest(uri); + String action = "samples".equalsIgnoreCase(getSchemaName()) ? "importSamples" : "importData"; + Map params = new HashMap<>(); + if (_auditBehavior != null) + params.put("auditBehavior", _auditBehavior.name()); + if (_crossTypeImport) + params.put("crossTypeImport", "true"); + if (_crossFolderImport) + params.put("crossFolderImport", "true"); + String url = WebTestHelper.buildURL("experiment", _containerPath, action, params); + try + { + post.setUri(new URI(url)); + } + catch (URISyntaxException e) + { + throw new RuntimeException(e); + } + return post; + } + +} diff --git a/src/org/labkey/test/BaseWebDriverTest.java b/src/org/labkey/test/BaseWebDriverTest.java index aff9ef103f..8049ba917e 100644 --- a/src/org/labkey/test/BaseWebDriverTest.java +++ b/src/org/labkey/test/BaseWebDriverTest.java @@ -2753,7 +2753,7 @@ protected void verifyQueryAPI(String schema, String dataType, @Nullable AuditLog String action = isInsert ? "insertRows" : "updateRows"; String updateScript = "LABKEY.Query." + action + "({ schemaName: \"" + schema + "\", "+ "queryName: " + EscapeUtil.toJSONStr(dataType) + ", " + - (auditBehavior == null ? "" : "auditBehavior: " + EscapeUtil.toJSONStr(auditBehavior.name())) + ", " + + (auditBehavior == null ? "" : ("auditBehavior: " + EscapeUtil.toJSONStr(auditBehavior.name())) + ", ") + "success: callback," + "failure: callback," + "rows: [" + EscapeUtil.toJSONRow(row) + "]" + diff --git a/src/org/labkey/test/util/AuditLogHelper.java b/src/org/labkey/test/util/AuditLogHelper.java index 3aa8b66606..277485869b 100644 --- a/src/org/labkey/test/util/AuditLogHelper.java +++ b/src/org/labkey/test/util/AuditLogHelper.java @@ -53,6 +53,13 @@ public class AuditLogHelper "Comment" ); + public static final String SCHEMA_XML_AUDIT = "\n" + + " \n" + + " %s\n" + + "
\n" + + "
\n"; + + private final WebDriverWrapper _wrapper; private final ConnectionSupplier _connectionSupplier; @@ -81,6 +88,7 @@ public enum AuditEvent INVENTORY_AUDIT_EVENT("InventoryAuditEvent"), LIST_AUDIT_EVENT("ListAuditEvent"), ASSAY_AUDIT_EVENT("AssayAuditEvent"), // avaialble with SampleManagement module + ASSAY_RESULT_AUDIT_EVENT("AssayResultAuditEvent"), // avaialble with SampleManagement module EXPERIMENT_AUDIT_EVENT("ExperimentAuditEvent"), SAMPLE_WORKFLOW_AUDIT_EVENT("SamplesWorkflowAuditEvent"), FILE_SYSTEM_EVENT("FileSystem"); @@ -165,16 +173,30 @@ public SelectRowsResponse getAuditLogsFromLKS(String containerPath, AuditEvent a } public List> getAuditLogsForTransactionId(String containerPath, AuditEvent auditEventName, List columnNames, - Integer transactionId, @Nullable ContainerFilter containerFilter) throws IOException, CommandException + Integer transactionId, @Nullable ContainerFilter containerFilter) throws IOException, CommandException + { + return getAuditLogsForTransactionId(containerPath, auditEventName, columnNames, transactionId, null, containerFilter); + } + + public List> getAuditLogsForTransactionId(String containerPath, AuditEvent auditEventName, List columnNames, + Integer transactionId, List eventFilters, @Nullable ContainerFilter containerFilter) throws IOException, CommandException { - List transactionFilter = List.of(new Filter("TransactionId", transactionId, Filter.Operator.EQUAL)); + List transactionFilter = new ArrayList<>(); + transactionFilter.add(new Filter("TransactionId", transactionId, Filter.Operator.EQUAL)); + if (eventFilters != null && !eventFilters.isEmpty()) + transactionFilter.addAll(eventFilters); return getAuditLogsFromLKS(containerPath, auditEventName, columnNames, transactionFilter, null, containerFilter).getRows(); } public void checkAuditEventValuesForTransactionId(String containerPath, AuditEvent auditEventName, Integer transactionId, int rowCount, Map expectedValues) throws IOException, CommandException + { + checkAuditEventValuesForTransactionId(containerPath, auditEventName, transactionId, null, rowCount, expectedValues); + } + + public void checkAuditEventValuesForTransactionId(String containerPath, AuditEvent auditEventName, Integer transactionId, List eventFilters, int rowCount, Map expectedValues) throws IOException, CommandException { List columnNames = expectedValues.keySet().stream().map(Object::toString).toList(); - List> events = getAuditLogsForTransactionId(containerPath, auditEventName, columnNames, transactionId, ContainerFilter.CurrentAndSubfolders); + List> events = getAuditLogsForTransactionId(containerPath, auditEventName, columnNames, transactionId, eventFilters, ContainerFilter.CurrentAndSubfolders); assertEquals("Unexpected number of events for transactionId " + transactionId, rowCount, events.size()); for (int i = 0; i < rowCount; i++) { @@ -279,16 +301,25 @@ public Integer doAndWaitForTransaction(Runnable action, String containerPath, Au }, "Error waiting for next transactionId in " + auditEventName, WAIT_FOR_JAVASCRIPT); } + public Integer checkAuditEventDiffCountForLastTransaction(String containerPath, AuditEvent auditEventName, int expectedDiffCount, + @Nullable Integer expectedEventCount) throws IOException, CommandException + { + return checkAuditEventDiffCountForLastTransaction(containerPath, auditEventName, Collections.emptyList(), expectedDiffCount, expectedEventCount); + } + /** * Check for the expected number of diffs in the audit event for the last transactionId. * If an expectedEventCount is also provided, it will check that the number of events for that transactionId matches the expectedEventCount. * @return transactionId */ - public Integer checkAuditEventDiffCountForLastTransaction(String containerPath, AuditEvent auditEventName, int expectedDiffCount, + public Integer checkAuditEventDiffCountForLastTransaction(String containerPath, AuditEvent auditEventName, @Nullable List eventFilters, int expectedDiffCount, @Nullable Integer expectedEventCount) throws IOException, CommandException { Integer transactionId = getLastTransactionId(containerPath, auditEventName); - List transactionFilter = List.of(new Filter("TransactionId", transactionId, Filter.Operator.EQUAL)); + List transactionFilter = new ArrayList<>(); + transactionFilter.add(new Filter("TransactionId", transactionId, Filter.Operator.EQUAL)); + if (eventFilters != null && !eventFilters.isEmpty()) + transactionFilter.addAll(eventFilters); List> events = getAuditLogsFromLKS(containerPath, auditEventName, List.of("Comment", "UserComment", "NewRecordMap"), transactionFilter, null, ContainerFilter.CurrentAndSubfolders).getRows(); if (expectedEventCount != null) { diff --git a/src/org/labkey/test/util/query/QueryApiHelper.java b/src/org/labkey/test/util/query/QueryApiHelper.java index 36b967051b..2e0d3e63ef 100644 --- a/src/org/labkey/test/util/query/QueryApiHelper.java +++ b/src/org/labkey/test/util/query/QueryApiHelper.java @@ -12,6 +12,7 @@ import org.labkey.remoteapi.query.Filter; import org.labkey.remoteapi.query.ImportDataCommand; import org.labkey.remoteapi.query.ImportDataResponse; +import org.labkey.remoteapi.query.ImportExperimentDataCommand; import org.labkey.remoteapi.query.InsertRowsCommand; import org.labkey.remoteapi.query.MoveRowsCommand; import org.labkey.remoteapi.query.RowsResponse; @@ -21,6 +22,7 @@ import org.labkey.remoteapi.query.TruncateTableCommand; import org.labkey.remoteapi.query.TruncateTableResponse; import org.labkey.remoteapi.query.UpdateRowsCommand; +import org.labkey.test.util.AuditLogHelper; import java.io.File; import java.io.IOException; @@ -127,7 +129,20 @@ public ImportDataResponse importData(File file) throws IOException, CommandExcep ImportDataCommand importDataCommand = new ImportDataCommand(_schema, _query); importDataCommand.setFile(file); importDataCommand.setTimeout(_insertTimout); - return importDataCommand.execute(_connection, _containerPath); + return importDataCommand.execute(_connection, _containerPath); + } + + public ImportDataResponse importExperimentData(String text, AuditLogHelper.AuditBehaviorType auditBehaviorType, ImportDataCommand.InsertOption insertOption, boolean isCrossType, boolean isCrossFolder, boolean isAsync) throws IOException, CommandException + { + ImportExperimentDataCommand importDataCommand = new ImportExperimentDataCommand(_schema, _query, _containerPath); + importDataCommand.setAuditBehavior(auditBehaviorType); + importDataCommand.setUseAsync(isAsync); + importDataCommand.setCrossFolderImport(isCrossFolder); + importDataCommand.setCrossTypeImport(isCrossType); + importDataCommand.setText(text); + importDataCommand.setInsertOption(insertOption); + importDataCommand.setTimeout(_insertTimout); + return importDataCommand.execute(_connection, _containerPath); } /** From 039f4195211f78239499b4066205a06aa2e33c1e Mon Sep 17 00:00:00 2001 From: XingY Date: Sun, 24 Aug 2025 18:11:48 -0700 Subject: [PATCH 3/6] Selenium tests for sources --- src/org/labkey/test/BaseWebDriverTest.java | 14 ++++++ src/org/labkey/test/tests/AuditLogTest.java | 51 +++++++++++++++++++- src/org/labkey/test/util/AuditLogHelper.java | 1 + src/org/labkey/test/util/EscapeUtil.java | 13 +++++ 4 files changed, 78 insertions(+), 1 deletion(-) diff --git a/src/org/labkey/test/BaseWebDriverTest.java b/src/org/labkey/test/BaseWebDriverTest.java index 8049ba917e..ca319c26c4 100644 --- a/src/org/labkey/test/BaseWebDriverTest.java +++ b/src/org/labkey/test/BaseWebDriverTest.java @@ -2762,6 +2762,20 @@ protected void verifyQueryAPI(String schema, String dataType, @Nullable AuditLog executeAndVerifyScript(updateScript, errorMsg); } + protected void verifyQueryAPI(String schema, String dataType, @Nullable AuditLogHelper.AuditBehaviorType auditBehavior, List> rows, boolean isInsert, String... errorMsg) + { + String action = isInsert ? "insertRows" : "updateRows"; + String updateScript = "LABKEY.Query." + action + "({ schemaName: \"" + schema + "\", "+ + "queryName: " + EscapeUtil.toJSONStr(dataType) + ", " + + (auditBehavior == null ? "" : ("auditBehavior: " + EscapeUtil.toJSONStr(auditBehavior.name())) + ", ") + + "success: callback," + + "failure: callback," + + "rows: [" + EscapeUtil.toJSONRow(rows) + "]" + + "})"; + log(updateScript); + executeAndVerifyScript(updateScript, errorMsg); + } + protected void executeAndVerifyScript(String script, @Nullable String... altErrors) { List errors = new ArrayList<>(); diff --git a/src/org/labkey/test/tests/AuditLogTest.java b/src/org/labkey/test/tests/AuditLogTest.java index aa429db57f..0a75098570 100644 --- a/src/org/labkey/test/tests/AuditLogTest.java +++ b/src/org/labkey/test/tests/AuditLogTest.java @@ -23,6 +23,7 @@ import org.junit.experimental.categories.Category; import org.labkey.remoteapi.CommandException; import org.labkey.remoteapi.Connection; +import org.labkey.remoteapi.query.BaseRowsCommand; import org.labkey.remoteapi.query.InsertRowsCommand; import org.labkey.remoteapi.query.RowsResponse; import org.labkey.test.BaseWebDriverTest; @@ -428,7 +429,7 @@ public void testDetailedQueryUpdateAuditLog() throws IOException, CommandExcepti { _containerHelper.createProject(AUDIT_DETAILED_TEST_PROJECT, "Custom"); _containerHelper.enableModule("simpletest"); - goToProjectHome(); + goToProjectHome(AUDIT_DETAILED_TEST_PROJECT); Connection cn = WebTestHelper.getRemoteApiConnection(); @@ -439,9 +440,43 @@ public void testDetailedQueryUpdateAuditLog() throws IOException, CommandExcepti insertCmd.addRow(rowMap); RowsResponse resp1 = insertCmd.execute(cn, AUDIT_DETAILED_TEST_PROJECT); + Integer transactionId = _auditLogHelper.checkAuditEventDiffCountForLastTransaction(AUDIT_DETAILED_TEST_PROJECT, AuditLogHelper.AuditEvent.QUERY_UPDATE_AUDIT_EVENT, 0, 1); + Map expectedValues = new HashMap<>(); + expectedValues.put("Comment", "1 row(s) were inserted."); + _auditLogHelper.checkAuditEventValuesForTransactionId(AUDIT_DETAILED_TEST_PROJECT, AuditLogHelper.AuditEvent.QUERY_UPDATE_AUDIT_EVENT, transactionId, 1, expectedValues); + goToProjectHome(AUDIT_DETAILED_TEST_PROJECT); + Map auditLog = getAuditLogRow(this, "Query update events", "Query Name", "Manufacturers"); assertEquals("Did not find expected audit log for summary log level", "1 row(s) were inserted.", auditLog.get("Comment")); + // create manufacturer (which has summary audit log level) with api audit override to detail + insertCmd = new InsertRowsCommand("vehicle", "manufacturers"); + insertCmd.setAuditBehavior(BaseRowsCommand.AuditBehavior.DETAILED); + rowMap = new HashMap<>(); + rowMap.put("name", "Kia_ev"); + insertCmd.addRow(rowMap); + insertCmd.execute(cn, AUDIT_DETAILED_TEST_PROJECT); + + goToProjectHome(AUDIT_DETAILED_TEST_PROJECT); + transactionId = _auditLogHelper.checkAuditEventDiffCountForLastTransaction(AUDIT_DETAILED_TEST_PROJECT, AuditLogHelper.AuditEvent.QUERY_UPDATE_AUDIT_EVENT, 7, 1); + expectedValues = new HashMap<>(); + expectedValues.put("Comment", "A row was inserted."); + _auditLogHelper.checkAuditEventValuesForTransactionId(AUDIT_DETAILED_TEST_PROJECT, AuditLogHelper.AuditEvent.QUERY_UPDATE_AUDIT_EVENT, transactionId, 1, expectedValues); + + // create manufacturer (which has summary audit log level) with api audit override to NONE. The override should be ignored + insertCmd = new InsertRowsCommand("vehicle", "manufacturers"); + insertCmd.setAuditBehavior(BaseRowsCommand.AuditBehavior.NONE); + rowMap = new HashMap<>(); + rowMap.put("name", "Kia_hybrid"); + insertCmd.addRow(rowMap); + insertCmd.execute(cn, AUDIT_DETAILED_TEST_PROJECT); + + goToProjectHome(AUDIT_DETAILED_TEST_PROJECT); + transactionId = _auditLogHelper.checkAuditEventDiffCountForLastTransaction(AUDIT_DETAILED_TEST_PROJECT, AuditLogHelper.AuditEvent.QUERY_UPDATE_AUDIT_EVENT, 0, 1); + expectedValues = new HashMap<>(); + expectedValues.put("Comment", "1 row(s) were inserted."); + _auditLogHelper.checkAuditEventValuesForTransactionId(AUDIT_DETAILED_TEST_PROJECT, AuditLogHelper.AuditEvent.QUERY_UPDATE_AUDIT_EVENT, transactionId, 1, expectedValues); + //then create model (which has detailed audit log level) InsertRowsCommand insertCmd2 = new InsertRowsCommand("vehicle", "models"); rowMap = new HashMap<>(); @@ -453,6 +488,20 @@ public void testDetailedQueryUpdateAuditLog() throws IOException, CommandExcepti refresh(); auditLog = getAuditLogRow(this, "Query update events", "Query Name", "Models"); assertEquals("Did not find expected audit log for detailed log level", "A row was inserted.", auditLog.get("Comment")); + goToProjectHome(AUDIT_DETAILED_TEST_PROJECT); + + // create model (which has detailed audit log level), with API audit SUMMARY, effective audit should be detailed + rowMap.put("name", "Carnival"); + insertCmd2 = new InsertRowsCommand("vehicle", "models"); + insertCmd2.setAuditBehavior(BaseRowsCommand.AuditBehavior.SUMMARY); + insertCmd2.addRow(rowMap); + insertCmd2.execute(cn, AUDIT_DETAILED_TEST_PROJECT); + + transactionId = _auditLogHelper.checkAuditEventDiffCountForLastTransaction(AUDIT_DETAILED_TEST_PROJECT, AuditLogHelper.AuditEvent.QUERY_UPDATE_AUDIT_EVENT, 8, 1); + expectedValues = new HashMap<>(); + expectedValues.put("Comment", "A row was inserted."); + _auditLogHelper.checkAuditEventValuesForTransactionId(AUDIT_DETAILED_TEST_PROJECT, AuditLogHelper.AuditEvent.QUERY_UPDATE_AUDIT_EVENT, transactionId, 1, expectedValues); + _containerHelper.deleteProject(AUDIT_DETAILED_TEST_PROJECT, false); } else diff --git a/src/org/labkey/test/util/AuditLogHelper.java b/src/org/labkey/test/util/AuditLogHelper.java index 277485869b..44015ae52a 100644 --- a/src/org/labkey/test/util/AuditLogHelper.java +++ b/src/org/labkey/test/util/AuditLogHelper.java @@ -91,6 +91,7 @@ public enum AuditEvent ASSAY_RESULT_AUDIT_EVENT("AssayResultAuditEvent"), // avaialble with SampleManagement module EXPERIMENT_AUDIT_EVENT("ExperimentAuditEvent"), SAMPLE_WORKFLOW_AUDIT_EVENT("SamplesWorkflowAuditEvent"), + QUERY_UPDATE_AUDIT_EVENT("QueryUpdateAuditEvent"), FILE_SYSTEM_EVENT("FileSystem"); private final String _name; diff --git a/src/org/labkey/test/util/EscapeUtil.java b/src/org/labkey/test/util/EscapeUtil.java index ad88def79c..7870369cbd 100644 --- a/src/org/labkey/test/util/EscapeUtil.java +++ b/src/org/labkey/test/util/EscapeUtil.java @@ -77,6 +77,19 @@ static public String toJSONRow(Map row) return sb.toString(); } + static public String toJSONRow(List> rows) + { + StringBuilder sb = new StringBuilder(); + String sep = ""; + for (Map row : rows) + { + sb.append(sep).append(toJSONRow(row)); + sep = ","; + } + + return sb.toString(); + } + static public String jsString(String s) { if (s == null) From 55cdfede89b0f376ecf4ced6e8ea3a5cd992f089 Mon Sep 17 00:00:00 2001 From: XingY Date: Mon, 25 Aug 2025 20:07:06 -0700 Subject: [PATCH 4/6] add selenium test for ETL bulk load --- .../SProcModifiedSinceNoSourceMultiStep.xml | 2 +- .../ETLs/SourceToTarget2BulkLoad.xml | 15 +++++++++++++++ .../ETLs/SourceToTarget2NoBulkLoad.xml | 15 +++++++++++++++ modules/ETLtest/resources/schemas/etltest.xml | 1 + src/org/labkey/test/util/AuditLogHelper.java | 19 +++++++++++++++++-- 5 files changed, 49 insertions(+), 3 deletions(-) create mode 100644 modules/ETLtest/resources/ETLs/SourceToTarget2BulkLoad.xml create mode 100644 modules/ETLtest/resources/ETLs/SourceToTarget2NoBulkLoad.xml diff --git a/modules/ETLtest/resources/ETLs/SProcModifiedSinceNoSourceMultiStep.xml b/modules/ETLtest/resources/ETLs/SProcModifiedSinceNoSourceMultiStep.xml index 36fb4539f9..7e96eb0b9a 100644 --- a/modules/ETLtest/resources/ETLs/SProcModifiedSinceNoSourceMultiStep.xml +++ b/modules/ETLtest/resources/ETLs/SProcModifiedSinceNoSourceMultiStep.xml @@ -1,6 +1,6 @@ - Stored Proc Modified Since No Source Multi Step + Stored Proc Modified Since No Source Multi Step// Multi Step using Modified Since filter and SP with no SP source diff --git a/modules/ETLtest/resources/ETLs/SourceToTarget2BulkLoad.xml b/modules/ETLtest/resources/ETLs/SourceToTarget2BulkLoad.xml new file mode 100644 index 0000000000..6b906aec7b --- /dev/null +++ b/modules/ETLtest/resources/ETLs/SourceToTarget2BulkLoad.xml @@ -0,0 +1,15 @@ + + + Source to target2 bulk load + append rows from source to target, skip detailed auditing + + + Copy to target2 + + + + + + + + diff --git a/modules/ETLtest/resources/ETLs/SourceToTarget2NoBulkLoad.xml b/modules/ETLtest/resources/ETLs/SourceToTarget2NoBulkLoad.xml new file mode 100644 index 0000000000..78a3118667 --- /dev/null +++ b/modules/ETLtest/resources/ETLs/SourceToTarget2NoBulkLoad.xml @@ -0,0 +1,15 @@ + + + Source to target2 no bulk load + append rows from source to target, with detailed auditing + + + Copy to target2 no bulkLoad + + + + + + + + \ No newline at end of file diff --git a/modules/ETLtest/resources/schemas/etltest.xml b/modules/ETLtest/resources/schemas/etltest.xml index a8326e4947..1abc4f056e 100644 --- a/modules/ETLtest/resources/schemas/etltest.xml +++ b/modules/ETLtest/resources/schemas/etltest.xml @@ -27,6 +27,7 @@ + DETAILED diff --git a/src/org/labkey/test/util/AuditLogHelper.java b/src/org/labkey/test/util/AuditLogHelper.java index 44015ae52a..df89964688 100644 --- a/src/org/labkey/test/util/AuditLogHelper.java +++ b/src/org/labkey/test/util/AuditLogHelper.java @@ -183,7 +183,8 @@ public List> getAuditLogsForTransactionId(String containerPa Integer transactionId, List eventFilters, @Nullable ContainerFilter containerFilter) throws IOException, CommandException { List transactionFilter = new ArrayList<>(); - transactionFilter.add(new Filter("TransactionId", transactionId, Filter.Operator.EQUAL)); + if (transactionId != null) + transactionFilter.add(new Filter("TransactionId", transactionId, Filter.Operator.EQUAL)); if (eventFilters != null && !eventFilters.isEmpty()) transactionFilter.addAll(eventFilters); return getAuditLogsFromLKS(containerPath, auditEventName, columnNames, transactionFilter, null, containerFilter).getRows(); @@ -280,6 +281,19 @@ public Integer getLastTransactionId(String containerPath, AuditEvent auditEventN } } + public Integer getLastEventId(String containerPath, AuditEvent auditEventName) + { + try + { + List> events = getAuditLogsFromLKS(containerPath, auditEventName, List.of("RowId"), Collections.emptyList(), 1, ContainerFilter.CurrentAndSubfolders).getRows(); + return events.size() == 1 ? (Integer) events.get(0).get("RowId") : null; + } + catch (Exception e) + { + throw new RuntimeException(e); + } + } + public Integer doAndWaitForTransaction(Runnable action, String containerPath, AuditEvent auditEventName) { int prevTransactionId; @@ -318,7 +332,8 @@ public Integer checkAuditEventDiffCountForLastTransaction(String containerPath, { Integer transactionId = getLastTransactionId(containerPath, auditEventName); List transactionFilter = new ArrayList<>(); - transactionFilter.add(new Filter("TransactionId", transactionId, Filter.Operator.EQUAL)); + if (transactionId != null) + transactionFilter.add(new Filter("TransactionId", transactionId, Filter.Operator.EQUAL)); if (eventFilters != null && !eventFilters.isEmpty()) transactionFilter.addAll(eventFilters); List> events = getAuditLogsFromLKS(containerPath, auditEventName, List.of("Comment", "UserComment", "NewRecordMap"), transactionFilter, null, ContainerFilter.CurrentAndSubfolders).getRows(); From 2efc122a1c34f87fc556d6efd58fac979781b21e Mon Sep 17 00:00:00 2001 From: XingY Date: Thu, 28 Aug 2025 13:37:12 -0700 Subject: [PATCH 5/6] Add test for checking audit log after LKS insert --- src/org/labkey/test/tests/SampleTypeTest.java | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/org/labkey/test/tests/SampleTypeTest.java b/src/org/labkey/test/tests/SampleTypeTest.java index b25c892025..4962306eb9 100644 --- a/src/org/labkey/test/tests/SampleTypeTest.java +++ b/src/org/labkey/test/tests/SampleTypeTest.java @@ -53,6 +53,7 @@ import org.labkey.test.params.FieldInfo; import org.labkey.test.params.experiment.SampleTypeDefinition; import org.labkey.test.util.ApiPermissionsHelper; +import org.labkey.test.util.AuditLogHelper; import org.labkey.test.util.DataRegionExportHelper; import org.labkey.test.util.DataRegionTable; import org.labkey.test.util.EscapeUtil; @@ -296,7 +297,7 @@ public void testCustomProperties() // Issue 47280: LKSM: Trailing/Leading whitespace in Source name won't resolve when deriving samples @Test - public void testImportSamplesWithTrailingSpace() + public void testImportSamplesWithTrailingSpace() throws IOException, CommandException { final String sampleTypeName = "SampleTypeWithProvidedName"; final List fields = List.of( @@ -317,6 +318,12 @@ public void testImportSamplesWithTrailingSpace() Map fieldMap = Map.of("Name", " S-1 ", "StringCol", "Ess ", "IntCol", "1 "); sampleTypeHelper.insertRow(fieldMap); + AuditLogHelper auditLogHelper = new AuditLogHelper(this); + int transactionId = auditLogHelper.checkAuditEventDiffCountForLastTransaction(getProjectName(), AuditLogHelper.AuditEvent.SAMPLE_TIMELINE_EVENT, 21, 1); + MapexpectedValues = new HashMap<>(); + expectedValues.put("Comment", "Sample was registered."); + auditLogHelper.checkAuditEventValuesForTransactionId(getProjectName(), AuditLogHelper.AuditEvent.SAMPLE_TIMELINE_EVENT, transactionId, 1, expectedValues); + log("Verify values were saved are without trailing spaces"); sampleTypeHelper.verifyDataValues(Collections.singletonList(fieldMap)); From dfe255cb2f2913fe09a23bcf883f8b93859cde51 Mon Sep 17 00:00:00 2001 From: XingY Date: Thu, 28 Aug 2025 13:45:45 -0700 Subject: [PATCH 6/6] clean --- .../resources/ETLs/SProcModifiedSinceNoSourceMultiStep.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/ETLtest/resources/ETLs/SProcModifiedSinceNoSourceMultiStep.xml b/modules/ETLtest/resources/ETLs/SProcModifiedSinceNoSourceMultiStep.xml index 7e96eb0b9a..36fb4539f9 100644 --- a/modules/ETLtest/resources/ETLs/SProcModifiedSinceNoSourceMultiStep.xml +++ b/modules/ETLtest/resources/ETLs/SProcModifiedSinceNoSourceMultiStep.xml @@ -1,6 +1,6 @@ - Stored Proc Modified Since No Source Multi Step// + Stored Proc Modified Since No Source Multi Step Multi Step using Modified Since filter and SP with no SP source