// TestJSONResponse verifies that a request sent with JSON content and an accepting JSON response, does in fact yield a // JSON response (from a proto handler) func (suite *serverSuite) TestJSONResponse() { srv := suite.server srv.AddEndpoints(Endpoint{ Name: "dummy", Request: new(testproto.DummyRequest), Response: new(testproto.DummyResponse), Handler: func(req mercury.Request) (mercury.Response, error) { request := req.Body().(*testproto.DummyRequest) return req.Response(&testproto.DummyResponse{ Pong: request.Ping, }), nil }}) req := mercury.NewRequest() req.SetService(testServiceName) req.SetEndpoint("dummy") req.SetBody(map[string]string{ "ping": "json"}) req.SetHeader(marshaling.AcceptHeader, "application/json") suite.Assert().NoError(tmsg.JSONMarshaler().MarshalBody(req)) rsp, err := suite.trans.Send(req, time.Second) suite.Require().NoError(err) suite.Require().NotNil(rsp) suite.Assert().Equal("application/json", rsp.Headers()[marshaling.ContentTypeHeader]) suite.Assert().Equal(`{"pong":"json"}`, string(rsp.Payload())) }
// TestRouting verifies a registered endpoint receives messages destined for it, and that responses are sent // appropriately func (suite *serverSuite) TestRouting() { srv := suite.server srv.AddEndpoints(Endpoint{ Name: "dummy", Request: new(testproto.DummyRequest), Response: new(testproto.DummyResponse), Handler: func(req mercury.Request) (mercury.Response, error) { request := req.Body().(*testproto.DummyRequest) rsp := req.Response(&testproto.DummyResponse{ Pong: request.Ping, }) rsp.SetHeader("X-Ping-Pong", request.Ping) return rsp, nil }}) req := mercury.NewRequest() req.SetService(testServiceName) req.SetEndpoint("dummy") req.SetBody(&testproto.DummyRequest{ Ping: "routing"}) suite.Assert().NoError(tmsg.JSONMarshaler().MarshalBody(req)) rsp, err := suite.trans.Send(req, time.Second) suite.Require().NoError(err) suite.Require().NotNil(rsp) suite.Require().NoError(tmsg.JSONUnmarshaler(new(testproto.DummyResponse)).UnmarshalPayload(rsp)) suite.Require().NotNil(rsp.Body()) suite.Require().IsType(new(testproto.DummyResponse), rsp.Body()) response := rsp.Body().(*testproto.DummyResponse) suite.Assert().Equal("routing", response.Pong) suite.Assert().Equal("routing", rsp.Headers()["X-Ping-Pong"]) }
// TestErrorResponse tests that errors are serialised and returned to callers appropriately (as we are using the // transport directly here, we actually get a response containing an error, not a transport error) func (suite *serverSuite) TestErrorResponse() { srv := suite.server srv.AddEndpoints(Endpoint{ Name: "err", Request: new(testproto.DummyRequest), Response: new(testproto.DummyResponse), Handler: func(req mercury.Request) (mercury.Response, error) { request := req.Body().(*testproto.DummyRequest) return nil, terrors.NotFound("", request.Ping, nil) }}) req := mercury.NewRequest() req.SetService(testServiceName) req.SetEndpoint("err") req.SetBody(&testproto.DummyRequest{ Ping: "Foo bar baz"}) suite.Assert().NoError(tmsg.JSONMarshaler().MarshalBody(req)) rsp_, err := suite.trans.Send(req, time.Second) suite.Assert().NoError(err) suite.Assert().NotNil(rsp_) rsp := mercury.FromTyphonResponse(rsp_) suite.Assert().True(rsp.IsError()) errResponse := &pe.Error{} suite.Assert().NoError(json.Unmarshal(rsp.Payload(), errResponse)) terr := terrors.Unmarshal(errResponse) suite.Require().NotNil(terr) suite.Assert().Equal("Foo bar baz", terr.Message, string(rsp.Payload())) suite.Assert().Equal(terrors.ErrNotFound, terr.Code) }
// TestE2E verifies parent request IDs are properly set on child requests func (suite *parentRequestIdMiddlewareSuite) TestE2E() { cli := client. NewClient(). SetTransport(suite.trans). SetMiddleware([]client.ClientMiddleware{Middleware()}) dummyOrigin := mercury.NewRequest() dummyOrigin.SetId("foobarbaz") ctx := context.WithValue(dummyOrigin.Context(), "Current-Service", testOriginServiceName) ctx = context.WithValue(ctx, "Current-Endpoint", "e2etest") dummyOrigin.SetContext(ctx) cli.Add(client.Call{ Uid: "call", Service: testServiceName, Endpoint: "foo", Context: dummyOrigin, Response: &testproto.DummyResponse{}, Body: &testproto.DummyRequest{}}) cli.Execute() suite.Assert().NoError(cli.Errors().Combined()) rsp := cli.Response("call") response := rsp.Body().(*testproto.DummyResponse) suite.Assert().NotEmpty(response.Pong) suite.Assert().Equal(response.Pong, rsp.Headers()[parentIdHeader]) }
// TestRoutingParallel sends a bunch of requests in parallel to different endpoints and checks that the responses match // correctly. 200 workers, 100 requests each. func (suite *serverSuite) TestRoutingParallel() { if testing.Short() { suite.T().Skip("Skipping TestRoutingParallel in short mode") } names := [...]string{"1", "2", "3"} srv := suite.server srv.AddEndpoints( Endpoint{ Name: names[0], Request: new(testproto.DummyRequest), Response: new(testproto.DummyResponse), Handler: func(req mercury.Request) (mercury.Response, error) { return req.Response(&testproto.DummyResponse{Pong: names[0]}), nil }}, Endpoint{ Name: names[1], Request: new(testproto.DummyRequest), Response: new(testproto.DummyResponse), Handler: func(req mercury.Request) (mercury.Response, error) { return req.Response(&testproto.DummyResponse{Pong: names[1]}), nil }}, Endpoint{ Name: names[2], Request: new(testproto.DummyRequest), Response: new(testproto.DummyResponse), Handler: func(req mercury.Request) (mercury.Response, error) { return req.Response(&testproto.DummyResponse{Pong: names[2]}), nil }}) workers := 200 wg := sync.WaitGroup{} wg.Add(workers) unmarshaler := tmsg.JSONUnmarshaler(new(testproto.DummyResponse)) work := func(i int) { defer wg.Done() rng := rand.New(rand.NewSource(time.Now().UnixNano())) ep := names[rng.Int()%len(names)] for i := 0; i < 100; i++ { req := mercury.NewRequest() req.SetService(testServiceName) req.SetEndpoint(ep) req.SetBody(&testproto.DummyRequest{}) suite.Assert().NoError(tmsg.JSONMarshaler().MarshalBody(req)) rsp, err := suite.trans.Send(req, time.Second) suite.Require().NoError(err) suite.Require().NotNil(rsp) suite.Require().NoError(unmarshaler.UnmarshalPayload(rsp)) response := rsp.Body().(*testproto.DummyResponse) suite.Assert().Equal(ep, response.Pong) } } for i := 0; i < workers; i++ { go work(i) } wg.Wait() }
func new2OldRequest(newReq typhon.Request) mercury.Request { req := mercury.NewRequest() req.SetService(newReq.Host) req.SetEndpoint(newReq.URL.Path) req.SetHeaders(fromHeader(newReq.Header)) b, _ := newReq.BodyBytes(true) req.SetPayload(b) req.SetId(newReq.Header.Get(legacyIdHeader)) req.SetContext(newReq) return req }
// Request yields a Request formed from this Call func (c Call) Request() (mercury.Request, error) { req := mercury.NewRequest() req.SetService(c.Service) req.SetEndpoint(c.Endpoint) req.SetHeaders(c.Headers) if c.Context != nil { req.SetContext(c.Context) } if c.Body != nil { req.SetBody(c.Body) if err := c.marshaler().MarshalBody(req); err != nil { return nil, terrors.WrapWithCode(err, nil, terrors.ErrBadRequest) } } return req, nil }
func main() { req := mercury.NewRequest() req.SetService("foo") req.SetEndpoint("Say.Hello") req.SetBody(&hello.Request{ Name: "John", }) tmsg.ProtoMarshaler().MarshalBody(req) trans := rabbit.NewTransport() rsp, err := trans.Send(req, time.Second) if err != nil { fmt.Println(err) return } tmsg.ProtoUnmarshaler(new(hello.Response)).UnmarshalPayload(rsp) fmt.Println(rsp.Body()) }
// TestEndpointNotFound tests that a Bad Request error is correctly returned on receiving an event for an unknown // endpoing func (suite *serverSuite) TestEndpointNotFound() { req := mercury.NewRequest() req.SetService(testServiceName) req.SetEndpoint("dummy") req.SetBody(&testproto.DummyRequest{ Ping: "routing"}) suite.Assert().NoError(tmsg.JSONMarshaler().MarshalBody(req)) rsp_, err := suite.trans.Send(req, time.Second) rsp := mercury.FromTyphonResponse(rsp_) suite.Require().NoError(err) suite.Require().NotNil(rsp) suite.Assert().True(rsp.IsError()) suite.Assert().NoError(tmsg.JSONUnmarshaler(new(pe.Error)).UnmarshalPayload(rsp)) suite.Assert().IsType(new(pe.Error), rsp.Body()) terr := terrors.Unmarshal(rsp.Body().(*pe.Error)) suite.Assert().Equal(terrors.ErrBadRequest+".endpoint_not_found", terr.Code) suite.Assert().Contains(terr.Error(), "Endpoint not found") }
// TestNilResponse tests that a nil response correctly returns a Response with an empty payload to the caller func (suite *serverSuite) TestNilResponse() { srv := suite.server srv.AddEndpoints(Endpoint{ Name: "nil", Request: new(testproto.DummyRequest), Response: new(testproto.DummyResponse), Handler: func(req mercury.Request) (mercury.Response, error) { return nil, nil }}) req := mercury.NewRequest() req.SetService(testServiceName) req.SetBody(&testproto.DummyRequest{}) suite.Assert().NoError(tmsg.JSONMarshaler().MarshalBody(req)) req.SetEndpoint("nil") rsp, err := suite.trans.Send(req, time.Second) suite.Require().NoError(err) suite.Require().NotNil(rsp) suite.Assert().Len(rsp.Payload(), 0) }
// TestJSON verifies a JSON request and response can be received from a protobuf handler func (suite *clientServerSuite) TestJSON() { suite.server.AddEndpoints( server.Endpoint{ Name: "test", Request: new(testproto.DummyRequest), Response: new(testproto.DummyResponse), Handler: func(req mercury.Request) (mercury.Response, error) { request := req.Body().(*testproto.DummyRequest) return req.Response(&testproto.DummyResponse{ Pong: request.Ping, }), nil }}) req := mercury.NewRequest() req.SetService(testServiceName) req.SetEndpoint("test") req.SetPayload([]byte(`{ "ping": "blah blah blah" }`)) req.SetHeader(marshaling.ContentTypeHeader, "application/json") req.SetHeader(marshaling.AcceptHeader, "application/json") cl := client.NewClient(). SetMiddleware(DefaultClientMiddleware()). AddRequest("call", req). SetTransport(suite.trans). SetTimeout(time.Second). Execute() suite.Assert().False(cl.Errors().Any()) rsp := cl.Response("call") suite.Assert().NotNil(rsp) var body map[string]string suite.Assert().NoError(json.Unmarshal(rsp.Payload(), &body)) suite.Assert().NotNil(body) suite.Assert().Equal(1, len(body)) suite.Assert().Equal("blah blah blah", body["pong"]) }