File view with blame information shown in the left gutter beside each line.

barerepo / server / internal/proposal/expire_test.go
196 lines · 5.9kb · master
log files threads runs releases config jump to file t
133728e barerepo 1mo
1
package proposal
133728e barerepo 1mo
2
133728e barerepo 1mo
3
import (
133728e barerepo 1mo
4
"context"
133728e barerepo 1mo
5
"os"
133728e barerepo 1mo
6
"os/exec"
133728e barerepo 1mo
7
"path/filepath"
133728e barerepo 1mo
8
"strings"
133728e barerepo 1mo
9
"testing"
133728e barerepo 1mo
10
"time"
133728e barerepo 1mo
11
133728e barerepo 1mo
12
"github.com/barerepo/server/internal/gitx"
133728e barerepo 1mo
13
"github.com/barerepo/server/internal/thread"
133728e barerepo 1mo
14
)
133728e barerepo 1mo
15
133728e barerepo 1mo
16
// seeded is a bare repository with one commit on master, which a proposal ref can point at.
133728e barerepo 1mo
17
func seeded(t *testing.T) string {
133728e barerepo 1mo
18
t.Helper()
133728e barerepo 1mo
19
dir := bare(t)
133728e barerepo 1mo
20
work := t.TempDir()
133728e barerepo 1mo
21
mustGit(t, "", "init", "-q", "-b", "master", work)
133728e barerepo 1mo
22
if err := os.WriteFile(filepath.Join(work, "f"), []byte("hi\n"), 0o644); err != nil {
133728e barerepo 1mo
23
t.Fatal(err)
133728e barerepo 1mo
24
}
133728e barerepo 1mo
25
mustGit(t, work, "add", "-A")
133728e barerepo 1mo
26
mustGit(t, work, "-c", "user.email=t@x", "-c", "user.name=t", "commit", "-qm", "first")
133728e barerepo 1mo
27
mustGit(t, work, "push", "-q", dir, "master")
133728e barerepo 1mo
28
return dir
133728e barerepo 1mo
29
}
133728e barerepo 1mo
30
133728e barerepo 1mo
31
func mustGit(t *testing.T, dir string, args ...string) string {
133728e barerepo 1mo
32
t.Helper()
133728e barerepo 1mo
33
cmd := exec.Command("git", args...)
133728e barerepo 1mo
34
cmd.Dir = dir
133728e barerepo 1mo
35
cmd.Env = append(os.Environ(), "GIT_AUTHOR_NAME=t", "GIT_AUTHOR_EMAIL=t@x",
133728e barerepo 1mo
36
"GIT_COMMITTER_NAME=t", "GIT_COMMITTER_EMAIL=t@x")
133728e barerepo 1mo
37
out, err := cmd.CombinedOutput()
133728e barerepo 1mo
38
if err != nil {
133728e barerepo 1mo
39
t.Fatalf("git %v: %v\n%s", args, err, out)
133728e barerepo 1mo
40
}
133728e barerepo 1mo
41
return strings.TrimSpace(string(out))
133728e barerepo 1mo
42
}
133728e barerepo 1mo
43
133728e barerepo 1mo
44
// Chapter 26: a proposal ref pins commits, so it expires, and the thread that is small stays.
133728e barerepo 1mo
45
func TestExpireDropsTheRefAndKeepsTheThread(t *testing.T) {
133728e barerepo 1mo
46
if _, err := exec.LookPath("git"); err != nil {
133728e barerepo 1mo
47
t.Skip("git is not installed")
133728e barerepo 1mo
48
}
133728e barerepo 1mo
49
ctx := context.Background()
133728e barerepo 1mo
50
dir := seeded(t)
133728e barerepo 1mo
51
tip := mustGit(t, dir, "rev-parse", "master")
133728e barerepo 1mo
52
133728e barerepo 1mo
53
// Two proposals, one touched long ago and one touched now.
133728e barerepo 1mo
54
for _, n := range []int{1, 2} {
133728e barerepo 1mo
55
mustGit(t, dir, "update-ref", Ref(n), tip)
133728e barerepo 1mo
56
meta := thread.Meta{Title: "proposal", State: thread.Open, Ref: Ref(n),
133728e barerepo 1mo
57
Author: "mark", Opened: time.Now()}
133728e barerepo 1mo
58
if err := thread.Write(ctx, dir, n, "open", func(tr *thread.Tree) { tr.Meta = meta }); err != nil {
133728e barerepo 1mo
59
t.Fatal(err)
133728e barerepo 1mo
60
}
133728e barerepo 1mo
61
}
133728e barerepo 1mo
62
133728e barerepo 1mo
63
// Nothing is stale yet, so a sweep with a long window must take nothing.
133728e barerepo 1mo
64
gone, err := Expire(ctx, dir, 180*24*time.Hour, time.Now())
133728e barerepo 1mo
65
if err != nil {
133728e barerepo 1mo
66
t.Fatal(err)
133728e barerepo 1mo
67
}
133728e barerepo 1mo
68
if len(gone) != 0 {
133728e barerepo 1mo
69
t.Fatalf("a fresh proposal was expired: %v", gone)
133728e barerepo 1mo
70
}
133728e barerepo 1mo
71
133728e barerepo 1mo
72
// A year on, both are past the window.
133728e barerepo 1mo
73
gone, err = Expire(ctx, dir, 180*24*time.Hour, time.Now().Add(365*24*time.Hour))
133728e barerepo 1mo
74
if err != nil {
133728e barerepo 1mo
75
t.Fatal(err)
133728e barerepo 1mo
76
}
133728e barerepo 1mo
77
if len(gone) != 2 {
133728e barerepo 1mo
78
t.Fatalf("expired %v, wanted both", gone)
133728e barerepo 1mo
79
}
133728e barerepo 1mo
80
refs, err := gitx.ListRefs(dir, "refs/proposals")
133728e barerepo 1mo
81
if err != nil {
133728e barerepo 1mo
82
t.Fatal(err)
133728e barerepo 1mo
83
}
133728e barerepo 1mo
84
if len(refs) != 0 {
133728e barerepo 1mo
85
t.Errorf("the refs are still here: %v", refs)
133728e barerepo 1mo
86
}
133728e barerepo 1mo
87
// The thread is the discussion and the whole point of keeping it.
133728e barerepo 1mo
88
list, err := thread.List(ctx, dir)
133728e barerepo 1mo
89
if err != nil {
133728e barerepo 1mo
90
t.Fatal(err)
133728e barerepo 1mo
91
}
133728e barerepo 1mo
92
if len(list) != 2 {
133728e barerepo 1mo
93
t.Errorf("expiring a ref took its thread with it: %d threads left", len(list))
133728e barerepo 1mo
94
}
133728e barerepo 1mo
95
if _, err := gitx.Run(ctx, dir, "cat-file", "-e", tip); err != nil {
133728e barerepo 1mo
96
t.Error("the commit is gone before a gc has run, which update-ref alone cannot do")
133728e barerepo 1mo
97
}
133728e barerepo 1mo
98
}
133728e barerepo 1mo
99
133728e barerepo 1mo
100
// A window of zero is expiry switched off, not expiry of everything.
133728e barerepo 1mo
101
func TestExpireOfZeroTakesNothing(t *testing.T) {
133728e barerepo 1mo
102
if _, err := exec.LookPath("git"); err != nil {
133728e barerepo 1mo
103
t.Skip("git is not installed")
133728e barerepo 1mo
104
}
133728e barerepo 1mo
105
ctx := context.Background()
133728e barerepo 1mo
106
dir := seeded(t)
133728e barerepo 1mo
107
mustGit(t, dir, "update-ref", Ref(1), mustGit(t, dir, "rev-parse", "master"))
133728e barerepo 1mo
108
133728e barerepo 1mo
109
gone, err := Expire(ctx, dir, 0, time.Now().Add(365*24*time.Hour))
133728e barerepo 1mo
110
if err != nil {
133728e barerepo 1mo
111
t.Fatal(err)
133728e barerepo 1mo
112
}
133728e barerepo 1mo
113
if len(gone) != 0 {
133728e barerepo 1mo
114
t.Errorf("a zero window expired %v", gone)
133728e barerepo 1mo
115
}
133728e barerepo 1mo
116
}
133728e barerepo 1mo
117
133728e barerepo 1mo
118
// Chapter 26: keep the most recent five retained tips, and the ones a comment is anchored to.
133728e barerepo 1mo
119
func TestPruneRevisionsKeepsFiveAndTheAnchoredOne(t *testing.T) {
133728e barerepo 1mo
120
if _, err := exec.LookPath("git"); err != nil {
133728e barerepo 1mo
121
t.Skip("git is not installed")
133728e barerepo 1mo
122
}
133728e barerepo 1mo
123
ctx := context.Background()
133728e barerepo 1mo
124
dir := seeded(t)
133728e barerepo 1mo
125
tip := mustGit(t, dir, "rev-parse", "master")
133728e barerepo 1mo
126
133728e barerepo 1mo
127
meta := thread.Meta{Title: "a proposal", State: thread.Open, Ref: Ref(1),
133728e barerepo 1mo
128
Author: "mark", Opened: time.Now()}
133728e barerepo 1mo
129
if err := thread.Write(ctx, dir, 1, "open", func(tr *thread.Tree) { tr.Meta = meta }); err != nil {
133728e barerepo 1mo
130
t.Fatal(err)
133728e barerepo 1mo
131
}
133728e barerepo 1mo
132
for k := 1; k <= 8; k++ {
133728e barerepo 1mo
133
mustGit(t, dir, "update-ref", RevisionRef(1, k), tip)
133728e barerepo 1mo
134
}
133728e barerepo 1mo
135
if got := CurrentRevision(dir, 1); got != 9 {
133728e barerepo 1mo
136
t.Fatalf("CurrentRevision = %d, wanted 9", got)
133728e barerepo 1mo
137
}
133728e barerepo 1mo
138
133728e barerepo 1mo
139
// One comment is anchored to revision 2, which is outside the newest five.
133728e barerepo 1mo
140
anchored := thread.Comment{Author: "john", Time: time.Now(), Body: "this line",
133728e barerepo 1mo
141
Anchor: "f:1", Blob: strings.Repeat("a", 40), Revision: 2}
133728e barerepo 1mo
142
if err := thread.Reply(ctx, dir, 1, tip, anchored); err != nil {
133728e barerepo 1mo
143
t.Fatal(err)
133728e barerepo 1mo
144
}
133728e barerepo 1mo
145
133728e barerepo 1mo
146
gone, err := PruneRevisions(ctx, dir, 1, RevisionsKept)
133728e barerepo 1mo
147
if err != nil {
133728e barerepo 1mo
148
t.Fatal(err)
133728e barerepo 1mo
149
}
133728e barerepo 1mo
150
// Eight revisions, five newest kept, revision 2 held by its comment, so 1 and 3 go.
133728e barerepo 1mo
151
if len(gone) != 2 || gone[0] != 1 || gone[1] != 3 {
133728e barerepo 1mo
152
t.Fatalf("pruned %v, wanted [1 3]", gone)
133728e barerepo 1mo
153
}
133728e barerepo 1mo
154
left, err := gitx.ListRefs(dir, RevisionPrefix(1))
133728e barerepo 1mo
155
if err != nil {
133728e barerepo 1mo
156
t.Fatal(err)
133728e barerepo 1mo
157
}
133728e barerepo 1mo
158
if len(left) != 6 {
133728e barerepo 1mo
159
t.Errorf("%d revisions left, wanted 6", len(left))
133728e barerepo 1mo
160
}
133728e barerepo 1mo
161
if _, ok := left[RevisionRef(1, 2)]; !ok {
133728e barerepo 1mo
162
t.Error("the revision a comment is anchored to was deleted")
133728e barerepo 1mo
163
}
133728e barerepo 1mo
164
}
133728e barerepo 1mo
165
133728e barerepo 1mo
166
// A comment that does not say which revision it belongs to pins all of them, per 43.4.
133728e barerepo 1mo
167
func TestAnAnchoredCommentWithNoRevisionHoldsEverything(t *testing.T) {
133728e barerepo 1mo
168
if _, err := exec.LookPath("git"); err != nil {
133728e barerepo 1mo
169
t.Skip("git is not installed")
133728e barerepo 1mo
170
}
133728e barerepo 1mo
171
ctx := context.Background()
133728e barerepo 1mo
172
dir := seeded(t)
133728e barerepo 1mo
173
tip := mustGit(t, dir, "rev-parse", "master")
133728e barerepo 1mo
174
133728e barerepo 1mo
175
meta := thread.Meta{Title: "a proposal", State: thread.Open, Ref: Ref(1),
133728e barerepo 1mo
176
Author: "mark", Opened: time.Now()}
133728e barerepo 1mo
177
if err := thread.Write(ctx, dir, 1, "open", func(tr *thread.Tree) { tr.Meta = meta }); err != nil {
133728e barerepo 1mo
178
t.Fatal(err)
133728e barerepo 1mo
179
}
133728e barerepo 1mo
180
for k := 1; k <= 8; k++ {
133728e barerepo 1mo
181
mustGit(t, dir, "update-ref", RevisionRef(1, k), tip)
133728e barerepo 1mo
182
}
133728e barerepo 1mo
183
old := thread.Comment{Author: "john", Time: time.Now(), Body: "written before revisions were recorded",
133728e barerepo 1mo
184
Anchor: "f:1", Blob: strings.Repeat("b", 40)}
133728e barerepo 1mo
185
if err := thread.Reply(ctx, dir, 1, tip, old); err != nil {
133728e barerepo 1mo
186
t.Fatal(err)
133728e barerepo 1mo
187
}
133728e barerepo 1mo
188
133728e barerepo 1mo
189
gone, err := PruneRevisions(ctx, dir, 1, RevisionsKept)
133728e barerepo 1mo
190
if err != nil {
133728e barerepo 1mo
191
t.Fatal(err)
133728e barerepo 1mo
192
}
133728e barerepo 1mo
193
if len(gone) != 0 {
133728e barerepo 1mo
194
t.Errorf("pruned %v while a comment could not say what it needs", gone)
133728e barerepo 1mo
195
}
133728e barerepo 1mo
196
}
history · rawbarerepo 0.1.0