package backend import ( "context" serverconfig "cursor/internal/backend/server/config" "cursor/internal/certs" "errors" "net" "net/http" "path/filepath" "testing" "time" ) func freeAddress(t *testing.T) string { t.Helper() l, err := net.Listen("tcp", "127.0.0.1:0") if err != nil { t.Fatal(err) } addr := l.Addr().String() l.Close() return addr } func TestHTTPSBindFailureRollsBackHTTPListener(t *testing.T) { occupied, err := net.Listen("tcp", "127.0.0.1:0") if err != nil { t.Fatal(err) } defer occupied.Close() cfg := serverconfig.DefaultConfig() cfg.BackendListenAddr = freeAddress(t) cfg.CLIHTTPSListenAddr = occupied.Addr().String() store := serverconfig.NewStore(filepath.Join(t.TempDir(), "config.yaml"), "") if _, err = store.Save(nil, cfg); err != nil { t.Fatal(err) } ca, err := certs.LoadOrCreateLocalCA(t.TempDir()) if err != nil { t.Fatal(err) } host, err := NewHost(store, ca) if err != nil { t.Fatal(err) } if err = host.Start(); err == nil { t.Fatal("HTTPS bind failure ignored") } if host.IsRunning() { t.Fatal("partial service reported running") } listener, err := net.Listen("tcp", cfg.BackendListenAddr) if err != nil { t.Fatal("HTTP listener leaked", err) } listener.Close() } func TestShutdownTimeoutForceClosesConnectionAndReleasesPort(t *testing.T) { listener, err := net.Listen("tcp", "127.0.0.1:0") if err != nil { t.Fatal(err) } address := listener.Addr().String() started := make(chan struct{}) ended := make(chan struct{}) server := &http.Server{Handler: http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { close(started); <-r.Context().Done(); close(ended) })} go server.Serve(listener) host := &Host{httpServer: server} requestDone := make(chan struct{}) go func() { defer close(requestDone) client := &http.Client{Timeout: time.Second} resp, _ := client.Get("http://" + address) if resp != nil { resp.Body.Close() } }() select { case <-started: case <-time.After(2 * time.Second): t.Fatal("request not started") } ctx, cancel := context.WithTimeout(context.Background(), 10*time.Millisecond) defer cancel() err = host.Stop(ctx) if !errors.Is(err, context.DeadlineExceeded) { t.Fatalf("expected timeout, got %v", err) } select { case <-ended: case <-time.After(time.Second): t.Fatal("handler still active") } <-requestDone if host.IsRunning() { t.Fatal("closed service still running") } rebound, err := net.Listen("tcp", address) if err != nil { t.Fatal("port not released", err) } rebound.Close() }