516 lines
14 KiB
Go
516 lines
14 KiB
Go
package database
|
|
|
|
import (
|
|
"fmt"
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
"testing"
|
|
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
"gorm.io/driver/sqlite"
|
|
"gorm.io/gorm"
|
|
)
|
|
|
|
// setupTestHelperEnvironment sets up the test environment for testhelper tests
|
|
func setupTestHelperEnvironment(t *testing.T) {
|
|
// Save original state
|
|
originalDB := DB
|
|
originalIsTestDb := isTestDb
|
|
originalTestdbTempDir := testdbTempDir
|
|
|
|
// Cleanup function
|
|
t.Cleanup(func() {
|
|
// Restore original state
|
|
DB = originalDB
|
|
isTestDb = originalIsTestDb
|
|
testdbTempDir = originalTestdbTempDir
|
|
})
|
|
}
|
|
|
|
func TestCopyFile(t *testing.T) {
|
|
// Create a temporary directory for testing
|
|
tempDir := t.TempDir()
|
|
|
|
// Create a source file with test content
|
|
sourceContent := "This is test content for file copying\nLine 2\nLine 3"
|
|
sourceFile := filepath.Join(tempDir, "source.txt")
|
|
err := os.WriteFile(sourceFile, []byte(sourceContent), 0644)
|
|
require.NoError(t, err, "Should be able to create source file")
|
|
|
|
// Define destination file path
|
|
destFile := filepath.Join(tempDir, "destination.txt")
|
|
|
|
// Test successful file copy
|
|
err = copyFile(sourceFile, destFile)
|
|
assert.NoError(t, err, "copyFile should succeed with valid source and destination")
|
|
|
|
// Verify destination file exists and has correct content
|
|
destContent, err := os.ReadFile(destFile)
|
|
assert.NoError(t, err, "Should be able to read destination file")
|
|
assert.Equal(t, sourceContent, string(destContent), "Destination file should have same content as source")
|
|
|
|
// Verify file info
|
|
sourceInfo, err := os.Stat(sourceFile)
|
|
require.NoError(t, err, "Should be able to stat source file")
|
|
destInfo, err := os.Stat(destFile)
|
|
require.NoError(t, err, "Should be able to stat destination file")
|
|
assert.Equal(t, sourceInfo.Size(), destInfo.Size(), "Files should have same size")
|
|
}
|
|
|
|
func TestCopyFile_NonExistentSource(t *testing.T) {
|
|
tempDir := t.TempDir()
|
|
|
|
sourceFile := filepath.Join(tempDir, "nonexistent.txt")
|
|
destFile := filepath.Join(tempDir, "destination.txt")
|
|
|
|
// Test copying from non-existent source
|
|
err := copyFile(sourceFile, destFile)
|
|
assert.Error(t, err, "copyFile should fail with non-existent source file")
|
|
assert.True(t, os.IsNotExist(err), "Error should be file not found error")
|
|
|
|
// Verify destination file was not created
|
|
_, err = os.Stat(destFile)
|
|
assert.True(t, os.IsNotExist(err), "Destination file should not exist")
|
|
}
|
|
|
|
func TestCopyFile_InvalidDestination(t *testing.T) {
|
|
tempDir := t.TempDir()
|
|
|
|
// Create a source file
|
|
sourceFile := filepath.Join(tempDir, "source.txt")
|
|
err := os.WriteFile(sourceFile, []byte("test content"), 0644)
|
|
require.NoError(t, err, "Should be able to create source file")
|
|
|
|
// Try to copy to an invalid destination (non-existent directory)
|
|
destFile := filepath.Join(tempDir, "nonexistent_dir", "destination.txt")
|
|
|
|
err = copyFile(sourceFile, destFile)
|
|
assert.Error(t, err, "copyFile should fail with invalid destination path")
|
|
}
|
|
|
|
func TestCopyFile_EmptyFile(t *testing.T) {
|
|
tempDir := t.TempDir()
|
|
|
|
// Create an empty source file
|
|
sourceFile := filepath.Join(tempDir, "empty.txt")
|
|
err := os.WriteFile(sourceFile, []byte(""), 0644)
|
|
require.NoError(t, err, "Should be able to create empty source file")
|
|
|
|
destFile := filepath.Join(tempDir, "empty_dest.txt")
|
|
|
|
// Test copying empty file
|
|
err = copyFile(sourceFile, destFile)
|
|
assert.NoError(t, err, "copyFile should succeed with empty file")
|
|
|
|
// Verify destination file exists and is empty
|
|
destContent, err := os.ReadFile(destFile)
|
|
assert.NoError(t, err, "Should be able to read empty destination file")
|
|
assert.Empty(t, destContent, "Destination file should be empty")
|
|
}
|
|
|
|
func TestCopyFile_LargeFile(t *testing.T) {
|
|
tempDir := t.TempDir()
|
|
|
|
// Create a larger file (1MB)
|
|
sourceFile := filepath.Join(tempDir, "large.txt")
|
|
largeContent := strings.Repeat("This is a test line.\n", 50000) // ~1MB
|
|
err := os.WriteFile(sourceFile, []byte(largeContent), 0644)
|
|
require.NoError(t, err, "Should be able to create large source file")
|
|
|
|
destFile := filepath.Join(tempDir, "large_dest.txt")
|
|
|
|
// Test copying large file
|
|
err = copyFile(sourceFile, destFile)
|
|
assert.NoError(t, err, "copyFile should succeed with large file")
|
|
|
|
// Verify file sizes match
|
|
sourceInfo, err := os.Stat(sourceFile)
|
|
require.NoError(t, err, "Should be able to stat source file")
|
|
destInfo, err := os.Stat(destFile)
|
|
require.NoError(t, err, "Should be able to stat destination file")
|
|
assert.Equal(t, sourceInfo.Size(), destInfo.Size(), "Large files should have same size")
|
|
}
|
|
|
|
func TestSetupTestDB_WithTestDatabase(t *testing.T) {
|
|
setupTestHelperEnvironment(t)
|
|
|
|
// Reset global state
|
|
DB = nil
|
|
isTestDb = false
|
|
|
|
// Create a mock prepared test database
|
|
tempDir := t.TempDir()
|
|
mockPreparedDB := filepath.Join(tempDir, "prepared_test.db")
|
|
|
|
// Create a simple SQLite database file
|
|
db, err := gorm.Open(sqlite.Open(mockPreparedDB), &gorm.Config{})
|
|
require.NoError(t, err, "Should be able to create mock prepared database")
|
|
sqlDB, err := db.DB()
|
|
require.NoError(t, err, "Should be able to get underlying sql.DB")
|
|
sqlDB.Close()
|
|
|
|
// Temporarily override PreparedTestDB path
|
|
originalPreparedTestDB := PreparedTestDB
|
|
PreparedTestDB = mockPreparedDB
|
|
defer func() {
|
|
PreparedTestDB = originalPreparedTestDB
|
|
}()
|
|
|
|
// Test SetupTestDB with test database (default behavior)
|
|
SetupTestDB()
|
|
|
|
// Verify database was set up
|
|
assert.NotNil(t, DB, "SetupTestDB should set global DB")
|
|
assert.True(t, isTestDb, "Should be using test database")
|
|
|
|
// Verify we can use the database
|
|
sqlDB, err = DB.DB()
|
|
assert.NoError(t, err, "Should be able to get underlying sql.DB")
|
|
if sqlDB != nil {
|
|
err = sqlDB.Ping()
|
|
assert.NoError(t, err, "Should be able to ping test database")
|
|
}
|
|
}
|
|
|
|
func TestSetupTestDB_WithLiveDatabase(t *testing.T) {
|
|
setupTestHelperEnvironment(t)
|
|
|
|
// Reset global state
|
|
DB = nil
|
|
isTestDb = false
|
|
testdbTempDir = ""
|
|
|
|
// Test SetupTestDB with live database
|
|
SetupTestDB(false)
|
|
|
|
// Verify database was set up
|
|
assert.NotNil(t, DB, "SetupTestDB should set global DB")
|
|
assert.False(t, isTestDb, "Should be using live database")
|
|
|
|
// Verify we can use the database (this will connect to the actual configured database)
|
|
sqlDB, err := DB.DB()
|
|
if err == nil && sqlDB != nil {
|
|
err = sqlDB.Ping()
|
|
assert.NoError(t, err, "Should be able to ping live database")
|
|
}
|
|
}
|
|
|
|
func TestSetupTestDB_AlreadyInitialized(t *testing.T) {
|
|
setupTestHelperEnvironment(t)
|
|
|
|
// Create a mock database connection
|
|
tempDir := t.TempDir()
|
|
dbPath := filepath.Join(tempDir, "existing.db")
|
|
existingDB, err := gorm.Open(sqlite.Open(dbPath), &gorm.Config{})
|
|
require.NoError(t, err, "Should be able to create existing database")
|
|
|
|
// Set global DB to existing connection
|
|
DB = existingDB
|
|
isTestDb = true
|
|
|
|
// Call SetupTestDB - should not change the existing DB
|
|
SetupTestDB()
|
|
|
|
// Verify DB remains the same
|
|
assert.Equal(t, existingDB, DB, "SetupTestDB should not change existing DB")
|
|
}
|
|
|
|
func TestSetupTestDB_MissingPreparedDatabase(t *testing.T) {
|
|
setupTestHelperEnvironment(t)
|
|
|
|
// Reset global state
|
|
DB = nil
|
|
isTestDb = false
|
|
|
|
// Set PreparedTestDB to non-existent file
|
|
originalPreparedTestDB := PreparedTestDB
|
|
PreparedTestDB = "/nonexistent/path/to/database.db"
|
|
defer func() {
|
|
PreparedTestDB = originalPreparedTestDB
|
|
}()
|
|
|
|
// Test SetupTestDB with missing prepared database - should panic
|
|
defer func() {
|
|
if r := recover(); r != nil {
|
|
assert.Contains(t, r.(string), "failed to copy prepared test database",
|
|
"Should panic with appropriate error message")
|
|
}
|
|
}()
|
|
|
|
SetupTestDB(true)
|
|
|
|
// If we reach here, the test should fail
|
|
t.Fatal("Expected panic when prepared test database is missing")
|
|
}
|
|
|
|
func TestSetupTestDB_ParameterVariations(t *testing.T) {
|
|
setupTestHelperEnvironment(t)
|
|
|
|
tests := []struct {
|
|
name string
|
|
params []bool
|
|
expectedVal bool
|
|
description string
|
|
}{
|
|
{
|
|
name: "No parameters",
|
|
params: []bool{},
|
|
expectedVal: true,
|
|
description: "Should default to test database",
|
|
},
|
|
{
|
|
name: "Explicit true",
|
|
params: []bool{true},
|
|
expectedVal: true,
|
|
description: "Should use test database when explicitly set to true",
|
|
},
|
|
{
|
|
name: "Explicit false",
|
|
params: []bool{false},
|
|
expectedVal: false,
|
|
description: "Should use live database when explicitly set to false",
|
|
},
|
|
{
|
|
name: "Multiple parameters (first true)",
|
|
params: []bool{true, false},
|
|
expectedVal: true,
|
|
description: "Should use first parameter when multiple provided",
|
|
},
|
|
{
|
|
name: "Multiple parameters (first false)",
|
|
params: []bool{false, true},
|
|
expectedVal: false,
|
|
description: "Should use first parameter when multiple provided",
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
// Reset state for each test
|
|
DB = nil
|
|
isTestDb = false
|
|
|
|
if tt.expectedVal {
|
|
// For test database, we need a mock prepared database
|
|
tempDir := t.TempDir()
|
|
mockPreparedDB := filepath.Join(tempDir, "prepared_test.db")
|
|
db, err := gorm.Open(sqlite.Open(mockPreparedDB), &gorm.Config{})
|
|
require.NoError(t, err, "Should be able to create mock prepared database")
|
|
sqlDB, err := db.DB()
|
|
require.NoError(t, err, "Should be able to get underlying sql.DB")
|
|
sqlDB.Close()
|
|
|
|
originalPreparedTestDB := PreparedTestDB
|
|
PreparedTestDB = mockPreparedDB
|
|
defer func() {
|
|
PreparedTestDB = originalPreparedTestDB
|
|
}()
|
|
}
|
|
|
|
SetupTestDB(tt.params...)
|
|
|
|
assert.Equal(t, tt.expectedVal, isTestDb, tt.description)
|
|
assert.NotNil(t, DB, "Database should be initialized")
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestResetTestDB_WithTestDatabase(t *testing.T) {
|
|
setupTestHelperEnvironment(t)
|
|
|
|
// Set up a test database first
|
|
tempDir := t.TempDir()
|
|
dbPath := filepath.Join(tempDir, "test_reset.db")
|
|
testDB, err := gorm.Open(sqlite.Open(dbPath), &gorm.Config{})
|
|
require.NoError(t, err, "Should be able to create test database")
|
|
|
|
// Set global state as if SetupTestDB was called
|
|
DB = testDB
|
|
isTestDb = true
|
|
|
|
// Call ResetTestDB
|
|
ResetTestDB()
|
|
|
|
// Verify cleanup
|
|
assert.Nil(t, DB, "DB should be reset to nil")
|
|
|
|
// Note: We can't easily test directory cleanup since the package-level
|
|
// testdbTempDir variable isn't being set properly in the current implementation
|
|
// But we can verify that the function completes without error
|
|
}
|
|
|
|
func TestResetTestDB_WithLiveDatabase(t *testing.T) {
|
|
setupTestHelperEnvironment(t)
|
|
|
|
// Set up as if using live database
|
|
tempDir := t.TempDir()
|
|
dbPath := filepath.Join(tempDir, "live_db.db")
|
|
liveDB, err := gorm.Open(sqlite.Open(dbPath), &gorm.Config{})
|
|
require.NoError(t, err, "Should be able to create live database")
|
|
|
|
DB = liveDB
|
|
isTestDb = false
|
|
|
|
// Call ResetTestDB
|
|
ResetTestDB()
|
|
|
|
// For live database, cleanup should be skipped
|
|
// DB and other state should remain unchanged for live database
|
|
// Note: The actual behavior might vary, but the function should not crash
|
|
assert.True(t, true, "ResetTestDB should not crash with live database")
|
|
}
|
|
|
|
func TestResetTestDB_WithNilDB(t *testing.T) {
|
|
setupTestHelperEnvironment(t)
|
|
|
|
// Set state with nil DB
|
|
DB = nil
|
|
isTestDb = true
|
|
|
|
// Call ResetTestDB - should not crash
|
|
defer func() {
|
|
if r := recover(); r != nil {
|
|
t.Fatalf("ResetTestDB should not panic with nil DB: %v", r)
|
|
}
|
|
}()
|
|
|
|
ResetTestDB()
|
|
|
|
// Should complete without error
|
|
assert.Nil(t, DB, "DB should remain nil")
|
|
}
|
|
|
|
func TestResetTestDB_ErrorHandling(t *testing.T) {
|
|
setupTestHelperEnvironment(t)
|
|
|
|
// Create a test database and close it immediately to simulate error conditions
|
|
tempDir := t.TempDir()
|
|
dbPath := filepath.Join(tempDir, "error_test.db")
|
|
testDB, err := gorm.Open(sqlite.Open(dbPath), &gorm.Config{})
|
|
require.NoError(t, err, "Should be able to create test database")
|
|
|
|
// Close the underlying connection to simulate error
|
|
sqlDB, err := testDB.DB()
|
|
require.NoError(t, err, "Should be able to get underlying sql.DB")
|
|
sqlDB.Close()
|
|
|
|
// Set global state
|
|
DB = testDB
|
|
isTestDb = true
|
|
|
|
// Call ResetTestDB - should handle errors gracefully
|
|
defer func() {
|
|
if r := recover(); r != nil {
|
|
t.Fatalf("ResetTestDB should not panic on errors: %v", r)
|
|
}
|
|
}()
|
|
|
|
ResetTestDB()
|
|
|
|
// Function should complete even with errors
|
|
assert.True(t, true, "ResetTestDB should handle errors gracefully")
|
|
}
|
|
|
|
func TestSetupTestDB_ResetTestDB_Cycle(t *testing.T) {
|
|
setupTestHelperEnvironment(t)
|
|
|
|
// Create a mock prepared test database
|
|
tempDir := t.TempDir()
|
|
mockPreparedDB := filepath.Join(tempDir, "prepared_cycle_test.db")
|
|
db, err := gorm.Open(sqlite.Open(mockPreparedDB), &gorm.Config{})
|
|
require.NoError(t, err, "Should be able to create mock prepared database")
|
|
sqlDB, err := db.DB()
|
|
require.NoError(t, err, "Should be able to get underlying sql.DB")
|
|
sqlDB.Close()
|
|
|
|
originalPreparedTestDB := PreparedTestDB
|
|
PreparedTestDB = mockPreparedDB
|
|
defer func() {
|
|
PreparedTestDB = originalPreparedTestDB
|
|
}()
|
|
|
|
// Test complete setup and reset cycle
|
|
for i := 0; i < 3; i++ {
|
|
t.Run(fmt.Sprintf("Cycle_%d", i+1), func(t *testing.T) {
|
|
// Reset state
|
|
DB = nil
|
|
isTestDb = false
|
|
|
|
// Setup
|
|
SetupTestDB()
|
|
assert.NotNil(t, DB, "SetupTestDB should initialize DB")
|
|
assert.True(t, isTestDb, "Should be using test database")
|
|
|
|
// Verify database is working
|
|
sqlDB, err := DB.DB()
|
|
assert.NoError(t, err, "Should be able to get underlying sql.DB")
|
|
if sqlDB != nil {
|
|
err = sqlDB.Ping()
|
|
assert.NoError(t, err, "Should be able to ping the database")
|
|
}
|
|
|
|
// Reset
|
|
ResetTestDB()
|
|
assert.Nil(t, DB, "ResetTestDB should reset DB to nil")
|
|
})
|
|
}
|
|
}
|
|
|
|
// Benchmark tests
|
|
func BenchmarkCopyFile(b *testing.B) {
|
|
// Create test files
|
|
tempDir := b.TempDir()
|
|
sourceFile := filepath.Join(tempDir, "source.txt")
|
|
content := strings.Repeat("benchmark test content\n", 1000)
|
|
err := os.WriteFile(sourceFile, []byte(content), 0644)
|
|
if err != nil {
|
|
b.Fatalf("Failed to create source file: %v", err)
|
|
}
|
|
|
|
b.ResetTimer()
|
|
|
|
for i := 0; i < b.N; i++ {
|
|
destFile := filepath.Join(tempDir, fmt.Sprintf("dest_%d.txt", i))
|
|
err := copyFile(sourceFile, destFile)
|
|
if err != nil {
|
|
b.Fatalf("copyFile failed: %v", err)
|
|
}
|
|
}
|
|
}
|
|
|
|
func BenchmarkSetupTestDB(b *testing.B) {
|
|
// Create a mock prepared test database
|
|
tempDir := b.TempDir()
|
|
mockPreparedDB := filepath.Join(tempDir, "benchmark_prepared.db")
|
|
db, err := gorm.Open(sqlite.Open(mockPreparedDB), &gorm.Config{})
|
|
if err != nil {
|
|
b.Fatalf("Failed to create mock prepared database: %v", err)
|
|
}
|
|
sqlDB, err := db.DB()
|
|
if err != nil {
|
|
b.Fatalf("Failed to get underlying sql.DB: %v", err)
|
|
}
|
|
sqlDB.Close()
|
|
|
|
originalPreparedTestDB := PreparedTestDB
|
|
PreparedTestDB = mockPreparedDB
|
|
defer func() {
|
|
PreparedTestDB = originalPreparedTestDB
|
|
}()
|
|
|
|
b.ResetTimer()
|
|
|
|
for i := 0; i < b.N; i++ {
|
|
// Reset state for each iteration
|
|
DB = nil
|
|
isTestDb = false
|
|
|
|
SetupTestDB()
|
|
|
|
// Clean up
|
|
ResetTestDB()
|
|
}
|
|
}
|