2026-03-21 15:05:40 +00:00
|
|
|
// SPDX-License-Identifier: EUPL-1.2
|
|
|
|
|
|
|
|
|
|
package agentic
|
|
|
|
|
|
|
|
|
|
import (
|
test: batch 1 — add 80 Bad/Ugly tests for paths, plan, status, shutdown, forge cmds
Fill missing Good/Bad/Ugly categories for:
- paths.go: LocalFs, WorkspaceRoot, CoreRoot, PlansRoot, AgentName, GitHubOrg, parseInt, DefaultBranch
- plan.go: planCreate/Read/Update/Delete/List Ugly, planPath Ugly, validPlanStatus Ugly
- status.go: writeStatus Bad, status Good/Bad
- shutdown.go: dispatchStart/shutdownGraceful Bad/Ugly, shutdownNow Ugly
- commands_forge.go: all 9 cmd* functions Ugly (with httptest mocks)
- sanitise.go: Bad/Ugly for all 5 functions
- prep.go: various lifecycle Bad/Ugly
Gap: 260 → 208 missing categories
Tests: 566 → 646 (+80)
Coverage: 74.4%
Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-25 08:43:35 +00:00
|
|
|
"context"
|
2026-03-21 15:05:40 +00:00
|
|
|
"testing"
|
|
|
|
|
"time"
|
test: batch 1 — add 80 Bad/Ugly tests for paths, plan, status, shutdown, forge cmds
Fill missing Good/Bad/Ugly categories for:
- paths.go: LocalFs, WorkspaceRoot, CoreRoot, PlansRoot, AgentName, GitHubOrg, parseInt, DefaultBranch
- plan.go: planCreate/Read/Update/Delete/List Ugly, planPath Ugly, validPlanStatus Ugly
- status.go: writeStatus Bad, status Good/Bad
- shutdown.go: dispatchStart/shutdownGraceful Bad/Ugly, shutdownNow Ugly
- commands_forge.go: all 9 cmd* functions Ugly (with httptest mocks)
- sanitise.go: Bad/Ugly for all 5 functions
- prep.go: various lifecycle Bad/Ugly
Gap: 260 → 208 missing categories
Tests: 566 → 646 (+80)
Coverage: 74.4%
Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-25 08:43:35 +00:00
|
|
|
|
feat(v0.8.0): full AX migration — ServiceRuntime, Actions, quality gates, transport
go-process:
- Register factory, Result lifecycle, 5 named Action handlers
- Start/Run/StartWithOptions/RunWithOptions all return core.Result
- core.ID() replaces fmt.Sprintf, core.As replaces errors.As
core/agent:
- PrepSubsystem + monitor.Subsystem + setup.Service embed ServiceRuntime[T]
- 22 named Actions + agent.completion Task pipeline in OnStartup
- ChannelNotifier removed — all IPC via c.ACTION(messages.X{})
- proc.go: all methods via s.Core().Process(), returns core.Result
- status.go: WriteAtomic + JSONMarshalString
- paths.go: Fs.NewUnrestricted() replaces unsafe.Pointer
- transport.go: ONE net/http file — HTTPGet/HTTPPost/HTTPDo/MCP transport
- All disallowed imports eliminated from source files (13 quality gates)
- String concat eliminated — core.Concat() throughout
- 1:1 _test.go + _example_test.go for every source file
- Reference docs synced from core/go v0.8.0
- RFC-025 updated with net/http, net/url, io/fs quality gates
- lib.go: io/fs eliminated via Data.ListNames, Array[T].Deduplicate
Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-26 01:27:46 +00:00
|
|
|
core "dappco.re/go/core"
|
test: batch 1 — add 80 Bad/Ugly tests for paths, plan, status, shutdown, forge cmds
Fill missing Good/Bad/Ugly categories for:
- paths.go: LocalFs, WorkspaceRoot, CoreRoot, PlansRoot, AgentName, GitHubOrg, parseInt, DefaultBranch
- plan.go: planCreate/Read/Update/Delete/List Ugly, planPath Ugly, validPlanStatus Ugly
- status.go: writeStatus Bad, status Good/Bad
- shutdown.go: dispatchStart/shutdownGraceful Bad/Ugly, shutdownNow Ugly
- commands_forge.go: all 9 cmd* functions Ugly (with httptest mocks)
- sanitise.go: Bad/Ugly for all 5 functions
- prep.go: various lifecycle Bad/Ugly
Gap: 260 → 208 missing categories
Tests: 566 → 646 (+80)
Coverage: 74.4%
Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-25 08:43:35 +00:00
|
|
|
"github.com/stretchr/testify/assert"
|
|
|
|
|
"github.com/stretchr/testify/require"
|
2026-03-21 15:05:40 +00:00
|
|
|
)
|
|
|
|
|
|
2026-03-30 20:20:50 +00:00
|
|
|
func mustReadStatus(t *testing.T, dir string) *WorkspaceStatus {
|
|
|
|
|
t.Helper()
|
|
|
|
|
|
|
|
|
|
result := ReadStatusResult(dir)
|
|
|
|
|
require.True(t, result.OK)
|
|
|
|
|
|
|
|
|
|
status, ok := workspaceStatusValue(result)
|
|
|
|
|
require.True(t, ok)
|
|
|
|
|
return status
|
|
|
|
|
}
|
|
|
|
|
|
2026-03-25 08:32:08 +00:00
|
|
|
func TestStatus_WriteStatus_Good(t *testing.T) {
|
2026-03-21 15:05:40 +00:00
|
|
|
dir := t.TempDir()
|
|
|
|
|
status := &WorkspaceStatus{
|
|
|
|
|
Status: "running",
|
|
|
|
|
Agent: "gemini",
|
|
|
|
|
Repo: "go-io",
|
|
|
|
|
Task: "fix tests",
|
|
|
|
|
PID: 12345,
|
|
|
|
|
StartedAt: time.Now(),
|
|
|
|
|
Runs: 1,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
err := writeStatus(dir, status)
|
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
2026-03-22 03:41:07 +00:00
|
|
|
// Verify file was written via core.Fs
|
2026-03-26 01:39:41 +00:00
|
|
|
r := fs.Read(core.JoinPath(dir, "status.json"))
|
2026-03-22 03:41:07 +00:00
|
|
|
require.True(t, r.OK)
|
2026-03-21 15:05:40 +00:00
|
|
|
|
|
|
|
|
var read WorkspaceStatus
|
2026-03-26 01:58:36 +00:00
|
|
|
ur := core.JSONUnmarshalString(r.Value.(string), &read)
|
|
|
|
|
require.True(t, ur.OK)
|
2026-03-21 15:05:40 +00:00
|
|
|
|
|
|
|
|
assert.Equal(t, "running", read.Status)
|
|
|
|
|
assert.Equal(t, "gemini", read.Agent)
|
|
|
|
|
assert.Equal(t, "go-io", read.Repo)
|
|
|
|
|
assert.Equal(t, "fix tests", read.Task)
|
|
|
|
|
assert.Equal(t, 12345, read.PID)
|
|
|
|
|
assert.Equal(t, 1, read.Runs)
|
|
|
|
|
assert.False(t, read.UpdatedAt.IsZero(), "UpdatedAt should be set by writeStatus")
|
|
|
|
|
}
|
|
|
|
|
|
2026-03-25 08:32:08 +00:00
|
|
|
func TestStatus_WriteStatus_Good_UpdatesTimestamp(t *testing.T) {
|
2026-03-21 15:05:40 +00:00
|
|
|
dir := t.TempDir()
|
|
|
|
|
before := time.Now().Add(-time.Second)
|
|
|
|
|
|
|
|
|
|
status := &WorkspaceStatus{
|
|
|
|
|
Status: "running",
|
|
|
|
|
Agent: "claude",
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
err := writeStatus(dir, status)
|
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
|
|
assert.True(t, status.UpdatedAt.After(before), "UpdatedAt should be after the start time")
|
|
|
|
|
}
|
|
|
|
|
|
2026-03-25 08:32:08 +00:00
|
|
|
func TestStatus_ReadStatus_Good(t *testing.T) {
|
2026-03-21 15:05:40 +00:00
|
|
|
dir := t.TempDir()
|
|
|
|
|
|
|
|
|
|
status := &WorkspaceStatus{
|
|
|
|
|
Status: "completed",
|
|
|
|
|
Agent: "codex",
|
|
|
|
|
Repo: "go-log",
|
|
|
|
|
Task: "add logging",
|
|
|
|
|
Branch: "agent/add-logging",
|
|
|
|
|
StartedAt: time.Now().Truncate(time.Second),
|
|
|
|
|
UpdatedAt: time.Now().Truncate(time.Second),
|
|
|
|
|
Runs: 2,
|
|
|
|
|
PRURL: "https://forge.lthn.ai/core/go-log/pulls/5",
|
|
|
|
|
}
|
|
|
|
|
|
2026-03-26 01:58:36 +00:00
|
|
|
require.True(t, fs.Write(core.JoinPath(dir, "status.json"), core.JSONMarshalString(status)).OK)
|
2026-03-21 15:05:40 +00:00
|
|
|
|
2026-03-30 20:20:50 +00:00
|
|
|
read := mustReadStatus(t, dir)
|
2026-03-21 15:05:40 +00:00
|
|
|
|
|
|
|
|
assert.Equal(t, "completed", read.Status)
|
|
|
|
|
assert.Equal(t, "codex", read.Agent)
|
|
|
|
|
assert.Equal(t, "go-log", read.Repo)
|
|
|
|
|
assert.Equal(t, "add logging", read.Task)
|
|
|
|
|
assert.Equal(t, "agent/add-logging", read.Branch)
|
|
|
|
|
assert.Equal(t, 2, read.Runs)
|
|
|
|
|
assert.Equal(t, "https://forge.lthn.ai/core/go-log/pulls/5", read.PRURL)
|
|
|
|
|
}
|
|
|
|
|
|
2026-03-30 16:24:06 +00:00
|
|
|
func TestStatus_ReadStatusResult_Good(t *testing.T) {
|
|
|
|
|
dir := t.TempDir()
|
|
|
|
|
|
|
|
|
|
status := &WorkspaceStatus{
|
|
|
|
|
Status: "completed",
|
|
|
|
|
Agent: "codex",
|
|
|
|
|
Repo: "go-log",
|
|
|
|
|
Task: "add logging",
|
|
|
|
|
Branch: "agent/add-logging",
|
|
|
|
|
StartedAt: time.Now().Truncate(time.Second),
|
|
|
|
|
UpdatedAt: time.Now().Truncate(time.Second),
|
|
|
|
|
Runs: 2,
|
|
|
|
|
PRURL: "https://forge.lthn.ai/core/go-log/pulls/5",
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
require.True(t, fs.Write(core.JoinPath(dir, "status.json"), core.JSONMarshalString(status)).OK)
|
|
|
|
|
|
|
|
|
|
result := ReadStatusResult(dir)
|
|
|
|
|
require.True(t, result.OK)
|
|
|
|
|
|
|
|
|
|
read, ok := result.Value.(*WorkspaceStatus)
|
|
|
|
|
require.True(t, ok)
|
|
|
|
|
assert.Equal(t, "completed", read.Status)
|
|
|
|
|
assert.Equal(t, "codex", read.Agent)
|
|
|
|
|
assert.Equal(t, "go-log", read.Repo)
|
|
|
|
|
assert.Equal(t, "add logging", read.Task)
|
|
|
|
|
assert.Equal(t, "agent/add-logging", read.Branch)
|
|
|
|
|
assert.Equal(t, 2, read.Runs)
|
|
|
|
|
assert.Equal(t, "https://forge.lthn.ai/core/go-log/pulls/5", read.PRURL)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func TestStatus_ReadStatusResult_Bad_NoFile(t *testing.T) {
|
|
|
|
|
result := ReadStatusResult(t.TempDir())
|
|
|
|
|
assert.False(t, result.OK)
|
|
|
|
|
err, ok := result.Value.(error)
|
|
|
|
|
require.True(t, ok)
|
|
|
|
|
assert.Error(t, err)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func TestStatus_ReadStatusResult_Ugly_InvalidJSON(t *testing.T) {
|
|
|
|
|
dir := t.TempDir()
|
|
|
|
|
require.True(t, fs.Write(core.JoinPath(dir, "status.json"), "{not-json").OK)
|
|
|
|
|
|
|
|
|
|
result := ReadStatusResult(dir)
|
|
|
|
|
assert.False(t, result.OK)
|
|
|
|
|
err, ok := result.Value.(error)
|
|
|
|
|
require.True(t, ok)
|
|
|
|
|
assert.Error(t, err)
|
|
|
|
|
}
|
|
|
|
|
|
2026-03-25 08:32:08 +00:00
|
|
|
func TestStatus_ReadStatus_Bad_NoFile(t *testing.T) {
|
2026-03-21 15:05:40 +00:00
|
|
|
dir := t.TempDir()
|
2026-03-30 20:20:50 +00:00
|
|
|
result := ReadStatusResult(dir)
|
|
|
|
|
assert.False(t, result.OK)
|
|
|
|
|
_, ok := result.Value.(error)
|
|
|
|
|
assert.True(t, ok)
|
2026-03-21 15:05:40 +00:00
|
|
|
}
|
|
|
|
|
|
2026-03-25 08:32:08 +00:00
|
|
|
func TestStatus_ReadStatus_Bad_InvalidJSON(t *testing.T) {
|
2026-03-21 15:05:40 +00:00
|
|
|
dir := t.TempDir()
|
2026-03-26 01:39:41 +00:00
|
|
|
require.True(t, fs.Write(core.JoinPath(dir, "status.json"), "not json{").OK)
|
2026-03-21 15:05:40 +00:00
|
|
|
|
2026-03-30 20:20:50 +00:00
|
|
|
result := ReadStatusResult(dir)
|
|
|
|
|
assert.False(t, result.OK)
|
|
|
|
|
_, ok := result.Value.(error)
|
|
|
|
|
assert.True(t, ok)
|
2026-03-21 15:05:40 +00:00
|
|
|
}
|
|
|
|
|
|
2026-03-25 08:32:08 +00:00
|
|
|
func TestStatus_ReadStatus_Good_BlockedWithQuestion(t *testing.T) {
|
2026-03-21 15:05:40 +00:00
|
|
|
dir := t.TempDir()
|
|
|
|
|
|
|
|
|
|
status := &WorkspaceStatus{
|
|
|
|
|
Status: "blocked",
|
|
|
|
|
Agent: "gemini",
|
|
|
|
|
Repo: "go-io",
|
|
|
|
|
Question: "Which interface should I implement?",
|
|
|
|
|
}
|
|
|
|
|
|
2026-03-26 01:58:36 +00:00
|
|
|
require.True(t, fs.Write(core.JoinPath(dir, "status.json"), core.JSONMarshalString(status)).OK)
|
2026-03-21 15:05:40 +00:00
|
|
|
|
2026-03-30 20:20:50 +00:00
|
|
|
read := mustReadStatus(t, dir)
|
2026-03-21 15:05:40 +00:00
|
|
|
|
|
|
|
|
assert.Equal(t, "blocked", read.Status)
|
|
|
|
|
assert.Equal(t, "Which interface should I implement?", read.Question)
|
|
|
|
|
}
|
|
|
|
|
|
2026-04-01 13:20:05 +00:00
|
|
|
func TestStatus_ReadStatus_Good_Wrapper(t *testing.T) {
|
|
|
|
|
dir := t.TempDir()
|
|
|
|
|
|
|
|
|
|
status := &WorkspaceStatus{
|
|
|
|
|
Status: "completed",
|
|
|
|
|
Agent: "codex",
|
|
|
|
|
Repo: "go-io",
|
|
|
|
|
Task: "add logging",
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
require.True(t, fs.Write(core.JoinPath(dir, "status.json"), core.JSONMarshalString(status)).OK)
|
|
|
|
|
|
|
|
|
|
read, err := ReadStatus(dir)
|
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
require.NotNil(t, read)
|
|
|
|
|
assert.Equal(t, "completed", read.Status)
|
|
|
|
|
assert.Equal(t, "go-io", read.Repo)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func TestStatus_ReadStatus_Bad_NoFile_Wrapper(t *testing.T) {
|
|
|
|
|
read, err := ReadStatus(t.TempDir())
|
|
|
|
|
assert.Nil(t, read)
|
|
|
|
|
require.Error(t, err)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func TestStatus_ReadStatus_Ugly_InvalidJSON_Wrapper(t *testing.T) {
|
|
|
|
|
dir := t.TempDir()
|
|
|
|
|
require.True(t, fs.Write(core.JoinPath(dir, "status.json"), "not json{").OK)
|
|
|
|
|
|
|
|
|
|
read, err := ReadStatus(dir)
|
|
|
|
|
assert.Nil(t, read)
|
|
|
|
|
require.Error(t, err)
|
|
|
|
|
}
|
|
|
|
|
|
2026-03-26 06:38:02 +00:00
|
|
|
func TestStatus_WriteRead_Good_Roundtrip(t *testing.T) {
|
2026-03-21 15:05:40 +00:00
|
|
|
dir := t.TempDir()
|
|
|
|
|
|
|
|
|
|
original := &WorkspaceStatus{
|
|
|
|
|
Status: "running",
|
|
|
|
|
Agent: "claude:opus",
|
|
|
|
|
Repo: "agent",
|
|
|
|
|
Org: "core",
|
|
|
|
|
Task: "write tests for agentic package",
|
|
|
|
|
Branch: "agent/write-tests",
|
|
|
|
|
Issue: 42,
|
|
|
|
|
PID: 99999,
|
|
|
|
|
StartedAt: time.Now().Truncate(time.Second),
|
|
|
|
|
Runs: 3,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
err := writeStatus(dir, original)
|
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
2026-03-30 20:20:50 +00:00
|
|
|
read := mustReadStatus(t, dir)
|
2026-03-21 15:05:40 +00:00
|
|
|
|
|
|
|
|
assert.Equal(t, original.Status, read.Status)
|
|
|
|
|
assert.Equal(t, original.Agent, read.Agent)
|
|
|
|
|
assert.Equal(t, original.Repo, read.Repo)
|
|
|
|
|
assert.Equal(t, original.Org, read.Org)
|
|
|
|
|
assert.Equal(t, original.Task, read.Task)
|
|
|
|
|
assert.Equal(t, original.Branch, read.Branch)
|
|
|
|
|
assert.Equal(t, original.Issue, read.Issue)
|
|
|
|
|
assert.Equal(t, original.PID, read.PID)
|
|
|
|
|
assert.Equal(t, original.Runs, read.Runs)
|
|
|
|
|
}
|
|
|
|
|
|
2026-03-25 08:32:08 +00:00
|
|
|
func TestStatus_WriteStatus_Good_OverwriteExisting(t *testing.T) {
|
2026-03-21 15:05:40 +00:00
|
|
|
dir := t.TempDir()
|
|
|
|
|
|
|
|
|
|
first := &WorkspaceStatus{Status: "running", Agent: "gemini"}
|
|
|
|
|
err := writeStatus(dir, first)
|
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
|
|
second := &WorkspaceStatus{Status: "completed", Agent: "gemini"}
|
|
|
|
|
err = writeStatus(dir, second)
|
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
2026-03-30 20:20:50 +00:00
|
|
|
read := mustReadStatus(t, dir)
|
2026-03-21 15:05:40 +00:00
|
|
|
assert.Equal(t, "completed", read.Status)
|
|
|
|
|
}
|
|
|
|
|
|
2026-03-25 08:32:08 +00:00
|
|
|
func TestStatus_ReadStatus_Ugly_EmptyFile(t *testing.T) {
|
2026-03-21 15:05:40 +00:00
|
|
|
dir := t.TempDir()
|
2026-03-26 01:39:41 +00:00
|
|
|
require.True(t, fs.Write(core.JoinPath(dir, "status.json"), "").OK)
|
2026-03-21 15:05:40 +00:00
|
|
|
|
2026-03-30 20:20:50 +00:00
|
|
|
result := ReadStatusResult(dir)
|
|
|
|
|
assert.False(t, result.OK)
|
|
|
|
|
_, ok := result.Value.(error)
|
|
|
|
|
assert.True(t, ok)
|
2026-03-21 15:05:40 +00:00
|
|
|
}
|
test: add Good/Bad/Ugly for status, paths, auto_pr, prep — agentic 74.0%
New properly named tests:
- TestStatus_Status_Ugly — dead PID detection (blocked/completed/failed)
- TestPaths_DefaultBranch_{Good,Bad,Ugly} — main/master/non-git
- TestAutoPR_AutoCreatePR_{Good,Bad,Ugly} — early returns + no commits
- TestPrep_BuildPrompt_{Good,Bad,Ugly} — basic/empty/persona+issue
558 agentic tests, 74.0% coverage
Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-25 08:16:53 +00:00
|
|
|
|
|
|
|
|
// --- status() dead PID detection ---
|
|
|
|
|
|
|
|
|
|
func TestStatus_Status_Ugly(t *testing.T) {
|
|
|
|
|
root := t.TempDir()
|
|
|
|
|
t.Setenv("CORE_WORKSPACE", root)
|
2026-03-26 01:39:41 +00:00
|
|
|
wsRoot := core.JoinPath(root, "workspace")
|
test: add Good/Bad/Ugly for status, paths, auto_pr, prep — agentic 74.0%
New properly named tests:
- TestStatus_Status_Ugly — dead PID detection (blocked/completed/failed)
- TestPaths_DefaultBranch_{Good,Bad,Ugly} — main/master/non-git
- TestAutoPR_AutoCreatePR_{Good,Bad,Ugly} — early returns + no commits
- TestPrep_BuildPrompt_{Good,Bad,Ugly} — basic/empty/persona+issue
558 agentic tests, 74.0% coverage
Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-25 08:16:53 +00:00
|
|
|
|
|
|
|
|
// Case 1: running + dead PID + BLOCKED.md → should detect as blocked
|
2026-03-26 01:39:41 +00:00
|
|
|
ws1 := core.JoinPath(wsRoot, "dead-blocked")
|
|
|
|
|
require.True(t, fs.EnsureDir(core.JoinPath(ws1, "repo")).OK)
|
test: add Good/Bad/Ugly for status, paths, auto_pr, prep — agentic 74.0%
New properly named tests:
- TestStatus_Status_Ugly — dead PID detection (blocked/completed/failed)
- TestPaths_DefaultBranch_{Good,Bad,Ugly} — main/master/non-git
- TestAutoPR_AutoCreatePR_{Good,Bad,Ugly} — early returns + no commits
- TestPrep_BuildPrompt_{Good,Bad,Ugly} — basic/empty/persona+issue
558 agentic tests, 74.0% coverage
Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-25 08:16:53 +00:00
|
|
|
require.NoError(t, writeStatus(ws1, &WorkspaceStatus{
|
|
|
|
|
Status: "running",
|
|
|
|
|
Repo: "go-io",
|
|
|
|
|
Agent: "codex",
|
|
|
|
|
PID: 999999,
|
|
|
|
|
}))
|
2026-03-26 01:39:41 +00:00
|
|
|
require.True(t, fs.Write(core.JoinPath(ws1, "repo", "BLOCKED.md"), "Need API credentials").OK)
|
test: add Good/Bad/Ugly for status, paths, auto_pr, prep — agentic 74.0%
New properly named tests:
- TestStatus_Status_Ugly — dead PID detection (blocked/completed/failed)
- TestPaths_DefaultBranch_{Good,Bad,Ugly} — main/master/non-git
- TestAutoPR_AutoCreatePR_{Good,Bad,Ugly} — early returns + no commits
- TestPrep_BuildPrompt_{Good,Bad,Ugly} — basic/empty/persona+issue
558 agentic tests, 74.0% coverage
Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-25 08:16:53 +00:00
|
|
|
|
|
|
|
|
// Case 2: running + dead PID + agent log → completed
|
2026-03-26 01:39:41 +00:00
|
|
|
ws2 := core.JoinPath(wsRoot, "dead-completed")
|
|
|
|
|
require.True(t, fs.EnsureDir(core.JoinPath(ws2, "repo")).OK)
|
2026-03-29 20:15:58 +00:00
|
|
|
require.True(t, fs.EnsureDir(core.JoinPath(ws2, ".meta")).OK)
|
test: add Good/Bad/Ugly for status, paths, auto_pr, prep — agentic 74.0%
New properly named tests:
- TestStatus_Status_Ugly — dead PID detection (blocked/completed/failed)
- TestPaths_DefaultBranch_{Good,Bad,Ugly} — main/master/non-git
- TestAutoPR_AutoCreatePR_{Good,Bad,Ugly} — early returns + no commits
- TestPrep_BuildPrompt_{Good,Bad,Ugly} — basic/empty/persona+issue
558 agentic tests, 74.0% coverage
Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-25 08:16:53 +00:00
|
|
|
require.NoError(t, writeStatus(ws2, &WorkspaceStatus{
|
|
|
|
|
Status: "running",
|
|
|
|
|
Repo: "go-log",
|
|
|
|
|
Agent: "claude",
|
|
|
|
|
PID: 999999,
|
|
|
|
|
}))
|
2026-03-29 20:15:58 +00:00
|
|
|
require.True(t, fs.Write(core.JoinPath(ws2, ".meta", "agent-claude.log"), "agent finished ok").OK)
|
test: add Good/Bad/Ugly for status, paths, auto_pr, prep — agentic 74.0%
New properly named tests:
- TestStatus_Status_Ugly — dead PID detection (blocked/completed/failed)
- TestPaths_DefaultBranch_{Good,Bad,Ugly} — main/master/non-git
- TestAutoPR_AutoCreatePR_{Good,Bad,Ugly} — early returns + no commits
- TestPrep_BuildPrompt_{Good,Bad,Ugly} — basic/empty/persona+issue
558 agentic tests, 74.0% coverage
Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-25 08:16:53 +00:00
|
|
|
|
|
|
|
|
// Case 3: running + dead PID + no log + no BLOCKED.md → failed
|
2026-03-26 01:39:41 +00:00
|
|
|
ws3 := core.JoinPath(wsRoot, "dead-failed")
|
|
|
|
|
require.True(t, fs.EnsureDir(core.JoinPath(ws3, "repo")).OK)
|
test: add Good/Bad/Ugly for status, paths, auto_pr, prep — agentic 74.0%
New properly named tests:
- TestStatus_Status_Ugly — dead PID detection (blocked/completed/failed)
- TestPaths_DefaultBranch_{Good,Bad,Ugly} — main/master/non-git
- TestAutoPR_AutoCreatePR_{Good,Bad,Ugly} — early returns + no commits
- TestPrep_BuildPrompt_{Good,Bad,Ugly} — basic/empty/persona+issue
558 agentic tests, 74.0% coverage
Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-25 08:16:53 +00:00
|
|
|
require.NoError(t, writeStatus(ws3, &WorkspaceStatus{
|
|
|
|
|
Status: "running",
|
|
|
|
|
Repo: "agent",
|
|
|
|
|
Agent: "gemini",
|
|
|
|
|
PID: 999999,
|
|
|
|
|
}))
|
|
|
|
|
|
|
|
|
|
s := &PrepSubsystem{
|
feat(v0.8.0): full AX migration — ServiceRuntime, Actions, quality gates, transport
go-process:
- Register factory, Result lifecycle, 5 named Action handlers
- Start/Run/StartWithOptions/RunWithOptions all return core.Result
- core.ID() replaces fmt.Sprintf, core.As replaces errors.As
core/agent:
- PrepSubsystem + monitor.Subsystem + setup.Service embed ServiceRuntime[T]
- 22 named Actions + agent.completion Task pipeline in OnStartup
- ChannelNotifier removed — all IPC via c.ACTION(messages.X{})
- proc.go: all methods via s.Core().Process(), returns core.Result
- status.go: WriteAtomic + JSONMarshalString
- paths.go: Fs.NewUnrestricted() replaces unsafe.Pointer
- transport.go: ONE net/http file — HTTPGet/HTTPPost/HTTPDo/MCP transport
- All disallowed imports eliminated from source files (13 quality gates)
- String concat eliminated — core.Concat() throughout
- 1:1 _test.go + _example_test.go for every source file
- Reference docs synced from core/go v0.8.0
- RFC-025 updated with net/http, net/url, io/fs quality gates
- lib.go: io/fs eliminated via Data.ListNames, Array[T].Deduplicate
Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-26 01:27:46 +00:00
|
|
|
ServiceRuntime: core.NewServiceRuntime(testCore, AgentOptions{}),
|
2026-03-29 20:15:58 +00:00
|
|
|
backoff: make(map[string]time.Time),
|
|
|
|
|
failCount: make(map[string]int),
|
test: add Good/Bad/Ugly for status, paths, auto_pr, prep — agentic 74.0%
New properly named tests:
- TestStatus_Status_Ugly — dead PID detection (blocked/completed/failed)
- TestPaths_DefaultBranch_{Good,Bad,Ugly} — main/master/non-git
- TestAutoPR_AutoCreatePR_{Good,Bad,Ugly} — early returns + no commits
- TestPrep_BuildPrompt_{Good,Bad,Ugly} — basic/empty/persona+issue
558 agentic tests, 74.0% coverage
Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-25 08:16:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
_, out, err := s.status(nil, nil, StatusInput{})
|
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
assert.Equal(t, 3, out.Total)
|
|
|
|
|
|
|
|
|
|
// Verify case 1: blocked
|
|
|
|
|
assert.Len(t, out.Blocked, 1)
|
|
|
|
|
assert.Equal(t, "go-io", out.Blocked[0].Repo)
|
|
|
|
|
assert.Equal(t, "Need API credentials", out.Blocked[0].Question)
|
|
|
|
|
|
|
|
|
|
// Verify case 2: completed
|
|
|
|
|
assert.Equal(t, 1, out.Completed)
|
|
|
|
|
|
|
|
|
|
// Verify case 3: failed
|
|
|
|
|
assert.Equal(t, 1, out.Failed)
|
|
|
|
|
|
|
|
|
|
// Verify statuses were persisted to disk
|
2026-03-30 20:20:50 +00:00
|
|
|
st1 := mustReadStatus(t, ws1)
|
test: add Good/Bad/Ugly for status, paths, auto_pr, prep — agentic 74.0%
New properly named tests:
- TestStatus_Status_Ugly — dead PID detection (blocked/completed/failed)
- TestPaths_DefaultBranch_{Good,Bad,Ugly} — main/master/non-git
- TestAutoPR_AutoCreatePR_{Good,Bad,Ugly} — early returns + no commits
- TestPrep_BuildPrompt_{Good,Bad,Ugly} — basic/empty/persona+issue
558 agentic tests, 74.0% coverage
Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-25 08:16:53 +00:00
|
|
|
assert.Equal(t, "blocked", st1.Status)
|
|
|
|
|
|
2026-03-30 20:20:50 +00:00
|
|
|
st2 := mustReadStatus(t, ws2)
|
test: add Good/Bad/Ugly for status, paths, auto_pr, prep — agentic 74.0%
New properly named tests:
- TestStatus_Status_Ugly — dead PID detection (blocked/completed/failed)
- TestPaths_DefaultBranch_{Good,Bad,Ugly} — main/master/non-git
- TestAutoPR_AutoCreatePR_{Good,Bad,Ugly} — early returns + no commits
- TestPrep_BuildPrompt_{Good,Bad,Ugly} — basic/empty/persona+issue
558 agentic tests, 74.0% coverage
Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-25 08:16:53 +00:00
|
|
|
assert.Equal(t, "completed", st2.Status)
|
|
|
|
|
|
2026-03-30 20:20:50 +00:00
|
|
|
st3 := mustReadStatus(t, ws3)
|
test: add Good/Bad/Ugly for status, paths, auto_pr, prep — agentic 74.0%
New properly named tests:
- TestStatus_Status_Ugly — dead PID detection (blocked/completed/failed)
- TestPaths_DefaultBranch_{Good,Bad,Ugly} — main/master/non-git
- TestAutoPR_AutoCreatePR_{Good,Bad,Ugly} — early returns + no commits
- TestPrep_BuildPrompt_{Good,Bad,Ugly} — basic/empty/persona+issue
558 agentic tests, 74.0% coverage
Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-25 08:16:53 +00:00
|
|
|
assert.Equal(t, "failed", st3.Status)
|
|
|
|
|
assert.Equal(t, "Agent process died (no output log)", st3.Question)
|
|
|
|
|
}
|
2026-03-25 08:26:15 +00:00
|
|
|
|
|
|
|
|
// --- writeStatus (extended Ugly) ---
|
|
|
|
|
|
|
|
|
|
func TestStatus_WriteStatus_Ugly(t *testing.T) {
|
|
|
|
|
// Write a status with all fields, read back, verify UpdatedAt is set and all fields preserved
|
|
|
|
|
dir := t.TempDir()
|
|
|
|
|
|
|
|
|
|
original := &WorkspaceStatus{
|
|
|
|
|
Status: "blocked",
|
|
|
|
|
Agent: "gemini:flash",
|
|
|
|
|
Repo: "go-mcp",
|
|
|
|
|
Org: "core",
|
|
|
|
|
Task: "Refactor IPC handler",
|
|
|
|
|
Branch: "agent/refactor-ipc",
|
|
|
|
|
Issue: 77,
|
|
|
|
|
PID: 999999, // dead PID — non-existent
|
|
|
|
|
StartedAt: time.Now().Add(-10 * time.Minute).Truncate(time.Second),
|
|
|
|
|
Question: "Should I break backward compat?",
|
|
|
|
|
Runs: 5,
|
|
|
|
|
PRURL: "https://forge.lthn.ai/core/go-mcp/pulls/12",
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
err := writeStatus(dir, original)
|
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
|
|
// UpdatedAt should have been set by writeStatus
|
|
|
|
|
assert.False(t, original.UpdatedAt.IsZero(), "writeStatus must set UpdatedAt")
|
|
|
|
|
|
|
|
|
|
// Read back and verify every field
|
2026-03-30 20:20:50 +00:00
|
|
|
read := mustReadStatus(t, dir)
|
2026-03-25 08:26:15 +00:00
|
|
|
|
|
|
|
|
assert.Equal(t, "blocked", read.Status)
|
|
|
|
|
assert.Equal(t, "gemini:flash", read.Agent)
|
|
|
|
|
assert.Equal(t, "go-mcp", read.Repo)
|
|
|
|
|
assert.Equal(t, "core", read.Org)
|
|
|
|
|
assert.Equal(t, "Refactor IPC handler", read.Task)
|
|
|
|
|
assert.Equal(t, "agent/refactor-ipc", read.Branch)
|
|
|
|
|
assert.Equal(t, 77, read.Issue)
|
|
|
|
|
assert.Equal(t, 999999, read.PID)
|
|
|
|
|
assert.Equal(t, "Should I break backward compat?", read.Question)
|
|
|
|
|
assert.Equal(t, 5, read.Runs)
|
|
|
|
|
assert.Equal(t, "https://forge.lthn.ai/core/go-mcp/pulls/12", read.PRURL)
|
|
|
|
|
assert.False(t, read.UpdatedAt.IsZero(), "UpdatedAt must survive roundtrip")
|
|
|
|
|
}
|
test: batch 1 — add 80 Bad/Ugly tests for paths, plan, status, shutdown, forge cmds
Fill missing Good/Bad/Ugly categories for:
- paths.go: LocalFs, WorkspaceRoot, CoreRoot, PlansRoot, AgentName, GitHubOrg, parseInt, DefaultBranch
- plan.go: planCreate/Read/Update/Delete/List Ugly, planPath Ugly, validPlanStatus Ugly
- status.go: writeStatus Bad, status Good/Bad
- shutdown.go: dispatchStart/shutdownGraceful Bad/Ugly, shutdownNow Ugly
- commands_forge.go: all 9 cmd* functions Ugly (with httptest mocks)
- sanitise.go: Bad/Ugly for all 5 functions
- prep.go: various lifecycle Bad/Ugly
Gap: 260 → 208 missing categories
Tests: 566 → 646 (+80)
Coverage: 74.4%
Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-25 08:43:35 +00:00
|
|
|
|
|
|
|
|
// --- writeStatus Bad ---
|
|
|
|
|
|
|
|
|
|
func TestStatus_WriteStatus_Bad_ReadOnlyPath(t *testing.T) {
|
|
|
|
|
// go-io fs.Write auto-creates dirs, so test with /dev/null parent
|
|
|
|
|
st := &WorkspaceStatus{Status: "running", Agent: "codex"}
|
|
|
|
|
err := writeStatus("/dev/null/impossible", st)
|
|
|
|
|
assert.Error(t, err, "writeStatus to an impossible path should fail")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// --- status() MCP handler Good/Bad ---
|
|
|
|
|
|
|
|
|
|
func TestStatus_Status_Good_PopulatedWorkspaces(t *testing.T) {
|
|
|
|
|
root := t.TempDir()
|
|
|
|
|
t.Setenv("CORE_WORKSPACE", root)
|
2026-03-26 01:39:41 +00:00
|
|
|
wsRoot := core.JoinPath(root, "workspace")
|
test: batch 1 — add 80 Bad/Ugly tests for paths, plan, status, shutdown, forge cmds
Fill missing Good/Bad/Ugly categories for:
- paths.go: LocalFs, WorkspaceRoot, CoreRoot, PlansRoot, AgentName, GitHubOrg, parseInt, DefaultBranch
- plan.go: planCreate/Read/Update/Delete/List Ugly, planPath Ugly, validPlanStatus Ugly
- status.go: writeStatus Bad, status Good/Bad
- shutdown.go: dispatchStart/shutdownGraceful Bad/Ugly, shutdownNow Ugly
- commands_forge.go: all 9 cmd* functions Ugly (with httptest mocks)
- sanitise.go: Bad/Ugly for all 5 functions
- prep.go: various lifecycle Bad/Ugly
Gap: 260 → 208 missing categories
Tests: 566 → 646 (+80)
Coverage: 74.4%
Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-25 08:43:35 +00:00
|
|
|
|
|
|
|
|
// Create a running workspace with a live PID (our own PID)
|
2026-03-26 01:39:41 +00:00
|
|
|
ws1 := core.JoinPath(wsRoot, "task-running")
|
|
|
|
|
require.True(t, fs.EnsureDir(core.JoinPath(ws1, "repo")).OK)
|
test: batch 1 — add 80 Bad/Ugly tests for paths, plan, status, shutdown, forge cmds
Fill missing Good/Bad/Ugly categories for:
- paths.go: LocalFs, WorkspaceRoot, CoreRoot, PlansRoot, AgentName, GitHubOrg, parseInt, DefaultBranch
- plan.go: planCreate/Read/Update/Delete/List Ugly, planPath Ugly, validPlanStatus Ugly
- status.go: writeStatus Bad, status Good/Bad
- shutdown.go: dispatchStart/shutdownGraceful Bad/Ugly, shutdownNow Ugly
- commands_forge.go: all 9 cmd* functions Ugly (with httptest mocks)
- sanitise.go: Bad/Ugly for all 5 functions
- prep.go: various lifecycle Bad/Ugly
Gap: 260 → 208 missing categories
Tests: 566 → 646 (+80)
Coverage: 74.4%
Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-25 08:43:35 +00:00
|
|
|
require.NoError(t, writeStatus(ws1, &WorkspaceStatus{
|
|
|
|
|
Status: "completed",
|
|
|
|
|
Repo: "go-io",
|
|
|
|
|
Agent: "codex",
|
|
|
|
|
Task: "fix tests",
|
|
|
|
|
}))
|
|
|
|
|
|
|
|
|
|
// Create a blocked workspace
|
2026-03-26 01:39:41 +00:00
|
|
|
ws2 := core.JoinPath(wsRoot, "task-blocked")
|
|
|
|
|
require.True(t, fs.EnsureDir(core.JoinPath(ws2, "repo")).OK)
|
test: batch 1 — add 80 Bad/Ugly tests for paths, plan, status, shutdown, forge cmds
Fill missing Good/Bad/Ugly categories for:
- paths.go: LocalFs, WorkspaceRoot, CoreRoot, PlansRoot, AgentName, GitHubOrg, parseInt, DefaultBranch
- plan.go: planCreate/Read/Update/Delete/List Ugly, planPath Ugly, validPlanStatus Ugly
- status.go: writeStatus Bad, status Good/Bad
- shutdown.go: dispatchStart/shutdownGraceful Bad/Ugly, shutdownNow Ugly
- commands_forge.go: all 9 cmd* functions Ugly (with httptest mocks)
- sanitise.go: Bad/Ugly for all 5 functions
- prep.go: various lifecycle Bad/Ugly
Gap: 260 → 208 missing categories
Tests: 566 → 646 (+80)
Coverage: 74.4%
Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-25 08:43:35 +00:00
|
|
|
require.NoError(t, writeStatus(ws2, &WorkspaceStatus{
|
|
|
|
|
Status: "blocked",
|
|
|
|
|
Repo: "go-log",
|
|
|
|
|
Agent: "gemini",
|
|
|
|
|
Question: "Which log format?",
|
|
|
|
|
}))
|
|
|
|
|
|
|
|
|
|
s := &PrepSubsystem{
|
feat(v0.8.0): full AX migration — ServiceRuntime, Actions, quality gates, transport
go-process:
- Register factory, Result lifecycle, 5 named Action handlers
- Start/Run/StartWithOptions/RunWithOptions all return core.Result
- core.ID() replaces fmt.Sprintf, core.As replaces errors.As
core/agent:
- PrepSubsystem + monitor.Subsystem + setup.Service embed ServiceRuntime[T]
- 22 named Actions + agent.completion Task pipeline in OnStartup
- ChannelNotifier removed — all IPC via c.ACTION(messages.X{})
- proc.go: all methods via s.Core().Process(), returns core.Result
- status.go: WriteAtomic + JSONMarshalString
- paths.go: Fs.NewUnrestricted() replaces unsafe.Pointer
- transport.go: ONE net/http file — HTTPGet/HTTPPost/HTTPDo/MCP transport
- All disallowed imports eliminated from source files (13 quality gates)
- String concat eliminated — core.Concat() throughout
- 1:1 _test.go + _example_test.go for every source file
- Reference docs synced from core/go v0.8.0
- RFC-025 updated with net/http, net/url, io/fs quality gates
- lib.go: io/fs eliminated via Data.ListNames, Array[T].Deduplicate
Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-26 01:27:46 +00:00
|
|
|
ServiceRuntime: core.NewServiceRuntime(testCore, AgentOptions{}),
|
2026-03-29 20:15:58 +00:00
|
|
|
backoff: make(map[string]time.Time),
|
|
|
|
|
failCount: make(map[string]int),
|
test: batch 1 — add 80 Bad/Ugly tests for paths, plan, status, shutdown, forge cmds
Fill missing Good/Bad/Ugly categories for:
- paths.go: LocalFs, WorkspaceRoot, CoreRoot, PlansRoot, AgentName, GitHubOrg, parseInt, DefaultBranch
- plan.go: planCreate/Read/Update/Delete/List Ugly, planPath Ugly, validPlanStatus Ugly
- status.go: writeStatus Bad, status Good/Bad
- shutdown.go: dispatchStart/shutdownGraceful Bad/Ugly, shutdownNow Ugly
- commands_forge.go: all 9 cmd* functions Ugly (with httptest mocks)
- sanitise.go: Bad/Ugly for all 5 functions
- prep.go: various lifecycle Bad/Ugly
Gap: 260 → 208 missing categories
Tests: 566 → 646 (+80)
Coverage: 74.4%
Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-25 08:43:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
_, out, err := s.status(context.Background(), nil, StatusInput{})
|
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
assert.Equal(t, 2, out.Total)
|
|
|
|
|
assert.Equal(t, 1, out.Completed)
|
|
|
|
|
assert.Len(t, out.Blocked, 1)
|
|
|
|
|
assert.Equal(t, "go-log", out.Blocked[0].Repo)
|
|
|
|
|
assert.Equal(t, "Which log format?", out.Blocked[0].Question)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func TestStatus_Status_Bad_EmptyWorkspaceRoot(t *testing.T) {
|
|
|
|
|
root := t.TempDir()
|
|
|
|
|
t.Setenv("CORE_WORKSPACE", root)
|
|
|
|
|
// Do NOT create the workspace/ subdirectory
|
|
|
|
|
|
|
|
|
|
s := &PrepSubsystem{
|
feat(v0.8.0): full AX migration — ServiceRuntime, Actions, quality gates, transport
go-process:
- Register factory, Result lifecycle, 5 named Action handlers
- Start/Run/StartWithOptions/RunWithOptions all return core.Result
- core.ID() replaces fmt.Sprintf, core.As replaces errors.As
core/agent:
- PrepSubsystem + monitor.Subsystem + setup.Service embed ServiceRuntime[T]
- 22 named Actions + agent.completion Task pipeline in OnStartup
- ChannelNotifier removed — all IPC via c.ACTION(messages.X{})
- proc.go: all methods via s.Core().Process(), returns core.Result
- status.go: WriteAtomic + JSONMarshalString
- paths.go: Fs.NewUnrestricted() replaces unsafe.Pointer
- transport.go: ONE net/http file — HTTPGet/HTTPPost/HTTPDo/MCP transport
- All disallowed imports eliminated from source files (13 quality gates)
- String concat eliminated — core.Concat() throughout
- 1:1 _test.go + _example_test.go for every source file
- Reference docs synced from core/go v0.8.0
- RFC-025 updated with net/http, net/url, io/fs quality gates
- lib.go: io/fs eliminated via Data.ListNames, Array[T].Deduplicate
Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-26 01:27:46 +00:00
|
|
|
ServiceRuntime: core.NewServiceRuntime(testCore, AgentOptions{}),
|
2026-03-29 20:15:58 +00:00
|
|
|
backoff: make(map[string]time.Time),
|
|
|
|
|
failCount: make(map[string]int),
|
test: batch 1 — add 80 Bad/Ugly tests for paths, plan, status, shutdown, forge cmds
Fill missing Good/Bad/Ugly categories for:
- paths.go: LocalFs, WorkspaceRoot, CoreRoot, PlansRoot, AgentName, GitHubOrg, parseInt, DefaultBranch
- plan.go: planCreate/Read/Update/Delete/List Ugly, planPath Ugly, validPlanStatus Ugly
- status.go: writeStatus Bad, status Good/Bad
- shutdown.go: dispatchStart/shutdownGraceful Bad/Ugly, shutdownNow Ugly
- commands_forge.go: all 9 cmd* functions Ugly (with httptest mocks)
- sanitise.go: Bad/Ugly for all 5 functions
- prep.go: various lifecycle Bad/Ugly
Gap: 260 → 208 missing categories
Tests: 566 → 646 (+80)
Coverage: 74.4%
Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-25 08:43:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
_, out, err := s.status(context.Background(), nil, StatusInput{})
|
|
|
|
|
require.NoError(t, err, "status on missing workspace dir should not error")
|
|
|
|
|
assert.Equal(t, 0, out.Total)
|
|
|
|
|
assert.Equal(t, 0, out.Running)
|
|
|
|
|
assert.Equal(t, 0, out.Completed)
|
|
|
|
|
}
|