From ee43e017a0ba2c911db849e20cebd7e1ab3e338e Mon Sep 17 00:00:00 2001 From: David Lick Date: Mon, 21 Jun 2021 09:58:43 -0400 Subject: [PATCH] Add DELETE /produce/{produceCode} endpoint --- internal/http/produce.go | 24 +++++++++++++ internal/http/produce_test.go | 68 +++++++++++++++++++++++++++++++++++ 2 files changed, 92 insertions(+) diff --git a/internal/http/produce.go b/internal/http/produce.go index f73ba53..b7ba65d 100644 --- a/internal/http/produce.go +++ b/internal/http/produce.go @@ -14,6 +14,9 @@ func (s *server) produceGroup(r chi.Router) { r.Route("/produce", func(r chi.Router) { r.Get("/", s.handleGetAllProduce) r.Post("/", s.handleAddProduce) + r.Route("/{produceCode}", func(r chi.Router) { + r.Delete("/", s.handleDeleteProduce) + }) }) }) } @@ -56,3 +59,24 @@ func (s *server) handleGetAllProduce(w http.ResponseWriter, r *http.Request) { s.writeSuccess(ctx, w, items, http.StatusOK) return } + +func (s *server) handleDeleteProduce(w http.ResponseWriter, r *http.Request) { + ctx := r.Context() + + produceCode := chi.URLParam(r, "produceCode") + if produceCode == "" { + s.writeError(ctx, w, ErrUnrecognizedCode, http.StatusBadRequest) + return + } + + err := s.produceSvc.Remove(produce.Item{ + Code: produceCode, + }) + if err != nil { + s.writeError(ctx, w, err, http.StatusInternalServerError) + return + } + + s.writeSuccess(ctx, w, nil, http.StatusNoContent) + return +} diff --git a/internal/http/produce_test.go b/internal/http/produce_test.go index 033b349..f8ec95e 100644 --- a/internal/http/produce_test.go +++ b/internal/http/produce_test.go @@ -1,7 +1,9 @@ package http import ( + "context" "errors" + "fmt" "io/ioutil" "net/http" "net/http/httptest" @@ -10,6 +12,7 @@ import ( "github.com/Rhymond/go-money" "github.com/davidlick/supermarket-api/internal/produce" + "github.com/go-chi/chi" "github.com/golang/mock/gomock" "github.com/sirupsen/logrus" "github.com/stretchr/testify/assert" @@ -142,3 +145,68 @@ func TestServer_handleGetAllProduce(t *testing.T) { }) } } + +func TestServer_handleDeleteProduce(t *testing.T) { + tests := []struct { + test string + produceCode string + expectFunc func(mockProduceSvc *MockProduceService) + assertFunc func(t *testing.T, w *httptest.ResponseRecorder) + }{ + { + test: "it should respond no content when successful", + produceCode: "test-code", + expectFunc: func(mockProduceSvc *MockProduceService) { + mockProduceSvc.EXPECT().Remove(produce.Item{Code: "test-code"}).Return(nil) + }, + assertFunc: func(t *testing.T, w *httptest.ResponseRecorder) { + assert.Equal(t, http.StatusNoContent, w.Code) + }, + }, + { + test: "it should respond internal server error if adding to service fails", + produceCode: "test-code", + expectFunc: func(mockProduceSvc *MockProduceService) { + mockProduceSvc.EXPECT().Remove(produce.Item{Code: "test-code"}).Return(errors.New("test error")) + }, + assertFunc: func(t *testing.T, w *httptest.ResponseRecorder) { + assert.Equal(t, http.StatusInternalServerError, w.Code) + }, + }, + { + test: "it should respond bad request if no produce code is supplied", + expectFunc: func(mockProduceSvc *MockProduceService) {}, + assertFunc: func(t *testing.T, w *httptest.ResponseRecorder) { + assert.Equal(t, http.StatusBadRequest, w.Code) + }, + }, + } + + for _, tc := range tests { + t.Run(tc.test, func(t *testing.T) { + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + r := httptest.NewRequest(http.MethodDelete, fmt.Sprintf("/v1/produce/%s", tc.produceCode), nil) + rctx := chi.NewRouteContext() + rctx.URLParams.Add("produceCode", tc.produceCode) + ctx := context.WithValue(context.Background(), chi.RouteCtxKey, rctx) + + r = r.WithContext(ctx) + w := httptest.NewRecorder() + + noopLogger := logrus.New() + noopLogger.SetOutput(ioutil.Discard) + + mockProduceSvc := NewMockProduceService(ctrl) + tc.expectFunc(mockProduceSvc) + + s := NewServer(3000, noopLogger, "test", mockProduceSvc) + + handler := http.HandlerFunc(s.handleDeleteProduce) + handler.ServeHTTP(w, r) + + tc.assertFunc(t, w) + }) + } +}