44import org .jetbrains .annotations .NotNull ;
55import org .jetbrains .annotations .Nullable ;
66import org .json .JSONException ;
7+ import org .json .JSONObject ;
78import org .labkey .api .collections .CaseInsensitiveHashMap ;
89import org .labkey .remoteapi .CommandException ;
910import org .labkey .remoteapi .Connection ;
@@ -101,7 +102,8 @@ public enum AuditEvent
101102 QUERY_UPDATE_AUDIT_EVENT ("QueryUpdateAuditEvent" ),
102103 SAMPLE_TIMELINE_EVENT ("SampleTimelineEvent" ),
103104 SAMPLE_WORKFLOW_AUDIT_EVENT ("SamplesWorkflowAuditEvent" ),
104- SOURCES_AUDIT_EVENT ("SourcesAuditEvent" ); // available with SampleManagement module
105+ SOURCES_AUDIT_EVENT ("SourcesAuditEvent" ),
106+ TRANSACTION_AUDIT_EVENT ("TransactionAuditEvent" ); // available with SampleManagement module
105107
106108 private final String _name ;
107109
@@ -116,6 +118,22 @@ public String getName()
116118 }
117119 }
118120
121+ public enum TransactionDetail
122+ {
123+ AuditEvents (),
124+ ImportFileName (),
125+ ClientLibrary ,
126+ Product ,
127+ Action ,
128+ QueryCommand ,
129+ DataIteratorUsed ,
130+ ImportOptions ,
131+ EditMethod ,
132+ RequestSource ,
133+ ETL ,
134+ FileWatcher ;
135+ }
136+
119137 public Integer getLatestAuditRowId (String auditTable ) throws IOException , CommandException
120138 {
121139 String rowId = "rowId" ;
@@ -233,6 +251,49 @@ public void checkAuditEventValuesForTransactionId(String containerPath, AuditEve
233251 }
234252 }
235253
254+ public Map <String , Object > getTransactionAuditLogDetails (Integer transactionAuditId )
255+ {
256+ Connection cn = WebTestHelper .getRemoteApiConnection ();
257+ SelectRowsCommand cmd = new SelectRowsCommand ("auditLog" , "TransactionAuditEvent" );
258+ cmd .setRequiredVersion (9.1 );
259+ cmd .setColumns (Arrays .asList ("TransactionDetails" ));
260+ cmd .addFilter ("RowId" , transactionAuditId , Filter .Operator .EQUAL );
261+ cmd .setContainerFilter (ContainerFilter .AllFolders );
262+
263+ Map <String , Object > event = executeSelectCommand (cn , cmd ).get (0 );
264+ String detailJSON = getLogColumnValue (event , "TransactionDetails" );
265+ log ("TransactionAuditEvent Details: " + detailJSON );
266+ if (detailJSON == null || detailJSON .isEmpty ())
267+ return Collections .emptyMap ();
268+
269+ return new JSONObject (detailJSON ).toMap ();
270+ }
271+
272+ public void checkLastTransactionAuditLogDetails (String containerPath , Map <TransactionDetail , Object > expectedDetails )
273+ {
274+ Integer transactionAuditId = getLastTransactionId (containerPath );
275+ if (transactionAuditId == null )
276+ fail ("No TransactionAuditEvent found in container: " + containerPath );
277+ checkTransactionAuditLogDetails (transactionAuditId , expectedDetails );
278+ }
279+
280+ public void checkTransactionAuditLogDetails (Integer transactionAuditId , Map <TransactionDetail , Object > expectedDetails )
281+ {
282+ Map <String , Object > actualDetails = getTransactionAuditLogDetails (transactionAuditId );
283+ assertEquals ("Unexpected number of events for transactionId " + transactionAuditId , expectedDetails .size (), actualDetails .size ());
284+ for (TransactionDetail key : expectedDetails .keySet ())
285+ {
286+ assertTrue ("Expected detail key not found: " + key , actualDetails .containsKey (key .name ()));
287+ if (TransactionDetail .RequestSource .name ().equals (key .name ()))
288+ {
289+ String expectedValue = expectedDetails .get (key ).toString ();
290+ String actualValue = actualDetails .get (key .name ()) != null ? actualDetails .get (key .name ()).toString () : null ;
291+ assertTrue ("Detail value for key " + key + " not as expected" , actualValue != null && actualValue .startsWith (expectedValue ));
292+ }
293+ else
294+ assertEquals ("Detail value for key " + key + " not as expected" , expectedDetails .get (key ), actualDetails .get (key .name ()));
295+ }
296+ }
236297 /**
237298 * Check the number of diffs in the audit event. This is a helper function to check the number of diffs in the
238299 * newRecordMap for an audit entry. If a transactionId is provided, it will check all rows for that
@@ -308,6 +369,19 @@ public Integer getLastTransactionId(String containerPath, AuditEvent auditEventN
308369 }
309370 }
310371
372+ public Integer getLastTransactionId (String containerPath )
373+ {
374+ try
375+ {
376+ List <Map <String , Object >> events = getAuditLogsFromLKS (containerPath , AuditEvent .TRANSACTION_AUDIT_EVENT , List .of ("RowId" ), Collections .emptyList (), 1 , ContainerFilter .CurrentAndSubfolders ).getRows ();
377+ return events .size () == 1 ? (Integer ) events .get (0 ).get ("RowId" ) : null ;
378+ }
379+ catch (Exception e )
380+ {
381+ throw new RuntimeException (e );
382+ }
383+ }
384+
311385 public Integer getLastEventId (String containerPath , AuditEvent auditEventName )
312386 {
313387 try
0 commit comments