TestCopyLiveDatabaseToFile now runs

after connection to local MySQL database is working for go tests
This commit is contained in:
2026-01-02 12:07:28 +01:00
parent 5ce28bb79b
commit a547d850a2
10 changed files with 58 additions and 25 deletions
+7 -7
View File
@@ -193,10 +193,10 @@ func splitSkills(object []models.SkFertigkeit) ([]models.SkFertigkeit, []models.
type ExperienceAndWealthResponse struct { type ExperienceAndWealthResponse struct {
ExperiencePoints int `json:"experience_points"` ExperiencePoints int `json:"experience_points"`
Wealth struct { Wealth struct {
Goldstücke int `json:"gold_coins"` // GS Goldstuecke int `json:"gold_coins"` // GS
Silberstücke int `json:"silver_coins"` // SS Silberstuecke int `json:"silver_coins"` // SS
Kupferstücke int `json:"copper_coins"` // KS Kupferstuecke int `json:"copper_coins"` // KS
TotalInGS int `json:"total_in_ss"` // Gesamt in Silberstücken TotalInGS int `json:"total_in_ss"` // Gesamt in Silberstücken
} `json:"wealth"` } `json:"wealth"`
} }
@@ -225,9 +225,9 @@ func GetCharacterExperienceAndWealth(c *gin.Context) {
response := ExperienceAndWealthResponse{ response := ExperienceAndWealthResponse{
ExperiencePoints: character.Erfahrungsschatz.EP, ExperiencePoints: character.Erfahrungsschatz.EP,
} }
response.Wealth.Goldstücke = gs response.Wealth.Goldstuecke = gs
response.Wealth.Silberstücke = ss response.Wealth.Silberstuecke = ss
response.Wealth.Kupferstücke = ks response.Wealth.Kupferstuecke = ks
response.Wealth.TotalInGS = totalInSS response.Wealth.TotalInGS = totalInSS
c.JSON(http.StatusOK, response) c.JSON(http.StatusOK, response)
+1
View File
@@ -599,6 +599,7 @@ func TestFinalizeCharacterCreation(t *testing.T) {
UserID: 1, UserID: 1,
Username: "bebe", Username: "bebe",
Email: "frank@wuenscheonline.de", Email: "frank@wuenscheonline.de",
Role: "admin",
} }
err = database.DB.Create(&testUser).Error err = database.DB.Create(&testUser).Error
assert.NoError(t, err) assert.NoError(t, err)
+4
View File
@@ -145,6 +145,10 @@ func LoadConfig() *Config {
// loadEnvFile lädt eine .env-Datei falls vorhanden // loadEnvFile lädt eine .env-Datei falls vorhanden
func loadEnvFile() { func loadEnvFile() {
envFiles := []string{".env", ".env.local"} envFiles := []string{".env", ".env.local"}
configFile := os.Getenv("CONFIG_FILE")
if configFile != "" {
envFiles = append(envFiles, configFile)
}
for _, envFile := range envFiles { for _, envFile := range envFiles {
if _, err := os.Stat(envFile); err == nil { if _, err := os.Stat(envFile); err == nil {
+1 -1
View File
@@ -70,7 +70,7 @@ func ConnectDatabaseOrig() *gorm.DB {
// Falls keine URL konfiguriert ist, verwende Standard-MySQL-Konfiguration als Fallback // Falls keine URL konfiguriert ist, verwende Standard-MySQL-Konfiguration als Fallback
dbURL := cfg.DatabaseURL dbURL := cfg.DatabaseURL
if dbURL == "" { if dbURL == "" {
dbURL = "bamort:bG4)efozrc@tcp(192.168.0.5:3306)/bamort?charset=utf8mb4&parseTime=True&loc=Local" dbURL = "bamort:bG4)efozrc@tcp(localhost:3306)/bamort?charset=utf8mb4&parseTime=True&loc=Local"
logger.Warn("Keine DATABASE_URL konfiguriert, verwende Standard-MySQL-Konfiguration") logger.Warn("Keine DATABASE_URL konfiguriert, verwende Standard-MySQL-Konfiguration")
cfg.DatabaseType = "mysql" cfg.DatabaseType = "mysql"
} }
+8 -4
View File
@@ -43,7 +43,9 @@ func TestMaintSetupCheck(t *testing.T) {
} }
func TestGetMasterData(t *testing.T) { func TestGetMasterData(t *testing.T) {
database.SetupTestDB() //(false) // Ensure fresh database connection
database.DB = nil
database.SetupTestDB()
// Initialize a Gin router // Initialize a Gin router
r := gin.Default() r := gin.Default()
router.SetupGin(r) router.SetupGin(r)
@@ -56,7 +58,9 @@ func TestGetMasterData(t *testing.T) {
c.JSON(http.StatusOK, gin.H{"status": "Test OK"}) c.JSON(http.StatusOK, gin.H{"status": "Test OK"})
}) })
u := user.User{} u := user.User{}
u.FirstId(1) err := u.FirstId(1)
require.NoError(t, err, "Failed to load user with ID 1")
require.Equal(t, "admin", u.Role, "User 1 should be admin")
// Create a test HTTP request // Create a test HTTP request
req, _ := http.NewRequest("GET", "/api/maintenance", nil) req, _ := http.NewRequest("GET", "/api/maintenance", nil)
@@ -82,8 +86,8 @@ func TestGetMasterData(t *testing.T) {
Weapons []models.Weapon `json:"weapons"` Weapons []models.Weapon `json:"weapons"`
} }
var dta dtaStruct var dta dtaStruct
err := json.Unmarshal(respRecorder.Body.Bytes(), &dta) errUnmarshal := json.Unmarshal(respRecorder.Body.Bytes(), &dta)
assert.NoError(t, err) assert.NoError(t, errUnmarshal)
} }
func TestGetMDSkillCategories(t *testing.T) { func TestGetMDSkillCategories(t *testing.T) {
+8 -2
View File
@@ -1,6 +1,7 @@
package maintenance package maintenance
import ( import (
"bamort/config"
"bamort/database" "bamort/database"
"bamort/models" "bamort/models"
"bamort/user" "bamort/user"
@@ -20,8 +21,13 @@ func TestCopyLiveDatabaseToFile(t *testing.T) {
// Setup // Setup
tempDir := t.TempDir() tempDir := t.TempDir()
targetFile := filepath.Join(tempDir, "empty_backup.db") targetFile := filepath.Join(tempDir, "empty_backup.db")
envpath, _ := filepath.Abs("../.env.test")
os.Setenv("CONFIG_FILE", envpath)
// Create empty live database (only migrate structures, no data) config.Cfg = config.LoadConfig()
// Reset database connection to ensure we use environment config
database.DB = nil
database.ConnectDatabase() database.ConnectDatabase()
liveDB := database.DB liveDB := database.DB
require.NotNil(t, liveDB, "Live database should be connected") require.NotNil(t, liveDB, "Live database should be connected")
@@ -51,7 +57,7 @@ func TestCopyLiveDatabaseToFile(t *testing.T) {
var userCount int64 var userCount int64
err = targetDB.Model(&user.User{}).Count(&userCount).Error err = targetDB.Model(&user.User{}).Count(&userCount).Error
require.NoError(t, err, "Should be able to count users") require.NoError(t, err, "Should be able to count users")
assert.Equal(t, int64(2), userCount, "User table should be empty") assert.GreaterOrEqual(t, userCount, int64(2), "User table should have more that 2 users")
// Copy target file to database.PreparedTestDB for permanent storage // Copy target file to database.PreparedTestDB for permanent storage
// Close the database connection before copying // Close the database connection before copying
+18 -6
View File
@@ -10,6 +10,7 @@ import (
"net/http" "net/http"
"os" "os"
"path/filepath" "path/filepath"
"reflect"
"strings" "strings"
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
@@ -299,19 +300,30 @@ func copyTableData(sourceDB, targetDB *gorm.DB, model interface{}) error {
batchSize := 100 batchSize := 100
totalBatches := (int(count) + batchSize - 1) / batchSize totalBatches := (int(count) + batchSize - 1) / batchSize
// Get the element type for creating slice of records
modelType := reflect.TypeOf(model).Elem()
for offset := 0; offset < int(count); offset += batchSize { for offset := 0; offset < int(count); offset += batchSize {
batchNum := (offset / batchSize) + 1 batchNum := (offset / batchSize) + 1
logger.Debug("Kopiere Batch %d/%d für %s (Offset: %d, Limit: %d)", batchNum, totalBatches, tableName, offset, batchSize) logger.Debug("Kopiere Batch %d/%d für %s (Offset: %d, Limit: %d)", batchNum, totalBatches, tableName, offset, batchSize)
var records []map[string]interface{} // Create a slice of the model type using reflection
sliceType := reflect.SliceOf(modelType)
recordsValue := reflect.MakeSlice(sliceType, 0, batchSize)
recordsPtr := reflect.New(sliceType)
recordsPtr.Elem().Set(recordsValue)
// Batch aus MariaDB lesen // Batch aus MariaDB lesen (use proper struct type instead of map)
if err := sourceDB.Model(model).Offset(offset).Limit(batchSize).Find(&records).Error; err != nil { if err := sourceDB.Model(model).Offset(offset).Limit(batchSize).Find(recordsPtr.Interface()).Error; err != nil {
logger.Error("Fehler beim Lesen von Batch %d für %s: %s", batchNum, tableName, err.Error()) logger.Error("Fehler beim Lesen von Batch %d für %s: %s", batchNum, tableName, err.Error())
return err return err
} }
if len(records) == 0 { // Get the actual records from reflection
records := recordsPtr.Elem().Interface()
recordsLen := recordsPtr.Elem().Len()
if recordsLen == 0 {
logger.Debug("Keine weiteren Datensätze für %s", tableName) logger.Debug("Keine weiteren Datensätze für %s", tableName)
break break
} }
@@ -320,12 +332,12 @@ func copyTableData(sourceDB, targetDB *gorm.DB, model interface{}) error {
// Verwende Clauses.OnConflict um bestehende Datensätze zu ersetzen // Verwende Clauses.OnConflict um bestehende Datensätze zu ersetzen
if err := targetDB.Model(model).Clauses(clause.OnConflict{ if err := targetDB.Model(model).Clauses(clause.OnConflict{
UpdateAll: true, UpdateAll: true,
}).Create(&records).Error; err != nil { }).Create(records).Error; err != nil {
logger.Error("Fehler beim Einfügen von Batch %d für %s: %s", batchNum, tableName, err.Error()) logger.Error("Fehler beim Einfügen von Batch %d für %s: %s", batchNum, tableName, err.Error())
return err return err
} }
logger.Debug("Batch %d/%d für %s erfolgreich kopiert (%d Datensätze)", batchNum, totalBatches, tableName, len(records)) logger.Debug("Batch %d/%d für %s erfolgreich kopiert (%d Datensätze)", batchNum, totalBatches, tableName, recordsLen)
} }
logger.Info("Tabelle %s erfolgreich kopiert (%d Datensätze total)", tableName, count) logger.Info("Tabelle %s erfolgreich kopiert (%d Datensätze total)", tableName, count)
+3 -3
View File
@@ -69,9 +69,9 @@ type Bennies struct {
type Vermoegen struct { type Vermoegen struct {
BamortCharTrait BamortCharTrait
Goldstuecke int `json:"goldstücke"` // GS Goldstuecke int `gorm:"column:goldstuecke" json:"goldstücke"` // GS
Silberstuecke int `json:"silberstücke"` // SS Silberstuecke int `gorm:"column:silberstuecke" json:"silberstücke"` // SS
Kupferstuecke int `json:"kupferstücke"` // KS Kupferstuecke int `gorm:"column:kupferstuecke" json:"kupferstücke"` // KS
} }
type Char struct { type Char struct {
+6
View File
@@ -565,6 +565,7 @@ func TestRegisterUser(t *testing.T) {
Username: "bebe", Username: "bebe",
PasswordHash: "osiris", PasswordHash: "osiris",
Email: "frank@wuenscheonline.de", Email: "frank@wuenscheonline.de",
Role: "admin",
} }
hashedPassword := md5.Sum([]byte(usr.PasswordHash)) hashedPassword := md5.Sum([]byte(usr.PasswordHash))
@@ -576,6 +577,7 @@ func TestRegisterUser(t *testing.T) {
Username: "bubnu", Username: "bubnu",
PasswordHash: "osiris", PasswordHash: "osiris",
Email: "spacer@wuenscheonline.de", Email: "spacer@wuenscheonline.de",
Role: "standard",
} }
hashedPassword = md5.Sum([]byte(usr2.PasswordHash)) hashedPassword = md5.Sum([]byte(usr2.PasswordHash))
usr2.PasswordHash = hex.EncodeToString(hashedPassword[:]) usr2.PasswordHash = hex.EncodeToString(hashedPassword[:])
@@ -591,6 +593,7 @@ func TestLoginUser(t *testing.T) {
Username: "logintest", Username: "logintest",
PasswordHash: "osiris", PasswordHash: "osiris",
Email: "login@test.com", Email: "login@test.com",
Role: "standard",
} }
hashedPassword := md5.Sum([]byte(usr.PasswordHash)) hashedPassword := md5.Sum([]byte(usr.PasswordHash))
usr.PasswordHash = hex.EncodeToString(hashedPassword[:]) usr.PasswordHash = hex.EncodeToString(hashedPassword[:])
@@ -686,6 +689,7 @@ func TestUser_EdgeCases(t *testing.T) {
Username: "", Username: "",
PasswordHash: "", PasswordHash: "",
Email: "", Email: "",
Role: "standard",
} }
err := user.Save() err := user.Save()
assert.NoError(t, err, "Should save user with empty strings") assert.NoError(t, err, "Should save user with empty strings")
@@ -704,6 +708,7 @@ func TestUser_EdgeCases(t *testing.T) {
Username: "longuser", Username: "longuser",
PasswordHash: longString, PasswordHash: longString,
Email: "long@example.com", Email: "long@example.com",
Role: "standard",
} }
err = user2.Create() err = user2.Create()
assert.NoError(t, err, "Should create user with long password hash") assert.NoError(t, err, "Should create user with long password hash")
@@ -717,6 +722,7 @@ func TestUser_ConcurrentAccess(t *testing.T) {
Username: "concurrentuser", Username: "concurrentuser",
PasswordHash: "hash", PasswordHash: "hash",
Email: "concurrent@example.com", Email: "concurrent@example.com",
Role: "standard",
} }
err := user.Create() err := user.Create()
require.NoError(t, err, "Should be able to create test user") require.NoError(t, err, "Should be able to create test user")
+2 -2
View File
@@ -48,8 +48,8 @@ services:
image: mariadb:11.4 image: mariadb:11.4
container_name: bamort-mariadb-dev container_name: bamort-mariadb-dev
restart: unless-stopped restart: unless-stopped
#ports: ports:
# - "3306:3306" - "3306:3306"
environment: environment:
MARIADB_ROOT_PASSWORD: ${MARIADB_ROOT_PASSWORD:-secure_root_password} MARIADB_ROOT_PASSWORD: ${MARIADB_ROOT_PASSWORD:-secure_root_password}
MARIADB_DATABASE: ${MARIADB_DATABASE:-bamort} MARIADB_DATABASE: ${MARIADB_DATABASE:-bamort}