11
11
12
12
import { describe , expect } from "@jest/globals" ;
13
13
import * as restate from "../src/public_api" ;
14
- import { TestDriver , TestGreeter , TestResponse } from "./testdriver" ;
14
+ import {
15
+ GreeterApi ,
16
+ TestDriver ,
17
+ TestGreeter ,
18
+ TestResponse ,
19
+ } from "./testdriver" ;
15
20
import {
16
21
awakeableMessage ,
17
22
completionMessage ,
@@ -27,6 +32,7 @@ import {
27
32
sleepMessage ,
28
33
sideEffectMessage ,
29
34
ackMessage ,
35
+ invokeMessage ,
30
36
} from "./protoutils" ;
31
37
import {
32
38
COMBINATOR_ENTRY_MESSAGE ,
@@ -35,6 +41,7 @@ import {
35
41
import { TimeoutError } from "../src/types/errors" ;
36
42
import { CombineablePromise } from "../src/context" ;
37
43
import { Empty } from "../src/generated/proto/protocol_pb" ;
44
+ import { Buffer } from "node:buffer" ;
38
45
39
46
class AwakeableSleepRaceGreeter implements TestGreeter {
40
47
async greet ( ctx : restate . ObjectContext ) : Promise < TestResponse > {
@@ -398,3 +405,182 @@ describe("AwakeableOrTimeoutGreeter", () => {
398
405
] ) ;
399
406
} ) ;
400
407
} ) ;
408
+
409
+ class InvokeRaceGreeter implements TestGreeter {
410
+ async greet ( ctx : restate . ObjectContext ) : Promise < TestResponse > {
411
+ const jack = ctx . objectClient ( GreeterApi , "Jack" ) . greet ( { name : "Jack" } ) ;
412
+ const jill = ctx . objectClient ( GreeterApi , "Jill" ) . greet ( { name : "Jill" } ) ;
413
+
414
+ const result = await CombineablePromise . race ( [ jack , jill ] ) ;
415
+
416
+ return TestResponse . create ( {
417
+ greeting : result . greeting ,
418
+ } ) ;
419
+ }
420
+ }
421
+
422
+ describe ( "InvokeRaceGreeter" , ( ) => {
423
+ const jackInvoke = invokeMessage (
424
+ "greeter" ,
425
+ "greet" ,
426
+ Buffer . from ( JSON . stringify ( { name : "Jack" } ) ) ,
427
+ undefined ,
428
+ undefined ,
429
+ "Jack"
430
+ ) ;
431
+ const jillInvoke = invokeMessage (
432
+ "greeter" ,
433
+ "greet" ,
434
+ Buffer . from ( JSON . stringify ( { name : "Jill" } ) ) ,
435
+ undefined ,
436
+ undefined ,
437
+ "Jill"
438
+ ) ;
439
+
440
+ it ( "should suspend without completions" , async ( ) => {
441
+ const result = await new TestDriver ( new InvokeRaceGreeter ( ) , [
442
+ startMessage ( ) ,
443
+ inputMessage ( greetRequest ( "Till" ) ) ,
444
+ ] ) . run ( ) ;
445
+
446
+ expect ( result . length ) . toStrictEqual ( 3 ) ;
447
+ expect ( result [ 0 ] ) . toStrictEqual ( jackInvoke ) ;
448
+ expect ( result [ 1 ] ) . toStrictEqual ( jillInvoke ) ;
449
+ expect ( result [ 2 ] ) . toStrictEqual ( suspensionMessage ( [ 1 , 2 ] ) ) ;
450
+ } ) ;
451
+
452
+ it ( "handles completion of first invoke" , async ( ) => {
453
+ const result = await new TestDriver ( new InvokeRaceGreeter ( ) , [
454
+ startMessage ( ) ,
455
+ inputMessage ( greetRequest ( "Till" ) ) ,
456
+ completionMessage ( 1 , greetResponse ( "Hi Jack" ) ) ,
457
+ ackMessage ( 3 ) ,
458
+ ] ) . run ( ) ;
459
+
460
+ expect ( result . length ) . toStrictEqual ( 5 ) ;
461
+ expect ( result [ 0 ] ) . toStrictEqual ( jackInvoke ) ;
462
+ expect ( result [ 1 ] ) . toStrictEqual ( jillInvoke ) ;
463
+ expect ( result . slice ( 2 ) ) . toStrictEqual ( [
464
+ combinatorEntryMessage ( 0 , [ 1 ] ) ,
465
+ outputMessage ( greetResponse ( "Hi Jack" ) ) ,
466
+ END_MESSAGE ,
467
+ ] ) ;
468
+ } ) ;
469
+
470
+ it ( "handles completion of second invoke" , async ( ) => {
471
+ const result = await new TestDriver ( new InvokeRaceGreeter ( ) , [
472
+ startMessage ( ) ,
473
+ inputMessage ( greetRequest ( "Till" ) ) ,
474
+ completionMessage ( 2 , greetResponse ( "Hi Jill" ) ) ,
475
+ ackMessage ( 3 ) ,
476
+ ] ) . run ( ) ;
477
+
478
+ expect ( result . length ) . toStrictEqual ( 5 ) ;
479
+ expect ( result [ 0 ] ) . toStrictEqual ( jackInvoke ) ;
480
+ expect ( result [ 1 ] ) . toStrictEqual ( jillInvoke ) ;
481
+ expect ( result . slice ( 2 ) ) . toStrictEqual ( [
482
+ combinatorEntryMessage ( 0 , [ 2 ] ) ,
483
+ outputMessage ( greetResponse ( `Hi Jill` ) ) ,
484
+ END_MESSAGE ,
485
+ ] ) ;
486
+ } ) ;
487
+
488
+ it ( "handles replay of the first invoke" , async ( ) => {
489
+ const result = await new TestDriver ( new InvokeRaceGreeter ( ) , [
490
+ startMessage ( ) ,
491
+ inputMessage ( greetRequest ( "Till" ) ) ,
492
+ invokeMessage (
493
+ "greeter" ,
494
+ "greet" ,
495
+ Buffer . from ( JSON . stringify ( { name : "Jack" } ) ) ,
496
+ greetResponse ( "Hi Jack" ) ,
497
+ undefined ,
498
+ "Jack"
499
+ ) ,
500
+ ackMessage ( 3 ) ,
501
+ ] ) . run ( ) ;
502
+
503
+ expect ( result . length ) . toStrictEqual ( 4 ) ;
504
+ expect ( result [ 0 ] ) . toStrictEqual ( jillInvoke ) ;
505
+ expect ( result . slice ( 1 ) ) . toStrictEqual ( [
506
+ combinatorEntryMessage ( 0 , [ 1 ] ) ,
507
+ outputMessage ( greetResponse ( "Hi Jack" ) ) ,
508
+ END_MESSAGE ,
509
+ ] ) ;
510
+ } ) ;
511
+
512
+ it ( "handles replay of both invokes" , async ( ) => {
513
+ const result = await new TestDriver ( new InvokeRaceGreeter ( ) , [
514
+ startMessage ( ) ,
515
+ inputMessage ( greetRequest ( "Till" ) ) ,
516
+ invokeMessage (
517
+ "greeter" ,
518
+ "greet" ,
519
+ Buffer . from ( JSON . stringify ( { name : "Jack" } ) ) ,
520
+ greetResponse ( "Hi Jack" ) ,
521
+ undefined ,
522
+ "Jack"
523
+ ) ,
524
+ invokeMessage (
525
+ "greeter" ,
526
+ "greet" ,
527
+ Buffer . from ( JSON . stringify ( { name : "Jill" } ) ) ,
528
+ greetResponse ( "Hi Jill" ) ,
529
+ undefined ,
530
+ "Jill"
531
+ ) ,
532
+ ackMessage ( 3 ) ,
533
+ ] ) . run ( ) ;
534
+
535
+ expect ( result ) . toStrictEqual ( [
536
+ // The first invoke will be chosen because Promise.race will pick the first promise, in case both are resolved
537
+ combinatorEntryMessage ( 0 , [ 1 , 2 ] ) ,
538
+ outputMessage ( greetResponse ( "Hi Jack" ) ) ,
539
+ END_MESSAGE ,
540
+ ] ) ;
541
+ } ) ;
542
+
543
+ it ( "handles replay of the combinator with first invoke completed" , async ( ) => {
544
+ const result = await new TestDriver ( new InvokeRaceGreeter ( ) , [
545
+ startMessage ( ) ,
546
+ inputMessage ( greetRequest ( "Till" ) ) ,
547
+ invokeMessage (
548
+ "greeter" ,
549
+ "greet" ,
550
+ Buffer . from ( JSON . stringify ( { name : "Jack" } ) ) ,
551
+ greetResponse ( "Hi Jack" ) ,
552
+ undefined ,
553
+ "Jack"
554
+ ) ,
555
+ jillInvoke ,
556
+ combinatorEntryMessage ( 0 , [ 1 ] ) ,
557
+ ] ) . run ( ) ;
558
+
559
+ expect ( result ) . toStrictEqual ( [
560
+ outputMessage ( greetResponse ( "Hi Jack" ) ) ,
561
+ END_MESSAGE ,
562
+ ] ) ;
563
+ } ) ;
564
+
565
+ it ( "handles replay of the combinator with second invoke completed" , async ( ) => {
566
+ const result = await new TestDriver ( new InvokeRaceGreeter ( ) , [
567
+ startMessage ( ) ,
568
+ inputMessage ( greetRequest ( "Till" ) ) ,
569
+ jackInvoke ,
570
+ invokeMessage (
571
+ "greeter" ,
572
+ "greet" ,
573
+ Buffer . from ( JSON . stringify ( { name : "Jill" } ) ) ,
574
+ greetResponse ( "Hi Jill" ) ,
575
+ undefined ,
576
+ "Jill"
577
+ ) ,
578
+ combinatorEntryMessage ( 0 , [ 2 ] ) ,
579
+ ] ) . run ( ) ;
580
+
581
+ expect ( result ) . toStrictEqual ( [
582
+ outputMessage ( greetResponse ( "Hi Jill" ) ) ,
583
+ END_MESSAGE ,
584
+ ] ) ;
585
+ } ) ;
586
+ } ) ;
0 commit comments