248 lines
6.4 KiB
TypeScript
248 lines
6.4 KiB
TypeScript
import test from 'node:test';
|
|
import assert from 'node:assert/strict';
|
|
import {
|
|
buildScheduledBoardPostTitle,
|
|
buildScheduledPlanWorkIdBase,
|
|
isPlanScheduledTaskDue,
|
|
mapPlanScheduledTaskRow,
|
|
shouldCreatePlanForScheduleExecution,
|
|
updatePlanScheduledTaskSchema,
|
|
} from './plan-schedule-service.js';
|
|
|
|
test('buildScheduledBoardPostTitle prefers the first memo line when present', () => {
|
|
assert.equal(
|
|
buildScheduledBoardPostTitle({
|
|
work_id: '반복작업',
|
|
note: ' 첫 줄 제목 \n둘째 줄 설명',
|
|
}),
|
|
'첫 줄 제목',
|
|
);
|
|
});
|
|
|
|
test('buildScheduledBoardPostTitle falls back to normalized work id when memo is empty', () => {
|
|
assert.equal(
|
|
buildScheduledBoardPostTitle({
|
|
work_id: ' 작업 ID ',
|
|
note: ' \n ',
|
|
}),
|
|
'반복작업',
|
|
);
|
|
});
|
|
|
|
test('buildScheduledPlanWorkIdBase uses the schedule work id for automation registration', () => {
|
|
assert.equal(
|
|
buildScheduledPlanWorkIdBase({
|
|
work_id: ' 반복-정리 ',
|
|
}),
|
|
'반복-정리',
|
|
);
|
|
});
|
|
|
|
test('buildScheduledPlanWorkIdBase keeps managed-service runs on the schedule work id with schedule pk prefix', () => {
|
|
assert.equal(
|
|
buildScheduledPlanWorkIdBase({
|
|
id: 10,
|
|
work_id: ' 반복-정리 ',
|
|
execution_mode: 'managed-service',
|
|
}),
|
|
'schedule-10-반복-정리',
|
|
);
|
|
|
|
assert.equal(
|
|
buildScheduledPlanWorkIdBase({
|
|
id: 10,
|
|
work_id: '반복-정리-service',
|
|
execution_mode: 'managed-service',
|
|
}),
|
|
'schedule-10-반복-정리-service',
|
|
);
|
|
});
|
|
|
|
test('buildScheduledPlanWorkIdBase falls back when managed-service schedule id is missing', () => {
|
|
assert.equal(
|
|
buildScheduledPlanWorkIdBase({
|
|
work_id: '반복-정리-service',
|
|
execution_mode: 'managed-service',
|
|
}),
|
|
'반복-정리-service',
|
|
);
|
|
});
|
|
|
|
test('shouldCreatePlanForScheduleExecution only returns true for managed-service schedules', () => {
|
|
assert.equal(
|
|
shouldCreatePlanForScheduleExecution({
|
|
execution_mode: 'codex',
|
|
}),
|
|
false,
|
|
);
|
|
|
|
assert.equal(
|
|
shouldCreatePlanForScheduleExecution({
|
|
execution_mode: 'managed-service',
|
|
}),
|
|
true,
|
|
);
|
|
});
|
|
|
|
test('updatePlanScheduledTaskSchema keeps partial updates partial', () => {
|
|
assert.deepEqual(updatePlanScheduledTaskSchema.parse({ recreateManagedServiceOnNextSave: true }), {
|
|
recreateManagedServiceOnNextSave: true,
|
|
});
|
|
});
|
|
|
|
test('updatePlanScheduledTaskSchema accepts second-based interval updates', () => {
|
|
assert.deepEqual(
|
|
updatePlanScheduledTaskSchema.parse({
|
|
repeatIntervalValue: 10,
|
|
repeatIntervalUnit: 'second',
|
|
repeatIntervalSeconds: 10,
|
|
}),
|
|
{
|
|
repeatIntervalValue: 10,
|
|
repeatIntervalUnit: 'second',
|
|
repeatIntervalSeconds: 10,
|
|
},
|
|
);
|
|
});
|
|
|
|
test('interval schedule with start time waits until start time when immediate run is enabled', () => {
|
|
assert.equal(
|
|
isPlanScheduledTaskDue(
|
|
{
|
|
schedule_mode: 'interval',
|
|
immediate_run_enabled: true,
|
|
repeat_interval_minutes: 60,
|
|
repeat_window_start_time: '09:00',
|
|
created_at: '2026-04-30T07:00:00+09:00',
|
|
},
|
|
new Date('2026-04-30T08:59:00+09:00'),
|
|
),
|
|
false,
|
|
);
|
|
|
|
assert.equal(
|
|
isPlanScheduledTaskDue(
|
|
{
|
|
schedule_mode: 'interval',
|
|
immediate_run_enabled: true,
|
|
repeat_interval_minutes: 60,
|
|
repeat_window_start_time: '09:00',
|
|
created_at: '2026-04-30T07:00:00+09:00',
|
|
},
|
|
new Date('2026-04-30T09:00:00+09:00'),
|
|
),
|
|
true,
|
|
);
|
|
});
|
|
|
|
test('interval schedule with start time waits one interval after the start when immediate run is disabled', () => {
|
|
assert.equal(
|
|
isPlanScheduledTaskDue(
|
|
{
|
|
schedule_mode: 'interval',
|
|
immediate_run_enabled: false,
|
|
repeat_interval_minutes: 60,
|
|
repeat_window_start_time: '09:00',
|
|
created_at: '2026-04-30T07:00:00+09:00',
|
|
},
|
|
new Date('2026-04-30T09:59:00+09:00'),
|
|
),
|
|
false,
|
|
);
|
|
|
|
assert.equal(
|
|
isPlanScheduledTaskDue(
|
|
{
|
|
schedule_mode: 'interval',
|
|
immediate_run_enabled: false,
|
|
repeat_interval_minutes: 60,
|
|
repeat_window_start_time: '09:00',
|
|
created_at: '2026-04-30T07:00:00+09:00',
|
|
},
|
|
new Date('2026-04-30T10:00:00+09:00'),
|
|
),
|
|
true,
|
|
);
|
|
});
|
|
|
|
test('interval schedule supports second-based due calculation', () => {
|
|
assert.equal(
|
|
isPlanScheduledTaskDue(
|
|
{
|
|
schedule_mode: 'interval',
|
|
immediate_run_enabled: false,
|
|
repeat_interval_unit: 'second',
|
|
repeat_interval_value: 10,
|
|
repeat_interval_seconds: 10,
|
|
created_at: '2026-04-30T09:00:00+09:00',
|
|
},
|
|
new Date('2026-04-30T09:00:09+09:00'),
|
|
),
|
|
false,
|
|
);
|
|
|
|
assert.equal(
|
|
isPlanScheduledTaskDue(
|
|
{
|
|
schedule_mode: 'interval',
|
|
immediate_run_enabled: false,
|
|
repeat_interval_unit: 'second',
|
|
repeat_interval_value: 10,
|
|
repeat_interval_seconds: 10,
|
|
created_at: '2026-04-30T09:00:00+09:00',
|
|
},
|
|
new Date('2026-04-30T09:00:10+09:00'),
|
|
),
|
|
true,
|
|
);
|
|
});
|
|
|
|
test('interval schedule uses repeat interval value and unit when stored seconds are stale', () => {
|
|
assert.equal(
|
|
isPlanScheduledTaskDue(
|
|
{
|
|
schedule_mode: 'interval',
|
|
immediate_run_enabled: false,
|
|
repeat_interval_unit: 'minute',
|
|
repeat_interval_value: 10,
|
|
repeat_interval_seconds: 3600,
|
|
created_at: '2026-04-30T09:50:00+09:00',
|
|
},
|
|
new Date('2026-04-30T09:59:59+09:00'),
|
|
),
|
|
false,
|
|
);
|
|
|
|
assert.equal(
|
|
isPlanScheduledTaskDue(
|
|
{
|
|
schedule_mode: 'interval',
|
|
immediate_run_enabled: false,
|
|
repeat_interval_unit: 'minute',
|
|
repeat_interval_value: 10,
|
|
repeat_interval_seconds: 3600,
|
|
created_at: '2026-04-30T09:50:00+09:00',
|
|
},
|
|
new Date('2026-04-30T10:00:00+09:00'),
|
|
),
|
|
true,
|
|
);
|
|
});
|
|
|
|
test('mapPlanScheduledTaskRow normalizes stale stored repeat interval seconds', () => {
|
|
const mapped = mapPlanScheduledTaskRow({
|
|
id: 2,
|
|
work_id: 'stock-alert',
|
|
schedule_mode: 'interval',
|
|
repeat_interval_unit: 'minute',
|
|
repeat_interval_value: 10,
|
|
repeat_interval_seconds: 3600,
|
|
repeat_interval_minutes: 60,
|
|
});
|
|
|
|
assert.equal(mapped.repeatIntervalValue, 10);
|
|
assert.equal(mapped.repeatIntervalUnit, 'minute');
|
|
assert.equal(mapped.repeatIntervalSeconds, 600);
|
|
assert.equal(mapped.repeatIntervalMinutes, 10);
|
|
});
|