mirror of
https://github.com/hansjone/dsh-ops-cron.git
synced 2026-10-09 01:53:19 +08:00
104 lines
3.6 KiB
JavaScript
104 lines
3.6 KiB
JavaScript
import assert from 'node:assert/strict'
|
|
import test from 'node:test'
|
|
import { normalizeAgentPresetId, resolveCreateAgentPreset } from '../lib/preset.js'
|
|
import { createJobRecord, emptyState } from '../lib/store.js'
|
|
|
|
test('normalizeAgentPresetId accepts empty and valid ids', () => {
|
|
assert.equal(normalizeAgentPresetId(''), '')
|
|
assert.equal(normalizeAgentPresetId(' ops-desk '), 'ops-desk')
|
|
assert.throws(() => normalizeAgentPresetId('bad preset'), /agentPreset/)
|
|
})
|
|
|
|
test('createJobRecord persists agentPreset', () => {
|
|
const job = createJobRecord({
|
|
name: 'n',
|
|
prompt: 'p',
|
|
schedule: { kind: 'cron', expr: '0 9 * * *', timezone: 'Asia/Shanghai' },
|
|
agentPreset: 'ops-desk',
|
|
}, emptyState(), Date.now())
|
|
assert.equal(job.agentPreset, 'ops-desk')
|
|
})
|
|
|
|
test('createJobRecord defaults mirrorToSession off and accepts explicit true', () => {
|
|
const base = {
|
|
name: 'n',
|
|
prompt: 'p',
|
|
schedule: { kind: 'cron', expr: '0 9 * * *', timezone: 'Asia/Shanghai' },
|
|
}
|
|
assert.equal(createJobRecord(base, emptyState(), Date.now()).mirrorToSession, false)
|
|
assert.equal(
|
|
createJobRecord({ ...base, mirrorToSession: true }, emptyState(), Date.now()).mirrorToSession,
|
|
true,
|
|
)
|
|
assert.equal(
|
|
createJobRecord({ ...base, mirror_to_session: true }, emptyState(), Date.now()).mirrorToSession,
|
|
true,
|
|
)
|
|
assert.equal(
|
|
createJobRecord({ ...base, mirrorToSession: 'yes' }, emptyState(), Date.now()).mirrorToSession,
|
|
false,
|
|
)
|
|
})
|
|
|
|
test('createJobRecord fires ASAP when one-shot at is slightly in the past', () => {
|
|
const now = Date.parse('2026-08-24T01:00:30.000Z')
|
|
const at = new Date(now - 15_000).toISOString()
|
|
const job = createJobRecord({
|
|
name: 'soon',
|
|
prompt: 'ping',
|
|
schedule: { kind: 'at', at, timezone: 'UTC' },
|
|
}, emptyState(), now)
|
|
assert.equal(job.nextRunAt, now)
|
|
|
|
assert.throws(
|
|
() => createJobRecord({
|
|
name: 'late',
|
|
prompt: 'ping',
|
|
schedule: { kind: 'at', at: new Date(now - 120_000).toISOString(), timezone: 'UTC' },
|
|
}, emptyState(), now),
|
|
(error) => error.code === 'INVALID_AT',
|
|
)
|
|
})
|
|
|
|
test('createStore recovers from NUL-corrupt store.json', async () => {
|
|
const { createStore } = await import('../lib/store.js')
|
|
const { mkdtemp, writeFile, readFile, rm } = await import('node:fs/promises')
|
|
const { tmpdir } = await import('node:os')
|
|
const { join } = await import('node:path')
|
|
const dir = await mkdtemp(join(tmpdir(), 'dsh-cron-store-'))
|
|
const filePath = join(dir, 'store.json')
|
|
await writeFile(filePath, `{\u0000"jobs":[]}`, 'utf8')
|
|
const store = createStore({ filePath })
|
|
const state = await store.read()
|
|
assert.equal(Array.isArray(state.jobs), true)
|
|
assert.equal(state.jobs.length, 0)
|
|
const rewritten = await readFile(filePath, 'utf8')
|
|
assert.equal(rewritten.includes('\u0000'), false)
|
|
await rm(dir, { recursive: true, force: true })
|
|
})
|
|
|
|
test('resolveCreateAgentPreset prefers explicit then peer then session then host default', async () => {
|
|
assert.equal(
|
|
await resolveCreateAgentPreset({ agent_preset: 'explicit' }, {}, {}),
|
|
'explicit',
|
|
)
|
|
|
|
const fromPeer = await resolveCreateAgentPreset({}, { agent: { session: { id: 's1' } } }, {
|
|
dshIm: {
|
|
resolveSessionPeer: async () => ({ agentPreset: 'from-peer' }),
|
|
},
|
|
})
|
|
assert.equal(fromPeer, 'from-peer')
|
|
|
|
const fromMeta = await resolveCreateAgentPreset({}, {
|
|
agent: { session: { meta: { agentPreset: 'from-meta' } } },
|
|
}, {})
|
|
assert.equal(fromMeta, 'from-meta')
|
|
|
|
const fromHost = await resolveCreateAgentPreset({}, {}, {
|
|
agentPresets: {
|
|
resolve: async () => ({ id: 'host-default' }),
|
|
},
|
|
})
|
|
assert.equal(fromHost, 'host-default')
|
|
})
|