//go:build integration package main import ( "bytes" "context" "encoding/json" "net" "net/http" "os" "path/filepath" "testing" "time" ) func TestStartupShutdownPreservesConfiguration(t *testing.T) { address := os.Getenv("SAAS_MOCK_TEST_BROKER_URL") if address == "" { t.Skip("requires isolated test broker") } dir, id := fixture(t) reserve, err := net.Listen("tcp", "127.0.0.1:0") if err != nil { t.Fatal(err) } listen := reserve.Addr().String() reserve.Close() config := startupConfig{Listen: listen, DispatcherID: id, DispatcherSecret: "test-secret", BrokerURL: address, Snapshots: ".", Feedback: filepath.Join(t.TempDir(), "feedback")} raw, _ := json.Marshal(config) path := filepath.Join(dir, "server.json") if err = os.WriteFile(path, raw, 0600); err != nil { t.Fatal(err) } before := map[string][]byte{} if err = filepath.WalkDir(dir, func(p string, d os.DirEntry, e error) error { if e != nil { return e } if !d.IsDir() { before[p], e = os.ReadFile(p) } return e }); err != nil { t.Fatal(err) } ctx, cancel := context.WithCancel(context.Background()) defer cancel() done := make(chan error, 1) go func() { done <- run(ctx, path) }() ready := false deadline := time.Now().Add(5 * time.Second) client := &http.Client{Timeout: time.Second} for time.Now().Before(deadline) { req, _ := http.NewRequest("GET", "http://"+listen+"/internal/v1/dispatcher/sip", nil) req.Header.Set("X-DISPATCHER-id", id) req.Header.Set("X-DISPATCHER-SECRET-KEY", "test-secret") resp, e := client.Do(req) if e == nil { resp.Body.Close() if resp.StatusCode == 200 { ready = true break } } select { case e = <-done: t.Fatalf("startup failed: %v", e) default: } time.Sleep(10 * time.Millisecond) } if !ready { t.Fatal("server did not become ready") } cancel() select { case err = <-done: if err != nil { t.Fatal(err) } case <-time.After(5 * time.Second): t.Fatal("shutdown timed out") } for p, want := range before { got, e := os.ReadFile(p) if e != nil || !bytes.Equal(got, want) { t.Fatalf("configuration changed on exit: %s %v", p, e) } } files, err := os.ReadDir(config.Feedback) if err != nil || len(files) != 0 { t.Fatalf("startup produced unsolicited feedback: %v %v", files, err) } }