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

barerepo / server / internal/proposal/counter_test.go
154 lines · 3.8kb · 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/exec"
133728e barerepo 1mo
6
"strings"
133728e barerepo 1mo
7
"sync"
133728e barerepo 1mo
8
"testing"
133728e barerepo 1mo
9
133728e barerepo 1mo
10
"github.com/barerepo/server/internal/gitx"
133728e barerepo 1mo
11
)
133728e barerepo 1mo
12
133728e barerepo 1mo
13
func bare(t *testing.T) string {
133728e barerepo 1mo
14
t.Helper()
133728e barerepo 1mo
15
if _, err := gitx.Version(context.Background()); err != nil {
133728e barerepo 1mo
16
t.Skip("git is not installed")
133728e barerepo 1mo
17
}
133728e barerepo 1mo
18
dir := t.TempDir()
133728e barerepo 1mo
19
cmd := exec.Command(gitx.Bin, "init", "--bare", "-q", "--initial-branch", "master", dir)
133728e barerepo 1mo
20
if out, err := cmd.CombinedOutput(); err != nil {
133728e barerepo 1mo
21
t.Fatalf("init: %v\n%s", err, out)
133728e barerepo 1mo
22
}
133728e barerepo 1mo
23
return dir
133728e barerepo 1mo
24
}
133728e barerepo 1mo
25
133728e barerepo 1mo
26
func TestAllocateCountsUp(t *testing.T) {
133728e barerepo 1mo
27
ctx := context.Background()
133728e barerepo 1mo
28
dir := bare(t)
133728e barerepo 1mo
29
for want := 1; want <= 5; want++ {
133728e barerepo 1mo
30
got, err := Allocate(ctx, dir)
133728e barerepo 1mo
31
if err != nil {
133728e barerepo 1mo
32
t.Fatal(err)
133728e barerepo 1mo
33
}
133728e barerepo 1mo
34
if got != want {
133728e barerepo 1mo
35
t.Fatalf("Allocate = %d, want %d", got, want)
133728e barerepo 1mo
36
}
133728e barerepo 1mo
37
}
133728e barerepo 1mo
38
// The number lives in the repository, so a mirror carries it.
133728e barerepo 1mo
39
if _, _, err := readCounter(ctx, dir); err != nil {
133728e barerepo 1mo
40
t.Fatal(err)
133728e barerepo 1mo
41
}
133728e barerepo 1mo
42
}
133728e barerepo 1mo
43
133728e barerepo 1mo
44
// Chapter 45.2: two simultaneous pushes, two different numbers, twenty times over.
133728e barerepo 1mo
45
func TestAllocateIsAtomic(t *testing.T) {
133728e barerepo 1mo
46
ctx := context.Background()
133728e barerepo 1mo
47
dir := bare(t)
133728e barerepo 1mo
48
133728e barerepo 1mo
49
const n = 20
133728e barerepo 1mo
50
var wg sync.WaitGroup
133728e barerepo 1mo
51
got := make([]int, n)
133728e barerepo 1mo
52
errs := make([]error, n)
133728e barerepo 1mo
53
start := make(chan struct{})
133728e barerepo 1mo
54
for i := 0; i < n; i++ {
133728e barerepo 1mo
55
wg.Add(1)
133728e barerepo 1mo
56
go func(i int) {
133728e barerepo 1mo
57
defer wg.Done()
133728e barerepo 1mo
58
<-start
133728e barerepo 1mo
59
got[i], errs[i] = Allocate(ctx, dir)
133728e barerepo 1mo
60
}(i)
133728e barerepo 1mo
61
}
133728e barerepo 1mo
62
close(start)
133728e barerepo 1mo
63
wg.Wait()
133728e barerepo 1mo
64
133728e barerepo 1mo
65
seen := map[int]bool{}
133728e barerepo 1mo
66
for i, v := range got {
133728e barerepo 1mo
67
if errs[i] != nil {
133728e barerepo 1mo
68
t.Fatalf("allocation %d failed: %v", i, errs[i])
133728e barerepo 1mo
69
}
133728e barerepo 1mo
70
if seen[v] {
133728e barerepo 1mo
71
t.Fatalf("number %d was handed out twice", v)
133728e barerepo 1mo
72
}
133728e barerepo 1mo
73
seen[v] = true
133728e barerepo 1mo
74
}
133728e barerepo 1mo
75
for want := 1; want <= n; want++ {
133728e barerepo 1mo
76
if !seen[want] {
133728e barerepo 1mo
77
t.Errorf("number %d was skipped", want)
133728e barerepo 1mo
78
}
133728e barerepo 1mo
79
}
133728e barerepo 1mo
80
}
133728e barerepo 1mo
81
133728e barerepo 1mo
82
func TestNumber(t *testing.T) {
133728e barerepo 1mo
83
for ref, want := range map[string]int{
133728e barerepo 1mo
84
"refs/proposals/47": 47,
133728e barerepo 1mo
85
"refs/proposals/47/rev/2": 47,
133728e barerepo 1mo
86
"refs/proposals/1": 1,
133728e barerepo 1mo
87
"refs/proposals/new": 0,
133728e barerepo 1mo
88
"refs/heads/master": 0,
133728e barerepo 1mo
89
"refs/proposals/0": 0,
133728e barerepo 1mo
90
"refs/proposals/-1": 0,
133728e barerepo 1mo
91
"refs/proposals/": 0,
133728e barerepo 1mo
92
"": 0,
133728e barerepo 1mo
93
} {
133728e barerepo 1mo
94
if got := Number(ref); got != want {
133728e barerepo 1mo
95
t.Errorf("Number(%q) = %d, want %d", ref, got, want)
133728e barerepo 1mo
96
}
133728e barerepo 1mo
97
}
133728e barerepo 1mo
98
}
133728e barerepo 1mo
99
133728e barerepo 1mo
100
// A revision cannot live under the proposal ref, where git would need a file and directory both.
133728e barerepo 1mo
101
func TestRevisionRefsCanCoexist(t *testing.T) {
133728e barerepo 1mo
102
ctx := context.Background()
133728e barerepo 1mo
103
dir := bare(t)
133728e barerepo 1mo
104
empty, err := gitx.RunStdin(ctx, dir, "", "hash-object", "-w", "--stdin")
133728e barerepo 1mo
105
if err != nil {
133728e barerepo 1mo
106
t.Fatal(err)
133728e barerepo 1mo
107
}
133728e barerepo 1mo
108
sha := strings.TrimSpace(empty)
133728e barerepo 1mo
109
if _, err := gitx.Run(ctx, dir, "update-ref", Ref(47), sha, ""); err != nil {
133728e barerepo 1mo
110
t.Fatal(err)
133728e barerepo 1mo
111
}
133728e barerepo 1mo
112
if _, err := gitx.Run(ctx, dir, "update-ref", RevisionRef(47, 1), sha, ""); err != nil {
133728e barerepo 1mo
113
t.Fatalf("a proposal and its retained revision cannot both exist: %v", err)
133728e barerepo 1mo
114
}
133728e barerepo 1mo
115
}
133728e barerepo 1mo
116
133728e barerepo 1mo
117
func TestRefNames(t *testing.T) {
133728e barerepo 1mo
118
if Ref(47) != "refs/proposals/47" {
133728e barerepo 1mo
119
t.Error(Ref(47))
133728e barerepo 1mo
120
}
133728e barerepo 1mo
121
if RevisionRef(47, 2) != "refs/revisions/47/2" {
133728e barerepo 1mo
122
t.Error(RevisionRef(47, 2))
133728e barerepo 1mo
123
}
133728e barerepo 1mo
124
// Appendix A: the whole layout has to be valid to git.
133728e barerepo 1mo
125
for _, r := range []string{Ref(47), RevisionRef(47, 2), NewRef, CounterRef} {
133728e barerepo 1mo
126
if !gitx.ValidRef(r) {
133728e barerepo 1mo
127
t.Errorf("%q is not a usable ref name", r)
133728e barerepo 1mo
128
}
133728e barerepo 1mo
129
}
133728e barerepo 1mo
130
}
133728e barerepo 1mo
131
133728e barerepo 1mo
132
// A pushed thread leaves the counter behind, and reusing the number merges two conversations.
133728e barerepo 1mo
133
func TestAllocateSkipsNumbersInUse(t *testing.T) {
133728e barerepo 1mo
134
ctx := context.Background()
133728e barerepo 1mo
135
dir := bare(t)
133728e barerepo 1mo
136
empty, err := gitx.RunStdin(ctx, dir, "", "hash-object", "-w", "--stdin")
133728e barerepo 1mo
137
if err != nil {
133728e barerepo 1mo
138
t.Fatal(err)
133728e barerepo 1mo
139
}
133728e barerepo 1mo
140
sha := strings.TrimSpace(empty)
133728e barerepo 1mo
141
// Somebody pushed thread 1 and thread 2 without asking the counter.
133728e barerepo 1mo
142
for _, ref := range []string{"refs/notes/threads/1", "refs/notes/threads/2"} {
133728e barerepo 1mo
143
if _, err := gitx.Run(ctx, dir, "update-ref", ref, sha, ""); err != nil {
133728e barerepo 1mo
144
t.Fatal(err)
133728e barerepo 1mo
145
}
133728e barerepo 1mo
146
}
133728e barerepo 1mo
147
got, err := Allocate(ctx, dir)
133728e barerepo 1mo
148
if err != nil {
133728e barerepo 1mo
149
t.Fatal(err)
133728e barerepo 1mo
150
}
133728e barerepo 1mo
151
if got != 3 {
133728e barerepo 1mo
152
t.Errorf("Allocate = %d, want 3: it handed out a number already in use", got)
133728e barerepo 1mo
153
}
133728e barerepo 1mo
154
}
history · rawbarerepo 0.1.0