Files
portal/app/tests/Unit/Autopodbor/AutopodborStudySchedulerTest.php
T

66 lines
2.8 KiB
PHP

<?php
declare(strict_types=1);
use App\Models\AutopodborRun;
use App\Models\Tenant;
use App\Services\Autopodbor\AutopodborStudyScheduler;
use Illuminate\Foundation\Testing\DatabaseTransactions;
use Tests\Concerns\SharesSupplierPdo;
uses(DatabaseTransactions::class, SharesSupplierPdo::class);
// Логический номер тенанта (1,2,…) → реальный tenants.id (FK autopodbor_runs.tenant_id).
// Сбрасываем перед каждым тестом: DatabaseTransactions откатывает строки, поэтому
// карта не должна протекать между тестами.
beforeEach(function () {
$GLOBALS['__sched_tenant_map'] = [];
});
function studyRun(int $tenant, string $status, ?string $finishedAt = null, ?string $createdAt = null): AutopodborRun {
if (! isset($GLOBALS['__sched_tenant_map'][$tenant])) {
$GLOBALS['__sched_tenant_map'][$tenant] = Tenant::factory()->create()->id;
}
$tenantId = $GLOBALS['__sched_tenant_map'][$tenant];
$run = AutopodborRun::create([
'tenant_id' => $tenantId, 'kind' => 'study', 'status' => $status,
'competitor_id' => null, 'region_code' => 1, 'params' => [],
'finished_at' => $finishedAt,
]);
if ($createdAt !== null) {
// created_at не в timestamps — задаём явно через query builder (мимо fillable),
// чтобы порядок был детерминирован
AutopodborRun::whereKey($run->id)->update(['created_at' => $createdAt]);
$run->refresh();
}
return $run;
}
it('дорожка занята: есть running → pickNext возвращает null', function () {
studyRun(1, 'running');
studyRun(2, 'queued');
expect(app(AutopodborStudyScheduler::class)->pickNextRunId())->toBeNull();
});
it('чередует тенантов: наименее недавно обслуженный вперёд', function () {
studyRun(1, 'done', finishedAt: now()->toDateTimeString());
studyRun(1, 'queued');
studyRun(2, 'done', finishedAt: now()->subHour()->toDateTimeString());
$t2q = studyRun(2, 'queued');
expect(app(AutopodborStudyScheduler::class)->pickNextRunId())->toBe($t2q->id);
});
it('внутри тенанта берёт самый старый queued', function () {
$old = studyRun(1, 'queued', createdAt: now()->subMinutes(10)->toDateTimeString());
studyRun(1, 'queued', createdAt: now()->toDateTimeString());
expect(app(AutopodborStudyScheduler::class)->pickNextRunId())->toBe($old->id);
});
it('никогда не обслуженный тенант имеет приоритет', function () {
studyRun(1, 'done', finishedAt: now()->subDay()->toDateTimeString());
studyRun(1, 'queued');
$t2q = studyRun(2, 'queued');
expect(app(AutopodborStudyScheduler::class)->pickNextRunId())->toBe($t2q->id);
});