Files
BlueArchiveToolkit/internal/api/config_toml_test.go
T

164 lines
4.6 KiB
Go

package api
import (
"os"
"path/filepath"
"runtime"
"strings"
"testing"
"time"
)
func writePrivateConfig(t *testing.T, dir, content string) {
t.Helper()
path := filepath.Join(dir, ConfigFileName)
if err := os.WriteFile(path, []byte(content), 0o600); err != nil {
t.Fatal(err)
}
}
func TestLoadConfigFromBinaryDirFirstLaunchCreatesExampleOnly(t *testing.T) {
dir := t.TempDir()
cfg := DefaultConfig()
if err := LoadConfigFromBinaryDir(dir, &cfg); err != nil {
t.Fatal(err)
}
if _, err := os.Stat(filepath.Join(dir, ConfigExampleName)); err != nil {
t.Fatalf("config.toml.example was not created: %v", err)
}
if _, err := os.Stat(filepath.Join(dir, ".env")); !os.IsNotExist(err) {
t.Fatalf("unexpected .env after first launch, err=%v", err)
}
if cfg.Listen != DefaultListen || cfg.RPCTimeout != 30*time.Second {
t.Fatalf("first launch changed defaults: %+v", cfg)
}
}
func TestCheckedInBatAPIConfigExampleMatchesRuntimeTemplate(t *testing.T) {
_, sourceFile, _, ok := runtime.Caller(0)
if !ok {
t.Fatal("runtime.Caller failed")
}
path := filepath.Join(filepath.Dir(sourceFile), "..", "..", "cmd", "bat-api", ConfigExampleName)
data, err := os.ReadFile(path)
if err != nil {
t.Fatal(err)
}
if string(data) != ConfigTOMLTemplate {
t.Fatal("cmd/bat-api/config.toml.example differs from runtime template")
}
}
func TestLoadConfigFromBinaryDirDoesNotReadDotEnv(t *testing.T) {
dir := t.TempDir()
if err := os.WriteFile(filepath.Join(dir, ".env"), []byte("BAT_API_LISTEN=':19999'\n"), 0o600); err != nil {
t.Fatal(err)
}
cfg := DefaultConfig()
if err := LoadConfigFromBinaryDir(dir, &cfg); err != nil {
t.Fatal(err)
}
if cfg.Listen != DefaultListen {
t.Fatalf("dotenv value was applied: %q", cfg.Listen)
}
if _, err := os.Stat(filepath.Join(dir, ConfigExampleName)); err != nil {
t.Fatalf("config.toml.example was not created: %v", err)
}
}
func TestLoadConfigFromBinaryDirAppliesAPISectionOnly(t *testing.T) {
dir := t.TempDir()
writePrivateConfig(t, dir, `
[runtime]
state_dir = '/rust-state'
this_key_belongs_to_rust = 'ignored-by-go'
[translation.worker]
provider = 'mock'
[api]
listen = '127.0.0.1:19080'
public_base_url = 'https://assets.example.test'
state_dir = '/api-state'
socket_path = '/api-state/bat.sock'
resource_root = '/srv/releases/current'
server_info_file = '/srv/server-info.json'
require_indexed = false
verify_size = false
rpc_timeout = '2s'
refresh_interval = '0s'
auth_token = 'secret'
auth_query_param = 'token'
auth_exempt_paths = ['/healthz', '/readyz']
trust_proxy_headers = true
access_log = true
rate_limit_rps = 12.5
rate_limit_burst = 30
max_resource_page_limit = 250
database_url = 'postgres://example'
database_password = 'db-secret'
redis_url = 'redis://example'
redis_password = 'redis-secret'
`)
cfg := DefaultConfig()
if err := LoadConfigFromBinaryDir(dir, &cfg); err != nil {
t.Fatal(err)
}
if cfg.Listen != "127.0.0.1:19080" ||
cfg.PublicBaseURL != "https://assets.example.test" ||
cfg.StateDir != "/api-state" ||
cfg.SocketPath != "/api-state/bat.sock" ||
cfg.ResourceRoot != "/srv/releases/current" ||
cfg.ServerInfoFile != "/srv/server-info.json" ||
cfg.RequireIndexed ||
cfg.VerifySize ||
cfg.RPCTimeout != 2*time.Second ||
cfg.RefreshInterval != 0 ||
cfg.AuthToken != "secret" ||
cfg.AuthQueryParam != "token" ||
cfg.TrustProxyHeaders != true ||
cfg.AccessLog != true ||
cfg.RateLimitRPS != 12.5 ||
cfg.RateLimitBurst != 30 ||
cfg.MaxResourcePageLimit != 250 ||
cfg.DatabaseURL != "postgres://example" ||
cfg.DatabasePassword != "db-secret" ||
cfg.RedisURL != "redis://example" ||
cfg.RedisPassword != "redis-secret" {
t.Fatalf("unexpected config: %+v", cfg)
}
if strings.Join(cfg.AuthExemptPaths, ",") != "/healthz,/readyz" {
t.Fatalf("auth exempt paths=%v", cfg.AuthExemptPaths)
}
}
func TestLoadConfigFromBinaryDirRejectsUnknownAPIKey(t *testing.T) {
dir := t.TempDir()
writePrivateConfig(t, dir, "[api]\nunknown_key = 'value'\n")
cfg := DefaultConfig()
err := LoadConfigFromBinaryDir(dir, &cfg)
if err == nil || !strings.Contains(err.Error(), "unsupported [api] key") {
t.Fatalf("unexpected error: %v", err)
}
}
func TestConfigPrecedenceEnvironmentOverConfig(t *testing.T) {
dir := t.TempDir()
writePrivateConfig(t, dir, "[api]\nlisten = ':19080'\nauth_token = 'config-token'\n")
t.Setenv("BAT_API_LISTEN", ":19081")
t.Setenv("BAT_API_AUTH_TOKEN", "env-token")
cfg := DefaultConfig()
if err := LoadConfigFromBinaryDir(dir, &cfg); err != nil {
t.Fatal(err)
}
ApplyEnv(&cfg)
if cfg.Listen != ":19081" || cfg.AuthToken != "env-token" {
t.Fatalf("environment did not override config: %+v", cfg)
}
}