main
e2e_test.go
Eric Bower
·
2026-02-25
1package patchbin
2
3import (
4 "context"
5 "log/slog"
6 "os"
7 "testing"
8 "time"
9
10 "github.com/picosh/patchbin/fixtures"
11 "github.com/picosh/patchbin/util"
12)
13
14func TestE2E(t *testing.T) {
15 testSingleTenantE2E(t)
16 testMultiTenantE2E(t)
17}
18
19func testSingleTenantE2E(t *testing.T) {
20 t.Log("single tenant end-to-end tests")
21 dataDir := util.CreateTmpDir()
22 defer func() {
23 _ = os.RemoveAll(dataDir)
24 }()
25 suite := setupTest(dataDir, cfgSingleTenantTmpl)
26 ctx, cancel := context.WithCancel(context.Background())
27 defer cancel()
28 s := GitSshServer(ctx, suite.cfg)
29 go func() {
30 _ = s.ListenAndServe()
31 }()
32 // Hack to wait for startup
33 time.Sleep(time.Millisecond * 100)
34
35 // Users are auto-created on first use, no registration needed
36 t.Log("User should be able to create a PR")
37 suite.userKey.MustCmd(suite.patch, "pr create test")
38
39 t.Log("Admin should also be able to create a PR")
40 suite.adminKey.MustCmd(suite.patch, "pr create test")
41
42 t.Log("List PRs")
43 suite.userKey.MustCmd(nil, "pr ls")
44}
45
46func testMultiTenantE2E(t *testing.T) {
47 t.Log("multi tenant end-to-end tests")
48 dataDir := util.CreateTmpDir()
49 defer func() {
50 _ = os.RemoveAll(dataDir)
51 }()
52 suite := setupTest(dataDir, cfgMultiTenantTmpl)
53 ctx, cancel := context.WithCancel(context.Background())
54 defer cancel()
55 s := GitSshServer(ctx, suite.cfg)
56 go func() {
57 _ = s.ListenAndServe()
58 }()
59
60 time.Sleep(time.Millisecond * 100)
61
62 // Users are auto-created on first use, no registration needed
63 // In zero-trust model, no repo creation needed
64 // Anyone can create PRs in any repo
65
66 t.Log("User creates PR")
67 output := suite.userKey.MustCmd(suite.patch, "pr create test")
68 userPRID := util.ParsePRID(output)
69
70 t.Log("User edits PR title (only creator can edit)")
71 suite.userKey.MustCmd(nil, "pr edit "+userPRID+" Updated title")
72
73 t.Log("User changes PR status to open (only creator can change status)")
74 suite.userKey.MustCmd(nil, "pr open "+userPRID)
75
76 t.Log("Admin creates PR")
77 suite.adminKey.MustCmd(suite.patch, "pr create admin-repo")
78
79 t.Log("Admin adds patchset to user's PR (zero-trust: anyone can add)")
80 suite.adminKey.MustCmd(suite.otherPatch, "pr add "+userPRID)
81
82 t.Log("User creates another PR and sets to open")
83 output2 := suite.userKey.MustCmd(suite.patch, "pr create draft-repo")
84 draftPRID := util.ParsePRID(output2)
85 suite.userKey.MustCmd(nil, "pr open "+draftPRID)
86
87 t.Log("List PRs")
88 suite.userKey.MustCmd(nil, "pr ls")
89
90 t.Log("View event logs")
91 suite.userKey.MustCmd(nil, "logs")
92}
93
94type TestSuite struct {
95 cfg *GitCfg
96 userKey util.UserSSH
97 adminKey util.UserSSH
98 patch []byte
99 otherPatch []byte
100}
101
102func setupTest(dataDir string, cfgTmpl string) TestSuite {
103 opts := &slog.HandlerOptions{
104 AddSource: true,
105 }
106 logger := slog.New(
107 slog.NewTextHandler(os.Stdout, opts),
108 )
109
110 adminKey, userKey := util.GenerateKeys()
111 cfgPath := util.CreateCfgFile(dataDir, cfgTmpl, adminKey)
112 LoadConfigFile(cfgPath, logger)
113 cfg := NewGitCfg(logger)
114
115 // so outputs dont show dates
116 cfg.TimeFormat = ""
117
118 patch, err := fixtures.Fixtures.ReadFile("single.patch")
119 if err != nil {
120 panic(err)
121 }
122 otherPatch, err := fixtures.Fixtures.ReadFile("with-cover.patch")
123 if err != nil {
124 panic(err)
125 }
126
127 return TestSuite{cfg, userKey, adminKey, patch, otherPatch}
128}
129
130var cfgSingleTenantTmpl = `
131url = "localhost"
132data_dir = %q
133admins = [%q]
134time_format = "01/02/2006 15:04:05 07:00"`
135
136var cfgMultiTenantTmpl = `
137url = "localhost"
138data_dir = %q
139admins = [%q]
140time_format = "01/02/2006 15:04:05 07:00"`