Files
Levyraati26_go/main_test.go
T
Esa Kataja 80f82a82de Add skeleton: config, migrations, startup sweep, two listeners
Step 1 of the build order in docs/decisions.md. Boots, applies migrations
before serving, and serves a health check and an empty admin page.

- 001_init.sql is the full schema from docs/spec.md, including the check
  constraints and indexes the old app lacked
- The startup sweep fails submissions left mid-conversion by a restart; an
  in-process goroutine dies with the process and those rows would otherwise
  say converting forever
- Admin is Basic Auth from env on its own listener, fatal at startup when
  ADMIN_PASSWORD is unset
2026-07-31 19:41:01 +03:00

76 lines
1.9 KiB
Go

package main
import (
"context"
"net/http"
"net/http/httptest"
"os"
"testing"
"github.com/jackc/pgx/v5/pgxpool"
)
func TestRequireAdmin(t *testing.T) {
a := &app{cfg: config{adminUser: "admin", adminPass: "s3cret"}}
h := a.requireAdmin(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusTeapot)
}))
for _, tc := range []struct {
name, user, pass string
auth bool
want int
}{
{name: "no credentials", want: http.StatusUnauthorized},
{name: "wrong password", user: "admin", pass: "hunter2", auth: true, want: http.StatusUnauthorized},
{name: "wrong user", user: "root", pass: "s3cret", auth: true, want: http.StatusUnauthorized},
{name: "correct", user: "admin", pass: "s3cret", auth: true, want: http.StatusTeapot},
} {
t.Run(tc.name, func(t *testing.T) {
r := httptest.NewRequest("GET", "/admin", nil)
if tc.auth {
r.SetBasicAuth(tc.user, tc.pass)
}
w := httptest.NewRecorder()
h.ServeHTTP(w, r)
if w.Code != tc.want {
t.Fatalf("status = %d, want %d", w.Code, tc.want)
}
})
}
}
// Set TEST_DATABASE_URL to run this against a throwaway database.
func TestMigrateIsIdempotent(t *testing.T) {
url := os.Getenv("TEST_DATABASE_URL")
if url == "" {
t.Skip("TEST_DATABASE_URL not set")
}
ctx := context.Background()
pool, err := pgxpool.New(ctx, url)
if err != nil {
t.Fatal(err)
}
defer pool.Close()
if _, err := pool.Exec(ctx, `drop schema public cascade; create schema public`); err != nil {
t.Fatal(err)
}
for i := range 2 {
if err := migrate(ctx, pool); err != nil {
t.Fatalf("migrate run %d: %v", i+1, err)
}
}
if err := sweep(ctx, pool); err != nil {
t.Fatalf("sweep: %v", err)
}
var n int
if err := pool.QueryRow(ctx, `select count(*) from schema_migrations`).Scan(&n); err != nil {
t.Fatal(err)
}
if n != 1 {
t.Fatalf("applied migrations = %d, want 1", n)
}
}