@@ -300,6 +300,66 @@ func Test_ExecuteOperation_ReportJSON_IdempotencyKey(t *testing.T) {
300300 })
301301}
302302
303+ func Test_ExecuteSequence_ReportJSON_IdempotencyKey (t * testing.T ) {
304+ t .Parallel ()
305+
306+ version := semver .MustParse ("1.0.0" )
307+ op := NewOperation ("plus1" , version , "plus 1" ,
308+ func (b Bundle , deps any , input int ) (int , error ) {
309+ return input + 1 , nil
310+ },
311+ )
312+ sequence := NewSequence ("seq-plus1" , version , "plus 1" ,
313+ func (b Bundle , deps any , input int ) (int , error ) {
314+ res , err := ExecuteOperation (b , op , nil , input )
315+ if err != nil {
316+ return 0 , err
317+ }
318+
319+ return res .Output , nil
320+ },
321+ )
322+
323+ t .Run ("includes idempotencyKey when set" , func (t * testing.T ) {
324+ t .Parallel ()
325+
326+ const idempotencyKey = "chain-42161"
327+ bundle := NewBundle (t .Context , logger .Test (t ), NewMemoryReporter ())
328+
329+ res , err := ExecuteSequence (bundle , sequence , nil , 1 , WithSequenceIdempotencyKey [int , any ](idempotencyKey ))
330+ require .NoError (t , err )
331+
332+ stored , err := bundle .reporter .GetReport (res .ID )
333+ require .NoError (t , err )
334+ assert .Equal (t , idempotencyKey , stored .IdempotencyKey )
335+
336+ raw , err := json .Marshal (stored )
337+ require .NoError (t , err )
338+
339+ var payload map [string ]json.RawMessage
340+ require .NoError (t , json .Unmarshal (raw , & payload ))
341+ require .Contains (t , payload , "idempotencyKey" )
342+ assert .JSONEq (t , `"` + idempotencyKey + `"` , string (payload ["idempotencyKey" ]))
343+ })
344+
345+ t .Run ("omits idempotencyKey when unset" , func (t * testing.T ) {
346+ t .Parallel ()
347+
348+ bundle := NewBundle (t .Context , logger .Test (t ), NewMemoryReporter ())
349+
350+ res , err := ExecuteSequence (bundle , sequence , nil , 1 )
351+ require .NoError (t , err )
352+
353+ stored , err := bundle .reporter .GetReport (res .ID )
354+ require .NoError (t , err )
355+ assert .Empty (t , stored .IdempotencyKey )
356+
357+ raw , err := json .Marshal (stored )
358+ require .NoError (t , err )
359+ assert .NotContains (t , string (raw ), "idempotencyKey" )
360+ })
361+ }
362+
303363func Test_ExecuteOperation_WithPreviousRun_UsesMostRecentSuccessfulReport (t * testing.T ) {
304364 t .Parallel ()
305365
@@ -523,6 +583,22 @@ func Test_ExecuteSequence_WithPreviousRun(t *testing.T) {
523583 assert .Len (t , res .ExecutionReports , 2 ) // 1 seq report + 1 op report
524584 assert .Equal (t , 2 , handlerCalledTimes )
525585
586+ // same input with a different idempotency key should execute again
587+ res , err = ExecuteSequence (bundle , sequence , nil , 1 , WithSequenceIdempotencyKey [int , any ]("other-key" ))
588+ require .NoError (t , err )
589+ require .Nil (t , res .Err )
590+ assert .Equal (t , 2 , res .Output )
591+ assert .Equal (t , 3 , handlerCalledTimes )
592+ idempotencyKeyRunID := res .ID
593+ assert .NotEqual (t , firstRunID , idempotencyKeyRunID )
594+
595+ // same input and idempotency key should reuse that sequence report
596+ res , err = ExecuteSequence (bundle , sequence , nil , 1 , WithSequenceIdempotencyKey [int , any ]("other-key" ))
597+ require .NoError (t , err )
598+ require .Nil (t , res .Err )
599+ assert .Equal (t , idempotencyKeyRunID , res .ID )
600+ assert .Equal (t , 3 , handlerCalledTimes )
601+
526602 // new run with different sequence but same operation, should perform execution
527603 sequence = NewSequence ("seq-plus1-v2" , semver .MustParse ("2.0.0" ), "plus 1" , handler )
528604 res , err = ExecuteSequence (bundle , sequence , nil , 1 )
@@ -531,7 +607,7 @@ func Test_ExecuteSequence_WithPreviousRun(t *testing.T) {
531607 assert .Equal (t , 2 , res .Output )
532608 // only 1 because the op was not executed due to previous execution found
533609 assert .Len (t , res .ExecutionReports , 1 )
534- assert .Equal (t , 3 , handlerCalledTimes )
610+ assert .Equal (t , 4 , handlerCalledTimes )
535611
536612 // new run with sequence that returns error
537613 res , err = ExecuteSequence (bundle , sequenceWithError , nil , 1 )
0 commit comments