Pin the e2e relay to a zooid digest (#578)
This commit is contained in:
parent
0776befc17
commit
ec835f7cfb
3 changed files with 45 additions and 16 deletions
|
|
@ -425,13 +425,17 @@ stranger.
|
||||||
The suite is not run by agents (see CLAUDE.md).
|
The suite is not run by agents (see CLAUDE.md).
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
pnpm exec playwright install # once
|
pnpm exec playwright install # once
|
||||||
docker pull gitea.coracle.social/coracle/zooid:latest # once; the harness never pulls
|
pnpm test # starts and stops the container itself
|
||||||
pnpm test # starts and stops the container itself
|
|
||||||
```
|
```
|
||||||
|
|
||||||
Every test skips when docker is unavailable, rather than failing.
|
Every test skips when docker is unavailable, rather than failing.
|
||||||
|
|
||||||
|
The relay is one pinned zooid, named by digest in `harness/zooid/relay.ts`, and the harness fetches
|
||||||
|
that image the first time a machine needs it. So a spec asserting relay behaviour runs against the
|
||||||
|
relay the diff names, and needing a newer zooid is a bump in that file. `ZOOID_IMAGE` overrides the
|
||||||
|
pin, which is how a spec is tried against a zooid built from a checkout.
|
||||||
|
|
||||||
A test fails when the app broke while it ran, whatever it asserted: an uncaught exception on any
|
A test fails when the app broke while it ran, whatever it asserted: an uncaught exception on any
|
||||||
of its pages, or code of ours the browser refused under the content security policy. A refusal
|
of its pages, or code of ours the browser refused under the content security policy. A refusal
|
||||||
reaches the console and nothing else, which is how a policy that had rotted past the script it
|
reaches the console and nothing else, which is how a policy that had rotted past the script it
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,9 @@ name: flotilla-e2e-zooid
|
||||||
|
|
||||||
services:
|
services:
|
||||||
relay:
|
relay:
|
||||||
image: gitea.coracle.social/coracle/zooid:latest
|
# Pinned by digest in e2e/harness/zooid/relay.ts, the only thing that brings this container up.
|
||||||
|
# No default, for the same reason the config mount below has none.
|
||||||
|
image: ${ZOOID_IMAGE:?staged by e2e/harness/zooid/relay.ts, which starts this container}
|
||||||
# The harness dials this published port and sends a `Host` per virtual relay, which is what the
|
# The harness dials this published port and sends a `Host` per virtual relay, which is what the
|
||||||
# dispatcher matches against the `host` in each file under config/.
|
# dispatcher matches against the `host` in each file under config/.
|
||||||
ports:
|
ports:
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,13 @@ import type {PublishOptions} from "./types"
|
||||||
import {connectToZooid, port, requestZooid} from "./transport"
|
import {connectToZooid, port, requestZooid} from "./transport"
|
||||||
import type {ZooidConnection} from "./transport"
|
import type {ZooidConnection} from "./transport"
|
||||||
|
|
||||||
const image = "gitea.coracle.social/coracle/zooid:latest"
|
// The relay every test runs against, pinned by digest so a spec is checked against one zooid rather
|
||||||
|
// than whatever this machine last pulled. The tag is there to read; docker resolves the digest, and
|
||||||
|
// `docker pull` of a newer tag prints the digest to paste beside it. A zooid built from a checkout
|
||||||
|
// has no published digest, so ZOOID_IMAGE is how an unreleased one is tried.
|
||||||
|
const image =
|
||||||
|
process.env.ZOOID_IMAGE ??
|
||||||
|
"gitea.coracle.social/coracle/zooid:0.2.2@sha256:70ecf2d3ad0ac338d48f14fe8e5ab9964193d2eb30d6b6f7d8972ca179cad513"
|
||||||
|
|
||||||
// How long after a recreate chromium can still abort what a page has in flight. Every netlink
|
// How long after a recreate chromium can still abort what a page has in flight. Every netlink
|
||||||
// event a create-and-destroy produces lands before `compose up --wait` returns — measured at 26 of
|
// event a create-and-destroy produces lands before `compose up --wait` returns — measured at 26 of
|
||||||
|
|
@ -63,11 +69,13 @@ const isRelayPortTaken = () =>
|
||||||
socket.once("error", () => resolve(false))
|
socket.once("error", () => resolve(false))
|
||||||
})
|
})
|
||||||
|
|
||||||
// Every invocation carries ZOOID_CONFIG, `down` included. The compose file names it without a
|
// Every invocation carries the config directory and the image, `down` included. The compose file
|
||||||
// default, so a call that left it out fails to interpolate rather than quietly mounting something
|
// names both without a default, so a call that left one out fails to interpolate rather than
|
||||||
// else.
|
// quietly mounting something else or running a relay nothing here chose.
|
||||||
const docker = (...args: string[]) =>
|
const docker = (...args: string[]) =>
|
||||||
execFileAsync(dockerCommand, args, {env: {...process.env, ZOOID_CONFIG: configDir}})
|
execFileAsync(dockerCommand, args, {
|
||||||
|
env: {...process.env, ZOOID_CONFIG: configDir, ZOOID_IMAGE: image},
|
||||||
|
})
|
||||||
|
|
||||||
const compose = (...args: string[]) => docker("compose", "-f", composeFile, ...args)
|
const compose = (...args: string[]) => docker("compose", "-f", composeFile, ...args)
|
||||||
|
|
||||||
|
|
@ -196,11 +204,7 @@ export class Zooid {
|
||||||
)
|
)
|
||||||
|
|
||||||
if (!hasImage) {
|
if (!hasImage) {
|
||||||
throw new Error(
|
await this.fetchImage()
|
||||||
`The zooid image ${image} is not present locally. Fetch it with ` +
|
|
||||||
`\`${dockerCommand} pull ${image}\`, or build it from a zooid checkout with ` +
|
|
||||||
`\`${dockerCommand} build -t ${image} .\`.`,
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (await isRelayPortTaken()) {
|
if (await isRelayPortTaken()) {
|
||||||
|
|
@ -208,8 +212,8 @@ export class Zooid {
|
||||||
`127.0.0.1:${port} is already in use, but the zooid relay container publishes ` +
|
`127.0.0.1:${port} is already in use, but the zooid relay container publishes ` +
|
||||||
"exactly that port and the harness talks to whatever answers there. This is a leftover " +
|
"exactly that port and the harness talks to whatever answers there. This is a leftover " +
|
||||||
"container from an interrupted run, or another copy of this suite running on the machine " +
|
"container from an interrupted run, or another copy of this suite running on the machine " +
|
||||||
`(under any user). Free it before running — \`${dockerCommand} compose -f ` +
|
`(under any user). Free it before running — \`${dockerCommand} rm -f ` +
|
||||||
"e2e/harness/zooid/docker/compose.yaml down\` clears one this project started.",
|
"flotilla-e2e-zooid-relay-1` clears the one this project starts.",
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -281,6 +285,25 @@ export class Zooid {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Fetching unasked is safe for a pinned reference: the pull can only produce the relay this suite
|
||||||
|
// was written against, and a machine that already has it never gets here.
|
||||||
|
private fetchImage = async () => {
|
||||||
|
console.warn(`\nFetching the zooid image this suite is pinned to:\n ${image}\n`)
|
||||||
|
|
||||||
|
try {
|
||||||
|
await docker("pull", image)
|
||||||
|
} catch (error) {
|
||||||
|
const {stderr} = Object(error) as {stderr?: string}
|
||||||
|
|
||||||
|
throw new Error(
|
||||||
|
`Could not fetch ${image}: ${stderr?.trim() || String(error)}\n\n` +
|
||||||
|
`Fetch it by hand with \`${dockerCommand} pull ${image}\`, or point ZOOID_IMAGE at a ` +
|
||||||
|
"zooid you built yourself.",
|
||||||
|
{cause: error},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Whatever the relay wrote before it died. Compose reports only that a container exited, so
|
// Whatever the relay wrote before it died. Compose reports only that a container exited, so
|
||||||
// without this a startup failure is a status code and no reason.
|
// without this a startup failure is a status code and no reason.
|
||||||
private logs = () =>
|
private logs = () =>
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue