| 1 | diff --git a/Makefile b/Makefile |
| 2 | index 10700c0..fd7f92e 100644 |
| 3 | --- a/Makefile |
| 4 | +++ b/Makefile |
| 5 | @@ -1,4 +1,4 @@ |
| 6 | -.PHONY: test test-race test-internal-race benchmark docker-test docker-build slate |
| 7 | +.PHONY: test test-race test-internal-race benchmark docker-test docker-build linux-test |
| 8 | |
| 9 | TEST_PACKAGES ?= ./... |
| 10 | |
| 11 | @@ -20,5 +20,5 @@ docker-test: |
| 12 | docker-build: |
| 13 | docker build --target runtime -t tinyrelay:local . |
| 14 | |
| 15 | -slate: |
| 16 | - ./scripts/test-slate.sh |
| 17 | +linux-test: |
| 18 | + ./scripts/test-linux.sh |
| 19 | diff --git a/README.md b/README.md |
| 20 | index 1665769..68b7995 100644 |
| 21 | --- a/README.md |
| 22 | +++ b/README.md |
| 23 | @@ -66,7 +66,7 @@ sudo systemctl enable --now tiny |
| 24 | |
| 25 | Keep the data directory on local durable storage. The process exposes `/healthz` and `/readyz`. An optional diagnostics listener provides `/metrics` and protected pprof endpoints. Set `--otlp-endpoint` or `OTEL_EXPORTER_OTLP_ENDPOINT` when exporting traces. |
| 26 | |
| 27 | -See [Personal relay deployment](docs/personal-relay.md) for the current Slate installation. |
| 28 | +See [Personal relay deployment](docs/personal-relay.md) for the reference installation. |
| 29 | |
| 30 | ## Test and diagnose |
| 31 | |
| 32 | @@ -77,4 +77,4 @@ make docker-test |
| 33 | make benchmark |
| 34 | ``` |
| 35 | |
| 36 | -Run the Linux race suite on Slate with `SLATE_HOST=slate ./scripts/test-slate.sh`. Run the conformance harness against a started daemon with `node scripts/conformance/run.mjs`; results are written under `artifacts/conformance/`. |
| 37 | +Run the Linux race suite on a Docker host with `LINUX_HOST=<host> ./scripts/test-linux.sh`. Run the conformance harness against a started daemon with `node scripts/conformance/run.mjs`; results are written under `artifacts/conformance/`. |
| 38 | diff --git a/deploy/slate-tiny.nix b/deploy/slate-tiny.nix |
| 39 | deleted file mode 100644 |
| 40 | index f6218ea..0000000 |
| 41 | --- a/deploy/slate-tiny.nix |
| 42 | +++ /dev/null |
| 43 | @@ -1,54 +0,0 @@ |
| 44 | -{ pkgs, ... }: |
| 45 | -{ |
| 46 | - fileSystems."/srv/tiny" = { |
| 47 | - device = "/dev/disk/by-uuid/98f49cba-bd8c-432d-a91a-41db66920e90"; |
| 48 | - fsType = "ext4"; |
| 49 | - options = [ "noatime" "nofail" "x-systemd.device-timeout=15s" ]; |
| 50 | - }; |
| 51 | - |
| 52 | - services.fstrim.enable = true; |
| 53 | - |
| 54 | - systemd.services.tiny-certificates = { |
| 55 | - description = "Renew tiny HTTPS certificates"; |
| 56 | - after = [ "tiny.service" ]; |
| 57 | - requires = [ "tiny.service" ]; |
| 58 | - unitConfig.RequiresMountsFor = "/srv/tiny"; |
| 59 | - path = [ pkgs.bash pkgs.coreutils pkgs.docker pkgs.openssl pkgs.util-linux ]; |
| 60 | - serviceConfig = { |
| 61 | - Type = "oneshot"; |
| 62 | - ExecStart = "${pkgs.bash}/bin/bash /srv/tiny/deploy/renew-certificates.sh"; |
| 63 | - }; |
| 64 | - }; |
| 65 | - |
| 66 | - systemd.timers.tiny-certificates = { |
| 67 | - wantedBy = [ "timers.target" ]; |
| 68 | - timerConfig = { |
| 69 | - OnCalendar = "daily"; |
| 70 | - Persistent = true; |
| 71 | - RandomizedDelaySec = "1h"; |
| 72 | - }; |
| 73 | - }; |
| 74 | - |
| 75 | - systemd.services.tiny = { |
| 76 | - description = "Personal tiny relay"; |
| 77 | - wantedBy = [ "multi-user.target" ]; |
| 78 | - after = [ "docker.service" "network-online.target" "srv-tiny.mount" ]; |
| 79 | - requires = [ "docker.service" ]; |
| 80 | - bindsTo = [ "srv-tiny.mount" ]; |
| 81 | - wants = [ "network-online.target" ]; |
| 82 | - unitConfig.RequiresMountsFor = "/srv/tiny"; |
| 83 | - path = [ pkgs.docker pkgs.docker-compose pkgs.util-linux ]; |
| 84 | - preStart = '' |
| 85 | - test "$(findmnt -n -o UUID --target /srv/tiny)" = 98f49cba-bd8c-432d-a91a-41db66920e90 |
| 86 | - ''; |
| 87 | - serviceConfig = { |
| 88 | - Type = "oneshot"; |
| 89 | - RemainAfterExit = true; |
| 90 | - WorkingDirectory = "/srv/tiny/deploy"; |
| 91 | - ExecStart = "${pkgs.docker-compose}/bin/docker-compose -f compose.yaml up -d --no-build"; |
| 92 | - ExecStop = "${pkgs.docker-compose}/bin/docker-compose -f compose.yaml down --timeout 30"; |
| 93 | - TimeoutStartSec = 180; |
| 94 | - TimeoutStopSec = 90; |
| 95 | - }; |
| 96 | - }; |
| 97 | -} |
| 98 | diff --git a/deploy/tiny-host.nix b/deploy/tiny-host.nix |
| 99 | new file mode 100644 |
| 100 | index 0000000..f6218ea |
| 101 | --- /dev/null |
| 102 | +++ b/deploy/tiny-host.nix |
| 103 | @@ -0,0 +1,54 @@ |
| 104 | +{ pkgs, ... }: |
| 105 | +{ |
| 106 | + fileSystems."/srv/tiny" = { |
| 107 | + device = "/dev/disk/by-uuid/98f49cba-bd8c-432d-a91a-41db66920e90"; |
| 108 | + fsType = "ext4"; |
| 109 | + options = [ "noatime" "nofail" "x-systemd.device-timeout=15s" ]; |
| 110 | + }; |
| 111 | + |
| 112 | + services.fstrim.enable = true; |
| 113 | + |
| 114 | + systemd.services.tiny-certificates = { |
| 115 | + description = "Renew tiny HTTPS certificates"; |
| 116 | + after = [ "tiny.service" ]; |
| 117 | + requires = [ "tiny.service" ]; |
| 118 | + unitConfig.RequiresMountsFor = "/srv/tiny"; |
| 119 | + path = [ pkgs.bash pkgs.coreutils pkgs.docker pkgs.openssl pkgs.util-linux ]; |
| 120 | + serviceConfig = { |
| 121 | + Type = "oneshot"; |
| 122 | + ExecStart = "${pkgs.bash}/bin/bash /srv/tiny/deploy/renew-certificates.sh"; |
| 123 | + }; |
| 124 | + }; |
| 125 | + |
| 126 | + systemd.timers.tiny-certificates = { |
| 127 | + wantedBy = [ "timers.target" ]; |
| 128 | + timerConfig = { |
| 129 | + OnCalendar = "daily"; |
| 130 | + Persistent = true; |
| 131 | + RandomizedDelaySec = "1h"; |
| 132 | + }; |
| 133 | + }; |
| 134 | + |
| 135 | + systemd.services.tiny = { |
| 136 | + description = "Personal tiny relay"; |
| 137 | + wantedBy = [ "multi-user.target" ]; |
| 138 | + after = [ "docker.service" "network-online.target" "srv-tiny.mount" ]; |
| 139 | + requires = [ "docker.service" ]; |
| 140 | + bindsTo = [ "srv-tiny.mount" ]; |
| 141 | + wants = [ "network-online.target" ]; |
| 142 | + unitConfig.RequiresMountsFor = "/srv/tiny"; |
| 143 | + path = [ pkgs.docker pkgs.docker-compose pkgs.util-linux ]; |
| 144 | + preStart = '' |
| 145 | + test "$(findmnt -n -o UUID --target /srv/tiny)" = 98f49cba-bd8c-432d-a91a-41db66920e90 |
| 146 | + ''; |
| 147 | + serviceConfig = { |
| 148 | + Type = "oneshot"; |
| 149 | + RemainAfterExit = true; |
| 150 | + WorkingDirectory = "/srv/tiny/deploy"; |
| 151 | + ExecStart = "${pkgs.docker-compose}/bin/docker-compose -f compose.yaml up -d --no-build"; |
| 152 | + ExecStop = "${pkgs.docker-compose}/bin/docker-compose -f compose.yaml down --timeout 30"; |
| 153 | + TimeoutStartSec = 180; |
| 154 | + TimeoutStopSec = 90; |
| 155 | + }; |
| 156 | + }; |
| 157 | +} |
| 158 | diff --git a/docs/personal-relay.md b/docs/personal-relay.md |
| 159 | index 9296c37..08f2323 100644 |
| 160 | --- a/docs/personal-relay.md |
| 161 | +++ b/docs/personal-relay.md |
| 162 | @@ -1,6 +1,6 @@ |
| 163 | # Personal relay deployment |
| 164 | |
| 165 | -The personal relay runs on Slate and is available through Tailscale. Open [https://tiny](https://tiny) on this Mac, or use [https://tiny.tailbe516a.ts.net](https://tiny.tailbe516a.ts.net) on your phone with Tailscale connected. |
| 166 | +The personal relay runs on a Linux Docker host and is available through Tailscale. Open [https://tiny](https://tiny) on this Mac, or use [https://tiny.tailbe516a.ts.net](https://tiny.tailbe516a.ts.net) on your phone with Tailscale connected. |
| 167 | |
| 168 | ## Storage |
| 169 | |
| 170 | @@ -22,13 +22,13 @@ The service is `tiny.service`, with certificate renewal scheduled by `tiny-certi |
| 171 | In the Tailscale admin console, open **Machines > tiny > Endpoints** to find the HTTP and HTTPS listeners. The node's key expiry is disabled. |
| 172 | |
| 173 | ```sh |
| 174 | -ssh slate sudo systemctl status tiny |
| 175 | -ssh slate sudo systemctl restart tiny |
| 176 | -ssh slate sudo systemctl status tiny-certificates.timer |
| 177 | -ssh slate docker logs tiny |
| 178 | +ssh <host> sudo systemctl status tiny |
| 179 | +ssh <host> sudo systemctl restart tiny |
| 180 | +ssh <host> sudo systemctl status tiny-certificates.timer |
| 181 | +ssh <host> docker logs tiny |
| 182 | ``` |
| 183 | |
| 184 | -To deploy an update, build the images from a checkout on Slate, then restart the service: |
| 185 | +To deploy an update, build the images from a checkout on the host, then restart the service: |
| 186 | |
| 187 | ```sh |
| 188 | docker build --target runtime -t tiny:dogfood . |
| 189 | diff --git a/docs/testing.md b/docs/testing.md |
| 190 | index 0e29914..3857d2f 100644 |
| 191 | --- a/docs/testing.md |
| 192 | +++ b/docs/testing.md |
| 193 | @@ -1,4 +1,4 @@ |
| 194 | -# Testing and the Linux slate |
| 195 | +# Testing and the Linux host |
| 196 | |
| 197 | The normal development loop is local: |
| 198 | |
| 199 | @@ -9,17 +9,17 @@ make test |
| 200 | |
| 201 | The repository also contains a multistage Docker build. `make docker-test` runs `TEST_PACKAGES` (default `./...`) under Go 1.27.1 on Debian Bookworm with the race detector. `make docker-build` builds the self-hosted runtime image. |
| 202 | |
| 203 | -## Remote slate |
| 204 | +## Remote Linux host |
| 205 | |
| 206 | -`scripts/test-slate.sh` runs the same internal race test in an isolated Docker build on the configured Linux host. It synchronizes the exact worktree, including untracked files, over SSH into a unique directory under `/home/tank/tinyrelay-tests/`; it never runs global Docker cleanup and never edits host configuration. |
| 207 | +`scripts/test-linux.sh` runs the same internal race test in an isolated Docker build on the configured Linux host. It synchronizes the exact worktree, including untracked files, over SSH into a unique directory under `~/tinyrelay-tests/` in the remote home directory; it never runs global Docker cleanup and never edits host configuration. |
| 208 | |
| 209 | ```sh |
| 210 | -SLATE_HOST=slate SLATE_NAME=tinyrelay-review-1 ./scripts/test-slate.sh |
| 211 | +LINUX_HOST=<host> LINUX_NAME=tinyrelay-review-1 ./scripts/test-linux.sh |
| 212 | ``` |
| 213 | |
| 214 | -Useful overrides are `SLATE_PACKAGES` (the default internal package list) and `SLATE_ARTIFACTS` (local artifact destination). The script records UTC time, host, kernel, CPU count, Docker server version, Go version, target platform, and SQLite module version beside the Docker build log, including a status file when the build fails. A unique `SLATE_NAME` is required when multiple runs share a slate host. |
| 215 | +Useful overrides are `LINUX_PACKAGES` (the default internal package list) and `LINUX_ARTIFACTS` (local artifact destination). The script records UTC time, host, kernel, CPU count, Docker server version, Go version, target platform, and SQLite module version beside the Docker build log, including a status file when the build fails. A unique `LINUX_NAME` is required when multiple runs share a host. |
| 216 | |
| 217 | -To run the complete tree on Linux, set `SLATE_PACKAGES='./...'`. |
| 218 | +To run the complete tree on Linux, set `LINUX_PACKAGES='./...'`. |
| 219 | |
| 220 | The runtime image is a small Debian image containing the static Go binary, `ca-certificates`, and `git`. It runs as UID 10001 (`relay`) with `/data` as the writable volume. Bind the relay and diagnostics listeners explicitly; diagnostics should stay on loopback or a protected Tailscale address and must not be published publicly. |
| 221 | |
| 222 | @@ -29,10 +29,10 @@ The checked-in benchmarks provide a repeatable first baseline without claiming a |
| 223 | |
| 224 | ```sh |
| 225 | make benchmark |
| 226 | -SLATE_HOST=slate ./scripts/bench-slate.sh |
| 227 | +LINUX_HOST=<host> ./scripts/bench-linux.sh |
| 228 | ``` |
| 229 | |
| 230 | -`BenchmarkSave`, `BenchmarkQuery`, and `BenchmarkTextSearch` use a local SQLite WAL store with representative seeded events. `BenchmarkFanout` measures only the in-memory broadcast and enqueue path to 10, 100, and 1,000 subscribed clients; it excludes websocket network writes and client-reader scheduling. The slate script records the Linux host, CPU count, Docker/Go/SQLite versions, benchmark output, and exit status under `artifacts/bench/`; use `BENCH_PACKAGES` and `BENCHTIME` for controlled comparisons. Treat these as baselines until a workload and hardware matrix supports a capacity claim. |
| 231 | +`BenchmarkSave`, `BenchmarkQuery`, and `BenchmarkTextSearch` use a local SQLite WAL store with representative seeded events. `BenchmarkFanout` measures only the in-memory broadcast and enqueue path to 10, 100, and 1,000 subscribed clients; it excludes websocket network writes and client-reader scheduling. The benchmark script records the Linux host, CPU count, Docker/Go/SQLite versions, benchmark output, and exit status under `artifacts/bench/`; use `BENCH_PACKAGES` and `BENCHTIME` for controlled comparisons. Treat these as baselines until a workload and hardware matrix supports a capacity claim. |
| 232 | |
| 233 | For Git workloads that include child processes inside Docker, `scripts/observe-git-benchmark.py` captures the benchmark output, host load/memory, and Docker cgroup v2 CPU, memory, I/O, and PID samples every 500ms. It also snapshots authenticated `/metrics`, heap, and goroutine profiles before and after the run. The optional `--cpu-profile` captures one bounded 60-second Go CPU profile; cgroup samples remain the source for child CPU accounting. |
| 234 | |
| 235 | diff --git a/internal/daemon/creation_test.go b/internal/daemon/creation_test.go |
| 236 | index cc41e24..8e82661 100644 |
| 237 | --- a/internal/daemon/creation_test.go |
| 238 | +++ b/internal/daemon/creation_test.go |
| 239 | @@ -72,7 +72,7 @@ func TestInboxSourceFollowsOwnerWithHourlyPull(t *testing.T) { |
| 240 | t.Fatal(err) |
| 241 | } |
| 242 | defer app.Close(ctx) |
| 243 | - meta, err := app.Catalog().Create(ctx, catalog.CreateOptions{Name: "inbox", Owner: creationOwner, Template: "inbox", Source: "https://slate.example/relay"}) |
| 244 | + meta, err := app.Catalog().Create(ctx, catalog.CreateOptions{Name: "inbox", Owner: creationOwner, Template: "inbox", Source: "https://upstream.example/relay"}) |
| 245 | if err != nil { |
| 246 | t.Fatal(err) |
| 247 | } |
| 248 | @@ -91,7 +91,7 @@ func TestInboxSourceFollowsOwnerWithHourlyPull(t *testing.T) { |
| 249 | if !strings.Contains(payload, `"every":1`) || !strings.Contains(payload, "#p") || !strings.Contains(payload, creationOwner) { |
| 250 | t.Fatalf("inbox source job payload = %s", payload) |
| 251 | } |
| 252 | - if strings.Contains(payload, "https://") || !strings.Contains(payload, "wss://slate.example/relay") { |
| 253 | + if strings.Contains(payload, "https://") || !strings.Contains(payload, "wss://upstream.example/relay") { |
| 254 | t.Fatalf("inbox source URL was not converted: %s", payload) |
| 255 | } |
| 256 | } |
| 257 | diff --git a/scripts/bench-linux.sh b/scripts/bench-linux.sh |
| 258 | new file mode 100755 |
| 259 | index 0000000..a9ef77f |
| 260 | --- /dev/null |
| 261 | +++ b/scripts/bench-linux.sh |
| 262 | @@ -0,0 +1,52 @@ |
| 263 | +#!/usr/bin/env bash |
| 264 | +set -euo pipefail |
| 265 | + |
| 266 | +remote_host="${LINUX_HOST:?set LINUX_HOST to the SSH name of the Linux Docker host}" |
| 267 | +name="${LINUX_NAME:-tinyrelay-bench-${USER:-user}-$$}" |
| 268 | +safe_name="$(printf '%s' "$name" | tr -cs 'A-Za-z0-9_.-' '-' | sed 's/^-*//;s/-*$//')" |
| 269 | +remote_root="tinyrelay-tests/${safe_name}" |
| 270 | +image="tinyrelay-bench-${safe_name}" |
| 271 | +packages="${BENCH_PACKAGES:-./internal/storage ./internal/relay}" |
| 272 | +benchtime="${BENCHTIME:-5s}" |
| 273 | +stamp="$(date -u +%Y%m%dT%H%M%SZ)" |
| 274 | +local_artifacts="${BENCH_ARTIFACTS:-artifacts/bench/${safe_name}/${stamp}}" |
| 275 | +mkdir -p "$local_artifacts" |
| 276 | +packages_b64="$(printf '%s' "$packages" | base64 | tr -d '\n')" |
| 277 | + |
| 278 | +COPYFILE_DISABLE=1 tar --no-xattrs \ |
| 279 | + --exclude=.git --exclude=.DS_Store --exclude=.playwright-cli \ |
| 280 | + --exclude=output --exclude=artifacts --exclude=node_modules \ |
| 281 | + -cf - . | ssh "$remote_host" "mkdir -p '$remote_root' && tar -xf - -C '$remote_root'" |
| 282 | + |
| 283 | +set +e |
| 284 | +ssh "$remote_host" "LINUX_PACKAGES_B64='$packages_b64' sh -s -- '$remote_root' '$image' '$stamp' '$benchtime'" <<'REMOTE' |
| 285 | +set -eu |
| 286 | +remote_root=$1 |
| 287 | +image=$2 |
| 288 | +stamp=$3 |
| 289 | +benchtime=$4 |
| 290 | +packages=$(printf '%s' "$LINUX_PACKAGES_B64" | base64 -d) |
| 291 | +artifact_dir="$remote_root/artifacts/$stamp" |
| 292 | +mkdir -p "$artifact_dir" |
| 293 | +{ |
| 294 | + date -u +%Y-%m-%dT%H:%M:%SZ |
| 295 | + printf 'host='; hostname |
| 296 | + printf 'kernel='; uname -a |
| 297 | + printf 'cpu='; nproc |
| 298 | + printf 'docker='; docker version --format '{{.Server.Version}}' |
| 299 | +} > "$artifact_dir/metadata.txt" |
| 300 | +set +e |
| 301 | +docker build --target bench --build-arg BENCH_PACKAGES="$packages" --build-arg BENCHTIME="$benchtime" -t "$image" "$remote_root" > "$artifact_dir/bench.log" 2>&1 |
| 302 | +status=$? |
| 303 | +cat "$artifact_dir/bench.log" |
| 304 | +printf '%s\n' "$status" > "$artifact_dir/status" |
| 305 | +exit "$status" |
| 306 | +REMOTE |
| 307 | +status=$? |
| 308 | +set -e |
| 309 | + |
| 310 | +scp -q "$remote_host:$remote_root/artifacts/$stamp/metadata.txt" "$local_artifacts/metadata.txt" || true |
| 311 | +scp -q "$remote_host:$remote_root/artifacts/$stamp/status" "$local_artifacts/status" || true |
| 312 | +scp -q "$remote_host:$remote_root/artifacts/$stamp/bench.log" "$local_artifacts/bench.log" || true |
| 313 | +printf 'artifacts: %s\n' "$local_artifacts" |
| 314 | +exit "$status" |
| 315 | diff --git a/scripts/bench-slate.sh b/scripts/bench-slate.sh |
| 316 | deleted file mode 100755 |
| 317 | index 0f61344..0000000 |
| 318 | --- a/scripts/bench-slate.sh |
| 319 | +++ /dev/null |
| 320 | @@ -1,52 +0,0 @@ |
| 321 | -#!/usr/bin/env bash |
| 322 | -set -euo pipefail |
| 323 | - |
| 324 | -remote_host="${SLATE_HOST:-slate}" |
| 325 | -name="${SLATE_NAME:-tinyrelay-bench-${USER:-user}-$$}" |
| 326 | -safe_name="$(printf '%s' "$name" | tr -cs 'A-Za-z0-9_.-' '-' | sed 's/^-*//;s/-*$//')" |
| 327 | -remote_root="/home/tank/tinyrelay-tests/${safe_name}" |
| 328 | -image="tinyrelay-bench-${safe_name}" |
| 329 | -packages="${BENCH_PACKAGES:-./internal/storage ./internal/relay}" |
| 330 | -benchtime="${BENCHTIME:-5s}" |
| 331 | -stamp="$(date -u +%Y%m%dT%H%M%SZ)" |
| 332 | -local_artifacts="${BENCH_ARTIFACTS:-artifacts/bench/${safe_name}/${stamp}}" |
| 333 | -mkdir -p "$local_artifacts" |
| 334 | -packages_b64="$(printf '%s' "$packages" | base64 | tr -d '\n')" |
| 335 | - |
| 336 | -COPYFILE_DISABLE=1 tar --no-xattrs \ |
| 337 | - --exclude=.git --exclude=.DS_Store --exclude=.playwright-cli \ |
| 338 | - --exclude=output --exclude=artifacts --exclude=node_modules \ |
| 339 | - -cf - . | ssh "$remote_host" "mkdir -p '$remote_root' && tar -xf - -C '$remote_root'" |
| 340 | - |
| 341 | -set +e |
| 342 | -ssh "$remote_host" "SLATE_PACKAGES_B64='$packages_b64' sh -s -- '$remote_root' '$image' '$stamp' '$benchtime'" <<'REMOTE' |
| 343 | -set -eu |
| 344 | -remote_root=$1 |
| 345 | -image=$2 |
| 346 | -stamp=$3 |
| 347 | -benchtime=$4 |
| 348 | -packages=$(printf '%s' "$SLATE_PACKAGES_B64" | base64 -d) |
| 349 | -artifact_dir="$remote_root/artifacts/$stamp" |
| 350 | -mkdir -p "$artifact_dir" |
| 351 | -{ |
| 352 | - date -u +%Y-%m-%dT%H:%M:%SZ |
| 353 | - printf 'host='; hostname |
| 354 | - printf 'kernel='; uname -a |
| 355 | - printf 'cpu='; nproc |
| 356 | - printf 'docker='; docker version --format '{{.Server.Version}}' |
| 357 | -} > "$artifact_dir/metadata.txt" |
| 358 | -set +e |
| 359 | -docker build --target bench --build-arg BENCH_PACKAGES="$packages" --build-arg BENCHTIME="$benchtime" -t "$image" "$remote_root" > "$artifact_dir/bench.log" 2>&1 |
| 360 | -status=$? |
| 361 | -cat "$artifact_dir/bench.log" |
| 362 | -printf '%s\n' "$status" > "$artifact_dir/status" |
| 363 | -exit "$status" |
| 364 | -REMOTE |
| 365 | -status=$? |
| 366 | -set -e |
| 367 | - |
| 368 | -scp -q "$remote_host:$remote_root/artifacts/$stamp/metadata.txt" "$local_artifacts/metadata.txt" || true |
| 369 | -scp -q "$remote_host:$remote_root/artifacts/$stamp/status" "$local_artifacts/status" || true |
| 370 | -scp -q "$remote_host:$remote_root/artifacts/$stamp/bench.log" "$local_artifacts/bench.log" || true |
| 371 | -printf 'artifacts: %s\n' "$local_artifacts" |
| 372 | -exit "$status" |
| 373 | diff --git a/scripts/test-linux.sh b/scripts/test-linux.sh |
| 374 | new file mode 100755 |
| 375 | index 0000000..1aa938c |
| 376 | --- /dev/null |
| 377 | +++ b/scripts/test-linux.sh |
| 378 | @@ -0,0 +1,65 @@ |
| 379 | +#!/usr/bin/env bash |
| 380 | +set -euo pipefail |
| 381 | + |
| 382 | +remote_host="${LINUX_HOST:?set LINUX_HOST to the SSH name of the Linux Docker host}" |
| 383 | +name="${LINUX_NAME:-tinyrelay-${USER:-user}-$$}" |
| 384 | +safe_name="$(printf '%s' "$name" | tr -cs 'A-Za-z0-9_.-' '-' | sed 's/^-*//;s/-*$//')" |
| 385 | +if [[ -z "$safe_name" ]]; then |
| 386 | + echo "invalid empty LINUX_NAME" >&2 |
| 387 | + exit 2 |
| 388 | +fi |
| 389 | +remote_root="tinyrelay-tests/${safe_name}" |
| 390 | +image="tinyrelay-linux-${safe_name}" |
| 391 | +packages="${LINUX_PACKAGES:-./internal/auth ./internal/blob ./internal/catalog ./internal/policy ./internal/relay ./internal/replication ./internal/storage ./internal/syncprotocol ./internal/telemetry ./internal/templates ./internal/work}" |
| 392 | +stamp="$(date -u +%Y%m%dT%H%M%SZ)" |
| 393 | +local_artifacts="${LINUX_ARTIFACTS:-artifacts/linux/${safe_name}/${stamp}}" |
| 394 | +mkdir -p "$local_artifacts" |
| 395 | +packages_b64="$(printf '%s' "$packages" | base64 | tr -d '\n')" |
| 396 | + |
| 397 | +echo "syncing worktree to ${remote_host}:${remote_root}" |
| 398 | +COPYFILE_DISABLE=1 tar \ |
| 399 | + --exclude=.git \ |
| 400 | + --exclude=.DS_Store \ |
| 401 | + --exclude=.playwright-cli \ |
| 402 | + --exclude=output \ |
| 403 | + --exclude=artifacts \ |
| 404 | + --exclude=node_modules \ |
| 405 | + --no-xattrs \ |
| 406 | + -cf - . | ssh "$remote_host" "mkdir -p '$remote_root' && tar -xf - -C '$remote_root'" |
| 407 | + |
| 408 | +echo "running Linux race tests in ${image}" |
| 409 | +set +e |
| 410 | +ssh "$remote_host" "LINUX_PACKAGES_B64='$packages_b64' sh -s -- '$remote_root' '$image' '$stamp'" <<'REMOTE' |
| 411 | +set -eu |
| 412 | +remote_root=$1 |
| 413 | +image=$2 |
| 414 | +stamp=$3 |
| 415 | +packages=$(printf '%s' "$LINUX_PACKAGES_B64" | base64 -d) |
| 416 | +artifact_dir="$remote_root/artifacts/$stamp" |
| 417 | +mkdir -p "$artifact_dir" |
| 418 | +{ |
| 419 | + date -u +%Y-%m-%dT%H:%M:%SZ |
| 420 | + printf 'host='; hostname |
| 421 | + printf 'kernel='; uname -a |
| 422 | + printf 'cpu='; nproc |
| 423 | + printf 'docker='; docker version --format '{{.Server.Version}}' |
| 424 | +} > "$artifact_dir/metadata.txt" |
| 425 | +set +e |
| 426 | +docker build --target test --build-arg TEST_PACKAGES="$packages" -t "$image" "$remote_root" > "$artifact_dir/docker-build.log" 2>&1 |
| 427 | +build_status=$? |
| 428 | +cat "$artifact_dir/docker-build.log" |
| 429 | +printf '%s\n' "$build_status" > "$artifact_dir/status" |
| 430 | +if [ "$build_status" -eq 0 ]; then |
| 431 | + docker run --rm "$image" sh -c 'export PATH=/usr/local/go/bin:/usr/local/bin:$PATH; /usr/local/go/bin/go version; /usr/local/go/bin/go env GOOS GOARCH GOVERSION; sed -n "s/^.*modernc.org\/sqlite v//p" go.mod | head -1' > "$artifact_dir/runtime.txt" |
| 432 | +fi |
| 433 | +exit "$build_status" |
| 434 | +REMOTE |
| 435 | +remote_status=$? |
| 436 | +set -e |
| 437 | + |
| 438 | +scp -q "$remote_host:$remote_root/artifacts/$stamp/metadata.txt" "$local_artifacts/metadata.txt" || true |
| 439 | +scp -q "$remote_host:$remote_root/artifacts/$stamp/runtime.txt" "$local_artifacts/runtime.txt" || true |
| 440 | +scp -q "$remote_host:$remote_root/artifacts/$stamp/status" "$local_artifacts/status" || true |
| 441 | +scp -q "$remote_host:$remote_root/artifacts/$stamp/docker-build.log" "$local_artifacts/docker-build.log" || true |
| 442 | +printf 'artifacts: %s\n' "$local_artifacts" |
| 443 | +exit "$remote_status" |
| 444 | diff --git a/scripts/test-slate.sh b/scripts/test-slate.sh |
| 445 | deleted file mode 100755 |
| 446 | index 2c82bcd..0000000 |
| 447 | --- a/scripts/test-slate.sh |
| 448 | +++ /dev/null |
| 449 | @@ -1,65 +0,0 @@ |
| 450 | -#!/usr/bin/env bash |
| 451 | -set -euo pipefail |
| 452 | - |
| 453 | -remote_host="${SLATE_HOST:-slate}" |
| 454 | -name="${SLATE_NAME:-tinyrelay-${USER:-user}-$$}" |
| 455 | -safe_name="$(printf '%s' "$name" | tr -cs 'A-Za-z0-9_.-' '-' | sed 's/^-*//;s/-*$//')" |
| 456 | -if [[ -z "$safe_name" ]]; then |
| 457 | - echo "invalid empty SLATE_NAME" >&2 |
| 458 | - exit 2 |
| 459 | -fi |
| 460 | -remote_root="/home/tank/tinyrelay-tests/${safe_name}" |
| 461 | -image="tinyrelay-slate-${safe_name}" |
| 462 | -packages="${SLATE_PACKAGES:-./internal/auth ./internal/blob ./internal/catalog ./internal/policy ./internal/relay ./internal/replication ./internal/storage ./internal/syncprotocol ./internal/telemetry ./internal/templates ./internal/work}" |
| 463 | -stamp="$(date -u +%Y%m%dT%H%M%SZ)" |
| 464 | -local_artifacts="${SLATE_ARTIFACTS:-artifacts/slate/${safe_name}/${stamp}}" |
| 465 | -mkdir -p "$local_artifacts" |
| 466 | -packages_b64="$(printf '%s' "$packages" | base64 | tr -d '\n')" |
| 467 | - |
| 468 | -echo "syncing worktree to ${remote_host}:${remote_root}" |
| 469 | -COPYFILE_DISABLE=1 tar \ |
| 470 | - --exclude=.git \ |
| 471 | - --exclude=.DS_Store \ |
| 472 | - --exclude=.playwright-cli \ |
| 473 | - --exclude=output \ |
| 474 | - --exclude=artifacts \ |
| 475 | - --exclude=node_modules \ |
| 476 | - --no-xattrs \ |
| 477 | - -cf - . | ssh "$remote_host" "mkdir -p '$remote_root' && tar -xf - -C '$remote_root'" |
| 478 | - |
| 479 | -echo "running Linux race tests in ${image}" |
| 480 | -set +e |
| 481 | -ssh "$remote_host" "SLATE_PACKAGES_B64='$packages_b64' sh -s -- '$remote_root' '$image' '$stamp'" <<'REMOTE' |
| 482 | -set -eu |
| 483 | -remote_root=$1 |
| 484 | -image=$2 |
| 485 | -stamp=$3 |
| 486 | -packages=$(printf '%s' "$SLATE_PACKAGES_B64" | base64 -d) |
| 487 | -artifact_dir="$remote_root/artifacts/$stamp" |
| 488 | -mkdir -p "$artifact_dir" |
| 489 | -{ |
| 490 | - date -u +%Y-%m-%dT%H:%M:%SZ |
| 491 | - printf 'host='; hostname |
| 492 | - printf 'kernel='; uname -a |
| 493 | - printf 'cpu='; nproc |
| 494 | - printf 'docker='; docker version --format '{{.Server.Version}}' |
| 495 | -} > "$artifact_dir/metadata.txt" |
| 496 | -set +e |
| 497 | -docker build --target test --build-arg TEST_PACKAGES="$packages" -t "$image" "$remote_root" > "$artifact_dir/docker-build.log" 2>&1 |
| 498 | -build_status=$? |
| 499 | -cat "$artifact_dir/docker-build.log" |
| 500 | -printf '%s\n' "$build_status" > "$artifact_dir/status" |
| 501 | -if [ "$build_status" -eq 0 ]; then |
| 502 | - docker run --rm "$image" sh -c 'export PATH=/usr/local/go/bin:/usr/local/bin:$PATH; /usr/local/go/bin/go version; /usr/local/go/bin/go env GOOS GOARCH GOVERSION; sed -n "s/^.*modernc.org\/sqlite v//p" go.mod | head -1' > "$artifact_dir/runtime.txt" |
| 503 | -fi |
| 504 | -exit "$build_status" |
| 505 | -REMOTE |
| 506 | -remote_status=$? |
| 507 | -set -e |
| 508 | - |
| 509 | -scp -q "$remote_host:$remote_root/artifacts/$stamp/metadata.txt" "$local_artifacts/metadata.txt" || true |
| 510 | -scp -q "$remote_host:$remote_root/artifacts/$stamp/runtime.txt" "$local_artifacts/runtime.txt" || true |
| 511 | -scp -q "$remote_host:$remote_root/artifacts/$stamp/status" "$local_artifacts/status" || true |
| 512 | -scp -q "$remote_host:$remote_root/artifacts/$stamp/docker-build.log" "$local_artifacts/docker-build.log" || true |
| 513 | -printf 'artifacts: %s\n' "$local_artifacts" |
| 514 | -exit "$remote_status" |