84 lines
2.0 KiB
Go
84 lines
2.0 KiB
Go
|
|
package config
|
||
|
|
|
||
|
|
import (
|
||
|
|
"context"
|
||
|
|
"errors"
|
||
|
|
"os"
|
||
|
|
"path/filepath"
|
||
|
|
"strings"
|
||
|
|
"sync"
|
||
|
|
"testing"
|
||
|
|
)
|
||
|
|
|
||
|
|
func TestConfigCASAndMetadataIsolation(t *testing.T) {
|
||
|
|
store := NewStore(filepath.Join(t.TempDir(), "config.yaml"), "")
|
||
|
|
m, err := NewManager(context.Background(), store)
|
||
|
|
if err != nil {
|
||
|
|
t.Fatal(err)
|
||
|
|
}
|
||
|
|
a, _ := m.Load(nil)
|
||
|
|
b, _ := m.Load(nil)
|
||
|
|
if a.Revision == "" {
|
||
|
|
t.Fatal("missing revision")
|
||
|
|
}
|
||
|
|
if err = m.SaveLastAgentModelHash(nil, "model-new"); err != nil {
|
||
|
|
t.Fatal(err)
|
||
|
|
}
|
||
|
|
a.CLIHTTPSListenAddr = "127.0.0.1:39099"
|
||
|
|
first, err := m.Save(nil, a)
|
||
|
|
if err != nil {
|
||
|
|
t.Fatal(err)
|
||
|
|
}
|
||
|
|
if first.LastAgentModelHash != "model-new" {
|
||
|
|
t.Fatal("UI overwrote backend metadata")
|
||
|
|
}
|
||
|
|
b.HomeMetrics.RefreshIntervalSeconds = 11
|
||
|
|
if _, err = m.Save(nil, b); !errors.Is(err, ErrConfigConflict) {
|
||
|
|
t.Fatalf("stale save accepted: %v", err)
|
||
|
|
}
|
||
|
|
current, _ := m.Load(nil)
|
||
|
|
if current.CLIHTTPSListenAddr != "127.0.0.1:39099" {
|
||
|
|
t.Fatal("CLI port lost")
|
||
|
|
}
|
||
|
|
data, _ := os.ReadFile(store.Path())
|
||
|
|
if strings.Contains(string(data), "revision:") {
|
||
|
|
t.Fatal("revision persisted in YAML")
|
||
|
|
}
|
||
|
|
if current.Revision == a.Revision {
|
||
|
|
t.Fatal("revision did not change")
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
func TestConcurrentSavesHaveExactlyOneWinner(t *testing.T) {
|
||
|
|
store := NewStore(filepath.Join(t.TempDir(), "config.yaml"), "")
|
||
|
|
m, err := NewManager(context.Background(), store)
|
||
|
|
if err != nil {
|
||
|
|
t.Fatal(err)
|
||
|
|
}
|
||
|
|
a, _ := m.Load(nil)
|
||
|
|
b := cloneConfig(a)
|
||
|
|
a.HomeMetrics.RefreshIntervalSeconds = 11
|
||
|
|
b.HomeMetrics.RefreshIntervalSeconds = 12
|
||
|
|
var wg sync.WaitGroup
|
||
|
|
results := make(chan error, 2)
|
||
|
|
for _, cfg := range []Config{a, b} {
|
||
|
|
wg.Add(1)
|
||
|
|
go func(c Config) { defer wg.Done(); _, err := m.Save(nil, c); results <- err }(cfg)
|
||
|
|
}
|
||
|
|
wg.Wait()
|
||
|
|
close(results)
|
||
|
|
success, conflict := 0, 0
|
||
|
|
for err := range results {
|
||
|
|
if err == nil {
|
||
|
|
success++
|
||
|
|
} else if errors.Is(err, ErrConfigConflict) {
|
||
|
|
conflict++
|
||
|
|
} else {
|
||
|
|
t.Fatal(err)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
if success != 1 || conflict != 1 {
|
||
|
|
t.Fatalf("success=%d conflict=%d", success, conflict)
|
||
|
|
}
|
||
|
|
}
|