mirror of
https://github.com/rcourtman/Pulse.git
synced 2026-08-12 18:43:32 +00:00
test(integration): restart managed runtime for verify
This commit is contained in:
parent
60e902ab9a
commit
d877763fde
4 changed files with 123 additions and 2 deletions
|
|
@ -200,6 +200,11 @@ across pretest, Playwright, and posttest. `scripts/hot-dev.sh` must honor that
|
|||
lock by suppressing source-triggered rebuilds and manual `pulse` binary restart
|
||||
churn while the owning proof process is still alive. Stale verify locks must
|
||||
clear themselves automatically once the owning process exits.
|
||||
That same verification contract also applies before Playwright attaches: if a
|
||||
managed hot-dev session is already running when the verify lock is active, the
|
||||
integration launcher must restart that session instead of silently attaching to
|
||||
an old frontend process, so browser proof reflects the current branch-tip
|
||||
source rather than whatever Vite shell happened to be left alive.
|
||||
That same launcher boundary also owns its CLI contract: managed commands such
|
||||
as `start --takeover` and `restart --takeover` must preserve the takeover flag
|
||||
through the actual script entrypoint instead of silently dropping second-arg
|
||||
|
|
|
|||
|
|
@ -243,6 +243,36 @@ test_verify_bg_holds_runtime_lock_for_proof_duration() {
|
|||
assert_contains "verify clears the runtime lock after proofs finish" "${output}" "lock_after=no"
|
||||
}
|
||||
|
||||
test_managed_dev_runtime_restarts_existing_session_for_verification() {
|
||||
local output
|
||||
output="$(
|
||||
ROOT_DIR="${ROOT_DIR}" \
|
||||
node --input-type=module <<'EOF'
|
||||
import fs from 'node:fs/promises';
|
||||
import os from 'node:os';
|
||||
import path from 'node:path';
|
||||
|
||||
const rootDir = process.env.ROOT_DIR;
|
||||
const modulePath = path.join(rootDir, 'tests', 'integration', 'scripts', 'managed-dev-runtime.mjs');
|
||||
const { shouldRestartManagedDevRuntimeForVerification } = await import(`file://${modulePath}`);
|
||||
|
||||
const tempDir = await fs.mkdtemp(path.join(os.tmpdir(), 'pulse-managed-dev-verify-'));
|
||||
const lockPath = path.join(tempDir, 'hot-dev.verify.lock');
|
||||
await fs.writeFile(lockPath, `pid=${process.pid}\ncreated_at=2026-03-28T23:00:00Z\n`, 'utf8');
|
||||
|
||||
console.log(
|
||||
`running=${shouldRestartManagedDevRuntimeForVerification({ env: { HOT_DEV_VERIFY_LOCK_FILE: lockPath }, wasRunning: true })}`,
|
||||
);
|
||||
console.log(
|
||||
`stopped=${shouldRestartManagedDevRuntimeForVerification({ env: { HOT_DEV_VERIFY_LOCK_FILE: lockPath }, wasRunning: false })}`,
|
||||
);
|
||||
EOF
|
||||
)"
|
||||
|
||||
assert_contains "managed dev runtime restarts existing sessions during verification" "${output}" "running=true"
|
||||
assert_contains "managed dev runtime does not restart absent prior session" "${output}" "stopped=false"
|
||||
}
|
||||
|
||||
test_takeover_avoids_killing_current_shell_lineage() {
|
||||
local output
|
||||
output="$(
|
||||
|
|
@ -865,6 +895,7 @@ main() {
|
|||
test_verify_command_injects_managed_runtime_env
|
||||
test_default_verify_command_runs_runtime_and_layout_proofs
|
||||
test_verify_bg_holds_runtime_lock_for_proof_duration
|
||||
test_managed_dev_runtime_restarts_existing_session_for_verification
|
||||
test_takeover_avoids_killing_current_shell_lineage
|
||||
test_launchd_session_supervises_managed_runtime
|
||||
test_start_bg_reports_browser_entrypoint
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
import fs from 'node:fs';
|
||||
import { spawn } from 'node:child_process';
|
||||
import path from 'node:path';
|
||||
import { fileURLToPath } from 'node:url';
|
||||
|
|
@ -18,6 +19,10 @@ function hotDevBgScriptPath(env = process.env) {
|
|||
return path.join(repoRootFromEnv(env), 'scripts', 'hot-dev-bg.sh');
|
||||
}
|
||||
|
||||
function managedVerifyLockPath(env = process.env) {
|
||||
return trim(env.HOT_DEV_VERIFY_LOCK_FILE) || path.join(repoRootFromEnv(env), 'tmp', 'hot-dev.verify.lock');
|
||||
}
|
||||
|
||||
function hotDevBrowserURL(env = process.env) {
|
||||
const host = trim(env.FRONTEND_DEV_HOST) || '127.0.0.1';
|
||||
const port = trim(env.FRONTEND_DEV_PORT) || '5173';
|
||||
|
|
@ -63,6 +68,32 @@ function statusReportsRunning(output) {
|
|||
return output.includes('[hot-dev-bg] Running');
|
||||
}
|
||||
|
||||
export function managedVerifyLockActive(env = process.env) {
|
||||
try {
|
||||
const raw = fs.readFileSync(managedVerifyLockPath(env), 'utf8');
|
||||
const ownerPid = Number.parseInt(
|
||||
raw
|
||||
.split('\n')
|
||||
.find((line) => line.startsWith('pid='))?.slice(4) || '',
|
||||
10,
|
||||
);
|
||||
if (!Number.isInteger(ownerPid) || ownerPid <= 0) {
|
||||
return false;
|
||||
}
|
||||
process.kill(ownerPid, 0);
|
||||
return true;
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
export function shouldRestartManagedDevRuntimeForVerification({
|
||||
env = process.env,
|
||||
wasRunning,
|
||||
}) {
|
||||
return Boolean(wasRunning) && managedVerifyLockActive(env);
|
||||
}
|
||||
|
||||
async function managedRuntimeStatusOutput(env = process.env) {
|
||||
const status = await runHotDevBg(['status'], env);
|
||||
if (status.code !== 0) {
|
||||
|
|
@ -231,14 +262,21 @@ export async function startManagedDevRuntime({
|
|||
throw new Error(`hot-dev-bg status failed before start: ${statusBefore.stderr || statusBefore.stdout}`);
|
||||
}
|
||||
const wasRunning = statusReportsRunning(`${statusBefore.stdout}${statusBefore.stderr}`);
|
||||
const shouldRestartForVerification = shouldRestartManagedDevRuntimeForVerification({
|
||||
env,
|
||||
wasRunning,
|
||||
});
|
||||
|
||||
const startArgs = ['start'];
|
||||
const startArgs = [shouldRestartForVerification ? 'restart' : 'start'];
|
||||
if (truthy(env.PULSE_E2E_HOT_DEV_TAKEOVER)) {
|
||||
startArgs.push('--takeover');
|
||||
}
|
||||
if (shouldRestartForVerification) {
|
||||
logger.log('[integration] Restarting managed dev runtime before browser verification to pick up current source changes');
|
||||
}
|
||||
const startResult = await runHotDevBg(startArgs, env);
|
||||
if (startResult.code !== 0) {
|
||||
throw new Error(`hot-dev-bg start failed: ${startResult.stderr || startResult.stdout}`);
|
||||
throw new Error(`hot-dev-bg ${startArgs[0]} failed: ${startResult.stderr || startResult.stdout}`);
|
||||
}
|
||||
|
||||
await waitForStableManagedRuntime({ env });
|
||||
|
|
|
|||
47
tests/integration/scripts/managed-dev-runtime.test.mjs
Normal file
47
tests/integration/scripts/managed-dev-runtime.test.mjs
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
import assert from 'node:assert/strict';
|
||||
import fs from 'node:fs/promises';
|
||||
import os from 'node:os';
|
||||
import path from 'node:path';
|
||||
import test from 'node:test';
|
||||
|
||||
import {
|
||||
managedVerifyLockActive,
|
||||
shouldRestartManagedDevRuntimeForVerification,
|
||||
} from './managed-dev-runtime.mjs';
|
||||
|
||||
test('managedVerifyLockActive returns true for a live verify lock owner', async () => {
|
||||
const rootDir = await fs.mkdtemp(path.join(os.tmpdir(), 'pulse-managed-dev-runtime-'));
|
||||
const lockPath = path.join(rootDir, 'hot-dev.verify.lock');
|
||||
await fs.writeFile(lockPath, `pid=${process.pid}\ncreated_at=2026-03-28T23:00:00Z\n`, 'utf8');
|
||||
|
||||
assert.equal(managedVerifyLockActive({ HOT_DEV_VERIFY_LOCK_FILE: lockPath }), true);
|
||||
});
|
||||
|
||||
test('managedVerifyLockActive clears false when the verify lock owner is stale', async () => {
|
||||
const rootDir = await fs.mkdtemp(path.join(os.tmpdir(), 'pulse-managed-dev-runtime-'));
|
||||
const lockPath = path.join(rootDir, 'hot-dev.verify.lock');
|
||||
await fs.writeFile(lockPath, 'pid=999999\ncreated_at=2026-03-28T23:00:00Z\n', 'utf8');
|
||||
|
||||
assert.equal(managedVerifyLockActive({ HOT_DEV_VERIFY_LOCK_FILE: lockPath }), false);
|
||||
});
|
||||
|
||||
test('shouldRestartManagedDevRuntimeForVerification only restarts existing sessions under verify lock', async () => {
|
||||
const rootDir = await fs.mkdtemp(path.join(os.tmpdir(), 'pulse-managed-dev-runtime-'));
|
||||
const lockPath = path.join(rootDir, 'hot-dev.verify.lock');
|
||||
await fs.writeFile(lockPath, `pid=${process.pid}\ncreated_at=2026-03-28T23:00:00Z\n`, 'utf8');
|
||||
|
||||
assert.equal(
|
||||
shouldRestartManagedDevRuntimeForVerification({
|
||||
env: { HOT_DEV_VERIFY_LOCK_FILE: lockPath },
|
||||
wasRunning: true,
|
||||
}),
|
||||
true,
|
||||
);
|
||||
assert.equal(
|
||||
shouldRestartManagedDevRuntimeForVerification({
|
||||
env: { HOT_DEV_VERIFY_LOCK_FILE: lockPath },
|
||||
wasRunning: false,
|
||||
}),
|
||||
false,
|
||||
);
|
||||
});
|
||||
Loading…
Add table
Add a link
Reference in a new issue