示例#1
0
// 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()))
}
示例#2
0
// 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"])
}
示例#3
0
// 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)
}
示例#4
0
// 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()
}
示例#5
0
文件: call.go 项目: mondough/mercury
func (c Call) marshaler() tmsg.Marshaler {
	result := tmsg.Marshaler(nil)
	if c.Headers != nil && c.Headers[marshaling.ContentTypeHeader] != "" {
		result = marshaling.Marshaler(c.Headers[marshaling.ContentTypeHeader])
	}
	if result == nil {
		result = tmsg.JSONMarshaler()
	}
	return result
}
示例#6
0
func (suite *clientSuite) SetupSuite() {
	trans := suite.TransF()
	select {
	case <-trans.Ready():
	case <-time.After(2 * time.Second):
		panic("transport not ready")
	}
	suite.trans = trans

	// Add a listener that responds blindly to all messages
	inboundChan := make(chan tmsg.Request, 10)
	trans.Listen(testServiceName, inboundChan)
	go func() {
		for {
			select {
			case _req := <-inboundChan:
				req := mercury.FromTyphonRequest(_req)
				switch req.Endpoint() {
				case "timeout":
					continue

				case "invalid-payload":
					// Wrong proto here
					rsp := req.Response(nil)
					rsp.SetPayload([]byte("†HÎß ßHøܬ∂ÑT ∑ø®K"))
					suite.Require().NoError(trans.Respond(req, rsp))

				case "error":
					err := terrors.BadRequest("", "foo bar", nil)
					rsp := req.Response(terrors.Marshal(err))
					rsp.SetHeaders(req.Headers())
					rsp.SetIsError(true)
					suite.Require().NoError(trans.Respond(req, rsp))

				case "bulls--t":
					rsp := req.Response(map[string]string{})
					rsp.SetHeaders(req.Headers())
					rsp.SetHeader(marshaling.ContentTypeHeader, "application/bulls--t")
					suite.Require().NoError(trans.Respond(req, rsp))

				default:
					rsp := req.Response(&testproto.DummyResponse{
						Pong: "Pong"})
					rsp.SetHeaders(req.Headers())
					suite.Require().NoError(tmsg.JSONMarshaler().MarshalBody(rsp))
					suite.Require().NoError(trans.Respond(req, rsp))
				}

			case <-trans.Tomb().Dying():
				return
			}
		}
	}()
}
示例#7
0
文件: srv.go 项目: mondough/mercury
// ErrorResponse constructs a response for the given request, with the given error as its contents. Mercury clients
// know how to unmarshal these errors.
func ErrorResponse(req mercury.Request, err error) mercury.Response {
	rsp := req.Response(nil)
	var terr *terrors.Error
	if err != nil {
		terr = terrors.Wrap(err, nil).(*terrors.Error)
	}
	rsp.SetBody(terrors.Marshal(terr))
	if err := tmsg.JSONMarshaler().MarshalBody(rsp); err != nil {
		log.Error(req, "[Mercury:Server] Failed to marshal error response: %v", err)
		return nil // Not much we can do here
	}
	rsp.SetIsError(true)
	return rsp
}
示例#8
0
// 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")
}
示例#9
0
// 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)
}