package controllers import ( "bytes" "encoding/json" "fmt" "io" "net/http" "net/http/httptest" "net/url" "path/filepath" "regexp" "strconv" "strings" "testing" "time" "github.com/gin-gonic/gin" "github.com/stretchr/testify/assert" "GoMembership/internal/config" "GoMembership/internal/constants" "GoMembership/internal/middlewares" "GoMembership/internal/models" "GoMembership/internal/utils" "GoMembership/pkg/logger" "github.com/golang-jwt/jwt/v5" ) type RegisterUserTest struct { WantDBData map[string]interface{} Name string Input string WantResponse int Assert bool } var jwtSigningMethod = jwt.SigningMethodHS256 func (rt *RegisterUserTest) SetupContext() (*gin.Context, *httptest.ResponseRecorder, *gin.Engine) { return GetMockedJSONContext([]byte(rt.Input), "register") } func (rt *RegisterUserTest) RunHandler(c *gin.Context, router *gin.Engine) { Uc.RegisterUser(c) } func (rt *RegisterUserTest) ValidateResponse(w *httptest.ResponseRecorder) error { if w.Code != rt.WantResponse { responseBody, _ := io.ReadAll(w.Body) return fmt.Errorf("Register User: Didn't get the expected response code: got: %v; expected: %v. Context: %#v", w.Code, rt.WantResponse, string(responseBody)) } return nil } func (rt *RegisterUserTest) ValidateResult() error { return validateUser(rt.Assert, rt.WantDBData) } func testUserController(t *testing.T) { tests := getTestUsers() for _, tt := range tests { logger.Error.Print("==============================================================") logger.Error.Printf("Register User Testing : %v", tt.Name) logger.Error.Print("==============================================================") t.Run(tt.Name, func(t *testing.T) { if err := runSingleTest(&tt); err != nil { t.Fatalf("Test failed: %v", err.Error()) } }) } loginEmail, loginCookie := testLoginHandler(t) logoutCookie := testCurrentUserHandler(t, loginEmail, loginCookie) testUpdateUser(t, loginEmail, loginCookie) testLogoutHandler(t, logoutCookie) } func testLogoutHandler(t *testing.T, loginCookie http.Cookie) { tests := []struct { name string setupCookie func(*http.Request) expectedStatus int }{ { name: "Logout with valid cookie", setupCookie: func(req *http.Request) { req.AddCookie(&loginCookie) }, expectedStatus: http.StatusOK, }, { name: "Logout without cookie", setupCookie: func(req *http.Request) {}, expectedStatus: http.StatusOK, // Logout should still succeed even without a cookie }, } for _, tt := range tests { logger.Error.Print("==============================================================") logger.Error.Printf("Logout User Testing : %v", tt.name) logger.Error.Print("==============================================================") t.Run(tt.name, func(t *testing.T) { gin.SetMode(gin.TestMode) router := gin.New() router.POST("/logout", Uc.LogoutHandler) w := httptest.NewRecorder() req, _ := http.NewRequest("POST", "/logout", nil) tt.setupCookie(req) router.ServeHTTP(w, req) assert.Equal(t, tt.expectedStatus, w.Code) var response map[string]string err := json.Unmarshal(w.Body.Bytes(), &response) assert.NoError(t, err) assert.Equal(t, "Logged out successfully", response["message"]) // Check if the cookie has been cleared var logoutCookie *http.Cookie for _, cookie := range w.Result().Cookies() { if cookie.Name == "jwt" { logoutCookie = cookie break } } assert.NotNil(t, logoutCookie, "Logout should set a clearing cookie") assert.Equal(t, "", logoutCookie.Value, "Logout cookie should have empty value") assert.True(t, logoutCookie.Expires.Before(time.Now()), "Logout cookie should be expired") // Verify that the user can no longer access protected routes w = httptest.NewRecorder() req, _ = http.NewRequest("GET", "/current", nil) if logoutCookie != nil { req.AddCookie(logoutCookie) } router.GET("/current", middlewares.AuthMiddleware(), Uc.CurrentUserHandler) router.ServeHTTP(w, req) assert.Equal(t, http.StatusUnauthorized, w.Code, "User should not be able to access protected routes after logout") }) } } func testLoginHandler(t *testing.T) (string, http.Cookie) { // This test should run after the user registration test var loginCookie http.Cookie var loginInput loginInput t.Run("LoginHandler", func(t *testing.T) { // Test cases tests := []struct { name string input string wantStatusCode int wantToken bool }{ { name: "Valid login", input: `{ "email": "john.doe@example.com", "password": "password123" }`, wantStatusCode: http.StatusOK, wantToken: true, }, { name: "Invalid email", input: `{ "email": "nonexistent@example.com", "password": "password123" }`, wantStatusCode: http.StatusNotFound, wantToken: false, }, { name: "Invalid password", input: `{ "email": "john.doe@example.com", "password": "wrongpassword" }`, wantStatusCode: http.StatusNotAcceptable, wantToken: false, }, } for _, tt := range tests { logger.Error.Print("==============================================================") logger.Error.Printf("Testing : %v", tt.name) logger.Error.Print("==============================================================") t.Run(tt.name, func(t *testing.T) { // Setup c, w, _ := GetMockedJSONContext([]byte(tt.input), "/login") // Execute Uc.LoginHandler(c) // Assert assert.Equal(t, tt.wantStatusCode, w.Code) var response map[string]interface{} err := json.Unmarshal(w.Body.Bytes(), &response) assert.NoError(t, err) if tt.wantToken { assert.Contains(t, response, "message") assert.Equal(t, "Login successful", response["message"]) for _, cookie := range w.Result().Cookies() { if cookie.Name == "jwt" { loginCookie = *cookie err = json.Unmarshal([]byte(tt.input), &loginInput) assert.NoError(t, err, "Failed to unmarshal input JSON") break } } assert.NotEmpty(t, loginCookie) } else { assert.Contains(t, response, "error") assert.NotEmpty(t, response["error"]) } }) } }) return loginInput.Email, loginCookie } func testCurrentUserHandler(t *testing.T, loginEmail string, loginCookie http.Cookie) http.Cookie { // This test should run after the user login test invalidCookie := http.Cookie{ Name: "jwt", Value: "invalid.token.here", } tests := []struct { name string setupCookie func(*http.Request) expectedUserMail string expectedStatus int expectNewCookie bool }{ { name: "With valid cookie", setupCookie: func(req *http.Request) { req.AddCookie(&loginCookie) }, expectedUserMail: loginEmail, expectedStatus: http.StatusOK, }, { name: "With valid expired cookie", setupCookie: func(req *http.Request) { sessionID := "test-session" token := jwt.NewWithClaims(jwtSigningMethod, jwt.MapClaims{ "user_id": 1, "role_id": 0, "session_id": sessionID, "exp": time.Now().Add(-time.Hour).Unix(), // Expired 1 hour ago }) tokenString, _ := token.SignedString([]byte(config.Auth.JWTSecret)) req.AddCookie(&http.Cookie{Name: "jwt", Value: tokenString}) middlewares.UpdateSession(sessionID, 1) // Add a valid session }, expectedUserMail: config.Recipients.AdminEmail, expectedStatus: http.StatusOK, expectNewCookie: true, }, { name: "Without cookie", setupCookie: func(req *http.Request) {}, expectedStatus: http.StatusUnauthorized, }, { name: "With invalid cookie", setupCookie: func(req *http.Request) { req.AddCookie(&invalidCookie) }, expectedStatus: http.StatusUnauthorized, }, } for _, tt := range tests { logger.Error.Print("==============================================================") logger.Error.Printf("Testing : %v", tt.name) logger.Error.Print("==============================================================") t.Run(tt.name, func(t *testing.T) { gin.SetMode(gin.TestMode) router := gin.New() router.Use(middlewares.AuthMiddleware()) router.GET("/current", Uc.CurrentUserHandler) w := httptest.NewRecorder() req, _ := http.NewRequest("GET", "/current", nil) tt.setupCookie(req) router.ServeHTTP(w, req) assert.Equal(t, tt.expectedStatus, w.Code) if tt.expectedStatus == http.StatusOK { var response models.User err := json.Unmarshal(w.Body.Bytes(), &response) assert.NoError(t, err) assert.Equal(t, tt.expectedUserMail, response.Email) var newCookie *http.Cookie for _, cookie := range w.Result().Cookies() { if cookie.Name == "jwt" { newCookie = cookie break } } if tt.expectNewCookie { assert.NotNil(t, newCookie, "New cookie should be set for expired token") assert.NotEqual(t, loginCookie.Value, newCookie.Value, "Cookie value should be different") assert.True(t, newCookie.MaxAge > 0, "New cookie should not be expired") } else { assert.Nil(t, newCookie, "No new cookie should be set for non-expired token") } } else { // For unauthorized requests, check for an error message var errorResponse map[string]string err := json.Unmarshal(w.Body.Bytes(), &errorResponse) assert.NoError(t, err) assert.Contains(t, errorResponse, "error") assert.NotEmpty(t, errorResponse["error"]) } }) } return loginCookie } func validateUser(assert bool, wantDBData map[string]interface{}) error { users, err := Uc.Service.GetUsers(wantDBData) if err != nil { return fmt.Errorf("Error in database ops: %#v", err) } if assert != (len(*users) != 0) { return fmt.Errorf("User entry query didn't met expectation: %v != %#v", assert, *users) } if assert { //check for email delivery messages := utils.SMTPGetMessages() for _, message := range messages { mail, err := utils.DecodeMail(message.MsgRequest()) if err != nil { logger.Error.Printf("Error in validateUser: %#v", err) return err } if strings.Contains(mail.Subject, constants.MailRegistrationSubject) { if err := checkRegistrationMail(mail, &(*users)[0]); err != nil { logger.Error.Printf("Error in checkRegistrationMail: %#v", err) return err } } else if strings.Contains(mail.Subject, constants.MailVerificationSubject) { if err := checkVerificationMail(mail, &(*users)[0]); err != nil { logger.Error.Printf("Error in checkVerificationMail: %#v", err) return err } verifiedUsers, err := Uc.Service.GetUsers(wantDBData) if err != nil { logger.Error.Printf("Error in GetUsers: %#v", err) return err } if (*verifiedUsers)[0].Status != constants.VerifiedStatus { return fmt.Errorf("Users(%v) status isn't verified after email verification. Status is: %v", (*verifiedUsers)[0].Email, (*verifiedUsers)[0].Status) } } else { return fmt.Errorf("Subject not expected: %v", mail.Subject) } } } return nil } func testUpdateUser(t *testing.T, loginEmail string, loginCookie http.Cookie) { invalidCookie := http.Cookie{ Name: "jwt", Value: "invalid.token.here", } // Get the user we just created users, err := Uc.Service.GetUsers(map[string]interface{}{"email": "john.doe@example.com"}) if err != nil || len(*users) == 0 { t.Fatalf("Failed to get test user: %v", err) } user := (*users)[0] tests := []struct { name string setupCookie func(*http.Request) updateFunc func(*models.User) expectedStatus int expectedError string }{ { name: "Valid Update", setupCookie: func(req *http.Request) { req.AddCookie(&loginCookie) }, updateFunc: func(u *models.User) { u.Password = "" u.FirstName = "John Updated" u.LastName = "Doe Updated" u.Phone = "01738484994" }, expectedStatus: http.StatusAccepted, }, { name: "Password Update", setupCookie: func(req *http.Request) { req.AddCookie(&loginCookie) }, updateFunc: func(u *models.User) { u.Password = "NewPassword" }, expectedStatus: http.StatusAccepted, }, { name: "Valid Update, invalid cookie", setupCookie: func(req *http.Request) { req.AddCookie(&invalidCookie) }, updateFunc: func(u *models.User) { u.Password = "" u.FirstName = "John Updated" u.LastName = "Doe Updated" u.Phone = "01738484994" }, expectedStatus: http.StatusUnauthorized, expectedError: "Auth token invalid", }, { name: "Invalid Email Update", setupCookie: func(req *http.Request) { req.AddCookie(&loginCookie) }, updateFunc: func(u *models.User) { u.Password = "" u.Email = "invalid-email" }, expectedStatus: http.StatusBadRequest, expectedError: "Invalid user data", }, { name: "User ID mismatch while not admin", setupCookie: func(req *http.Request) { req.AddCookie(&loginCookie) }, updateFunc: func(u *models.User) { u.Password = "" u.ID = 1 u.FirstName = "John Missing ID" }, expectedStatus: http.StatusForbidden, expectedError: "You are not authorized to update this user", }, // { // name: "Non-existent User", // setupCookie: func(req *http.Request) { // req.AddCookie(&loginCookie) // }, // updateFunc: func(u *models.User) { // u.Password = "" // u.ID = 99999 // u.FirstName = "Non-existent" // }, // expectedStatus: http.StatusNotFound, // expectedError: "User not found", // }, } for _, tt := range tests { logger.Error.Print("==============================================================") logger.Error.Printf("Update Testing : %v", tt.name) logger.Error.Print("==============================================================") t.Run(tt.name, func(t *testing.T) { // Create a copy of the user and apply the updates updatedUser := user tt.updateFunc(&updatedUser) // Convert user to JSON jsonData, err := json.Marshal(updatedUser) if err != nil { t.Fatalf("Failed to marshal user data: %v", err) } // Create request req, _ := http.NewRequest("PUT", "/users/"+strconv.FormatUint(uint64(user.ID), 10), bytes.NewBuffer(jsonData)) req.Header.Set("Content-Type", "application/json") tt.setupCookie(req) // Create response recorder w := httptest.NewRecorder() // Set up router and add middleware router := gin.New() router.Use(middlewares.AuthMiddleware()) router.PUT("/users/:id", Uc.UpdateHandler) // Perform request router.ServeHTTP(w, req) // Check status code assert.Equal(t, tt.expectedStatus, w.Code) // Parse response var response map[string]interface{} err = json.Unmarshal(w.Body.Bytes(), &response) assert.NoError(t, err) if tt.expectedError != "" { assert.Equal(t, tt.expectedError, response["error"]) } else { assert.Equal(t, "User updated successfully", response["message"]) // Verify the update in the database updatedUserFromDB, err := Uc.Service.GetUserByID(user.ID) updatedUserFromDB.UpdatedAt = updatedUser.UpdatedAt updatedUserFromDB.Membership.UpdatedAt = updatedUser.Membership.UpdatedAt updatedUserFromDB.BankAccount.UpdatedAt = updatedUser.BankAccount.UpdatedAt updatedUserFromDB.Verification.UpdatedAt = updatedUser.Verification.UpdatedAt updatedUserFromDB.Membership.SubscriptionModel.UpdatedAt = updatedUser.Membership.SubscriptionModel.UpdatedAt if updatedUser.Password == "" { assert.Equal(t, user.Password, (*updatedUserFromDB).Password) } else { assert.NotEqual(t, user.Password, (*updatedUserFromDB).Password) updatedUser.Password = "" } updatedUserFromDB.Password = "" assert.NoError(t, err) assert.Equal(t, updatedUser, *updatedUserFromDB, "Updated user in DB does not match expected user") } }) } } func checkWelcomeMail(message *utils.Email, user *models.User) error { if !strings.Contains(message.To, user.Email) { return fmt.Errorf("Registration Information didn't reach the user! Recipient was: %v instead of %v", message.To, user.Email) } if !strings.Contains(message.From, config.SMTP.User) { return fmt.Errorf("Registration Information was sent from unexpected address! Sender was: %v instead of %v", message.From, config.SMTP.User) } //Check if all the relevant data has been passed to the mail. if !strings.Contains(message.Body, user.FirstName) { return fmt.Errorf("User first name(%v) has not been rendered in registration mail.", user.FirstName) } if !strings.Contains(message.Body, fmt.Sprintf("Preis/Monat: %v", user.Membership.SubscriptionModel.MonthlyFee)) { return fmt.Errorf("Users monthly subscription fee(%v) has not been rendered in registration mail.", user.Membership.SubscriptionModel.MonthlyFee) } if !strings.Contains(message.Body, fmt.Sprintf("Preis/h: %v", user.Membership.SubscriptionModel.HourlyRate)) { return fmt.Errorf("Users hourly subscription fee(%v) has not been rendered in registration mail.", user.Membership.SubscriptionModel.HourlyRate) } if user.Company != "" && !strings.Contains(message.Body, user.Company) { return fmt.Errorf("Users Company(%v) has not been rendered in registration mail.", user.Company) } if !strings.Contains(message.Body, fmt.Sprintf("Mitgliedsnummer: %v", user.Membership.ID)) { return fmt.Errorf("Users membership Id(%v) has not been rendered in registration mail.", user.Membership.ID) } if !strings.Contains(message.Body, config.Site.BaseURL) { return fmt.Errorf("Base Url (%v) has not been rendered in registration mail.", config.Site.BaseURL) } if !strings.Contains(message.Body, config.Site.BaseURL+config.Templates.LogoURI) { return fmt.Errorf("Logo Url (%v) has not been rendered in registration mail.", config.Site.BaseURL+config.Site.WebsiteTitle) } if !strings.Contains(message.Body, config.Site.WebsiteTitle) { return fmt.Errorf("Website title (%v) has not been rendered in registration mail.", config.Site.WebsiteTitle) } return nil } func checkRegistrationMail(message *utils.Email, user *models.User) error { if !strings.Contains(message.To, config.Recipients.UserRegistration) { return fmt.Errorf("Registration Information didn't reach admin! Recipient was: %v instead of %v", message.To, config.Recipients.UserRegistration) } if !strings.Contains(message.From, config.SMTP.User) { return fmt.Errorf("Registration Information was sent from unexpected address! Sender was: %v instead of %v", message.From, config.SMTP.User) } //Check if all the relevant data has been passed to the mail. if !strings.Contains(message.Body, user.FirstName+" "+user.LastName) { return fmt.Errorf("User first and last name(%v) has not been rendered in registration mail.", user.FirstName+" "+user.LastName) } if !strings.Contains(message.Body, fmt.Sprintf("Preis/Monat: %v", user.Membership.SubscriptionModel.MonthlyFee)) { return fmt.Errorf("Users monthly subscription fee(%v) has not been rendered in registration mail.", user.Membership.SubscriptionModel.MonthlyFee) } if !strings.Contains(message.Body, fmt.Sprintf("Preis/h: %v", user.Membership.SubscriptionModel.HourlyRate)) { return fmt.Errorf("Users hourly subscription fee(%v) has not been rendered in registration mail.", user.Membership.SubscriptionModel.HourlyRate) } if user.Company != "" && !strings.Contains(message.Body, user.Company) { return fmt.Errorf("Users Company(%v) has not been rendered in registration mail.", user.Company) } if !strings.Contains(message.Body, fmt.Sprintf("Mitgliedsnr: %v", user.Membership.ID)) { return fmt.Errorf("Users membership Id(%v) has not been rendered in registration mail.", user.Membership.ID) } if !strings.Contains(message.Body, user.Address+","+user.ZipCode) { return fmt.Errorf("Users address(%v) has not been rendered in registration mail.", user.Address+" sv,"+user.ZipCode) } if !strings.Contains(message.Body, user.City) { return fmt.Errorf("Users city(%v) has not been rendered in registration mail.", user.City) } if !strings.Contains(message.Body, user.DateOfBirth.Format("20060102")) { return fmt.Errorf("Users birthday(%v) has not been rendered in registration mail.", user.DateOfBirth.Format("20060102")) } if !strings.Contains(message.Body, "Email: "+user.Email) { return fmt.Errorf("Users email(%v) has not been rendered in registration mail.", user.Email) } if !strings.Contains(message.Body, user.Phone) { return fmt.Errorf("Users phone(%v) has not been rendered in registration mail.", user.Phone) } if !strings.Contains(message.Body, user.BankAccount.IBAN) { return fmt.Errorf("Users IBAN(%v) has not been rendered in registration mail.", user.BankAccount.IBAN) } if !strings.Contains(message.Body, config.Site.BaseURL) { return fmt.Errorf("Base Url (%v) has not been rendered in registration mail.", config.Site.BaseURL) } return nil } func checkVerificationMail(message *utils.Email, user *models.User) error { if !strings.Contains(message.To, user.Email) { return fmt.Errorf("Registration Information didn't reach client! Recipient was: %v instead of %v", message.To, user.Email) } verificationURL, err := getVerificationURL(message.Body) if err != nil { return fmt.Errorf("Error parsing verification URL: %#v", err.Error()) } if !strings.Contains(verificationURL, user.Verification.VerificationToken) { return fmt.Errorf("Users Verification link token(%v) has not been rendered in email verification mail. %v", user.Verification.VerificationToken, verificationURL) } if !strings.Contains(message.Body, config.Site.BaseURL) { return fmt.Errorf("Base Url (%v) has not been rendered in email verification mail.", config.Site.BaseURL) } // open the provided link: if err := verifyMail(verificationURL); err != nil { return err } messages := utils.SMTPGetMessages() for _, message := range messages { mail, err := utils.DecodeMail(message.MsgRequest()) if err != nil { return err } if err := checkWelcomeMail(mail, user); err != nil { return err } } return nil } func verifyMail(verificationURL string) error { gin.SetMode(gin.TestMode) router := gin.New() router.LoadHTMLGlob(filepath.Join(config.Templates.HTMLPath, "*")) router.GET("/users/verify", Uc.VerifyMailHandler) wv := httptest.NewRecorder() cv, _ := gin.CreateTestContext(wv) var err error cv.Request, err = http.NewRequest("GET", verificationURL, nil) if err != nil { return fmt.Errorf("Failed to create new GET Request: %v", err.Error()) } router.ServeHTTP(wv, cv.Request) if wv.Code != 200 { responseBody, _ := io.ReadAll(wv.Body) return fmt.Errorf("VerifyMail: Didn't get the expected response code: got: %v; expected: %v Context: %#v", wv.Code, 200, string(responseBody)) } return nil } func getVerificationURL(mailBody string) (string, error) { re := regexp.MustCompile(`"([^"]*verify[^"]*)"`) // Find the matching URL in the email content match := re.FindStringSubmatch(mailBody) if len(match) == 0 { return "", fmt.Errorf("No mail verification link found in email body: %#v", mailBody) } verificationURL, err := url.QueryUnescape(match[1]) if err != nil { return "", fmt.Errorf("Error decoding URL: %v", err) } logger.Info.Printf("VerificationURL: %#v", verificationURL) return verificationURL, nil } // TEST DATA: func customizeInput(customize func(models.User) models.User) *RegistrationData { user := getBaseUser() user = customize(user) // Apply the customization return &RegistrationData{User: user} } func getTestUsers() []RegisterUserTest { return []RegisterUserTest{ { Name: "birthday < 18 should fail", WantResponse: http.StatusNotAcceptable, WantDBData: map[string]interface{}{"email": "john.doe@example.com"}, Assert: false, Input: GenerateInputJSON(customizeInput(func(user models.User) models.User { user.DateOfBirth = time.Date(2020, time.January, 1, 0, 0, 0, 0, time.UTC) return user })), }, { Name: "FirstName empty, should fail", WantResponse: http.StatusNotAcceptable, WantDBData: map[string]interface{}{"email": "john.doe@example.com"}, Assert: false, Input: GenerateInputJSON(customizeInput(func(user models.User) models.User { user.FirstName = "" return user })), }, { Name: "LastName Empty should fail", WantResponse: http.StatusNotAcceptable, WantDBData: map[string]interface{}{"email": "john.doe@example.com"}, Assert: false, Input: GenerateInputJSON(customizeInput(func(user models.User) models.User { user.LastName = "" return user })), }, { Name: "EMail wrong format should fail", WantResponse: http.StatusNotAcceptable, WantDBData: map[string]interface{}{"email": "johnexample.com"}, Assert: false, Input: GenerateInputJSON(customizeInput(func(user models.User) models.User { user.Email = "johnexample.com" return user })), }, { Name: "Missing Zip Code should fail", WantResponse: http.StatusNotAcceptable, WantDBData: map[string]interface{}{"email": "john.doe@example.com"}, Assert: false, Input: GenerateInputJSON(customizeInput(func(user models.User) models.User { user.ZipCode = "" return user })), }, { Name: "Missing Address should fail", WantResponse: http.StatusNotAcceptable, WantDBData: map[string]interface{}{"email": "john.doe@example.com"}, Assert: false, Input: GenerateInputJSON(customizeInput(func(user models.User) models.User { user.Address = "" return user })), }, { Name: "Missing City should fail", WantResponse: http.StatusNotAcceptable, WantDBData: map[string]interface{}{"email": "john.doe@example.com"}, Assert: false, Input: GenerateInputJSON(customizeInput(func(user models.User) models.User { user.City = "" return user })), }, { Name: "Missing IBAN should fail", WantResponse: http.StatusNotAcceptable, WantDBData: map[string]interface{}{"email": "john.doe@example.com"}, Assert: false, Input: GenerateInputJSON(customizeInput(func(user models.User) models.User { user.BankAccount.IBAN = "" return user })), }, { Name: "Invalid IBAN should fail", WantResponse: http.StatusNotAcceptable, WantDBData: map[string]interface{}{"email": "john.doe@example.com"}, Assert: false, Input: GenerateInputJSON(customizeInput(func(user models.User) models.User { user.BankAccount.IBAN = "DE1234234123134" return user })), }, { Name: "Missing subscription plan should fail", WantResponse: http.StatusNotAcceptable, WantDBData: map[string]interface{}{"email": "john.doe@example.com"}, Assert: false, Input: GenerateInputJSON(customizeInput(func(user models.User) models.User { user.Membership.SubscriptionModel.Name = "" return user })), }, { Name: "Invalid subscription plan should fail", WantResponse: http.StatusNotFound, WantDBData: map[string]interface{}{"email": "john.doe@example.com"}, Assert: false, Input: GenerateInputJSON(customizeInput(func(user models.User) models.User { user.Membership.SubscriptionModel.Name = "NOTEXISTENTPLAN" return user })), }, { Name: "Correct Entry should pass", WantResponse: http.StatusCreated, WantDBData: map[string]interface{}{"Email": "john.doe@example.com"}, Assert: true, Input: GenerateInputJSON(customizeInput(func(user models.User) models.User { return user })), }, { Name: "Email duplicate should fail", WantResponse: http.StatusConflict, WantDBData: map[string]interface{}{"first_name": "Jane"}, Assert: false, Input: GenerateInputJSON(customizeInput(func(user models.User) models.User { user.FirstName = "Jane" return user })), }, { Name: "Company present should pass", WantResponse: http.StatusCreated, WantDBData: map[string]interface{}{"Email": "john.doe2@example.com"}, Assert: true, Input: GenerateInputJSON(customizeInput(func(user models.User) models.User { user.Email = "john.doe2@example.com" user.Company = "ACME" return user })), }, { Name: "Subscription constraints not entered; should fail", WantResponse: http.StatusNotAcceptable, WantDBData: map[string]interface{}{"Email": "john.junior.doe@example.com"}, Assert: false, Input: GenerateInputJSON(customizeInput(func(user models.User) models.User { user.Email = "john.junior.doe@example.com" user.Membership.SubscriptionModel.Name = "additional" return user })), }, { Name: "Subscription constraints wrong; should fail", WantResponse: http.StatusNotAcceptable, WantDBData: map[string]interface{}{"Email": "john.junior.doe@example.com"}, Assert: false, Input: GenerateInputJSON(customizeInput(func(user models.User) models.User { user.Email = "john.junior.doe@example.com" user.Membership.ParentMembershipID = 200 user.Membership.SubscriptionModel.Name = "additional" return user })), }, { Name: "Subscription constraints correct, should pass", WantResponse: http.StatusCreated, WantDBData: map[string]interface{}{"Email": "john.junior.doe@example.com"}, Assert: true, Input: GenerateInputJSON(customizeInput(func(user models.User) models.User { user.Email = "john.junior.doe@example.com" user.Membership.ParentMembershipID = 1 user.Membership.SubscriptionModel.Name = "additional" return user })), }, } }