- serve prints a startup summary on a terminal (version, environment, URL, admin, database host and name, pending migrations, plugins, drivers) and logs it as a 'startup summary' record plus 'listening on <addr>' - on SIGINT/SIGTERM serve drains, prints and logs a shutdown report and returns nil (exit 0), or the drain errors (exit 1) - the request log is on by default under diary component http with request_id; the route pattern, never the path, is logged - lagoon.PendingMigrations, conga.Worker.Stats, diary.HideOnTTY, bonfire.IsTerminal and bonfire.Details back the summary and report
124 lines
4.2 KiB
Go
124 lines
4.2 KiB
Go
package surf
|
||
|
||
import (
|
||
"bytes"
|
||
"os"
|
||
"path/filepath"
|
||
"slices"
|
||
"strings"
|
||
"testing"
|
||
|
||
"git.golem15.com/golem15/summercms/modules/backpack"
|
||
"git.golem15.com/golem15/summercms/modules/bonfire"
|
||
"git.golem15.com/golem15/summercms/modules/compass"
|
||
"gocloud.dev/blob"
|
||
)
|
||
|
||
func TestPublishUploadsRequiresURL(t *testing.T) {
|
||
app := serveTestApp(t, "uploads:\n bucket_url: \"\"\n")
|
||
_, err := publishUploads(t.Context(), app)
|
||
if err == nil || !strings.Contains(err.Error(), "bucket_url") {
|
||
t.Fatalf("got %v, want bucket_url error", err)
|
||
}
|
||
}
|
||
|
||
func TestPublishUploadsStoresBucket(t *testing.T) {
|
||
app := serveTestApp(t, "uploads:\n bucket_url: \"mem://\"\n public_path_prefix: \"/storage/uploads\"\n")
|
||
bucket, err := publishUploads(t.Context(), app)
|
||
if err != nil {
|
||
t.Fatal(err)
|
||
}
|
||
t.Cleanup(func() { _ = bucket.Close() })
|
||
got, ok := app.Lookup[*blob.Bucket]()
|
||
if !ok || got != bucket {
|
||
t.Fatal("publishUploads must store the opened *blob.Bucket")
|
||
}
|
||
}
|
||
|
||
func serveTestApp(t *testing.T, storageYAML string) *backpack.App {
|
||
t.Helper()
|
||
dir := t.TempDir()
|
||
if err := os.WriteFile(filepath.Join(dir, "app.yaml"), []byte("name: serve-uploads\n"), 0o644); err != nil {
|
||
t.Fatal(err)
|
||
}
|
||
if err := os.WriteFile(filepath.Join(dir, "storage.yaml"), []byte(storageYAML), 0o644); err != nil {
|
||
t.Fatal(err)
|
||
}
|
||
cfg, err := compass.Open(compass.Options{
|
||
Dir: dir,
|
||
Env: "development",
|
||
Environ: []string{"SUMMER_ENV=development"},
|
||
})
|
||
if err != nil {
|
||
t.Fatal(err)
|
||
}
|
||
return backpack.New(cfg)
|
||
}
|
||
|
||
func TestServeURL(t *testing.T) {
|
||
for _, tc := range []struct{ addr, want string }{
|
||
{":8123", "http://127.0.0.1:8123/"},
|
||
{"127.0.0.1:9000", "http://127.0.0.1:9000/"},
|
||
{"[::1]:8080", "http://[::1]:8080/"},
|
||
{"0.0.0.0:80", "http://127.0.0.1/"},
|
||
{"[::]:8080", "http://127.0.0.1:8080/"},
|
||
{"localhost:3000", "http://localhost:3000/"},
|
||
{"8080", ""},
|
||
{"", ""},
|
||
{"127.0.0.1:", ""},
|
||
} {
|
||
if got := serveURL(tc.addr); got != tc.want {
|
||
t.Errorf("serveURL(%q) = %q, want %q", tc.addr, got, tc.want)
|
||
}
|
||
}
|
||
}
|
||
|
||
// TestServeBanner checks the summary's Admin value and the notes printed
|
||
// after the summary for each admin state.
|
||
func TestServeBanner(t *testing.T) {
|
||
create := "summer admin:create --email you@example.com --superuser"
|
||
for _, tc := range []struct {
|
||
name string
|
||
addr string
|
||
prefix string
|
||
mounted bool
|
||
admins adminPresence
|
||
value string
|
||
notes []bannerLine
|
||
}{
|
||
{"present", ":8123", "/backend", true, adminsPresent, "http://127.0.0.1:8123/backend", nil},
|
||
{"none", ":8123", "/backend", true, adminsNone, "http://127.0.0.1:8123/backend", []bannerLine{
|
||
{warn: true, text: "no administrators yet; create one with " + create}}},
|
||
{"missing table", ":8123", "/backend", true, adminsMissingTable, "http://127.0.0.1:8123/backend", []bannerLine{
|
||
{warn: true, text: "the admin tables do not exist yet; run summer migrate, then " + create}}},
|
||
{"unknown", ":8123", "/backend", true, adminsUnknown, "http://127.0.0.1:8123/backend", []bannerLine{
|
||
{text: "sign in with an administrator; " + create + " creates one"}}},
|
||
{"off", ":8123", "", false, adminsUnknown, "off — no plugin registers an admin controller", []bannerLine{
|
||
{text: "to add an admin, run summer make:admin-controller <vendor.plugin> <Name>, then summer build, summer migrate and " + create + "; the admin needs SUMMER_ADMIN__JWT__SECRET, which summer new writes to .env"}}},
|
||
{"unparsable address", "8080", "/backend", true, adminsPresent, "mounted at /backend", nil},
|
||
} {
|
||
t.Run(tc.name, func(t *testing.T) {
|
||
value, notes := adminStatus(serveURL(tc.addr), tc.prefix, tc.mounted, tc.admins)
|
||
if value != tc.value || !slices.Equal(notes, tc.notes) {
|
||
t.Fatalf("adminStatus:\n got %q %#v\nwant %q %#v", value, notes, tc.value, tc.notes)
|
||
}
|
||
})
|
||
}
|
||
}
|
||
|
||
func TestPrintBanner(t *testing.T) {
|
||
var buf bytes.Buffer
|
||
out := bonfire.NewOutput(strings.NewReader(""), &buf, &buf)
|
||
printBanner(out, []bannerLine{{text: "plain"}, {warn: true, text: "careful"}})
|
||
got := buf.String()
|
||
if !strings.Contains(got, "ℹ plain") || !strings.Contains(got, "⚠ careful") {
|
||
t.Fatalf("printBanner output = %q", got)
|
||
}
|
||
}
|
||
|
||
func TestCountAdminsNilDB(t *testing.T) {
|
||
if got := countAdmins(t.Context(), nil); got != adminsUnknown {
|
||
t.Fatalf("countAdmins(nil) = %v, want adminsUnknown", got)
|
||
}
|
||
}
|