~bigbes/sr-ht-ecore

ref: 34cf83d43d19071055e7e7593d0646519771e625 sr-ht-ecore/ecoretest/ecoretest_test.go -rw-r--r-- 6.8 KiB
34cf83d4 — Eugene Blikh follow compare.sr.ht's rename to diff.sr.ht 9 days 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
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
package ecoretest

import (
	"net/http/httptest"
	"strings"
	"testing"

	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"
	"github.com/vaughan0/go-ini"
	"sourcecraft.dev/bigbes/sr-ht-core/crypto"

	"sourcecraft.dev/bigbes/sr-ht-ecore/chrome"
)

// TestConfigHasTheSectionsTheNavRulesNeed runs the config through the very
// consumer it exists for. Every rule of the switcher — canonical order first,
// customs alphabetical after, hub/paste/pages excluded, a configured service
// without an origin skipped — needs a section in the fixture to be exercised at
// all, and the copies this package replaces were each missing a different one.
func TestConfigHasTheSectionsTheNavRulesNeed(t *testing.T) {
	nav := chrome.BuildNav(Config("bench.sr.ht"), "bench.sr.ht")

	var names []string
	for _, item := range nav {
		names = append(names, item.Name)
	}
	assert.Equal(t, []string{
		"git", "lists", "todo", "builds", "man", "meta",
		"bench", "cover", "diff", "dolt", "spec", "tokens",
	}, names)

	for _, item := range nav {
		assert.Equal(t, item.Name == "bench", item.Active, "active flag for %s", item.Name)
		assert.Equal(t, Origin(item.Name+".sr.ht"), item.Origin)
	}
}

// TestConfigCarriesTheServiceItIsBuiltFor: a service this package has never
// heard of still gets a config it appears in.
func TestConfigCarriesTheServiceItIsBuiltFor(t *testing.T) {
	conf := Config("newthing.sr.ht")

	origin, ok := conf.Get("newthing.sr.ht", "origin")
	require.True(t, ok, "an unknown service section must be added")
	assert.Equal(t, "https://newthing.example", origin)

	svc := chrome.NewService(conf, "newthing.sr.ht")
	assert.Equal(t, "https://newthing.example", svc.SelfOrigin())
	assert.Equal(t, SiteName, svc.SiteName())
	assert.Equal(t, "https://meta.example", svc.MetaOrigin())
	assert.Equal(t, "https://hub.example", svc.HubOrigin())

	// A known service is not rewritten, and "" is not a section.
	assert.Equal(t, Origin("bench.sr.ht"), Config("bench.sr.ht")["bench.sr.ht"]["origin"])
	_, hasEmpty := Config("")[""]
	assert.False(t, hasEmpty)
}

// TestOriginsAgreeWithTheConfig pins the one spelling of the fake origins: what
// Origin answers is what a test asserting a rendered link can compare against.
func TestOriginsAgreeWithTheConfig(t *testing.T) {
	conf := Config("")
	for section, values := range conf {
		if !strings.HasSuffix(section, ".sr.ht") {
			continue
		}
		assert.Equal(t, Origin(section), values["origin"], "origin of %s", section)
	}

	assert.Equal(t, "https://git.example", Origin("git.sr.ht"))
	// The section that is configured without an origin, and the non-services.
	assert.Empty(t, Origin(NoOrigin))
	assert.Empty(t, conf[NoOrigin]["origin"])
	assert.Empty(t, Origin("sr.ht"))
	assert.Empty(t, Origin("webhooks"))
}

func TestOverridesApply(t *testing.T) {
	t.Run("set", func(t *testing.T) {
		conf := Config("bench.sr.ht", Set("sr.ht", "environment", "staging"))
		assert.Equal(t, "staging", conf["sr.ht"]["environment"])
		// The rest of the section survives an override of one key.
		assert.Equal(t, SiteName, conf["sr.ht"]["site-name"])
		page := chrome.NewService(conf, "bench.sr.ht").
			Page(httptest.NewRequest("GET", "/", nil), "t", "")
		assert.True(t, page.ShowBanner)
	})

	t.Run("set creates a missing section", func(t *testing.T) {
		conf := Config("", Set("bench.sr.ht", "connection-string", "postgres://x"))
		assert.Equal(t, "postgres://x", conf["bench.sr.ht"]["connection-string"])
		assert.Equal(t, Origin("bench.sr.ht"), conf["bench.sr.ht"]["origin"])
	})

	t.Run("delete", func(t *testing.T) {
		conf := Config("bench.sr.ht", Delete("hub.sr.ht", "meta.sr.ht"))
		assert.NotContains(t, conf, "hub.sr.ht")
		assert.NotContains(t, conf, "meta.sr.ht")
		assert.Empty(t, chrome.NewService(conf, "bench.sr.ht").HubOrigin())
	})

	t.Run("section replaces wholesale", func(t *testing.T) {
		values := map[string]string{"origin": "https://elsewhere.example"}
		conf := Config("bench.sr.ht", Section("git.sr.ht", values))
		assert.Equal(t, ini.Section{"origin": "https://elsewhere.example"}, conf["git.sr.ht"])

		// The caller's map is copied, not aliased: editing either afterwards
		// leaves the other alone.
		values["origin"] = "https://mutated.example"
		assert.Equal(t, "https://elsewhere.example", conf["git.sr.ht"]["origin"])
	})

	t.Run("applied in order, after the base config", func(t *testing.T) {
		conf := Config("bench.sr.ht",
			Set("sr.ht", "site-name", "first"),
			Set("sr.ht", "site-name", "second"))
		assert.Equal(t, "second", conf["sr.ht"]["site-name"])
	})
}

// TestCallsShareNoMutableState is the whole reason Config is a function rather
// than a package-level fixture: the nav tests delete sections and the banner
// tests overwrite keys, and in a shared map the next test reads the wreckage.
func TestCallsShareNoMutableState(t *testing.T) {
	first := Config("bench.sr.ht")
	delete(first, "hub.sr.ht")
	first["sr.ht"]["environment"] = "staging"
	first["git.sr.ht"]["origin"] = "https://mutated.example"

	second := Config("bench.sr.ht")
	assert.Equal(t, "https://hub.example", second["hub.sr.ht"]["origin"])
	assert.Equal(t, Environment, second["sr.ht"]["environment"])
	assert.Equal(t, "https://git.example", second["git.sr.ht"]["origin"])

	// Not merely equal by value: the section maps are distinct allocations, so
	// a mutation of one is invisible to the other in either direction.
	second["sr.ht"]["site-name"] = "late edit"
	assert.Equal(t, SiteName, first["sr.ht"]["site-name"])
}

// TestInitCryptoSealsAndOpens: the bootstrap works, end to end, offline — a
// payload sealed with the installed fernet key opens again, and a signature
// made with the installed webhook key verifies.
func TestInitCryptoSealsAndOpens(t *testing.T) {
	InitCrypto()

	sealed := crypto.Encrypt([]byte("~alice"))
	assert.Equal(t, []byte("~alice"), crypto.DecryptWithoutExpiration(sealed))

	payload := []byte(`{"id":1}`)
	assert.True(t, crypto.Verify(payload, crypto.Sign(payload)))
	nonce, signature := crypto.SignWebhook(payload)
	assert.True(t, crypto.VerifyWebhook(payload, nonce, signature))

	// Idempotent: a second call — another package's TestMain, in a real service
	// — must not rotate the keys the first one sealed with.
	InitCrypto()
	crypto.InitCrypto(Config("bench.sr.ht"))
	assert.Equal(t, []byte("~alice"), crypto.DecryptWithoutExpiration(sealed))
}

// TestConfigCarriesTheKeysCryptoWants guards the two keys by name: crypto reads
// them from a config file and log.Fatals when either is missing, which takes
// the whole test binary with it rather than failing one test.
func TestConfigCarriesTheKeysCryptoWants(t *testing.T) {
	conf := Config("bench.sr.ht")

	networkKey, ok := conf.Get("sr.ht", "network-key")
	require.True(t, ok)
	assert.Equal(t, NetworkKey, networkKey)

	webhookKey, ok := conf.Get("webhooks", "private-key")
	require.True(t, ok)
	assert.Equal(t, WebhookKey, webhookKey)
}