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

barerepo / cli / e2e_test.go
177 lines · 5.1kb · master
log files threads runs releases config jump to file t
7b321bc barerepo 1mo
1
//go:build crossrepo
7b321bc barerepo 1mo
2
7b321bc barerepo 1mo
3
package cli_test
7b321bc barerepo 1mo
4
7b321bc barerepo 1mo
5
import (
7b321bc barerepo 1mo
6
"context"
7b321bc barerepo 1mo
7
"fmt"
7b321bc barerepo 1mo
8
"net/http"
7b321bc barerepo 1mo
9
"os"
7b321bc barerepo 1mo
10
"os/exec"
7b321bc barerepo 1mo
11
"path/filepath"
7b321bc barerepo 1mo
12
"strings"
7b321bc barerepo 1mo
13
"testing"
7b321bc barerepo 1mo
14
7b321bc barerepo 1mo
15
"github.com/barerepo/server/testserver"
7b321bc barerepo 1mo
16
)
7b321bc barerepo 1mo
17
7b321bc barerepo 1mo
18
var binary string
7b321bc barerepo 1mo
19
7b321bc barerepo 1mo
20
func TestMain(m *testing.M) {
7b321bc barerepo 1mo
21
dir, err := os.MkdirTemp("", "br-e2e-")
7b321bc barerepo 1mo
22
if err != nil {
7b321bc barerepo 1mo
23
panic(err)
7b321bc barerepo 1mo
24
}
7b321bc barerepo 1mo
25
binary = filepath.Join(dir, "br")
7b321bc barerepo 1mo
26
if out, err := exec.Command("go", "build", "-o", binary, "./cmd/br").CombinedOutput(); err != nil {
7b321bc barerepo 1mo
27
fmt.Fprintf(os.Stderr, "building br: %v\n%s", err, out)
7b321bc barerepo 1mo
28
os.Exit(1)
7b321bc barerepo 1mo
29
}
7b321bc barerepo 1mo
30
code := m.Run()
7b321bc barerepo 1mo
31
os.RemoveAll(dir)
7b321bc barerepo 1mo
32
os.Exit(code)
7b321bc barerepo 1mo
33
}
7b321bc barerepo 1mo
34
7b321bc barerepo 1mo
35
func needs(t *testing.T, names ...string) {
7b321bc barerepo 1mo
36
t.Helper()
7b321bc barerepo 1mo
37
for _, name := range names {
7b321bc barerepo 1mo
38
if _, err := exec.LookPath(name); err != nil {
7b321bc barerepo 1mo
39
t.Skipf("%s is not installed", name)
7b321bc barerepo 1mo
40
}
7b321bc barerepo 1mo
41
}
7b321bc barerepo 1mo
42
}
7b321bc barerepo 1mo
43
7b321bc barerepo 1mo
44
func run(t *testing.T, dir, name string, args ...string) string {
7b321bc barerepo 1mo
45
t.Helper()
7b321bc barerepo 1mo
46
out, err := try(t, dir, name, args...)
7b321bc barerepo 1mo
47
if err != nil {
7b321bc barerepo 1mo
48
t.Fatalf("%s %s: %v\n%s", name, strings.Join(args, " "), err, out)
7b321bc barerepo 1mo
49
}
7b321bc barerepo 1mo
50
return out
7b321bc barerepo 1mo
51
}
7b321bc barerepo 1mo
52
7b321bc barerepo 1mo
53
func try(t *testing.T, dir, name string, args ...string) (string, error) {
7b321bc barerepo 1mo
54
t.Helper()
7b321bc barerepo 1mo
55
cmd := exec.Command(name, args...)
7b321bc barerepo 1mo
56
cmd.Dir = dir
7b321bc barerepo 1mo
57
cmd.Env = append(os.Environ(),
7b321bc barerepo 1mo
58
"GIT_AUTHOR_NAME=tester", "GIT_AUTHOR_EMAIL=t@x",
7b321bc barerepo 1mo
59
"GIT_COMMITTER_NAME=tester", "GIT_COMMITTER_EMAIL=t@x",
7b321bc barerepo 1mo
60
"GIT_TERMINAL_PROMPT=0", "GIT_CONFIG_COUNT=1",
7b321bc barerepo 1mo
61
"GIT_CONFIG_KEY_0=credential.helper", "GIT_CONFIG_VALUE_0=")
7b321bc barerepo 1mo
62
out, err := cmd.CombinedOutput()
7b321bc barerepo 1mo
63
return strings.TrimSpace(string(out)), err
7b321bc barerepo 1mo
64
}
7b321bc barerepo 1mo
65
7b321bc barerepo 1mo
66
// br talks to a real barerepo, so only a test that runs both halves catches them drifting apart.
7b321bc barerepo 1mo
67
func TestBrDrivesARealServer(t *testing.T) {
7b321bc barerepo 1mo
68
needs(t, "git", "ssh-keygen", "go")
7b321bc barerepo 1mo
69
in := testserver.New(t)
7b321bc barerepo 1mo
70
john := in.Account(t, "john")
7b321bc barerepo 1mo
71
in.Repo(t, john, "john", "johnbot")
7b321bc barerepo 1mo
72
7b321bc barerepo 1mo
73
work := filepath.Join(t.TempDir(), "c")
7b321bc barerepo 1mo
74
run(t, "", "git", "clone", "-q", in.URLFor(john, "/john/johnbot"), work)
7b321bc barerepo 1mo
75
run(t, work, "git", "checkout", "-q", "-b", "my-fix")
7b321bc barerepo 1mo
76
if err := os.WriteFile(filepath.Join(work, "config.go"),
7b321bc barerepo 1mo
77
[]byte("package main\n\nfunc main() {}\n"), 0o600); err != nil {
7b321bc barerepo 1mo
78
t.Fatal(err)
7b321bc barerepo 1mo
79
}
7b321bc barerepo 1mo
80
run(t, work, "git", "commit", "-qam", "fix the spin")
7b321bc barerepo 1mo
81
7b321bc barerepo 1mo
82
if out := run(t, work, binary, "propose"); !strings.Contains(out, "proposal 1 opened") {
7b321bc barerepo 1mo
83
t.Fatalf("br propose did not open a proposal: %s", out)
7b321bc barerepo 1mo
84
}
7b321bc barerepo 1mo
85
7b321bc barerepo 1mo
86
other := filepath.Join(t.TempDir(), "r")
7b321bc barerepo 1mo
87
run(t, "", "git", "clone", "-q", in.URLFor(john, "/john/johnbot"), other)
7b321bc barerepo 1mo
88
if out := run(t, other, binary, "fetch", "1"); !strings.Contains(out, "prop-1") {
7b321bc barerepo 1mo
89
t.Errorf("br fetch did not make prop-1: %s", out)
7b321bc barerepo 1mo
90
}
7b321bc barerepo 1mo
91
if got := run(t, other, "git", "log", "-1", "--format=%s", "prop-1"); got != "fix the spin" {
7b321bc barerepo 1mo
92
t.Errorf("prop-1 is at %q, want the proposed commit", got)
7b321bc barerepo 1mo
93
}
7b321bc barerepo 1mo
94
7b321bc barerepo 1mo
95
if out := run(t, other, binary, "notes"); !strings.Contains(out, "refs/notes/threads/1") {
7b321bc barerepo 1mo
96
t.Errorf("br notes did not fetch the proposal's thread: %s", out)
7b321bc barerepo 1mo
97
}
7b321bc barerepo 1mo
98
if out := run(t, other, binary, "threads"); !strings.Contains(out, "git log --show-notes=threads/1") {
7b321bc barerepo 1mo
99
t.Errorf("br threads did not list thread 1: %s", out)
7b321bc barerepo 1mo
100
}
7b321bc barerepo 1mo
101
run(t, other, binary, "reply", "1", "-m", "reads fine to me")
7b321bc barerepo 1mo
102
run(t, work, binary, "notes")
7b321bc barerepo 1mo
103
if out := run(t, work, binary, "thread", "1"); !strings.Contains(out, "reads fine to me") {
7b321bc barerepo 1mo
104
t.Errorf("a reply pushed by br did not come back: %s", out)
7b321bc barerepo 1mo
105
}
7b321bc barerepo 1mo
106
}
7b321bc barerepo 1mo
107
7b321bc barerepo 1mo
108
// br auth is the one protocol the client speaks alone, so it is the one that can drift unseen.
7b321bc barerepo 1mo
109
func TestBrAuthTradesASignatureForOneSignInLink(t *testing.T) {
7b321bc barerepo 1mo
110
needs(t, "git", "ssh-keygen", "go")
7b321bc barerepo 1mo
111
in := testserver.New(t)
7b321bc barerepo 1mo
112
7b321bc barerepo 1mo
113
home := t.TempDir()
7b321bc barerepo 1mo
114
if err := os.MkdirAll(filepath.Join(home, ".ssh"), 0o700); err != nil {
7b321bc barerepo 1mo
115
t.Fatal(err)
7b321bc barerepo 1mo
116
}
7b321bc barerepo 1mo
117
key := filepath.Join(home, ".ssh", "id_ed25519")
7b321bc barerepo 1mo
118
run(t, "", "ssh-keygen", "-t", "ed25519", "-N", "", "-C", "june", "-f", key, "-q")
7b321bc barerepo 1mo
119
pub, err := os.ReadFile(key + ".pub")
7b321bc barerepo 1mo
120
if err != nil {
7b321bc barerepo 1mo
121
t.Fatal(err)
7b321bc barerepo 1mo
122
}
7b321bc barerepo 1mo
123
if _, err := in.DB.CreateAccount(context.Background(), "june", string(pub), false); err != nil {
7b321bc barerepo 1mo
124
t.Fatal(err)
7b321bc barerepo 1mo
125
}
7b321bc barerepo 1mo
126
7b321bc barerepo 1mo
127
cmd := exec.Command(binary, "auth", "june", in.URL)
7b321bc barerepo 1mo
128
cmd.Dir = t.TempDir()
7b321bc barerepo 1mo
129
cmd.Env = append(os.Environ(), "HOME="+home)
7b321bc barerepo 1mo
130
raw, err := cmd.CombinedOutput()
7b321bc barerepo 1mo
131
if err != nil {
7b321bc barerepo 1mo
132
t.Fatalf("br auth: %v\n%s", err, raw)
7b321bc barerepo 1mo
133
}
7b321bc barerepo 1mo
134
out := string(raw)
7b321bc barerepo 1mo
135
if !strings.Contains(out, "signed in as june") {
7b321bc barerepo 1mo
136
t.Fatalf("br auth did not sign in: %s", out)
7b321bc barerepo 1mo
137
}
7b321bc barerepo 1mo
138
link := ""
7b321bc barerepo 1mo
139
for _, word := range strings.Fields(out) {
7b321bc barerepo 1mo
140
if strings.Contains(word, "/auth/claim?c=") {
7b321bc barerepo 1mo
141
link = word
7b321bc barerepo 1mo
142
}
7b321bc barerepo 1mo
143
}
7b321bc barerepo 1mo
144
if link == "" {
7b321bc barerepo 1mo
145
t.Fatalf("br auth printed no claim link: %s", out)
7b321bc barerepo 1mo
146
}
7b321bc barerepo 1mo
147
7b321bc barerepo 1mo
148
client := &http.Client{CheckRedirect: func(*http.Request, []*http.Request) error {
7b321bc barerepo 1mo
149
return http.ErrUseLastResponse
7b321bc barerepo 1mo
150
}}
7b321bc barerepo 1mo
151
resp, err := client.Get(link)
7b321bc barerepo 1mo
152
if err != nil {
7b321bc barerepo 1mo
153
t.Fatal(err)
7b321bc barerepo 1mo
154
}
7b321bc barerepo 1mo
155
resp.Body.Close()
7b321bc barerepo 1mo
156
if resp.StatusCode != http.StatusFound || resp.Header.Get("Location") != "/june" {
7b321bc barerepo 1mo
157
t.Fatalf("the claim link answered %d to %q", resp.StatusCode, resp.Header.Get("Location"))
7b321bc barerepo 1mo
158
}
7b321bc barerepo 1mo
159
signed := false
7b321bc barerepo 1mo
160
for _, c := range resp.Cookies() {
7b321bc barerepo 1mo
161
if c.Name == "barerepo_session" && c.Value != "" {
7b321bc barerepo 1mo
162
signed = true
7b321bc barerepo 1mo
163
}
7b321bc barerepo 1mo
164
}
7b321bc barerepo 1mo
165
if !signed {
7b321bc barerepo 1mo
166
t.Error("the claim link set no session")
7b321bc barerepo 1mo
167
}
7b321bc barerepo 1mo
168
7b321bc barerepo 1mo
169
again, err := client.Get(link)
7b321bc barerepo 1mo
170
if err != nil {
7b321bc barerepo 1mo
171
t.Fatal(err)
7b321bc barerepo 1mo
172
}
7b321bc barerepo 1mo
173
again.Body.Close()
7b321bc barerepo 1mo
174
if again.StatusCode != http.StatusUnauthorized {
7b321bc barerepo 1mo
175
t.Errorf("the claim link answered %d the second time, want it spent", again.StatusCode)
7b321bc barerepo 1mo
176
}
7b321bc barerepo 1mo
177
}
history · rawbarerepo 0.1.0