orchard
mirrorEvery site I host, in one repo, along with the Cloudflare Tunnel and Caddy that front them. It's all Go, Vite, and SQLite, and it runs on a desktop at home with nothing listening on an inbound port.
blogbuncaddycloudflare-tunneldockergogolanghomelabhtml-templatemonorepoself-hostedseosqlitestatic-sitetypstuptime-monitoringviteweb-analytics
1package main
2
3import (
4 "encoding/json"
5 "net/http"
6 "net/http/httptest"
7 "os"
8 "os/exec"
9 "path/filepath"
10 "strings"
11 "testing"
12)
13
14// chat.bythewood.me could list these repositories and read nothing inside them,
15// so every question about Isaac's own code ended with the model guessing raw
16// addresses and collecting 404s. These two endpoints are what it reads instead,
17// so the shape they answer in is a contract.
18func TestAPITreeAndFile(t *testing.T) {
19 if _, err := exec.LookPath("git"); err != nil {
20 t.Skip("git not on PATH")
21 }
22 root := t.TempDir()
23 work := filepath.Join(root, "work")
24 git := func(dir string, args ...string) {
25 t.Helper()
26 cmd := exec.Command("git", args...)
27 cmd.Dir = dir
28 cmd.Env = append(os.Environ(),
29 "GIT_AUTHOR_NAME=Test", "[email protected]",
30 "GIT_COMMITTER_NAME=Test", "[email protected]",
31 "GIT_CONFIG_NOSYSTEM=1", "HOME="+root)
32 if out, err := cmd.CombinedOutput(); err != nil {
33 t.Fatalf("git %s: %v: %s", strings.Join(args, " "), err, out)
34 }
35 }
36 if err := os.MkdirAll(filepath.Join(work, "tools"), 0o755); err != nil {
37 t.Fatal(err)
38 }
39 if err := os.WriteFile(filepath.Join(work, "tools", "web.go"),
40 []byte("package tools\n"), 0o644); err != nil {
41 t.Fatal(err)
42 }
43 git(work, "init", "-q", "-b", "main")
44 git(work, "add", "-A")
45 git(work, "commit", "-qm", "first commit")
46 git(root, "clone", "-q", "--bare", work, filepath.Join(root, "demo.git"))
47
48 s := &site{store: NewStore(root)}
49 defer s.store.Close()
50
51 call := func(h http.HandlerFunc, pattern, target string) (int, map[string]any) {
52 t.Helper()
53 mux := http.NewServeMux()
54 mux.HandleFunc(pattern, h)
55 w := httptest.NewRecorder()
56 mux.ServeHTTP(w, httptest.NewRequest(http.MethodGet, target, nil))
57 var out map[string]any
58 _ = json.Unmarshal(w.Body.Bytes(), &out)
59 return w.Code, out
60 }
61
62 code, out := call(s.apiTree, "GET /api/repos/{name}/tree/{rev}", "/api/repos/demo/tree/HEAD")
63 if code != http.StatusOK {
64 t.Fatalf("listing the top of the repository answered %d: %v", code, out)
65 }
66 entries, _ := out["entries"].([]any)
67 if len(entries) == 0 {
68 t.Fatalf("the top level listed nothing: %v", out)
69 }
70
71 code, out = call(s.apiTree, "GET /api/repos/{name}/tree/{rev}/{path...}", "/api/repos/demo/tree/HEAD/tools")
72 if code != http.StatusOK {
73 t.Fatalf("listing a directory answered %d: %v", code, out)
74 }
75 if entries, _ := out["entries"].([]any); len(entries) != 1 {
76 t.Errorf("the tools directory listed %v", out["entries"])
77 }
78
79 code, out = call(s.apiFile, "GET /api/repos/{name}/file/{rev}/{path...}", "/api/repos/demo/file/HEAD/tools/web.go")
80 if code != http.StatusOK {
81 t.Fatalf("reading a file answered %d: %v", code, out)
82 }
83 if out["text"] != "package tools\n" {
84 t.Errorf("the file came back as %q", out["text"])
85 }
86
87 // A missing path is a 404, which is what orchard_code falls through on when
88 // it tries a file first and the path turns out to be a directory.
89 code, _ = call(s.apiFile, "GET /api/repos/{name}/file/{rev}/{path...}", "/api/repos/demo/file/HEAD/tools")
90 if code != http.StatusNotFound {
91 t.Errorf("a directory read as a file answered %d, want 404", code)
92 }
93 code, _ = call(s.apiTree, "GET /api/repos/{name}/tree/{rev}", "/api/repos/nope/tree/HEAD")
94 if code != http.StatusNotFound {
95 t.Errorf("an unknown repository answered %d, want 404", code)
96 }
97}