func BenchmarkBothSerial(b *testing.B) { serverAddr, err := setupBenchServer() require.NoError(b, err, "setupBenchServer failed") opts := testutils.NewOpts().SetFramePool(tchannel.NewSyncFramePool()) clientCh := testutils.NewClient(b, opts) for _, addr := range serverAddr { clientCh.Peers().Add(addr) } thriftClient := thrift.NewClient(clientCh, "bench-server", nil) client := gen.NewTChanSecondServiceClient(thriftClient) ctx, cancel := thrift.NewContext(10 * time.Millisecond) client.Echo(ctx, "make connection") cancel() b.ResetTimer() for i := 0; i < b.N; i++ { ctx, cancel := thrift.NewContext(10 * time.Millisecond) defer cancel() _, err := client.Echo(ctx, "hello world") if err != nil { b.Errorf("Echo failed: %v", err) } } }
func TestMakeRemoteClient(t *testing.T) { rp := &mocks.Ringpop{} rp.On("RegisterListener", mock.Anything).Return() rp.On("Lookup", "hello").Return("127.0.0.1:3001") rp.On("WhoAmI").Return("127.0.0.1:3000") serviceImpl := &servicemocks.TChanRemoteService{} serviceImpl.On("RemoteCall", mock.Anything, "hello").Return(nil) ctx, _ := thrift.NewContext(0 * time.Second) ch, err := tchannel.NewChannel("remote", nil) assert.Equal(t, err, nil, "could not create tchannel") adapter, err := NewRingpopRemoteServiceAdapter(serviceImpl, rp, ch, RemoteServiceConfiguration{ RemoteCall: &RemoteServiceRemoteCallConfiguration{ Key: func(ctx thrift.Context, name string) (string, error) { return name, nil }, }, }) tchanClient := &mocks.TChanClient{} tchanClient.On("Call", mock.Anything, "RemoteService", "RemoteCall", &RemoteServiceRemoteCallArgs{Name: "hello"}, mock.Anything).Return(true, nil) cf := adapter.(router.ClientFactory) remoteClient := cf.MakeRemoteClient(tchanClient).(TChanRemoteService) err = remoteClient.RemoteCall(ctx, "hello") assert.Equal(t, err, nil, "calling the remote client gave an error") tchanClient.AssertCalled(t, "Call", mock.Anything, "RemoteService", "RemoteCall", &RemoteServiceRemoteCallArgs{Name: "hello"}, mock.Anything) }
func TestRingpopRemoteServiceAdapterCallRemote(t *testing.T) { rp := &mocks.Ringpop{} rp.On("RegisterListener", mock.Anything).Return() rp.On("Lookup", "hello").Return("127.0.0.1:3001", nil) rp.On("WhoAmI").Return("127.0.0.1:3000", nil) serviceImpl := &servicemocks.TChanRemoteService{} serviceImpl.On("RemoteCall", mock.Anything, "hello").Return(nil) ctx, _ := thrift.NewContext(0 * time.Second) ch, err := tchannel.NewChannel("remote", nil) assert.Equal(t, err, nil, "could not create tchannel") adapter, err := NewRingpopRemoteServiceAdapter(serviceImpl, rp, ch, RemoteServiceConfiguration{ RemoteCall: &RemoteServiceRemoteCallConfiguration{ Key: func(ctx thrift.Context, name string) (string, error) { return name, nil }, }, }) assert.Equal(t, err, nil, "creation of adator gave an error") // Because it is not easily possible to stub a remote call we assert that the remote call failed. // If it didn't fail it is likely that the serviceImpl was called, which we assert that it isn't called either err = adapter.RemoteCall(ctx, "hello") assert.NotEqual(t, err, nil, "we expected an error from the remote call since it could not reach anything over the network") serviceImpl.AssertNotCalled(t, "RemoteCall", mock.Anything, "hello") }
func thriftCall(clientt thrift.TChanClient, headers map[string]string, token string) (*echo.Pong, map[string]string, error) { client := echo.NewTChanEchoClient(clientt) ctx, cancel := thrift.NewContext(time.Second) ctx = thrift.WithHeaders(ctx, headers) defer cancel() pong, err := client.Echo(ctx, &echo.Ping{Beep: token}) return pong, ctx.ResponseHeaders(), err }
func TestSetForwardedHeader(t *testing.T) { ctx, _ := thrift.NewContext(0 * time.Second) ctx = SetForwardedHeader(ctx) if ctx.Headers()["ringpop-forwarded"] != "true" { t.Errorf("ringpop forwarding header is not set") } ctx, _ = thrift.NewContext(0 * time.Second) ctx = thrift.WithHeaders(ctx, map[string]string{ "keep": "this key", }) ctx = SetForwardedHeader(ctx) if ctx.Headers()["ringpop-forwarded"] != "true" { t.Errorf("ringpop forwarding header is not set if there were headers set already") } if ctx.Headers()["keep"] != "this key" { t.Errorf("ringpop forwarding header removed a header that was already present") } }
func TestHasForwardedHeader(t *testing.T) { ctx, _ := thrift.NewContext(0 * time.Second) if HasForwardedHeader(ctx) { t.Errorf("ringpop claimed that the forwarded header was set before it was set") } ctx = SetForwardedHeader(ctx) if !HasForwardedHeader(ctx) { t.Errorf("ringpop was not able to identify that the forwarded header was set") } ctx, _ = thrift.NewContext(0 * time.Second) ctx = thrift.WithHeaders(ctx, map[string]string{ "keep": "this key", }) if HasForwardedHeader(ctx) { t.Errorf("ringpop claimed that the forwarded header was set before it was set in the case of alread present headers") } ctx = SetForwardedHeader(ctx) if !HasForwardedHeader(ctx) { t.Errorf("ringpop was not able to identify that the forwarded header was set in the case of alread present headers") } }
// Discover queries Hyperbahn for a list of peers that are currently // advertised with the specified service name. func (c *Client) Discover(serviceName string) ([]string, error) { ctx, cancel := thrift.NewContext(time.Second) defer cancel() result, err := c.hyperbahnClient.Discover(ctx, &hyperbahn.DiscoveryQuery{ServiceName: serviceName}) if err != nil { return nil, err } var hostPorts []string for _, peer := range result.GetPeers() { hostPorts = append(hostPorts, servicePeerToHostPort(peer)) } return hostPorts, nil }
func makeCall(client gen.TChanSecondService) { ctx, cancel := thrift.NewContext(*timeout) defer cancel() arg := makeArg() started := time.Now() res, err := client.Echo(ctx, arg) if err != nil { fmt.Println("failed:", err) return } if res != arg { log.Fatalf("Echo gave different string!") } duration := time.Since(started) fmt.Println(duration) }
func runClient2(hyperbahnService string, addr net.Addr) error { tchan, err := tchannel.NewChannel("client2", optsFor("client2")) if err != nil { return err } tchan.Peers().Add(addr.String()) tclient := thrift.NewClient(tchan, hyperbahnService, nil) client := gen.NewTChanSecondClient(tclient) go func() { for { ctx, cancel := thrift.NewContext(time.Second) client.Test(ctx) cancel() time.Sleep(100 * time.Millisecond) } }() return nil }
func withSetup(t *testing.T, f func(ctx thrift.Context, args testArgs)) { args := testArgs{ s: new(mocks.TChanTCollector), } ctx, cancel := thrift.NewContext(time.Second * 10) defer cancel() // Start server tchan := setupServer(t, args.s) defer tchan.Close() // Get client1 args.c = getClient(t, tchan.PeerInfo().HostPort) f(ctx, args) args.s.AssertExpectations(t) }
func (c *internalClient) ThriftCallBuffer(latencies []time.Duration) error { return c.makeCalls(latencies, func() (time.Duration, error) { ctx, cancel := thrift.NewContext(c.opts.timeout) defer cancel() started := time.Now() res, err := c.tClient.Echo(ctx, c.argStr) duration := time.Since(started) if err != nil { return 0, err } if c.checkResult { if res != c.argStr { panic("thrift Echo returned wrong result") } } return duration, nil }) }
func runClient1(hyperbahnService string, addr net.Addr) error { tchan, err := tchannel.NewChannel("client1", optsFor("client1")) if err != nil { return err } tchan.Peers().Add(addr.String()) tclient := thrift.NewClient(tchan, hyperbahnService, nil) client := gen.NewTChanFirstClient(tclient) go func() { for { ctx, cancel := thrift.NewContext(time.Second) res, err := client.Echo(ctx, "Hi") log.Println("Echo(Hi) = ", res, ", err: ", err) log.Println("AppError() = ", client.AppError(ctx)) log.Println("BaseCall() = ", client.BaseCall(ctx)) cancel() time.Sleep(100 * time.Millisecond) } }() return nil }
func main() { ch, err := tchannel.NewChannel("tcheck", nil) if err != nil { fmt.Println("failed to create tchannel:", err) os.Exit(1) } hostsFile := flag.String("hostsFile", "/etc/uber/hyperbahn/hosts.json", "hyperbahn hosts file") serviceName := flag.String("serviceName", "hyperbahn", "service name to check health of") peer := flag.String("peer", "", "peer to hit directly") flag.Parse() var config hyperbahn.Configuration if *peer != "" { config = hyperbahn.Configuration{InitialNodes: []string{*peer}} } else { config = hyperbahn.Configuration{InitialNodesFile: *hostsFile} } hyperbahn.NewClient(ch, config, nil) thriftClient := thrift.NewClient(ch, *serviceName, nil) client := meta.NewTChanMetaClient(thriftClient) ctx, cancel := thrift.NewContext(time.Second) defer cancel() val, err := client.Health(ctx) if err != nil { fmt.Printf("NOT OK %v\nError: %v\n", *serviceName, err) os.Exit(2) } else if val.Ok != true { fmt.Printf("NOT OK %v\n", *val.Message) os.Exit(3) } else { fmt.Printf("OK\n") } }
func TestRingpopRemoteServiceAdapterCallLocal(t *testing.T) { rp := &mocks.Ringpop{} rp.On("RegisterListener", mock.Anything).Return() rp.On("Lookup", "hello").Return("127.0.0.1:3000", nil) rp.On("WhoAmI").Return("127.0.0.1:3000", nil) serviceImpl := &servicemocks.TChanRemoteService{} serviceImpl.On("RemoteCall", mock.Anything, "hello").Return(nil) ctx, _ := thrift.NewContext(0 * time.Second) adapter, err := NewRingpopRemoteServiceAdapter(serviceImpl, rp, nil, RemoteServiceConfiguration{ RemoteCall: &RemoteServiceRemoteCallConfiguration{ Key: func(ctx thrift.Context, name string) (string, error) { return name, nil }, }, }) assert.Equal(t, err, nil, "creation of adator gave an error") err = adapter.RemoteCall(ctx, "hello") assert.Equal(t, err, nil, "calling RemoteCall gave an error") serviceImpl.AssertCalled(t, "RemoteCall", mock.Anything, "hello") }
func runGauntlet(t crossdock.T, clientt thrift.TChanClient) { checks := crossdock.Checks(t) token := random.String(5) bytesToken := random.Bytes(1) tests := []gauntlet.TT{ { Function: "TestBinary", Give: []interface{}{bytesToken}, Want: bytesToken, }, { Function: "TestByte", Give: []interface{}{int8(42)}, Want: int8(42), }, { Function: "TestDouble", Give: []interface{}{float64(12.34)}, Want: float64(12.34), }, { Function: "TestEnum", Details: "MyNumberz", Give: []interface{}{gauntlet_tchannel.Numberz(gauntlet_tchannel.MyNumberz)}, Want: gauntlet_tchannel.Numberz(gauntlet_tchannel.MyNumberz), }, { Function: "TestEnum", Details: "NumberzThree", Give: []interface{}{gauntlet_tchannel.Numberz_THREE}, Want: gauntlet_tchannel.Numberz_THREE, }, { Function: "TestEnum", Details: "unrecognized Numberz", Give: []interface{}{gauntlet_tchannel.Numberz(42)}, Want: gauntlet_tchannel.Numberz(42), }, { Function: "TestException", Details: "Xception", Give: []interface{}{"Xception"}, WantError: &gauntlet_tchannel.Xception{ ErrorCode: ptr.Int32(1001), Message: ptr.String("Xception"), }, }, { Function: "TestException", Details: "TException", Give: []interface{}{"TException"}, WantErrorLike: `UnexpectedError: error for procedure "ThriftTest::testException" of service "yarpc-test": great sadness`, }, { Function: "TestException", Details: "no error", Give: []interface{}{"yolo"}, }, { Function: "TestI32", Give: []interface{}{int32(123)}, Want: int32(123), }, { Function: "TestI64", Give: []interface{}{int64(18934714)}, Want: int64(18934714), }, { Function: "TestInsanity", Give: []interface{}{ &gauntlet_tchannel.Insanity{ UserMap: map[gauntlet_tchannel.Numberz]gauntlet_tchannel.UserId{ gauntlet_tchannel.Numberz_THREE: gauntlet_tchannel.UserId(100), gauntlet_tchannel.Numberz(100): gauntlet_tchannel.UserId(200), }, Xtructs: []*gauntlet_tchannel.Xtruct{ {StringThing: ptr.String("0")}, {ByteThing: ptr.Int8(1)}, {I32Thing: ptr.Int32(2)}, {I64Thing: ptr.Int64(3)}, }, }, }, Want: map[gauntlet_tchannel.UserId]map[gauntlet_tchannel.Numberz]*gauntlet_tchannel.Insanity{ 1: { gauntlet_tchannel.Numberz_TWO: &gauntlet_tchannel.Insanity{ UserMap: map[gauntlet_tchannel.Numberz]gauntlet_tchannel.UserId{ gauntlet_tchannel.Numberz_THREE: gauntlet_tchannel.UserId(100), gauntlet_tchannel.Numberz(100): gauntlet_tchannel.UserId(200), }, Xtructs: []*gauntlet_tchannel.Xtruct{ {StringThing: ptr.String("0")}, {ByteThing: ptr.Int8(1)}, {I32Thing: ptr.Int32(2)}, {I64Thing: ptr.Int64(3)}, }, }, gauntlet_tchannel.Numberz_THREE: &gauntlet_tchannel.Insanity{ UserMap: map[gauntlet_tchannel.Numberz]gauntlet_tchannel.UserId{ gauntlet_tchannel.Numberz_THREE: gauntlet_tchannel.UserId(100), gauntlet_tchannel.Numberz(100): gauntlet_tchannel.UserId(200), }, Xtructs: []*gauntlet_tchannel.Xtruct{ {StringThing: ptr.String("0")}, {ByteThing: ptr.Int8(1)}, {I32Thing: ptr.Int32(2)}, {I64Thing: ptr.Int64(3)}, }, }, }, 2: { gauntlet_tchannel.Numberz_SIX: &gauntlet_tchannel.Insanity{}, }, }, }, { Function: "TestList", Give: []interface{}{[]int32{1, 2, 3}}, Want: []int32{1, 2, 3}, }, { Function: "TestMap", Give: []interface{}{map[int32]int32{1: 2, 3: 4, 5: 6}}, Want: map[int32]int32{1: 2, 3: 4, 5: 6}, }, { Function: "TestMapMap", Give: []interface{}{int32(42)}, Want: map[int32]map[int32]int32{ -4: { -4: -4, -3: -3, -2: -2, -1: -1, }, 4: { 1: 1, 2: 2, 3: 3, 4: 4, }, }, }, { Function: "TestMulti", Give: []interface{}{ int8(100), int32(200), int64(300), map[int16]string{1: "1", 2: "2", 3: "3"}, gauntlet_tchannel.Numberz_EIGHT, gauntlet_tchannel.UserId(42), }, Want: &gauntlet_tchannel.Xtruct{ StringThing: ptr.String("Hello2"), ByteThing: ptr.Int8(100), I32Thing: ptr.Int32(200), I64Thing: ptr.Int64(300), }, }, { Function: "TestMultiException", Details: "Xception", Give: []interface{}{"Xception", "foo"}, WantError: &gauntlet_tchannel.Xception{ ErrorCode: ptr.Int32(1001), Message: ptr.String("This is an Xception"), }, }, { Function: "TestMultiException", Details: "Xception2", Give: []interface{}{"Xception2", "foo"}, WantError: &gauntlet_tchannel.Xception2{ ErrorCode: ptr.Int32(2002), StructThing: &gauntlet_tchannel.Xtruct{StringThing: ptr.String("foo")}, }, }, { Function: "TestMultiException", Details: "no error", Give: []interface{}{"hello", "foo"}, Want: &gauntlet_tchannel.Xtruct{StringThing: ptr.String("foo")}, }, { Function: "TestNest", Give: []interface{}{ &gauntlet_tchannel.Xtruct2{ ByteThing: ptr.Int8(-1), I32Thing: ptr.Int32(-1234), StructThing: &gauntlet_tchannel.Xtruct{ StringThing: ptr.String("0"), ByteThing: ptr.Int8(1), I32Thing: ptr.Int32(2), I64Thing: ptr.Int64(3), }, }, }, Want: &gauntlet_tchannel.Xtruct2{ ByteThing: ptr.Int8(-1), I32Thing: ptr.Int32(-1234), StructThing: &gauntlet_tchannel.Xtruct{ StringThing: ptr.String("0"), ByteThing: ptr.Int8(1), I32Thing: ptr.Int32(2), I64Thing: ptr.Int64(3), }, }, }, { Function: "TestSet", Give: []interface{}{ map[int32]bool{ 1: true, 2: true, -1: true, -2: true, }, }, Want: map[int32]bool{ 1: true, 2: true, -1: true, -2: true, }, }, { Function: "TestString", Give: []interface{}{token}, Want: token, }, { Function: "TestStringMap", Give: []interface{}{ map[string]string{ "foo": "bar", "hello": "world", }, }, Want: map[string]string{ "foo": "bar", "hello": "world", }, }, { Function: "TestStruct", Give: []interface{}{ &gauntlet_tchannel.Xtruct{ StringThing: ptr.String("0"), ByteThing: ptr.Int8(1), I32Thing: ptr.Int32(2), I64Thing: ptr.Int64(3), }, }, Want: &gauntlet_tchannel.Xtruct{ StringThing: ptr.String("0"), ByteThing: ptr.Int8(1), I32Thing: ptr.Int32(2), I64Thing: ptr.Int64(3), }, }, { Function: "TestTypedef", Give: []interface{}{gauntlet_tchannel.UserId(42)}, Want: gauntlet_tchannel.UserId(42), }, { Function: "TestVoid", Give: []interface{}{}, }, { Service: "SecondService", Function: "BlahBlah", Give: []interface{}{}, }, { Service: "SecondService", Function: "SecondtestString", Give: []interface{}{"hello"}, Want: "hello", }, } for _, tt := range tests { desc := gauntlet.BuildDesc(tt) client := buildClient(t, desc, tt.Service, clientt) f := client.MethodByName(tt.Function) if !checks.True(f.IsValid(), "%v: invalid function", desc) { continue } ctx, cancel := thrift.NewContext(time.Second) defer cancel() args := []reflect.Value{reflect.ValueOf(ctx)} if give, ok := gauntlet.BuildArgs(t, desc, f.Type(), tt.Give, 1); ok { args = append(args, give...) } else { continue } got, err := extractCallResponse(t, desc, f.Call(args)) if isUnrecognizedProcedure(err) { t.Skipf("%v: procedure not defined", desc) continue } gauntlet.Assert(t, tt, desc, got, err) } }
func createContext() (thrift.Context, func()) { ctx, cancel := thrift.NewContext(time.Second) ctx = thrift.WithHeaders(ctx, map[string]string{"user": curUser}) return ctx, cancel }