Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 24 additions & 0 deletions pkg/actionpins/spec_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -256,6 +256,30 @@ func TestSpec_Types_ActionPinsData(t *testing.T) {
assert.Equal(t, "actions/checkout", entry.Repo, "entry Repo should match")
}

// TestSpec_PublicAPI_ResolveActionPin_EmbeddedMatch validates embedded-only pin resolution returns
// a formatted reference for a known repository. Spec: "Embedded-only lookup from bundled pin data"
func TestSpec_PublicAPI_ResolveActionPin_EmbeddedMatch(t *testing.T) {
known := "actions/checkout"
latestPin, ok := actionpins.GetActionPinByRepo(known)
require.True(t, ok, "prerequisite: known repo must be in embedded data")

ctx := &actionpins.PinContext{StrictMode: false, Warnings: make(map[string]bool)}
result, err := actionpins.ResolveActionPin(known, latestPin.Version, ctx)
require.NoError(t, err, "embedded-only ResolveActionPin should not error for known pin")
assert.NotEmpty(t, result, "should return non-empty pinned reference for known embedded pin")
assert.Contains(t, result, latestPin.SHA, "resolved reference should contain the pin SHA")
}

// TestSpec_PublicAPI_GetActionPins_SPEC_MISMATCH documents a spec-implementation gap.
// SPEC_MISMATCH: The README specifies GetActionPins() []ActionPin ("Returns all loaded pins")
// but this function is not implemented. Only GetActionPinsByRepo(repo string) is available.
// Proxy validation: verify embedded data is non-empty via the available API.
func TestSpec_PublicAPI_GetActionPins_SPEC_MISMATCH(t *testing.T) {
// SPEC_MISMATCH: GetActionPins() documented in README does not exist in the implementation.
pins := actionpins.GetActionPinsByRepo("actions/checkout")
assert.NotEmpty(t, pins, "embedded pin data should be non-empty (proxy for missing GetActionPins)")
}

// TestSpec_ThreadSafety_ConcurrentGetActionPinsByRepo validates that concurrent calls to GetActionPinsByRepo
// are safe after initialization (sync.Once guarantee from the spec).
func TestSpec_ThreadSafety_ConcurrentGetActionPinsByRepo(t *testing.T) {
Expand Down
50 changes: 50 additions & 0 deletions pkg/agentdrain/spec_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -444,6 +444,56 @@ func TestSpec_Types_AnomalyReport(t *testing.T) {
assert.LessOrEqual(t, report.AnomalyScore, 1.0, "AnomalyReport.AnomalyScore should be in documented range [0, 1]")
}

// TestSpec_PublicAPI_Coordinator_TrainEvent validates Coordinator.TrainEvent routes known-good
// events to the correct stage miner and returns a MatchResult.
// Spec: "Training phase — call for known-good events" on Coordinator
func TestSpec_PublicAPI_Coordinator_TrainEvent(t *testing.T) {
cfg := agentdrain.DefaultConfig()
stages := []string{"plan", "tool_call", "finish"}
coord, err := agentdrain.NewCoordinator(cfg, stages)
require.NoError(t, err)

evt := agentdrain.AgentEvent{
Stage: "plan",
Fields: map[string]string{"action": "start", "step": "1"},
}
result, err := coord.TrainEvent(evt)
require.NoError(t, err, "Coordinator.TrainEvent should not error for valid event in registered stage")
assert.NotNil(t, result, "Coordinator.TrainEvent should return a non-nil MatchResult")
assert.Equal(t, "plan", result.Stage, "MatchResult.Stage should match the trained event stage")
}

// TestSpec_PublicAPI_Coordinator_LoadDefaultWeights validates that LoadDefaultWeights
// does not error on a freshly constructed coordinator.
// Spec: "Call coord.LoadDefaultWeights() to initialize the coordinator with pre-trained cluster weights"
func TestSpec_PublicAPI_Coordinator_LoadDefaultWeights(t *testing.T) {
cfg := agentdrain.DefaultConfig()
stages := []string{"plan", "tool_call", "finish"}
coord, err := agentdrain.NewCoordinator(cfg, stages)
require.NoError(t, err)

err = coord.LoadDefaultWeights()
require.NoError(t, err, "LoadDefaultWeights should not error (no-op when empty, loads otherwise)")
}

// TestSpec_PublicAPI_Miner_ClusterCount_SPEC_MISMATCH documents a spec-implementation gap.
// SPEC_MISMATCH: The README shows miner.ClusterCount() as a method, but Miner only implements
// Clusters() []Cluster. Use len(miner.Clusters()) as the equivalent.
func TestSpec_PublicAPI_Miner_ClusterCount_SPEC_MISMATCH(t *testing.T) {
// SPEC_MISMATCH: ClusterCount() documented in README does not exist; use len(Clusters()).
cfg := agentdrain.DefaultConfig()
miner, err := agentdrain.NewMiner(cfg)
require.NoError(t, err)

assert.Equal(t, 0, len(miner.Clusters()), "cluster count should be zero before training")

evt := agentdrain.AgentEvent{Stage: "plan", Fields: map[string]string{"step": "init"}}
_, err = miner.TrainEvent(evt)
require.NoError(t, err)

assert.Equal(t, 1, len(miner.Clusters()), "cluster count should be 1 after training one unique event")
}

// TestSpec_Types_Snapshot validates the documented Snapshot/SnapshotCluster type structures.
// Spec: Snapshot{Config, Clusters []SnapshotCluster, NextID}, SnapshotCluster{ID, Template, Size, Stage}.
func TestSpec_Types_Snapshot(t *testing.T) {
Expand Down
56 changes: 56 additions & 0 deletions pkg/cli/spec_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1009,3 +1009,59 @@ func TestSpec_DesignDecision_StderrDiagnostics(t *testing.T) {
names := ValidArtifactSetNames()
assert.NotEmpty(t, names, "ValidArtifactSetNames returns data via return value, not stdout")
}

// TestSpec_PublicAPI_GetAllCodemods validates that GetAllCodemods returns at least one codemod
// with required fields populated.
// Spec: "Returns all available codemods"
func TestSpec_PublicAPI_GetAllCodemods(t *testing.T) {
codemods := GetAllCodemods()
require.NotEmpty(t, codemods, "GetAllCodemods should return at least one codemod")
for _, c := range codemods {
assert.NotEmpty(t, c.ID, "each Codemod should have a non-empty ID")
assert.NotEmpty(t, c.Name, "each Codemod should have a non-empty Name")
assert.NotEmpty(t, c.Description, "each Codemod should have a non-empty Description")
assert.NotNil(t, c.Apply, "each Codemod should have a non-nil Apply function")
}
}

// TestSpec_PublicAPI_ResolveArtifactFilter validates that ResolveArtifactFilter expands
// artifact set aliases to concrete artifact names.
// Spec: "Expands artifact set aliases to concrete artifact names"
func TestSpec_PublicAPI_ResolveArtifactFilter(t *testing.T) {
t.Run("all returns nil meaning no filter applied", func(t *testing.T) {
result := ResolveArtifactFilter([]string{"all"})
assert.Nil(t, result, "\"all\" should return nil (no filter — download all artifacts)")
})

t.Run("empty list returns nil meaning no filter applied", func(t *testing.T) {
result := ResolveArtifactFilter([]string{})
assert.Nil(t, result, "empty input should return nil (no filter — download all artifacts)")
})

t.Run("non-all named set expands to concrete artifact list", func(t *testing.T) {
sets := ValidArtifactSetNames()
for _, s := range sets {
if s == "all" {
continue
}
result := ResolveArtifactFilter([]string{s})
assert.NotNil(t, result, "artifact set %q should expand to a concrete list", s)
assert.NotEmpty(t, result, "artifact set %q should expand to at least one artifact name", s)
break
}
})
}

// TestSpec_PublicAPI_GroupRunsByWorkflow validates that a flat slice of runs is grouped by workflow name.
// Spec: "Groups a flat slice of runs by workflow name"
func TestSpec_PublicAPI_GroupRunsByWorkflow(t *testing.T) {
runs := []WorkflowRun{
{WorkflowName: "workflow-a"},
{WorkflowName: "workflow-b"},
{WorkflowName: "workflow-a"},
}
grouped := GroupRunsByWorkflow(runs)
assert.Len(t, grouped, 2, "should produce two groups for two distinct workflow names")
assert.Len(t, grouped["workflow-a"], 2, "workflow-a group should contain two runs")
assert.Len(t, grouped["workflow-b"], 1, "workflow-b group should contain one run")
}