Skip to content

Commit

Permalink
Merge pull request #12 from isd-sgcu/sunioatm/joh-29-pet-endpoints
Browse files Browse the repository at this point in the history
Sunioatm/joh 29 pet endpoints
  • Loading branch information
Sunioatm authored Jan 6, 2024
2 parents 4d75cf2 + 3caba53 commit 8859b23
Show file tree
Hide file tree
Showing 9 changed files with 256 additions and 17 deletions.
17 changes: 11 additions & 6 deletions src/app/dto/adopt.dto.go
Original file line number Diff line number Diff line change
@@ -1,10 +1,15 @@
package dto

import (
"github.com/google/uuid"
)

type AdoptDto struct {
UserID uuid.UUID `json:"user_id" validate:"required"`
PetID uuid.UUID `json:"pet_id" validate:"required"`
UserID string `json:"user_id" validate:"required"`
PetID string `json:"pet_id" validate:"required"`
}

type AdoptByRequest struct {
UserID string `json:"user_id" validate:"required"`
PetID string `json:"pet_id" validate:"required"`
}

type AdoptByResponse struct {
Success bool `json:"success"`
}
63 changes: 63 additions & 0 deletions src/app/handler/pet/pet.handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -298,3 +298,66 @@ func (h *Handler) Delete(c router.IContext) {
})
return
}

// Adopt is a function that handles the adoption of a pet in the database
// @Summary Adopt a pet
// @Description Return true if the pet is successfully adopted
// @Param id path string true "Pet ID"
// @Param user_id body string true "User ID"
// @Param pet_id body string true "Pet ID"
// @Tags pet
// @Accept json
// @Produce json
// @Success 201 {object} bool
// @Failure 400 {object} dto.ResponseBadRequestErr "Invalid request body"
// @Failure 500 {object} dto.ResponseInternalErr "Internal service error"
// @Failure 503 {object} dto.ResponseServiceDownErr "Service is down"
// @Router /v1/pets/{id}/adopt [put]
func (h *Handler) Adopt(c router.IContext) {
petId, err := c.Param("id")
if err != nil {
c.JSON(http.StatusBadRequest, &dto.ResponseErr{
StatusCode: http.StatusBadRequest,
Message: "Invalid ID",
Data: nil,
})
return
}

request := &dto.AdoptByRequest{}
err = c.Bind(request)
if err != nil {
c.JSON(http.StatusBadRequest, dto.ResponseErr{
StatusCode: http.StatusBadRequest,
Message: constant.BindingRequestErrorMessage + err.Error(),
Data: nil,
})
return
}

if err := h.validate.Validate(request); err != nil {
var errorMessage []string
for _, reqErr := range err {
errorMessage = append(errorMessage, reqErr.Message)
}
c.JSON(http.StatusBadRequest, dto.ResponseErr{
StatusCode: http.StatusBadRequest,
Message: constant.InvalidRequestBodyMessage + strings.Join(errorMessage, ", "),
Data: nil,
})
return
}

res, errRes := h.service.Adopt(petId, request)
if errRes != nil {
c.JSON(errRes.StatusCode, errRes)
return
}

c.JSON(http.StatusOK, dto.ResponseSuccess{
StatusCode: http.StatusOK,
Message: petconst.AdoptPetSuccessMessage,
Data: res,
})
return
}
74 changes: 74 additions & 0 deletions src/app/handler/pet/pet.handler_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ type PetHandlerTest struct {
CreatePetRequest *dto.CreatePetRequest
ChangeViewPetRequest *dto.ChangeViewPetRequest
UpdatePetRequest *dto.UpdatePetRequest
AdoptByRequest *dto.AdoptByRequest
BindErr *dto.ResponseErr
NotFoundErr *dto.ResponseErr
ServiceDownErr *dto.ResponseErr
Expand Down Expand Up @@ -102,6 +103,8 @@ func (t *PetHandlerTest) SetupTest() {

t.ChangeViewPetRequest = &dto.ChangeViewPetRequest{}

t.AdoptByRequest = &dto.AdoptByRequest{}

t.ServiceDownErr = &dto.ResponseErr{
StatusCode: http.StatusServiceUnavailable,
Message: "Service is down",
Expand Down Expand Up @@ -449,3 +452,74 @@ func (t *PetHandlerTest) TestChangeViewGrpcErr() {
handler := NewHandler(petSvc, imageSvc, validator)
handler.ChangeView(context)
}

func (t *PetHandlerTest) TestAdoptSuccess() {
adoptByResponse := &dto.AdoptByResponse{
Success: true,
}
expectedResponse := dto.ResponseSuccess{
StatusCode: http.StatusOK,
Message: petConst.AdoptPetSuccessMessage,
Data: adoptByResponse,
}

controller := gomock.NewController(t.T())

petSvc := petMock.NewMockService(controller)
imageSvc := imageMock.NewMockService(controller)
validator := validatorMock.NewMockIDtoValidator(controller)
context := routerMock.NewMockIContext(controller)

context.EXPECT().Param("id").Return(t.Pet.Id, nil)
context.EXPECT().Bind(t.AdoptByRequest).Return(nil)
validator.EXPECT().Validate(t.AdoptByRequest).Return(nil)
petSvc.EXPECT().Adopt(t.Pet.Id, t.AdoptByRequest).Return(adoptByResponse, nil)
context.EXPECT().JSON(http.StatusOK, expectedResponse)

handler := NewHandler(petSvc, imageSvc, validator)
handler.Adopt(context)
}

func (t *PetHandlerTest) TestAdoptNotFound() {
adoptByResponse := &dto.AdoptByResponse{
Success: false,
}

controller := gomock.NewController(t.T())

petSvc := petMock.NewMockService(controller)
imageSvc := imageMock.NewMockService(controller)
validator := validatorMock.NewMockIDtoValidator(controller)
context := routerMock.NewMockIContext(controller)

context.EXPECT().Param("id").Return(t.Pet.Id, nil)
context.EXPECT().Bind(t.AdoptByRequest).Return(nil)
validator.EXPECT().Validate(t.AdoptByRequest).Return(nil)
petSvc.EXPECT().Adopt(t.Pet.Id, t.AdoptByRequest).Return(adoptByResponse, t.NotFoundErr)
context.EXPECT().JSON(http.StatusNotFound, t.NotFoundErr)

handler := NewHandler(petSvc, imageSvc, validator)
handler.Adopt(context)
}

func (t *PetHandlerTest) TestAdoptGrpcErr() {
adoptByResponse := &dto.AdoptByResponse{
Success: false,
}

controller := gomock.NewController(t.T())

petSvc := petMock.NewMockService(controller)
imageSvc := imageMock.NewMockService(controller)
validator := validatorMock.NewMockIDtoValidator(controller)
context := routerMock.NewMockIContext(controller)

context.EXPECT().Param("id").Return(t.Pet.Id, nil)
context.EXPECT().Bind(t.AdoptByRequest).Return(nil)
validator.EXPECT().Validate(t.AdoptByRequest).Return(nil)
petSvc.EXPECT().Adopt(t.Pet.Id, t.AdoptByRequest).Return(adoptByResponse, t.ServiceDownErr)
context.EXPECT().JSON(http.StatusServiceUnavailable, t.ServiceDownErr)

handler := NewHandler(petSvc, imageSvc, validator)
handler.Adopt(context)
}
49 changes: 44 additions & 5 deletions src/app/service/pet/pet.service.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,6 @@ type Service struct {
petClient petproto.PetServiceClient
}

// Adopt implements pet.Service.
func (*Service) Adopt(*dto.AdoptDto) (bool, *dto.ResponseErr) {
panic("unimplemented")
}

func NewService(petClient petproto.PetServiceClient) *Service {
return &Service{
petClient: petClient,
Expand Down Expand Up @@ -276,3 +271,47 @@ func (s *Service) ChangeView(id string, in *dto.ChangeViewPetRequest) (result *d
Success: res.Success,
}, nil
}

func (s *Service) Adopt(petId string, in *dto.AdoptByRequest) (result *dto.AdoptByResponse, err *dto.ResponseErr) {
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()

res, errRes := s.petClient.AdoptPet(ctx, &petproto.AdoptPetRequest{
UserId: in.UserID,
PetId: in.PetID,
})
if errRes != nil {
st, _ := status.FromError(errRes)
log.Error().
Err(errRes).
Str("service", "pet").
Str("module", "adopt").
Msg(st.Message())
switch st.Code() {
case codes.NotFound:
return nil,
&dto.ResponseErr{
StatusCode: http.StatusNotFound,
Message: constant.PetNotFoundMessage,
Data: nil,
}
case codes.Unavailable:
return nil,
&dto.ResponseErr{
StatusCode: http.StatusServiceUnavailable,
Message: constant.UnavailableServiceMessage,
Data: nil,
}
default:
return nil,
&dto.ResponseErr{
StatusCode: http.StatusServiceUnavailable,
Message: constant.InternalErrorMessage,
Data: nil,
}
}
}
return &dto.AdoptByResponse{
Success: res.Success,
}, nil
}
56 changes: 56 additions & 0 deletions src/app/service/pet/pet.service_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ type PetServiceTest struct {
InvalidArgumentErr *dto.ResponseErr
InternalErr *dto.ResponseErr
ChangeViewedPetDto *dto.ChangeViewPetRequest
AdoptDto *dto.AdoptByRequest

Images []*imgproto.Image
ImagesList [][]*imgproto.Image
Expand Down Expand Up @@ -160,6 +161,11 @@ func (t *PetServiceTest) SetupTest() {
UserId: t.Pet.AdoptBy,
}

t.AdoptDto = &dto.AdoptByRequest{
UserID: t.Pet.AdoptBy,
PetID: t.Pet.Id,
}

t.UnavailableServiceErr = &dto.ResponseErr{
StatusCode: http.StatusServiceUnavailable,
Message: constant.UnavailableServiceMessage,
Expand Down Expand Up @@ -514,3 +520,53 @@ func (t *PetServiceTest) TestChangeViewUnavailableServiceError() {
assert.Equal(t.T(), &dto.ChangeViewPetResponse{Success: false}, actual)
assert.Equal(t.T(), expected, err)
}

func (t *PetServiceTest) TestAdoptSuccess() {
protoReq := t.AdoptReq
protoResp := &petproto.AdoptPetResponse{
Success: true,
}

client := &petmock.PetClientMock{}
client.On("AdoptPet", protoReq).Return(protoResp, nil)

svc := NewService(client)
actual, err := svc.Adopt(t.Pet.Id, t.AdoptDto)

assert.Nil(t.T(), err)
assert.Equal(t.T(), actual, &dto.AdoptByResponse{Success: true})
}

func (t *PetServiceTest) TestAdoptNotFoundError() {
protoReq := t.AdoptReq

clientErr := status.Error(codes.NotFound, constant.PetNotFoundMessage)

expected := t.NotFoundErr

client := &petmock.PetClientMock{}
client.On("AdoptPet", protoReq).Return(nil, clientErr)

svc := NewService(client)
actual, err := svc.Adopt(t.Pet.Id, t.AdoptDto)

assert.Nil(t.T(), actual)
assert.Equal(t.T(), expected, err)
}

func (t *PetServiceTest) TestAdoptUnavailableServiceError() {
protoReq := t.AdoptReq

clientErr := status.Error(codes.Unavailable, constant.UnavailableServiceMessage)

expected := t.UnavailableServiceErr

client := &petmock.PetClientMock{}
client.On("AdoptPet", protoReq).Return(nil, clientErr)

svc := NewService(client)
actual, err := svc.Adopt(t.Pet.Id, t.AdoptDto)

assert.Nil(t.T(), actual)
assert.Equal(t.T(), expected, err)
}
1 change: 1 addition & 0 deletions src/constant/pet/pet.constant.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,3 +64,4 @@ const CreatePetSuccessMessage = "create pet success"
const UpdatePetSuccessMessage = "update pet success"
const ChangeViewPetSuccessMessage = "change view pet success"
const DeletePetSuccessMessage = "delete pet success"
const AdoptPetSuccessMessage = "adopt pet success"
1 change: 1 addition & 0 deletions src/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,7 @@ func main() {
r.GetPet("/:id", petHandler.FindOne)
r.PostPet("/create", petHandler.Create)
r.PutPet("/:id", petHandler.Update)
r.PutPet("/:id/adopt", petHandler.Adopt)
r.PutPet("/:id/visible", petHandler.ChangeView)
r.DeletePet("/:id", petHandler.Delete)

Expand Down
10 changes: 5 additions & 5 deletions src/mocks/service/pet/pet.mock.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion src/pkg/service/pet/pet.service.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,5 +11,5 @@ type Service interface {
Update(string, *dto.UpdatePetRequest) (*dto.PetResponse, *dto.ResponseErr)
Delete(string) (*dto.DeleteResponse, *dto.ResponseErr)
ChangeView(string, *dto.ChangeViewPetRequest) (*dto.ChangeViewPetResponse, *dto.ResponseErr)
Adopt(*dto.AdoptDto) (bool, *dto.ResponseErr)
Adopt(string, *dto.AdoptByRequest) (*dto.AdoptByResponse, *dto.ResponseErr)
}

0 comments on commit 8859b23

Please sign in to comment.