/** * Smoke: the shortest path that proves the harness can reach every plane it * needs, and that the deployment is fundamentally alive. * * If this fails, nothing else in the suite is worth reading. It covers: * - the cluster plane (kubectl can list the StatefulSet pods) * - public DNS + TLS (the hostname resolves and the ingress serves health) * - the credential path (the sourced bearer is accepted) * - the write path (a quorum-acked write really commits) */ import { resolve4 } from 'node:dns/promises'; import { expect, test } from '@playwright/test'; import { kubectl, waitForPodsReady } from './support/cluster'; import { observed, recordJson } from './support/evidence'; import { EXPECTED_NODE_IPS, NAMESPACE, POD_NAMES, PUBLIC_BASE_URL, PUBLIC_HOST, apiKey, } from './support/env'; test.describe('smoke', () => { test('all three cluster pods are Ready', async ({}, testInfo) => { // Polled, not sampled once: `reseed_self_restart: true` means a node that // latches a reseed marker legitimately exits(0) and comes back. Observed // 2026-08-30 — tidaldb-2 restarted mid-suite with // {"reason":"reseed_self_restart","shard":1} and was Ready ~20s later. A // single sample turns that self-healing behavior into a red suite. const outcome = await waitForPodsReady(NAMESPACE, POD_NAMES); await recordJson(testInfo, 'pod-readiness', { converged: outcome.converged, final: outcome.final, restarts: outcome.restarts, samples: outcome.samples, note: 'restartCount is evidence, not a failure: a bounded reseed_self_restart is ' + 'designed behavior. A CLIMBING count across runs is the livelock signature ' + '(the 2026-08-20 incident reached 196).', }); expect( outcome.converged, `pods did not all reach Ready within the budget; final=${JSON.stringify(outcome.final)}`, ).toBe(true); expect( Object.keys(outcome.final).sort(), 'expected exactly the known pod set', ).toEqual([...POD_NAMES].sort()); }); test('public hostname resolves to every node and serves health over valid TLS', async ({ playwright, }, testInfo) => { // Real public resolution is part of the claim, so resolve it for real // rather than pinning an IP. A pinned IP would still pass if DNS were // broken — which is precisely the failure that retired the old hostname. const addresses = await resolve4(PUBLIC_HOST); await recordJson(testInfo, 'dns-resolution', { host: PUBLIC_HOST, addresses }); expect( [...addresses].sort(), 'every node IP should answer for the public hostname', ).toEqual([...EXPECTED_NODE_IPS].sort()); // ignoreHTTPSErrors stays false: an invalid or expired certificate must // fail this test, not be tolerated. const context = await playwright.request.newContext({ ignoreHTTPSErrors: false }); try { const response = await context.get(`${PUBLIC_BASE_URL}/health`); await recordJson(testInfo, 'health-response', { status: response.status(), body: (await response.text()).slice(0, 500), }); expect(response.status(), 'health must be publicly reachable').toBe(200); } finally { await context.dispose(); } }); test('sourced bearer is accepted and a quorum write commits', async ({ playwright, }, testInfo) => { const context = await playwright.request.newContext({ baseURL: PUBLIC_BASE_URL, extraHTTPHeaders: { authorization: `Bearer ${apiKey()}` }, }); try { const read = await context.get('/search', { params: { query: 'smoke', limit: 1 } }); expect(read.status(), 'authenticated read must succeed').toBe(200); const write = await context.post('/items', { headers: { 'content-type': 'application/json', 'x-tidal-ack': 'quorum' }, data: { entity_id: 999_000_001, metadata: { title: 'harness smoke', category: 'verification' }, }, }); await recordJson(testInfo, 'quorum-write', { status: write.status(), body: (await write.text()).slice(0, 500), }); // 201 means the write was acknowledged by a quorum, not merely accepted // by one node. This is the single strongest signal in the suite. expect(write.status(), 'quorum-acked write must commit').toBe(201); } finally { await context.dispose(); } }); });