package main import ( "io" "net" "net/http" "os" "os/exec" "path/filepath" "strings" "testing" "time" ) func TestPlaceholderNeverOpensActivationDatabase(t *testing.T) { dir := t.TempDir() binary := filepath.Join(dir, "home-placeholder") build := exec.Command("go", "build", "-o", binary, ".") if out, err := build.CombinedOutput(); err != nil { t.Fatalf("build: %v: %s", err, out) } l, err := net.Listen("tcp", "127.0.0.1:0") if err != nil { t.Fatal(err) } addr := l.Addr().String() l.Close() // The parent is deliberately missing: any database open must fail boot. database := filepath.Join(dir, "absent", "must-not-exist.db") cmd := exec.Command(binary, "-addr", addr, "-db", database) cmd.Env = []string{"PATH=" + os.Getenv("PATH")} if err := cmd.Start(); err != nil { t.Fatal(err) } t.Cleanup(func() { _ = cmd.Process.Kill(); _ = cmd.Wait() }) client := &http.Client{Timeout: time.Second, CheckRedirect: func(*http.Request, []*http.Request) error { return http.ErrUseLastResponse }} origin := "http://" + addr deadline := time.Now().Add(10 * time.Second) for { response, err := client.Get(origin + "/healthz") if err == nil { response.Body.Close() if response.StatusCode == 200 { break } } if time.Now().After(deadline) { t.Fatal("placeholder did not start without secrets and with an unusable database path") } time.Sleep(25 * time.Millisecond) } for path, status := range map[string]int{"/": 200, "/static/brand/icon.svg": 200, "/signin": 404, "/authorize": 404, "/static/brand/": 404} { response, err := client.Get(origin + path) if err != nil { t.Fatal(err) } body, err := io.ReadAll(response.Body) response.Body.Close() if err != nil { t.Fatal(err) } if response.StatusCode != status { t.Errorf("%s: status %d, want %d", path, response.StatusCode, status) } if len(response.Cookies()) != 0 { t.Errorf("%s set cookies", path) } if path == "/" && !strings.Contains(string(body), `href="/static/brand/icon.svg"`) { t.Error("missing favicon") } } if _, err := os.Stat(filepath.Dir(database)); !os.IsNotExist(err) { t.Fatalf("database parent created or unreadable: %v", err) } }