oficina / docs Public

Clone
git clone https://amadan.net/oficina/docs

Plain git — no account needed to clone.

Download

Download this file

1package main
2
3import (
4 "bytes"
5 "context"
6 "io"
7 "net"
8 "net/http"
9 "os"
10 "os/exec"
11 "path/filepath"
12 "runtime"
13 "strings"
14 "testing"
15 "time"
16)
17
18// TestReleaseBinaryReportsItsVersion builds the real release artifact and
19// asks the running process what it is. The failure this guards against is
20// a release that answers "dev": rastrillo's BuildVersion default, which
21// the platform's deploy check compares against the release it believes it
22// adopted — so an unstamped binary makes that check structurally unable to
23// fail while still reporting green.
24//
25// The expected value is whatever scripts/build-release.sh stamps, computed
26// the same way it computes it: the tag when this revision carries one, and
27// the abbreviated sha when it does not. Asserting the full sha instead
28// would pass only for untagged builds, which is the case that matters
29// least.
30func TestReleaseBinaryReportsItsVersion(t *testing.T) {
31 root, err := filepath.Abs("../..")
32 if err != nil {
33 t.Fatal(err)
34 }
35 described, err := exec.Command("git", "-C", root, "describe", "--tags", "--always", "HEAD").Output()
36 if err != nil {
37 t.Fatal(err)
38 }
39 want := strings.TrimSpace(string(described))
40 if want == "" || want == "dev" {
41 t.Fatalf("git describe gave %q, which is not a version this test can check for", want)
42 }
43 dir := t.TempDir()
44 binary := filepath.Join(dir, "docs")
45 ctx, cancel := context.WithTimeout(context.Background(), 2*time.Minute)
46 defer cancel()
47 build := exec.CommandContext(ctx, "bash", filepath.Join(root, "scripts/build-release.sh"), binary)
48 build.Dir = root
49 build.Env = append(os.Environ(), "GOOS="+runtime.GOOS, "GOARCH="+runtime.GOARCH)
50 if output, err := build.CombinedOutput(); err != nil {
51 t.Fatalf("build: %v\n%s", err, output)
52 }
53 socket := filepath.Join(dir, "docs.sock")
54 var output bytes.Buffer
55 server := exec.CommandContext(ctx, binary, "-env", "development", "-socket", socket, "-db", filepath.Join(dir, "docs.db"))
56 server.Env = append(os.Environ(), "DOCS_ORIGIN=http://localhost", "DOCS_SEED_ADDRESS=", "DOCS_SAMPLE_DOCUMENTS=0")
57 server.Stdout = &output
58 server.Stderr = &output
59 if err := server.Start(); err != nil {
60 t.Fatal(err)
61 }
62 t.Cleanup(func() {
63 _ = server.Process.Kill()
64 _ = server.Wait()
65 })
66 transport := &http.Transport{DialContext: func(ctx context.Context, _, _ string) (net.Conn, error) {
67 return (&net.Dialer{}).DialContext(ctx, "unix", socket)
68 }}
69 defer transport.CloseIdleConnections()
70 client := &http.Client{Transport: transport, Timeout: time.Second}
71 deadline := time.Now().Add(15 * time.Second)
72 for time.Now().Before(deadline) {
73 response, err := client.Get("http://localhost/api/version")
74 if err != nil {
75 time.Sleep(25 * time.Millisecond)
76 continue
77 }
78 body, readErr := io.ReadAll(response.Body)
79 _ = response.Body.Close()
80 if readErr != nil {
81 t.Fatal(readErr)
82 }
83 if response.StatusCode != http.StatusOK || strings.TrimSpace(string(body)) != want {
84 t.Fatalf("version response %d %q; want %q", response.StatusCode, body, want)
85 }
86 return
87 }
88 _ = server.Process.Kill()
89 _ = server.Wait()
90 t.Fatalf("process did not answer /api/version: %s", output.String())
91}
92