- site_cache_keys_test.go: wireSiteCache on a config without a database - rename the Docker admin test to TestCategoriesAdminFrameworkKeysWin so the unit test owns TestSiteCacheFrameworkKeysWin (one name per test binary)
223 lines
7.4 KiB
Go
223 lines
7.4 KiB
Go
package journal
|
|
|
|
import (
|
|
"bytes"
|
|
"log/slog"
|
|
"strings"
|
|
"sync"
|
|
"testing"
|
|
|
|
"git.golem15.com/golem15/sm-journal-plugin/classes"
|
|
"git.golem15.com/golem15/summercms/modules/backpack"
|
|
"git.golem15.com/golem15/summercms/modules/compass"
|
|
"git.golem15.com/golem15/summercms/modules/cooler"
|
|
)
|
|
|
|
const siteCacheKeysToken = "journal-site-cache-keys-token-0123456789"
|
|
|
|
type keysLogBuffer struct {
|
|
mu sync.Mutex
|
|
buf bytes.Buffer
|
|
}
|
|
|
|
func (b *keysLogBuffer) Write(p []byte) (int, error) {
|
|
b.mu.Lock()
|
|
defer b.mu.Unlock()
|
|
return b.buf.Write(p)
|
|
}
|
|
|
|
func (b *keysLogBuffer) lines() []string {
|
|
b.mu.Lock()
|
|
defer b.mu.Unlock()
|
|
var out []string
|
|
for _, l := range strings.Split(strings.TrimSpace(b.buf.String()), "\n") {
|
|
if l != "" {
|
|
out = append(out, l)
|
|
}
|
|
}
|
|
return out
|
|
}
|
|
|
|
// siteCacheApp returns an app on a config without a database holding values,
|
|
// with slog.Default captured for the test.
|
|
func siteCacheApp(t *testing.T, values map[string]string) (*backpack.App, *keysLogBuffer) {
|
|
t.Helper()
|
|
cfg, err := compass.Open(compass.Options{Dir: t.TempDir(), Environ: []string{}})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
for k, v := range values {
|
|
if err := cfg.Set(k, v); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
}
|
|
buf := &keysLogBuffer{}
|
|
prev := slog.Default()
|
|
slog.SetDefault(slog.New(slog.NewTextHandler(buf, nil)))
|
|
t.Cleanup(func() { slog.SetDefault(prev) })
|
|
return backpack.New(cfg), buf
|
|
}
|
|
|
|
func assertNoPurgeToken(t *testing.T, lines []string) {
|
|
t.Helper()
|
|
for _, l := range lines {
|
|
if strings.Contains(l, siteCacheKeysToken) {
|
|
t.Fatalf("log line carries the token: %s", l)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestSiteCacheFrameworkKeysWin(t *testing.T) {
|
|
framework := map[string]string{
|
|
cooler.SiteCachePurgeURLKey: "http://127.0.0.1:3000/api/__site__/cache/purge",
|
|
cooler.SiteCachePurgeTokenKey: siteCacheKeysToken,
|
|
}
|
|
|
|
t.Run("framework keys only: the Journal publishes nothing and stays quiet", func(t *testing.T) {
|
|
app, logs := siteCacheApp(t, framework)
|
|
if err := (&Plugin{}).wireSiteCache(app); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if p, ok := app.Lookup[*cooler.SiteCachePurger](); ok && p != nil {
|
|
t.Fatal("the Journal published a purger although the framework keys are set")
|
|
}
|
|
if lines := logs.lines(); len(lines) != 0 {
|
|
t.Fatalf("log = %q, want nothing", lines)
|
|
}
|
|
// The framework builds the purger from its own keys.
|
|
if p := cooler.SiteCacheFromApp(app); p == nil || p.Endpoint() != "127.0.0.1:3000/api/__site__/cache/purge" {
|
|
t.Fatalf("cooler.SiteCacheFromApp = %v", p)
|
|
}
|
|
})
|
|
|
|
t.Run("alias keys too: one warning that they are ignored", func(t *testing.T) {
|
|
values := map[string]string{
|
|
classes.SiteCachePurgeURLKey: "http://127.0.0.1:4000/purge",
|
|
classes.SiteCachePurgeTokenKey: "x", // invalid, but ignored
|
|
}
|
|
for k, v := range framework {
|
|
values[k] = v
|
|
}
|
|
app, logs := siteCacheApp(t, values)
|
|
if err := (&Plugin{}).wireSiteCache(app); err != nil {
|
|
t.Fatalf("ignored alias keys must not fail boot: %v", err)
|
|
}
|
|
if p, ok := app.Lookup[*cooler.SiteCachePurger](); ok && p != nil {
|
|
t.Fatal("the Journal published a purger from ignored keys")
|
|
}
|
|
lines := logs.lines()
|
|
if len(lines) != 1 || !strings.Contains(lines[0], "level=WARN") || !strings.Contains(lines[0], "ignored") ||
|
|
!strings.Contains(lines[0], cooler.SiteCachePurgeURLKey) {
|
|
t.Fatalf("log = %q, want one warning naming the framework keys", lines)
|
|
}
|
|
assertNoPurgeToken(t, lines)
|
|
})
|
|
|
|
t.Run("only the framework token set still counts as framework keys", func(t *testing.T) {
|
|
app, _ := siteCacheApp(t, map[string]string{
|
|
cooler.SiteCachePurgeTokenKey: siteCacheKeysToken,
|
|
classes.SiteCachePurgeURLKey: "http://127.0.0.1:4000/purge",
|
|
classes.SiteCachePurgeTokenKey: siteCacheKeysToken,
|
|
})
|
|
if err := (&Plugin{}).wireSiteCache(app); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if p, ok := app.Lookup[*cooler.SiteCachePurger](); ok && p != nil {
|
|
t.Fatal("alias keys were used although a framework key is set")
|
|
}
|
|
})
|
|
}
|
|
|
|
func TestSiteCacheAliasKeysDeprecated(t *testing.T) {
|
|
t.Run("valid alias keys publish a purger with one deprecation warning", func(t *testing.T) {
|
|
app, logs := siteCacheApp(t, map[string]string{
|
|
classes.SiteCachePurgeURLKey: "http://127.0.0.1:4000/api/__site__/cache/purge",
|
|
classes.SiteCachePurgeTokenKey: siteCacheKeysToken,
|
|
})
|
|
if err := (&Plugin{}).wireSiteCache(app); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
p, ok := app.Lookup[*cooler.SiteCachePurger]()
|
|
if !ok || p == nil || p.Endpoint() != "127.0.0.1:4000/api/__site__/cache/purge" {
|
|
t.Fatalf("published purger = %v", p)
|
|
}
|
|
if got := cooler.SiteCacheFromApp(app); got != p {
|
|
t.Fatal("cooler.SiteCacheFromApp did not return the alias purger")
|
|
}
|
|
lines := logs.lines()
|
|
if len(lines) != 1 || !strings.Contains(lines[0], "level=WARN") || !strings.Contains(lines[0], "deprecated") ||
|
|
!strings.Contains(lines[0], cooler.SiteCachePurgeURLKey) || !strings.Contains(lines[0], cooler.SiteCachePurgeTokenKey) {
|
|
t.Fatalf("log = %q, want one deprecation warning naming both framework keys", lines)
|
|
}
|
|
assertNoPurgeToken(t, lines)
|
|
})
|
|
|
|
for _, tc := range []struct {
|
|
name, url, token, key string
|
|
}{
|
|
{"only the alias URL", "http://127.0.0.1:4000/purge", "", classes.SiteCachePurgeTokenKey},
|
|
{"only the alias token", "", siteCacheKeysToken, classes.SiteCachePurgeURLKey},
|
|
{"http to a remote host", "http://example.test/purge", siteCacheKeysToken, classes.SiteCachePurgeURLKey},
|
|
{"a short token", "http://127.0.0.1:4000/purge", "short", classes.SiteCachePurgeTokenKey},
|
|
} {
|
|
t.Run("invalid alias keys fail boot: "+tc.name, func(t *testing.T) {
|
|
app, _ := siteCacheApp(t, map[string]string{
|
|
classes.SiteCachePurgeURLKey: tc.url,
|
|
classes.SiteCachePurgeTokenKey: tc.token,
|
|
})
|
|
err := (&Plugin{}).wireSiteCache(app)
|
|
if err == nil || !strings.Contains(err.Error(), tc.key) {
|
|
t.Fatalf("wireSiteCache = %v, want an error naming %s", err, tc.key)
|
|
}
|
|
if tc.token != "" && strings.Contains(err.Error(), tc.token) {
|
|
t.Fatalf("error %q carries the token", err)
|
|
}
|
|
if p, ok := app.Lookup[*cooler.SiteCachePurger](); ok && p != nil {
|
|
t.Fatal("an invalid alias configuration published a purger")
|
|
}
|
|
})
|
|
}
|
|
|
|
t.Run("an already published purger is kept", func(t *testing.T) {
|
|
app, _ := siteCacheApp(t, map[string]string{
|
|
classes.SiteCachePurgeURLKey: "http://127.0.0.1:4000/purge",
|
|
classes.SiteCachePurgeTokenKey: siteCacheKeysToken,
|
|
})
|
|
first, err := cooler.NewSiteCachePurger("http://127.0.0.1:5000/purge", siteCacheKeysToken)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := app.Publish(first); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := (&Plugin{}).wireSiteCache(app); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if got, _ := app.Lookup[*cooler.SiteCachePurger](); got != first {
|
|
t.Fatal("wireSiteCache replaced a published purger")
|
|
}
|
|
})
|
|
}
|
|
|
|
func TestSiteCacheNoKeys(t *testing.T) {
|
|
app, logs := siteCacheApp(t, nil)
|
|
if err := (&Plugin{}).wireSiteCache(app); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if p, ok := app.Lookup[*cooler.SiteCachePurger](); ok && p != nil {
|
|
t.Fatal("no keys published a purger")
|
|
}
|
|
if p := cooler.SiteCacheFromApp(app); p != nil {
|
|
t.Fatalf("cooler.SiteCacheFromApp = %v, want nil", p)
|
|
}
|
|
if lines := logs.lines(); len(lines) != 0 {
|
|
t.Fatalf("log = %q, want nothing", lines)
|
|
}
|
|
if err := (&Plugin{}).wireSiteCache(nil); err != nil {
|
|
t.Fatalf("wireSiteCache(nil) = %v", err)
|
|
}
|
|
if err := (&Plugin{}).wireSiteCache(backpack.New(nil)); err != nil {
|
|
t.Fatalf("wireSiteCache(no config) = %v", err)
|
|
}
|
|
}
|