feat(v0.5.3): AttachExisting passive reattach helper
This commit is contained in:
@@ -0,0 +1,29 @@
|
||||
package session
|
||||
|
||||
import (
|
||||
"github.com/warrenronsiek/ctask/internal/shell"
|
||||
)
|
||||
|
||||
// attacher is the test seam used by AttachExisting. Production code calls
|
||||
// shell.AttachSession directly; tests override this variable to capture
|
||||
// invocations or simulate failures. Do not run tests that override this
|
||||
// variable in parallel — it is a package global.
|
||||
var attacher = shell.AttachSession
|
||||
|
||||
// AttachExisting is the passive-reattach path. It is invoked when a tmux
|
||||
// session for the workspace already exists and the lease is fresh and local
|
||||
// (the original ctask owner is alive and heartbeating).
|
||||
//
|
||||
// AttachExisting performs no Preflight, writes no lease, captures no
|
||||
// manifest, starts no heartbeat, prints no banner, and runs no finalize.
|
||||
// It connects the user's terminal to the existing tmux session via
|
||||
// shell.AttachSession and returns when the user detaches or the session
|
||||
// ends. shell.AttachSession's contract handles failure-mode classification:
|
||||
// nil on clean exit, wrapped error on non-zero exit.
|
||||
//
|
||||
// If the session disappeared between the dispatcher's HasSession check
|
||||
// and this call, AttachSession returns an error and the user can retry —
|
||||
// the next invocation will hit the owner-create path.
|
||||
func AttachExisting(tmuxPath, name string) error {
|
||||
return attacher(tmuxPath, name)
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
package session
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"testing"
|
||||
)
|
||||
|
||||
// Tests in this file mutate the package-level `attacher` variable and must
|
||||
// not be run with t.Parallel().
|
||||
|
||||
func TestAttachExistingDelegatesToAttacher(t *testing.T) {
|
||||
called := 0
|
||||
orig := attacher
|
||||
attacher = func(tmuxPath, name string) error {
|
||||
called++
|
||||
if name != "ctask-test-abc" {
|
||||
t.Errorf("name: got %q", name)
|
||||
}
|
||||
if tmuxPath != "/usr/bin/tmux" {
|
||||
t.Errorf("tmuxPath: got %q", tmuxPath)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
t.Cleanup(func() { attacher = orig })
|
||||
|
||||
if err := AttachExisting("/usr/bin/tmux", "ctask-test-abc"); err != nil {
|
||||
t.Fatalf("AttachExisting: %v", err)
|
||||
}
|
||||
if called != 1 {
|
||||
t.Errorf("expected 1 call, got %d", called)
|
||||
}
|
||||
}
|
||||
|
||||
func TestAttachExistingPropagatesAttachError(t *testing.T) {
|
||||
want := errors.New("attach failed")
|
||||
orig := attacher
|
||||
attacher = func(_, _ string) error { return want }
|
||||
t.Cleanup(func() { attacher = orig })
|
||||
|
||||
if err := AttachExisting("/usr/bin/tmux", "ctask-x"); !errors.Is(err, want) {
|
||||
t.Errorf("expected %v, got %v", want, err)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user