Skip to content

Commit

Permalink
tests: adding tests for comments and refactoring responsibles
Browse files Browse the repository at this point in the history
  • Loading branch information
felipebrsk committed Nov 6, 2024
1 parent e2e6a04 commit 851fc05
Show file tree
Hide file tree
Showing 8 changed files with 363 additions and 56 deletions.
2 changes: 1 addition & 1 deletion internal/adapters/api/auth_handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ func (h *AuthHandler) Register(c *gin.Context) {
return
}

c.JSON(http.StatusOK, response)
c.JSON(http.StatusCreated, response)
}

func (h *AuthHandler) Logout(c *gin.Context) {
Expand Down
61 changes: 18 additions & 43 deletions internal/adapters/api/comment_handler.go
Original file line number Diff line number Diff line change
@@ -1,12 +1,9 @@
package api

import (
"gcstatus/internal/domain"
"gcstatus/internal/errors"
"gcstatus/internal/resources"
"gcstatus/internal/ports"
"gcstatus/internal/usecases"
"gcstatus/internal/utils"
"gcstatus/pkg/s3"
"net/http"
"strconv"

Expand All @@ -19,79 +16,57 @@ type CommentHandler struct {
}

func NewCommentHandler(
userServuce *usecases.UserService,
userService *usecases.UserService,
commentService *usecases.CommentService,
) *CommentHandler {
return &CommentHandler{
userService: userServuce,
userService: userService,
commentService: commentService,
}
}

func (h *CommentHandler) Create(c *gin.Context) {
user, err := utils.Auth(c, h.userService.GetUserByID)
if err != nil {
RespondWithError(c, http.StatusUnauthorized, "Unauthorized: "+err.Error())
return
}

var request struct {
ParentID *uint `json:"parent_id"`
Comment string `json:"comment" binding:"required"`
CommentableID uint `json:"commentable_id" binding:"required"`
CommentableType string `json:"commentable_type" binding:"required"`
}
var request ports.CommentStorePayload

if err := c.ShouldBindJSON(&request); err != nil {
RespondWithError(c, http.StatusUnprocessableEntity, "Invalid request data")
return
}

commentable := domain.Commentable{
UserID: user.ID,
Comment: request.Comment,
CommentableID: request.CommentableID,
CommentableType: request.CommentableType,
ParentID: request.ParentID,
}

comment, err := h.commentService.Create(commentable)
user, err := utils.Auth(c, h.userService.GetUserByID)
if err != nil {
RespondWithError(c, http.StatusInternalServerError, "Failed to create comment.")
RespondWithError(c, http.StatusUnauthorized, "Failed to create comment: could not authenticate user.")
return
}

transformedComment := resources.TransformCommentable(*comment, s3.GlobalS3Client, user.ID)

response := resources.Response{
Data: transformedComment,
response, httpErr := h.commentService.Create(user, request)
if httpErr != nil {
RespondWithError(c, httpErr.Code, httpErr.Error())
return
}

c.JSON(http.StatusCreated, response)
}

func (h *CommentHandler) Delete(c *gin.Context) {
commentIDStr := c.Param("id")
user, err := utils.Auth(c, h.userService.GetUserByID)
commentID, err := strconv.ParseUint(commentIDStr, 10, 32)
if err != nil {
RespondWithError(c, http.StatusUnauthorized, "Unauthorized: "+err.Error())
RespondWithError(c, http.StatusBadRequest, "Invalid comment ID: "+err.Error())
return
}

commentID, err := strconv.ParseUint(commentIDStr, 10, 32)
user, err := utils.Auth(c, h.userService.GetUserByID)
if err != nil {
RespondWithError(c, http.StatusBadRequest, "Invalid comment ID: "+err.Error())
RespondWithError(c, http.StatusUnauthorized, "Unauthorized: "+err.Error())
return
}

if err := h.commentService.Delete(uint(commentID), user.ID); err != nil {
if httpErr, ok := err.(*errors.HttpError); ok {
RespondWithError(c, httpErr.Code, httpErr.Error())
} else {
RespondWithError(c, http.StatusInternalServerError, "Failed to delete comment: "+err.Error())
}
response, httpErr := h.commentService.Delete(uint(commentID), user.ID)
if httpErr != nil {
RespondWithError(c, httpErr.Code, httpErr.Error())
return
}

c.JSON(http.StatusOK, gin.H{"message": "Your comment was successfully removed!"})
c.JSON(http.StatusOK, response)
}
10 changes: 8 additions & 2 deletions internal/adapters/api/handler_interface.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,14 @@
package api

import "github.com/gin-gonic/gin"
import (
"gcstatus/internal/resources"

"github.com/gin-gonic/gin"
)

// Helper to respond with error
func RespondWithError(c *gin.Context, statusCode int, message string) {
c.JSON(statusCode, gin.H{"message": message})
c.JSON(statusCode, resources.Response{
Data: gin.H{"message": message},
})
}
7 changes: 7 additions & 0 deletions internal/ports/comment_repository.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,13 @@ package ports

import "gcstatus/internal/domain"

type CommentStorePayload struct {
ParentID *uint `json:"parent_id"`
Comment string `json:"comment" binding:"required"`
CommentableID uint `json:"commentable_id" binding:"required"`
CommentableType string `json:"commentable_type" binding:"required"`
}

type CommentRepository interface {
FindByID(id uint) (*domain.Commentable, error)
Create(commentable domain.Commentable) (*domain.Commentable, error)
Expand Down
42 changes: 35 additions & 7 deletions internal/usecases/comment_service.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,12 @@ import (
"gcstatus/internal/domain"
"gcstatus/internal/errors"
"gcstatus/internal/ports"
"gcstatus/internal/resources"
"gcstatus/pkg/s3"
"log"
"net/http"

"github.com/gin-gonic/gin"
)

type CommentService struct {
Expand All @@ -15,23 +20,46 @@ func NewCommentService(repo ports.CommentRepository) *CommentService {
return &CommentService{repo: repo}
}

func (h *CommentService) Create(commentable domain.Commentable) (*domain.Commentable, error) {
return h.repo.Create(commentable)
func (h *CommentService) Create(user *domain.User, payload ports.CommentStorePayload) (resources.Response, *errors.HttpError) {
commentable := domain.Commentable{
UserID: user.ID,
Comment: payload.Comment,
CommentableID: payload.CommentableID,
CommentableType: payload.CommentableType,
ParentID: payload.ParentID,
}

comment, err := h.repo.Create(commentable)
if err != nil {
log.Printf("failed to create comment: %+v.\n err: %+v", commentable, err)
return resources.Response{}, errors.NewHttpError(http.StatusInternalServerError, "Failed to create comment. Please, try again later.")
}

transformedComment := resources.TransformCommentable(*comment, s3.GlobalS3Client, user.ID)

response := resources.Response{
Data: transformedComment,
}

return response, nil
}

func (h *CommentService) Delete(id uint, userID uint) error {
func (h *CommentService) Delete(id uint, userID uint) (resources.Response, *errors.HttpError) {
comment, err := h.repo.FindByID(id)
if err != nil {
return err
return resources.Response{}, errors.NewHttpError(http.StatusNotFound, "Could not found the given comment!")
}

if comment.UserID != userID {
return errors.NewHttpError(http.StatusForbidden, "This comment does not belongs to you user!")
return resources.Response{}, errors.NewHttpError(http.StatusForbidden, "This comment does not belongs to you user!")
}

if err := h.repo.Delete(id); err != nil {
return err
log.Printf("failed to delete comment: %+v.\n err: %+v", comment, err)
return resources.Response{}, errors.NewHttpError(http.StatusInternalServerError, "We could not delete the given comment. Please, try again later.")
}

return nil
return resources.Response{
Data: gin.H{"message": "Your comment was successfully removed!"},
}, nil
}
45 changes: 45 additions & 0 deletions tests/data/mocks/has_dummy_comment.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package test_mocks

import (
"gcstatus/internal/domain"
"testing"

"gorm.io/gorm"
)

func CreateDummyComment(t *testing.T, dbConn *gorm.DB, overrides *domain.Commentable) (*domain.Commentable, error) {

defaultComment := domain.Commentable{
Comment: "Testing comment",
CommentableID: 1,
CommentableType: "games",
}

if overrides != nil {
if overrides.Comment != "" {
defaultComment.Comment = overrides.Comment
}
if overrides.CommentableID != 0 {
defaultComment.CommentableID = overrides.CommentableID
}
if overrides.CommentableType != "" {
defaultComment.CommentableType = overrides.CommentableType
}
if overrides.User.ID != 0 {
defaultComment.User = overrides.User
} else {
user, err := CreateDummyUser(t, dbConn, &overrides.User)
if err != nil {
t.Fatalf("failed to create dummy user for comment: %+v", err)
}

defaultComment.User = *user
}
}

if err := dbConn.Create(&defaultComment).Error; err != nil {
return nil, err
}

return &defaultComment, nil
}
25 changes: 22 additions & 3 deletions tests/feature/api/auth_handler_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -169,8 +169,11 @@ func TestAuthHandler_Me(t *testing.T) {
}
}
} else {
assert.Contains(t, responseBody, "message")
assert.Equal(t, tc.expectResponse["message"], responseBody["message"])
if data, exists := tc.expectResponse["data"]; exists {
if message, exists := data.(map[string]any)["message"]; exists {
assert.Equal(t, message, responseBody["message"], "unexpected response message")
}
}
}
})
}
Expand Down Expand Up @@ -238,7 +241,7 @@ func TestAuthHandler_Register(t *testing.T) {
"password": "Password@123",
"password_confirmation": "Password@123"
}`,
expectCode: http.StatusOK,
expectCode: http.StatusCreated,
expectResponse: "User registered successfully",
},
"password mismatch": {
Expand Down Expand Up @@ -315,6 +318,22 @@ func TestAuthHandler_Register(t *testing.T) {

assert.Equal(t, tc.expectCode, w.Code)
assert.Contains(t, w.Body.String(), tc.expectResponse)

if w.Code == http.StatusCreated {
var payloadData map[string]any
json.Unmarshal([]byte(tc.payload), &payloadData)

Check failure on line 324 in tests/feature/api/auth_handler_test.go

View workflow job for this annotation

GitHub Actions / Running tests - GoLang v1.22.0

Error return value of `json.Unmarshal` is not checked (errcheck)

email := payloadData["email"].(string)

var createdUser domain.User
err := dbConn.Where("email = ?", email).First(&createdUser).Error
assert.NoError(t, err, "User record should exist in the database")
assert.Equal(t, payloadData["name"], createdUser.Name)
assert.Equal(t, payloadData["email"], createdUser.Email)
assert.Equal(t, payloadData["nickname"], createdUser.Nickname)
assert.Equal(t, payloadData["birthdate"], createdUser.Birthdate.UTC().Format("2006-01-02"))
assert.True(t, utils.IsHashEqualsValue(createdUser.Password, payloadData["password"].(string)))
}
})
}

Expand Down
Loading

0 comments on commit 851fc05

Please sign in to comment.