Files
api/services/nginx/app/tests/Unit/Cron/CronTaskRegistryTest.php
T
Jeppe Bandopenhands 5441fea665 fix(api): simplify XLVask Selvvask surface by removing AI autopilot pipeline (#367)
## Summary

Removes the XLVask autopilot / automation / MiniMax / OpenAI pipeline
and the related module config, CLI, cron, and migration scaffolding. The
Selvvask view (Superuser -> Fakturaer -> Periode -> Selvvask) is reduced
to a single read-only listing of usage logs plus operator-driven ignore
/ unignore / accept / reject endpoints gated on the
`review_xlvask_usage_order` permission.

See `inventory/self-serve-inventory.md` for the full surface map.

## Test plan

- [x] `vendor/bin/pest --testsuite=Unit` -> **1266 passed**, 1 unrelated
pre-existing failure (`BirdControlPlaneActivationTest`, needs
`PLENO_REPO_ROOT_FOR_TESTS`).
- [x] `php -l` on every modified PHP file -> no syntax errors.
- [x] Grep validation -> zero production-code references to removed
surfaces (`xlvask_autopilot_service`, `xlvask_automation_service`,
`xlvask_automation_policy_service`, `EnsureXLVaskAutomationSchema`,
`runScheduledAutomationIfReady`, `processAutopilotQueue`, `MiniMax`,
`minimax`, ...).
- [ ] Qodana + Tests workflows green on this PR.

Co-authored-by: openhands <openhands@all-hands.dev>

---------

Co-authored-by: openhands <openhands@all-hands.dev>
2026-08-12 20:02:30 +02:00

80 lines
2.7 KiB
PHP

<?php
use classes\cron_schedule;
use classes\cron_task_registry;
it('discovers module-owned cron task definitions', function (): void {
$registry = new cron_task_registry(app_path('modules'));
$definitions = $registry->definitions();
expect($definitions)->toHaveCount(22);
expect(array_keys($definitions))->toContain(
'system.sync_logs',
'backups.process_jobs',
'backups.prune_retention',
'economic.transfer_queue',
'dynamicimages.pre_render',
'weatherapi.preload_department_responses',
'goals.progress_alerts',
'account.process_deletion_requests',
'selfserve.activate_opening_cleaner_relays'
);
expect(array_keys($definitions))->not->toContain('xlvask.autopilot_queue');
$transferQueue = $registry->get('EconomicTransferQueueCron');
expect($transferQueue)->not->toBeNull();
expect($transferQueue->id)->toBe('economic.transfer_queue');
expect($transferQueue->module)->toBe('economic');
expect($transferQueue->schedule)->toBe(['type' => 'interval', 'seconds' => 30]);
});
it('keeps every discovered cron task in a module cron folder', function (): void {
$files = glob(app_path('modules/*/cron/tasks.php')) ?: [];
$modules = array_map(
static fn(string $file): string => basename(dirname(dirname($file))),
$files
);
$registry = new cron_task_registry(app_path('modules'));
foreach ($registry->definitions() as $definition) {
expect($modules)->toContain($definition->module);
}
});
it('normalizes and advances interval schedules without tight loops', function (): void {
expect(cron_schedule::normalize(['type' => 'interval', 'seconds' => 60]))
->toBe(['type' => 'interval', 'seconds' => 60]);
$now = strtotime('2026-07-09 12:10:00');
$next = cron_schedule::nextRunAt(
['type' => 'interval', 'seconds' => 300],
'2026-07-09 12:00:00',
$now
);
expect($next)->toBe('2026-07-09 12:15:00');
});
it('keeps minute schedules anchored to intended slots when execution finishes late', function (): void {
$schedule = ['type' => 'interval', 'seconds' => 60];
$first = cron_schedule::nextRunAt(
$schedule,
'2026-07-27 12:00:00',
strtotime('2026-07-27 12:00:47')
);
$second = cron_schedule::nextRunAt(
$schedule,
$first,
strtotime('2026-07-27 12:01:52')
);
expect($first)->toBe('2026-07-27 12:01:00');
expect($second)->toBe('2026-07-27 12:02:00');
});
it('rejects unsafe cron intervals', function (): void {
expect(fn() => cron_schedule::normalize(['type' => 'interval', 'seconds' => 5]))
->toThrow(InvalidArgumentException::class);
});