func TestContextBuilder(t *testing.T) { ctx, cancel := tchannel.NewContextBuilder(time.Second).SetShardKey("shard").Build() defer cancel() var called bool testutils.WithServer(t, nil, func(ch *tchannel.Channel, hostPort string) { peerInfo := ch.PeerInfo() testutils.RegisterFunc(ch, "SecondService::Echo", func(ctx context.Context, args *raw.Args) (*raw.Res, error) { call := tchannel.CurrentCall(ctx) assert.Equal(t, peerInfo.ServiceName, call.CallerName(), "unexpected caller name") assert.Equal(t, "shard", call.ShardKey(), "unexpected shard key") assert.Equal(t, tchannel.Thrift, args.Format) called = true return nil, errors.New("err") }) client := NewClient(ch, ch.PeerInfo().ServiceName, &ClientOptions{ HostPort: peerInfo.HostPort, }) secondClient := gen.NewTChanSecondServiceClient(client) secondClient.Echo(ctx, "asd") assert.True(t, called, "test not called") }) }
func TestActiveCallReq(t *testing.T) { t.Skip("Test skipped due to unreliable way to test for protocol errors") ctx, cancel := NewContext(time.Second) defer cancel() // Note: This test cannot use log verification as the duplicate ID causes a log. // It does not use a verified server, as it leaks a message exchange due to the // modification of IDs in the relay. opts := testutils.NewOpts().DisableLogVerification() testutils.WithServer(t, opts, func(ch *Channel, hostPort string) { gotCall := make(chan struct{}) unblock := make(chan struct{}) testutils.RegisterFunc(ch, "blocked", func(ctx context.Context, args *raw.Args) (*raw.Res, error) { gotCall <- struct{}{} <-unblock return &raw.Res{}, nil }) relayFunc := func(outgoing bool, frame *Frame) *Frame { if outgoing && frame.Header.ID == 3 { frame.Header.ID = 2 } return frame } relayHostPort, closeRelay := testutils.FrameRelay(t, hostPort, relayFunc) defer closeRelay() firstComplete := make(chan struct{}) go func() { // This call will block until we close unblock. raw.Call(ctx, ch, relayHostPort, ch.PeerInfo().ServiceName, "blocked", nil, nil) close(firstComplete) }() // Wait for the first call to be received by the server <-gotCall // Make a new call, which should fail _, _, _, err := raw.Call(ctx, ch, relayHostPort, ch.PeerInfo().ServiceName, "blocked", nil, nil) assert.Error(t, err, "Expect error") assert.True(t, strings.Contains(err.Error(), "already active"), "expected already active error, got %v", err) close(unblock) <-firstComplete }) }
// WithVerifiedServer runs the given test function with a server channel that is verified // at the end to make sure there are no leaks (e.g. no exchanges leaked). func WithVerifiedServer(t *testing.T, opts *testutils.ChannelOpts, f func(serverCh *Channel, hostPort string)) { var ch *Channel testutils.WithServer(t, opts, func(serverCh *Channel, hostPort string) { f(serverCh, hostPort) ch = serverCh }) if !waitForChannelClose(t, ch) { return } // Check the message exchanges and make sure they are all empty. if exchangesLeft := CheckEmptyExchanges(ch); exchangesLeft != "" { t.Errorf("Found uncleared message exchanges:\n%v", exchangesLeft) } }
func (tt tchannelTransport) WithRegistry(r transport.Registry, f func(transport.UnaryOutbound)) { serverOpts := testutils.NewOpts().SetServiceName(testService) clientOpts := testutils.NewOpts().SetServiceName(testCaller) testutils.WithServer(tt.t, serverOpts, func(ch *tchannel.Channel, hostPort string) { i := tch.NewInbound(ch) require.NoError(tt.t, i.Start(transport.ServiceDetail{Name: testService, Registry: r}, transport.NoDeps), "failed to start") defer i.Stop() // ^ the server is already listening so this will just set up the // handler. client := testutils.NewClient(tt.t, clientOpts) o := tch.NewOutbound(client, tch.HostPort(hostPort)) require.NoError(tt.t, o.Start(transport.NoDeps), "failed to start outbound") defer o.Stop() f(o) }) }
func TestActiveCallReq(t *testing.T) { ctx, cancel := NewContext(time.Second) defer cancel() // Note: This test leaks a message exchange due to the modification of IDs in the relay. require.NoError(t, testutils.WithServer(nil, func(ch *Channel, hostPort string) { gotCall := make(chan struct{}) unblock := make(chan struct{}) testutils.RegisterFunc(t, ch, "blocked", func(ctx context.Context, args *raw.Args) (*raw.Res, error) { gotCall <- struct{}{} <-unblock return &raw.Res{}, nil }) relayFunc := func(outgoing bool, frame *Frame) *Frame { if outgoing && frame.Header.ID == 2 { frame.Header.ID = 3 } return frame } relayHostPort, closeRelay := testutils.FrameRelay(t, hostPort, relayFunc) defer closeRelay() go func() { // This call will block until we close unblock. raw.Call(ctx, ch, relayHostPort, ch.PeerInfo().ServiceName, "blocked", nil, nil) }() // Wait for the first call to be received by the server <-gotCall // Make a new call, which should fail _, _, _, err := raw.Call(ctx, ch, relayHostPort, ch.PeerInfo().ServiceName, "blocked", nil, nil) assert.Error(t, err, "Expect error") assert.True(t, strings.Contains(err.Error(), "already active"), "expected already active error, got %v", err) close(unblock) })) }
// WithVerifiedServer runs the given test function with a server channel that is verified // at the end to make sure there are no leaks (e.g. no exchanges leaked). func WithVerifiedServer(t *testing.T, opts *testutils.ChannelOpts, f func(serverCh *Channel, hostPort string)) { var ch *Channel testutils.WithServer(t, opts, func(serverCh *Channel, hostPort string) { f(serverCh, hostPort) ch = serverCh }) // Wait till the channel is closed for i := 0; i < 10; i++ { if ch.State() == ChannelClosed { break } runtime.Gosched() } // Check the message exchanges and make sure they are all empty. if exchangesLeft := CheckEmptyExchanges(ch); exchangesLeft != "" { t.Errorf("Found uncleared message exchanges:\n%v", exchangesLeft) } }