Drive the first-run experience in a real browser
e2e-setup-browser.sh signs a user with no organisation into the real web console, creates a farm, copies the gateway settings the page shows, connects a stand-in gateway configured from exactly those settings, adds a printer through the form, gets a failed-print alert and dismisses it, then removes the printer. Afterwards it searches every table and the backend log for the access code the browser typed. No printer is touched and dispatch is off. The e2e scripts that start the real proxy also give it its own store file in the scratch directory.
This commit is contained in:
@@ -274,6 +274,7 @@ env -C "$PROXY_DIR" \
|
|||||||
CONTINUUM_GO2RTC_CONFIG="$WORK/go2rtc.yaml" \
|
CONTINUUM_GO2RTC_CONFIG="$WORK/go2rtc.yaml" \
|
||||||
CONTINUUM_STREAM_BASE_URL="http://e2e-gateway.invalid:1984" \
|
CONTINUUM_STREAM_BASE_URL="http://e2e-gateway.invalid:1984" \
|
||||||
CONTINUUM_PRINTERS_PATH=printers.toml \
|
CONTINUUM_PRINTERS_PATH=printers.toml \
|
||||||
|
CONTINUUM_STORE_PATH="$WORK/continuum.db" \
|
||||||
RUST_LOG=info \
|
RUST_LOG=info \
|
||||||
"$PROXY_DIR/target/debug/continuum-proxy" > "$WORK/proxy.log" 2>&1 &
|
"$PROXY_DIR/target/debug/continuum-proxy" > "$WORK/proxy.log" 2>&1 &
|
||||||
PROXY_PID=$!
|
PROXY_PID=$!
|
||||||
|
|||||||
@@ -220,6 +220,7 @@ env -C "$PROXY_DIR" \
|
|||||||
CONTINUUM_GO2RTC_CONFIG="$WORK/go2rtc.yaml" \
|
CONTINUUM_GO2RTC_CONFIG="$WORK/go2rtc.yaml" \
|
||||||
CONTINUUM_STREAM_BASE_URL="$STREAM_BASE_URL" \
|
CONTINUUM_STREAM_BASE_URL="$STREAM_BASE_URL" \
|
||||||
CONTINUUM_PRINTERS_PATH=printers.toml \
|
CONTINUUM_PRINTERS_PATH=printers.toml \
|
||||||
|
CONTINUUM_STORE_PATH="$WORK/continuum.db" \
|
||||||
RUST_LOG=info \
|
RUST_LOG=info \
|
||||||
"$PROXY_DIR/target/debug/continuum-proxy" > "$WORK/proxy.log" 2>&1 &
|
"$PROXY_DIR/target/debug/continuum-proxy" > "$WORK/proxy.log" 2>&1 &
|
||||||
PROXY_PID=$!
|
PROXY_PID=$!
|
||||||
|
|||||||
Executable
+137
@@ -0,0 +1,137 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# The first-run experience in the real web console, in a real Chrome: a user
|
||||||
|
# with no organisation signs in, creates a farm, copies the gateway settings,
|
||||||
|
# connects a gateway configured from exactly those settings, adds a printer
|
||||||
|
# through the form, gets an alert when it fails, and removes it.
|
||||||
|
#
|
||||||
|
# The gateway is a stand-in (scripts/fake-gateway-serve.ts), so NO printer and
|
||||||
|
# no network device is touched; e2e-provision-proxy.sh covers the real proxy.
|
||||||
|
#
|
||||||
|
# SAFETY: nothing here talks to a real printer, and dispatch is off.
|
||||||
|
#
|
||||||
|
# Needs: source ../dev-secrets.sh first (real Supabase, as e2e-camera.sh's
|
||||||
|
# BROWSER mode), a migrated database, Chrome, ../continuum-app installed, and
|
||||||
|
# port 3042 free. Uses the throwaway Supabase user continuum-e2e@example.invalid,
|
||||||
|
# which must have no organisation (it refuses to start otherwise, so it cannot
|
||||||
|
# trample a SERVE=1 stack) and removes what it creates.
|
||||||
|
#
|
||||||
|
# Usage:
|
||||||
|
# set -a; . ../dev-secrets.sh; set +a
|
||||||
|
# scripts/e2e-setup-browser.sh
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||||
|
cd "$REPO_ROOT"
|
||||||
|
|
||||||
|
PORT="${PORT:-3036}"
|
||||||
|
BASE="http://localhost:$PORT"
|
||||||
|
DATABASE_URL="${DATABASE_URL:-postgres://continuum:continuum@localhost:5432/continuum}"
|
||||||
|
VALKEY_URL="${VALKEY_URL:-redis://localhost:6379}"
|
||||||
|
EDGE_JWT_SECRET="${EDGE_JWT_SECRET:-e2e-edge-secret}"
|
||||||
|
R2_ACCESS_KEY_ID="${R2_ACCESS_KEY_ID:-e2e}"
|
||||||
|
R2_SECRET_ACCESS_KEY="${R2_SECRET_ACCESS_KEY:-e2e}"
|
||||||
|
R2_ENDPOINT="${R2_ENDPOINT:-http://localhost:9000}"
|
||||||
|
export DATABASE_URL VALKEY_URL EDGE_JWT_SECRET PORT R2_ACCESS_KEY_ID R2_SECRET_ACCESS_KEY R2_ENDPOINT
|
||||||
|
|
||||||
|
APP_DIR="${APP_DIR:-$REPO_ROOT/../continuum-app}"
|
||||||
|
APP_PORT="${APP_PORT:-3042}"
|
||||||
|
CHROME_BIN="${CHROME_BIN:-/usr/bin/google-chrome}"
|
||||||
|
|
||||||
|
WORK="$(mktemp -d)"
|
||||||
|
BACKEND_PID=""
|
||||||
|
APP_PID=""
|
||||||
|
USER_ID=""
|
||||||
|
|
||||||
|
fail() { echo "FAIL: $*" >&2; exit 1; }
|
||||||
|
ok() { echo " ok: $*"; }
|
||||||
|
psql_q() { psql "$DATABASE_URL" -tAq -c "$1"; }
|
||||||
|
|
||||||
|
cleanup() {
|
||||||
|
local rc=$?
|
||||||
|
[ -n "$BACKEND_PID" ] && kill "$BACKEND_PID" 2>/dev/null || true
|
||||||
|
[ -n "$APP_PID" ] && kill -- "-$APP_PID" 2>/dev/null || true
|
||||||
|
sleep 0.5
|
||||||
|
[ -n "$BACKEND_PID" ] && kill -9 "$BACKEND_PID" 2>/dev/null || true
|
||||||
|
[ -n "$APP_PID" ] && kill -9 -- "-$APP_PID" 2>/dev/null || true
|
||||||
|
# What this run created, and only that: the user began with no organisation.
|
||||||
|
if [ -n "$USER_ID" ] && [ -z "${KEEP_DATA:-}" ]; then
|
||||||
|
psql_q "DELETE FROM organisations WHERE id IN (SELECT org_id FROM org_members WHERE user_id='$USER_ID')" >/dev/null 2>&1 || true
|
||||||
|
fi
|
||||||
|
if [ $rc -ne 0 ]; then
|
||||||
|
echo; echo "--- backend log (tail) ---"; tail -20 "$WORK/backend.log" 2>/dev/null || true
|
||||||
|
echo "--- web console log (tail) ---"; tail -15 "$WORK/app.log" 2>/dev/null || true
|
||||||
|
fi
|
||||||
|
rm -rf "$WORK"
|
||||||
|
exit $rc
|
||||||
|
}
|
||||||
|
trap cleanup EXIT
|
||||||
|
|
||||||
|
for name in SUPABASE_URL SUPABASE_SECRET_KEY SUPABASE_PUBLISHABLE_KEY; do
|
||||||
|
[ -n "${!name:-}" ] || fail "$name is not set - source ../dev-secrets.sh"
|
||||||
|
done
|
||||||
|
psql_q "SELECT 1 FROM printer_alerts LIMIT 0" >/dev/null 2>&1 || fail "no migrated database - run scripts/dev-env.sh up && schema"
|
||||||
|
[ -x "$CHROME_BIN" ] || fail "no Chrome at $CHROME_BIN"
|
||||||
|
[ -d "$APP_DIR/apps/web/node_modules" ] || fail "$APP_DIR has no installed web app"
|
||||||
|
# bash's own /dev/tcp rather than `ss`, which is not installed everywhere.
|
||||||
|
if (exec 3<>"/dev/tcp/127.0.0.1/$APP_PORT") 2>/dev/null; then fail "port $APP_PORT is already in use (a SERVE=1 stack running?)"; fi
|
||||||
|
|
||||||
|
SB_USER="$(bun scripts/e2e-supabase-user.ts)" || fail "could not provision the Supabase test user"
|
||||||
|
sb_field() { printf '%s' "$SB_USER" | python3 -c 'import json,sys; print(json.load(sys.stdin)[sys.argv[1]])' "$1"; }
|
||||||
|
USER_ID="$(sb_field id)"; SB_EMAIL="$(sb_field email)"; SB_PASSWORD="$(sb_field password)"
|
||||||
|
unset SB_USER
|
||||||
|
[ "$(psql_q "SELECT count(*) FROM org_members WHERE user_id='$USER_ID'")" = "0" ] \
|
||||||
|
|| fail "the test user already belongs to an organisation - stop any SERVE=1 stack first"
|
||||||
|
ok "a Supabase user with no organisation"
|
||||||
|
|
||||||
|
echo "==> starting the backend on :$PORT"
|
||||||
|
DISPATCH_ENABLED=false bun run src/index.ts > "$WORK/backend.log" 2>&1 &
|
||||||
|
BACKEND_PID=$!
|
||||||
|
for _ in $(seq 1 60); do curl -sf "$BASE/health" >/dev/null 2>&1 && break; sleep 0.5; done
|
||||||
|
curl -sf "$BASE/health" >/dev/null || fail "backend did not become healthy"
|
||||||
|
ok "backend healthy"
|
||||||
|
|
||||||
|
echo "==> starting the web console on :$APP_PORT"
|
||||||
|
setsid env -C "$APP_DIR/apps/web" \
|
||||||
|
NUXT_PUBLIC_API_BASE="$BASE" \
|
||||||
|
NUXT_PUBLIC_WS_BASE="ws://localhost:$PORT" \
|
||||||
|
SUPABASE_URL="$SUPABASE_URL" \
|
||||||
|
SUPABASE_KEY="$SUPABASE_PUBLISHABLE_KEY" \
|
||||||
|
NUXT_PUBLIC_PASSWORD_LOGIN=true \
|
||||||
|
pnpm exec nuxt dev --host 127.0.0.1 --port "$APP_PORT" > "$WORK/app.log" 2>&1 &
|
||||||
|
APP_PID=$!
|
||||||
|
for _ in $(seq 1 120); do curl -sf -o /dev/null "http://127.0.0.1:$APP_PORT/login" 2>/dev/null && break; sleep 1; done
|
||||||
|
curl -sf -o /dev/null "http://127.0.0.1:$APP_PORT/login" || fail "the web console did not start"
|
||||||
|
ok "the web console is up"
|
||||||
|
|
||||||
|
ACCESS_CODE="BROWSERCODE$(cat /proc/sys/kernel/random/uuid | cut -c1-6)"
|
||||||
|
FRAMES="$WORK/frames.jsonl"; : > "$FRAMES"
|
||||||
|
|
||||||
|
echo "==> first run, in real Chrome"
|
||||||
|
OUT="$(env APP_URL="http://127.0.0.1:$APP_PORT" API_BASE="$BASE" WS_BASE="ws://localhost:$PORT" \
|
||||||
|
SUPABASE_E2E_EMAIL="$SB_EMAIL" SUPABASE_E2E_PASSWORD="$SB_PASSWORD" CHROME_BIN="$CHROME_BIN" \
|
||||||
|
FRAMES_FILE="$FRAMES" ACCESS_CODE="$ACCESS_CODE" \
|
||||||
|
timeout 280 bun scripts/e2e-setup-browser.ts 2>&1 || true)"
|
||||||
|
seen=0; bad=0
|
||||||
|
while IFS=$'\t' read -r verdict label; do
|
||||||
|
case "$verdict" in
|
||||||
|
ok) ok "$label"; seen=$((seen + 1)) ;;
|
||||||
|
FAILED) echo " FAILED: $label" >&2; seen=$((seen + 1)); bad=$((bad + 1)) ;;
|
||||||
|
esac
|
||||||
|
done < <(printf '%s\n' "$OUT" | grep -E "^(ok|FAILED)$(printf '\t')")
|
||||||
|
if [ "$seen" -lt 18 ] && [ "$bad" -eq 0 ]; then
|
||||||
|
bad=1; echo " FAILED: the browser run produced only $seen of 18 results" >&2
|
||||||
|
fi
|
||||||
|
if [ "$bad" -ne 0 ]; then
|
||||||
|
printf '%s\n' "$OUT" | sed 's/^/ | /' >&2
|
||||||
|
fail "the first-run experience did not work"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# The credential the browser typed must rest nowhere in the cloud.
|
||||||
|
grep -q "$ACCESS_CODE" "$WORK/backend.log" && fail "the access code is in the backend log"
|
||||||
|
LEAK="$(psql "$DATABASE_URL" -tAq -c "SELECT string_agg(table_name, ' ') FROM information_schema.tables WHERE table_schema='public'" \
|
||||||
|
| tr ' ' '\n' | while read -r tbl; do [ -n "$tbl" ] && psql_q "SELECT count(*) FROM \"$tbl\" t WHERE row_to_json(t)::text LIKE '%$ACCESS_CODE%'" | sed "s/^/$tbl /"; done | awk '$2>0')"
|
||||||
|
[ -z "$LEAK" ] || fail "the access code is stored in: $LEAK"
|
||||||
|
ok "the access code is in no table and no log"
|
||||||
|
|
||||||
|
echo
|
||||||
|
echo "PASS - a new user went from nothing to a farm, a gateway, a printer, an alert and back."
|
||||||
@@ -0,0 +1,158 @@
|
|||||||
|
/**
|
||||||
|
* Drives the console's first-run experience in a real Chrome, for
|
||||||
|
* scripts/e2e-setup-browser.sh: a brand-new user with nothing signs in, creates
|
||||||
|
* a farm, gets gateway settings, connects a (stand-in) gateway with them, adds
|
||||||
|
* a printer through the form, sees an alert when it fails, dismisses it, and
|
||||||
|
* removes the printer.
|
||||||
|
*
|
||||||
|
* Results are `ok<TAB>label` / `FAILED<TAB>label`. The password, the gateway
|
||||||
|
* token and the printer's access code never reach a log line.
|
||||||
|
*
|
||||||
|
* Environment: APP_URL, API_BASE, WS_BASE, SUPABASE_E2E_EMAIL,
|
||||||
|
* SUPABASE_E2E_PASSWORD, FRAMES_FILE, ACCESS_CODE, CHROME_BIN.
|
||||||
|
*/
|
||||||
|
import { readFileSync } from "node:fs";
|
||||||
|
import puppeteer from "puppeteer-core";
|
||||||
|
|
||||||
|
const { APP_URL, API_BASE, WS_BASE, FRAMES_FILE, ACCESS_CODE } = process.env as Record<string, string>;
|
||||||
|
const email = process.env.SUPABASE_E2E_EMAIL!;
|
||||||
|
const password = process.env.SUPABASE_E2E_PASSWORD!;
|
||||||
|
const chromeBin = process.env.CHROME_BIN ?? "/usr/bin/google-chrome";
|
||||||
|
|
||||||
|
let failed = false;
|
||||||
|
const say = (good: boolean, label: string, detail = "") => {
|
||||||
|
if (!good) failed = true;
|
||||||
|
console.log(`${good ? "ok" : "FAILED"}\t${label}${detail ? ` (${detail})` : ""}`);
|
||||||
|
};
|
||||||
|
|
||||||
|
const browser = await puppeteer.launch({
|
||||||
|
executablePath: chromeBin,
|
||||||
|
headless: true,
|
||||||
|
args: ["--no-sandbox", "--disable-dev-shm-usage"],
|
||||||
|
});
|
||||||
|
|
||||||
|
let gateway: ReturnType<typeof Bun.spawn> | undefined;
|
||||||
|
|
||||||
|
try {
|
||||||
|
const page = await browser.newPage();
|
||||||
|
const pageErrors: string[] = [];
|
||||||
|
page.on("pageerror", (err) => pageErrors.push(String((err as Error).message ?? err).slice(0, 160)));
|
||||||
|
|
||||||
|
const waitText = (selector: string, text: string, timeout = 30_000) =>
|
||||||
|
page
|
||||||
|
.waitForFunction(
|
||||||
|
(sel: string, want: string) => document.querySelector(sel)?.textContent?.includes(want) ?? false,
|
||||||
|
{ timeout },
|
||||||
|
selector,
|
||||||
|
text,
|
||||||
|
)
|
||||||
|
.then(() => true)
|
||||||
|
.catch(() => false);
|
||||||
|
|
||||||
|
await page.goto(`${APP_URL}/login`, { waitUntil: "domcontentloaded", timeout: 120_000 });
|
||||||
|
await page.waitForFunction(
|
||||||
|
() => typeof (window as any).useNuxtApp === "function" && Boolean((window as any).useNuxtApp().$supabase),
|
||||||
|
{ timeout: 120_000 },
|
||||||
|
);
|
||||||
|
const signInError = await page.evaluate(
|
||||||
|
async (e: string, p: string) => {
|
||||||
|
const { client } = (window as any).useNuxtApp().$supabase;
|
||||||
|
const { error } = await client.auth.signInWithPassword({ email: e, password: p });
|
||||||
|
return error ? String(error.message) : null;
|
||||||
|
},
|
||||||
|
email,
|
||||||
|
password,
|
||||||
|
);
|
||||||
|
say(signInError === null, "a brand-new user signs in", signInError ?? "");
|
||||||
|
if (signInError) process.exit(1);
|
||||||
|
|
||||||
|
// 1. nothing yet -> pointed at Setup
|
||||||
|
await page.goto(`${APP_URL}/`, { waitUntil: "domcontentloaded", timeout: 60_000 });
|
||||||
|
say(await waitText(".fleet", "You have no farm yet"), "the empty fleet page points a new user to Setup");
|
||||||
|
|
||||||
|
// 2. onboarding
|
||||||
|
await page.goto(`${APP_URL}/setup`, { waitUntil: "domcontentloaded", timeout: 60_000 });
|
||||||
|
await page.waitForSelector(".onboarding input", { timeout: 30_000 });
|
||||||
|
await page.type(".onboarding input", "Browser Farm");
|
||||||
|
await page.click(".onboarding button[type=submit]");
|
||||||
|
say(await waitText(".setup__farm h2", "Browser Farm"), "creating a farm from nothing works (org and farm)");
|
||||||
|
|
||||||
|
// 3. gateway settings
|
||||||
|
await page.waitForSelector(".gateway-setup button", { timeout: 15_000 });
|
||||||
|
say(
|
||||||
|
await page.$eval(".gateway-setup", (el) => el.textContent?.includes("No gateway is connected") ?? false),
|
||||||
|
"setup says no gateway is connected yet",
|
||||||
|
);
|
||||||
|
await page.click(".gateway-setup button");
|
||||||
|
await page.waitForSelector(".gateway-setup__settings", { timeout: 15_000 });
|
||||||
|
const settings = await page.$eval(".gateway-setup__settings", (el) => el.textContent ?? "");
|
||||||
|
const farmId = /farm_id = "([^"]+)"/.exec(settings)?.[1] ?? "";
|
||||||
|
const proxyToken = /gateway_token = "([^"]+)"/.exec(settings)?.[1] ?? "";
|
||||||
|
const uplink = /uplink_url = "([^"]+)"/.exec(settings)?.[1] ?? "";
|
||||||
|
say(Boolean(farmId && proxyToken && uplink.endsWith("/ws/edge/v1")), "the page shows complete gateway settings");
|
||||||
|
|
||||||
|
// 4. a gateway configured from exactly what the page showed
|
||||||
|
const exchanged = await fetch(`${API_BASE}/auth/edge-token`, {
|
||||||
|
method: "POST",
|
||||||
|
headers: { "content-type": "application/json" },
|
||||||
|
body: JSON.stringify({ farmId, edgeProxyToken: proxyToken }),
|
||||||
|
});
|
||||||
|
say(exchanged.ok, "the token the page showed is accepted by the cloud");
|
||||||
|
const jwt = ((await exchanged.json()) as { token: string }).token;
|
||||||
|
gateway = Bun.spawn(["bun", "scripts/fake-gateway-serve.ts", `${WS_BASE}/ws/edge/v1`, jwt, "120", FRAMES_FILE], {
|
||||||
|
env: { ...process.env, FARM_ID: farmId, TELEMETRY_AFTER_PROVISION: "1" },
|
||||||
|
stdout: "ignore",
|
||||||
|
stderr: "ignore",
|
||||||
|
});
|
||||||
|
say(await waitText(".gateway-setup", "A gateway is connected", 30_000), "the page notices the gateway connecting");
|
||||||
|
await page.click(".gateway-setup button:last-of-type"); // Done: the token leaves the screen
|
||||||
|
say(
|
||||||
|
!(await page.$eval("body", (el, token) => el.textContent?.includes(token) ?? false, proxyToken)),
|
||||||
|
"dismissing the settings removes the token from the page",
|
||||||
|
);
|
||||||
|
|
||||||
|
// 5. add a printer
|
||||||
|
const fields = await page.$$(".add-printer form input");
|
||||||
|
await fields[0]!.type("Bench P1P");
|
||||||
|
await fields[1]!.type("192.168.0.77");
|
||||||
|
await fields[2]!.type("01P00A000000007");
|
||||||
|
await fields[3]!.type(ACCESS_CODE);
|
||||||
|
await page.click(".add-printer button[type=submit]");
|
||||||
|
say(await waitText(".add-printer", "Added Bench P1P", 45_000), "adding a printer through the form succeeds");
|
||||||
|
say(await waitText(".managed", "Bench P1P"), "the printer appears in the list");
|
||||||
|
const leftover = await page.$eval(".add-printer input[type=password]", (el) => (el as HTMLInputElement).value);
|
||||||
|
say(leftover === "", "the access code is cleared from the form after sending");
|
||||||
|
const frames = readFileSync(FRAMES_FILE, "utf8");
|
||||||
|
say(frames.includes(ACCESS_CODE), "the gateway received the access code");
|
||||||
|
|
||||||
|
// 6. the printer fails -> an alert on the fleet page
|
||||||
|
await page.goto(`${APP_URL}/`, { waitUntil: "domcontentloaded", timeout: 60_000 });
|
||||||
|
say(await waitText(".alert-list", "the print failed", 60_000), "a failed print raises an alert on the fleet page");
|
||||||
|
await page.click(".alert-list button");
|
||||||
|
const gone = await page
|
||||||
|
.waitForFunction(() => document.querySelector(".alert-list") === null, { timeout: 20_000 })
|
||||||
|
.then(() => true)
|
||||||
|
.catch(() => false);
|
||||||
|
say(gone, "dismissing the alert removes it");
|
||||||
|
|
||||||
|
// 7. remove
|
||||||
|
await page.goto(`${APP_URL}/setup`, { waitUntil: "domcontentloaded", timeout: 60_000 });
|
||||||
|
await page.waitForSelector(".managed button", { timeout: 20_000 });
|
||||||
|
await page.click(".managed button");
|
||||||
|
say(await waitText(".managed", "forget its access code"), "removing asks first, and says what it deletes");
|
||||||
|
const buttons = await page.$$(".managed button");
|
||||||
|
await buttons[0]!.click(); // "Yes, remove"
|
||||||
|
const removed = await page
|
||||||
|
.waitForFunction(() => document.querySelector(".managed") === null, { timeout: 30_000 })
|
||||||
|
.then(() => true)
|
||||||
|
.catch(() => false);
|
||||||
|
say(removed, "the printer is removed");
|
||||||
|
say(readFileSync(FRAMES_FILE, "utf8").includes("remove_printer"), "the gateway was told to forget it");
|
||||||
|
|
||||||
|
say(pageErrors.length === 0, "no uncaught page errors", pageErrors.slice(0, 2).join(" | "));
|
||||||
|
} finally {
|
||||||
|
gateway?.kill();
|
||||||
|
await browser.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
process.exit(failed ? 1 : 0);
|
||||||
@@ -2,6 +2,10 @@
|
|||||||
* A stand-in gateway that stays connected and answers printer provisioning,
|
* A stand-in gateway that stays connected and answers printer provisioning,
|
||||||
* for scripts/e2e-provision.sh.
|
* for scripts/e2e-provision.sh.
|
||||||
*
|
*
|
||||||
|
* With TELEMETRY_AFTER_PROVISION=1 it also reports each provisioned printer
|
||||||
|
* (running, then failed a few seconds later), so the console has something to
|
||||||
|
* alert on.
|
||||||
|
*
|
||||||
* Needs FARM_ID in the environment (the hello must name the token's farm).
|
* Needs FARM_ID in the environment (the hello must name the token's farm).
|
||||||
*
|
*
|
||||||
* Usage: bun scripts/fake-gateway-serve.ts <ws-url> <edge-jwt> <seconds> <frames-file> [refuse-access-code]
|
* Usage: bun scripts/fake-gateway-serve.ts <ws-url> <edge-jwt> <seconds> <frames-file> [refuse-access-code]
|
||||||
@@ -33,6 +37,14 @@ ws.onmessage = (event) => {
|
|||||||
const message = JSON.parse(String(event.data));
|
const message = JSON.parse(String(event.data));
|
||||||
if (message.type !== "provision_printer" && message.type !== "remove_printer") return;
|
if (message.type !== "provision_printer" && message.type !== "remove_printer") return;
|
||||||
appendFileSync(framesFile, JSON.stringify(message) + "\n");
|
appendFileSync(framesFile, JSON.stringify(message) + "\n");
|
||||||
|
if (message.type === "provision_printer" && process.env.TELEMETRY_AFTER_PROVISION === "1") {
|
||||||
|
const id = message.printer.id;
|
||||||
|
const report = (state: string) =>
|
||||||
|
ws.send(JSON.stringify({ type: "telemetry", printers: [{ printer_id: id, name: message.printer.name, state, percent: 40, print_error: 0 }] }));
|
||||||
|
setTimeout(() => report("RUNNING"), 1500);
|
||||||
|
setTimeout(() => report("RUNNING"), 3000);
|
||||||
|
setTimeout(() => report("FAILED"), 4500);
|
||||||
|
}
|
||||||
const refused = message.type === "provision_printer" && refuseCode && message.printer.access_code === refuseCode;
|
const refused = message.type === "provision_printer" && refuseCode && message.printer.access_code === refuseCode;
|
||||||
ws.send(
|
ws.send(
|
||||||
JSON.stringify({
|
JSON.stringify({
|
||||||
|
|||||||
Reference in New Issue
Block a user