func jsonCall(call call, headers map[string]string, token string) (jsonResp, map[string]string, error) { peer := call.Channel.Peers().Add(call.ServerHostPort) ctx, cancel := json.NewContext(time.Second) ctx = json.WithHeaders(ctx, headers) defer cancel() var response jsonResp err := json.CallPeer(ctx, peer, serverName, "echo", &jsonResp{Token: token}, &response) return response, ctx.ResponseHeaders(), err }
// Run exercises a YARPC server with outbound TChannel requests from a rigged // client and validates behavior that might only be visible to a TChannel // client without the YARPC abstraction interposed, typically errors. func Run(t crossdock.T) { fatals := crossdock.Fatals(t) assert := crossdock.Assert(t) tests := []test{ { name: "happy path", procedure: "echo", body: []byte("{}"), headers: []byte("{}"), validate: func(res3 []byte, isAppErr bool, err error) { assert.NoError(err, "is not error") assert.False(isAppErr, "malformed body must not be application error") }, }, { name: "malformed body", procedure: "echo", body: []byte(""), headers: []byte("{}"), validate: func(res3 []byte, isAppErr bool, err error) { assert.Error(err, "is error") assert.False(isAppErr, "malformed body must not be application error") err, ok := err.(tchannel.SystemError) assert.True(ok, "malformed body must produce system error") if !ok { return } code := tchannel.GetSystemErrorCode(err) assert.Contains(err.Error(), `failed to decode "json"`, "must mention failing to decode JSON in error message") assert.Equal(tchannel.ErrCodeBadRequest, code, "must produce bad request error") }, }, // TODO test invalid headers { name: "missing procedure", procedure: "", body: []byte{}, headers: []byte("{}"), validate: func(res3 []byte, isAppErr bool, err error) { assert.Error(err, "is error") assert.False(isAppErr, "missing procedure must not produce an application error") err, ok := err.(tchannel.SystemError) assert.True(ok, "missing procedure must produce system error") if !ok { return } code := tchannel.GetSystemErrorCode(err) assert.Equal(tchannel.ErrCodeBadRequest, code, "missing procedure must produce bad request error") assert.Contains(err.Error(), "missing procedure", "must mention missing procedure in error message") }, }, { name: "invalid procedure", procedure: "no-such-procedure", body: []byte{}, headers: []byte("{}"), validate: func(res3 []byte, isAppErr bool, err error) { assert.Error(err, "is error") assert.False(isAppErr, "no-such-procedure must not produce application error") err, ok := err.(tchannel.SystemError) assert.True(ok, "no-such-procedure must produce system error") if !ok { return } code := tchannel.GetSystemErrorCode(err) assert.Equal(tchannel.ErrCodeBadRequest, code, "must produce bad request error") assert.Contains(err.Error(), `unrecognized procedure "no-such-procedure"`, "must mention unrecongized procedure in error message") }, }, { name: "bad response", procedure: "bad-response", body: []byte("{}"), headers: []byte("{}"), validate: func(res3 []byte, isAppErr bool, err error) { assert.Error(err, "is error") assert.False(isAppErr, "bad-response must not produce an application error") err, ok := err.(tchannel.SystemError) assert.True(ok, "bad-response must produce system error") if !ok { return } code := tchannel.GetSystemErrorCode(err) assert.Equal(tchannel.ErrCodeUnexpected, code, "bad-response must produce unexpected error") assert.Contains(err.Error(), `failed to encode "json"`, "must mention failure to encode JSON in error message") }, }, { name: "unexpected error", procedure: "unexpected-error", body: []byte("{}"), headers: []byte("{}"), validate: func(res3 []byte, isAppErr bool, err error) { assert.Error(err, "is error") assert.False(isAppErr, "unexpected-error procedure must not produce application error") err, ok := err.(tchannel.SystemError) assert.True(ok, "unexpected-error procedure must produce system error") code := tchannel.GetSystemErrorCode(err) assert.Equal(tchannel.ErrCodeUnexpected, code, "must produce transport error") }, }, } server := t.Param(params.Server) serverHostPort := fmt.Sprintf("%v:%v", server, serverPort) ch, err := tchannel.NewChannel(serviceName, nil) fatals.NoError(err, "could not create channel") peer := ch.Peers().Add(serverHostPort) for _, tt := range tests { var res2, res3 []byte var headers map[string]string t.Tag("case", tt.name) t.Tag("procedure", tt.procedure) ctx, cancel := json.NewContext(time.Second) defer cancel() ctx = json.WithHeaders(ctx, headers) encoding := "json" if tt.encoding != "" { encoding = tt.encoding } call, err := peer.BeginCall( ctx, serviceName, tt.procedure, &tchannel.CallOptions{Format: tchannel.Format(encoding)}, ) fatals.NoError(err, "could not begin call") err = tchannel.NewArgWriter(call.Arg2Writer()).Write(tt.headers) fatals.NoError(err, "could not write request headers") err = tchannel.NewArgWriter(call.Arg3Writer()).Write(tt.body) fatals.NoError(err, "could not write request body") err = tchannel.NewArgReader(call.Response().Arg2Reader()).Read(&res2) isAppErr := call.Response().ApplicationError() if err == nil { err = tchannel.NewArgReader(call.Response().Arg3Reader()).Read(&res3) } tt.validate(res3, isAppErr, err) } }