repos
/ orchard main

orchard

mirror

Every 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

3.3 KB · 98 lines · Go Raw History
 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}