66 lines
2.8 KiB
PHP
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);
|
|
});
|