예제 #1
0
파일: thrift.go 프로젝트: yarpc/yarpc-go
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)
	}
}
예제 #2
0
func TestAddRootService(t *testing.T) {
	tests := []struct {
		desc string
		spec *compile.ServiceSpec
		want *api.GenerateServiceRequest
	}{
		{
			desc: "empty service",
			spec: &compile.ServiceSpec{
				Name: "EmptyService",
				File: "idl/empty.thrift",
			},
			want: &api.GenerateServiceRequest{
				RootServices: []api.ServiceID{1},
				Services: map[api.ServiceID]*api.Service{
					1: {
						Name:       "EmptyService",
						ThriftName: "EmptyService",
						Functions:  []*api.Function{}, // must be non-nil
						ModuleID:   1,
					},
				},
				Modules: map[api.ModuleID]*api.Module{
					1: {
						ImportPath: "go.uber.org/thriftrw/gen/testdata/empty",
						Directory:  "empty",
					},
				},
			},
		},
		{
			desc: "Non standard names",
			spec: &compile.ServiceSpec{
				Name: "non_standard_service_name",
				File: "idl/service.thrift",
			},
			want: &api.GenerateServiceRequest{
				RootServices: []api.ServiceID{1},
				Services: map[api.ServiceID]*api.Service{
					1: {
						Name:       "NonStandardServiceName",
						ThriftName: "non_standard_service_name",
						Functions:  []*api.Function{}, // must be non-nil
						ModuleID:   1,
					},
				},
				Modules: map[api.ModuleID]*api.Module{
					1: {
						ImportPath: "go.uber.org/thriftrw/gen/testdata/service",
						Directory:  "service",
					},
				},
			},
		},
		{
			desc: "service with a parent",
			spec: &compile.ServiceSpec{
				Name: "KeyValue",
				File: "idl/kv.thrift",
				Parent: &compile.ServiceSpec{
					Name: "AbstractService",
					File: "idl/common/abstract.thrift",
				},
			},
			want: &api.GenerateServiceRequest{
				RootServices: []api.ServiceID{2},
				Services: map[api.ServiceID]*api.Service{
					1: {
						Name:       "AbstractService",
						ThriftName: "AbstractService",
						Functions:  []*api.Function{}, // must be non-nil
						ModuleID:   1,
					},
					2: {
						Name:       "KeyValue",
						ThriftName: "KeyValue",
						ParentID:   (*api.ServiceID)(ptr.Int32(1)),
						Functions:  []*api.Function{}, // must be non-nil
						ModuleID:   2,
					},
				},
				Modules: map[api.ModuleID]*api.Module{
					1: {
						ImportPath: "go.uber.org/thriftrw/gen/testdata/common/abstract",
						Directory:  "common/abstract",
					},
					2: {
						ImportPath: "go.uber.org/thriftrw/gen/testdata/kv",
						Directory:  "kv",
					},
				},
			},
		},
	}

	for _, tt := range tests {
		spec := tt.spec
		err := spec.Link(compile.EmptyScope("foo"))
		if !assert.NoError(t, err, "%v: invalid test: scope must link", tt.desc) {
			continue
		}

		importer := thriftPackageImporter{
			ImportPrefix: "go.uber.org/thriftrw/gen/testdata",
			ThriftRoot:   "idl",
		}

		g := newGenerateServiceBuilder(importer)
		if _, err := g.AddRootService(spec); assert.NoError(t, err, tt.desc) {
			assert.Equal(t, tt.want, g.Build(), tt.desc)
		}
	}
}
예제 #3
0
func TestServiceGenerator(t *testing.T) {
	transport, done := fakeEnvelopeClient()
	defer done()

	mockCtrl := gomock.NewController(t)
	defer mockCtrl.Finish()

	serviceGenerator := plugintest.NewMockServiceGenerator(mockCtrl)

	go Main(&Plugin{
		Name:             "hello",
		ServiceGenerator: serviceGenerator,
	})

	pluginClient := api.NewPluginClient(multiplex.NewClient("Plugin", transport))
	defer pluginClient.Goodbye()

	handshake, err := pluginClient.Handshake(&api.HandshakeRequest{})
	require.NoError(t, err)
	assert.Equal(t, api.APIVersion, handshake.APIVersion)
	assert.Equal(t, version.Version, *handshake.LibraryVersion)
	assert.Equal(t, "hello", handshake.Name)
	assert.Contains(t, handshake.Features, api.FeatureServiceGenerator)

	sgClient := api.NewServiceGeneratorClient(multiplex.NewClient("ServiceGenerator", transport))
	req := &api.GenerateServiceRequest{
		RootServices: []api.ServiceID{1},
		Services: map[api.ServiceID]*api.Service{
			1: {
				Name:       "MyService",
				ThriftName: "MyService",
				Functions:  []*api.Function{},
				ParentID:   (*api.ServiceID)(ptr.Int32(2)),
				ModuleID:   1,
			},
			2: {
				Name:       "BaseService",
				ThriftName: "BaseService",
				Functions: []*api.Function{
					{
						Name:       "Healthy",
						ThriftName: "healthy",
						Arguments:  []*api.Argument{},
					},
				},
				ModuleID: 1,
			},
		},
		Modules: map[api.ModuleID]*api.Module{
			1: {
				ImportPath: "go.uber.org/thriftrw/plugin/fake",
				Directory:  "fake",
			},
		},
	}

	res := &api.GenerateServiceResponse{
		Files: map[string][]byte{
			"fake/myservice/foo.go":   {1, 2, 3},
			"fake/baseservice/bar.go": {4, 5, 6},
			"fake/baz.go":             {7, 8, 9},
		},
	}

	serviceGenerator.EXPECT().Generate(req).Return(res, nil)
	gotRes, err := sgClient.Generate(req)
	if assert.NoError(t, err) {
		assert.Equal(t, res, gotRes)
	}
}
예제 #4
0
func (v *DefaultsStruct) FromWire(w wire.Value) error {
	var err error
	for _, field := range w.GetStruct().Fields {
		switch field.ID {
		case 1:
			if field.Value.Type() == wire.TI32 {
				var x int32
				x, err = field.Value.GetI32(), error(nil)
				v.RequiredPrimitive = &x
				if err != nil {
					return err
				}
			}
		case 2:
			if field.Value.Type() == wire.TI32 {
				var x int32
				x, err = field.Value.GetI32(), error(nil)
				v.OptionalPrimitive = &x
				if err != nil {
					return err
				}
			}
		case 3:
			if field.Value.Type() == wire.TI32 {
				var x enums.EnumDefault
				x, err = _EnumDefault_Read(field.Value)
				v.RequiredEnum = &x
				if err != nil {
					return err
				}
			}
		case 4:
			if field.Value.Type() == wire.TI32 {
				var x enums.EnumDefault
				x, err = _EnumDefault_Read(field.Value)
				v.OptionalEnum = &x
				if err != nil {
					return err
				}
			}
		case 5:
			if field.Value.Type() == wire.TList {
				v.RequiredList, err = _List_String_Read(field.Value.GetList())
				if err != nil {
					return err
				}
			}
		case 6:
			if field.Value.Type() == wire.TList {
				v.OptionalList, err = _List_Double_Read(field.Value.GetList())
				if err != nil {
					return err
				}
			}
		case 7:
			if field.Value.Type() == wire.TStruct {
				v.RequiredStruct, err = _Frame_Read(field.Value)
				if err != nil {
					return err
				}
			}
		case 8:
			if field.Value.Type() == wire.TStruct {
				v.OptionalStruct, err = _Edge_Read(field.Value)
				if err != nil {
					return err
				}
			}
		}
	}
	if v.RequiredPrimitive == nil {
		v.RequiredPrimitive = ptr.Int32(100)
	}
	if v.OptionalPrimitive == nil {
		v.OptionalPrimitive = ptr.Int32(200)
	}
	if v.RequiredEnum == nil {
		v.RequiredEnum = _EnumDefault_ptr(enums.EnumDefaultBar)
	}
	if v.OptionalEnum == nil {
		v.OptionalEnum = _EnumDefault_ptr(enums.EnumDefaultBaz)
	}
	if v.RequiredList == nil {
		v.RequiredList = []string{"hello", "world"}
	}
	if v.OptionalList == nil {
		v.OptionalList = []float64{1, 2, 3}
	}
	if v.RequiredStruct == nil {
		v.RequiredStruct = &Frame{Size: &Size{Height: 200, Width: 100}, TopLeft: &Point{X: 1, Y: 2}}
	}
	if v.OptionalStruct == nil {
		v.OptionalStruct = &Edge{EndPoint: &Point{X: 3, Y: 4}, StartPoint: &Point{X: 1, Y: 2}}
	}
	return nil
}
예제 #5
0
func (v *DefaultsStruct) ToWire() (wire.Value, error) {
	var (
		fields [8]wire.Field
		i      int = 0
		w      wire.Value
		err    error
	)
	if v.RequiredPrimitive == nil {
		v.RequiredPrimitive = ptr.Int32(100)
	}
	{
		w, err = wire.NewValueI32(*(v.RequiredPrimitive)), error(nil)
		if err != nil {
			return w, err
		}
		fields[i] = wire.Field{ID: 1, Value: w}
		i++
	}
	if v.OptionalPrimitive == nil {
		v.OptionalPrimitive = ptr.Int32(200)
	}
	{
		w, err = wire.NewValueI32(*(v.OptionalPrimitive)), error(nil)
		if err != nil {
			return w, err
		}
		fields[i] = wire.Field{ID: 2, Value: w}
		i++
	}
	if v.RequiredEnum == nil {
		v.RequiredEnum = _EnumDefault_ptr(enums.EnumDefaultBar)
	}
	{
		w, err = v.RequiredEnum.ToWire()
		if err != nil {
			return w, err
		}
		fields[i] = wire.Field{ID: 3, Value: w}
		i++
	}
	if v.OptionalEnum == nil {
		v.OptionalEnum = _EnumDefault_ptr(enums.EnumDefaultBaz)
	}
	{
		w, err = v.OptionalEnum.ToWire()
		if err != nil {
			return w, err
		}
		fields[i] = wire.Field{ID: 4, Value: w}
		i++
	}
	if v.RequiredList == nil {
		v.RequiredList = []string{"hello", "world"}
	}
	{
		w, err = wire.NewValueList(_List_String_ValueList(v.RequiredList)), error(nil)
		if err != nil {
			return w, err
		}
		fields[i] = wire.Field{ID: 5, Value: w}
		i++
	}
	if v.OptionalList == nil {
		v.OptionalList = []float64{1, 2, 3}
	}
	{
		w, err = wire.NewValueList(_List_Double_ValueList(v.OptionalList)), error(nil)
		if err != nil {
			return w, err
		}
		fields[i] = wire.Field{ID: 6, Value: w}
		i++
	}
	if v.RequiredStruct == nil {
		v.RequiredStruct = &Frame{Size: &Size{Height: 200, Width: 100}, TopLeft: &Point{X: 1, Y: 2}}
	}
	{
		w, err = v.RequiredStruct.ToWire()
		if err != nil {
			return w, err
		}
		fields[i] = wire.Field{ID: 7, Value: w}
		i++
	}
	if v.OptionalStruct == nil {
		v.OptionalStruct = &Edge{EndPoint: &Point{X: 3, Y: 4}, StartPoint: &Point{X: 1, Y: 2}}
	}
	{
		w, err = v.OptionalStruct.ToWire()
		if err != nil {
			return w, err
		}
		fields[i] = wire.Field{ID: 8, Value: w}
		i++
	}
	return wire.NewValueStruct(wire.Struct{Fields: fields[:i]}), nil
}
예제 #6
0
파일: behavior.go 프로젝트: yarpc/yarpc-go
// 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)
	}
}