package controllers import ( "bytes" "encoding/json" "strconv" // "io/ioutil" "net/http" "net/http/httptest" "os" "testing" "time" "github.com/gin-gonic/gin" "gorm.io/gorm" "GoMembership/internal/config" "GoMembership/internal/database" "GoMembership/internal/models" "GoMembership/internal/repositories" "GoMembership/internal/services" "GoMembership/internal/utils" "GoMembership/pkg/logger" ) type test struct { name string input string wantDBData map[string]interface{} wantResponse uint16 assert bool } // type RegistrationData struct { // User models.User `json:"user"` // } const ( Host = "127.0.0.1" Port int = 2525 User = "alex@mail.de" Pass = "secret" AdminMail = "admin@mail.de" ) var ( uc UserController ) func TestUserController(t *testing.T) { _ = deleteTestDB("test.db") if err := database.InitDB("test.db"); err != nil { t.Errorf("Failed to create DB: %#v", err) } if err := os.Setenv("SMTP_HOST", Host); err != nil { t.Errorf("Error setting environment variable: %v", err) } if err := os.Setenv("SMTP_PORT", strconv.Itoa(Port)); err != nil { t.Errorf("Error setting environment variable: %v", err) } if err := os.Setenv("ADMIN_MAIL", AdminMail); err != nil { t.Errorf("Error setting environment variable: %v", err) } if err := os.Setenv("SMTP_USER", User); err != nil { t.Errorf("Error setting environment variable: %v", err) } if err := os.Setenv("SMTP_PASS", Pass); err != nil { t.Errorf("Error setting environment variable: %v", err) } config.LoadConfig() utils.SMTPStart(Host, Port) emailService := services.NewEmailService(config.SMTP.Host, config.SMTP.Port, config.SMTP.User, config.SMTP.Password, config.SMTP.AdminEmail) var consentRepo repositories.ConsentRepositoryInterface = &repositories.ConsentRepository{} consentService := &services.ConsentService{Repo: consentRepo} var bankAccountRepo repositories.BankAccountRepositoryInterface = &repositories.BankAccountRepository{} bankAccountService := &services.BankAccountService{Repo: bankAccountRepo} var membershipRepo repositories.MembershipRepositoryInterface = &repositories.MembershipRepository{} var subscriptionRepo repositories.SubscriptionModelsRepositoryInterface = &repositories.SubscriptionModelsRepository{} membershipService := &services.MembershipService{Repo: membershipRepo, SubscriptionRepo: subscriptionRepo} var userRepo repositories.UserRepositoryInterface = &repositories.UserRepository{} userService := &services.UserService{Repo: userRepo} uc = UserController{Service: userService, EmailService: emailService, ConsentService: consentService, BankAccountService: bankAccountService, MembershipService: membershipService} if err := initSubscriptionPlans(); err != nil { t.Errorf("Failed to init Susbcription plans: %#v", err) } tests := getTestUsers() for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { runSingleTest(t, &tt) }) } if err := deleteTestDB("test.db"); err != nil { t.Errorf("Failed to tear down DB: %#v", err) } } func runSingleTest(t *testing.T, tt *test) { c, w := getMockedContext([]byte(tt.input)) uc.RegisterUser(c) if w.Code != int(tt.wantResponse) { t.Errorf("Didn't get the expected response code: got: %v; expected: %v", w.Code, tt.wantResponse) } validateUser(t, tt.assert, tt.wantDBData) } func handleError(t *testing.T, err error, assert bool) { if err == gorm.ErrRecordNotFound && !assert { return // Expected case: user not found and assertion is false } if err != nil { t.Errorf("Error during testing: %#v", err) } } func validateUser(t *testing.T, assert bool, wantDBData map[string]interface{}) { users, err := uc.Service.GetUsers(wantDBData) if err != nil { t.Errorf("Error in database ops: %#v", err) } if assert != (len(*users) != 0) { t.Errorf("User entry query didn't met expectation: %v != %#v", assert, *users) } } func initSubscriptionPlans() error { subscription := models.SubscriptionModel{ Name: "Basic", Details: "Test Plan", MonthlyFee: 2, HourlyRate: 3, } result := database.DB.Create(&subscription) if result.Error != nil { return result.Error } return nil } func getMockedContext(jsonStr []byte) (*gin.Context, *httptest.ResponseRecorder) { gin.SetMode(gin.TestMode) w := httptest.NewRecorder() c, _ := gin.CreateTestContext(w) var err error c.Request, err = http.NewRequest("POST", "/register", bytes.NewBuffer(jsonStr)) if err != nil { logger.Error.Fatalf("Failed to create new Request: %#v", err) } c.Request.Header.Set("Content-Type", "application/json") return c, w } func deleteTestDB(dbPath string) error { err := os.Remove(dbPath) if err != nil { return err } return nil } // TEST DATA: func getBaseUser() models.User { return models.User{ DateOfBirth: time.Date(2000, time.January, 1, 0, 0, 0, 0, time.UTC), FirstName: "John", LastName: "Doe", Email: "john.doe@example.com", Address: "Pablo Escobar Str. 4", ZipCode: "25474", City: "Hasloh", Phone: "01738484993", BankAccount: models.BankAccount{IBAN: "DE89370400440532013000"}, Membership: models.Membership{SubscriptionModel: models.SubscriptionModel{Name: "Basic"}}, ProfilePicture: "", Password: "password123", Company: "", } } func generateInputJSON(customize func(models.User) models.User) string { user := getBaseUser() user = customize(user) // Apply the customization regData := RegistrationData{User: user} jsonBytes, err := json.Marshal(regData) if err != nil { logger.Error.Printf("couldn't generate Json from User: %#v\nERROR: %#v", regData, err) return "" } return string(jsonBytes) } func getTestUsers() []test { return []test{ { name: "birthday < 18 should fail", wantResponse: http.StatusNotAcceptable, wantDBData: map[string]interface{}{"email": "john.doe@example.com"}, assert: false, input: generateInputJSON(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(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(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(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(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(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(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(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(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(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(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(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(func(user models.User) models.User { user.FirstName = "Jane" return user }), }, } }