Files
proxy/internal/app/storage_test.go
T

83 lines
2.3 KiB
Go

package app_test
import (
"io"
"os"
"path/filepath"
"strings"
"testing"
"proxyctl/internal/app"
"proxyctl/internal/profile"
)
func TestProfileConfigurationUsesIsolatedXDGPathOwnerOnlyAndAtomicReplacement(t *testing.T) {
xdg := t.TempDir()
t.Setenv("XDG_CONFIG_HOME", xdg)
path, err := profile.ConfigPath()
if err != nil {
t.Fatalf("resolve XDG configuration: %v", err)
}
wantPath := filepath.Join(xdg, "proxyctl", "profiles.json")
if path != wantPath {
t.Fatalf("configuration path = %q, want %q", path, wantPath)
}
application, err := app.New(profile.NewFileStore(path))
if err != nil {
t.Fatal(err)
}
created := application.Dispatch(app.Intent{Kind: app.CreateProfile, Profile: profile.Profile{
Name: "private", Mode: profile.SingleMode, SingleURL: "http://alice:secret@proxy.example:8080",
}})
if created.Err != nil {
t.Fatal(created.Err)
}
assertMode(t, filepath.Dir(path), 0o700)
assertMode(t, path, 0o600)
data, err := os.ReadFile(path)
if err != nil {
t.Fatal(err)
}
if !strings.Contains(string(data), "\n \"profiles\"") {
t.Fatalf("Profile configuration is not human-readable JSON:\n%s", data)
}
oldFile, err := os.Open(path)
if err != nil {
t.Fatal(err)
}
defer oldFile.Close()
updated := application.Dispatch(app.Intent{Kind: app.UpdateProfile, Name: "private", Profile: profile.Profile{
Name: "renamed", Mode: profile.SingleMode, SingleURL: "http://alice:new-secret@proxy.example:8080",
}})
if updated.Err != nil {
t.Fatal(updated.Err)
}
oldData, err := io.ReadAll(oldFile)
if err != nil {
t.Fatal(err)
}
newData, err := os.ReadFile(path)
if err != nil {
t.Fatal(err)
}
if !strings.Contains(string(oldData), `"name": "private"`) || !strings.Contains(string(newData), `"name": "renamed"`) {
t.Fatalf("configuration was not atomically replaced; old=%s new=%s", oldData, newData)
}
matches, err := filepath.Glob(filepath.Join(filepath.Dir(path), ".profiles-*"))
if err != nil || len(matches) != 0 {
t.Fatalf("temporary Profile files left behind: %v (%v)", matches, err)
}
}
func assertMode(t *testing.T, path string, want os.FileMode) {
t.Helper()
info, err := os.Stat(path)
if err != nil {
t.Fatal(err)
}
if got := info.Mode().Perm(); got != want {
t.Fatalf("mode for %s = %#o, want %#o", path, got, want)
}
}