feat(ms-ai-architect): add cross-OS scheduling templates (launchd/systemd/Windows) [skip-docs]
This commit is contained in:
parent
aefe9ef5b4
commit
03c77b6452
6 changed files with 295 additions and 0 deletions
|
|
@ -0,0 +1,98 @@
|
|||
// tests/kb-update/test-template-generation.test.mjs
|
||||
// Structural-regex tests for scripts/kb-update/templates/* (Step 8).
|
||||
// Verifies that each template file exists, contains the documented sentinel
|
||||
// strings, and exposes the documented placeholder set. No template execution
|
||||
// or real scheduling occurs in this test — that lives in Wave 6 live-test.
|
||||
|
||||
import { test } from 'node:test';
|
||||
import assert from 'node:assert/strict';
|
||||
import { readFileSync, existsSync } from 'node:fs';
|
||||
import { join, dirname } from 'node:path';
|
||||
import { fileURLToPath } from 'node:url';
|
||||
|
||||
const __dirname = dirname(fileURLToPath(import.meta.url));
|
||||
const TEMPLATES_DIR = join(__dirname, '..', '..', 'scripts', 'kb-update', 'templates');
|
||||
|
||||
const PLIST = join(TEMPLATES_DIR, 'com.fromaitochitta.ms-ai-architect.kb-update.plist');
|
||||
const SERVICE = join(TEMPLATES_DIR, 'ms-ai-architect-kb-update.service');
|
||||
const TIMER = join(TEMPLATES_DIR, 'ms-ai-architect-kb-update.timer');
|
||||
const PS1 = join(TEMPLATES_DIR, 'ms-ai-architect-kb-update.ps1');
|
||||
const README = join(TEMPLATES_DIR, 'README.md');
|
||||
|
||||
function readTpl(p) {
|
||||
assert.equal(existsSync(p), true, `template missing: ${p}`);
|
||||
return readFileSync(p, 'utf8');
|
||||
}
|
||||
|
||||
test('plist — exists with required keys and placeholders', () => {
|
||||
const content = readTpl(PLIST);
|
||||
assert.match(content, /<key>Label<\/key>/);
|
||||
assert.match(content, /<key>StartCalendarInterval<\/key>/);
|
||||
assert.match(content, /<key>ProgramArguments<\/key>/);
|
||||
assert.match(content, /<key>StandardOutPath<\/key>/);
|
||||
assert.match(content, /<key>StandardErrorPath<\/key>/);
|
||||
assert.match(content, /<key>EnvironmentVariables<\/key>/);
|
||||
assert.match(content, /<key>RunAtLoad<\/key>\s*<false\/>/);
|
||||
assert.match(content, /\{\{NODE_BIN\}\}/);
|
||||
assert.match(content, /\{\{PLUGIN_ROOT\}\}/);
|
||||
assert.match(content, /\{\{LOG_FILE\}\}/);
|
||||
assert.match(content, /\{\{SCHEDULE_HOUR\}\}/);
|
||||
assert.match(content, /\{\{SCHEDULE_MINUTE\}\}/);
|
||||
assert.match(content, /\{\{SCHEDULE_DAY_OF_WEEK\}\}/);
|
||||
});
|
||||
|
||||
test('systemd .timer — exists with OnCalendar and Persistent', () => {
|
||||
const content = readTpl(TIMER);
|
||||
assert.match(content, /\[Unit\]/);
|
||||
assert.match(content, /\[Timer\]/);
|
||||
assert.match(content, /\[Install\]/);
|
||||
assert.match(content, /OnCalendar=Wed/);
|
||||
assert.match(content, /Persistent=true/);
|
||||
assert.match(content, /WantedBy=timers\.target/);
|
||||
});
|
||||
|
||||
test('systemd .service — exists with [Unit], [Service] and ExecStart', () => {
|
||||
const content = readTpl(SERVICE);
|
||||
assert.match(content, /\[Unit\]/);
|
||||
assert.match(content, /\[Service\]/);
|
||||
assert.match(content, /ExecStart=/);
|
||||
assert.match(content, /\{\{NODE_BIN\}\}/);
|
||||
assert.match(content, /\{\{PLUGIN_ROOT\}\}/);
|
||||
});
|
||||
|
||||
test('PowerShell ps1 — exists with Register-ScheduledTask and InteractiveToken', () => {
|
||||
const content = readTpl(PS1);
|
||||
assert.match(content, /Register-ScheduledTask/);
|
||||
assert.match(content, /InteractiveToken/);
|
||||
assert.match(content, /New-ScheduledTaskTrigger/);
|
||||
assert.match(content, /-Weekly/);
|
||||
assert.match(content, /-DaysOfWeek\s+Wednesday/);
|
||||
assert.match(content, /\{\{NODE_BIN\}\}/);
|
||||
assert.match(content, /\{\{PLUGIN_ROOT\}\}/);
|
||||
});
|
||||
|
||||
test('README — exists and references each template by filename', () => {
|
||||
const content = readTpl(README);
|
||||
assert.match(content, /com\.fromaitochitta\.ms-ai-architect\.kb-update\.plist/);
|
||||
assert.match(content, /ms-ai-architect-kb-update\.service/);
|
||||
assert.match(content, /ms-ai-architect-kb-update\.timer/);
|
||||
assert.match(content, /ms-ai-architect-kb-update\.ps1/);
|
||||
});
|
||||
|
||||
test('plist + service + ps1 reference NODE_BIN and PLUGIN_ROOT', () => {
|
||||
// The .timer is a pure trigger — it activates the .service, which is
|
||||
// the only systemd unit that needs to know the binary + plugin root.
|
||||
// launchd and Windows put the command directly in the trigger spec, so
|
||||
// they need both placeholders themselves.
|
||||
for (const tpl of [PLIST, SERVICE, PS1]) {
|
||||
const content = readFileSync(tpl, 'utf8');
|
||||
assert.match(content, /\{\{NODE_BIN\}\}/, `${tpl} missing NODE_BIN placeholder`);
|
||||
assert.match(content, /\{\{PLUGIN_ROOT\}\}/, `${tpl} missing PLUGIN_ROOT placeholder`);
|
||||
}
|
||||
});
|
||||
|
||||
test('.timer is placeholder-free literal (Wed 04:23 hardcoded per plan)', () => {
|
||||
const content = readFileSync(TIMER, 'utf8');
|
||||
assert.match(content, /OnCalendar=Wed \*-\*-\* 04:23:00/);
|
||||
assert.doesNotMatch(content, /\{\{[A-Z_]+\}\}/);
|
||||
});
|
||||
Loading…
Add table
Add a link
Reference in a new issue