a06f331eb8
CI / benchmark (push) Has been skipped
install-script / posix-syntax (push) Successful in 6m1s
CI / build-onnx (push) Failing after 6m43s
init-smoke / dry-run (push) Failing after 15m57s
security / govulncheck (push) Has been cancelled
security / trivy-fs (push) Has been cancelled
CI / test (1.26, ubuntu-latest) (push) Has been cancelled
Scorecard supply-chain security / Scorecard analysis (push) Has been cancelled
CI / test (1.26, macos-latest) (push) Has been cancelled
CI / build-windows (push) Has been cancelled
CI / lint (push) Has been cancelled
install-script / powershell-syntax (push) Has been cancelled
install-script / install (macos-14) (push) Has been cancelled
install-script / install (ubuntu-latest) (push) Has been cancelled
138 lines
5.0 KiB
Go
138 lines
5.0 KiB
Go
package mcp
|
|
|
|
import (
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/zzet/gortex/internal/analysis"
|
|
"github.com/zzet/gortex/internal/graph"
|
|
)
|
|
|
|
// buildHotspotRerankFixture seeds three function nodes with deterministic
|
|
// complexity scores AND varying blame / releases metadata so the
|
|
// novelty / directional modes can reorder them in predictable ways.
|
|
func buildHotspotRerankFixture(t *testing.T, now time.Time) (graph.Store, []analysis.HotspotEntry) {
|
|
t.Helper()
|
|
g := graph.New()
|
|
|
|
g.AddNode(&graph.Node{
|
|
ID: "fresh", Name: "Fresh", Kind: graph.KindFunction, FilePath: "fresh.go",
|
|
Meta: map[string]any{
|
|
"last_authored": map[string]any{"timestamp": now.Add(-2 * 24 * time.Hour).Unix()},
|
|
"added_in": map[string]any{"timestamp": now.Add(-2 * 24 * time.Hour).Unix()},
|
|
},
|
|
})
|
|
g.AddNode(&graph.Node{
|
|
ID: "midway", Name: "Midway", Kind: graph.KindFunction, FilePath: "midway.go",
|
|
Meta: map[string]any{
|
|
"last_authored": map[string]any{"timestamp": now.Add(-15 * 24 * time.Hour).Unix()},
|
|
"added_in": map[string]any{"timestamp": now.Add(-15 * 24 * time.Hour).Unix()},
|
|
},
|
|
})
|
|
g.AddNode(&graph.Node{
|
|
ID: "stale", Name: "Stale", Kind: graph.KindFunction, FilePath: "stale.go",
|
|
Meta: map[string]any{
|
|
"last_authored": map[string]any{"timestamp": now.Add(-90 * 24 * time.Hour).Unix()},
|
|
"added_in": map[string]any{"timestamp": now.Add(-90 * 24 * time.Hour).Unix()},
|
|
},
|
|
})
|
|
|
|
// Identical complexity scores so the rerank is decisive.
|
|
entries := []analysis.HotspotEntry{
|
|
{ID: "fresh", Name: "Fresh", ComplexityScore: 10.0},
|
|
{ID: "midway", Name: "Midway", ComplexityScore: 10.0},
|
|
{ID: "stale", Name: "Stale", ComplexityScore: 10.0},
|
|
}
|
|
return g, entries
|
|
}
|
|
|
|
func TestRerankHotspots_ComplexityIsPassThrough(t *testing.T) {
|
|
g, entries := buildHotspotRerankFixture(t, time.Now())
|
|
out := rerankHotspots(entries, g, "complexity", "", 30)
|
|
// Same order, same scores.
|
|
assert.Len(t, out, 3)
|
|
for i, e := range out {
|
|
assert.Equal(t, entries[i].ComplexityScore, e.ComplexityScore)
|
|
}
|
|
}
|
|
|
|
func TestRerankHotspots_NoveltyPromotesRecent(t *testing.T) {
|
|
now := time.Now()
|
|
g, entries := buildHotspotRerankFixture(t, now)
|
|
out := rerankHotspots(entries, g, "novelty", "", 30)
|
|
// 'fresh' (2 days old) ranks first; 'stale' (90 days) drops to 0.
|
|
assert.Equal(t, "fresh", out[0].ID)
|
|
var staleScore float64
|
|
for _, e := range out {
|
|
if e.ID == "stale" {
|
|
staleScore = e.ComplexityScore
|
|
}
|
|
}
|
|
assert.InDelta(t, 0.0, staleScore, 1e-6, "stale outside window gets zero novelty weight")
|
|
}
|
|
|
|
func TestRerankHotspots_DirectionalAddsRewardsRecent(t *testing.T) {
|
|
g, entries := buildHotspotRerankFixture(t, time.Now())
|
|
out := rerankHotspots(entries, g, "directional", "adds", 30)
|
|
assert.Equal(t, "fresh", out[0].ID, "adds direction promotes the newest addition")
|
|
}
|
|
|
|
func TestRerankHotspots_DirectionalStableRewardsOld(t *testing.T) {
|
|
g, entries := buildHotspotRerankFixture(t, time.Now())
|
|
out := rerankHotspots(entries, g, "directional", "stable", 30)
|
|
// stale (90 days) saturates frac=1.0 (clamped), midway and fresh
|
|
// are < 1.0 — stale wins.
|
|
assert.Equal(t, "stale", out[0].ID, "stable direction promotes the oldest addition")
|
|
}
|
|
|
|
func TestRerankHotspots_MissingMetaScoresZero(t *testing.T) {
|
|
g := graph.New()
|
|
g.AddNode(&graph.Node{ID: "nometa", Name: "NoMeta", Kind: graph.KindFunction, FilePath: "x.go"})
|
|
entries := []analysis.HotspotEntry{{ID: "nometa", Name: "NoMeta", ComplexityScore: 10.0}}
|
|
|
|
out := rerankHotspots(entries, g, "novelty", "", 30)
|
|
for _, e := range out {
|
|
if e.ID == "nometa" {
|
|
assert.InDelta(t, 0.0, e.ComplexityScore, 1e-6, "missing meta -> zero weight under novelty")
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestRerankHotspots_MissingNodeDropped(t *testing.T) {
|
|
g := graph.New()
|
|
entries := []analysis.HotspotEntry{{ID: "doesnotexist", Name: "X", ComplexityScore: 5.0}}
|
|
out := rerankHotspots(entries, g, "novelty", "", 30)
|
|
assert.Empty(t, out, "entries whose node is missing from the graph are dropped")
|
|
}
|
|
|
|
func TestDecodeMetaTimestamp_Forms(t *testing.T) {
|
|
now := time.Now().Truncate(time.Second).UTC()
|
|
cases := []any{
|
|
now.Unix(),
|
|
int(now.Unix()),
|
|
float64(now.Unix()),
|
|
now.Format(time.RFC3339),
|
|
}
|
|
for _, c := range cases {
|
|
got := decodeMetaTimestamp(c)
|
|
assert.Equal(t, now.Unix(), got.Unix(), "decode %T(%v) → %v", c, c, got)
|
|
}
|
|
assert.True(t, decodeMetaTimestamp(nil).IsZero())
|
|
assert.True(t, decodeMetaTimestamp("garbage").IsZero())
|
|
}
|
|
|
|
func TestNoveltyWeight_LinearDecay(t *testing.T) {
|
|
now := time.Now()
|
|
window := 30 * 24 * time.Hour
|
|
// Day 0 → weight 1.0
|
|
n := &graph.Node{Meta: map[string]any{"last_authored": map[string]any{"timestamp": now.Unix()}}}
|
|
assert.InDelta(t, 1.0, noveltyWeight(nil, n, now, window), 1e-6)
|
|
// Day 15 → weight 0.5
|
|
n.Meta["last_authored"] = map[string]any{"timestamp": now.Add(-15 * 24 * time.Hour).Unix()}
|
|
assert.InDelta(t, 0.5, noveltyWeight(nil, n, now, window), 1e-2)
|
|
// Day 30+ → weight 0
|
|
n.Meta["last_authored"] = map[string]any{"timestamp": now.Add(-31 * 24 * time.Hour).Unix()}
|
|
assert.InDelta(t, 0.0, noveltyWeight(nil, n, now, window), 1e-6)
|
|
}
|