Files
projectsend/tests/Feature/Platform/RecordsScheduledTaskRunsTest.php
T
ignacionelson 6e47d76ba6 ProjectSend 2.0.0
Client file sharing, rebuilt from the ground up: a private area per
client, resumable uploads, folders, groups and categories, sharing with
expiry dates and download limits, comments, file versions, an activity
log, a REST API, and sixteen languages.

This repository begins here. ProjectSend 2 was developed privately, and
that development history is not published — the previous generation
remains available, with its own history, at projectsend/legacy.

Free software under the GNU General Public License v2, or (at your
option) any later version.
2026-08-14 01:38:12 -03:00

80 lines
3.1 KiB
PHP

<?php
declare(strict_types=1);
use App\Modules\Platform\Scheduling\RecordsScheduledTaskRuns;
use App\Modules\Platform\Scheduling\ScheduledTaskRun;
use App\Modules\Platform\Scheduling\TaskRunStatus;
use Illuminate\Console\Events\ScheduledTaskFailed;
use Illuminate\Console\Events\ScheduledTaskFinished;
use Illuminate\Console\Scheduling\Event as ScheduledEvent;
use Illuminate\Console\Scheduling\EventMutex;
/**
* Not a full `artisan schedule:run` integration test — that spawns real
* subprocess `php artisan ...` children that can't see this test's
* `:memory:` SQLite connection. Instead, exercises the listener directly
* against real Illuminate\Console\Events objects, the same shape
* ScheduleRunCommand actually dispatches (verified against its vendor
* source before writing this feature).
*
* EventMutex isn't container-bound outside a real console boot, so a
* trivial no-op stub stands in — Event's constructor just needs something
* implementing the interface, nothing in these tests exercises locking.
*/
function fakeScheduledEvent(string $rawCommand): ScheduledEvent
{
$mutex = new class implements EventMutex
{
public function create($event): bool
{
return true;
}
public function exists($event): bool
{
return false;
}
public function forget($event): void {}
};
return new ScheduledEvent($mutex, $rawCommand);
}
test('a finished task is recorded as succeeded', function () {
$listener = app(RecordsScheduledTaskRuns::class);
$task = fakeScheduledEvent("'/usr/bin/php' 'artisan' projectsend:purge-expired-files > '/dev/null' 2>&1");
$listener->onFinished(new ScheduledTaskFinished($task, 1.23));
$run = ScheduledTaskRun::query()->where('command', 'projectsend:purge-expired-files')->sole();
expect($run->status)->toBe(TaskRunStatus::Success)
->and($run->message)->toBeNull()
->and($run->duration_ms)->toBe(1230);
});
test('a failed task is recorded as failed, overwriting a prior success', function () {
$listener = app(RecordsScheduledTaskRuns::class);
$task = fakeScheduledEvent("'/usr/bin/php' 'artisan' projectsend:fetch-news > '/dev/null' 2>&1");
// ScheduleRunCommand always dispatches Finished first, then Failed
// only if the exit code was non-zero — replicate that exact order.
$listener->onFinished(new ScheduledTaskFinished($task, 0.5));
$listener->onFailed(new ScheduledTaskFailed($task, new RuntimeException('Scheduled command [...] failed with exit code [1].')));
$run = ScheduledTaskRun::query()->where('command', 'projectsend:fetch-news')->sole();
expect($run->status)->toBe(TaskRunStatus::Failed)
->and($run->message)->toContain('exit code [1]')
->and($run->duration_ms)->toBeNull();
});
test('a non-projectsend command is not tracked', function () {
$listener = app(RecordsScheduledTaskRuns::class);
$task = fakeScheduledEvent("'/usr/bin/php' 'artisan' some:other-command");
$listener->onFinished(new ScheduledTaskFinished($task, 0.1));
expect(ScheduledTaskRun::query()->count())->toBe(0);
});