diff --git a/src/org/labkey/test/components/bootstrap/ModalDialog.java b/src/org/labkey/test/components/bootstrap/ModalDialog.java index a4cf5d5b2d..2afdb12439 100644 --- a/src/org/labkey/test/components/bootstrap/ModalDialog.java +++ b/src/org/labkey/test/components/bootstrap/ModalDialog.java @@ -26,6 +26,8 @@ import org.openqa.selenium.support.ui.WebDriverWait; import java.time.Duration; +import java.util.regex.Matcher; +import java.util.regex.Pattern; import static org.labkey.test.WebDriverWrapper.WAIT_FOR_JAVASCRIPT; @@ -84,6 +86,25 @@ public String getBodyText() return elementCache().body.getText(); } + public Integer getCountFromTitle() + { + Pattern pattern = Pattern.compile("(\\d+)"); + Matcher matcher = pattern.matcher(getTitle()); + if (matcher.find()) + { + try + { + return Integer.parseInt(matcher.group(1).trim()); + } + catch (NumberFormatException e) + { + // If we can't parse the number, return null + return null; + } + } + return null; + } + public void close() { elementCache().closeButton.click(); diff --git a/src/org/labkey/test/components/ui/DeleteConfirmationDialog.java b/src/org/labkey/test/components/ui/DeleteConfirmationDialog.java index b63cf27c4d..b2e62029bc 100644 --- a/src/org/labkey/test/components/ui/DeleteConfirmationDialog.java +++ b/src/org/labkey/test/components/ui/DeleteConfirmationDialog.java @@ -1,21 +1,27 @@ package org.labkey.test.components.ui; import org.jetbrains.annotations.NotNull; +import org.labkey.remoteapi.CommandException; import org.labkey.test.BootstrapLocators; import org.labkey.test.Locator; +import org.labkey.test.TestProperties; import org.labkey.test.WebDriverWrapper; +import org.labkey.test.WebTestHelper; import org.labkey.test.components.UpdatingComponent; import org.labkey.test.components.bootstrap.ModalDialog; import org.labkey.test.components.html.Input; +import org.labkey.test.util.AuditLogHelper; import org.openqa.selenium.WebElement; import org.openqa.selenium.support.ui.ExpectedConditions; +import java.io.IOException; import java.util.function.Function; import java.util.function.Supplier; public class DeleteConfirmationDialog extends ModalDialog { private final Function _confirmationSynchronizationFunction; + private boolean skipAuditEventCheck = false; public DeleteConfirmationDialog(@NotNull WebDriverWrapper sourcePage, Supplier confirmPageSupplier) { @@ -68,6 +74,12 @@ protected void waitForReady() "The delete confirmation dialog did not become ready.", 1_000); } + public DeleteConfirmationDialog setSkipAuditEventCheck(boolean skipAuditEventCheck) + { + this.skipAuditEventCheck = skipAuditEventCheck; + return this; + } + public void cancelDelete() { this.dismiss("Cancel"); @@ -80,7 +92,33 @@ public ConfirmPage confirmDelete() public ConfirmPage confirmDelete(Integer waitSeconds) { - return _confirmationSynchronizationFunction.apply(() -> this.dismiss("Yes, Delete", waitSeconds)); + Integer count = getCountFromTitle(); + AuditLogHelper.AuditEvent auditEventName = getAuditEvent(); + + var confirmPage = _confirmationSynchronizationFunction.apply(() -> this.dismiss("Yes, Delete", waitSeconds)); + + if (!skipAuditEventCheck && count != null && auditEventName != null && !TestProperties.isTrialServer()) + verifyAuditEvents(getWrapper(), getWrapper().getCurrentProject(), auditEventName, count); + + return confirmPage; + } + + public AuditLogHelper.AuditEvent getAuditEvent() + { + return new AuditLogHelper(getWrapper()).getAuditEventNameFromURL(); + } + + public static void verifyAuditEvents(WebDriverWrapper wrapper, String containerPath, AuditLogHelper.AuditEvent auditEventName, int entityCount) + { + try + { + AuditLogHelper auditLogHelper = new AuditLogHelper(wrapper, () -> WebTestHelper.getRemoteApiConnection(false)); + auditLogHelper.checkAuditEventDiffCountForLastTransaction(containerPath, auditEventName, 0, entityCount); + } + catch (CommandException | IOException e) + { + throw new RuntimeException(e); + } } public Boolean isDeleteEnabled() diff --git a/src/org/labkey/test/components/ui/entities/EntityBulkUpdateDialog.java b/src/org/labkey/test/components/ui/entities/EntityBulkUpdateDialog.java index 289c1e7007..a5300dca78 100644 --- a/src/org/labkey/test/components/ui/entities/EntityBulkUpdateDialog.java +++ b/src/org/labkey/test/components/ui/entities/EntityBulkUpdateDialog.java @@ -350,25 +350,6 @@ public EntityBulkUpdateDialog clearActionComment() return this; } - public Integer getCountFromTitle() - { - // expecting title to be like "Update N items" - String title = getTitle(); - String[] parts = title.split(" "); - if (parts.length > 1) - { - try - { - return Integer.parseInt(parts[1]); - } - catch (NumberFormatException nfe) - { - return null; - } - } - return null; - } - // dismiss the dialog public String clickUpdateExpectingError() @@ -395,7 +376,7 @@ public void clickUpdate(boolean skipAuditEventCheck) // check for the expected number of Data Changes in the latest audit event records AuditLogHelper auditLogHelper = new AuditLogHelper(getWrapper(), () -> WebTestHelper.getRemoteApiConnection(false)); - String auditEventName = auditLogHelper.getAuditEventNameFromURL(); + AuditLogHelper.AuditEvent auditEventName = auditLogHelper.getAuditEventNameFromURL(); if (!skipAuditEventCheck && auditEventName != null && !TestProperties.isTrialServer()) { try diff --git a/src/org/labkey/test/components/ui/grids/DetailTableEdit.java b/src/org/labkey/test/components/ui/grids/DetailTableEdit.java index ec4f0fa610..f153ac42df 100644 --- a/src/org/labkey/test/components/ui/grids/DetailTableEdit.java +++ b/src/org/labkey/test/components/ui/grids/DetailTableEdit.java @@ -511,7 +511,7 @@ public DetailDataPanel clickSave(boolean skipAuditEventCheck) // check for the expected number of Data Changes in the latest audit event records AuditLogHelper auditLogHelper = new AuditLogHelper(getWrapper(), () -> WebTestHelper.getRemoteApiConnection(false)); - String auditEventName = auditLogHelper.getAuditEventNameFromURL(); + AuditLogHelper.AuditEvent auditEventName = auditLogHelper.getAuditEventNameFromURL(); if (!skipAuditEventCheck && auditEventName != null && !TestProperties.isTrialServer()) { try diff --git a/src/org/labkey/test/util/AuditLogHelper.java b/src/org/labkey/test/util/AuditLogHelper.java index 0f0d8f7b57..8914ff5190 100644 --- a/src/org/labkey/test/util/AuditLogHelper.java +++ b/src/org/labkey/test/util/AuditLogHelper.java @@ -50,6 +50,28 @@ public AuditLogHelper(WebDriverWrapper wrapper) this(wrapper, wrapper::createDefaultConnection); } + public enum AuditEvent + { + SAMPLE_TIMELINE_EVENT("SampleTimelineEvent"), + SOURCES_AUDIT_EVENT("SourcesAuditEvent"), + INVENTORY_AUDIT_EVENT("InventoryAuditEvent"), + LIST_AUDIT_EVENT("ListAuditEvent"), + EXPERIMENT_AUDIT_EVENT("ExperimentAuditEvent"), + SAMPLE_WORKFLOW_AUDIT_EVENT("SamplesWorkflowAuditEvent"); + + private final String _name; + + AuditEvent(String name) + { + _name = name; + } + + public String getName() + { + return _name; + } + } + public Integer getLatestAuditRowId(String auditTable) throws IOException, CommandException { String rowId = "rowId"; @@ -101,10 +123,10 @@ public DataRegionTable goToAuditEventView(String eventType) * @throws IOException Can be thrown by the SelectRowsCommand. * @throws CommandException Can be thrown by the SelectRowsCommand. */ - public SelectRowsResponse getAuditLogsFromLKS(String containerPath, String auditEventName, List columnNames, + public SelectRowsResponse getAuditLogsFromLKS(String containerPath, AuditEvent auditEventName, List columnNames, List filters, @Nullable Integer maxRows, @Nullable ContainerFilter containerFilter) throws IOException, CommandException { - SelectRowsCommand cmd = new SelectRowsCommand("auditLog", auditEventName); + SelectRowsCommand cmd = new SelectRowsCommand("auditLog", auditEventName.getName()); cmd.setColumns(columnNames); cmd.addFilter("ProjectId/Name", _wrapper.getCurrentProject(), Filter.Operator.EQUAL); filters.forEach(cmd::addFilter); @@ -115,14 +137,14 @@ public SelectRowsResponse getAuditLogsFromLKS(String containerPath, String audit return cmd.execute(_connectionSupplier.get(), containerPath); } - public List> getAuditLogsForTransactionId(String containerPath, String auditEventName, List columnNames, + public List> getAuditLogsForTransactionId(String containerPath, AuditEvent auditEventName, List columnNames, Integer transactionId, @Nullable ContainerFilter containerFilter) throws IOException, CommandException { List transactionFilter = List.of(new Filter("TransactionId", transactionId, Filter.Operator.EQUAL)); return getAuditLogsFromLKS(containerPath, auditEventName, columnNames, transactionFilter, null, containerFilter).getRows(); } - public void checkAuditEventValuesForTransactionId(String containerPath, String auditEventName, Integer transactionId, int rowCount, Map expectedValues) throws IOException, CommandException + public void checkAuditEventValuesForTransactionId(String containerPath, AuditEvent auditEventName, Integer transactionId, 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); @@ -143,11 +165,11 @@ public void checkTimelineAuditEventDiffCount(String containerPath, List { checkAuditEventDiffCount(containerPath, getAuditEventNameFromURL(), expectedDiffCounts); } - public void checkAuditEventDiffCount(String containerPath, String auditEventName, List expectedDiffCounts) throws IOException, CommandException + public void checkAuditEventDiffCount(String containerPath, AuditEvent auditEventName, List expectedDiffCounts) throws IOException, CommandException { checkAuditEventDiffCount(containerPath, auditEventName, Collections.emptyList(), expectedDiffCounts); } - public void checkAuditEventDiffCount(String containerPath, String auditEventName, List filters, List expectedDiffCounts) throws IOException, CommandException + public void checkAuditEventDiffCount(String containerPath, AuditEvent auditEventName, List filters, List expectedDiffCounts) throws IOException, CommandException { Integer maxRows = expectedDiffCounts.size(); List> events = getAuditLogsFromLKS(containerPath, auditEventName, List.of("InventoryUpdateType", "NewRecordMap"), filters, maxRows, ContainerFilter.CurrentAndSubfolders).getRows(); @@ -171,7 +193,7 @@ public void checkAuditEventDiffCount(String containerPath, String auditEventName } } - public Integer getLastTransactionId(String containerPath, String auditEventName) throws IOException, CommandException + public Integer getLastTransactionId(String containerPath, AuditEvent auditEventName) throws IOException, CommandException { List> events = getAuditLogsFromLKS(containerPath, auditEventName, List.of("TransactionId"), Collections.emptyList(), 1, ContainerFilter.CurrentAndSubfolders).getRows(); return events.size() == 1 ? (Integer) events.get(0).get("TransactionId") : null; @@ -182,7 +204,7 @@ public Integer getLastTransactionId(String containerPath, String auditEventName) * 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, String auditEventName, int expectedDiffCount, + public Integer checkAuditEventDiffCountForLastTransaction(String containerPath, AuditEvent auditEventName, int expectedDiffCount, @Nullable Integer expectedEventCount) throws IOException, CommandException { Integer transactionId = getLastTransactionId(containerPath, auditEventName); @@ -195,12 +217,12 @@ public Integer checkAuditEventDiffCountForLastTransaction(String containerPath, return transactionId; } - public String getAuditEventNameFromURL() + public AuditEvent getAuditEventNameFromURL() { if (isSamplesRoute()) - return "SampleTimelineEvent"; + return AuditEvent.SAMPLE_TIMELINE_EVENT; else if (isDataClassRoute()) - return "SourcesAuditEvent"; + return AuditEvent.SOURCES_AUDIT_EVENT; return null; }