package config import ( "testing" sdkconfig "github.com/go-admin-team/go-admin-core/sdk/config" ) func TestApplyEnvironment(t *testing.T) { originalDefault := *sdkconfig.DatabaseConfig originalDatabases := sdkconfig.DatabasesConfig originalApplication := *sdkconfig.ApplicationConfig t.Cleanup(func() { *sdkconfig.DatabaseConfig = originalDefault sdkconfig.DatabasesConfig = originalDatabases *sdkconfig.ApplicationConfig = originalApplication }) sdkconfig.DatabasesConfig = map[string]*sdkconfig.Database{"*": {Driver: "sqlite3", Source: "old.db"}} t.Setenv("GOAUTO_DB_DSN", "user:secret@tcp(127.0.0.1:3306)/goauto") t.Setenv("GOAUTO_DB_DRIVER", "mysql") t.Setenv("GOAUTO_SERVER_PORT", "18000") ApplyEnvironment() if sdkconfig.DatabaseConfig.Driver != "mysql" || sdkconfig.DatabaseConfig.Source == "" { t.Fatal("default database was not overridden") } if database := sdkconfig.DatabasesConfig["*"]; database.Driver != "mysql" || database.Source != sdkconfig.DatabaseConfig.Source { t.Fatal("host database was not overridden") } if sdkconfig.ApplicationConfig.Port != 18000 { t.Fatalf("application port = %d, want 18000", sdkconfig.ApplicationConfig.Port) } } func TestApplyEnvironmentIgnoresEmptyDatabaseAndInvalidPort(t *testing.T) { original := *sdkconfig.DatabaseConfig originalApplication := *sdkconfig.ApplicationConfig t.Cleanup(func() { *sdkconfig.DatabaseConfig = original *sdkconfig.ApplicationConfig = originalApplication }) sdkconfig.DatabaseConfig.Driver = "sqlite3" sdkconfig.DatabaseConfig.Source = "local.db" sdkconfig.ApplicationConfig.Port = 8000 t.Setenv("GOAUTO_DB_DSN", "") t.Setenv("GOAUTO_SERVER_PORT", "70000") ApplyEnvironment() if sdkconfig.DatabaseConfig.Driver != "sqlite3" || sdkconfig.DatabaseConfig.Source != "local.db" { t.Fatal("empty environment unexpectedly changed database config") } if sdkconfig.ApplicationConfig.Port != 8000 { t.Fatal("invalid environment unexpectedly changed application port") } } // 凭据只能来自环境变量:settings.yml 里不放账号密码,避免它们进 Git。 func TestApplyEnvironmentLoadsSYBCredentials(t *testing.T) { original := ExtConfig.SYB t.Cleanup(func() { ExtConfig.SYB = original }) t.Setenv("GOAUTO_SYB_USERNAME", " operator ") t.Setenv("GOAUTO_SYB_PASSWORD", " se cret ") ApplyEnvironment() if ExtConfig.SYB.Username != "operator" { t.Fatalf("账号应去掉首尾空白: %q", ExtConfig.SYB.Username) } // 密码原样保留:首尾空白可能是密码的一部分,剪掉就是悄悄改了凭据。 if ExtConfig.SYB.Password != " se cret " { t.Fatalf("密码不应被修改: %q", ExtConfig.SYB.Password) } } // 同上,yeeke 凭据也只能来自环境变量 (#336)。 func TestApplyEnvironmentLoadsYeekeCredentials(t *testing.T) { original := ExtConfig.Yeeke t.Cleanup(func() { ExtConfig.Yeeke = original }) t.Setenv("GOAUTO_YEEKE_USERNAME", " operator ") t.Setenv("GOAUTO_YEEKE_PASSWORD", " se cret ") ApplyEnvironment() if ExtConfig.Yeeke.Username != "operator" { t.Fatalf("账号应去掉首尾空白: %q", ExtConfig.Yeeke.Username) } if ExtConfig.Yeeke.Password != " se cret " { t.Fatalf("密码不应被修改: %q", ExtConfig.Yeeke.Password) } } func TestYeekeResolvedFillsBlanksButNeverInventsCredentials(t *testing.T) { resolved := Yeeke{}.Resolved() if resolved.BaseURL != DefaultYeekeBaseURL { t.Fatalf("BaseURL 默认值不对: %q", resolved.BaseURL) } if resolved.PageSize != DefaultYeekePageSize || resolved.MaxPages != DefaultYeekeMaxPages { t.Fatalf("分页默认值不对: %+v", resolved) } if resolved.OcrMaxAttempts != DefaultYeekeOcrMaxAttempts { t.Fatalf("OCR 重试次数默认值不对: %d", resolved.OcrMaxAttempts) } if resolved.Username != "" || resolved.Password != "" { t.Fatal("Resolved 不得给账号密码编造默认值") } if resolved.OcrURL != "" { t.Fatalf("空 OcrURL 不应被填充: %q", resolved.OcrURL) } } func TestYeekeHasCredentialsRequiresBothFields(t *testing.T) { for _, c := range []struct { name string yeeke Yeeke want bool }{ {"都有", Yeeke{Username: "a", Password: "b"}, true}, {"缺密码", Yeeke{Username: "a"}, false}, {"缺账号", Yeeke{Password: "b"}, false}, {"账号只有空白", Yeeke{Username: " ", Password: "b"}, false}, {"都没有", Yeeke{}, false}, } { if got := c.yeeke.HasCredentials(); got != c.want { t.Fatalf("%s: 期望 %v,实际 %v", c.name, c.want, got) } } } func TestSYBResolvedFillsBlanksButNeverInventsCredentials(t *testing.T) { resolved := SYB{}.Resolved() if resolved.BaseURL != DefaultSYBBaseURL { t.Fatalf("BaseURL 默认值不对: %q", resolved.BaseURL) } if resolved.PageSize != DefaultSYBPageSize || resolved.MaxMatches != DefaultSYBMaxMatches { t.Fatalf("分页默认值不对: %+v", resolved) } if resolved.OcrMaxAttempts != DefaultSYBOcrMaxAttempts { t.Fatalf("OCR 重试次数默认值不对: %d", resolved.OcrMaxAttempts) } if resolved.Username != "" || resolved.Password != "" { t.Fatal("Resolved 不得给账号密码编造默认值") } // ocr_url 留空是合法配置(降级到手工输入),不能被填上默认值。 if resolved.OcrURL != "" { t.Fatalf("空 OcrURL 不应被填充: %q", resolved.OcrURL) } } func TestSYBResolvedNormalisesBaseURLTrailingSlash(t *testing.T) { if got := (SYB{BaseURL: " https://example.com/ "}).Resolved().BaseURL; got != "https://example.com" { t.Fatalf("BaseURL 规范化不对: %q", got) } } func TestSYBHasCredentialsRequiresBothFields(t *testing.T) { for _, c := range []struct { name string syb SYB want bool }{ {"都有", SYB{Username: "a", Password: "b"}, true}, {"缺密码", SYB{Username: "a"}, false}, {"缺账号", SYB{Password: "b"}, false}, {"账号只有空白", SYB{Username: " ", Password: "b"}, false}, {"都没有", SYB{}, false}, } { if got := c.syb.HasCredentials(); got != c.want { t.Fatalf("%s: 期望 %v,实际 %v", c.name, c.want, got) } } }