// 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.ProtoMarshaler().MarshalBody(req)) rsp, err := suite.trans.Send(req, time.Second) suite.Assert().NoError(err) suite.Assert().NotNil(rsp) suite.Assert().Equal(req.Service(), rsp.Service()) suite.Assert().Equal(req.Endpoint(), rsp.Endpoint()) suite.Assert().NoError(tmsg.ProtoUnmarshaler(new(testproto.DummyResponse)).UnmarshalPayload(rsp)) suite.Assert().NotNil(rsp.Body()) suite.Assert().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"]) }
// 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.ProtoUnmarshaler(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.ProtoMarshaler().MarshalBody(req)) rsp, err := suite.trans.Send(req, time.Second) suite.Assert().NoError(err) suite.Assert().NotNil(rsp) suite.Assert().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 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.ProtoMarshaler().MarshalBody(req)) rsp_, err := suite.trans.Send(req, time.Second) rsp := mercury.FromTyphonResponse(rsp_) suite.Assert().NoError(err) suite.Assert().NotNil(rsp) suite.Assert().True(rsp.IsError()) suite.Assert().NoError(tmsg.ProtoUnmarshaler(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") }
type MarshalerFactory func() tmsg.Marshaler type UnmarshalerFactory func(interface{}) tmsg.Unmarshaler type marshalerPair struct { m MarshalerFactory u UnmarshalerFactory } var ( marshalerRegistryM sync.RWMutex marshalerRegistry = map[string]marshalerPair{ ProtoContentType: { m: tmsg.ProtoMarshaler, // Wrapped so we can type assert the interface{} to a proto.Message u: func(protocol interface{}) tmsg.Unmarshaler { return tmsg.ProtoUnmarshaler(protocol.(proto.Message)) }}, JSONContentType: { m: tmsg.JSONMarshaler, u: tmsg.JSONUnmarshaler}, } ) func Register(contentType string, mc MarshalerFactory, uc UnmarshalerFactory) { if contentType == "" || mc == nil || uc == nil { return } marshalerRegistryM.Lock() defer marshalerRegistryM.Unlock() marshalerRegistry[contentType] = marshalerPair{