cli + daemon: move test seams off package globals onto injected structs
CLI: introduce internal/cli.deps which owns every RPC/SSH/host-command seam the tree used to reach through mutable package vars. Command builders, orchestrators, and the completion helpers become methods on *deps. Tests construct their own deps per case, so fakes no longer leak across cases and tests are free to run in parallel. Daemon: move workspaceInspectRepoFunc + workspaceImportFunc onto the Daemon struct (workspaceInspectRepo / workspaceImport), mirroring the existing guestWaitForSSH / guestDial pattern. Workspace-prepare tests drop t.Parallel() guards now that they no longer mutate process-wide state. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
d38f580e00
commit
c42fcbe012
19 changed files with 664 additions and 733 deletions
|
|
@ -18,7 +18,7 @@ import (
|
|||
// ensureDaemon pings the socket; on miss it auto-starts bangerd, on
|
||||
// version mismatch it restarts. Every CLI command that needs to talk
|
||||
// to the daemon routes through here.
|
||||
func ensureDaemon(ctx context.Context) (paths.Layout, model.DaemonConfig, error) {
|
||||
func (d *deps) ensureDaemon(ctx context.Context) (paths.Layout, model.DaemonConfig, error) {
|
||||
layout, err := paths.Resolve()
|
||||
if err != nil {
|
||||
return paths.Layout{}, model.DaemonConfig{}, err
|
||||
|
|
@ -27,16 +27,16 @@ func ensureDaemon(ctx context.Context) (paths.Layout, model.DaemonConfig, error)
|
|||
if err != nil {
|
||||
return paths.Layout{}, model.DaemonConfig{}, err
|
||||
}
|
||||
if ping, err := daemonPingFunc(ctx, layout.SocketPath); err == nil {
|
||||
if daemonOutdated(ping.PID) {
|
||||
if err := restartDaemon(ctx, layout, ping.PID); err != nil {
|
||||
if ping, err := d.daemonPing(ctx, layout.SocketPath); err == nil {
|
||||
if d.daemonOutdated(ping.PID) {
|
||||
if err := d.restartDaemon(ctx, layout, ping.PID); err != nil {
|
||||
return paths.Layout{}, model.DaemonConfig{}, err
|
||||
}
|
||||
return layout, cfg, nil
|
||||
}
|
||||
return layout, cfg, nil
|
||||
}
|
||||
if err := startDaemon(ctx, layout); err != nil {
|
||||
if err := d.startDaemon(ctx, layout); err != nil {
|
||||
return paths.Layout{}, model.DaemonConfig{}, err
|
||||
}
|
||||
return layout, cfg, nil
|
||||
|
|
@ -47,11 +47,11 @@ func ensureDaemon(ctx context.Context) (paths.Layout, model.DaemonConfig, error)
|
|||
// session still holds a handle to an old daemon. os.SameFile compares
|
||||
// inode + dev, so a fresh binary at the same path registers as
|
||||
// different.
|
||||
func daemonOutdated(pid int) bool {
|
||||
func (d *deps) daemonOutdated(pid int) bool {
|
||||
if pid <= 0 {
|
||||
return false
|
||||
}
|
||||
daemonBin, err := bangerdPathFunc()
|
||||
daemonBin, err := d.bangerdPath()
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
|
|
@ -59,20 +59,20 @@ func daemonOutdated(pid int) bool {
|
|||
if err != nil {
|
||||
return false
|
||||
}
|
||||
runningInfo, err := os.Stat(daemonExePath(pid))
|
||||
runningInfo, err := os.Stat(d.daemonExePath(pid))
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
return !os.SameFile(currentInfo, runningInfo)
|
||||
}
|
||||
|
||||
func restartDaemon(ctx context.Context, layout paths.Layout, pid int) error {
|
||||
func (d *deps) restartDaemon(ctx context.Context, layout paths.Layout, pid int) error {
|
||||
stopCtx, cancel := context.WithTimeout(ctx, 2*time.Second)
|
||||
defer cancel()
|
||||
|
||||
_, _ = rpc.Call[api.ShutdownResult](stopCtx, layout.SocketPath, "shutdown", api.Empty{})
|
||||
if waitForPIDExit(pid, 2*time.Second) {
|
||||
return startDaemon(ctx, layout)
|
||||
return d.startDaemon(ctx, layout)
|
||||
}
|
||||
if proc, err := os.FindProcess(pid); err == nil {
|
||||
_ = proc.Signal(syscall.SIGTERM)
|
||||
|
|
@ -80,7 +80,7 @@ func restartDaemon(ctx context.Context, layout paths.Layout, pid int) error {
|
|||
if !waitForPIDExit(pid, 2*time.Second) {
|
||||
return fmt.Errorf("timed out restarting stale daemon pid %d", pid)
|
||||
}
|
||||
return startDaemon(ctx, layout)
|
||||
return d.startDaemon(ctx, layout)
|
||||
}
|
||||
|
||||
func waitForPIDExit(pid int, timeout time.Duration) bool {
|
||||
|
|
@ -105,7 +105,7 @@ func pidRunning(pid int) bool {
|
|||
return proc.Signal(syscall.Signal(0)) == nil
|
||||
}
|
||||
|
||||
func startDaemon(ctx context.Context, layout paths.Layout) error {
|
||||
func (d *deps) startDaemon(ctx context.Context, layout paths.Layout) error {
|
||||
if err := paths.Ensure(layout); err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue