//go:build browser package harness import ( "os" "os/exec" "strings" "testing" "time" ) // bootBudget is how long a failed boot may take to fail. The real // failure takes milliseconds; the hang this guards against lasted // until go test's own ten-minute alarm. const bootBudget = 30 * time.Second // TestAFailedBootFailsPromptly pins the boot path in New. With a // browser that cannot start, chromedp's graceful Cancel waits forever // on a process that never existed (the context watcher takes the one // token Cancel would have read), so New must tear the contexts down // itself and only register Cancel once a browser is up. Measured in a // subprocess, because the hang holds the whole test binary: this // binary runs TestScreenPassesACleanPage again with FIESTA_CHROME // pointing at nothing, and the run has to fail, by the boot's own // name, inside the budget. // // ChromePath first: the subprocess needs no browser, but the policy // does. With none, this fails as every drive does, or skips when // FIESTA_BROWSER_OPTIONAL says so. func TestAFailedBootFailsPromptly(t *testing.T) { ChromePath(t) cmd := exec.Command(os.Args[0], "-test.run=^TestScreenPassesACleanPage$", "-test.count=1", "-test.timeout="+bootBudget.String()) cmd.Env = append(os.Environ(), "FIESTA_CHROME=/nonexistent", "FIESTA_BROWSER_OPTIONAL=") start := time.Now() out, err := cmd.CombinedOutput() took := time.Since(start) if err == nil { t.Fatalf("a boot with FIESTA_CHROME=/nonexistent passed:\n%s", out) } if took > bootBudget { t.Errorf("the failed boot took %s to fail, over the %s budget: the hang is back", took, bootBudget) } for _, want := range []string{"harness: browser boot:", "/nonexistent"} { if !strings.Contains(string(out), want) { t.Errorf("the failure does not say %q; the boot did not fail as itself:\n%s", want, out) } } if strings.Contains(string(out), "test timed out") { t.Errorf("the subprocess hit go test's alarm instead of failing:\n%s", out) } }