From 6a5fc5658f09c3d0cc11f7fea3c2c0f50dc79283 Mon Sep 17 00:00:00 2001 From: garrettladley Date: Sat, 27 Jan 2024 15:07:20 -0500 Subject: [PATCH] migration complete --- backend/go.mod | 2 +- backend/src/database/db.go | 6 + backend/src/errors/error.go | 4 +- backend/src/models/category.go | 4 +- backend/src/models/club.go | 8 +- backend/src/models/comment.go | 18 +-- backend/src/models/contact.go | 8 +- backend/src/models/event.go | 4 +- backend/src/models/notification.go | 6 +- backend/src/models/point_of_contact.go | 8 +- .../{types/root_model.go => models/root.go} | 6 +- backend/src/models/tag.go | 14 +- backend/src/models/user.go | 4 +- backend/src/services/category.go | 12 +- backend/src/services/tag.go | 12 +- backend/src/services/user.go | 12 +- backend/src/transactions/category.go | 7 +- backend/src/transactions/tag.go | 7 +- backend/src/transactions/user.go | 7 +- backend/src/utilities/validator.go | 11 +- backend/tests/api/category_test.go | 145 +++++++++++++----- backend/tests/api/helpers.go | 6 +- backend/tests/api/tag_test.go | 96 +++++++----- backend/tests/api/user_test.go | 104 +++++++------ 24 files changed, 311 insertions(+), 200 deletions(-) rename backend/src/{types/root_model.go => models/root.go} (61%) diff --git a/backend/go.mod b/backend/go.mod index 1ef878c4d..e8404efb9 100644 --- a/backend/go.mod +++ b/backend/go.mod @@ -27,7 +27,7 @@ require ( github.com/go-playground/locales v0.14.1 // indirect github.com/go-playground/universal-translator v0.18.1 // indirect github.com/goccy/go-json v0.10.2 - github.com/google/uuid v1.5.0 // indirect + github.com/google/uuid v1.5.0 github.com/hashicorp/hcl v1.0.0 // indirect github.com/huandu/go-assert v1.1.6 github.com/jackc/pgpassfile v1.0.0 // indirect diff --git a/backend/src/database/db.go b/backend/src/database/db.go index 20b2b955d..2d8d3b9bf 100644 --- a/backend/src/database/db.go +++ b/backend/src/database/db.go @@ -21,6 +21,12 @@ func ConfigureDB(settings config.Settings) (*gorm.DB, error) { return nil, err } + err = db.Exec("CREATE EXTENSION IF NOT EXISTS \"uuid-ossp\"").Error + + if err != nil { + return nil, err + } + if err := MigrateDB(settings, db); err != nil { return nil, err } diff --git a/backend/src/errors/error.go b/backend/src/errors/error.go index c59c20262..ee5035f4e 100644 --- a/backend/src/errors/error.go +++ b/backend/src/errors/error.go @@ -9,10 +9,10 @@ type Error struct { Message string } -func (e Error) FiberError(c *fiber.Ctx) error { +func (e *Error) FiberError(c *fiber.Ctx) error { return c.Status(e.StatusCode).JSON(fiber.Map{"error": e.Message}) } -func (e Error) Error() string { +func (e *Error) Error() string { return e.Message } diff --git a/backend/src/models/category.go b/backend/src/models/category.go index d5ceb7d46..6f9770557 100644 --- a/backend/src/models/category.go +++ b/backend/src/models/category.go @@ -1,9 +1,7 @@ package models -import "github.com/GenerateNU/sac/backend/src/types" - type Category struct { - types.Model + Model Name string `gorm:"type:varchar(255);unique" json:"name" validate:"required,max=255"` Tag []Tag `gorm:"constraint:OnUpdate:CASCADE,OnDelete:CASCADE;" json:"-" validate:"-"` diff --git a/backend/src/models/club.go b/backend/src/models/club.go index b512fa3ee..01542a7be 100644 --- a/backend/src/models/club.go +++ b/backend/src/models/club.go @@ -3,7 +3,7 @@ package models import ( "time" - "github.com/GenerateNU/sac/backend/src/types" + "github.com/google/uuid" ) type RecruitmentCycle string @@ -24,7 +24,7 @@ const ( ) type Club struct { - types.Model + Model SoftDeletedAt time.Time `gorm:"type:timestamptz;default:NULL" json:"-" validate:"-"` @@ -38,8 +38,8 @@ type Club struct { ApplicationLink string `gorm:"type:varchar(255);default:NULL" json:"application_link" validate:"required,max=255"` Logo string `gorm:"type:varchar(255);default:NULL" json:"logo" validate:"url,max=255"` // S3 URL - Parent *uint `gorm:"foreignKey:Parent" json:"-" validate:"min=1"` - Tag []Tag `gorm:"many2many:club_tags;constraint:OnUpdate:CASCADE,OnDelete:CASCADE;" json:"-" validate:"-"` + Parent *uuid.UUID `gorm:"foreignKey:Parent" json:"-" validate:"uuid4"` + Tag []Tag `gorm:"many2many:club_tags;constraint:OnUpdate:CASCADE,OnDelete:CASCADE;" json:"-" validate:"-"` // User Member []User `gorm:"many2many:user_club_members;constraint:OnUpdate:CASCADE,OnDelete:CASCADE;" json:"-" validate:"required"` Follower []User `gorm:"many2many:user_club_followers;constraint:OnUpdate:CASCADE,OnDelete:CASCADE;" json:"-" validate:"-"` diff --git a/backend/src/models/comment.go b/backend/src/models/comment.go index 043c42d15..9e2bb9eb1 100644 --- a/backend/src/models/comment.go +++ b/backend/src/models/comment.go @@ -1,22 +1,20 @@ package models -import ( - "github.com/GenerateNU/sac/backend/src/types" -) +import "github.com/google/uuid" type Comment struct { - types.Model + Model Question string `gorm:"type:varchar(255)" json:"question" validate:"required,max=255"` Answer string `gorm:"type:varchar(255)" json:"answer" validate:",max=255"` NumFoundHelpful uint `gorm:"type:int;default:0" json:"num_found_helpful" validate:"min=0"` - AskedByID uint `gorm:"type:uuid" json:"-" validate:"min=1"` - AskedBy User `gorm:"foreignKey:AskedByID" json:"-" validate:"-"` + AskedByID uuid.UUID `gorm:"type:uuid" json:"-" validate:"uuid4"` + AskedBy User `gorm:"foreignKey:AskedByID" json:"-" validate:"-"` - ClubID uint `gorm:"type:uuid" json:"-" validate:"min=1"` - Club Club `gorm:"foreignKey:ClubID" json:"-" validate:"-"` + ClubID uuid.UUID `gorm:"type:uuid" json:"-" validate:"uuid4"` + Club Club `gorm:"foreignKey:ClubID" json:"-" validate:"-"` - AnsweredByID *uint `gorm:"type:uuid" json:"-" validate:"min=1"` - AnsweredBy *User `gorm:"foreignKey:AnsweredBy" json:"-" validate:"-"` + AnsweredByID *uuid.UUID `gorm:"type:uuid" json:"-" validate:"uuid4"` + AnsweredBy *User `gorm:"foreignKey:AnsweredBy" json:"-" validate:"-"` } diff --git a/backend/src/models/contact.go b/backend/src/models/contact.go index 5e4f74c0b..93e2b2bce 100644 --- a/backend/src/models/contact.go +++ b/backend/src/models/contact.go @@ -1,8 +1,6 @@ package models -import ( - "github.com/GenerateNU/sac/backend/src/types" -) +import "github.com/google/uuid" type Media string @@ -17,10 +15,10 @@ const ( ) type Contact struct { - types.Model + Model Type Media `gorm:"type:varchar(255)" json:"type" validate:"required,max=255"` Content string `gorm:"type:varchar(255)" json:"content" validate:"required,url,max=255"` // media URL - ClubID uint `gorm:"foreignKey:ClubID" json:"-" validate:"min=1"` + ClubID uuid.UUID `gorm:"foreignKey:ClubID" json:"-" validate:"uuid4"` } diff --git a/backend/src/models/event.go b/backend/src/models/event.go index 075e47e1f..ad155ef39 100644 --- a/backend/src/models/event.go +++ b/backend/src/models/event.go @@ -2,8 +2,6 @@ package models import ( "time" - - "github.com/GenerateNU/sac/backend/src/types" ) type EventType string @@ -14,7 +12,7 @@ const ( ) type Event struct { - types.Model + Model Name string `gorm:"type:varchar(255)" json:"name" validate:"required,max=255"` Preview string `gorm:"type:varchar(255)" json:"preview" validate:"required,max=255"` diff --git a/backend/src/models/notification.go b/backend/src/models/notification.go index cc15ab032..d20db3288 100644 --- a/backend/src/models/notification.go +++ b/backend/src/models/notification.go @@ -3,7 +3,7 @@ package models import ( "time" - "github.com/GenerateNU/sac/backend/src/types" + "github.com/google/uuid" ) type NotificationType string @@ -14,7 +14,7 @@ const ( ) type Notification struct { - types.Model + Model SendAt time.Time `gorm:"type:timestamptz" json:"send_at" validate:"required"` Title string `gorm:"type:varchar(255)" json:"title" validate:"required,max=255"` @@ -22,6 +22,6 @@ type Notification struct { DeepLink string `gorm:"type:varchar(255)" json:"deep_link" validate:"required,max=255"` Icon string `gorm:"type:varchar(255)" json:"icon" validate:"required,url,max=255"` // S3 URL - ReferenceID uint `gorm:"type:int" json:"-" validate:"min=1"` + ReferenceID uuid.UUID `gorm:"type:int" json:"-" validate:"uuid4"` ReferenceType NotificationType `gorm:"type:varchar(255)" json:"-" validate:"max=255"` } diff --git a/backend/src/models/point_of_contact.go b/backend/src/models/point_of_contact.go index e8a4b024a..a6b6ffab1 100644 --- a/backend/src/models/point_of_contact.go +++ b/backend/src/models/point_of_contact.go @@ -1,16 +1,14 @@ package models -import ( - "github.com/GenerateNU/sac/backend/src/types" -) +import "github.com/google/uuid" type PointOfContact struct { - types.Model + Model Name string `gorm:"type:varchar(255)" json:"name" validate:"required,max=255"` Email string `gorm:"type:varchar(255)" json:"email" validate:"required,email,max=255"` Photo string `gorm:"type:varchar(255);default:NULL" json:"photo" validate:"url,max=255"` // S3 URL, fallback to default logo if null Position string `gorm:"type:varchar(255);" json:"position" validate:"required,max=255"` - ClubID uint `gorm:"foreignKey:ClubID" json:"-" validate:"min=1"` + ClubID uuid.UUID `gorm:"foreignKey:ClubID" json:"-" validate:"uuid4"` } diff --git a/backend/src/types/root_model.go b/backend/src/models/root.go similarity index 61% rename from backend/src/types/root_model.go rename to backend/src/models/root.go index 341b761c9..a1babc13a 100644 --- a/backend/src/types/root_model.go +++ b/backend/src/models/root.go @@ -1,11 +1,13 @@ -package types +package models import ( "time" + + "github.com/google/uuid" ) type Model struct { - ID uint `gorm:"primarykey" json:"id" example:"1"` + ID uuid.UUID `gorm:"type:uuid;primary_key;default:uuid_generate_v4()" json:"id" example:"123e4567-e89b-12d3-a456-426614174000"` CreatedAt time.Time `gorm:"type:timestamp;default:CURRENT_TIMESTAMP" json:"created_at" example:"2023-09-20T16:34:50Z"` UpdatedAt time.Time `gorm:"type:timestamp;default:CURRENT_TIMESTAMP" json:"updated_at" example:"2023-09-20T16:34:50Z"` } diff --git a/backend/src/models/tag.go b/backend/src/models/tag.go index 7594c8459..471b8b2ae 100644 --- a/backend/src/models/tag.go +++ b/backend/src/models/tag.go @@ -1,15 +1,13 @@ package models -import ( - "github.com/GenerateNU/sac/backend/src/types" -) +import "github.com/google/uuid" type Tag struct { - types.Model + Model Name string `gorm:"type:varchar(255)" json:"name" validate:"required,max=255"` - CategoryID uint `gorm:"foreignKey:CategoryID" json:"category_id" validate:"required,min=1"` + CategoryID uuid.UUID `gorm:"foreignKey:CategoryID" json:"category_id" validate:"required,uuid4"` User []User `gorm:"many2many:user_tags;constraint:OnUpdate:CASCADE,OnDelete:CASCADE;" json:"-" validate:"-"` Club []Club `gorm:"many2many:club_tags;constraint:OnUpdate:CASCADE,OnDelete:CASCADE;" json:"-" validate:"-"` @@ -17,6 +15,6 @@ type Tag struct { } type TagRequestBody struct { - Name string `json:"name" validate:"required,max=255"` - CategoryID uint `json:"category_id" validate:"required,min=1"` -} \ No newline at end of file + Name string `json:"name" validate:"required,max=255"` + CategoryID uuid.UUID `json:"category_id" validate:"required,uuid4"` +} diff --git a/backend/src/models/user.go b/backend/src/models/user.go index 1f6b3aa7e..1242ee4e3 100644 --- a/backend/src/models/user.go +++ b/backend/src/models/user.go @@ -1,7 +1,5 @@ package models -import "github.com/GenerateNU/sac/backend/src/types" - type UserRole string const ( @@ -36,7 +34,7 @@ const ( ) type User struct { - types.Model + Model Role UserRole `gorm:"type:varchar(255);" json:"user_role,omitempty" validate:"required,max=255"` NUID string `gorm:"column:nuid;type:varchar(9);unique" json:"nuid" validate:"required,numeric,len=9"` diff --git a/backend/src/services/category.go b/backend/src/services/category.go index 523b41e09..91aabe3db 100644 --- a/backend/src/services/category.go +++ b/backend/src/services/category.go @@ -61,17 +61,17 @@ func (c *CategoryService) GetCategories(limit string, page string) ([]models.Cat } func (c *CategoryService) GetCategory(id string) (*models.Category, *errors.Error) { - uintId, err := utilities.ValidateID(id) + idAsUUID, err := utilities.ValidateID(id) if err != nil { return nil, err } - return transactions.GetCategory(c.DB, *uintId) + return transactions.GetCategory(c.DB, *idAsUUID) } func (c *CategoryService) UpdateCategory(id string, categoryBody models.CategoryRequestBody) (*models.Category, *errors.Error) { - idAsUint, idErr := utilities.ValidateID(id) + idAsUUID, idErr := utilities.ValidateID(id) if idErr != nil { return nil, idErr } @@ -87,14 +87,14 @@ func (c *CategoryService) UpdateCategory(id string, categoryBody models.Category category.Name = cases.Title(language.English).String(category.Name) - return transactions.UpdateCategory(c.DB, *idAsUint, *category) + return transactions.UpdateCategory(c.DB, *idAsUUID, *category) } func (c *CategoryService) DeleteCategory(id string) *errors.Error { - idAsUInt, err := utilities.ValidateID(id) + idAsUUID, err := utilities.ValidateID(id) if err != nil { return err } - return transactions.DeleteCategory(c.DB, *idAsUInt) + return transactions.DeleteCategory(c.DB, *idAsUUID) } diff --git a/backend/src/services/tag.go b/backend/src/services/tag.go index b5ebac64f..0abbd15bc 100644 --- a/backend/src/services/tag.go +++ b/backend/src/services/tag.go @@ -35,16 +35,16 @@ func (t *TagService) CreateTag(tagBody models.TagRequestBody) (*models.Tag, *err } func (t *TagService) GetTag(id string) (*models.Tag, *errors.Error) { - idAsUint, err := utilities.ValidateID(id) + idAsUUID, err := utilities.ValidateID(id) if err != nil { return nil, err } - return transactions.GetTag(t.DB, *idAsUint) + return transactions.GetTag(t.DB, *idAsUUID) } func (t *TagService) UpdateTag(id string, tagBody models.TagRequestBody) (*models.Tag, *errors.Error) { - idAsUint, idErr := utilities.ValidateID(id) + idAsUUID, idErr := utilities.ValidateID(id) if idErr != nil { return nil, idErr } @@ -58,14 +58,14 @@ func (t *TagService) UpdateTag(id string, tagBody models.TagRequestBody) (*model return nil, &errors.FailedToMapRequestToModel } - return transactions.UpdateTag(t.DB, *idAsUint, *tag) + return transactions.UpdateTag(t.DB, *idAsUUID, *tag) } func (t *TagService) DeleteTag(id string) *errors.Error { - idAsUint, err := utilities.ValidateID(id) + idAsUUID, err := utilities.ValidateID(id) if err != nil { return &errors.FailedToValidateID } - return transactions.DeleteTag(t.DB, *idAsUint) + return transactions.DeleteTag(t.DB, *idAsUUID) } diff --git a/backend/src/services/user.go b/backend/src/services/user.go index 324e37d56..d77d9cd79 100644 --- a/backend/src/services/user.go +++ b/backend/src/services/user.go @@ -66,16 +66,16 @@ func (u *UserService) GetUsers(limit string, page string) ([]models.User, *error } func (u *UserService) GetUser(id string) (*models.User, *errors.Error) { - idAsUint, err := utilities.ValidateID(id) + idAsUUID, err := utilities.ValidateID(id) if err != nil { return nil, &errors.FailedToValidateID } - return transactions.GetUser(u.DB, *idAsUint) + return transactions.GetUser(u.DB, *idAsUUID) } func (u *UserService) UpdateUser(id string, userBody models.UpdateUserRequestBody) (*models.User, *errors.Error) { - idAsUint, idErr := utilities.ValidateID(id) + idAsUUID, idErr := utilities.ValidateID(id) if idErr != nil { return nil, idErr } @@ -96,14 +96,14 @@ func (u *UserService) UpdateUser(id string, userBody models.UpdateUserRequestBod user.PasswordHash = *passwordHash - return transactions.UpdateUser(u.DB, *idAsUint, *user) + return transactions.UpdateUser(u.DB, *idAsUUID, *user) } func (u *UserService) DeleteUser(id string) *errors.Error { - idAsInt, err := utilities.ValidateID(id) + idAsUUID, err := utilities.ValidateID(id) if err != nil { return err } - return transactions.DeleteUser(u.DB, *idAsInt) + return transactions.DeleteUser(u.DB, *idAsUUID) } diff --git a/backend/src/transactions/category.go b/backend/src/transactions/category.go index bf7713fe0..8d5be8392 100644 --- a/backend/src/transactions/category.go +++ b/backend/src/transactions/category.go @@ -4,6 +4,7 @@ import ( stdliberrors "errors" "github.com/GenerateNU/sac/backend/src/errors" + "github.com/google/uuid" "github.com/GenerateNU/sac/backend/src/models" @@ -32,7 +33,7 @@ func GetCategories(db *gorm.DB, limit int, offset int) ([]models.Category, *erro return categories, nil } -func GetCategory(db *gorm.DB, id uint) (*models.Category, *errors.Error) { +func GetCategory(db *gorm.DB, id uuid.UUID) (*models.Category, *errors.Error) { var category models.Category if err := db.First(&category, id).Error; err != nil { @@ -46,7 +47,7 @@ func GetCategory(db *gorm.DB, id uint) (*models.Category, *errors.Error) { return &category, nil } -func UpdateCategory(db *gorm.DB, id uint, category models.Category) (*models.Category, *errors.Error) { +func UpdateCategory(db *gorm.DB, id uuid.UUID, category models.Category) (*models.Category, *errors.Error) { if err := db.Model(&models.Category{}).Where("id = ?", id).Updates(category).First(&category, id).Error; err != nil { if stdliberrors.Is(err, gorm.ErrRecordNotFound) { return nil, &errors.TagNotFound @@ -58,7 +59,7 @@ func UpdateCategory(db *gorm.DB, id uint, category models.Category) (*models.Cat return &category, nil } -func DeleteCategory(db *gorm.DB, id uint) *errors.Error { +func DeleteCategory(db *gorm.DB, id uuid.UUID) *errors.Error { if result := db.Delete(&models.Category{}, id); result.RowsAffected == 0 { if result.Error == nil { return &errors.CategoryNotFound diff --git a/backend/src/transactions/tag.go b/backend/src/transactions/tag.go index 9214ca683..cefc99740 100644 --- a/backend/src/transactions/tag.go +++ b/backend/src/transactions/tag.go @@ -4,6 +4,7 @@ import ( stdliberrors "errors" "github.com/GenerateNU/sac/backend/src/errors" + "github.com/google/uuid" "github.com/GenerateNU/sac/backend/src/models" @@ -18,7 +19,7 @@ func CreateTag(db *gorm.DB, tag models.Tag) (*models.Tag, *errors.Error) { return &tag, nil } -func GetTag(db *gorm.DB, id uint) (*models.Tag, *errors.Error) { +func GetTag(db *gorm.DB, id uuid.UUID) (*models.Tag, *errors.Error) { var tag models.Tag if err := db.First(&tag, id).Error; err != nil { @@ -32,7 +33,7 @@ func GetTag(db *gorm.DB, id uint) (*models.Tag, *errors.Error) { return &tag, nil } -func UpdateTag(db *gorm.DB, id uint, tag models.Tag) (*models.Tag, *errors.Error) { +func UpdateTag(db *gorm.DB, id uuid.UUID, tag models.Tag) (*models.Tag, *errors.Error) { if err := db.Model(&models.Tag{}).Where("id = ?", id).Updates(tag).First(&tag, id).Error; err != nil { if stdliberrors.Is(err, gorm.ErrRecordNotFound) { return nil, &errors.TagNotFound @@ -44,7 +45,7 @@ func UpdateTag(db *gorm.DB, id uint, tag models.Tag) (*models.Tag, *errors.Error return &tag, nil } -func DeleteTag(db *gorm.DB, id uint) *errors.Error { +func DeleteTag(db *gorm.DB, id uuid.UUID) *errors.Error { if result := db.Delete(&models.Tag{}, id); result.RowsAffected == 0 { if result.Error == nil { return &errors.TagNotFound diff --git a/backend/src/transactions/user.go b/backend/src/transactions/user.go index 9fb868ee6..75d51b147 100644 --- a/backend/src/transactions/user.go +++ b/backend/src/transactions/user.go @@ -5,6 +5,7 @@ import ( "github.com/GenerateNU/sac/backend/src/errors" "github.com/GenerateNU/sac/backend/src/models" + "github.com/google/uuid" "gorm.io/gorm" ) @@ -31,7 +32,7 @@ func GetUsers(db *gorm.DB, limit int, offset int) ([]models.User, *errors.Error) return users, nil } -func GetUser(db *gorm.DB, id uint) (*models.User, *errors.Error) { +func GetUser(db *gorm.DB, id uuid.UUID) (*models.User, *errors.Error) { var user models.User if err := db.Omit("password_hash").First(&user, id).Error; err != nil { if stdliberrors.Is(err, gorm.ErrRecordNotFound) { @@ -44,7 +45,7 @@ func GetUser(db *gorm.DB, id uint) (*models.User, *errors.Error) { return &user, nil } -func UpdateUser(db *gorm.DB, id uint, user models.User) (*models.User, *errors.Error) { +func UpdateUser(db *gorm.DB, id uuid.UUID, user models.User) (*models.User, *errors.Error) { var existingUser models.User err := db.First(&existingUser, id).Error @@ -63,7 +64,7 @@ func UpdateUser(db *gorm.DB, id uint, user models.User) (*models.User, *errors.E return &existingUser, nil } -func DeleteUser(db *gorm.DB, id uint) *errors.Error { +func DeleteUser(db *gorm.DB, id uuid.UUID) *errors.Error { result := db.Delete(&models.User{}, id) if result.RowsAffected == 0 { if result.Error == nil { diff --git a/backend/src/utilities/validator.go b/backend/src/utilities/validator.go index c42fd8863..5ec5d71d3 100644 --- a/backend/src/utilities/validator.go +++ b/backend/src/utilities/validator.go @@ -5,6 +5,7 @@ import ( "strconv" "github.com/GenerateNU/sac/backend/src/errors" + "github.com/google/uuid" "github.com/go-playground/validator/v10" "github.com/mcnijman/go-emailaddress" @@ -38,16 +39,14 @@ func ValidatePassword(fl validator.FieldLevel) bool { } // Validates that an id follows postgres uint format, returns a uint otherwise returns an error -func ValidateID(id string) (*uint, *errors.Error) { - idAsInt, err := strconv.Atoi(id) +func ValidateID(id string) (*uuid.UUID, *errors.Error) { + idAsUUID, err := uuid.Parse(id) - if err != nil || idAsInt < 1 { // postgres ids start at 1 + if err != nil { return nil, &errors.FailedToValidateID } - idAsUint := uint(idAsInt) - - return &idAsUint, nil + return &idAsUUID, nil } func ValidateNonNegative(value string) (*int, *errors.Error) { diff --git a/backend/tests/api/category_test.go b/backend/tests/api/category_test.go index 9683ceea0..7eb5c9cea 100644 --- a/backend/tests/api/category_test.go +++ b/backend/tests/api/category_test.go @@ -8,9 +8,8 @@ import ( "github.com/GenerateNU/sac/backend/src/errors" "github.com/GenerateNU/sac/backend/src/models" "github.com/gofiber/fiber/v2" + "github.com/google/uuid" "github.com/huandu/go-assert" - "golang.org/x/text/cases" - "golang.org/x/text/language" "github.com/goccy/go-json" ) @@ -21,7 +20,32 @@ func SampleCategoryFactory() *map[string]interface{} { } } -func AssertCategoryWithIDBodyRespDB(app TestApp, assert *assert.A, resp *http.Response, id uint, body *map[string]interface{}) { +func AssertCategoryBodyRespDB(app TestApp, assert *assert.A, resp *http.Response, body *map[string]interface{}) uuid.UUID { + var respCategory models.Category + + err := json.NewDecoder(resp.Body).Decode(&respCategory) + + assert.NilError(err) + + var dbCategories []models.Category + + err = app.Conn.Find(&dbCategories).Error + + assert.NilError(err) + + assert.Equal(1, len(dbCategories)) + + dbCategory := dbCategories[0] + + assert.Equal(dbCategory.ID, respCategory.ID) + assert.Equal(dbCategory.Name, respCategory.Name) + + assert.Equal((*body)["name"].(string), dbCategory.Name) + + return dbCategory.ID +} + +func AssertCategoryWithBodyRespDBMostRecent(app TestApp, assert *assert.A, resp *http.Response, body *map[string]interface{}) uuid.UUID { var respCategory models.Category err := json.NewDecoder(resp.Body).Decode(&respCategory) @@ -30,7 +54,7 @@ func AssertCategoryWithIDBodyRespDB(app TestApp, assert *assert.A, resp *http.Re var dbCategory models.Category - err = app.Conn.First(&dbCategory, id).Error + err = app.Conn.Last(&dbCategory).Error assert.NilError(err) @@ -38,27 +62,40 @@ func AssertCategoryWithIDBodyRespDB(app TestApp, assert *assert.A, resp *http.Re assert.Equal(dbCategory.Name, respCategory.Name) assert.Equal((*body)["name"].(string), dbCategory.Name) + + return dbCategory.ID } -func AssertSampleCategoryBodyRespDB(app TestApp, assert *assert.A, resp *http.Response) { - AssertCategoryWithIDBodyRespDB(app, assert, resp, 1, SampleCategoryFactory()) +func AssertSampleCategoryBodyRespDB(app TestApp, assert *assert.A, resp *http.Response) uuid.UUID { + return AssertCategoryBodyRespDB(app, assert, resp, SampleCategoryFactory()) } -func CreateSampleCategory(t *testing.T) ExistingAppAssert { - return TestRequest{ +func CreateSampleCategory(t *testing.T, existingAppAssert *ExistingAppAssert) (ExistingAppAssert, uuid.UUID) { + var sampleCategoryUUID uuid.UUID + + newAppAssert := TestRequest{ Method: fiber.MethodPost, Path: "/api/v1/categories/", Body: SampleCategoryFactory(), - }.TestOnStatusAndDB(t, nil, + }.TestOnStatusAndDB(t, existingAppAssert, DBTesterWithStatus{ - Status: fiber.StatusCreated, - DBTester: AssertSampleCategoryBodyRespDB, + Status: fiber.StatusCreated, + DBTester: func(app TestApp, assert *assert.A, resp *http.Response) { + sampleCategoryUUID = AssertSampleCategoryBodyRespDB(app, assert, resp) + }, }, ) + + if existingAppAssert == nil { + return newAppAssert, sampleCategoryUUID + } else { + return *existingAppAssert, sampleCategoryUUID + } } func TestCreateCategoryWorks(t *testing.T) { - CreateSampleCategory(t).Close() + existingAppAssert, _ := CreateSampleCategory(t, nil) + existingAppAssert.Close() } func TestCreateCategoryIgnoresid(t *testing.T) { @@ -71,8 +108,10 @@ func TestCreateCategoryIgnoresid(t *testing.T) { }, }.TestOnStatusAndDB(t, nil, DBTesterWithStatus{ - Status: fiber.StatusCreated, - DBTester: AssertSampleCategoryBodyRespDB, + Status: fiber.StatusCreated, + DBTester: func(app TestApp, assert *assert.A, resp *http.Response) { + AssertSampleCategoryBodyRespDB(app, assert, resp) + }, }, ).Close() } @@ -120,8 +159,7 @@ func TestCreateCategoryFailsIfNameIsMissing(t *testing.T) { } func TestCreateCategoryFailsIfCategoryWithThatNameAlreadyExists(t *testing.T) { - - existingAppAssert := CreateSampleCategory(t) + existingAppAssert, _ := CreateSampleCategory(t, nil) var TestNumCategoriesRemainsAt1 = func(app TestApp, assert *assert.A, resp *http.Response) { AssertNumCategoriesRemainsAtN(app, assert, resp, 1) @@ -147,15 +185,17 @@ func TestCreateCategoryFailsIfCategoryWithThatNameAlreadyExists(t *testing.T) { } func TestGetCategoryWorks(t *testing.T) { - existingAppAssert := CreateSampleCategory(t) + existingAppAssert, uuid := CreateSampleCategory(t, nil) TestRequest{ Method: "GET", - Path: "/api/v1/categories/1", + Path: fmt.Sprintf("/api/v1/categories/%s", uuid), }.TestOnStatusAndDB(t, &existingAppAssert, DBTesterWithStatus{ - Status: fiber.StatusOK, - DBTester: AssertSampleCategoryBodyRespDB, + Status: fiber.StatusOK, + DBTester: func(app TestApp, assert *assert.A, resp *http.Response) { + AssertSampleCategoryBodyRespDB(app, assert, resp) + }, }, ).Close() } @@ -180,12 +220,12 @@ func TestGetCategoryFailsBadRequest(t *testing.T) { func TestGetCategoryFailsNotFound(t *testing.T) { TestRequest{ Method: "GET", - Path: "/api/v1/categories/1", + Path: fmt.Sprintf("/api/v1/categories/%s", uuid.New()), }.TestOnError(t, nil, errors.CategoryNotFound).Close() } func TestGetCategoriesWorks(t *testing.T) { - existingAppAssert := CreateSampleCategory(t) + existingAppAssert, _ := CreateSampleCategory(t, nil) TestRequest{ Method: "GET", @@ -219,20 +259,46 @@ func TestGetCategoriesWorks(t *testing.T) { ).Close() } +func AssertUpdatedCategoryBodyRespDB(app TestApp, assert *assert.A, resp *http.Response, body *map[string]interface{}) { + var respCategory models.Category + + err := json.NewDecoder(resp.Body).Decode(&respCategory) + + assert.NilError(err) + + var dbCategories []models.Category + + err = app.Conn.Find(&dbCategories).Error + + assert.NilError(err) + + assert.Equal(1, len(dbCategories)) + + dbCategory := dbCategories[0] + + assert.Equal(dbCategory.ID, respCategory.ID) + assert.Equal(dbCategory.Name, respCategory.Name) + + assert.Equal((*body)["id"].(uuid.UUID), dbCategory.ID) + assert.Equal((*body)["name"].(string), dbCategory.Name) +} + func TestUpdateCategoryWorks(t *testing.T) { - existingAppAssert := CreateSampleCategory(t) + existingAppAssert, uuid := CreateSampleCategory(t, nil) - generateNUCategory := *SampleCategoryFactory() - generateNUCategory["name"] = cases.Title(language.English).String("GenerateNU") + category := map[string]interface{}{ + "id": uuid, + "name": "Arts & Crafts", + } var AssertUpdatedCategoryBodyRespDB = func(app TestApp, assert *assert.A, resp *http.Response) { - AssertCategoryWithIDBodyRespDB(app, assert, resp, 1, &generateNUCategory) + AssertUpdatedCategoryBodyRespDB(app, assert, resp, &category) } TestRequest{ Method: fiber.MethodPatch, - Path: "/api/v1/categories/1", - Body: &generateNUCategory, + Path: fmt.Sprintf("/api/v1/categories/%s", uuid), + Body: &category, }.TestOnStatusAndDB(t, &existingAppAssert, DBTesterWithStatus{ Status: fiber.StatusOK, @@ -242,12 +308,19 @@ func TestUpdateCategoryWorks(t *testing.T) { } func TestUpdateCategoryWorksWithSameDetails(t *testing.T) { - existingAppAssert := CreateSampleCategory(t) + existingAppAssert, uuid := CreateSampleCategory(t, nil) + + category := *SampleCategoryFactory() + category["id"] = uuid + + var AssertSampleCategoryBodyRespDB = func(app TestApp, assert *assert.A, resp *http.Response) { + AssertUpdatedCategoryBodyRespDB(app, assert, resp, &category) + } TestRequest{ Method: fiber.MethodPatch, - Path: "/api/v1/categories/1", - Body: SampleCategoryFactory(), + Path: fmt.Sprintf("/api/v1/categories/%s", uuid), + Body: &category, }.TestOnStatusAndDB(t, &existingAppAssert, DBTesterWithStatus{ Status: fiber.StatusOK, @@ -268,18 +341,18 @@ func TestUpdateCategoryFailsBadRequest(t *testing.T) { for _, badRequest := range badRequests { TestRequest{ Method: fiber.MethodPatch, - Path: fmt.Sprintf("/api/v1/tags/%s", badRequest), - Body: SampleTagFactory(), + Path: fmt.Sprintf("/api/v1/categories/%s", badRequest), + Body: SampleCategoryFactory(), }.TestOnError(t, nil, errors.FailedToValidateID).Close() } } func TestDeleteCategoryWorks(t *testing.T) { - existingAppAssert := CreateSampleCategory(t) + existingAppAssert, uuid := CreateSampleCategory(t, nil) TestRequest{ Method: fiber.MethodDelete, - Path: "/api/v1/categories/1", + Path: fmt.Sprintf("/api/v1/categories/%s", uuid), }.TestOnStatusAndDB(t, &existingAppAssert, DBTesterWithStatus{ Status: fiber.StatusNoContent, @@ -308,6 +381,6 @@ func TestDeleteCategoryFailsBadRequest(t *testing.T) { func TestDeleteCategoryFailsNotFound(t *testing.T) { TestRequest{ Method: fiber.MethodDelete, - Path: "/api/v1/categories/1", + Path: fmt.Sprintf("/api/v1/categories/%s", uuid.New()), }.TestOnError(t, nil, errors.CategoryNotFound).Close() } diff --git a/backend/tests/api/helpers.go b/backend/tests/api/helpers.go index c9fce06dc..13a7a95dc 100644 --- a/backend/tests/api/helpers.go +++ b/backend/tests/api/helpers.go @@ -109,6 +109,11 @@ func configureDatabase(config config.Settings) (*gorm.DB, error) { return nil, err } + err = dbWithDB.Exec("CREATE EXTENSION IF NOT EXISTS \"uuid-ossp\"").Error + + if err != nil { + return nil, err + } err = database.MigrateDB(config, dbWithDB) if err != nil { @@ -211,7 +216,6 @@ func (request TestRequest) TestOnError(t *testing.T, existingAppAssert *Existing err := json.NewDecoder(resp.Body).Decode(&respBody) assert.NilError(err) - assert.Equal(expectedError.Message, respBody["error"].(string)) assert.Equal(expectedError.StatusCode, resp.StatusCode) diff --git a/backend/tests/api/tag_test.go b/backend/tests/api/tag_test.go index 854061476..5d26b61ba 100644 --- a/backend/tests/api/tag_test.go +++ b/backend/tests/api/tag_test.go @@ -8,19 +8,20 @@ import ( "github.com/GenerateNU/sac/backend/src/errors" "github.com/GenerateNU/sac/backend/src/models" "github.com/gofiber/fiber/v2" + "github.com/google/uuid" "github.com/huandu/go-assert" "github.com/goccy/go-json" ) -func SampleTagFactory() *map[string]interface{} { +func SampleTagFactory(categoryID uuid.UUID) *map[string]interface{} { return &map[string]interface{}{ "name": "Generate", - "category_id": 1, + "category_id": categoryID, } } -func AssertTagWithIDBodyRespDB(app TestApp, assert *assert.A, resp *http.Response, id uint, body *map[string]interface{}) { +func AssertTagWithBodyRespDB(app TestApp, assert *assert.A, resp *http.Response, body *map[string]interface{}) uuid.UUID { var respTag models.Tag err := json.NewDecoder(resp.Body).Decode(&respTag) @@ -29,39 +30,53 @@ func AssertTagWithIDBodyRespDB(app TestApp, assert *assert.A, resp *http.Respons var dbTag models.Tag - err = app.Conn.First(&dbTag, id).Error + err = app.Conn.Last(&dbTag).Error assert.NilError(err) + fmt.Println(dbTag.ID) + fmt.Println(respTag.ID) + assert.Equal(dbTag.ID, respTag.ID) assert.Equal(dbTag.Name, respTag.Name) assert.Equal(dbTag.CategoryID, respTag.CategoryID) assert.Equal((*body)["name"].(string), dbTag.Name) - assert.Equal((*body)["category_id"].(int), int(dbTag.CategoryID)) + assert.Equal((*body)["category_id"].(uuid.UUID), dbTag.CategoryID) + + return dbTag.ID } -func AssertSampleTagBodyRespDB(app TestApp, assert *assert.A, resp *http.Response) { - AssertTagWithIDBodyRespDB(app, assert, resp, 1, SampleTagFactory()) +func AssertSampleTagBodyRespDB(t *testing.T, app TestApp, assert *assert.A, resp *http.Response) uuid.UUID { + appAssert, uuid := CreateSampleCategory(t, &ExistingAppAssert{App: app, + Assert: assert}) + return AssertTagWithBodyRespDB(appAssert.App, appAssert.Assert, resp, SampleTagFactory(uuid)) } -func CreateSampleTag(t *testing.T) ExistingAppAssert { - appAssert := CreateSampleCategory(t) +func CreateSampleTag(t *testing.T) (appAssert ExistingAppAssert, categoryUUID uuid.UUID, tagUUID uuid.UUID) { + appAssert, categoryUUID = CreateSampleCategory(t, nil) + + var AssertSampleTagBodyRespDB = func(app TestApp, assert *assert.A, resp *http.Response) { + tagUUID = AssertTagWithBodyRespDB(app, assert, resp, SampleTagFactory(categoryUUID)) + } - return TestRequest{ + TestRequest{ Method: fiber.MethodPost, Path: "/api/v1/tags/", - Body: SampleTagFactory(), + Body: SampleTagFactory(categoryUUID), }.TestOnStatusAndDB(t, &appAssert, DBTesterWithStatus{ Status: fiber.StatusCreated, DBTester: AssertSampleTagBodyRespDB, }, ) + + return appAssert, categoryUUID, tagUUID } func TestCreateTagWorks(t *testing.T) { - CreateSampleTag(t).Close() + appAssert, _, _ := CreateSampleTag(t) + appAssert.Close() } var AssertNoTags = func(app TestApp, assert *assert.A, resp *http.Response) { @@ -106,7 +121,7 @@ func TestCreateTagFailsValidation(t *testing.T) { "name": "Generate", }, { - "category_id": 1, + "category_id": uuid.New(), }, {}, } @@ -126,15 +141,17 @@ func TestCreateTagFailsValidation(t *testing.T) { } func TestGetTagWorks(t *testing.T) { - existingAppAssert := CreateSampleTag(t) + existingAppAssert, categoryUUID, tagUUID := CreateSampleTag(t) TestRequest{ Method: fiber.MethodGet, - Path: "/api/v1/tags/1", + Path: fmt.Sprintf("/api/v1/tags/%s", tagUUID), }.TestOnStatusAndDB(t, &existingAppAssert, DBTesterWithStatus{ - Status: fiber.StatusOK, - DBTester: AssertSampleTagBodyRespDB, + Status: fiber.StatusOK, + DBTester: func(app TestApp, assert *assert.A, resp *http.Response) { + AssertTagWithBodyRespDB(app, assert, resp, SampleTagFactory(categoryUUID)) + }, }, ).Close() } @@ -159,23 +176,23 @@ func TestGetTagFailsBadRequest(t *testing.T) { func TestGetTagFailsNotFound(t *testing.T) { TestRequest{ Method: fiber.MethodGet, - Path: "/api/v1/tags/1", + Path: fmt.Sprintf("/api/v1/tags/%s", uuid.New()), }.TestOnError(t, nil, errors.TagNotFound).Close() } func TestUpdateTagWorksUpdateName(t *testing.T) { - existingAppAssert := CreateSampleTag(t) + existingAppAssert, categoryUUID, tagUUID := CreateSampleTag(t) - generateNUTag := *SampleTagFactory() + generateNUTag := *SampleTagFactory(categoryUUID) generateNUTag["name"] = "GenerateNU" var AssertUpdatedTagBodyRespDB = func(app TestApp, assert *assert.A, resp *http.Response) { - AssertTagWithIDBodyRespDB(app, assert, resp, 1, &generateNUTag) + tagUUID = AssertTagWithBodyRespDB(app, assert, resp, &generateNUTag) } TestRequest{ Method: fiber.MethodPatch, - Path: "/api/v1/tags/1", + Path: fmt.Sprintf("/api/v1/tags/%s", tagUUID), Body: &generateNUTag, }.TestOnStatusAndDB(t, &existingAppAssert, DBTesterWithStatus{ @@ -186,13 +203,13 @@ func TestUpdateTagWorksUpdateName(t *testing.T) { } func TestUpdateTagWorksUpdateCategory(t *testing.T) { - existingAppAssert := CreateSampleTag(t) + existingAppAssert, categoryUUID, tagUUID := CreateSampleTag(t) technologyCategory := *SampleCategoryFactory() technologyCategory["name"] = "Technology" var AssertNewCategoryBodyRespDB = func(app TestApp, assert *assert.A, resp *http.Response) { - AssertCategoryWithIDBodyRespDB(app, assert, resp, 2, &technologyCategory) + AssertCategoryWithBodyRespDBMostRecent(app, assert, resp, &technologyCategory) } TestRequest{ @@ -206,16 +223,15 @@ func TestUpdateTagWorksUpdateCategory(t *testing.T) { }, ) - technologyTag := *SampleTagFactory() - technologyTag["category_id"] = 2 + technologyTag := *SampleTagFactory(categoryUUID) var AssertUpdatedTagBodyRespDB = func(app TestApp, assert *assert.A, resp *http.Response) { - AssertTagWithIDBodyRespDB(app, assert, resp, 1, &technologyTag) + AssertTagWithBodyRespDB(app, assert, resp, &technologyTag) } TestRequest{ Method: fiber.MethodPatch, - Path: "/api/v1/tags/1", + Path: fmt.Sprintf("/api/v1/tags/%s", tagUUID), Body: &technologyTag, }.TestOnStatusAndDB(t, &existingAppAssert, DBTesterWithStatus{ @@ -226,21 +242,25 @@ func TestUpdateTagWorksUpdateCategory(t *testing.T) { } func TestUpdateTagWorksWithSameDetails(t *testing.T) { - existingAppAssert := CreateSampleTag(t) + existingAppAssert, categoryUUID, tagUUID := CreateSampleTag(t) TestRequest{ Method: fiber.MethodPatch, - Path: "/api/v1/tags/1", - Body: SampleTagFactory(), + Path: fmt.Sprintf("/api/v1/tags/%s", tagUUID), + Body: SampleTagFactory(categoryUUID), }.TestOnStatusAndDB(t, &existingAppAssert, DBTesterWithStatus{ - Status: fiber.StatusOK, - DBTester: AssertSampleTagBodyRespDB, + Status: fiber.StatusOK, + DBTester: func(app TestApp, assert *assert.A, resp *http.Response) { + AssertTagWithBodyRespDB(app, assert, resp, SampleTagFactory(categoryUUID)) + }, }, ).Close() } func TestUpdateTagFailsBadRequest(t *testing.T) { + appAssert, uuid := CreateSampleCategory(t, nil) + badRequests := []string{ "0", "-1", @@ -253,17 +273,17 @@ func TestUpdateTagFailsBadRequest(t *testing.T) { TestRequest{ Method: fiber.MethodPatch, Path: fmt.Sprintf("/api/v1/tags/%s", badRequest), - Body: SampleTagFactory(), - }.TestOnError(t, nil, errors.FailedToValidateID).Close() + Body: SampleTagFactory(uuid), + }.TestOnError(t, &appAssert, errors.FailedToValidateID).Close() } } func TestDeleteTagWorks(t *testing.T) { - existingAppAssert := CreateSampleTag(t) + existingAppAssert, _, tagUUID := CreateSampleTag(t) TestRequest{ Method: fiber.MethodDelete, - Path: "/api/v1/tags/1", + Path: fmt.Sprintf("/api/v1/tags/%s", tagUUID), }.TestOnStatusAndDB(t, &existingAppAssert, DBTesterWithStatus{ Status: fiber.StatusNoContent, @@ -292,6 +312,6 @@ func TestDeleteTagFailsBadRequest(t *testing.T) { func TestDeleteTagFailsNotFound(t *testing.T) { TestRequest{ Method: fiber.MethodDelete, - Path: "/api/v1/tags/1", + Path: fmt.Sprintf("/api/v1/tags/%s", uuid.New()), }.TestOnError(t, nil, errors.TagNotFound).Close() } diff --git a/backend/tests/api/user_test.go b/backend/tests/api/user_test.go index 6ef0883b7..9655a2b3b 100644 --- a/backend/tests/api/user_test.go +++ b/backend/tests/api/user_test.go @@ -12,6 +12,7 @@ import ( "github.com/GenerateNU/sac/backend/src/models" "github.com/GenerateNU/sac/backend/src/transactions" "github.com/gofiber/fiber/v2" + "github.com/google/uuid" "gorm.io/gorm" "github.com/goccy/go-json" @@ -58,12 +59,12 @@ func TestGetUsersWorks(t *testing.T) { } func TestGetUserWorks(t *testing.T) { - id := 1 + appAssert, uuid := CreateSampleUser(t, nil) TestRequest{ Method: fiber.MethodGet, - Path: fmt.Sprintf("/api/v1/users/%d", id), - }.TestOnStatusAndDB(t, nil, + Path: fmt.Sprintf("/api/v1/users/%s", uuid), + }.TestOnStatusAndDB(t, &appAssert, DBTesterWithStatus{ Status: fiber.StatusOK, DBTester: func(app TestApp, assert *assert.A, resp *http.Response) { @@ -73,14 +74,16 @@ func TestGetUserWorks(t *testing.T) { assert.NilError(err) - assert.Equal("SAC", respUser.FirstName) - assert.Equal("Super", respUser.LastName) - assert.Equal("generatesac@gmail.com", respUser.Email) - assert.Equal("000000000", respUser.NUID) - assert.Equal(models.College("KCCS"), respUser.College) - assert.Equal(models.Year(1), respUser.Year) + sampleUser := *SampleUserFactory() - dbUser, err := transactions.GetUser(app.Conn, uint(id)) + assert.Equal(sampleUser["first_name"].(string), respUser.FirstName) + assert.Equal(sampleUser["last_name"].(string), respUser.LastName) + assert.Equal(sampleUser["email"].(string), respUser.Email) + assert.Equal(sampleUser["nuid"].(string), respUser.NUID) + assert.Equal(models.College(sampleUser["college"].(string)), respUser.College) + assert.Equal(models.Year(sampleUser["year"].(int)), respUser.Year) + + dbUser, err := transactions.GetUser(app.Conn, uuid) assert.NilError(&err) @@ -108,18 +111,18 @@ func TestGetUserFailsBadRequest(t *testing.T) { } func TestGetUserFailsNotExist(t *testing.T) { - id := uint(69) + uuid := uuid.New() TestRequest{ Method: fiber.MethodGet, - Path: fmt.Sprintf("/api/v1/users/%d", id), + Path: fmt.Sprintf("/api/v1/users/%s", uuid), }.TestOnStatusMessageAndDB(t, nil, ErrorWithDBTester{ Error: errors.UserNotFound, DBTester: func(app TestApp, assert *assert.A, resp *http.Response) { var user models.User - err := app.Conn.Where("id = ?", id).First(&user).Error + err := app.Conn.Where("id = ?", uuid).First(&user).Error assert.Assert(stdliberrors.Is(err, gorm.ErrRecordNotFound)) @@ -129,15 +132,14 @@ func TestGetUserFailsNotExist(t *testing.T) { } func TestUpdateUserWorks(t *testing.T) { - appAssert := CreateSampleUser(t) + appAssert, uuid := CreateSampleUser(t, nil) - id := 2 newFirstName := "Michael" newLastName := "Brennan" TestRequest{ Method: fiber.MethodPatch, - Path: fmt.Sprintf("/api/v1/users/%d", id), + Path: fmt.Sprintf("/api/v1/users/%s", uuid), Body: &map[string]interface{}{ "first_name": newFirstName, "last_name": newLastName, @@ -161,7 +163,7 @@ func TestUpdateUserWorks(t *testing.T) { var dbUser models.User - err = app.Conn.First(&dbUser, id).Error + err = app.Conn.First(&dbUser, uuid).Error assert.NilError(err) @@ -177,7 +179,7 @@ func TestUpdateUserWorks(t *testing.T) { } func TestUpdateUserFailsOnInvalidBody(t *testing.T) { - appAssert := CreateSampleUser(t) + appAssert, uuid := CreateSampleUser(t, nil) for _, invalidData := range []map[string]interface{}{ {"email": "not.northeastern@gmail.com"}, @@ -188,7 +190,7 @@ func TestUpdateUserFailsOnInvalidBody(t *testing.T) { } { TestRequest{ Method: fiber.MethodPatch, - Path: "/api/v1/users/2", + Path: fmt.Sprintf("/api/v1/users/%s", uuid), Body: &invalidData, }.TestOnStatusMessageAndDB(t, &appAssert, ErrorWithDBTester{ @@ -219,11 +221,11 @@ func TestUpdateUserFailsBadRequest(t *testing.T) { } func TestUpdateUserFailsOnIdNotExist(t *testing.T) { - id := uint(69) + uuid := uuid.New() TestRequest{ Method: fiber.MethodPatch, - Path: fmt.Sprintf("/api/v1/users/%d", id), + Path: fmt.Sprintf("/api/v1/users/%s", uuid), Body: SampleUserFactory(), }.TestOnStatusMessageAndDB(t, nil, ErrorWithDBTester{ @@ -231,7 +233,7 @@ func TestUpdateUserFailsOnIdNotExist(t *testing.T) { DBTester: func(app TestApp, assert *assert.A, resp *http.Response) { var user models.User - err := app.Conn.Where("id = ?", id).First(&user).Error + err := app.Conn.Where("id = ?", uuid).First(&user).Error assert.Assert(stdliberrors.Is(err, gorm.ErrRecordNotFound)) }, @@ -240,11 +242,11 @@ func TestUpdateUserFailsOnIdNotExist(t *testing.T) { } func TestDeleteUserWorks(t *testing.T) { - appAssert := CreateSampleUser(t) + appAssert, uuid := CreateSampleUser(t, nil) TestRequest{ Method: fiber.MethodDelete, - Path: "/api/v1/users/2", + Path: fmt.Sprintf("/api/v1/users/%s", uuid), }.TestOnStatusAndDB(t, &appAssert, DBTesterWithStatus{ Status: fiber.StatusNoContent, @@ -254,18 +256,17 @@ func TestDeleteUserWorks(t *testing.T) { } func TestDeleteUserNotExist(t *testing.T) { - id := uint(69) - + uuid := uuid.New() TestRequest{ Method: fiber.MethodDelete, - Path: fmt.Sprintf("/api/v1/users/%d", id), + Path: fmt.Sprintf("/api/v1/users/%s", uuid), }.TestOnStatusMessageAndDB(t, nil, ErrorWithDBTester{ Error: errors.UserNotFound, DBTester: func(app TestApp, assert *assert.A, resp *http.Response) { var user models.User - err := app.Conn.Where("id = ?", id).First(&user).Error + err := app.Conn.Where("id = ?", uuid).First(&user).Error assert.Assert(stdliberrors.Is(err, gorm.ErrRecordNotFound)) }, @@ -303,19 +304,23 @@ func SampleUserFactory() *map[string]interface{} { } } -func AssertUserWithIDBodyRespDB(app TestApp, assert *assert.A, resp *http.Response, id uint, body *map[string]interface{}) { +func AssertUserWithIDBodyRespDB(app TestApp, assert *assert.A, resp *http.Response, body *map[string]interface{}) uuid.UUID { var respUser models.User err := json.NewDecoder(resp.Body).Decode(&respUser) assert.NilError(err) - var dbUser models.User + var dbUsers []models.User - err = app.Conn.First(&dbUser, id).Error + err = app.Conn.Find(&dbUsers).Error assert.NilError(err) + assert.Equal(2, len(dbUsers)) + + dbUser := dbUsers[1] + assert.Equal(dbUser.FirstName, respUser.FirstName) assert.Equal(dbUser.LastName, respUser.LastName) assert.Equal(dbUser.Email, respUser.Email) @@ -335,23 +340,35 @@ func AssertUserWithIDBodyRespDB(app TestApp, assert *assert.A, resp *http.Respon assert.Equal((*body)["nuid"].(string), dbUser.NUID) assert.Equal(models.College((*body)["college"].(string)), dbUser.College) assert.Equal(models.Year((*body)["year"].(int)), dbUser.Year) + + return dbUser.ID } -func AssertSampleUserBodyRespDB(app TestApp, assert *assert.A, resp *http.Response) { - AssertUserWithIDBodyRespDB(app, assert, resp, 2, SampleUserFactory()) +func AssertSampleUserBodyRespDB(app TestApp, assert *assert.A, resp *http.Response) uuid.UUID { + return AssertUserWithIDBodyRespDB(app, assert, resp, SampleUserFactory()) } -func CreateSampleUser(t *testing.T) ExistingAppAssert { - return TestRequest{ +func CreateSampleUser(t *testing.T, existingAppAssert *ExistingAppAssert) (ExistingAppAssert, uuid.UUID) { + var uuid uuid.UUID + + newAppAssert := TestRequest{ Method: fiber.MethodPost, Path: "/api/v1/users/", Body: SampleUserFactory(), - }.TestOnStatusAndDB(t, nil, + }.TestOnStatusAndDB(t, existingAppAssert, DBTesterWithStatus{ - Status: fiber.StatusCreated, - DBTester: AssertSampleUserBodyRespDB, + Status: fiber.StatusCreated, + DBTester: func(app TestApp, assert *assert.A, resp *http.Response) { + uuid = AssertSampleUserBodyRespDB(app, assert, resp) + }, }, ) + + if existingAppAssert == nil { + return newAppAssert, uuid + } else { + return *existingAppAssert, uuid + } } func AssertNumUsersRemainsAtN(app TestApp, assert *assert.A, resp *http.Response, n int) { @@ -373,11 +390,12 @@ var TestNumUsersRemainsAt2 = func(app TestApp, assert *assert.A, resp *http.Resp } func TestCreateUserWorks(t *testing.T) { - CreateSampleUser(t).Close() + appAssert, _ := CreateSampleUser(t, nil) + appAssert.Close() } func TestCreateUserFailsIfUserWithEmailAlreadyExists(t *testing.T) { - appAssert := CreateSampleUser(t) + appAssert, _ := CreateSampleUser(t, nil) TestRequest{ Method: fiber.MethodPost, @@ -394,7 +412,7 @@ func TestCreateUserFailsIfUserWithEmailAlreadyExists(t *testing.T) { } func TestCreateUserFailsIfUserWithNUIDAlreadyExists(t *testing.T) { - appAssert := CreateSampleUser(t) + appAssert, _ := CreateSampleUser(t, nil) slightlyDifferentSampleUser := &map[string]interface{}{ "first_name": "John", @@ -419,7 +437,7 @@ func TestCreateUserFailsIfUserWithNUIDAlreadyExists(t *testing.T) { } func AssertCreateBadDataFails(t *testing.T, jsonKey string, badValues []interface{}) { - appAssert := CreateSampleUser(t) + appAssert, _ := CreateSampleUser(t, nil) for _, badValue := range badValues { sampleUserPermutation := *SampleUserFactory() @@ -501,7 +519,7 @@ func TestCreateUserFailsOnInvalidCollege(t *testing.T) { } func TestCreateUserFailsOnMissingFields(t *testing.T) { - appAssert := CreateSampleUser(t) + appAssert, _ := CreateSampleUser(t, nil) for _, missingField := range []string{ "first_name",