diff --git a/CHANGELOG.md b/CHANGELOG.md index c4aeff35..50d510d7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,7 +8,9 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. ### Changed - Abstract away dynamodb dependency. [#35](https://github.com/xmidt-org/argus/pull/35) - Add unit tests for new dynamodb abstraction changes. [#39](https://github.com/xmidt-org/argus/pull/39) -- Add encoders/decoders for GetItem Handler. [#44](https://github.com/xmidt-org/argus/pull/44) +- Add helper functions for GetItem Handler. [#44](https://github.com/xmidt-org/argus/pull/44) +- Add helper functions for DeleteItem Handler. [#52](https://github.com/xmidt-org/argus/pull/52) +- Add helper functions for GetAllItems Handler. [#53](https://github.com/xmidt-org/argus/pull/53) ## [v0.3.5] diff --git a/store/endpoint.go b/store/endpoint.go index 3f97937a..0db48f8c 100644 --- a/store/endpoint.go +++ b/store/endpoint.go @@ -174,6 +174,18 @@ func NewGetEndpoint(s S) endpoint.Endpoint { } } +func newGetAllItemsEndpoint(s S) endpoint.Endpoint { + return func(ctx context.Context, request interface{}) (interface{}, error) { + itemsRequest := request.(*getAllItemsRequest) + items, err := s.GetAll(itemsRequest.bucket) + if err != nil { + return nil, err + } + + return FilterOwner(items, itemsRequest.owner), nil + } +} + func NewGetAllEndpoint(s S) endpoint.Endpoint { return func(ctx context.Context, request interface{}) (interface{}, error) { var ( diff --git a/store/endpoint_test.go b/store/endpoint_test.go index f6aa9f99..feff07c2 100644 --- a/store/endpoint_test.go +++ b/store/endpoint_test.go @@ -160,3 +160,64 @@ func TestDeleteItemEndpoint(t *testing.T) { }) } } + +func TestGetAllItemsEndpoint(t *testing.T) { + t.Run("DAOFails", testGetAllItemsEndpointDAOFails) + t.Run("FilteredItems", testGetAllItemsEndpointFiltered) +} + +func testGetAllItemsEndpointDAOFails(t *testing.T) { + assert := assert.New(t) + m := new(MockDAO) + itemsRequest := &getAllItemsRequest{ + bucket: "sports-cars", + owner: "alfa-romeo", + } + mockedErr := errors.New("sports cars api is down") + m.On("GetAll", "sports-cars").Return(map[string]OwnableItem{}, mockedErr) + + endpoint := newGetAllItemsEndpoint(m) + resp, err := endpoint(context.Background(), itemsRequest) + + assert.Nil(resp) + assert.Equal(mockedErr, err) +} + +func testGetAllItemsEndpointFiltered(t *testing.T) { + assert := assert.New(t) + m := new(MockDAO) + itemsRequest := &getAllItemsRequest{ + bucket: "sports-cars", + owner: "alfa-romeo", + } + mockedItems := map[string]OwnableItem{ + "mustang": OwnableItem{ + Owner: "ford", + }, + "4c-spider": OwnableItem{ + Owner: "alfa-romeo", + }, + "gtr": OwnableItem{ + Owner: "nissan", + }, + "giulia": OwnableItem{ + Owner: "alfa-romeo", + }, + } + m.On("GetAll", "sports-cars").Return(mockedItems, error(nil)) + + endpoint := newGetAllItemsEndpoint(m) + resp, err := endpoint(context.Background(), itemsRequest) + + expectedItems := map[string]OwnableItem{ + "4c-spider": OwnableItem{ + Owner: "alfa-romeo", + }, + "giulia": OwnableItem{ + Owner: "alfa-romeo", + }, + } + + assert.Equal(expectedItems, resp) + assert.Nil(err) +} diff --git a/store/handler.go b/store/handler.go index 9a920274..9ef7d394 100644 --- a/store/handler.go +++ b/store/handler.go @@ -76,7 +76,15 @@ func newDeleteItemHandler(s S) Handler { encodeGetOrDeleteItemResponse, kithttp.ServerErrorEncoder(encodeError), ) +} +func newGetAllItemsHandler(s S) Handler { + return kithttp.NewServer( + newGetAllItemsEndpoint(s), + decodeGetAllItemsRequest, + encodeGetAllItemsResponse, + kithttp.ServerErrorEncoder(encodeError), + ) } type requestHandler struct { diff --git a/store/transport.go b/store/transport.go index 3a903cc2..560d3d84 100644 --- a/store/transport.go +++ b/store/transport.go @@ -37,6 +37,41 @@ type getOrDeleteItemRequest struct { owner string } +type getAllItemsRequest struct { + bucket string + owner string +} + +func decodeGetAllItemsRequest(ctx context.Context, r *http.Request) (interface{}, error) { + vars := mux.Vars(r) + bucket, ok := vars[bucketVarKey] + if !ok { + return nil, &BadRequestErr{Message: bucketVarMissingMsg} + } + return &getAllItemsRequest{ + bucket: bucket, + owner: r.Header.Get(ItemOwnerHeaderKey), + }, nil +} + +func encodeGetAllItemsResponse(ctx context.Context, rw http.ResponseWriter, response interface{}) error { + items := response.(map[string]OwnableItem) + payload := map[string]model.Item{} + for k, value := range items { + if value.TTL <= 0 { + continue + } + payload[k] = value.Item + } + data, err := json.Marshal(&payload) + if err != nil { + return err + } + rw.Header().Add("Content-Type", "application/json") + rw.Write(data) + return nil +} + func decodeGetOrDeleteItemRequest(ctx context.Context, r *http.Request) (interface{}, error) { vars := mux.Vars(r) bucket, ok := vars[bucketVarKey] diff --git a/store/transport_test.go b/store/transport_test.go index be435def..119c2dbd 100644 --- a/store/transport_test.go +++ b/store/transport_test.go @@ -142,6 +142,67 @@ func TestEncodeGetOrDeleteItemResponse(t *testing.T) { } } +func TestDecodeGetAllItemsRequest(t *testing.T) { + t.Run("Bucket Missing", testDecodeGetAllItemsRequestBucketMissing) + t.Run("Success", testDecodeGetAllItemsRequestSuccessful) +} + +func testDecodeGetAllItemsRequestBucketMissing(t *testing.T) { + assert := assert.New(t) + r := httptest.NewRequest(http.MethodGet, "http://localhost:9030", nil) + + decodedRequest, err := decodeGetAllItemsRequest(context.Background(), r) + assert.Nil(decodedRequest) + assert.Equal(&BadRequestErr{Message: bucketVarMissingMsg}, err) +} + +func testDecodeGetAllItemsRequestSuccessful(t *testing.T) { + assert := assert.New(t) + r := httptest.NewRequest(http.MethodGet, "http://localhost:9030", nil) + r.Header.Set(ItemOwnerHeaderKey, "bob-ross") + r = mux.SetURLVars(r, map[string]string{bucketVarKey: "happy-little-accidents"}) + expectedDecodedRequest := &getAllItemsRequest{ + bucket: "happy-little-accidents", + owner: "bob-ross", + } + + decodedRequest, err := decodeGetAllItemsRequest(context.Background(), r) + assert.Nil(err) + assert.Equal(expectedDecodedRequest, decodedRequest) +} + +func TestEncodeGetAllItemsResponse(t *testing.T) { + assert := assert.New(t) + response := map[string]OwnableItem{ + "fix-you": OwnableItem{ + Item: model.Item{ + Identifier: "coldplay-04", + TTL: 1, + Data: map[string]interface{}{}, + }, + }, + "bohemian-rhapsody": OwnableItem{ + Item: model.Item{ + Identifier: "queen-03", + TTL: 0, + Data: map[string]interface{}{}, + }, + }, + "don't-stop-me-know": OwnableItem{ + Item: model.Item{ + Identifier: "queen-02", + TTL: 0, + Data: map[string]interface{}{}, + }, + }, + } + recorder := httptest.NewRecorder() + expectedResponseBody := `{"fix-you":{"identifier":"coldplay-04","data":{},"ttl":1}}` + err := encodeGetAllItemsResponse(context.Background(), recorder, response) + assert.Nil(err) + assert.Equal(expectedResponseBody, recorder.Body.String()) +} + func transferHeaders(headers map[string][]string, r *http.Request) { for k, values := range headers { for _, value := range values {