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"`