mirror of
https://github.com/Yuyi-Oak/BlueArchiveToolkit.git
synced 2026-09-19 12:06:40 +08:00
164 lines
4.6 KiB
Go
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)
|
|
}
|
|
}
|