From 1e81db04cbf5b61bc08975c9a8144909e0503691 Mon Sep 17 00:00:00 2001 From: Eve Date: Fri, 8 May 2026 21:06:51 +0800 Subject: [PATCH] refactor: shim repo sender binding entrypoint --- scripts/operator_notify_sender_binding.mjs | 3 + ..._notify_sender_binding_shim_regression.mjs | 114 ++++++++++++++++++ 2 files changed, 117 insertions(+) create mode 100644 scripts/operator_notify_sender_binding.mjs create mode 100644 scripts/test_operator_notify_sender_binding_shim_regression.mjs diff --git a/scripts/operator_notify_sender_binding.mjs b/scripts/operator_notify_sender_binding.mjs new file mode 100644 index 0000000..48f3b5a --- /dev/null +++ b/scripts/operator_notify_sender_binding.mjs @@ -0,0 +1,3 @@ +#!/usr/bin/env node + +import '../plugins/reporting-governance/scripts/operator_notify_sender_binding.mjs'; diff --git a/scripts/test_operator_notify_sender_binding_shim_regression.mjs b/scripts/test_operator_notify_sender_binding_shim_regression.mjs new file mode 100644 index 0000000..412d9f0 --- /dev/null +++ b/scripts/test_operator_notify_sender_binding_shim_regression.mjs @@ -0,0 +1,114 @@ +#!/usr/bin/env node + +import assert from 'node:assert/strict'; +import { mkdtempSync, mkdirSync, readFileSync, rmSync } from 'node:fs'; +import { tmpdir } from 'node:os'; +import path from 'node:path'; +import process from 'node:process'; +import { spawnSync } from 'node:child_process'; + +const ROOT_DIR = path.resolve(import.meta.dirname, '..'); +const REPO_SHIM = path.join(ROOT_DIR, 'scripts', 'operator_notify_sender_binding.mjs'); +const PACKAGE_ENTRY = path.join(ROOT_DIR, 'plugins', 'reporting-governance', 'scripts', 'operator_notify_sender_binding.mjs'); + +function run(script, args = [], env = {}) { + const result = spawnSync(process.execPath, [script, ...args], { + cwd: ROOT_DIR, + encoding: 'utf8', + env: { ...process.env, ...env }, + }); + return { + status: result.status, + stdout: result.stdout ?? '', + stderr: result.stderr ?? '', + }; +} + +function createFixture() { + const fixtureRoot = mkdtempSync(path.join(tmpdir(), 'operator-notify-sender-binding-shim-regression-')); + const attemptDir = path.join(fixtureRoot, 'attempts'); + mkdirSync(attemptDir, { recursive: true }); + return { fixtureRoot, attemptDir }; +} + +function normalizeJson(text) { + return JSON.parse(text); +} + +function normalizeAttempt(filePath) { + const json = JSON.parse(readFileSync(filePath, 'utf8')); + json.contract.spoolPath = ''; + json.contract.queueItemPath = ''; + return json; +} + +const contractEnv = { + OPERATOR_NOTIFY_SPOOL_PATH: '/tmp/spool-item.json', + OPERATOR_NOTIFY_QUEUE_ITEM_PATH: '/tmp/queue-item.json', + OPERATOR_NOTIFY_NOTIFICATION_ID: 'notify-sender-binding-shim-regression-1', + OPERATOR_NOTIFY_CHANNEL: 'telegram', + OPERATOR_NOTIFY_TARGET: '864811879', + OPERATOR_NOTIFY_MESSAGE: 'watchdog overdue', + OPERATOR_NOTIFY_QUEUE_DIR: '/tmp/queue', + OPERATOR_NOTIFY_NOW: '2026-05-08T12:34:56.000Z', +}; + +const tests = []; +function test(name, fn) { tests.push({ name, fn }); } +function printResult(prefix, name, detail = '') { process.stdout.write(`${prefix} ${name}${detail ? ` ${detail}` : ''}\n`); } + +test('repo-root shim forwards help text and exits like package entrypoint', () => { + const shim = run(REPO_SHIM, ['--help']); + const pkg = run(PACKAGE_ENTRY, ['--help']); + assert.equal(shim.status, 0); + assert.equal(pkg.status, 0); + assert.equal(shim.stderr, ''); + assert.equal(pkg.stderr, ''); + assert.equal(shim.stdout, pkg.stdout); +}); + +test('repo-root shim forwards args and preserves shim-mode payload semantics', () => { + const shimFixture = createFixture(); + const pkgFixture = createFixture(); + try { + const argsA = ['--mode', 'shim', '--attempt-dir', shimFixture.attemptDir, '--now', '2026-05-08T12:34:56.000Z', '--compact']; + const argsB = ['--mode', 'shim', '--attempt-dir', pkgFixture.attemptDir, '--now', '2026-05-08T12:34:56.000Z', '--compact']; + const shim = run(REPO_SHIM, argsA, contractEnv); + const pkg = run(PACKAGE_ENTRY, argsB, contractEnv); + assert.equal(shim.status, 0, shim.stderr); + assert.equal(pkg.status, 0, pkg.stderr); + + const shimOut = normalizeJson(shim.stdout); + const pkgOut = normalizeJson(pkg.stdout); + assert.deepEqual({ ...shimOut, attemptPath: '' }, { ...pkgOut, attemptPath: '' }); + assert.deepEqual(normalizeAttempt(shimOut.attemptPath), normalizeAttempt(pkgOut.attemptPath)); + } finally { + rmSync(shimFixture.fixtureRoot, { recursive: true, force: true }); + rmSync(pkgFixture.fixtureRoot, { recursive: true, force: true }); + } +}); + +test('repo-root shim preserves non-zero exit semantics from package core', () => { + const shim = run(REPO_SHIM, ['--now', 'not-an-iso']); + const pkg = run(PACKAGE_ENTRY, ['--now', 'not-an-iso']); + assert.equal(shim.status, 1); + assert.equal(pkg.status, 1); + assert.equal(shim.stdout, ''); + assert.equal(pkg.stdout, ''); + assert.equal(shim.stderr, pkg.stderr); +}); + +let failures = 0; +for (const { name, fn } of tests) { + try { + fn(); + printResult('ok', name); + } catch (error) { + failures += 1; + printResult('not ok', name, `- ${error instanceof Error ? error.message : String(error)}`); + } +} + +if (failures > 0) { + process.exit(1); +}