~james/core

core/spindle/pause_test.go -rw-r--r-- 3.5 KiB
452f17b7 — james chore(import): snapshot james.dad.town/core at f70c71c7696a 14 hours ago
                                                                                
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
package spindle

import (
	"testing"
	"time"

	"github.com/bluesky-social/indigo/atproto/syntax"

	"tangled.org/core/spindle/config"
	"tangled.org/core/spindle/db"
)

const pausedOwner = syntax.DID("did:plc:thespindleowner")

// enroll runs before seed, a repo only gets served if its owner is already admitted
func newClosedPushEnv(t *testing.T, asAdmin bool, enroll func(*db.DB) error) *pushEnv {
	t.Helper()
	w := newWorld(t)
	w.admission = config.AdmissionClosed
	if !asAdmin {
		w.owner = pausedOwner
	}
	repo := w.serveGitRepo(testRepoDid)
	n := w.boot()
	if enroll != nil {
		if err := enroll(n.s.db); err != nil {
			t.Fatal(err)
		}
		// the allowlist xrpc tracks the owner too, or hydrant never backfills them
		n.s.backfill.Track(testOwner)
	}
	w.seed(n, testBob)
	return &pushEnv{w: w, n: n, repo: repo}
}

func listOwner(d *db.DB) error { return db.AddToAllowlist(d, testOwner) }

func inviteOwner(d *db.DB) error {
	code, _, err := d.MintInvite("did:plc:someadmin", time.Now())
	if err != nil {
		return err
	}
	return d.RedeemInvite(code, testOwner, time.Now())
}

func (e *pushEnv) allow(t *testing.T) {
	t.Helper()
	if err := db.AddToAllowlist(e.n.s.db, testOwner); err != nil {
		t.Fatal(err)
	}
}

func (e *pushEnv) disallow(t *testing.T) {
	t.Helper()
	if err := db.RemoveFromAllowlist(e.n.s.db, testOwner); err != nil {
		t.Fatal(err)
	}
}

func (e *pushEnv) pushNext(t *testing.T) string {
	t.Helper()
	uri, err := e.notify(e.n.s, e.firstPush(t))
	if err != nil {
		t.Fatalf("notify: %v", err)
	}
	return string(uri)
}

func TestRemovedFromTheAllowlistPausesTheOwnersRepos(t *testing.T) {
	e := newClosedPushEnv(t, false, listOwner)
	addTestSecret(t, e.n.s, testRepoDid)

	if e.pushNext(t) == "" {
		t.Fatal("setup: an admitted owner's push made no pipeline")
	}
	e.disallow(t)
	if uri := e.pushNext(t); uri != "" {
		t.Fatalf("a push of an owner who was removed from the allow-list made pipeline %q", uri)
	}
	e.wantPipelines(t, 1, "after the owner was removed")
	if got := secretCount(t, e.n.s, testRepoDid); got != 1 {
		t.Fatalf("%d secrets after the owner was removed, want the 1 that was there", got)
	}
	if len(repoRows(t, e.n.s, testRepoDid)) != 1 {
		t.Fatal("the repo row went away with the allow-list entry")
	}

	e.allow(t)
	if e.pushNext(t) == "" {
		t.Fatal("a push made no pipeline after the owner was added back")
	}
	e.wantPipelines(t, 2, "after the owner was added back")
}

func TestOwnerEnrolledByInviteIsPausedAndResumedToo(t *testing.T) {
	e := newClosedPushEnv(t, false, inviteOwner)
	if e.pushNext(t) == "" {
		t.Fatal("setup: an owner enrolled by invite made no pipeline")
	}

	e.disallow(t)
	if uri := e.pushNext(t); uri != "" {
		t.Fatalf("a push of an invited owner who was removed made pipeline %q", uri)
	}
	e.allow(t)
	if e.pushNext(t) == "" {
		t.Fatal("a push made no pipeline after the invited owner was added back")
	}
}

func TestAdminOwnerIsNeverPaused(t *testing.T) {
	e := newClosedPushEnv(t, true, nil)
	if e.pushNext(t) == "" {
		t.Fatal("an admin owner who isn't on the allow-list made no pipeline under closed admission")
	}
}

func TestOpeningAdmissionResumesAPausedOwner(t *testing.T) {
	e := newClosedPushEnv(t, false, listOwner)
	e.disallow(t)
	if uri := e.pushNext(t); uri != "" {
		t.Fatalf("an owner who isn't admitted made pipeline %q", uri)
	}

	// admission is read at boot, opening it takes a restart
	e.n.stop()
	e.w.admission = config.AdmissionOpen
	e.n = e.w.boot()
	if e.pushNext(t) == "" {
		t.Fatal("a push made no pipeline after admission opened")
	}
}