Esempio n. 1
0
// 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.Assert().NotNil(err)
	suite.Assert().Equal(terrors.ErrBadRequest, err.Code)
}
Esempio n. 2
0
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)
}
Esempio n. 3
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.ProtoMarshaler().MarshalBody(rsp))
					suite.Require().NoError(trans.Respond(req, rsp))
				}

			case <-trans.Tomb().Dying():
				return
			}
		}
	}()
}
Esempio n. 4
0
	"github.com/mondough/mercury"
	"github.com/mondough/mercury/transport"
	terrors "github.com/mondough/typhon/errors"
	tmsg "github.com/mondough/typhon/message"
	ttrans "github.com/mondough/typhon/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,
	}
}
Esempio n. 5
0
	"github.com/mondough/typhon/message"
	"github.com/mondough/typhon/transport"
)

const (
	DirectReplyQueue = "amq.rabbitmq.reply-to"

	connectTimeout  = 30 * time.Second
	chanSendTimeout = 10 * time.Second
	respondTimeout  = 10 * time.Second
)

var (
	ErrCouldntConnect   = errors.InternalService("", "Could not connect to RabbitMQ", nil)
	ErrDeliveriesClosed = errors.InternalService("", "Delivery channel closed", nil)
	ErrNoReplyTo        = errors.BadRequest("", "Request does not have appropriate X-Rabbit-ReplyTo header", nil)
)

type rabbitTransport struct {
	tomb          *tomb.Tomb
	connM         sync.RWMutex                       // protects conn + connReady
	conn          *RabbitConnection                  // underlying connection
	connReady     chan struct{}                      // swapped along with conn (reconnecting)
	replyQueue    string                             // message reply queue name
	inflightReqs  map[string]chan<- message.Response // correlation id: response chan
	inflightReqsM sync.Mutex                         // protects inflightReqs
	listeners     map[string]*tomb.Tomb              // service name: tomb
	listenersM    sync.RWMutex                       // protects listeners
}

// run starts the asynchronous run-loop connecting to RabbitMQ