Files
omega-server/tests/testing.go
Fran Jurmanović b9cb315944 add tests
2025-07-06 19:19:42 +02:00

363 lines
8.6 KiB
Go

package tests
import (
"context"
"fmt"
"omega-server/local/model"
"omega-server/local/utl/logging"
"os"
"testing"
"go.uber.org/dig"
"gorm.io/driver/postgres"
"gorm.io/gorm"
"gorm.io/gorm/logger"
)
// TestConfig holds configuration for testing
type TestConfig struct {
DBHost string
DBPort string
DBUser string
DBPassword string
DBName string
DBSSLMode string
}
// TestSuite provides a base structure for test suites
type TestSuite struct {
DB *gorm.DB
DI *dig.Container
Config *TestConfig
}
// NewTestSuite creates a new test suite
func NewTestSuite() *TestSuite {
config := &TestConfig{
DBHost: getEnvOrDefault("TEST_DB_HOST", "localhost"),
DBPort: getEnvOrDefault("TEST_DB_PORT", "5432"),
DBUser: getEnvOrDefault("TEST_DB_USER", "postgres"),
DBPassword: getEnvOrDefault("TEST_DB_PASSWORD", "password"),
DBName: getEnvOrDefault("TEST_DB_NAME", "omega_test"),
DBSSLMode: getEnvOrDefault("TEST_DB_SSL_MODE", "disable"),
}
return &TestSuite{
Config: config,
DI: dig.New(),
}
}
// Setup initializes the test environment
func (ts *TestSuite) Setup(t *testing.T) {
// Initialize logger for tests
logger, err := logging.Initialize()
if err != nil {
t.Fatalf("Failed to initialize logger: %v", err)
}
defer logger.Close()
// Setup test database
ts.setupTestDatabase(t)
// Setup dependency injection
ts.setupDI(t)
// Migrate database
ts.migrateDatabase(t)
}
// Teardown cleans up the test environment
func (ts *TestSuite) Teardown(t *testing.T) {
if ts.DB != nil {
// Clean up test data
ts.cleanupDatabase(t)
// Close database connection
sqlDB, err := ts.DB.DB()
if err == nil {
sqlDB.Close()
}
}
}
// setupTestDatabase initializes the test database connection
func (ts *TestSuite) setupTestDatabase(t *testing.T) {
dsn := fmt.Sprintf("host=%s user=%s password=%s dbname=%s port=%s sslmode=%s TimeZone=UTC",
ts.Config.DBHost,
ts.Config.DBUser,
ts.Config.DBPassword,
ts.Config.DBName,
ts.Config.DBPort,
ts.Config.DBSSLMode,
)
// Use silent logger for tests
gormLogger := logger.Default.LogMode(logger.Silent)
db, err := gorm.Open(postgres.Open(dsn), &gorm.Config{
Logger: gormLogger,
})
if err != nil {
t.Skipf("Failed to connect to test database: %v", err)
}
ts.DB = db
}
// setupDI initializes dependency injection for tests
func (ts *TestSuite) setupDI(t *testing.T) {
err := ts.DI.Provide(func() *gorm.DB {
return ts.DB
})
if err != nil {
t.Fatalf("Failed to provide database to DI: %v", err)
}
}
// migrateDatabase runs database migrations for tests
func (ts *TestSuite) migrateDatabase(t *testing.T) {
err := ts.DB.AutoMigrate(
&model.User{},
&model.Role{},
&model.Permission{},
&model.Type{},
&model.Project{},
&model.Task{},
&model.Integration{},
&model.ProjectMember{},
&model.TaskAssignee{},
&model.SystemConfig{},
&model.AuditLog{},
&model.SecurityEvent{},
)
if err != nil {
t.Fatalf("Failed to migrate test database: %v", err)
}
}
// cleanupDatabase cleans up test data
func (ts *TestSuite) cleanupDatabase(t *testing.T) {
// Clean up in reverse order of dependencies
tables := []string{
"task_assignees",
"project_members",
"integrations",
"tasks",
"projects",
"types",
"user_roles",
"role_permissions",
"users",
"roles",
"permissions",
"system_configs",
"audit_logs",
"security_events",
}
for _, table := range tables {
err := ts.DB.Exec(fmt.Sprintf("TRUNCATE TABLE %s RESTART IDENTITY CASCADE", table)).Error
if err != nil {
t.Logf("Warning: Failed to truncate table %s: %v", table, err)
}
}
}
// CreateTestUser creates a test user
func (ts *TestSuite) CreateTestUser(t *testing.T, email, fullName string) *model.User {
user := &model.User{
Email: email,
FullName: fullName,
}
user.Init()
err := user.SetPassword("testpassword123")
if err != nil {
t.Fatalf("Failed to set password for test user: %v", err)
}
err = ts.DB.Create(user).Error
if err != nil {
t.Fatalf("Failed to create test user: %v", err)
}
return user
}
// CreateTestRole creates a test role
func (ts *TestSuite) CreateTestRole(t *testing.T, name, description string) *model.Role {
role := &model.Role{
Name: name,
Description: description,
Active: true,
}
role.Init()
err := ts.DB.Create(role).Error
if err != nil {
t.Fatalf("Failed to create test role: %v", err)
}
return role
}
// CreateTestPermission creates a test permission
func (ts *TestSuite) CreateTestPermission(t *testing.T, name, description, category string) *model.Permission {
permission := &model.Permission{
Name: name,
Description: description,
Category: category,
Active: true,
}
permission.Init()
err := ts.DB.Create(permission).Error
if err != nil {
t.Fatalf("Failed to create test permission: %v", err)
}
return permission
}
// CreateTestType creates a test project type
func (ts *TestSuite) CreateTestType(t *testing.T, name, description string, userID *string) *model.Type {
projectType := &model.Type{
Name: name,
Description: description,
UserID: userID,
}
projectType.Init()
err := ts.DB.Create(projectType).Error
if err != nil {
t.Fatalf("Failed to create test type: %v", err)
}
return projectType
}
// CreateTestProject creates a test project
func (ts *TestSuite) CreateTestProject(t *testing.T, name, description, ownerID, typeID string) *model.Project {
project := &model.Project{
Name: name,
Description: description,
OwnerID: ownerID,
TypeID: typeID,
}
project.Init()
err := ts.DB.Create(project).Error
if err != nil {
t.Fatalf("Failed to create test project: %v", err)
}
return project
}
// CreateTestTask creates a test task
func (ts *TestSuite) CreateTestTask(t *testing.T, title, description, projectID string) *model.Task {
task := &model.Task{
Title: title,
Description: description,
Status: model.TaskStatusTodo,
Priority: model.TaskPriorityMedium,
ProjectID: projectID,
}
task.Init()
err := ts.DB.Create(task).Error
if err != nil {
t.Fatalf("Failed to create test task: %v", err)
}
return task
}
// WithTransaction runs a function within a database transaction
func (ts *TestSuite) WithTransaction(t *testing.T, fn func(tx *gorm.DB) error) {
tx := ts.DB.Begin()
defer func() {
if r := recover(); r != nil {
tx.Rollback()
t.Fatalf("Transaction panicked: %v", r)
}
}()
if err := fn(tx); err != nil {
tx.Rollback()
t.Fatalf("Transaction failed: %v", err)
}
if err := tx.Commit().Error; err != nil {
t.Fatalf("Failed to commit transaction: %v", err)
}
}
// AssertUserExists asserts that a user exists in the database
func (ts *TestSuite) AssertUserExists(t *testing.T, email string) *model.User {
var user model.User
err := ts.DB.Where("email = ?", email).First(&user).Error
if err != nil {
t.Fatalf("Expected user with email %s to exist, but not found: %v", email, err)
}
return &user
}
// AssertUserNotExists asserts that a user does not exist in the database
func (ts *TestSuite) AssertUserNotExists(t *testing.T, email string) {
var user model.User
err := ts.DB.Where("email = ?", email).First(&user).Error
if err == nil {
t.Fatalf("Expected user with email %s to not exist, but found: %+v", email, user)
}
}
// AssertProjectExists asserts that a project exists in the database
func (ts *TestSuite) AssertProjectExists(t *testing.T, name string) *model.Project {
var project model.Project
err := ts.DB.Where("name = ?", name).First(&project).Error
if err != nil {
t.Fatalf("Expected project with name %s to exist, but not found: %v", name, err)
}
return &project
}
// AssertTaskExists asserts that a task exists in the database
func (ts *TestSuite) AssertTaskExists(t *testing.T, title string) *model.Task {
var task model.Task
err := ts.DB.Where("title = ?", title).First(&task).Error
if err != nil {
t.Fatalf("Expected task with title %s to exist, but not found: %v", title, err)
}
return &task
}
// TestContext creates a test context
func (ts *TestSuite) TestContext() context.Context {
return context.Background()
}
// getEnvOrDefault returns environment variable value or default
func getEnvOrDefault(key, defaultValue string) string {
if value := os.Getenv(key); value != "" {
return value
}
return defaultValue
}
// SkipIfNoTestDB skips test if test database is not available
func (ts *TestSuite) SkipIfNoTestDB(t *testing.T) {
if ts.DB == nil {
t.Skip("Test database not available, skipping test")
}
}
// RunInTestTransaction runs a test function in a transaction that gets rolled back
func (ts *TestSuite) RunInTestTransaction(t *testing.T, testFn func(tx *gorm.DB)) {
tx := ts.DB.Begin()
defer tx.Rollback()
testFn(tx)
}