优化结构
This commit is contained in:
@@ -0,0 +1,118 @@
|
||||
package config
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func writeConfig(t *testing.T, path, body string) {
|
||||
t.Helper()
|
||||
if err := os.WriteFile(path, []byte(body), 0o600); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestLoadDirectoryAndDurations(t *testing.T) {
|
||||
dir := t.TempDir()
|
||||
path := filepath.Join(dir, "config.yaml")
|
||||
writeConfig(t, path, "server:\n http:\n addr: :9000\n timeout: 600s\ndata:\n redis:\n read_timeout: 200ms\nadmin:\n jwt:\n expires_time: 168h\n media:\n session_ttl: 36\n")
|
||||
loaded, err := Load(dir)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if loaded.Server == nil || loaded.Server.HTTP == nil || loaded.Server.HTTP.Timeout != 10*time.Minute {
|
||||
t.Fatalf("server timeout = %#v", loaded.Server)
|
||||
}
|
||||
if loaded.Data == nil || loaded.Data.Redis == nil || loaded.Data.Redis.ReadTimeout != 200*time.Millisecond {
|
||||
t.Fatalf("redis timeout = %#v", loaded.Data)
|
||||
}
|
||||
if loaded.Admin == nil || loaded.Admin.JWT == nil || loaded.Admin.JWT.ExpiresTime != 7*24*time.Hour {
|
||||
t.Fatalf("jwt duration = %#v", loaded.Admin)
|
||||
}
|
||||
if loaded.Admin.ConfigPath != path {
|
||||
t.Fatalf("config path = %q, want %q", loaded.Admin.ConfigPath, path)
|
||||
}
|
||||
}
|
||||
|
||||
func TestLoadRejectsInvalidDuration(t *testing.T) {
|
||||
path := filepath.Join(t.TempDir(), "config.yaml")
|
||||
writeConfig(t, path, "server:\n http:\n timeout: definitely-not-a-duration\n")
|
||||
if _, err := Load(path); err == nil {
|
||||
t.Fatal("invalid duration was accepted")
|
||||
}
|
||||
}
|
||||
|
||||
func TestLoadEnvironmentOverride(t *testing.T) {
|
||||
path := filepath.Join(t.TempDir(), "config.yaml")
|
||||
writeConfig(t, path, "server:\n http:\n addr: :8000\n")
|
||||
t.Setenv("KRA_SERVER_HTTP_ADDR", ":9100")
|
||||
loaded, err := Load(path)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if loaded.Server == nil || loaded.Server.HTTP == nil || loaded.Server.HTTP.Addr != ":9100" {
|
||||
t.Fatalf("environment override = %#v", loaded.Server)
|
||||
}
|
||||
}
|
||||
|
||||
func TestStoreSnapshotIsolationAndSubscriptions(t *testing.T) {
|
||||
store := NewStore(&Config{Admin: &Admin{JWT: &JWT{SigningKey: "before"}}})
|
||||
var calls atomic.Int32
|
||||
stop := store.Subscribe(func(value *Config) {
|
||||
calls.Add(1)
|
||||
value.Admin.JWT.SigningKey = "callback-mutation"
|
||||
})
|
||||
store.Replace(&Config{Admin: &Admin{JWT: &JWT{SigningKey: "after"}}})
|
||||
stop()
|
||||
stop()
|
||||
value := store.Snapshot()
|
||||
if value == nil || value.Admin == nil || value.Admin.JWT == nil || value.Admin.JWT.SigningKey != "after" {
|
||||
t.Fatalf("snapshot was mutated by callback: %#v", value)
|
||||
}
|
||||
if calls.Load() != 1 {
|
||||
t.Fatalf("callback count = %d", calls.Load())
|
||||
}
|
||||
}
|
||||
|
||||
func TestStoreConcurrentReadersAndReplacements(t *testing.T) {
|
||||
store := NewStore(&Config{Data: &Data{Database: &Database{Name: "initial"}}})
|
||||
var wait sync.WaitGroup
|
||||
for i := 0; i < 8; i++ {
|
||||
wait.Add(1)
|
||||
go func() {
|
||||
defer wait.Done()
|
||||
for j := 0; j < 500; j++ {
|
||||
_ = store.Snapshot()
|
||||
}
|
||||
}()
|
||||
}
|
||||
for i := 0; i < 500; i++ {
|
||||
store.Replace(&Config{Data: &Data{Database: &Database{Name: "next"}}})
|
||||
}
|
||||
wait.Wait()
|
||||
}
|
||||
|
||||
func TestStoreWatchReloadAndClose(t *testing.T) {
|
||||
dir := t.TempDir()
|
||||
path := filepath.Join(dir, "config.yaml")
|
||||
writeConfig(t, path, "admin:\n app:\n app_id: first\n")
|
||||
store, err := LoadStore(path)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer store.Close()
|
||||
writeConfig(t, path, "admin:\n app:\n app_id: second\n")
|
||||
deadline := time.Now().Add(3 * time.Second)
|
||||
for time.Now().Before(deadline) {
|
||||
value := store.Snapshot()
|
||||
if value != nil && value.Admin != nil && value.Admin.App != nil && value.Admin.App.AppID == "second" {
|
||||
return
|
||||
}
|
||||
time.Sleep(20 * time.Millisecond)
|
||||
}
|
||||
t.Fatalf("watcher did not reload configuration: %#v", store.Snapshot())
|
||||
}
|
||||
Reference in New Issue
Block a user