kunchenguid--no-mistakes
26f897c1ec
release / release-please (push) Failing after 1m49s
docs / build (push) Failing after 6m34s
release / build-and-upload (arm64, linux) (push) Has been cancelled
release / build-and-upload (arm64, windows) (push) Has been cancelled
release / build-darwin (amd64, darwin) (push) Has been cancelled
release / checksums (push) Has been cancelled
release / finalize (push) Has been cancelled
release / build-darwin (arm64, darwin) (push) Has been cancelled
release / build-and-upload (amd64, linux) (push) Has been cancelled
release / build-and-upload (amd64, windows) (push) Has been cancelled
docs / deploy (push) Has been cancelled
270 行
9.3 KiB
Go
270 行
9.3 KiB
Go
package db
|
|
|
|
import (
|
|
"testing"
|
|
|
|
"github.com/kunchenguid/no-mistakes/internal/types"
|
|
)
|
|
|
|
func TestStepRoundInsertAndGet(t *testing.T) {
|
|
d := openTestDB(t)
|
|
repo, _ := d.InsertRepo("/home/user/project", "git@github.com:user/project.git", "main")
|
|
run, _ := d.InsertRun(repo.ID, "feature", "abc", "def")
|
|
step, _ := d.InsertStepResult(run.ID, types.StepReview)
|
|
|
|
findings := `{"findings":[{"id":"review-1","severity":"warning","description":"unused var"}],"summary":"1 issue"}`
|
|
r, err := d.InsertStepRound(step.ID, 1, "initial", &findings, nil, 1200)
|
|
if err != nil {
|
|
t.Fatalf("insert round: %v", err)
|
|
}
|
|
if r.ID == "" {
|
|
t.Fatal("expected non-empty ID")
|
|
}
|
|
if r.StepResultID != step.ID {
|
|
t.Errorf("step_result_id = %q, want %q", r.StepResultID, step.ID)
|
|
}
|
|
if r.Round != 1 {
|
|
t.Errorf("round = %d, want 1", r.Round)
|
|
}
|
|
if r.Trigger != "initial" {
|
|
t.Errorf("trigger = %q, want %q", r.Trigger, "initial")
|
|
}
|
|
if r.FindingsJSON == nil || *r.FindingsJSON != findings {
|
|
t.Errorf("findings = %v, want %q", r.FindingsJSON, findings)
|
|
}
|
|
if r.DurationMS != 1200 {
|
|
t.Errorf("duration_ms = %d, want 1200", r.DurationMS)
|
|
}
|
|
if r.CreatedAt == 0 {
|
|
t.Error("expected non-zero created_at")
|
|
}
|
|
if r.SelectedFindingIDs != nil {
|
|
t.Errorf("expected nil selected_finding_ids on fresh insert, got %v", r.SelectedFindingIDs)
|
|
}
|
|
if r.SelectionSource != nil {
|
|
t.Errorf("expected nil selection_source on fresh insert, got %v", r.SelectionSource)
|
|
}
|
|
if r.FixSummary != nil {
|
|
t.Errorf("expected nil fix_summary on non-fix round, got %v", r.FixSummary)
|
|
}
|
|
}
|
|
|
|
func TestStepRoundNullFindings(t *testing.T) {
|
|
d := openTestDB(t)
|
|
repo, _ := d.InsertRepo("/home/user/project", "git@github.com:user/project.git", "main")
|
|
run, _ := d.InsertRun(repo.ID, "feature", "abc", "def")
|
|
step, _ := d.InsertStepResult(run.ID, types.StepTest)
|
|
|
|
r, err := d.InsertStepRound(step.ID, 1, "initial", nil, nil, 500)
|
|
if err != nil {
|
|
t.Fatalf("insert round: %v", err)
|
|
}
|
|
if r.FindingsJSON != nil {
|
|
t.Errorf("findings = %v, want nil", r.FindingsJSON)
|
|
}
|
|
}
|
|
|
|
func TestGetRoundsByStep(t *testing.T) {
|
|
d := openTestDB(t)
|
|
repo, _ := d.InsertRepo("/home/user/project", "git@github.com:user/project.git", "main")
|
|
run, _ := d.InsertRun(repo.ID, "feature", "abc", "def")
|
|
step, _ := d.InsertStepResult(run.ID, types.StepLint)
|
|
|
|
findings1 := `{"findings":[{"id":"lint-1","severity":"error","description":"missing check"}],"summary":"1 error"}`
|
|
d.InsertStepRound(step.ID, 1, "initial", &findings1, nil, 800)
|
|
fixSummary := "fix missing check"
|
|
d.InsertStepRound(step.ID, 2, "auto_fix", nil, &fixSummary, 600)
|
|
|
|
rounds, err := d.GetRoundsByStep(step.ID)
|
|
if err != nil {
|
|
t.Fatalf("get rounds: %v", err)
|
|
}
|
|
if len(rounds) != 2 {
|
|
t.Fatalf("got %d rounds, want 2", len(rounds))
|
|
}
|
|
if rounds[0].Round != 1 {
|
|
t.Errorf("first round = %d, want 1", rounds[0].Round)
|
|
}
|
|
if rounds[0].Trigger != "initial" {
|
|
t.Errorf("first trigger = %q, want initial", rounds[0].Trigger)
|
|
}
|
|
if rounds[0].FindingsJSON == nil {
|
|
t.Fatal("expected non-nil findings on round 1")
|
|
}
|
|
if rounds[0].FixSummary != nil {
|
|
t.Errorf("expected nil fix_summary on initial round, got %v", rounds[0].FixSummary)
|
|
}
|
|
if rounds[1].Round != 2 {
|
|
t.Errorf("second round = %d, want 2", rounds[1].Round)
|
|
}
|
|
if rounds[1].Trigger != "auto_fix" {
|
|
t.Errorf("second trigger = %q, want auto_fix", rounds[1].Trigger)
|
|
}
|
|
if rounds[1].FindingsJSON != nil {
|
|
t.Errorf("expected nil findings on round 2, got %v", rounds[1].FindingsJSON)
|
|
}
|
|
if rounds[1].FixSummary == nil || *rounds[1].FixSummary != fixSummary {
|
|
t.Errorf("second fix_summary = %v, want %q", rounds[1].FixSummary, fixSummary)
|
|
}
|
|
}
|
|
|
|
func TestGetRoundsByStepEmpty(t *testing.T) {
|
|
d := openTestDB(t)
|
|
repo, _ := d.InsertRepo("/home/user/project", "git@github.com:user/project.git", "main")
|
|
run, _ := d.InsertRun(repo.ID, "feature", "abc", "def")
|
|
step, _ := d.InsertStepResult(run.ID, types.StepPush)
|
|
|
|
rounds, err := d.GetRoundsByStep(step.ID)
|
|
if err != nil {
|
|
t.Fatalf("get rounds: %v", err)
|
|
}
|
|
if len(rounds) != 0 {
|
|
t.Errorf("got %d rounds, want 0", len(rounds))
|
|
}
|
|
}
|
|
|
|
func TestStepFixSummaries(t *testing.T) {
|
|
d := openTestDB(t)
|
|
repo, _ := d.InsertRepo("/home/user/project", "git@github.com:user/project.git", "main")
|
|
run, _ := d.InsertRun(repo.ID, "feature", "abc", "def")
|
|
step, _ := d.InsertStepResult(run.ID, types.StepReview)
|
|
|
|
findings := `{"findings":[{"id":"review-1","severity":"warning","description":"x"}],"summary":"1"}`
|
|
d.InsertStepRound(step.ID, 1, "initial", &findings, nil, 100)
|
|
s1 := "handle nil pointer in executor"
|
|
d.InsertStepRound(step.ID, 2, "auto_fix", nil, &s1, 100)
|
|
// Legacy fix round without a recorded summary still counts as a fix.
|
|
d.InsertStepRound(step.ID, 3, "user_fix", nil, nil, 100)
|
|
s2 := "tighten log path validation"
|
|
d.InsertStepRound(step.ID, 4, "auto_fix", nil, &s2, 100)
|
|
|
|
got, err := d.StepFixSummaries(step.ID)
|
|
if err != nil {
|
|
t.Fatalf("step fix summaries: %v", err)
|
|
}
|
|
want := []string{s1, "", s2}
|
|
if len(got) != len(want) {
|
|
t.Fatalf("got %d summaries %v, want %d %v", len(got), got, len(want), want)
|
|
}
|
|
for i := range want {
|
|
if got[i] != want[i] {
|
|
t.Errorf("summary[%d] = %q, want %q", i, got[i], want[i])
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestStepRoundStats(t *testing.T) {
|
|
d := openTestDB(t)
|
|
repo, _ := d.InsertRepo("/home/user/project", "git@github.com:user/project.git", "main")
|
|
run, _ := d.InsertRun(repo.ID, "feature", "abc", "def")
|
|
step, _ := d.InsertStepResult(run.ID, types.StepLint)
|
|
|
|
findings := `{"findings":[{"id":"lint-1","action":"auto-fix","description":"missing check"}]}`
|
|
round1, _ := d.InsertStepRound(step.ID, 1, "initial", &findings, nil, 800)
|
|
selected := `["lint-1"]`
|
|
if err := d.SetStepRoundSelection(round1.ID, &selected, RoundSelectionSourceAutoFix); err != nil {
|
|
t.Fatalf("set selection: %v", err)
|
|
}
|
|
fixSummary := "fix missing check"
|
|
d.InsertStepRound(step.ID, 2, "auto_fix", nil, &fixSummary, 600)
|
|
|
|
stats, err := d.StepRoundStats(step.ID)
|
|
if err != nil {
|
|
t.Fatalf("step round stats: %v", err)
|
|
}
|
|
if stats.TotalRounds != 2 {
|
|
t.Fatalf("total rounds = %d, want 2", stats.TotalRounds)
|
|
}
|
|
if stats.FixRounds != 1 {
|
|
t.Fatalf("fix rounds = %d, want 1", stats.FixRounds)
|
|
}
|
|
if stats.LatestRound != 2 || stats.LatestTrigger != "auto_fix" {
|
|
t.Fatalf("latest = round %d trigger %q, want round 2 auto_fix", stats.LatestRound, stats.LatestTrigger)
|
|
}
|
|
if !stats.SelectedForFix || !stats.AutoSelectedForFix {
|
|
t.Fatalf("selection flags = selected %v auto %v, want both true", stats.SelectedForFix, stats.AutoSelectedForFix)
|
|
}
|
|
}
|
|
|
|
func TestStepFixSummariesNoFixRounds(t *testing.T) {
|
|
d := openTestDB(t)
|
|
repo, _ := d.InsertRepo("/home/user/project", "git@github.com:user/project.git", "main")
|
|
run, _ := d.InsertRun(repo.ID, "feature", "abc", "def")
|
|
step, _ := d.InsertStepResult(run.ID, types.StepLint)
|
|
d.InsertStepRound(step.ID, 1, "initial", nil, nil, 100)
|
|
|
|
got, err := d.StepFixSummaries(step.ID)
|
|
if err != nil {
|
|
t.Fatalf("step fix summaries: %v", err)
|
|
}
|
|
if len(got) != 0 {
|
|
t.Errorf("got %v, want no summaries", got)
|
|
}
|
|
}
|
|
|
|
func TestStepRoundCascadeDelete(t *testing.T) {
|
|
d := openTestDB(t)
|
|
repo, _ := d.InsertRepo("/home/user/project", "git@github.com:user/project.git", "main")
|
|
run, _ := d.InsertRun(repo.ID, "feature", "abc", "def")
|
|
step, _ := d.InsertStepResult(run.ID, types.StepReview)
|
|
d.InsertStepRound(step.ID, 1, "initial", nil, nil, 100)
|
|
|
|
if err := d.DeleteRepo(repo.ID); err != nil {
|
|
t.Fatalf("delete repo: %v", err)
|
|
}
|
|
rounds, err := d.GetRoundsByStep(step.ID)
|
|
if err != nil {
|
|
t.Fatalf("get rounds after cascade: %v", err)
|
|
}
|
|
if len(rounds) != 0 {
|
|
t.Errorf("got %d rounds after cascade delete, want 0", len(rounds))
|
|
}
|
|
}
|
|
|
|
func TestSetStepRoundSelectedFindingIDs(t *testing.T) {
|
|
d := openTestDB(t)
|
|
repo, _ := d.InsertRepo("/home/user/project", "git@github.com:user/project.git", "main")
|
|
run, _ := d.InsertRun(repo.ID, "feature", "abc", "def")
|
|
step, _ := d.InsertStepResult(run.ID, types.StepReview)
|
|
|
|
findings := `{"findings":[{"id":"review-1","severity":"warning","description":"x"},{"id":"review-2","severity":"error","description":"y"}],"summary":"2"}`
|
|
r, err := d.InsertStepRound(step.ID, 1, "initial", &findings, nil, 50)
|
|
if err != nil {
|
|
t.Fatalf("insert round: %v", err)
|
|
}
|
|
|
|
selected := `["review-1"]`
|
|
if err := d.SetStepRoundSelection(r.ID, &selected, RoundSelectionSourceUser); err != nil {
|
|
t.Fatalf("set selected: %v", err)
|
|
}
|
|
|
|
rounds, err := d.GetRoundsByStep(step.ID)
|
|
if err != nil {
|
|
t.Fatalf("get rounds: %v", err)
|
|
}
|
|
if len(rounds) != 1 {
|
|
t.Fatalf("expected 1 round, got %d", len(rounds))
|
|
}
|
|
if rounds[0].SelectedFindingIDs == nil || *rounds[0].SelectedFindingIDs != selected {
|
|
t.Errorf("selected_finding_ids = %v, want %q", rounds[0].SelectedFindingIDs, selected)
|
|
}
|
|
if rounds[0].SelectionSource == nil || *rounds[0].SelectionSource != RoundSelectionSourceUser {
|
|
t.Errorf("selection_source = %v, want %q", rounds[0].SelectionSource, RoundSelectionSourceUser)
|
|
}
|
|
|
|
// Clearing the selection resets the column to NULL.
|
|
if err := d.SetStepRoundSelection(r.ID, nil, RoundSelectionSourceUser); err != nil {
|
|
t.Fatalf("clear selected: %v", err)
|
|
}
|
|
rounds, err = d.GetRoundsByStep(step.ID)
|
|
if err != nil {
|
|
t.Fatalf("get rounds: %v", err)
|
|
}
|
|
if rounds[0].SelectedFindingIDs != nil {
|
|
t.Errorf("expected nil after clear, got %v", rounds[0].SelectedFindingIDs)
|
|
}
|
|
if rounds[0].SelectionSource != nil {
|
|
t.Errorf("expected nil selection_source after clear, got %v", rounds[0].SelectionSource)
|
|
}
|
|
}
|