@@ -87,8 +87,14 @@ void emptyOrchestration() throws TimeoutException {
8787 void singleTimer () throws IOException , TimeoutException {
8888 final String orchestratorName = "SingleTimer" ;
8989 final Duration delay = Duration .ofSeconds (3 );
90+ AtomicReferenceArray <LocalDateTime > timestamps = new AtomicReferenceArray <>(2 );
91+ AtomicInteger counter = new AtomicInteger ();
9092 DurableTaskGrpcWorker worker = this .createWorkerBuilder ()
91- .addOrchestrator (orchestratorName , ctx -> ctx .createTimer (delay ).await ())
93+ .addOrchestrator (orchestratorName , ctx -> {
94+ timestamps .set (counter .get (), LocalDateTime .now ());
95+ counter .incrementAndGet ();
96+ ctx .createTimer (delay ).await ();
97+ })
9298 .buildAndStart ();
9399
94100 DurableTaskClient client = new DurableTaskGrpcClientBuilder ().build ();
@@ -103,11 +109,22 @@ void singleTimer() throws IOException, TimeoutException {
103109 long expectedCompletionSecond = instance .getCreatedAt ().plus (delay ).getEpochSecond ();
104110 long actualCompletionSecond = instance .getLastUpdatedAt ().getEpochSecond ();
105111 assertTrue (expectedCompletionSecond <= actualCompletionSecond );
112+
113+ // Verify that the correct number of timers were created
114+ // This should yield 2 (first invocation + replay invocations for internal timers)
115+ assertEquals (2 , counter .get ());
116+
117+ // Verify that each timer is the expected length
118+ int [] secondsElapsed = new int [1 ];
119+ for (int i = 0 ; i < timestamps .length () - 1 ; i ++) {
120+ secondsElapsed [i ] = timestamps .get (i + 1 ).getSecond () - timestamps .get (i ).getSecond ();
121+ }
122+ assertEquals (secondsElapsed [0 ], 3 );
123+
106124 }
107125 }
108126
109127 @ Test
110- @ Disabled ("Test is disabled for investigation, fixing the test retry pattern exposed the failure (could be timer creation issue)" )
111128 void longTimer () throws TimeoutException {
112129 final String orchestratorName = "LongTimer" ;
113130 final Duration delay = Duration .ofSeconds (7 );
@@ -285,6 +302,31 @@ void singleTimeStampTimer() throws IOException, TimeoutException {
285302 }
286303 }
287304
305+
306+ @ Test
307+ void singleTimeStampCreateTimer () throws IOException , TimeoutException {
308+ final String orchestratorName = "SingleTimeStampTimer" ;
309+ final Duration delay = Duration .ofSeconds (3 );
310+ final ZonedDateTime zonedDateTime = ZonedDateTime .of (LocalDateTime .now ().plusSeconds (delay .getSeconds ()), ZoneId .systemDefault ());
311+ DurableTaskGrpcWorker worker = this .createWorkerBuilder ()
312+ .addOrchestrator (orchestratorName , ctx -> ctx .createTimer (zonedDateTime ).await ())
313+ .buildAndStart ();
314+
315+ DurableTaskClient client = new DurableTaskGrpcClientBuilder ().build ();
316+ try (worker ; client ) {
317+ String instanceId = client .scheduleNewOrchestrationInstance (orchestratorName );
318+ Duration timeout = delay .plus (defaultTimeout );
319+ OrchestrationMetadata instance = client .waitForInstanceCompletion (instanceId , timeout , false );
320+ assertNotNull (instance );
321+ assertEquals (OrchestrationRuntimeStatus .COMPLETED , instance .getRuntimeStatus ());
322+
323+ // Verify that the delay actually happened
324+ long expectedCompletionSecond = zonedDateTime .toInstant ().getEpochSecond ();
325+ long actualCompletionSecond = instance .getLastUpdatedAt ().getEpochSecond ();
326+ assertTrue (expectedCompletionSecond <= actualCompletionSecond );
327+ }
328+ }
329+
288330 @ Test
289331 void isReplaying () throws IOException , InterruptedException , TimeoutException {
290332 final String orchestratorName = "SingleTimer" ;
0 commit comments