tractor.dev/toolkit-go@v0.0.0-20241010005851-214d91207d07/duplex/duplex_test.go (about) 1 package duplex 2 3 import ( 4 "context" 5 "testing" 6 7 "tractor.dev/toolkit-go/duplex/codec" 8 "tractor.dev/toolkit-go/duplex/fn" 9 "tractor.dev/toolkit-go/duplex/mux" 10 "tractor.dev/toolkit-go/duplex/talk" 11 ) 12 13 func fatal(t *testing.T, err error) { 14 if err != nil { 15 t.Fatal(err) 16 } 17 } 18 19 func equal(t *testing.T, a, b any, message string) { 20 if a != b { 21 t.Log(message) 22 t.Fail() 23 } 24 } 25 26 func makeClientServer(service any) (client, server *talk.Peer, closer func()) { 27 c, s := mux.Pair() 28 client = talk.NewPeer(c, codec.CBORCodec{}) 29 server = talk.NewPeer(s, codec.CBORCodec{}) 30 server.Server.Handler = fn.HandlerFrom(service) 31 go client.Respond() 32 go server.Respond() 33 closer = func() { 34 client.Close() 35 server.Close() 36 } 37 return 38 } 39 40 type TestService struct { 41 T *testing.T 42 } 43 44 func (s *TestService) Hello() string { 45 return "Hello" 46 } 47 48 func (s *TestService) NilAnyArg(a string, v any) { 49 equal(s.T, v, nil, "nil any arg not nil") 50 } 51 52 func TestBasic(t *testing.T) { 53 c, _, closer := makeClientServer(&TestService{T: t}) 54 defer closer() 55 56 var ret string 57 _, err := c.Call(context.Background(), "Hello", nil, &ret) 58 fatal(t, err) 59 60 equal(t, ret, "Hello", "return not Hello") 61 } 62 63 func TestNilAnyArg(t *testing.T) { 64 c, _, closer := makeClientServer(&TestService{T: t}) 65 defer closer() 66 67 _, err := c.Call(context.Background(), "NilAnyArg", fn.Args{"abc", nil}, nil) 68 fatal(t, err) 69 70 } 71 72 // this test ensures the io.Pipe based mux.Pair buffers enough writes 73 // to allow a simultaneous call or channel open, since a lockstep pipe 74 // will deadlock unable to write the open confirm since the other end 75 // will also be trying to write an open confirm before reading next packet 76 func TestSimultaneousOpen(t *testing.T) { 77 c, s := mux.Pair() 78 client := talk.NewPeer(c, codec.CBORCodec{}) 79 client.Server.Handler = fn.HandlerFrom(&TestService{T: t}) 80 server := talk.NewPeer(s, codec.CBORCodec{}) 81 server.Server.Handler = fn.HandlerFrom(&TestService{T: t}) 82 go client.Respond() 83 go server.Respond() 84 85 cdone := make(chan bool) 86 sdone := make(chan bool) 87 88 go func() { 89 var ret any 90 _, err := client.Call(context.Background(), "Hello", nil, &ret) 91 fatal(t, err) 92 close(cdone) 93 }() 94 95 go func() { 96 var ret any 97 _, err := server.Call(context.Background(), "Hello", nil, &ret) 98 fatal(t, err) 99 close(sdone) 100 }() 101 102 <-sdone 103 <-cdone 104 105 client.Close() 106 server.Close() 107 }