package controllers import ( "bytes" "encoding/json" "net/http" "net/http/httptest" "net/url" "os" "path/filepath" "strconv" "testing" "log" "github.com/gin-gonic/gin" "GoMembership/internal/config" "GoMembership/internal/database" "GoMembership/internal/models" "GoMembership/internal/repositories" "GoMembership/internal/services" "GoMembership/internal/utils" "GoMembership/pkg/logger" ) type TestCase interface { SetupContext() (*gin.Context, *httptest.ResponseRecorder, *gin.Engine) RunHandler(*gin.Context, *gin.Engine) ValidateResponse(*httptest.ResponseRecorder) error ValidateResult() error } const ( Host = "127.0.0.1" Port int = 2525 ) var ( Uc *UserController Mc *MembershipController Cc *ContactController ) func TestSuite(t *testing.T) { _ = deleteTestDB("test.db") cwd, err := os.Getwd() if err != nil { log.Fatalf("Failed to get current working directory: %v", err) } // Build paths relative to the current working directory configFilePath := filepath.Join(cwd, "..", "..", "configs", "config.json") templateHTMLPath := filepath.Join(cwd, "..", "..", "templates", "html") templateMailPath := filepath.Join(cwd, "..", "..", "templates", "email") if err := os.Setenv("TEMPLATE_MAIL_PATH", templateMailPath); err != nil { log.Fatalf("Error setting environment variable: %v", err) } if err := os.Setenv("TEMPLATE_HTML_PATH", templateHTMLPath); err != nil { log.Fatalf("Error setting environment variable: %v", err) } if err := os.Setenv("CONFIG_FILE_PATH", configFilePath); err != nil { log.Fatalf("Error setting environment variable: %v", err) } if err := os.Setenv("SMTP_HOST", Host); err != nil { log.Fatalf("Error setting environment variable: %v", err) } if err := os.Setenv("SMTP_PORT", strconv.Itoa(Port)); err != nil { log.Fatalf("Error setting environment variable: %v", err) } if err := os.Setenv("BASE_URL", "http://"+Host+":2525"); err != nil { log.Fatalf("Error setting environment variable: %v", err) } config.LoadConfig() if err := database.Open("test.db", config.Recipients.AdminEmail); err != nil { log.Fatalf("Failed to create DB: %#v", err) } utils.SMTPStart(Host, Port) emailService := services.NewEmailService(config.SMTP.Host, config.SMTP.Port, config.SMTP.User, config.SMTP.Password) 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} Mc = &MembershipController{Service: *membershipService} Cc = &ContactController{EmailService: emailService} if err := initSubscriptionPlans(); err != nil { log.Fatalf("Failed to init Subscription plans: %#v", err) } // Run all tests // code := m.Run() t.Run("userController", func(t *testing.T) { testUserController(t) }) t.Run("contactController", func(t *testing.T) { testContactController(t) }) t.Run("membershipController", func(t *testing.T) { testMembershipController(t) }) if err := utils.SMTPStop(); err != nil { log.Fatalf("Failed to stop SMTP Mockup Server: %#v", err) } if err := deleteTestDB("test.db"); err != nil { log.Fatalf("Failed to tear down DB: %#v", err) } } func initSubscriptionPlans() error { subscriptions := []models.SubscriptionModel{ { Name: "Basic", Details: "Test Plan", MonthlyFee: 2, HourlyRate: 3, }, { Name: "additional", Details: "This plan needs another membership id to validate", RequiredMembershipField: "ParentMembershipID", MonthlyFee: 2, HourlyRate: 3, }, } for _, subscription := range subscriptions { result := database.DB.Create(&subscription) if result.Error != nil { return result.Error } } return nil } func GetMockedJSONContext(jsonStr []byte, url string) (*gin.Context, *httptest.ResponseRecorder, *gin.Engine) { gin.SetMode(gin.TestMode) w := httptest.NewRecorder() c, _ := gin.CreateTestContext(w) router := gin.New() // Load HTML templates router.LoadHTMLGlob(config.Templates.HTMLPath + "/*") var err error c.Request, err = http.NewRequest("POST", url, bytes.NewBuffer(jsonStr)) if err != nil { log.Fatalf("Failed to create new Request: %#v", err) } c.Request.Header.Set("Content-Type", "application/json") return c, w, router } func GetMockedFormContext(formData url.Values, url string) (*gin.Context, *httptest.ResponseRecorder, *gin.Engine) { gin.SetMode(gin.TestMode) w := httptest.NewRecorder() c, _ := gin.CreateTestContext(w) router := gin.New() // Load HTML templates router.LoadHTMLGlob(config.Templates.HTMLPath + "/*") req, err := http.NewRequest("POST", url, bytes.NewBufferString(formData.Encode())) if err != nil { log.Fatalf("Failed to create new Request: %#v", err) } req.Header.Set("Content-Type", "application/x-www-form-urlencoded") c.Request = req return c, w, router } func deleteTestDB(dbPath string) error { err := os.Remove(dbPath) if err != nil { return err } return nil } func runSingleTest(tc TestCase) error { c, w, router := tc.SetupContext() tc.RunHandler(c, router) if err := tc.ValidateResponse(w); err != nil { return err } return tc.ValidateResult() } func GenerateInputJSON(aStruct interface{}) string { // Marshal the object into JSON jsonBytes, err := json.Marshal(aStruct) if err != nil { logger.Error.Fatalf("Couldn't generate JSON: %#v\nERROR: %#v", aStruct, err) return "" } return string(jsonBytes) }