package config import ( "os" "path/filepath" "strings" "testing" ) const baseConfig = ` app: name: test-app env: development server: host: 127.0.0.1 port: 8080 database: host: 127.0.0.1 port: 3306 name: base_db user: base_user password: base_password auth: jwt_secret: base-development-secret seed: admin_username: admin admin_password: admin123 admin_display_name: Admin ` func TestLoadProfileThenEnvironmentOverride(t *testing.T) { dir := writeConfigs(t, ` app: env: test server: port: 8081 database: name: profile_db auth: jwt_secret: test-profile-secret `) t.Setenv("APP_DATABASE_NAME", "environment_db") t.Setenv("APP_SERVER_PORT", "9090") cfg, err := Load(LoadOptions{Environment: "test", ConfigDir: dir}) if err != nil { t.Fatalf("Load() error = %v", err) } if cfg.App.Env != "test" || cfg.Database.Name != "environment_db" || cfg.Database.User != "base_user" || cfg.Server.Port != 9090 { t.Fatalf("unexpected merged config: %+v", cfg) } } func TestLoadProductionRequiresEnvironmentSecrets(t *testing.T) { dir := writeConfigs(t, "app:\n env: production\n") t.Setenv("APP_DATABASE_PASSWORD", "") t.Setenv("APP_AUTH_JWT_SECRET", "") _, err := Load(LoadOptions{Environment: "prod", ConfigDir: dir}) if err == nil || !strings.Contains(err.Error(), "APP_DATABASE_PASSWORD") { t.Fatalf("Load() error = %v, want production password requirement", err) } t.Setenv("APP_DATABASE_PASSWORD", "production-password") t.Setenv("APP_AUTH_JWT_SECRET", "production-jwt-secret") cfg, err := Load(LoadOptions{Environment: "prod", ConfigDir: dir}) if err != nil { t.Fatalf("Load() with environment secrets error = %v", err) } if cfg.Database.Password != "production-password" || cfg.Auth.JWTSecret != "production-jwt-secret" { t.Fatalf("environment secrets were not applied") } } func TestLoadMultiTableEnvironmentConfiguration(t *testing.T) { dir := writeConfigs(t, "") t.Setenv("APP_MULTITABLE_ENABLED", "true") t.Setenv("APP_MULTITABLE_API_KEY", "test-key") for key, value := range map[string]string{ "APP_MULTITABLE_TABLES_SCENARIOS": "46", "APP_MULTITABLE_TABLES_SCENARIO_FIELDS": "47", "APP_MULTITABLE_TABLES_SCENARIO_RULES": "54", "APP_MULTITABLE_TABLES_SOP_VERSIONS": "48", "APP_MULTITABLE_TABLES_SOP_NODES": "49", "APP_MULTITABLE_TABLES_SOP_EDGES": "50", "APP_MULTITABLE_TABLES_KNOWLEDGE_VERSIONS": "51", "APP_MULTITABLE_TABLES_KNOWLEDGE_ITEMS": "55", "APP_MULTITABLE_TABLES_KNOWLEDGE_RELATIONS": "56", "APP_MULTITABLE_TABLES_RUNS": "52", "APP_MULTITABLE_TABLES_FEEDBACK": "53", } { t.Setenv(key, value) } cfg, err := Load(LoadOptions{ConfigDir: dir}) if err != nil { t.Fatalf("Load() error = %v", err) } if !cfg.MultiTable.Enabled || cfg.MultiTable.Tables.Scenarios != 46 || cfg.MultiTable.Tables.ScenarioRules != 54 || cfg.MultiTable.Tables.KnowledgeItems != 55 || cfg.MultiTable.Tables.KnowledgeRelations != 56 || cfg.MultiTable.Tables.Feedback != 53 { t.Fatalf("unexpected multitable configuration: %+v", cfg.MultiTable) } } func writeConfigs(t *testing.T, profile string) string { t.Helper() dir := t.TempDir() if err := os.WriteFile(filepath.Join(dir, "config.yml"), []byte(baseConfig), 0o600); err != nil { t.Fatal(err) } if err := os.WriteFile(filepath.Join(dir, "config.test.yml"), []byte(profile), 0o600); err != nil { t.Fatal(err) } if err := os.WriteFile(filepath.Join(dir, "config.prod.yml"), []byte(profile), 0o600); err != nil { t.Fatal(err) } return dir }