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 "context"
5 "io"
6 "net/http"
7 "strings"
8 "testing"
9)
10
11func TestPythonDepsSkipsStdlibAndMapsNames(t *testing.T) {
12 code := strings.Join([]string{
13 "import os, json",
14 "import requests",
15 "from flask import Flask, jsonify",
16 "import yfinance as yf",
17 "from bs4 import BeautifulSoup",
18 "import yaml",
19 }, "\n")
20 got := names(pythonDeps(code))
21 want := []string{"requests", "flask", "yfinance", "beautifulsoup4", "pyyaml"}
22 if !sameSet(got, want) {
23 t.Errorf("got %v, want %v", got, want)
24 }
25}
26
27func TestJSDepsSkipsRelativeAndBuiltin(t *testing.T) {
28 code := strings.Join([]string{
29 `import express from "express";`,
30 `import { z } from "@hono/zod-validator";`,
31 `const fs = require("node:fs");`,
32 `import local from "./util.js";`,
33 }, "\n")
34 got := names(jsDeps(code))
35 if !sameSet(got, []string{"express", "@hono/zod-validator"}) {
36 t.Errorf("got %v", got)
37 }
38}
39
40func TestGoDepsTrimsToTheModuleRoot(t *testing.T) {
41 code := "import (\n\t\"fmt\"\n\t\"github.com/gin-gonic/gin/binding\"\n\t\"modernc.org/sqlite\"\n)\n"
42 got := names(goDeps(code))
43 if !sameSet(got, []string{"github.com/gin-gonic/gin", "modernc.org/sqlite"}) {
44 t.Errorf("got %v", got)
45 }
46}
47
48func TestDockerRepoNormalises(t *testing.T) {
49 cases := map[string]string{
50 "ollama/ollama:latest": "ollama/ollama",
51 "python:3.12-slim": "library/python",
52 "alpine": "library/alpine",
53 "builder": "",
54 "scratch": "",
55 "ghcr.io/someone/thing:v1": "",
56 "$BASE_IMAGE": "",
57 }
58 for in, want := range cases {
59 if got := dockerRepo(in); got != want {
60 t.Errorf("dockerRepo(%q) = %q, want %q", in, got, want)
61 }
62 }
63}
64
65func TestShellDepsReadsInstallLines(t *testing.T) {
66 code := "pip install flask==3.0.0 requests\nnpm install -g typescript\ndocker run -d --name ollama -p 11434:11434 ollama/ollama\n"
67 deps := shellDeps(code)
68 got := names(deps)
69 if !sameSet(got, []string{"flask", "requests", "typescript", "ollama/ollama"}) {
70 t.Errorf("got %v", got)
71 }
72}
73
74func TestGoProxyEscape(t *testing.T) {
75 if got := goProxyEscape("github.com/BurntSushi/toml"); got != "github.com/!burnt!sushi/toml" {
76 t.Errorf("got %q", got)
77 }
78}
79
80// stubRegistry answers as the four registries would, so the lookup path is
81// exercised without touching the network.
82type stubRegistry struct{ known map[string]bool }
83
84func (s stubRegistry) RoundTrip(r *http.Request) (*http.Response, error) {
85 code := http.StatusNotFound
86 if s.known[r.URL.Host+r.URL.Path] {
87 code = http.StatusOK
88 }
89 return &http.Response{
90 StatusCode: code,
91 Body: io.NopCloser(strings.NewReader("{}")),
92 Header: make(http.Header),
93 Request: r,
94 }, nil
95}
96
97func TestVerifyDepsMarksTheMissingOne(t *testing.T) {
98 client := &http.Client{Transport: stubRegistry{known: map[string]bool{
99 "pypi.org/pypi/flask/json": true,
100 }}}
101 blocks := []CodeBlock{{Lang: "python", Closed: true, Code: "import flask\nimport flask_yahoo_cache\n"}}
102
103 deps := verifyDeps(context.Background(), client, blocks)
104 if len(deps) != 2 {
105 t.Fatalf("want 2 deps, got %+v", deps)
106 }
107 byName := map[string]Dependency{}
108 for _, d := range deps {
109 byName[d.Name] = d
110 }
111 if !byName["flask"].Found || !byName["flask"].Checked {
112 t.Errorf("flask should be found: %+v", byName["flask"])
113 }
114 if byName["flask-yahoo-cache"].Found {
115 t.Errorf("an invented package was reported as real: %+v", byName["flask-yahoo-cache"])
116 }
117 warns := depWarnings(deps)
118 if len(warns) != 1 || !strings.Contains(warns[0], "flask-yahoo-cache") {
119 t.Errorf("want one warning naming the missing package, got %v", warns)
120 }
121}
122
123// A registry that will not answer is not evidence of anything, and saying a
124// real package does not exist is worse than saying nothing.
125func TestVerifyDepsStaysQuietWhenTheRegistryIsDown(t *testing.T) {
126 client := &http.Client{Transport: roundTripFunc(func(*http.Request) (*http.Response, error) {
127 return &http.Response{StatusCode: http.StatusTooManyRequests, Body: io.NopCloser(strings.NewReader("")), Header: make(http.Header)}, nil
128 })}
129 deps := verifyDeps(context.Background(), client, []CodeBlock{{Lang: "python", Closed: true, Code: "import requests\n"}})
130 if len(deps) != 1 || deps[0].Checked {
131 t.Fatalf("a throttled registry should leave the dep unchecked: %+v", deps)
132 }
133 if warns := depWarnings(deps); len(warns) != 0 {
134 t.Errorf("nothing should be warned about, got %v", warns)
135 }
136}
137
138type roundTripFunc func(*http.Request) (*http.Response, error)
139
140func (f roundTripFunc) RoundTrip(r *http.Request) (*http.Response, error) { return f(r) }
141
142func names(deps []Dependency) []string {
143 out := make([]string, 0, len(deps))
144 seen := map[string]bool{}
145 for _, d := range deps {
146 if !seen[d.Name] {
147 seen[d.Name] = true
148 out = append(out, d.Name)
149 }
150 }
151 return out
152}
153
154func sameSet(got, want []string) bool {
155 if len(got) != len(want) {
156 return false
157 }
158 have := map[string]bool{}
159 for _, g := range got {
160 have[g] = true
161 }
162 for _, w := range want {
163 if !have[w] {
164 return false
165 }
166 }
167 return true
168}