| 1 | //go:build linux && rootrunner |
| 2 | |
| 3 | package host |
| 4 | |
| 5 | import ( |
| 6 | "database/sql" |
| 7 | "encoding/json" |
| 8 | "io" |
| 9 | "net" |
| 10 | "net/http" |
| 11 | "net/url" |
| 12 | "sync/atomic" |
| 13 | "testing" |
| 14 | "time" |
| 15 | |
| 16 | "github.com/carlosframework/platform/internal/provision" |
| 17 | ) |
| 18 | |
| 19 | func plan14WoodstarProgram(t *testing.T, host, endpoint string) (claimUnitProgram, func(*http.Client)) { |
| 20 | t.Helper() |
| 21 | ln, err := net.Listen("tcp", "127.0.0.1:0") |
| 22 | if err != nil { |
| 23 | t.Fatal(err) |
| 24 | } |
| 25 | var contacted atomic.Int64 |
| 26 | srv := &http.Server{Handler: http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { |
| 27 | contacted.Add(1) |
| 28 | io.WriteString(w, `<html><head><title>runner upstream</title></head></html>`) |
| 29 | })} |
| 30 | go srv.Serve(ln) |
| 31 | t.Cleanup(func() { srv.Close() }) |
| 32 | upstream := "http://" + ln.Addr().String() |
| 33 | dbPath := provision.NestedDBPath("/data", host) |
| 34 | p := claimUnitProgram{Schema: 1, Host: host, Args: []string{"-addr", endpoint, "-db", dbPath, "-allow-private"}} |
| 35 | var savedKey string |
| 36 | var savedFetch int64 |
| 37 | return p, func(c *http.Client) { |
| 38 | t.Helper() |
| 39 | resp, err := c.Get("http://tenant/unfurl?url=" + url.QueryEscape(upstream)) |
| 40 | if err != nil { |
| 41 | t.Fatal(err) |
| 42 | } |
| 43 | var card map[string]any |
| 44 | err = json.NewDecoder(resp.Body).Decode(&card) |
| 45 | resp.Body.Close() |
| 46 | if err != nil || resp.StatusCode != http.StatusOK || card["ok"] != false || contacted.Load() != 0 { |
| 47 | t.Fatal("Woodstar containment allowed sibling fetch", resp.Status, card, contacted.Load(), err) |
| 48 | } |
| 49 | db, err := sql.Open("sqlite", dbPath) |
| 50 | if err != nil { |
| 51 | t.Fatal(err) |
| 52 | } |
| 53 | defer db.Close() |
| 54 | var key string |
| 55 | if err := db.QueryRow("SELECT value FROM config WHERE key = 'img_sign_key'").Scan(&key); err != nil || len(key) != 64 { |
| 56 | t.Fatal("Woodstar did not persist its signing key", err) |
| 57 | } |
| 58 | var fetched int64 |
| 59 | if err := db.QueryRow("SELECT fetched_at FROM cards WHERE url = ? AND ok = 0", upstream).Scan(&fetched); err != nil || fetched <= 0 { |
| 60 | t.Fatal("Woodstar did not persist its cache", err, fetched) |
| 61 | } |
| 62 | if savedKey != "" && (savedKey != key || savedFetch != fetched) { |
| 63 | t.Fatal("Woodstar restart lost persistent state") |
| 64 | } |
| 65 | savedKey, savedFetch = key, fetched |
| 66 | control := &http.Client{Timeout: time.Second} |
| 67 | resp, err = control.Get(upstream) |
| 68 | if err != nil { |
| 69 | t.Fatal(err) |
| 70 | } |
| 71 | resp.Body.Close() |
| 72 | if contacted.Swap(0) != 1 { |
| 73 | t.Fatal("upstream control did not connect") |
| 74 | } |
| 75 | } |
| 76 | } |
| 77 | |