Files
GoMembership/internal/controllers/user_controller_test.go
2024-08-08 09:29:49 +02:00

336 lines
9.7 KiB
Go

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
}),
},
}
}