363 lines
8.6 KiB
Go
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)
|
|
}
|