package main import ( "context" "net/http" "net/http/httptest" "testing" ) // A plain member must not be able to tell that /admin exists, and a stranger must be sent to log in. func TestRequireAdmin(t *testing.T) { a := &app{} h := a.requireAdmin(func(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusTeapot) }) for _, tc := range []struct { name string as *member want int }{ {name: "signed out", as: nil, want: http.StatusSeeOther}, {name: "member", as: &member{ID: 1}, want: http.StatusNotFound}, {name: "admin", as: &member{ID: 1, IsAdmin: true}, want: http.StatusTeapot}, } { t.Run(tc.name, func(t *testing.T) { r := httptest.NewRequest("GET", "/admin", nil) if tc.as != nil { r = r.WithContext(context.WithValue(r.Context(), memberKey, tc.as)) } w := httptest.NewRecorder() h(w, r) if w.Code != tc.want { t.Fatalf("status = %d, want %d", w.Code, tc.want) } }) } } // The first account cannot arrive by invite, because minting an invite needs an admin. func TestSeedAdminOnlyOnEmptyDatabase(t *testing.T) { a := testApp(t) ctx := context.Background() cfg := config{adminEmail: "Esa@Example.com", adminName: "Ylläpito", adminPass: "salasana1"} if err := seedAdmin(ctx, a.db, cfg); err != nil { t.Fatal(err) } var name, email string var isAdmin bool if err := a.db.QueryRowContext(ctx, `select name, email, is_admin from users`).Scan(&name, &email, &isAdmin); err != nil { t.Fatal(err) } if !isAdmin || name != "Ylläpito" { t.Fatalf("seeded %q is_admin=%v, want Ylläpito admin", name, isAdmin) } // Login is by lowercased email, so the seed must not smuggle in a capital. if email != "esa@example.com" { t.Fatalf("email = %q, want lowercased", email) } // Re-running on a populated database must not add a second account or reset the first. cfg.adminEmail = "toinen@example.com" if err := seedAdmin(ctx, a.db, cfg); err != nil { t.Fatal(err) } var n int if err := a.db.QueryRowContext(ctx, `select count(*) from users`).Scan(&n); err != nil { t.Fatal(err) } if n != 1 { t.Fatalf("users = %d, want 1", n) } } func TestMigrateIsIdempotent(t *testing.T) { ctx := context.Background() a := testApp(t) // already migrated once if err := migrate(ctx, a.db); err != nil { t.Fatalf("second migrate: %v", err) } if err := sweep(ctx, a.db); err != nil { t.Fatalf("sweep: %v", err) } var n int if err := a.db.QueryRowContext(ctx, `select count(*) from schema_migrations`).Scan(&n); err != nil { t.Fatal(err) } if n != 2 { t.Fatalf("applied migrations = %d, want 2", n) } }