Sign in

Search issue titles and bodies, change requests and comments. Private repositories you cannot read are not included.

vole
Clone

Read only, no credentials:

https://rodent.software/git/vole.git

Write over SSH with a registered key:

git clone ssh://git@0.0.0.0:2222/vole.git

A free and open-source forge that lives in your Git repo.

Blame · forge/index/activity_test.go

Line attribution on main · 125 line(s)

4d938fe8
Keenan Nemetz
9d ago
1 package index
2
3 // State changes are the activity feed's closed/reopened/merged events. They come
4 // from metadata commit subjects, so the index derives them from the commits it
5 // already reads, and a rebuild and a delta must agree.
6
7 import (
8 "testing"
9 "time"
10
d37d301f
Keenan Nemetz
17h ago
11 "rodent.software/vole/metadata"
4d938fe8
Keenan Nemetz
9d ago
12 )
13
14 func TestStateChangesAreIndexedFromCommitSubjects(t *testing.T) {
15 t.Parallel()
16 s, m, g := incrementalRepo(t)
17 now := time.Date(2026, 10, 30, 12, 0, 0, 0, time.UTC)
18 iss := createIndexedIssue(t, g, "Closes and reopens", now, nil, nil)
19 if err := s.Ensure(m); err != nil {
20 t.Fatal(err)
21 }
22 if list, err := s.StateChanges(m.ID, 0); err != nil || len(list) != 0 {
23 t.Fatalf("a new issue produced state changes: %+v, %v", list, err)
24 }
25
26 if _, err := metadata.SetIssueState(g, iss.ID, "closed", "keenan"); err != nil {
27 t.Fatal(err)
28 }
29 if err := s.Ensure(m); err != nil {
30 t.Fatal(err)
31 }
32 list, err := s.StateChanges(m.ID, 0)
33 if err != nil {
34 t.Fatal(err)
35 }
36 if len(list) != 1 {
37 t.Fatalf("state changes = %+v, want one close", list)
38 }
39 if list[0].Kind != "issue" || list[0].ID != iss.ID || list[0].State != "closed" || list[0].Actor != "keenan" {
40 t.Fatalf("close event = %+v", list[0])
41 }
42 if list[0].Time.IsZero() {
43 t.Fatal("close event has no time")
44 }
45
46 if _, err := metadata.SetIssueState(g, iss.ID, "open", "wilbur"); err != nil {
47 t.Fatal(err)
48 }
49 if err := s.Ensure(m); err != nil {
50 t.Fatal(err)
51 }
52 list, err = s.StateChanges(m.ID, 0)
53 if err != nil {
54 t.Fatal(err)
55 }
56 if len(list) != 2 {
57 t.Fatalf("state changes = %+v, want a close and a reopen", list)
58 }
59 // Newest first: the reopen is the first row.
60 if list[0].State != "open" || list[0].Actor != "wilbur" {
61 t.Fatalf("newest event = %+v, want the reopen", list[0])
62 }
63 if list[1].State != "closed" {
64 t.Fatalf("older event = %+v, want the close", list[1])
65 }
66 }
67
68 func TestStateChangesDoNotDuplicateOnARefresh(t *testing.T) {
69 t.Parallel()
70 s, m, g := incrementalRepo(t)
71 now := time.Date(2026, 10, 30, 12, 0, 0, 0, time.UTC)
72 iss := createIndexedIssue(t, g, "One close", now, nil, nil)
73 if _, err := metadata.SetIssueState(g, iss.ID, "closed", "keenan"); err != nil {
74 t.Fatal(err)
75 }
76 for i := 0; i < 3; i++ {
77 if err := s.Ensure(m); err != nil {
78 t.Fatal(err)
79 }
80 }
81 list, err := s.StateChanges(m.ID, 0)
82 if err != nil {
83 t.Fatal(err)
84 }
85 if len(list) != 1 {
86 t.Fatalf("state changes = %+v after three refreshes, want one", list)
87 }
88 }
89
90 func TestStateChangesSurviveARebuild(t *testing.T) {
91 t.Parallel()
92 s, m, g := incrementalRepo(t)
93 now := time.Date(2026, 10, 30, 12, 0, 0, 0, time.UTC)
94 iss := createIndexedIssue(t, g, "An issue", now, nil, nil)
95 req := createIndexedRequest(t, g, "A change", now.Add(time.Minute), nil)
96 if _, err := metadata.SetIssueState(g, iss.ID, "closed", "keenan"); err != nil {
97 t.Fatal(err)
98 }
99 if _, err := metadata.SetRequestState(g, req.ID, "closed", "keenan"); err != nil {
100 t.Fatal(err)
101 }
102 if err := s.Ensure(m); err != nil {
103 t.Fatal(err)
104 }
105 before, err := s.StateChanges(m.ID, 0)
106 if err != nil || len(before) != 2 {
107 t.Fatalf("incremental state changes = %+v, %v", before, err)
108 }
109
110 if err := s.IndexRepo(m); err != nil {
111 t.Fatal(err)
112 }
113 after, err := s.StateChanges(m.ID, 0)
114 if err != nil {
115 t.Fatal(err)
116 }
117 if len(after) != len(before) {
118 t.Fatalf("rebuilt state changes = %+v, want %d", after, len(before))
119 }
120 for i := range before {
121 if before[i] != after[i] {
122 t.Fatalf("event %d differs: incremental %+v, rebuilt %+v", i, before[i], after[i])
123 }
124 }
125 }