From 68c6eb38202436bbf88d29a236ab6844fa0c233b Mon Sep 17 00:00:00 2001 From: labkey-nicka Date: Fri, 19 Sep 2025 13:58:23 -0700 Subject: [PATCH 1/5] Initial tests --- src/org/labkey/test/util/AuditLogHelper.java | 50 +++++++++++++++----- 1 file changed, 37 insertions(+), 13 deletions(-) diff --git a/src/org/labkey/test/util/AuditLogHelper.java b/src/org/labkey/test/util/AuditLogHelper.java index 73be97476f..b776b1de29 100644 --- a/src/org/labkey/test/util/AuditLogHelper.java +++ b/src/org/labkey/test/util/AuditLogHelper.java @@ -4,6 +4,7 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.json.JSONException; +import org.labkey.api.collections.CaseInsensitiveHashMap; import org.labkey.remoteapi.CommandException; import org.labkey.remoteapi.Connection; import org.labkey.remoteapi.query.ContainerFilter; @@ -29,10 +30,10 @@ import java.util.Map; import java.util.Objects; import java.util.Set; -import java.util.stream.Stream; import static java.lang.Integer.parseInt; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import static org.labkey.test.WebDriverWrapper.WAIT_FOR_JAVASCRIPT; @@ -85,16 +86,19 @@ public enum AuditBehaviorType public enum AuditEvent { - SAMPLE_TIMELINE_EVENT("SampleTimelineEvent"), - SOURCES_AUDIT_EVENT("SourcesAuditEvent"), // avaialble with SampleManagement module + ASSAY_AUDIT_EVENT("AssayAuditEvent"), // available with SampleManagement module + ASSAY_RESULT_AUDIT_EVENT("AssayResultAuditEvent"), // available with SampleManagement module + EXPERIMENT_AUDIT_EVENT("ExperimentAuditEvent"), + FILE_SYSTEM_EVENT("FileSystem"), 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"), + PLATE_AUDIT_EVENT("PlateAuditEvent"), // available in Biologics module + PLATE_DATA_AUDIT_EVENT("PlateDataAuditEvent"), // available in Biologics module + PLATE_SET_AUDIT_EVENT("PlateSetAuditEvent"), // available in Biologics module QUERY_UPDATE_AUDIT_EVENT("QueryUpdateAuditEvent"), - FILE_SYSTEM_EVENT("FileSystem"); + SAMPLE_TIMELINE_EVENT("SampleTimelineEvent"), + SAMPLE_WORKFLOW_AUDIT_EVENT("SamplesWorkflowAuditEvent"), + SOURCES_AUDIT_EVENT("SourcesAuditEvent"); // available with SampleManagement module private final String _name; @@ -257,16 +261,16 @@ public void checkAuditEventDiffCount(String containerPath, AuditEvent auditEvent boolean isInventoryUpdateType = event.get("InventoryUpdateType") != null; int expectedDiffCount = isInventoryUpdateType ? 0 : expectedDiffCounts.get(i); String dataChangesStr = (String) event.get(eventDiffFieldName); - String[] dataChanges = dataChangesStr != null ? dataChangesStr.split("&") : new String[0]; + Map dataChanges = decodeValues(dataChangesStr); // filter out SampleStateLabel as that is not a change, it is added for display purposes - dataChanges = Stream.of(dataChanges).filter(s -> !s.toLowerCase().startsWith("samplestatelabel=")).toArray(String[]::new); + dataChanges.remove("SampleStateLabel"); // filter out RowId as that is not a change, it is added for display purposes - dataChanges = Stream.of(dataChanges).filter(s -> !s.toLowerCase().startsWith("rowid=")).toArray(String[]::new); + dataChanges.remove("RowId"); log("Audit record data changes diff count check (" + eventDiffFieldName + "): " + dataChangesStr); - assertEquals("Audit record data changes did not include the expected number of diffs in " + eventDiffFieldName + ", expected " + expectedDiffCount + " but was " + dataChanges.length + ": " + dataChangesStr, - expectedDiffCount, dataChanges.length); + assertEquals("Audit record data changes did not include the expected number of diffs in " + eventDiffFieldName + ", expected " + expectedDiffCount + " but was " + dataChanges.size() + ": " + dataChangesStr, + expectedDiffCount, dataChanges.size()); } } @@ -527,6 +531,26 @@ public String getLogString() } } + public static Map decodeValues(String recordMapString) + { + if (recordMapString == null || recordMapString.isEmpty()) + return Collections.emptyMap(); + + Map recordMap = new CaseInsensitiveHashMap<>(); + for (String part : recordMapString.split("&")) + { + String[] keyValue = part.split("="); + assertEquals("Audit record map string does not have expected shape", 2, keyValue.length); + + String key = EscapeUtil.decode(keyValue[0]); + assertFalse(String.format("Audit record map already contains key for %s", key), recordMap.containsKey(key)); + + recordMap.put(key, EscapeUtil.decode(keyValue[1])); + } + + return recordMap; + } + /** * URL-encode fields and values for {@link DetailedAuditEventRow#newValues} or {@link DetailedAuditEventRow#oldValues} * @param pairs alternating field names and their associated values From 5c0f48a7c1c36488879826b255a5c6fcaedba882 Mon Sep 17 00:00:00 2001 From: labkey-nicka Date: Sun, 21 Sep 2025 12:45:06 -0700 Subject: [PATCH 2/5] Relax constraint --- src/org/labkey/test/util/AuditLogHelper.java | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/org/labkey/test/util/AuditLogHelper.java b/src/org/labkey/test/util/AuditLogHelper.java index b776b1de29..1631650969 100644 --- a/src/org/labkey/test/util/AuditLogHelper.java +++ b/src/org/labkey/test/util/AuditLogHelper.java @@ -540,12 +540,10 @@ public static Map decodeValues(String recordMapString) for (String part : recordMapString.split("&")) { String[] keyValue = part.split("="); - assertEquals("Audit record map string does not have expected shape", 2, keyValue.length); - String key = EscapeUtil.decode(keyValue[0]); assertFalse(String.format("Audit record map already contains key for %s", key), recordMap.containsKey(key)); - recordMap.put(key, EscapeUtil.decode(keyValue[1])); + recordMap.put(key, keyValue.length > 1 ? EscapeUtil.decode(keyValue[1]) : null); } return recordMap; From 7dc94b99ca27ba1ea94f124f58479e0675c59eda Mon Sep 17 00:00:00 2001 From: labkey-nicka Date: Sun, 21 Sep 2025 13:28:40 -0700 Subject: [PATCH 3/5] Additional tests --- src/org/labkey/test/util/AuditLogHelper.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/org/labkey/test/util/AuditLogHelper.java b/src/org/labkey/test/util/AuditLogHelper.java index 1631650969..d37c0f23e7 100644 --- a/src/org/labkey/test/util/AuditLogHelper.java +++ b/src/org/labkey/test/util/AuditLogHelper.java @@ -92,9 +92,9 @@ public enum AuditEvent FILE_SYSTEM_EVENT("FileSystem"), INVENTORY_AUDIT_EVENT("InventoryAuditEvent"), LIST_AUDIT_EVENT("ListAuditEvent"), - PLATE_AUDIT_EVENT("PlateAuditEvent"), // available in Biologics module + PLATE_AUDIT_EVENT("PlateEvent"), // available in Biologics module PLATE_DATA_AUDIT_EVENT("PlateDataAuditEvent"), // available in Biologics module - PLATE_SET_AUDIT_EVENT("PlateSetAuditEvent"), // available in Biologics module + PLATE_SET_AUDIT_EVENT("PlateSetEvent"), // available in Biologics module QUERY_UPDATE_AUDIT_EVENT("QueryUpdateAuditEvent"), SAMPLE_TIMELINE_EVENT("SampleTimelineEvent"), SAMPLE_WORKFLOW_AUDIT_EVENT("SamplesWorkflowAuditEvent"), From 4ceea9c40a621e8f72fb94437b2080ee83fafce6 Mon Sep 17 00:00:00 2001 From: labkey-nicka Date: Mon, 22 Sep 2025 12:53:40 -0700 Subject: [PATCH 4/5] Test plate set events --- .../labkey/remoteapi/plate/PlateParams.java | 35 +++++++++++++++---- .../remoteapi/plate/PlateSetParams.java | 30 ++++++++++++++++ 2 files changed, 59 insertions(+), 6 deletions(-) diff --git a/src/org/labkey/remoteapi/plate/PlateParams.java b/src/org/labkey/remoteapi/plate/PlateParams.java index f68788cd88..b158a5b21e 100644 --- a/src/org/labkey/remoteapi/plate/PlateParams.java +++ b/src/org/labkey/remoteapi/plate/PlateParams.java @@ -2,20 +2,25 @@ import org.json.JSONObject; +import java.util.Map; + public class PlateParams { + private boolean _archived; + private String _assayType; + private int _columns; + private String _description; private String _name; private String _plateId; - private int _rowId; private int _plateSetId; - private String _description; - private int _rows; - private int _columns; private int _plateType; - private String _assayType; + private int _rowId; + private int _rows; private boolean _template; - private boolean _archived; + private PlateParams() + { + } public PlateParams(JSONObject json) { @@ -47,6 +52,24 @@ public PlateParams(JSONObject json) _archived = json.getBoolean("archived"); } + public static PlateParams fromQueryRow(Map row) + { + var params = new PlateParams(); + params._archived = (Boolean) row.get("Archived"); + params._assayType = (String) row.get("AssayType"); + params._columns = (Integer) row.get("PlateType/Columns"); + params._description = (String) row.get("Description"); + params._name = (String) row.get("Name"); + params._plateId = (String) row.get("PlateId"); + params._plateSetId = (Integer) row.get("PlateSet"); + params._plateType = (Integer) row.get("PlateType"); + params._rowId = (Integer) row.get("RowId"); + params._rows = (Integer) row.get("PlateType/Rows"); + params._template = (Boolean) row.get("Template"); + + return params; + } + public String getName() { return _name; diff --git a/src/org/labkey/remoteapi/plate/PlateSetParams.java b/src/org/labkey/remoteapi/plate/PlateSetParams.java index a6d4e0da96..e9e1c05873 100644 --- a/src/org/labkey/remoteapi/plate/PlateSetParams.java +++ b/src/org/labkey/remoteapi/plate/PlateSetParams.java @@ -2,6 +2,9 @@ import org.json.JSONObject; +import java.util.Date; +import java.util.Map; + public class PlateSetParams { private boolean _archived; @@ -22,6 +25,10 @@ public class PlateSetParams private boolean _template; private CreatePlateSetParams.PlateSetType _plateSetType; + private PlateSetParams() + { + } + public PlateSetParams(JSONObject json) { if (json.has("archived")) @@ -58,6 +65,29 @@ public PlateSetParams(JSONObject json) _plateSetType = CreatePlateSetParams.PlateSetType.fromName(json.getString("type")); } + public static PlateSetParams fromQueryRow(Map row) + { + var params = new PlateSetParams(); + params._containerId = (String) row.get("Folder/EntityId"); + params._containerName = (String) row.get("Folder/Name"); + params._containerPath = (String) row.get("Folder/Path"); + params._created = row.get("Created").toString(); + params._createdBy = (Integer) row.get("CreatedBy"); + params._description = (String) row.get("Description"); + params._modified = row.get("Modified").toString(); + params._modifiedBy = (Integer) row.get("ModifiedBy"); + params._name = (String) row.get("Name"); + params._plateCount = (Integer) row.get("PlateCount"); + params._plateSetId = (String) row.get("PlateSetId"); + params._plateSetType = CreatePlateSetParams.PlateSetType.fromName((String) row.get("Type")); + params._primaryPlateSetId = (Integer) row.get("PrimaryPlateSetId"); + params._rootPlateSetId = (Integer) row.get("RootPlateSetId"); + params._rowId = (Integer) row.get("RowId"); + params._template = (Boolean) row.get("Template"); + + return params; + } + public boolean getArchived() { return _archived; From 205f1175ae142706b41aa1f268ba787cde2add3f Mon Sep 17 00:00:00 2001 From: labkey-nicka Date: Fri, 26 Sep 2025 13:04:02 -0700 Subject: [PATCH 5/5] Additional tests --- src/org/labkey/remoteapi/plate/PlateParams.java | 13 +++++++++++++ src/org/labkey/remoteapi/plate/PlateSetParams.java | 4 +++- src/org/labkey/test/LabKeySiteWrapper.java | 10 +++++----- 3 files changed, 21 insertions(+), 6 deletions(-) diff --git a/src/org/labkey/remoteapi/plate/PlateParams.java b/src/org/labkey/remoteapi/plate/PlateParams.java index b158a5b21e..2d7060574f 100644 --- a/src/org/labkey/remoteapi/plate/PlateParams.java +++ b/src/org/labkey/remoteapi/plate/PlateParams.java @@ -2,12 +2,14 @@ import org.json.JSONObject; +import java.util.List; import java.util.Map; public class PlateParams { private boolean _archived; private String _assayType; + private String _barcode; private int _columns; private String _description; private String _name; @@ -50,13 +52,19 @@ public PlateParams(JSONObject json) if (json.has("archived")) _archived = json.getBoolean("archived"); + + if (json.has("barcode")) + _barcode = json.getString("barcode"); } + public static final List QUERY_COLUMNS = List.of("Archived", "AssayType", "Barcode", "Description", "Name", "PlateId", "PlateSet", "PlateType", "PlateType/Columns", "PlateType/Rows", "RowId", "Template"); + public static PlateParams fromQueryRow(Map row) { var params = new PlateParams(); params._archived = (Boolean) row.get("Archived"); params._assayType = (String) row.get("AssayType"); + params._barcode = (String) row.get("Barcode"); params._columns = (Integer) row.get("PlateType/Columns"); params._description = (String) row.get("Description"); params._name = (String) row.get("Name"); @@ -70,6 +78,11 @@ public static PlateParams fromQueryRow(Map row) return params; } + public String getBarcode() + { + return _barcode; + } + public String getName() { return _name; diff --git a/src/org/labkey/remoteapi/plate/PlateSetParams.java b/src/org/labkey/remoteapi/plate/PlateSetParams.java index e9e1c05873..e95120d6ce 100644 --- a/src/org/labkey/remoteapi/plate/PlateSetParams.java +++ b/src/org/labkey/remoteapi/plate/PlateSetParams.java @@ -2,7 +2,7 @@ import org.json.JSONObject; -import java.util.Date; +import java.util.List; import java.util.Map; public class PlateSetParams @@ -65,6 +65,8 @@ public PlateSetParams(JSONObject json) _plateSetType = CreatePlateSetParams.PlateSetType.fromName(json.getString("type")); } + public static final List QUERY_COLUMNS = List.of("Archived", "Created", "CreatedBy", "Description", "Folder/EntityId", "Folder/Name", "Folder/Path", "Modified", "ModifiedBy", "Name", "PlateCount", "PlateSetId", "PrimaryPlateSetId", "RootPlateSetId", "RowId", "Template", "Type"); + public static PlateSetParams fromQueryRow(Map row) { var params = new PlateSetParams(); diff --git a/src/org/labkey/test/LabKeySiteWrapper.java b/src/org/labkey/test/LabKeySiteWrapper.java index e669f9f4bf..2abd3f59fc 100644 --- a/src/org/labkey/test/LabKeySiteWrapper.java +++ b/src/org/labkey/test/LabKeySiteWrapper.java @@ -1530,7 +1530,6 @@ protected SelectRowsResponse executeSelectRowCommand(String schemaName, String q protected SelectRowsResponse executeSelectRowCommand(String schemaName, String queryName, ContainerFilter containerFilter, String path, @Nullable List filters, @Nullable List requestedColumns) { - Connection cn = createDefaultConnection(); SelectRowsCommand selectCmd = new SelectRowsCommand(schemaName, queryName); selectCmd.setMaxRows(-1); selectCmd.setContainerFilter(containerFilter); @@ -1538,18 +1537,19 @@ protected SelectRowsResponse executeSelectRowCommand(String schemaName, String q if (filters != null) selectCmd.setFilters(filters); - SelectRowsResponse selectResp; + return executeSelectRowCommand(path, selectCmd); + } + protected SelectRowsResponse executeSelectRowCommand(String containerPath, SelectRowsCommand command) + { try { - selectResp = selectCmd.execute(cn, path); + return command.execute(createDefaultConnection(), containerPath); } catch (CommandException | IOException e) { throw new RuntimeException(e); } - - return selectResp; } // Returns the text contents of every "Status" cell in the pipeline StatusFiles grid