gitlink-cli/shortcuts/workflow/triage_rules_test.go

159 lines
5.7 KiB
Go

package workflow
import (
"testing"
)
func TestAnalyzeIssueDetectsSecurityP0(t *testing.T) {
result := AnalyzeIssue(IssueInput{
Title: "Token leaked in command output",
Body: "A secret token leaked and may allow permission escalation.",
Labels: []string{"security"},
}, "en")
if result.DetectedType != IssueTypeSecurity {
t.Fatalf("DetectedType = %q, want %q", result.DetectedType, IssueTypeSecurity)
}
if result.Priority != PriorityP0 {
t.Fatalf("Priority = %q, want %q", result.Priority, PriorityP0)
}
if !containsString(result.RiskFlags, RiskPossibleSecretLeak) && !containsString(result.RiskFlags, RiskSecuritySensitive) {
t.Fatalf("RiskFlags = %v, want security or secret leak flag", result.RiskFlags)
}
if result.Confidence < 70 {
t.Fatalf("Confidence = %d, want >= 70", result.Confidence)
}
}
func TestAnalyzeIssueDetectsBugAndMissingInfo(t *testing.T) {
result := AnalyzeIssue(IssueInput{
Title: "CLI crash with error",
Body: "It crashes.",
}, "en")
if result.DetectedType != IssueTypeBug {
t.Fatalf("DetectedType = %q, want %q", result.DetectedType, IssueTypeBug)
}
if result.Priority != PriorityP1 && result.Priority != PriorityP2 {
t.Fatalf("Priority = %q, want P1 or P2", result.Priority)
}
if len(result.MissingInformation) == 0 {
t.Fatal("MissingInformation is empty, want bug info requirements")
}
if !containsString(result.RiskFlags, RiskInsufficientInfo) {
t.Fatalf("RiskFlags = %v, want %q", result.RiskFlags, RiskInsufficientInfo)
}
}
func TestAnalyzeIssueDetectsDocs(t *testing.T) {
result := AnalyzeIssue(IssueInput{
Title: "README typo in documentation example",
Body: "The docs guide has a typo.",
}, "en")
if result.DetectedType != IssueTypeDocs {
t.Fatalf("DetectedType = %q, want %q", result.DetectedType, IssueTypeDocs)
}
if result.Priority != PriorityP3 {
t.Fatalf("Priority = %q, want %q", result.Priority, PriorityP3)
}
if result.RecommendedAction != ActionUpdateDocs {
t.Fatalf("RecommendedAction = %q, want %q", result.RecommendedAction, ActionUpdateDocs)
}
}
func TestAnalyzeIssueChinese(t *testing.T) {
result := AnalyzeIssue(IssueInput{
Title: "安装失败并且报错,无法登录",
Body: "执行登录命令后失败。",
}, "zh-CN")
if result.DetectedType != IssueTypeBug {
t.Fatalf("DetectedType = %q, want %q", result.DetectedType, IssueTypeBug)
}
if result.Priority != PriorityP1 {
t.Fatalf("Priority = %q, want %q", result.Priority, PriorityP1)
}
if result.SuggestedComment == "" {
t.Fatal("SuggestedComment is empty")
}
}
func TestAnalyzeIssueUnknownLowConfidence(t *testing.T) {
result := AnalyzeIssue(IssueInput{
Title: "General repository note",
Body: "This is a neutral note without clear maintenance signal.",
}, "en")
if result.DetectedType != IssueTypeUnknown {
t.Fatalf("DetectedType = %q, want %q", result.DetectedType, IssueTypeUnknown)
}
if result.Confidence > 40 {
t.Fatalf("Confidence = %d, want <= 40", result.Confidence)
}
}
func TestDeterminePriority(t *testing.T) {
tests := []struct {
name string
text string
detectedType string
wantPriority string
}{
{"security type", "something", IssueTypeSecurity, PriorityP0},
{"token leak in text", "token leak found", IssueTypeBug, PriorityP0},
{"secret leak", "a secret leak happened", IssueTypeBug, PriorityP0},
{"vulnerability", "vulnerability in parse", IssueTypeBug, PriorityP0},
{"chinese auth bypass", "认证绕过", IssueTypeBug, PriorityP0},
{"crash", "the cli crash on start", IssueTypeBug, PriorityP1},
{"panic", "panic at runtime", IssueTypeBug, PriorityP1},
{"install failed", "install failed on windows", IssueTypeBug, PriorityP1},
{"cannot login", "cannot login with token", IssueTypeBug, PriorityP1},
{"chinese install failed", "安装失败", IssueTypeBug, PriorityP1},
{"chinese login fail", "无法登录", IssueTypeBug, PriorityP1},
{"chinese crash", "崩溃", IssueTypeBug, PriorityP1},
{"bug type", "some text", IssueTypeBug, PriorityP2},
{"ci type", "ci failure", IssueTypeCI, PriorityP2},
{"performance", "slow response", IssueTypePerformance, PriorityP2},
{"feature", "new feature request", IssueTypeFeature, PriorityP2},
{"default", "random note", IssueTypeQuestion, PriorityP3},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got, _ := determinePriority(tt.text, tt.detectedType)
if got != tt.wantPriority {
t.Fatalf("determinePriority = %q, want %q", got, tt.wantPriority)
}
})
}
}
func TestRecommendedAction(t *testing.T) {
tests := []struct {
name string
detectedType string
priority string
riskFlags []string
missingInformation []string
want string
}{
{"security flag", IssueTypeBug, PriorityP2, []string{RiskSecuritySensitive}, nil, ActionReviewSecurity},
{"secret leak flag", IssueTypeBug, PriorityP2, []string{RiskPossibleSecretLeak}, nil, ActionReviewSecurity},
{"security type", IssueTypeSecurity, PriorityP2, nil, nil, ActionReviewSecurity},
{"p0 immediate", IssueTypeBug, PriorityP0, nil, nil, ActionPrioritizeImmediate},
{"request more info", IssueTypeBug, PriorityP1, nil, []string{"version"}, ActionRequestMoreInfo},
{"question convert", IssueTypeQuestion, PriorityP3, nil, nil, ActionConvertToDiscussion},
{"docs update", IssueTypeDocs, PriorityP3, nil, nil, ActionUpdateDocs},
{"ci investigate", IssueTypeCI, PriorityP2, nil, nil, ActionInvestigateCI},
{"default schedule fix", IssueTypeBug, PriorityP2, nil, nil, ActionScheduleFix},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got := recommendedAction(tt.detectedType, tt.priority, tt.riskFlags, tt.missingInformation)
if got != tt.want {
t.Fatalf("recommendedAction = %q, want %q", got, tt.want)
}
})
}
}