예제 #1
0
// RequireHeader requires a request header to match a value pattern. If the
// header is missing or does not match then the failureStatus is the response
// (e.g. http.StatusUnauthorized). If pathPattern is nil then any path is
// included. If requiredHeaderValue is nil then any value is accepted so long as
// the header is non-empty.
func RequireHeader(
	service *goa.Service,
	pathPattern *regexp.Regexp,
	requiredHeaderName string,
	requiredHeaderValue *regexp.Regexp,
	failureStatus int) goa.Middleware {

	return func(h goa.Handler) goa.Handler {
		return func(ctx context.Context, rw http.ResponseWriter, req *http.Request) (err error) {
			if pathPattern == nil || pathPattern.MatchString(req.URL.Path) {
				matched := false
				headerValue := req.Header.Get(requiredHeaderName)
				if len(headerValue) > 0 {
					if requiredHeaderValue == nil {
						matched = true
					} else {
						matched = requiredHeaderValue.MatchString(headerValue)
					}
				}
				if matched {
					err = h(ctx, rw, req)
				} else {
					err = service.Send(ctx, failureStatus, http.StatusText(failureStatus))
				}
			} else {
				err = h(ctx, rw, req)
			}
			return
		}
	}
}
예제 #2
0
// MountAeController "mounts" a Ae resource controller on the given service.
func MountAeController(service *goa.Service, ctrl AeController) {
	initService(service)
	var h goa.Handler

	h = func(ctx context.Context, rw http.ResponseWriter, req *http.Request) error {
		// Check if there was an error loading the request
		if err := goa.ContextError(ctx); err != nil {
			return err
		}
		// Build the context
		rctx, err := NewHealthAeContext(ctx, service)
		if err != nil {
			return err
		}
		return ctrl.Health(rctx)
	}
	service.Mux.Handle("GET", "/_ah/health", ctrl.MuxHandler("Health", h, nil))
	service.LogInfo("mount", "ctrl", "Ae", "action", "Health", "route", "GET /_ah/health")

	h = func(ctx context.Context, rw http.ResponseWriter, req *http.Request) error {
		// Check if there was an error loading the request
		if err := goa.ContextError(ctx); err != nil {
			return err
		}
		// Build the context
		rctx, err := NewStartAeContext(ctx, service)
		if err != nil {
			return err
		}
		return ctrl.Start(rctx)
	}
	service.Mux.Handle("GET", "/_ah/start", ctrl.MuxHandler("Start", h, nil))
	service.LogInfo("mount", "ctrl", "Ae", "action", "Start", "route", "GET /_ah/start")
}
예제 #3
0
// ErrorHandler turns a Go error into an HTTP response. It should be placed in the middleware chain
// below the logger middleware so the logger properly logs the HTTP response. ErrorHandler
// understands instances of goa.Error and returns the status and response body embodied in them,
// it turns other Go error types into a 500 internal error response.
// If verbose is false the details of internal errors is not included in HTTP responses.
func ErrorHandler(service *goa.Service, verbose bool) goa.Middleware {
	return func(h goa.Handler) goa.Handler {
		return func(ctx context.Context, rw http.ResponseWriter, req *http.Request) error {
			e := h(ctx, rw, req)
			if e == nil {
				return nil
			}

			status := http.StatusInternalServerError
			var respBody interface{}
			if err, ok := e.(*goa.Error); ok {
				status = err.Status
				respBody = err
				goa.ContextResponse(ctx).ErrorCode = err.Code
				rw.Header().Set("Content-Type", goa.ErrorMediaIdentifier)
			} else {
				respBody = e.Error()
				rw.Header().Set("Content-Type", "text/plain")
			}
			if status >= 500 && status < 600 {
				reqID := ctx.Value(reqIDKey)
				if reqID == nil {
					reqID = shortID()
					ctx = context.WithValue(ctx, reqIDKey, reqID)
				}
				goa.LogError(ctx, "uncaught error", "id", reqID, "msg", respBody)
				if !verbose {
					rw.Header().Set("Content-Type", goa.ErrorMediaIdentifier)
					respBody = goa.ErrInternal("internal error [%s]", reqID)
				}
			}
			return service.Send(ctx, status, respBody)
		}
	}
}
예제 #4
0
// NewWorkItemLinkController creates a work-item-link controller.
func NewWorkItemLinkController(service *goa.Service, db application.DB) *WorkItemLinkController {
	if db == nil {
		panic("db must not be nil")
	}
	return &WorkItemLinkController{
		Controller: service.NewController("WorkItemLinkController"),
		db:         db,
	}
}
예제 #5
0
// unmarshalCreateBottlePayload unmarshals the request body into the context request data Payload field.
func unmarshalCreateBottlePayload(ctx context.Context, service *goa.Service, req *http.Request) error {
	payload := &createBottlePayload{}
	if err := service.DecodeRequest(req, payload); err != nil {
		return err
	}
	if err := payload.Validate(); err != nil {
		return err
	}
	goa.ContextRequest(ctx).Payload = payload.Publicize()
	return nil
}
예제 #6
0
// StartAeOK runs the method Start of the given controller with the given parameters.
// It returns the response writer so it's possible to inspect the response headers.
// If ctx is nil then context.Background() is used.
// If service is nil then a default service is created.
func StartAeOK(t goatest.TInterface, ctx context.Context, service *goa.Service, ctrl app.AeController) http.ResponseWriter {
	// Setup service
	var (
		logBuf bytes.Buffer
		resp   interface{}

		respSetter goatest.ResponseSetterFunc = func(r interface{}) { resp = r }
	)
	if service == nil {
		service = goatest.Service(&logBuf, respSetter)
	} else {
		logger := log.New(&logBuf, "", log.Ltime)
		service.WithLogger(goa.NewLogger(logger))
		newEncoder := func(io.Writer) goa.Encoder { return respSetter }
		service.Encoder = goa.NewHTTPEncoder() // Make sure the code ends up using this decoder
		service.Encoder.Register(newEncoder, "*/*")
	}

	// Setup request context
	rw := httptest.NewRecorder()
	u := &url.URL{
		Path: fmt.Sprintf("/_ah/start"),
	}
	req, err := http.NewRequest("GET", u.String(), nil)
	if err != nil {
		panic("invalid test " + err.Error()) // bug
	}
	prms := url.Values{}
	if ctx == nil {
		ctx = context.Background()
	}
	goaCtx := goa.NewContext(goa.WithAction(ctx, "AeTest"), rw, req, prms)
	startCtx, err := app.NewStartAeContext(goaCtx, service)
	if err != nil {
		panic("invalid test data " + err.Error()) // bug
	}

	// Perform action
	err = ctrl.Start(startCtx)

	// Validate response
	if err != nil {
		t.Fatalf("controller returned %s, logs:\n%s", err, logBuf.String())
	}
	if rw.Code != 200 {
		t.Errorf("invalid response status code: got %+v, expected 200", rw.Code)
	}

	// Return results
	return rw
}
예제 #7
0
// ErrorHandler turns a Go error into an JSONAPI HTTP response. It should be placed in the middleware chain
// below the logger middleware so the logger properly logs the HTTP response. ErrorHandler
// understands instances of goa.ServiceError and returns the status and response body embodied in
// them, it turns other Go error types into a 500 internal error response.
// If verbose is false the details of internal errors is not included in HTTP responses.
// If you use github.com/pkg/errors then wrapping the error will allow a trace to be printed to the logs
func ErrorHandler(service *goa.Service, verbose bool) goa.Middleware {
	return func(h goa.Handler) goa.Handler {
		return func(ctx context.Context, rw http.ResponseWriter, req *http.Request) error {
			e := h(ctx, rw, req)
			if e == nil {
				return nil
			}
			cause := errs.Cause(e)
			status := http.StatusInternalServerError
			var respBody interface{}
			respBody, status = ErrorToJSONAPIErrors(e)
			rw.Header().Set("Content-Type", ErrorMediaIdentifier)
			if err, ok := cause.(goa.ServiceError); ok {
				status = err.ResponseStatus()
				//respBody = err
				goa.ContextResponse(ctx).ErrorCode = err.Token()
				//rw.Header().Set("Content-Type", ErrorMediaIdentifier)
			} else {
				//respBody = e.Error()
				//rw.Header().Set("Content-Type", "text/plain")
			}
			if status >= 500 && status < 600 {
				//reqID := ctx.Value(reqIDKey)
				reqID := ctx.Value(1) // TODO remove this hack
				if reqID == nil {
					reqID = shortID()
					//ctx = context.WithValue(ctx, reqIDKey, reqID)
					ctx = context.WithValue(ctx, 1, reqID) // TODO remove this hack
				}
				log.Error(ctx, map[string]interface{}{
					"msg": respBody,
					"err": fmt.Sprintf("%+v", e),
				}, "uncaught error detected in ErrorHandler")

				if !verbose {
					rw.Header().Set("Content-Type", goa.ErrorMediaIdentifier)
					msg := errors.NewInternalError(fmt.Sprintf("%s [%s]", http.StatusText(http.StatusInternalServerError), reqID))
					//respBody = goa.ErrInternal(msg)
					respBody, status = ErrorToJSONAPIErrors(msg)
					// Preserve the ID of the original error as that's what gets logged, the client
					// received error ID must match the original
					// TODO for JSONAPI this won't work I guess.
					if origErrID := goa.ContextResponse(ctx).ErrorCode; origErrID != "" {
						respBody.(*goa.ErrorResponse).ID = origErrID
					}
				}
			}
			return service.Send(ctx, status, respBody)
		}
	}
}
예제 #8
0
// ErrorHandler turns a Go error into an HTTP response. It should be placed in the middleware chain
// below the logger middleware so the logger properly logs the HTTP response. ErrorHandler
// understands instances of goa.ServiceError and returns the status and response body embodied in
// them, it turns other Go error types into a 500 internal error response.
// If verbose is false the details of internal errors is not included in HTTP responses.
// If you use github.com/pkg/errors then wrapping the error will allow a trace to be printed to the logs
func ErrorHandler(service *goa.Service, verbose bool) goa.Middleware {
	return func(h goa.Handler) goa.Handler {
		return func(ctx context.Context, rw http.ResponseWriter, req *http.Request) error {
			e := h(ctx, rw, req)
			if e == nil {
				return nil
			}
			cause := errors.Cause(e)
			status := http.StatusInternalServerError
			var respBody interface{}
			if err, ok := cause.(goa.ServiceError); ok {
				status = err.ResponseStatus()
				respBody = err
				goa.ContextResponse(ctx).ErrorCode = err.Token()
				rw.Header().Set("Content-Type", goa.ErrorMediaIdentifier)
			} else {
				respBody = e.Error()
				rw.Header().Set("Content-Type", "text/plain")
			}
			if status >= 500 && status < 600 {
				reqID := ctx.Value(reqIDKey)
				if reqID == nil {
					reqID = shortID()
					ctx = context.WithValue(ctx, reqIDKey, reqID)
				}
				goa.LogError(ctx, "uncaught error", "err", fmt.Sprintf("%+v", e), "id", reqID, "msg", respBody)
				if !verbose {
					rw.Header().Set("Content-Type", goa.ErrorMediaIdentifier)
					msg := fmt.Sprintf("%s [%s]", http.StatusText(http.StatusInternalServerError), reqID)
					respBody = goa.ErrInternal(msg)
					// Preserve the ID of the original error as that's what gets logged, the client
					// received error ID must match the original
					if origErrID := goa.ContextResponse(ctx).ErrorCode; origErrID != "" {
						respBody.(*goa.ErrorResponse).ID = origErrID
					}
				}
			}
			return service.Send(ctx, status, respBody)
		}
	}
}
예제 #9
0
// MountSpecController "mounts" a Spec resource controller on the given service.
func MountSpecController(service *goa.Service, ctrl SpecController) {
	initService(service)
	var h goa.Handler
	service.Mux.Handle("OPTIONS", "/swagger/spec", ctrl.MuxHandler("preflight", handleSpecOrigin(cors.HandlePreflight()), nil))

	h = func(ctx context.Context, rw http.ResponseWriter, req *http.Request) error {
		// Check if there was an error loading the request
		if err := goa.ContextError(ctx); err != nil {
			return err
		}
		// Build the context
		rctx, err := NewShowSpecContext(ctx, service)
		if err != nil {
			return err
		}
		return ctrl.Show(rctx)
	}
	h = handleSpecOrigin(h)
	service.Mux.Handle("GET", "/swagger/spec", ctrl.MuxHandler("Show", h, nil))
	service.LogInfo("mount", "ctrl", "Spec", "action", "Show", "route", "GET /swagger/spec")
}
예제 #10
0
// MountBottleController "mounts" a Bottle resource controller on the given service.
func MountBottleController(service *goa.Service, ctrl BottleController) {
	initService(service)
	var h goa.Handler

	h = func(ctx context.Context, rw http.ResponseWriter, req *http.Request) error {
		// Check if there was an error loading the request
		if err := goa.ContextError(ctx); err != nil {
			return err
		}
		// Build the context
		rctx, err := NewCreateBottleContext(ctx, service)
		if err != nil {
			return err
		}
		// Build the payload
		if rawPayload := goa.ContextRequest(ctx).Payload; rawPayload != nil {
			rctx.Payload = rawPayload.(*CreateBottlePayload)
		} else {
			return goa.MissingPayloadError()
		}
		return ctrl.Create(rctx)
	}
	service.Mux.Handle("POST", "/bottles", ctrl.MuxHandler("Create", h, unmarshalCreateBottlePayload))
	service.LogInfo("mount", "ctrl", "Bottle", "action", "Create", "route", "POST /bottles")

	h = func(ctx context.Context, rw http.ResponseWriter, req *http.Request) error {
		// Check if there was an error loading the request
		if err := goa.ContextError(ctx); err != nil {
			return err
		}
		// Build the context
		rctx, err := NewShowBottleContext(ctx, service)
		if err != nil {
			return err
		}
		return ctrl.Show(rctx)
	}
	service.Mux.Handle("GET", "/bottles/:id", ctrl.MuxHandler("Show", h, nil))
	service.LogInfo("mount", "ctrl", "Bottle", "action", "Show", "route", "GET /bottles/:id")
}
예제 #11
0
// MountSwaggerController "mounts" a Swagger resource controller on the given service.
func MountSwaggerController(service *goa.Service, ctrl SwaggerController) {
	initService(service)
	var h goa.Handler

	h = ctrl.FileHandler("/swagger-ui/*filepath", "swagger-ui/")
	service.Mux.Handle("GET", "/swagger-ui/*filepath", ctrl.MuxHandler("serve", h, nil))
	service.LogInfo("mount", "ctrl", "Swagger", "files", "swagger-ui/", "route", "GET /swagger-ui/*filepath")

	h = ctrl.FileHandler("/swagger.json", "swagger/swagger.json")
	service.Mux.Handle("GET", "/swagger.json", ctrl.MuxHandler("serve", h, nil))
	service.LogInfo("mount", "ctrl", "Swagger", "files", "swagger/swagger.json", "route", "GET /swagger.json")

	h = ctrl.FileHandler("/swagger-ui/", "swagger-ui/index.html")
	service.Mux.Handle("GET", "/swagger-ui/", ctrl.MuxHandler("serve", h, nil))
	service.LogInfo("mount", "ctrl", "Swagger", "files", "swagger-ui/index.html", "route", "GET /swagger-ui/")
}
예제 #12
0
// MountPreflightController mounts the handlers for the CORS preflight requests onto service.
func MountPreflightController(service goa.Service, spec Specification) {
	for _, res := range spec {
		path := res.Path
		if res.IsPathPrefix {
			if strings.HasSuffix(path, "/") {
				path += "*cors"
			} else {
				path += "/*cors"
			}
		}
		handle := service.ServeMux().Lookup("OPTIONS", path)
		if handle == nil {
			h := func(ctx *goa.Context) error {
				return ctx.Respond(200, nil)
			}
			ctrl := service.NewController("cors")
			service.ServeMux().Handle("OPTIONS", path, ctrl.HandleFunc("preflight", h, nil))
		}
	}
}
예제 #13
0
// NewWorkItemCommentsController creates a work-item-relationships-comments controller.
func NewWorkItemCommentsController(service *goa.Service, db application.DB) *WorkItemCommentsController {
	return &WorkItemCommentsController{Controller: service.NewController("WorkItemRelationshipsCommentsController"), db: db}
}
예제 #14
0
// NewUsersController creates a users controller.
func NewUsersController(service *goa.Service, db application.DB) *UsersController {
	return &UsersController{Controller: service.NewController("UsersController"), db: db}
}
예제 #15
0
// NewTrackerqueryController creates a trackerquery controller.
func NewTrackerqueryController(service *goa.Service, db application.DB, scheduler *remoteworkitem.Scheduler) *TrackerqueryController {
	return &TrackerqueryController{Controller: service.NewController("TrackerqueryController"), db: db, scheduler: scheduler}
}
예제 #16
0
	Describe("GetMany", func() {
		It("returns nil if not initialized", func() {
			Ω(ctx.GetMany("foo")).Should(BeNil())
		})
	})

	Describe("RawPayload", func() {
		It("returns nil if not initialized", func() {
			Ω(ctx.RawPayload()).Should(BeNil())
		})
	})

	Context("with a request response", func() {
		const appName = "foo"
		var app goa.Service
		const resName = "res"
		const actName = "act"
		var handler, unmarshaler goa.Handler
		const reqBody = `"body"`
		const respStatus = 200
		var respContent = []byte("response")
		var handleFunc goa.HandleFunc
		var rw http.ResponseWriter
		var request *http.Request
		var params url.Values

		BeforeEach(func() {
			app = goa.New(appName)
			handler = func(c *goa.Context) error {
				ctx = c
예제 #17
0
// MountAccountController "mounts" a Account resource controller on the given service.
func MountAccountController(service goa.Service, ctrl AccountController) {
	// Setup encoders and decoders. This is idempotent and is done by each MountXXX function.
	tmp15 := goa.GobEncoderFactory()
	service.SetEncoder(tmp15, false, "application/gob", "application/x-gob")
	tmp16 := goa.JSONEncoderFactory()
	service.SetEncoder(tmp16, true, "application/json")
	tmp17 := goa.XMLEncoderFactory()
	service.SetEncoder(tmp17, false, "application/xml", "text/xml")
	tmp18 := goa.GobDecoderFactory()
	service.SetDecoder(tmp18, false, "application/gob", "application/x-gob")
	tmp19 := goa.JSONDecoderFactory()
	service.SetDecoder(tmp19, true, "application/json")
	tmp20 := goa.XMLDecoderFactory()
	service.SetDecoder(tmp20, false, "application/xml", "text/xml")

	// Setup endpoint handler
	var h goa.Handler
	mux := service.ServeMux()
	h = func(c *goa.Context) error {
		ctx, err := NewCreateAccountContext(c)
		ctx.Payload = ctx.RawPayload().(*CreateAccountPayload)
		if err != nil {
			return goa.NewBadRequestError(err)
		}
		return ctrl.Create(ctx)
	}
	mux.Handle("POST", "/cellar/accounts", ctrl.HandleFunc("Create", h, unmarshalCreateAccountPayload))
	service.Info("mount", "ctrl", "Account", "action", "Create", "route", "POST /cellar/accounts")
	h = func(c *goa.Context) error {
		ctx, err := NewDeleteAccountContext(c)
		if err != nil {
			return goa.NewBadRequestError(err)
		}
		return ctrl.Delete(ctx)
	}
	mux.Handle("DELETE", "/cellar/accounts/:accountID", ctrl.HandleFunc("Delete", h, nil))
	service.Info("mount", "ctrl", "Account", "action", "Delete", "route", "DELETE /cellar/accounts/:accountID")
	h = func(c *goa.Context) error {
		ctx, err := NewShowAccountContext(c)
		if err != nil {
			return goa.NewBadRequestError(err)
		}
		return ctrl.Show(ctx)
	}
	mux.Handle("GET", "/cellar/accounts/:accountID", ctrl.HandleFunc("Show", h, nil))
	service.Info("mount", "ctrl", "Account", "action", "Show", "route", "GET /cellar/accounts/:accountID")
	h = func(c *goa.Context) error {
		ctx, err := NewUpdateAccountContext(c)
		ctx.Payload = ctx.RawPayload().(*UpdateAccountPayload)
		if err != nil {
			return goa.NewBadRequestError(err)
		}
		return ctrl.Update(ctx)
	}
	mux.Handle("PUT", "/cellar/accounts/:accountID", ctrl.HandleFunc("Update", h, unmarshalUpdateAccountPayload))
	service.Info("mount", "ctrl", "Account", "action", "Update", "route", "PUT /cellar/accounts/:accountID")
}
예제 #18
0
			It("wraps it in a middleware", func() {
				Ω(mErr).ShouldNot(HaveOccurred())
				h := func(ctx *goa.Context) error { return nil }
				Ω(middleware(h)(ctx)).ShouldNot(HaveOccurred())
				Ω(ctx.ResponseStatus()).Should(Equal(200))
			})
		})

	})
})

var _ = Describe("LogRequest", func() {
	var handler *testHandler
	var ctx *goa.Context
	var service goa.Service
	params := url.Values{"param": []string{"value"}}
	payload := map[string]interface{}{"payload": 42}

	BeforeEach(func() {
		service = goa.New("test")
		service.SetEncoder(goa.JSONEncoderFactory(), true, "*/*")
		req, err := http.NewRequest("POST", "/goo", strings.NewReader(`{"payload":42}`))
		Ω(err).ShouldNot(HaveOccurred())
		rw := new(testResponseWriter)
		ctx = goa.NewContext(nil, service, req, rw, params)
		ctx.SetPayload(payload)
		handler = new(testHandler)
		logger := log15.New("test", "test")
		logger.SetHandler(handler)
		ctx.Logger = logger
예제 #19
0
// MountController mounts the JavaScript example controller under "/js".
func MountController(service *goa.Service) {
	// Serve static files under js
	service.ServeFiles("/js/*filepath", "/Users/nii236/Go/src/github.com/nii236/go-react-webpack/js")
	goa.Info(goa.RootContext, "mount", goa.KV{"ctrl", "JS"}, goa.KV{"action", "ServeFiles"}, goa.KV{"route", "GET /js/*"})
}
예제 #20
0
// initService sets up the service encoders, decoders and mux.
func initService(service *goa.Service) {
	if inited {
		return
	}
	inited = true

	// Setup encoders and decoders
	service.Encoder(goa.NewJSONEncoder, "application/json")
	service.Decoder(goa.NewJSONDecoder, "application/json")
	service.Decoder(goa.NewGobDecoder, "application/gob", "application/x-gob")
	service.Decoder(goa.NewXMLDecoder, "application/xml")

	// Setup default encoder and decoder
	service.Encoder(goa.NewJSONEncoder, "*/*")
	service.Decoder(goa.NewJSONDecoder, "*/*")
}
예제 #21
0
// NewOperandsController creates a operands controller.
func NewOperandsController(service *goa.Service) *OperandsController {
	return &OperandsController{Controller: service.NewController("operands")}
}
예제 #22
0
	"golang.org/x/net/context"

	"github.com/goadesign/goa"
	"github.com/goadesign/goa/middleware"
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
)

var _ = Describe("RequestID", func() {
	const reqID = "request id"
	var ctx context.Context
	var rw http.ResponseWriter
	var req *http.Request
	var params url.Values
	var service *goa.Service

	BeforeEach(func() {
		service = newService(nil)

		var err error
		req, err = http.NewRequest("GET", "/goo", nil)
		Ω(err).ShouldNot(HaveOccurred())
		req.Header.Set(middleware.RequestIDHeader, reqID)
		rw = new(testResponseWriter)
		params = url.Values{"query": []string{"value"}}
		service.Encoder.Register(goa.NewJSONEncoder, "*/*")
		ctx = newContext(service, rw, req, params)
	})

	It("sets the request ID in the context", func() {
예제 #23
0
// ShowBottleOK Show runs the method Show of the given controller with the given parameters.
// It returns the response writer so it's possible to inspect the response headers and the media type struct written to the response.
// If ctx is nil then context.Background() is used.
// If service is nil then a default service is created.
func ShowBottleOK(t *testing.T, ctx context.Context, service *goa.Service, ctrl app.BottleController, id int) (http.ResponseWriter, *app.Bottle) {
	// Setup service
	var (
		logBuf bytes.Buffer
		resp   interface{}

		respSetter goatest.ResponseSetterFunc = func(r interface{}) { resp = r }
	)
	if service == nil {
		service = goatest.Service(&logBuf, respSetter)
	} else {
		logger := log.New(&logBuf, "", log.Ltime)
		service.WithLogger(goa.NewLogger(logger))
		newEncoder := func(io.Writer) goa.Encoder { return respSetter }
		service.Encoder = goa.NewHTTPEncoder() // Make sure the code ends up using this decoder
		service.Encoder.Register(newEncoder, "*/*")
	}

	// Setup request context
	rw := httptest.NewRecorder()
	u := &url.URL{
		Path: fmt.Sprintf("/bottles/%v", id),
	}
	req, err := http.NewRequest("GET", u.String(), nil)
	if err != nil {
		panic("invalid test " + err.Error()) // bug
	}
	prms := url.Values{}
	prms["id"] = []string{fmt.Sprintf("%v", id)}
	if ctx == nil {
		ctx = context.Background()
	}
	goaCtx := goa.NewContext(goa.WithAction(ctx, "BottleTest"), rw, req, prms)
	showCtx, err := app.NewShowBottleContext(goaCtx, service)
	if err != nil {
		panic("invalid test data " + err.Error()) // bug
	}

	// Perform action
	err = ctrl.Show(showCtx)

	// Validate response
	if err != nil {
		t.Fatalf("controller returned %s, logs:\n%s", err, logBuf.String())
	}
	if rw.Code != 200 {
		t.Errorf("invalid response status code: got %+v, expected 200", rw.Code)
	}
	var mt *app.Bottle
	if resp != nil {
		var ok bool
		mt, ok = resp.(*app.Bottle)
		if !ok {
			t.Errorf("invalid response media: got %+v, expected instance of app.Bottle", resp)
		}
		err = mt.Validate()
		if err != nil {
			t.Errorf("invalid response media type: %s", err)
		}
	}

	// Return results
	return rw, mt
}
예제 #24
0
// CreateBottleCreated Create runs the method Create of the given controller with the given parameters and payload.
// It returns the response writer so it's possible to inspect the response headers.
// If ctx is nil then context.Background() is used.
// If service is nil then a default service is created.
func CreateBottleCreated(t *testing.T, ctx context.Context, service *goa.Service, ctrl app.BottleController, payload *app.CreateBottlePayload) http.ResponseWriter {
	// Setup service
	var (
		logBuf bytes.Buffer
		resp   interface{}

		respSetter goatest.ResponseSetterFunc = func(r interface{}) { resp = r }
	)
	if service == nil {
		service = goatest.Service(&logBuf, respSetter)
	} else {
		logger := log.New(&logBuf, "", log.Ltime)
		service.WithLogger(goa.NewLogger(logger))
		newEncoder := func(io.Writer) goa.Encoder { return respSetter }
		service.Encoder = goa.NewHTTPEncoder() // Make sure the code ends up using this decoder
		service.Encoder.Register(newEncoder, "*/*")
	}

	// Validate payload
	err := payload.Validate()
	if err != nil {
		e, ok := err.(*goa.Error)
		if !ok {
			panic(err) // bug
		}
		if e.Status != 201 {
			t.Errorf("unexpected payload validation error: %+v", e)
		}
		return nil
	}

	// Setup request context
	rw := httptest.NewRecorder()
	u := &url.URL{
		Path: fmt.Sprintf("/bottles"),
	}
	req, err := http.NewRequest("POST", u.String(), nil)
	if err != nil {
		panic("invalid test " + err.Error()) // bug
	}
	prms := url.Values{}
	if ctx == nil {
		ctx = context.Background()
	}
	goaCtx := goa.NewContext(goa.WithAction(ctx, "BottleTest"), rw, req, prms)
	createCtx, err := app.NewCreateBottleContext(goaCtx, service)
	if err != nil {
		panic("invalid test data " + err.Error()) // bug
	}
	createCtx.Payload = payload

	// Perform action
	err = ctrl.Create(createCtx)

	// Validate response
	if err != nil {
		t.Fatalf("controller returned %s, logs:\n%s", err, logBuf.String())
	}
	if rw.Code != 201 {
		t.Errorf("invalid response status code: got %+v, expected 201", rw.Code)
	}

	// Return results
	return rw
}
예제 #25
0
// MountController mounts the swagger spec controller under "/swagger.json".
func MountController(service goa.Service) {
	service.ServeFiles("/swagger.json", "swagger/swagger.json")
}
예제 #26
0
파일: service_test.go 프로젝트: is00hcw/goa
import (
	"bytes"
	"fmt"
	"io/ioutil"
	"net/http"
	"net/url"

	"github.com/goadesign/goa"
	"github.com/goadesign/middleware"
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
)

var _ = Describe("Application", func() {
	const appName = "foo"
	var s goa.Service

	BeforeEach(func() {
		s = goa.New(appName)
		s.SetDecoder(goa.JSONDecoderFactory(), true, "*/*")
		s.SetEncoder(goa.JSONEncoderFactory(), true, "*/*")
	})

	Describe("New", func() {
		It("creates an application", func() {
			Ω(s).ShouldNot(BeNil())
		})

		It("initializes the application fields", func() {
			Ω(s.Name()).Should(Equal(appName))
			Ω(s).Should(BeAssignableToTypeOf(&goa.Application{}))
예제 #27
0
// NewWorkitemtypeController creates a workitemtype controller.
func NewWorkitemtypeController(service *goa.Service, db application.DB) *WorkitemtypeController {
	return &WorkitemtypeController{
		Controller: service.NewController("WorkitemtypeController"),
		db:         db,
	}
}
예제 #28
0
// NewAreaController creates a area controller.
func NewAreaController(service *goa.Service, db application.DB) *AreaController {
	return &AreaController{Controller: service.NewController("AreaController"), db: db}
}
예제 #29
0
	"regexp"
	"strings"

	"golang.org/x/net/context"

	"github.com/goadesign/goa"
	"github.com/goadesign/goa/middleware"
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
)

var _ = Describe("RequireHeader", func() {
	var ctx context.Context
	var req *http.Request
	var rw http.ResponseWriter
	var service *goa.Service
	headerName := "Some-Header"

	BeforeEach(func() {
		var err error
		service = newService(nil)
		req, err = http.NewRequest("POST", "/foo/bar", strings.NewReader(`{"payload":42}`))
		Ω(err).ShouldNot(HaveOccurred())
		rw = new(testResponseWriter)
		ctx = newContext(service, rw, req, nil)
	})

	It("matches a header value", func() {
		req.Header.Set(headerName, "some value")
		var newCtx context.Context
		h := func(ctx context.Context, rw http.ResponseWriter, req *http.Request) error {
예제 #30
0
// MountBottleController "mounts" a Bottle resource controller on the given service.
func MountBottleController(service goa.Service, ctrl BottleController) {
	// Setup encoders and decoders. This is idempotent and is done by each MountXXX function.
	tmp21 := goa.GobEncoderFactory()
	service.SetEncoder(tmp21, false, "application/gob", "application/x-gob")
	tmp22 := goa.JSONEncoderFactory()
	service.SetEncoder(tmp22, true, "application/json")
	tmp23 := goa.XMLEncoderFactory()
	service.SetEncoder(tmp23, false, "application/xml", "text/xml")
	tmp24 := goa.GobDecoderFactory()
	service.SetDecoder(tmp24, false, "application/gob", "application/x-gob")
	tmp25 := goa.JSONDecoderFactory()
	service.SetDecoder(tmp25, true, "application/json")
	tmp26 := goa.XMLDecoderFactory()
	service.SetDecoder(tmp26, false, "application/xml", "text/xml")

	// Setup endpoint handler
	var h goa.Handler
	mux := service.ServeMux()
	h = func(c *goa.Context) error {
		ctx, err := NewCreateBottleContext(c)
		ctx.Payload = ctx.RawPayload().(*CreateBottlePayload)
		if err != nil {
			return goa.NewBadRequestError(err)
		}
		return ctrl.Create(ctx)
	}
	mux.Handle("POST", "/cellar/accounts/:accountID/bottles", ctrl.HandleFunc("Create", h, unmarshalCreateBottlePayload))
	service.Info("mount", "ctrl", "Bottle", "action", "Create", "route", "POST /cellar/accounts/:accountID/bottles")
	h = func(c *goa.Context) error {
		ctx, err := NewDeleteBottleContext(c)
		if err != nil {
			return goa.NewBadRequestError(err)
		}
		return ctrl.Delete(ctx)
	}
	mux.Handle("DELETE", "/cellar/accounts/:accountID/bottles/:bottleID", ctrl.HandleFunc("Delete", h, nil))
	service.Info("mount", "ctrl", "Bottle", "action", "Delete", "route", "DELETE /cellar/accounts/:accountID/bottles/:bottleID")
	h = func(c *goa.Context) error {
		ctx, err := NewListBottleContext(c)
		if err != nil {
			return goa.NewBadRequestError(err)
		}
		return ctrl.List(ctx)
	}
	mux.Handle("GET", "/cellar/accounts/:accountID/bottles", ctrl.HandleFunc("List", h, nil))
	service.Info("mount", "ctrl", "Bottle", "action", "List", "route", "GET /cellar/accounts/:accountID/bottles")
	h = func(c *goa.Context) error {
		ctx, err := NewRateBottleContext(c)
		ctx.Payload = ctx.RawPayload().(*RateBottlePayload)
		if err != nil {
			return goa.NewBadRequestError(err)
		}
		return ctrl.Rate(ctx)
	}
	mux.Handle("PUT", "/cellar/accounts/:accountID/bottles/:bottleID/actions/rate", ctrl.HandleFunc("Rate", h, unmarshalRateBottlePayload))
	service.Info("mount", "ctrl", "Bottle", "action", "Rate", "route", "PUT /cellar/accounts/:accountID/bottles/:bottleID/actions/rate")
	h = func(c *goa.Context) error {
		ctx, err := NewShowBottleContext(c)
		if err != nil {
			return goa.NewBadRequestError(err)
		}
		return ctrl.Show(ctx)
	}
	mux.Handle("GET", "/cellar/accounts/:accountID/bottles/:bottleID", ctrl.HandleFunc("Show", h, nil))
	service.Info("mount", "ctrl", "Bottle", "action", "Show", "route", "GET /cellar/accounts/:accountID/bottles/:bottleID")
	h = func(c *goa.Context) error {
		ctx, err := NewUpdateBottleContext(c)
		ctx.Payload = ctx.RawPayload().(*UpdateBottlePayload)
		if err != nil {
			return goa.NewBadRequestError(err)
		}
		return ctrl.Update(ctx)
	}
	mux.Handle("PATCH", "/cellar/accounts/:accountID/bottles/:bottleID", ctrl.HandleFunc("Update", h, unmarshalUpdateBottlePayload))
	service.Info("mount", "ctrl", "Bottle", "action", "Update", "route", "PATCH /cellar/accounts/:accountID/bottles/:bottleID")
}