func runRaw(t crossdock.T, call call) { assert := crossdock.Assert(t) checks := crossdock.Checks(t) headers := []byte{ 0x00, 0x01, // 1 header 0x00, 0x05, // length = 5 'h', 'e', 'l', 'l', 'o', 0x00, 0x03, // length = 3 'r', 'a', 'w', } expectedHeaderContains := []byte{ 0x00, 0x05, // length = 5 'h', 'e', 'l', 'l', 'o', 0x00, 0x03, // length = 3 'r', 'a', 'w', } token := random.Bytes(5) resp, respHeaders, err := rawCall(call, headers, token) if checks.NoError(err, "raw: call failed") { assert.Equal(token, resp, "body echoed") assert.Contains( string(respHeaders), string(expectedHeaderContains), "headers echoed", ) } }
// remoteTimeout tests if a yarpc client returns a remote timeout error behind // the TimeoutError interface when a remote tchannel handler returns a handler // timeout. func remoteTimeout(t crossdock.T, dispatcher yarpc.Dispatcher) { assert := crossdock.Assert(t) headers := yarpc.NewHeaders() token := random.Bytes(5) _, _, err := rawCall(dispatcher, headers, "handlertimeout/raw", token) if skipOnConnRefused(t, err) { return } if !assert.Error(err, "expected an error") { return } if transport.IsBadRequestError(err) { t.Skipf("handlertimeout/raw procedure not implemented: %v", err) return } assert.True(transport.IsTimeoutError(err), "returns a TimeoutError: %T", err) form := strings.HasPrefix(err.Error(), `Timeout: call to procedure "handlertimeout/raw" of service "service" from caller "caller" timed out after`) assert.True(form, "must be a remote handler timeout: %q", err.Error()) }
// Raw implements the 'raw' behavior. func Raw(t crossdock.T) { t = createEchoT("raw", t) fatals := crossdock.Fatals(t) dispatcher := disp.Create(t) fatals.NoError(dispatcher.Start(), "could not start Dispatcher") defer dispatcher.Stop() client := raw.New(dispatcher.Channel("yarpc-test")) ctx, cancel := context.WithTimeout(context.Background(), time.Second) defer cancel() token := random.Bytes(5) resBody, _, err := client.Call(ctx, yarpc.NewReqMeta().Procedure("echo/raw"), token) crossdock.Fatals(t).NoError(err, "call to echo/raw failed: %v", err) crossdock.Assert(t).True(bytes.Equal(token, resBody), "server said: %v", resBody) }
func hello(t crossdock.T, dispatcher yarpc.Dispatcher) { assert := crossdock.Assert(t) checks := crossdock.Checks(t) // TODO headers should be at yarpc, not transport headers := yarpc.NewHeaders().With("hello", "raw") token := random.Bytes(5) resBody, resMeta, err := rawCall(dispatcher, headers, "echo/raw", token) if skipOnConnRefused(t, err) { return } if checks.NoError(err, "raw: call failed") { assert.Equal(token, resBody, "body echoed") resHeaders := internal.RemoveVariableHeaderKeys(resMeta.Headers()) assert.Equal(headers, resHeaders, "headers echoed") } }
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) } }
// RunGauntlet takes an rpc object and runs the gauntlet func RunGauntlet(t crossdock.T, c Config) { checks := crossdock.Checks(t) if c.Services == 0 { c.Services = AllServices } bytesToken := random.Bytes(10) tests := []TT{ { Function: "TestBinary", Give: []interface{}{bytesToken}, Want: bytesToken, }, { Function: "TestByte", Give: []interface{}{ptr.Int8(42)}, Want: int8(42), }, { Function: "TestDouble", Give: []interface{}{ptr.Float64(12.34)}, Want: float64(12.34), }, { Function: "TestEnum", Details: "MyNumberz", Give: []interface{}{numberzp(gauntlet.MyNumberz)}, Want: gauntlet.MyNumberz, }, { Function: "TestEnum", Details: "NumberzThree", Give: []interface{}{numberzp(gauntlet.NumberzThree)}, Want: gauntlet.NumberzThree, }, { Function: "TestEnum", Details: "unrecognized Numberz", Give: []interface{}{numberzp(gauntlet.Numberz(42))}, Want: gauntlet.Numberz(42), }, { Function: "TestException", Details: "Xception", Give: []interface{}{ptr.String("Xception")}, WantError: &gauntlet.Xception{ ErrorCode: ptr.Int32(1001), Message: ptr.String("Xception"), }, }, { Function: "TestException", Details: "TException", Give: []interface{}{ptr.String("TException")}, WantErrorLike: "great sadness", }, { Function: "TestException", Details: "no error", Give: []interface{}{ptr.String("yolo")}, }, { Function: "TestI32", Give: []interface{}{ptr.Int32(123)}, Want: int32(123), }, { Function: "TestI64", Give: []interface{}{ptr.Int64(18934714)}, Want: int64(18934714), }, { Function: "TestInsanity", Give: []interface{}{ &gauntlet.Insanity{ UserMap: map[gauntlet.Numberz]gauntlet.UserId{ gauntlet.NumberzThree: gauntlet.UserId(100), gauntlet.Numberz(100): gauntlet.UserId(200), }, Xtructs: []*gauntlet.Xtruct{ {StringThing: ptr.String("0")}, {ByteThing: ptr.Int8(1)}, {I32Thing: ptr.Int32(2)}, {I64Thing: ptr.Int64(3)}, }, }, }, Want: map[gauntlet.UserId]map[gauntlet.Numberz]*gauntlet.Insanity{ 1: { gauntlet.NumberzTwo: &gauntlet.Insanity{ UserMap: map[gauntlet.Numberz]gauntlet.UserId{ gauntlet.NumberzThree: gauntlet.UserId(100), gauntlet.Numberz(100): gauntlet.UserId(200), }, Xtructs: []*gauntlet.Xtruct{ {StringThing: ptr.String("0")}, {ByteThing: ptr.Int8(1)}, {I32Thing: ptr.Int32(2)}, {I64Thing: ptr.Int64(3)}, }, }, gauntlet.NumberzThree: &gauntlet.Insanity{ UserMap: map[gauntlet.Numberz]gauntlet.UserId{ gauntlet.NumberzThree: gauntlet.UserId(100), gauntlet.Numberz(100): gauntlet.UserId(200), }, Xtructs: []*gauntlet.Xtruct{ {StringThing: ptr.String("0")}, {ByteThing: ptr.Int8(1)}, {I32Thing: ptr.Int32(2)}, {I64Thing: ptr.Int64(3)}, }, }, }, 2: { gauntlet.NumberzSix: &gauntlet.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{}{ptr.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{}{ ptr.Int8(100), ptr.Int32(200), ptr.Int64(300), map[int16]string{1: "1", 2: "2", 3: "3"}, numberzp(gauntlet.NumberzEight), useridp(42), }, Want: &gauntlet.Xtruct{ StringThing: ptr.String("Hello2"), ByteThing: ptr.Int8(100), I32Thing: ptr.Int32(200), I64Thing: ptr.Int64(300), }, }, { Function: "TestMultiException", Details: "Xception", Give: []interface{}{ptr.String("Xception"), ptr.String("foo")}, WantError: &gauntlet.Xception{ ErrorCode: ptr.Int32(1001), Message: ptr.String("This is an Xception"), }, }, { Function: "TestMultiException", Details: "Xception2", Give: []interface{}{ptr.String("Xception2"), ptr.String("foo")}, WantError: &gauntlet.Xception2{ ErrorCode: ptr.Int32(2002), StructThing: &gauntlet.Xtruct{StringThing: ptr.String("foo")}, }, }, { Function: "TestMultiException", Details: "no error", Give: []interface{}{ptr.String("hello"), ptr.String("foo")}, Want: &gauntlet.Xtruct{StringThing: ptr.String("foo")}, }, { Function: "TestNest", Give: []interface{}{ &gauntlet.Xtruct2{ ByteThing: ptr.Int8(-1), I32Thing: ptr.Int32(-1234), StructThing: &gauntlet.Xtruct{ StringThing: ptr.String("0"), ByteThing: ptr.Int8(1), I32Thing: ptr.Int32(2), I64Thing: ptr.Int64(3), }, }, }, Want: &gauntlet.Xtruct2{ ByteThing: ptr.Int8(-1), I32Thing: ptr.Int32(-1234), StructThing: &gauntlet.Xtruct{ StringThing: ptr.String("0"), ByteThing: ptr.Int8(1), I32Thing: ptr.Int32(2), I64Thing: ptr.Int64(3), }, }, }, { Function: "TestSet", Give: []interface{}{ map[int32]struct{}{ 1: {}, 2: {}, -1: {}, -2: {}, }, }, Want: map[int32]struct{}{ 1: {}, 2: {}, -1: {}, -2: {}, }, }, { Function: "TestString", Give: []interface{}{ptr.String("hello")}, Want: "hello", }, { Function: "TestStringMap", Give: []interface{}{ map[string]string{ "foo": "bar", "hello": "world", }, }, Want: map[string]string{ "foo": "bar", "hello": "world", }, }, { Function: "TestStruct", Give: []interface{}{ &gauntlet.Xtruct{ StringThing: ptr.String("0"), ByteThing: ptr.Int8(1), I32Thing: ptr.Int32(2), I64Thing: ptr.Int64(3), }, }, Want: &gauntlet.Xtruct{ StringThing: ptr.String("0"), ByteThing: ptr.Int8(1), I32Thing: ptr.Int32(2), I64Thing: ptr.Int64(3), }, }, { Function: "TestTypedef", Give: []interface{}{useridp(42)}, Want: gauntlet.UserId(42), }, { Function: "TestVoid", Give: []interface{}{}, }, { Function: "TestOneway", Oneway: true, Give: []interface{}{ptr.Int32(123)}, WantError: nil, }, { Service: "SecondService", Function: "BlahBlah", Give: []interface{}{}, }, { Service: "SecondService", Function: "SecondtestString", Give: []interface{}{ptr.String("hello")}, Want: "hello", }, } for _, tt := range tests { if tt.Service == "" { tt.Service = "ThriftTest" } switch tt.Service { case "ThriftTest": if c.Services&ThriftTest == 0 { continue } case "SecondService": if c.Services&SecondService == 0 { continue } } t.Tag("service", tt.Service) t.Tag("function", tt.Function) //only run oneway tests if specified if !c.EnableOneway && tt.Oneway { continue } desc := BuildDesc(tt) client := buildClient(t, desc, tt.Service, c) f := client.MethodByName(tt.Function) if !checks.True(f.IsValid(), "%v: invalid function", desc) { continue } ctx, cancel := context.WithTimeout(context.Background(), time.Second) defer cancel() args := []reflect.Value{reflect.ValueOf(ctx), reflect.ValueOf(yarpc.NewReqMeta())} if give, ok := BuildArgs(t, desc, f.Type(), tt.Give, 2); 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 } Assert(t, tt, desc, got, err) } }