@@ -377,4 +377,120 @@ describe("In-Memory Backend", () => {
377377 expect ( state ?. runtimeStatus ) . toEqual ( OrchestrationStatus . COMPLETED ) ;
378378 expect ( state ?. serializedOutput ) . toEqual ( JSON . stringify ( 42 ) ) ;
379379 } ) ;
380+
381+ describe ( "suspend and resume status" , ( ) => {
382+ it ( "should update status to SUSPENDED when suspend is called" , async ( ) => {
383+ const orchestrator : TOrchestrator = async function * ( ctx : OrchestrationContext ) : any {
384+ yield ctx . waitForExternalEvent ( "proceed" ) ;
385+ return "done" ;
386+ } ;
387+
388+ worker . addOrchestrator ( orchestrator ) ;
389+ await worker . start ( ) ;
390+
391+ const id = await client . scheduleNewOrchestration ( orchestrator ) ;
392+ await client . waitForOrchestrationStart ( id , false , 10 ) ;
393+
394+ await client . suspendOrchestration ( id ) ;
395+
396+ const state = await client . getOrchestrationState ( id ) ;
397+ expect ( state ?. runtimeStatus ) . toEqual ( OrchestrationStatus . SUSPENDED ) ;
398+ } ) ;
399+
400+ it ( "should update status to RUNNING when resume is called after suspend" , async ( ) => {
401+ const orchestrator : TOrchestrator = async function * ( ctx : OrchestrationContext ) : any {
402+ yield ctx . waitForExternalEvent ( "proceed" ) ;
403+ return "done" ;
404+ } ;
405+
406+ worker . addOrchestrator ( orchestrator ) ;
407+ await worker . start ( ) ;
408+
409+ const id = await client . scheduleNewOrchestration ( orchestrator ) ;
410+ await client . waitForOrchestrationStart ( id , false , 10 ) ;
411+
412+ await client . suspendOrchestration ( id ) ;
413+ let state = await client . getOrchestrationState ( id ) ;
414+ expect ( state ?. runtimeStatus ) . toEqual ( OrchestrationStatus . SUSPENDED ) ;
415+
416+ await client . resumeOrchestration ( id ) ;
417+ state = await client . getOrchestrationState ( id ) ;
418+ expect ( state ?. runtimeStatus ) . toEqual ( OrchestrationStatus . RUNNING ) ;
419+ } ) ;
420+
421+ it ( "should complete successfully after suspend and resume" , async ( ) => {
422+ const orchestrator : TOrchestrator = async function * ( ctx : OrchestrationContext ) : any {
423+ const val : number = yield ctx . waitForExternalEvent ( "proceed" ) ;
424+ return val * 2 ;
425+ } ;
426+
427+ worker . addOrchestrator ( orchestrator ) ;
428+ await worker . start ( ) ;
429+
430+ const id = await client . scheduleNewOrchestration ( orchestrator ) ;
431+ await client . waitForOrchestrationStart ( id , false , 10 ) ;
432+
433+ // Suspend the orchestration
434+ await client . suspendOrchestration ( id ) ;
435+ let state = await client . getOrchestrationState ( id ) ;
436+ expect ( state ?. runtimeStatus ) . toEqual ( OrchestrationStatus . SUSPENDED ) ;
437+
438+ // Send an event while suspended (will be buffered)
439+ await client . raiseOrchestrationEvent ( id , "proceed" , 21 ) ;
440+
441+ // Resume the orchestration
442+ await client . resumeOrchestration ( id ) ;
443+
444+ // Wait for completion — the buffered event should be processed
445+ state = await client . waitForOrchestrationCompletion ( id , true , 10 ) ;
446+ expect ( state ?. runtimeStatus ) . toEqual ( OrchestrationStatus . COMPLETED ) ;
447+ expect ( state ?. serializedOutput ) . toEqual ( JSON . stringify ( 42 ) ) ;
448+ } ) ;
449+
450+ it ( "should be idempotent when suspend is called twice" , async ( ) => {
451+ const orchestrator : TOrchestrator = async function * ( ctx : OrchestrationContext ) : any {
452+ yield ctx . waitForExternalEvent ( "proceed" ) ;
453+ return "done" ;
454+ } ;
455+
456+ worker . addOrchestrator ( orchestrator ) ;
457+ await worker . start ( ) ;
458+
459+ const id = await client . scheduleNewOrchestration ( orchestrator ) ;
460+ await client . waitForOrchestrationStart ( id , false , 10 ) ;
461+
462+ // Call suspend twice — should not throw
463+ await client . suspendOrchestration ( id ) ;
464+ await client . suspendOrchestration ( id ) ;
465+
466+ const state = await client . getOrchestrationState ( id ) ;
467+ expect ( state ?. runtimeStatus ) . toEqual ( OrchestrationStatus . SUSPENDED ) ;
468+ } ) ;
469+
470+ it ( "should notify state waiters on suspend" , async ( ) => {
471+ const orchestrator : TOrchestrator = async function * ( ctx : OrchestrationContext ) : any {
472+ yield ctx . waitForExternalEvent ( "proceed" ) ;
473+ return "done" ;
474+ } ;
475+
476+ worker . addOrchestrator ( orchestrator ) ;
477+ await worker . start ( ) ;
478+
479+ const id = await client . scheduleNewOrchestration ( orchestrator ) ;
480+ await client . waitForOrchestrationStart ( id , false , 10 ) ;
481+
482+ // Set up a waiter for SUSPENDED status, then suspend
483+ const suspendedPromise = backend . waitForState (
484+ id ,
485+ ( inst ) => backend . toClientStatus ( inst . status ) === OrchestrationStatus . SUSPENDED ,
486+ 5000 ,
487+ ) ;
488+
489+ await client . suspendOrchestration ( id ) ;
490+
491+ const suspendedInstance = await suspendedPromise ;
492+ expect ( suspendedInstance ) . toBeDefined ( ) ;
493+ expect ( backend . toClientStatus ( suspendedInstance ! . status ) ) . toEqual ( OrchestrationStatus . SUSPENDED ) ;
494+ } ) ;
495+ } ) ;
380496} ) ;
0 commit comments