88import java .util .concurrent .atomic .AtomicInteger ;
99import org .junit .jupiter .api .Test ;
1010import software .amazon .awssdk .services .lambda .model .OperationType ;
11+ import software .amazon .lambda .durable .config .RunInChildContextConfig ;
1112import software .amazon .lambda .durable .model .ExecutionStatus ;
1213import software .amazon .lambda .durable .testing .LocalDurableTestRunner ;
1314
@@ -42,6 +43,34 @@ void childContextResultSurvivesReplay() {
4243 assertEquals (1 , childExecutionCount .get (), "Child function should not re-execute on replay" );
4344 }
4445
46+ @ Test
47+ void virtualChildContextResultSurvivesReplay () {
48+ var childExecutionCount = new AtomicInteger (0 );
49+
50+ var runner = LocalDurableTestRunner .create (
51+ String .class ,
52+ (input , ctx ) -> ctx .runInChildContext (
53+ "compute" ,
54+ TypeToken .get (String .class ),
55+ child -> {
56+ childExecutionCount .incrementAndGet ();
57+ return child .step ("work" , String .class , stepCtx -> "result-" + input );
58+ },
59+ RunInChildContextConfig .builder ().isVirtual (true ).build ()));
60+
61+ // First run - executes child context
62+ var result = runner .runUntilComplete ("test" );
63+ assertEquals (ExecutionStatus .SUCCEEDED , result .getStatus ());
64+ assertEquals ("result-test" , result .getResult (String .class ));
65+ assertEquals (1 , childExecutionCount .get ());
66+
67+ // Second run - replays, should return cached result without re-executing
68+ result = runner .run ("test" );
69+ assertEquals (ExecutionStatus .SUCCEEDED , result .getStatus ());
70+ assertEquals ("result-test" , result .getResult (String .class ));
71+ assertEquals (2 , childExecutionCount .get (), "Child function should re-execute on replay" );
72+ }
73+
4574 /**
4675 * A child context that fails with a reconstructable exception SHALL preserve the exception type, message, and error
4776 * details through the checkpoint-and-replay cycle.
@@ -62,7 +91,7 @@ void childContextExceptionPreservedOnReplay() {
6291 assertEquals (ExecutionStatus .FAILED , result .getStatus ());
6392 assertEquals (1 , childExecutionCount .get ());
6493
65- // Second run - replays, should throw same exception without re-executing
94+ // Second run - replays, should throw same exception with re-executing
6695 result = runner .run ("test" );
6796 assertEquals (ExecutionStatus .FAILED , result .getStatus ());
6897 assertTrue (result .getError ().isPresent ());
@@ -72,6 +101,36 @@ void childContextExceptionPreservedOnReplay() {
72101 assertEquals (1 , childExecutionCount .get (), "Child function should not re-execute on failed replay" );
73102 }
74103
104+ @ Test
105+ void virtualChildContextExceptionPreservedOnReplay () {
106+ var childExecutionCount = new AtomicInteger (0 );
107+
108+ var runner = LocalDurableTestRunner .create (
109+ String .class ,
110+ (input , ctx ) -> ctx .runInChildContext (
111+ "failing" ,
112+ String .class ,
113+ child -> {
114+ childExecutionCount .incrementAndGet ();
115+ throw new IllegalArgumentException ("bad input: " + input );
116+ },
117+ RunInChildContextConfig .builder ().isVirtual (true ).build ()));
118+
119+ // First run - child context fails
120+ var result = runner .run ("test" );
121+ assertEquals (ExecutionStatus .FAILED , result .getStatus ());
122+ assertEquals (1 , childExecutionCount .get ());
123+
124+ // Second run - replays, should throw same exception with re-executing
125+ result = runner .run ("test" );
126+ assertEquals (ExecutionStatus .FAILED , result .getStatus ());
127+ assertTrue (result .getError ().isPresent ());
128+ var error = result .getError ().get ();
129+ assertEquals ("java.lang.IllegalArgumentException" , error .errorType ());
130+ assertEquals ("bad input: test" , error .errorMessage ());
131+ assertEquals (2 , childExecutionCount .get (), "Child function should re-execute on failed replay" );
132+ }
133+
75134 /** Operations checkpointed from within a child context SHALL have the child context's ID as their parentId. */
76135 @ Test
77136 void operationsInChildContextHaveCorrectParentId () {
0 commit comments