test: comprehensive test coverage for 5 packages (#351)

* test(util): add comprehensive tests for atomic write functions

Add tests for:
- File permissions
- Empty data handling
- Various JSON types (string, int, float, bool, null, array, nested)
- Unmarshallable types error handling
- Read-only directory permission errors
- Concurrent writes
- Original content preservation on failure
- Struct serialization/deserialization
- Large data (1MB)

* test(connection): add edge case tests for address parsing

Add comprehensive test coverage for ParseAddress edge cases:
- Empty/whitespace/slash-only inputs
- Leading/trailing slash handling
- Machine prefix edge cases (colons, empty machine)
- Multiple slashes in polecat name (SplitN behavior)
- Unicode and emoji support
- Very long addresses
- Special characters (hyphens, underscores, dots)
- Whitespace in components

Also adds tests for MustParseAddress panic behavior and RigPath method.

Closes: gt-xgjyp

* test(checkpoint): add comprehensive test coverage for checkpoint package

Tests all public functions: Read, Write, Remove, Capture, WithMolecule,
WithHookedBead, WithNotes, Age, IsStale, Summary, Path.

Edge cases covered: missing file, corrupted JSON, stale detection.

Closes: gt-09yn1

* test(lock): add comprehensive tests for lock package

Add lock_test.go with tests covering:
- LockInfo.IsStale() with valid/invalid PIDs
- Lock.Acquire/Release lifecycle
- Re-acquiring own lock (session refresh)
- Stale lock cleanup during Acquire
- Lock.Read() for missing/invalid/valid files
- Lock.Check() for unlocked/owned/stale scenarios
- Lock.Status() string formatting
- Lock.ForceRelease()
- processExists() helper
- FindAllLocks() directory scanning
- CleanStaleLocks() with mocked tmux
- getActiveTmuxSessions() parsing
- splitOnColon() and splitLines() helpers
- DetectCollisions() for stale/orphaned locks

Coverage: 84.4%

* test(keepalive): add example tests demonstrating usage patterns

Add ExampleTouchInWorkspace, ExampleRead, and ExampleState_Age to
serve as documentation for how to use the keepalive package.

* fix(test): correct boundary test timing race in checkpoint_test.go

The 'exactly threshold' test case was flaky due to timing: by the time
time.Since() runs after setting Timestamp, microseconds have passed,
making age > threshold. Changed expectation to true since at-threshold
is effectively stale.

---------

Co-authored-by: slit <gt@gastown.local>
This commit is contained in:
Bo
2026-01-12 02:04:03 -05:00
committed by GitHub
parent 4bbf97ab82
commit 1f272ffc53
5 changed files with 1652 additions and 0 deletions

View File

@@ -76,3 +76,63 @@ func TestDirectoryCreation(t *testing.T) {
t.Error("expected .runtime directory to be created")
}
}
// Example functions demonstrate keepalive usage patterns.
func ExampleTouchInWorkspace() {
// TouchInWorkspace signals agent activity in a specific workspace.
// This is the core function - use it when you know the workspace root.
workspaceRoot := "/path/to/workspace"
// Signal that "gt status" was run
TouchInWorkspace(workspaceRoot, "gt status")
// Signal a command with arguments
TouchInWorkspace(workspaceRoot, "gt sling bd-abc123 ai-platform")
// All errors are silently ignored (best-effort design).
// This is intentional - keepalive failures should never break commands.
}
func ExampleRead() {
// Read retrieves the current keepalive state for a workspace.
// Returns nil if no keepalive file exists or it can't be read.
workspaceRoot := "/path/to/workspace"
state := Read(workspaceRoot)
if state == nil {
// No keepalive found - agent may not have run any commands yet
return
}
// Access the last command that was run
_ = state.LastCommand // e.g., "gt status"
// Access when the command was run
_ = state.Timestamp // time.Time in UTC
}
func ExampleState_Age() {
// Age() returns how long ago the keepalive was updated.
// This is useful for detecting idle or stuck agents.
workspaceRoot := "/path/to/workspace"
state := Read(workspaceRoot)
// Age() is nil-safe - returns ~1 year for nil state
age := state.Age()
// Check if agent was active recently (within 5 minutes)
if age < 5*time.Minute {
// Agent is active
_ = "active"
}
// Check if agent might be stuck (no activity for 30+ minutes)
if age > 30*time.Minute {
// Agent may need attention
_ = "possibly stuck"
}
}