Skip to content

Commit

Permalink
Add 409 return status code to Config API resources. Closes #465 (#466)
Browse files Browse the repository at this point in the history
  • Loading branch information
baniol authored and mthenw committed Jun 27, 2018
1 parent 73ba4a3 commit 5e02910
Show file tree
Hide file tree
Showing 3 changed files with 125 additions and 7 deletions.
4 changes: 4 additions & 0 deletions docs/api.md
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,7 @@ Status code:

* `201 Created` on success
* `400 Bad Request` on validation error
* `409 Conflict` if event type already exists

JSON object:

Expand Down Expand Up @@ -296,6 +297,7 @@ Status code:

* `201 Created` on success
* `400 Bad Request` on validation error
* `409 Conflict` if function already exists

JSON object:

Expand Down Expand Up @@ -431,6 +433,7 @@ Status code:

* `201 Created` on success
* `400 Bad Request` on validation error
* `409 Conflict` if subscription already exists

JSON object:

Expand Down Expand Up @@ -576,6 +579,7 @@ Status code:

* `201 Created` on success
* `400 Bad Request` on validation error
* `409 Conflict` if CORS configuration already exists

JSON object:

Expand Down
8 changes: 4 additions & 4 deletions httpapi/httpapi.go
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ func (h HTTPAPI) createEventType(w http.ResponseWriter, r *http.Request, params
if _, ok := err.(*event.ErrEventTypeValidation); ok {
w.WriteHeader(http.StatusBadRequest)
} else if _, ok := err.(*event.ErrEventTypeAlreadyExists); ok {
w.WriteHeader(http.StatusBadRequest)
w.WriteHeader(http.StatusConflict)
} else {
w.WriteHeader(http.StatusInternalServerError)
}
Expand Down Expand Up @@ -267,7 +267,7 @@ func (h HTTPAPI) createFunction(w http.ResponseWriter, r *http.Request, params h
if _, ok := err.(*function.ErrFunctionValidation); ok {
w.WriteHeader(http.StatusBadRequest)
} else if _, ok := err.(*function.ErrFunctionAlreadyRegistered); ok {
w.WriteHeader(http.StatusBadRequest)
w.WriteHeader(http.StatusConflict)
} else {
w.WriteHeader(http.StatusInternalServerError)
}
Expand Down Expand Up @@ -398,7 +398,7 @@ func (h HTTPAPI) createSubscription(w http.ResponseWriter, r *http.Request, para
output, err := h.Subscriptions.CreateSubscription(s)
if err != nil {
if _, ok := err.(*subscription.ErrSubscriptionAlreadyExists); ok {
w.WriteHeader(http.StatusBadRequest)
w.WriteHeader(http.StatusConflict)
} else if _, ok := err.(*event.ErrEventTypeNotFound); ok {
w.WriteHeader(http.StatusBadRequest)
} else if _, ok := err.(*function.ErrFunctionNotFound); ok {
Expand Down Expand Up @@ -540,7 +540,7 @@ func (h HTTPAPI) createCORS(w http.ResponseWriter, r *http.Request, params httpr
output, err := h.CORSes.CreateCORS(config)
if err != nil {
if _, ok := err.(*cors.ErrCORSAlreadyExists); ok {
w.WriteHeader(http.StatusBadRequest)
w.WriteHeader(http.StatusConflict)
} else if _, ok := err.(*cors.ErrCORSValidation); ok {
w.WriteHeader(http.StatusBadRequest)
} else {
Expand Down
120 changes: 117 additions & 3 deletions httpapi/httpapi_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@ func TestCreateEventType(t *testing.T) {

httpresp := &httpapi.Response{}
json.Unmarshal(resp.Body.Bytes(), httpresp)
assert.Equal(t, http.StatusBadRequest, resp.Code)
assert.Equal(t, http.StatusConflict, resp.Code)
assert.Equal(t, `Event Type "test.event" already exists.`, httpresp.Errors[0].Message)
})

Expand Down Expand Up @@ -416,7 +416,7 @@ func TestRegisterFunction(t *testing.T) {

httpresp := &httpapi.Response{}
json.Unmarshal(resp.Body.Bytes(), httpresp)
assert.Equal(t, http.StatusBadRequest, resp.Code)
assert.Equal(t, http.StatusConflict, resp.Code)
assert.Equal(t, `Function "func1" already registered.`, httpresp.Errors[0].Message)
})

Expand Down Expand Up @@ -541,6 +541,120 @@ func TestListSubscriptions(t *testing.T) {
})
}

func TestCreateSubscription(t *testing.T) {
ctrl := gomock.NewController(t)
defer ctrl.Finish()
router, _, _, subscriptions, _ := setup(ctrl)
subPayload := []byte(`{"type":"sync","eventType":"http.request",` +
`"functionId":"func","method":"GET","path":"/"}`)

createSub := &subscription.Subscription{
Space: "default",
Type: subscription.TypeSync,
EventType: "http.request",
FunctionID: "func",
Method: "GET",
Path: "/",
}

t.Run("subscription created", func(t *testing.T) {
subscriptions.EXPECT().CreateSubscription(createSub).Return(createSub, nil)
resp := request(router, http.MethodPost, "/v1/spaces/default/subscriptions", subPayload)

sub := &subscription.Subscription{}
json.Unmarshal(resp.Body.Bytes(), sub)
assert.Equal(t, http.StatusCreated, resp.Code)
assert.Equal(t, "application/json", resp.Header().Get("Content-Type"))
assert.Equal(t, "default", sub.Space)
assert.Equal(t, function.ID("func"), sub.FunctionID)
assert.Equal(t, event.TypeName("http.request"), sub.EventType)
assert.Equal(t, subscription.TypeSync, sub.Type)
assert.Equal(t, "/", sub.Path)
assert.Equal(t, "GET", sub.Method)
assert.NotNil(t, sub.ID)
})

t.Run("subscription already exists", func(t *testing.T) {
subscriptions.EXPECT().CreateSubscription(gomock.Any()).
Return(nil, &subscription.ErrSubscriptionAlreadyExists{ID: subscription.ID("sub1")})

resp := request(router, http.MethodPost, "/v1/spaces/default/subscriptions", subPayload)

httpresp := &httpapi.Response{}
json.Unmarshal(resp.Body.Bytes(), httpresp)
assert.Equal(t, http.StatusConflict, resp.Code)
assert.Equal(t, `Subscription "sub1" already exists.`, httpresp.Errors[0].Message)
})

t.Run("subscription validation error", func(t *testing.T) {
subscriptions.EXPECT().CreateSubscription(gomock.Any()).
Return(nil, &subscription.ErrSubscriptionValidation{Message: "wrong function ID format"})

resp := request(router, http.MethodPost, "/v1/spaces/default/subscriptions", subPayload)

httpresp := &httpapi.Response{}
json.Unmarshal(resp.Body.Bytes(), httpresp)
assert.Equal(t, http.StatusBadRequest, resp.Code)
assert.Equal(t, `Subscription doesn't validate. Validation error: wrong function ID format`, httpresp.Errors[0].Message)
})

t.Run("function not found", func(t *testing.T) {
subscriptions.EXPECT().CreateSubscription(gomock.Any()).
Return(nil, &function.ErrFunctionNotFound{ID: function.ID("func")})

resp := request(router, http.MethodPost, "/v1/spaces/default/subscriptions", subPayload)

httpresp := &httpapi.Response{}
json.Unmarshal(resp.Body.Bytes(), httpresp)
assert.Equal(t, http.StatusBadRequest, resp.Code)
assert.Equal(t, `Function "func" not found.`, httpresp.Errors[0].Message)
})

t.Run("event type not found", func(t *testing.T) {
subscriptions.EXPECT().CreateSubscription(gomock.Any()).
Return(nil, &event.ErrEventTypeNotFound{Name: event.TypeName("http.request")})

resp := request(router, http.MethodPost, "/v1/spaces/default/subscriptions", subPayload)

httpresp := &httpapi.Response{}
json.Unmarshal(resp.Body.Bytes(), httpresp)
assert.Equal(t, http.StatusBadRequest, resp.Code)
assert.Equal(t, `Event Type "http.request" not found.`, httpresp.Errors[0].Message)
})

t.Run("path conflict", func(t *testing.T) {
subscriptions.EXPECT().CreateSubscription(gomock.Any()).
Return(nil, &subscription.ErrPathConfict{Message: "route / conflicts with existing route"})

resp := request(router, http.MethodPost, "/v1/spaces/default/subscriptions", subPayload)

httpresp := &httpapi.Response{}
json.Unmarshal(resp.Body.Bytes(), httpresp)
assert.Equal(t, http.StatusBadRequest, resp.Code)
assert.Equal(t, `Subscription path conflict: route / conflicts with existing route`, httpresp.Errors[0].Message)
})

t.Run("invalid JSON", func(t *testing.T) {
resp := request(router, http.MethodPost, "/v1/spaces/default/subscriptions", []byte(`{"name":"te`))

httpresp := &httpapi.Response{}
json.Unmarshal(resp.Body.Bytes(), httpresp)
assert.Equal(t, http.StatusBadRequest, resp.Code)
assert.Equal(t, "Subscription doesn't validate. Validation error: unexpected EOF", httpresp.Errors[0].Message)
})

t.Run("internal error", func(t *testing.T) {
subscriptions.EXPECT().CreateSubscription(gomock.Any()).Return(nil, errors.New("processing failed"))

resp := request(router, http.MethodPost, "/v1/spaces/default/subscriptions", subPayload)

httpresp := &httpapi.Response{}
json.Unmarshal(resp.Body.Bytes(), httpresp)
assert.Equal(t, http.StatusInternalServerError, resp.Code)
assert.Equal(t, "processing failed", httpresp.Errors[0].Message)
})
}

func TestUpdateSubscription(t *testing.T) {
ctrl := gomock.NewController(t)
defer ctrl.Finish()
Expand Down Expand Up @@ -801,7 +915,7 @@ func TestCreateCORS(t *testing.T) {

httpresp := &httpapi.Response{}
json.Unmarshal(resp.Body.Bytes(), httpresp)
assert.Equal(t, http.StatusBadRequest, resp.Code)
assert.Equal(t, http.StatusConflict, resp.Code)
assert.Equal(t, `CORS configuration "GET%2Fhello" already exists.`, httpresp.Errors[0].Message)
})

Expand Down

0 comments on commit 5e02910

Please sign in to comment.