gitlink-cli/shortcuts/workflow/rules/contributor_test.go

149 lines
4.6 KiB
Go

package rules
import (
"testing"
"time"
)
func TestContributorRanking(t *testing.T) {
upstream := map[string]interface{}{
"commits": map[string]interface{}{
"data": []interface{}{
map[string]interface{}{"created_at": "2025-06-01T00:00:00Z", "author": "dev1"},
map[string]interface{}{"created_at": "2025-06-05T00:00:00Z", "author": "dev1"},
map[string]interface{}{"created_at": "2025-06-10T00:00:00Z", "author": "dev2"},
},
},
"open-issues": map[string]interface{}{"data": []interface{}{}},
"closed-issues": map[string]interface{}{"data": []interface{}{}},
"merged-prs": map[string]interface{}{"data": []interface{}{}},
"members": map[string]interface{}{
"data": []interface{}{
map[string]interface{}{"login": "dev1", "name": "Dev One"},
map[string]interface{}{"login": "dev2", "name": "Dev Two"},
},
},
}
resp, err := ContributorRankingRule(upstream, "contributor-ranking")
if err != nil {
t.Fatalf("ContributorRankingRule failed: %v", err)
}
analysis := resp.Analysis.(map[string]interface{})
rankings := analysis["rankings"].([]map[string]interface{})
if len(rankings) != 2 {
t.Fatalf("expected 2 rankings, got %d", len(rankings))
}
// dev1 should be ranked #1 (2 commits vs 1).
first := rankings[0]
if first["login"] != "dev1" {
t.Errorf("expected dev1 as #1, got %v", first["login"])
}
if first["rank"] != 1 {
t.Errorf("expected rank 1, got %v", first["rank"])
}
if first["commits"] != 2 {
t.Errorf("expected 2 commits, got %v", first["commits"])
}
}
func TestChurnRiskDetection(t *testing.T) {
// 35 days ago — should trigger churn risk.
oldDate := "2025-01-01T00:00:00Z"
upstream := map[string]interface{}{
"commits": map[string]interface{}{
"data": []interface{}{
map[string]interface{}{"created_at": oldDate, "author": "dev1"},
},
},
"open-issues": map[string]interface{}{"data": []interface{}{}},
"closed-issues": map[string]interface{}{"data": []interface{}{}},
"merged-prs": map[string]interface{}{"data": []interface{}{}},
"members": map[string]interface{}{
"data": []interface{}{
map[string]interface{}{"login": "dev1", "name": "Dev One"},
},
},
}
resp, err := ContributorRankingRule(upstream, "contributor-ranking")
if err != nil {
t.Fatalf("ContributorRankingRule failed: %v", err)
}
analysis := resp.Analysis.(map[string]interface{})
rankings := analysis["rankings"].([]map[string]interface{})
if len(rankings) > 0 {
tags := rankings[0]["tags"].([]string)
for _, tag := range tags {
if tag == "churn-risk" {
return // success
}
}
t.Errorf("expected churn-risk tag for old activity, got tags: %v", tags)
}
}
func TestContributorOutputFormat(t *testing.T) {
resp, err := ContributorRankingRule(map[string]interface{}{}, "contributor-ranking")
if err != nil {
t.Fatalf("ContributorRankingRule failed: %v", err)
}
if resp.Analysis == nil {
t.Fatal("expected non-nil Analysis")
}
if resp.Actions != nil {
t.Fatal("expected nil Actions (read-only report)")
}
}
func TestNewStarDetection(t *testing.T) {
// Use very recent dates so the commits appear in the last 30 days.
now := time.Now()
d1 := now.Add(-2 * 24 * time.Hour).Format(time.RFC3339)
d2 := now.Add(-3 * 24 * time.Hour).Format(time.RFC3339)
d3 := now.Add(-4 * 24 * time.Hour).Format(time.RFC3339)
upstream := map[string]interface{}{
"commits": map[string]interface{}{
"data": []interface{}{
map[string]interface{}{"created_at": d1, "author": "dev1"},
map[string]interface{}{"created_at": d2, "author": "dev1"},
map[string]interface{}{"created_at": d3, "author": "dev1"},
},
},
"open-issues": map[string]interface{}{"data": []interface{}{}},
"closed-issues": map[string]interface{}{"data": []interface{}{}},
"merged-prs": map[string]interface{}{"data": []interface{}{}},
"members": map[string]interface{}{
"data": []interface{}{
map[string]interface{}{"login": "dev1", "name": "Dev One"},
},
},
}
resp, err := ContributorRankingRule(upstream, "contributor-ranking")
if err != nil {
t.Fatalf("ContributorRankingRule failed: %v", err)
}
analysis := resp.Analysis.(map[string]interface{})
// Should have new-star or at least ranking.
rankings := analysis["rankings"].([]map[string]interface{})
if len(rankings) == 0 {
t.Fatal("expected at least 1 ranking entry")
}
tags, _ := rankings[0]["tags"].([]string)
t.Logf("tags for dev1: %v", tags)
// With only recent commits (no previous period), trend should be 100%, triggering new-star.
found := false
for _, tag := range tags {
if tag == "new-star" {
found = true
}
}
if !found {
t.Errorf("expected new-star tag, got: %v", tags)
}
}