Files
restic-manager/e2e/playwright/tests/smoke.spec.ts
T
steve ea9941b9ec
CI / Test (rest) (pull_request) Successful in 7s
CI / Test (store) (pull_request) Successful in 6s
CI / Build (windows/amd64) (pull_request) Successful in 8s
CI / Lint (pull_request) Successful in 18s
CI / Build (linux/amd64) (pull_request) Successful in 7s
CI / Build (linux/arm64) (pull_request) Successful in 8s
e2e / Playwright vs docker-compose (pull_request) Successful in 1m27s
CI / Test (server-http) (pull_request) Successful in 3m3s
e2e: dispatch backup via source-group API
Per-host Run-backup is gone — the host_chrome partial still
renders the button but it's hard-disabled with a tooltip
pointing to per-source-group Run-now. The smoke test was
clicking that disabled button and waiting forever for a URL
change that would never happen.

Replace the navigation-based dispatch with two API calls:
create a source group covering the agent's /source mount,
then POST to /api/hosts/{id}/source-groups/{gid}/run. The
backup-status assertion at the end is unchanged — host record
is still the source of truth.
2026-05-08 22:16:57 +01:00

91 lines
3.7 KiB
TypeScript

// End-to-end smoke: bootstrap → accept pending host → run backup → see succeeded.
//
// The compose stack stands up a server, a sibling rest-server, and an
// agent in announce-and-approve mode. This test drives the operator
// path through the UI (login + dashboard) and the API
// (accept + run-now + poll for terminal) — UI for the human surfaces,
// API for the deterministic ones.
import { test, expect } from '@playwright/test';
import {
baseURL,
bootstrapAdmin,
loginViaUI,
waitForPendingHostID,
acceptPending,
waitForHostStatus,
createSourceGroup,
runSourceGroup,
getSessionCookie,
} from './lib/server';
test.describe('smoke: enrol-via-announce → backup', () => {
test('happy path: enrol → accept → backup → succeeded', async ({ page, request }) => {
const { username, password } = await bootstrapAdmin(request);
await loginViaUI(page, username, password);
// Dashboard renders.
await expect(page.locator('main')).toContainText(/host|fleet|pending/i, { timeout: 10_000 });
// Pending host appears (the agent container has been
// announcing since startup).
const pendingID = await waitForPendingHostID(page);
const cookie = await getSessionCookie(page);
// Accept with the rest-server creds. compose's rest-server runs
// --no-auth, so any credentials work; restic still demands a
// password to encrypt the repo.
await acceptPending(request, cookie, pendingID, {
url: 'rest:http://rest-server:8000/',
password: 'e2e-repo-password',
});
// Wait for the host to come online AND for auto-init to
// finish. Coming online happens as soon as the agent's
// bearer-authed WS attaches (~1s after accept); repo_status
// flips to 'ready' once the auto-init job completes (a
// couple of seconds later). Loading the host page before
// that leaves the Run-backup button disabled because the
// server-rendered HTML reflects the still-in-progress init,
// and the page has no live-refresh on that field.
const readyHost = await waitForHostStatus(
request, cookie,
(h) => h.status === 'online' && h.repo_status === 'ready',
90_000,
);
expect(readyHost.id).toBeTruthy();
// Per-host Run-now is gone; backups are dispatched per
// source-group now. Create one that maps to the agent's
// /source mount, then kick it via the JSON API.
const groupID = await createSourceGroup(request, cookie, readyHost.id, {
name: 'default',
includes: ['/source'],
});
await runSourceGroup(request, cookie, readyHost.id, groupID);
// Wait for the host's last_backup_status to flip to 'succeeded'.
// The host record is the source of truth: it's what the
// dashboard projects from job-completion events on the WS
// channel.
const finishedHost = await waitForHostStatus(
request, cookie,
(h) => h.id === readyHost.id && h.last_backup_status === 'succeeded',
120_000,
);
expect(finishedHost.last_backup_status).toBe('succeeded');
});
});
test.describe('smoke: scrape /metrics', () => {
test('metrics endpoint exposes the host gauge', async ({ request }) => {
// Compose sets RM_METRICS_TRUSTED_CIDR=0.0.0.0/0 so the
// endpoint is open to the test runner.
const res = await request.get(`${baseURL}/metrics`);
expect(res.status()).toBe(200);
const body = await res.text();
expect(body).toContain('rm_hosts_total');
expect(body).toContain('rm_build_info{');
});
});