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 } } }() }
func (suite *errorSetSuite) TestMultiErrorPriority() { br := terrors.BadRequest("missing_param", "foo bar", nil) is := terrors.InternalService("something_broke", "hello world", nil) suite.Assert().True(higherPriority(is.Code, br.Code)) se := terrors.New("something_else", "baz", nil) suite.Assert().True(higherPriority(is.Code, se.Code)) suite.Assert().True(higherPriority(br.Code, se.Code)) es := ErrorSet{se, is, br} suite.Assert().Equal(is.Code, es.Combined().(*terrors.Error).Code) }
// TestErrors verifies that an error sent from a handler is correctly returned by a client func (suite *clientServerSuite) TestErrors() { suite.server.AddEndpoints(server.Endpoint{ Name: "error", Request: new(testproto.DummyRequest), Response: new(testproto.DummyResponse), Handler: func(req mercury.Request) (mercury.Response, error) { return nil, terrors.BadRequest("", "naughty naughty", nil) }}) cl := client.NewClient(). SetMiddleware(DefaultClientMiddleware()). Add( client.Call{ Uid: "call", Service: testServiceName, Endpoint: "error", Body: &testproto.DummyRequest{}, Response: &testproto.DummyResponse{}, }). SetTransport(suite.trans). SetTimeout(time.Second). Execute() suite.Assert().True(cl.Errors().Any()) err := cl.Errors().ForUid("call") suite.Require().NotNil(err) suite.Assert().Equal(terrors.ErrBadRequest, err.Code) rsp := mercury.FromTyphonResponse(cl.Response("call").Copy()) rsp.SetBody("FOO") // Deliberately set this to verify it is not mutated while accessing the error suite.Require().NotNil(rsp) suite.Assert().True(rsp.IsError()) suite.Assert().NotNil(rsp.Error()) suite.Assert().IsType(&terrors.Error{}, rsp.Error()) err = rsp.Error().(*terrors.Error) suite.Assert().Equal(terrors.ErrBadRequest, err.Code) suite.Assert().Equal("FOO", rsp.Body()) }
ttrans "github.com/mondough/typhon/transport" "golang.org/x/net/context" "gopkg.in/tomb.v2" "github.com/mondough/mercury" "github.com/mondough/mercury/transport" ) const ( connectTimeout = 30 * time.Second ) var ( ErrAlreadyRunning error = terrors.InternalService("", "Server is already running", nil) // empty dotted code so impl details don't leak outside ErrTransportClosed error = terrors.InternalService("", "Transport closed", nil) errEndpointNotFound = terrors.BadRequest("endpoint_not_found", "Endpoint not found", nil) defaultMiddleware []ServerMiddleware defaultMiddlewareM sync.RWMutex ) func NewServer(name string) Server { defaultMiddlewareM.RLock() middleware := defaultMiddleware defaultMiddlewareM.RUnlock() return &server{ name: name, middleware: middleware, } }