package hostnginx import ( "context" "errors" "os" "path/filepath" "slices" "testing" ) func TestControllerSwitchesAndReloadsExactService(t *testing.T) { configPath := writeNginxConfig(t, serverConfiguration) runner := &recordingRunner{} controller, err := newController(configPath, "/usr/sbin/nginx", "/bin/systemctl", "nginx.service", runner) if err != nil { t.Fatalf("create host Nginx controller: %v", err) } previous, err := controller.Switch(context.Background(), 8080) if err != nil { t.Fatalf("switch host Nginx backend: %v", err) } if previous.ActivePort != 8081 { t.Fatalf("unexpected previous port: %d", previous.ActivePort) } current, err := controller.Read() if err != nil || current.ActivePort != 8080 { t.Fatalf("unexpected current host Nginx configuration: snapshot=%+v err=%v", current, err) } wantCalls := [][]string{ {"/usr/sbin/nginx", "-t"}, {"/bin/systemctl", "reload", "--", "nginx.service"}, } if !slices.EqualFunc(runner.calls, wantCalls, slices.Equal) { t.Fatalf("unexpected host Nginx commands: %+v", runner.calls) } } func TestControllerRestoresConfigurationWhenValidationFails(t *testing.T) { configPath := writeNginxConfig(t, serverConfiguration) runner := &recordingRunner{errors: []error{errors.New("nginx test failed"), nil, nil}} controller, err := newController(configPath, "/usr/sbin/nginx", "/bin/systemctl", "nginx.service", runner) if err != nil { t.Fatalf("create host Nginx controller: %v", err) } if _, err := controller.Switch(context.Background(), 8080); err == nil { t.Fatal("expected host Nginx validation failure") } current, err := controller.Read() if err != nil || current.ActivePort != 8081 || string(current.Content) != serverConfiguration { t.Fatalf("host Nginx configuration was not restored: snapshot=%+v err=%v", current, err) } if len(runner.calls) != 3 { t.Fatalf("unexpected validation compensation calls: %+v", runner.calls) } } func TestControllerRestoreUsesCompleteSnapshot(t *testing.T) { configPath := writeNginxConfig(t, serverConfiguration) runner := &recordingRunner{} controller, err := newController(configPath, "/usr/sbin/nginx", "/bin/systemctl", "nginx.service", runner) if err != nil { t.Fatalf("create host Nginx controller: %v", err) } previous, err := controller.Switch(context.Background(), 8080) if err != nil { t.Fatalf("switch host Nginx backend: %v", err) } if err := controller.Restore(context.Background(), previous); err != nil { t.Fatalf("restore host Nginx backend: %v", err) } current, err := controller.Read() if err != nil || current.ActivePort != 8081 || string(current.Content) != serverConfiguration { t.Fatalf("unexpected restored configuration: snapshot=%+v err=%v", current, err) } } func writeNginxConfig(t *testing.T, content string) string { t.Helper() path := filepath.Join(t.TempDir(), "nginx.conf") if err := os.WriteFile(path, []byte(content), 0o640); err != nil { t.Fatalf("write host Nginx configuration: %v", err) } return path } type recordingRunner struct { calls [][]string errors []error } func (r *recordingRunner) Run(_ context.Context, executable string, arguments ...string) error { call := append([]string{executable}, arguments...) r.calls = append(r.calls, call) if len(r.errors) == 0 { return nil } err := r.errors[0] r.errors = r.errors[1:] return err }