fix: serialize persistent profile mutations
This commit is contained in:
@@ -5,6 +5,7 @@ import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"sync"
|
||||
"testing"
|
||||
|
||||
"proxyctl/internal/app"
|
||||
@@ -70,6 +71,64 @@ func TestProfileConfigurationUsesIsolatedXDGPathOwnerOnlyAndAtomicReplacement(t
|
||||
}
|
||||
}
|
||||
|
||||
func TestConcurrentApplicationsMutateLatestStateWithoutLostUpdates(t *testing.T) {
|
||||
path := filepath.Join(t.TempDir(), "proxyctl", "profiles.json")
|
||||
first, err := app.New(profile.NewFileStore(path))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
second, err := app.New(profile.NewFileStore(path))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
start := make(chan struct{})
|
||||
results := make(chan app.Result, 2)
|
||||
var workers sync.WaitGroup
|
||||
for application, name := range map[*app.Application]string{first: "home", second: "office"} {
|
||||
workers.Add(1)
|
||||
go func() {
|
||||
defer workers.Done()
|
||||
<-start
|
||||
results <- application.Dispatch(app.Intent{Kind: app.CreateProfile, Profile: profile.Profile{
|
||||
Name: name, Mode: profile.SingleMode, SingleURL: "http://proxy.example:8080",
|
||||
}})
|
||||
}()
|
||||
}
|
||||
close(start)
|
||||
workers.Wait()
|
||||
close(results)
|
||||
for result := range results {
|
||||
if result.Err != nil {
|
||||
t.Fatalf("concurrent mutation: %v", result.Err)
|
||||
}
|
||||
}
|
||||
|
||||
reloaded, err := app.New(profile.NewFileStore(path))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if got := len(reloaded.Snapshot().Profiles); got != 2 {
|
||||
t.Fatalf("persisted Profiles = %d, want both concurrent updates", got)
|
||||
}
|
||||
assertMode(t, path+".lock", 0o600)
|
||||
}
|
||||
|
||||
func TestLoadSecuresExistingSecretBearingConfiguration(t *testing.T) {
|
||||
path := filepath.Join(t.TempDir(), "proxyctl", "profiles.json")
|
||||
if err := os.MkdirAll(filepath.Dir(path), 0o700); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
contents := `{"profiles":[{"name":"private","mode":"single","singleUrl":"http://alice:secret@proxy.example:8080"}]}`
|
||||
if err := os.WriteFile(path, []byte(contents), 0o644); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if _, err := app.New(profile.NewFileStore(path)); err != nil {
|
||||
t.Fatalf("load existing configuration: %v", err)
|
||||
}
|
||||
assertMode(t, path, 0o600)
|
||||
}
|
||||
|
||||
func assertMode(t *testing.T, path string, want os.FileMode) {
|
||||
t.Helper()
|
||||
info, err := os.Stat(path)
|
||||
|
||||
Reference in New Issue
Block a user