go.uber.org/yarpc@v1.72.1/transport/tchannel/channel_inbound_test.go (about) 1 // Copyright (c) 2022 Uber Technologies, Inc. 2 // 3 // Permission is hereby granted, free of charge, to any person obtaining a copy 4 // of this software and associated documentation files (the "Software"), to deal 5 // in the Software without restriction, including without limitation the rights 6 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 // copies of the Software, and to permit persons to whom the Software is 8 // furnished to do so, subject to the following conditions: 9 // 10 // The above copyright notice and this permission notice shall be included in 11 // all copies or substantial portions of the Software. 12 // 13 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 // THE SOFTWARE. 20 21 package tchannel 22 23 import ( 24 "bytes" 25 "context" 26 "fmt" 27 "io/ioutil" 28 "testing" 29 30 "github.com/stretchr/testify/assert" 31 "github.com/stretchr/testify/require" 32 "github.com/uber/tchannel-go" 33 tjson "github.com/uber/tchannel-go/json" 34 "github.com/uber/tchannel-go/testutils" 35 "go.uber.org/yarpc" 36 "go.uber.org/yarpc/api/transport" 37 "go.uber.org/yarpc/encoding/json" 38 "go.uber.org/yarpc/encoding/raw" 39 "go.uber.org/yarpc/internal/testtime" 40 ) 41 42 func TestChannelInboundStartNew(t *testing.T) { 43 ch, err := tchannel.NewChannel("foo", nil) 44 require.NoError(t, err) 45 46 x, err := NewChannelTransport(WithChannel(ch)) 47 require.NoError(t, err) 48 49 i := x.NewInbound() 50 i.SetRouter(yarpc.NewMapRouter("foo")) 51 // Can't do Equal because we want to match the pointer, not a 52 // DeepEqual. 53 assert.True(t, ch == i.Channel(), "channel does not match") 54 require.NoError(t, i.Start()) 55 require.NoError(t, x.Start()) 56 57 assert.Equal(t, tchannel.ChannelListening, ch.State()) 58 assert.NoError(t, i.Stop()) 59 assert.NoError(t, x.Stop()) 60 assert.Equal(t, tchannel.ChannelClosed, ch.State()) 61 } 62 63 func TestChannelInboundStartAlreadyListening(t *testing.T) { 64 ch, err := tchannel.NewChannel("foo", nil) 65 require.NoError(t, err) 66 67 require.NoError(t, ch.ListenAndServe("127.0.0.1:0")) 68 assert.Equal(t, tchannel.ChannelListening, ch.State()) 69 70 x, err := NewChannelTransport(WithChannel(ch)) 71 require.NoError(t, err) 72 73 i := x.NewInbound() 74 75 i.SetRouter(yarpc.NewMapRouter("foo")) 76 require.NoError(t, i.Start()) 77 require.NoError(t, x.Start()) 78 assert.Equal(t, tchannel.ChannelListening, ch.State()) 79 80 assert.NoError(t, i.Stop()) 81 assert.NoError(t, x.Stop()) 82 assert.Equal(t, tchannel.ChannelClosed, ch.State()) 83 } 84 85 func TestChannelInboundStopWithoutStarting(t *testing.T) { 86 ch, err := tchannel.NewChannel("foo", nil) 87 require.NoError(t, err) 88 89 x, err := NewChannelTransport(WithChannel(ch)) 90 require.NoError(t, err) 91 92 i := x.NewInbound() 93 assert.NoError(t, i.Stop()) 94 } 95 96 func TestChannelInboundInvalidAddress(t *testing.T) { 97 x, err := NewChannelTransport(ServiceName("foo"), ListenAddr("not valid")) 98 require.NoError(t, err) 99 100 i := x.NewInbound() 101 i.SetRouter(yarpc.NewMapRouter("foo")) 102 assert.Nil(t, i.Start()) 103 defer i.Stop() 104 assert.Error(t, x.Start()) 105 defer x.Stop() 106 } 107 108 func TestChannelInboundExistingMethods(t *testing.T) { 109 // Create a channel with an existing "echo" method. 110 ch, err := tchannel.NewChannel("foo", nil) 111 require.NoError(t, err) 112 tjson.Register(ch, tjson.Handlers{ 113 "echo": func(ctx tjson.Context, req map[string]string) (map[string]string, error) { 114 return req, nil 115 }, 116 }, nil) 117 118 x, err := NewChannelTransport(WithChannel(ch)) 119 require.NoError(t, err) 120 121 i := x.NewInbound() 122 i.SetRouter(yarpc.NewMapRouter("foo")) 123 require.NoError(t, i.Start()) 124 defer i.Stop() 125 require.NoError(t, x.Start()) 126 defer x.Stop() 127 128 // Make a call to the "echo" method which should call our pre-registered method. 129 ctx, cancel := tjson.NewContext(testtime.Second) 130 defer cancel() 131 132 var resp map[string]string 133 arg := map[string]string{"k": "v"} 134 135 svc := ch.ServiceName() 136 peer := ch.Peers().GetOrAdd(ch.PeerInfo().HostPort) 137 err = tjson.CallPeer(ctx, peer, svc, "echo", arg, &resp) 138 require.NoError(t, err, "Call failed") 139 assert.Equal(t, arg, resp, "Response mismatch") 140 } 141 142 func TestChannelInboundMaskedMethods(t *testing.T) { 143 // Create a channel with an existing "echo" method. 144 ch, err := tchannel.NewChannel("foo", nil) 145 require.NoError(t, err) 146 tjson.Register(ch, tjson.Handlers{ 147 "echo": func(ctx tjson.Context, req map[string]string) (map[string]string, error) { 148 // i should not be 149 return nil, fmt.Errorf("SVM NON DEBEAM") 150 }, 151 }, nil) 152 153 x, err := NewChannelTransport(WithChannel(ch)) 154 require.NoError(t, err) 155 156 // Override TChannel version of echo 157 i := x.NewInbound() 158 r := yarpc.NewMapRouter("foo") 159 echo := func(ctx context.Context, req map[string]string) (map[string]string, error) { 160 return req, nil 161 } 162 r.Register(json.Procedure("echo", echo)) 163 i.SetRouter(r) 164 require.NoError(t, i.Start()) 165 defer i.Stop() 166 require.NoError(t, x.Start()) 167 defer x.Stop() 168 169 // Make a call to the "echo" method which should call our pre-registered method. 170 ctx, cancel := tjson.NewContext(testtime.Second) 171 defer cancel() 172 173 var resp map[string]string 174 arg := map[string]string{"k": "v"} 175 176 svc := ch.ServiceName() 177 peer := ch.Peers().GetOrAdd(ch.PeerInfo().HostPort) 178 err = tjson.CallPeer(ctx, peer, svc, "echo", arg, &resp) 179 require.NoError(t, err, "Call failed") 180 assert.Equal(t, arg, resp, "Response mismatch") 181 } 182 183 func TestChannelInboundSubServices(t *testing.T) { 184 chserv := testutils.NewServer(t, nil) 185 defer chserv.Close() 186 chservEndpoint := chserv.PeerInfo().HostPort 187 188 itransport, err := NewChannelTransport(ServiceName("myservice"), WithChannel(chserv)) 189 require.NoError(t, err) 190 191 router := yarpc.NewMapRouter("myservice") 192 193 i := itransport.NewInbound() 194 i.SetRouter(router) 195 196 nophandlerspec := transport.NewUnaryHandlerSpec(nophandler{}) 197 198 router.Register([]transport.Procedure{ 199 {Name: "hello", HandlerSpec: nophandlerspec}, 200 {Service: "subservice", Name: "hello", HandlerSpec: nophandlerspec}, 201 {Service: "subservice", Name: "world", HandlerSpec: nophandlerspec}, 202 {Service: "subservice2", Name: "hello", HandlerSpec: nophandlerspec}, 203 {Service: "subservice2", Name: "monde", HandlerSpec: nophandlerspec}, 204 }) 205 206 require.NoError(t, i.Start()) 207 require.NoError(t, itransport.Start()) 208 209 otransport, err := NewChannelTransport(ServiceName("caller")) 210 require.NoError(t, err) 211 o := otransport.NewSingleOutbound(chservEndpoint) 212 213 require.NoError(t, o.Start()) 214 defer o.Stop() 215 216 for _, tt := range []struct { 217 service string 218 procedure string 219 }{ 220 {"myservice", "hello"}, 221 {"subservice", "hello"}, 222 {"subservice", "world"}, 223 {"subservice2", "hello"}, 224 {"subservice2", "monde"}, 225 } { 226 ctx, cancel := context.WithTimeout(context.Background(), 200*testtime.Millisecond) 227 defer cancel() 228 res, err := o.Call( 229 ctx, 230 &transport.Request{ 231 Caller: "caller", 232 Service: tt.service, 233 Procedure: tt.procedure, 234 Encoding: raw.Encoding, 235 Body: bytes.NewReader([]byte{}), 236 }, 237 ) 238 if !assert.NoError(t, err, "failed to make call") { 239 continue 240 } 241 if !assert.Equal(t, false, res.ApplicationError, "not application error") { 242 continue 243 } 244 body, err := ioutil.ReadAll(res.Body) 245 if !assert.NoError(t, err) { 246 continue 247 } 248 assert.Equal(t, string(body), tt.service) 249 } 250 251 require.NoError(t, i.Stop()) 252 require.NoError(t, itransport.Stop()) 253 }