Files
portal/app/tests/Feature/Supplier/FlushDeferredOnlineSyncTest.php
T
Дмитрий 9d703ccb2a feat/supplier: онлайн-заморозка 18:00→00:00 + досыл очередью в 00:05 (Эпик 4)
Закрывает рассинхрон онлайна со слепком поставщика 21:00.
- 4.1: SyncSupplierProjectJob в окне 18:00→00:00 МСК кладёт проект в новую очередь
  supplier_deferred_sync вместо немедленной отправки (перезаписала бы зафиксированный
  слепок). Вне окна — как раньше.
- 4.2: FlushDeferredOnlineSyncJob в 00:05 МСК досылает отложенное вне окна и чистит очередь.
- Схема: +1 таблица supplier_deferred_sync (project_id PK, без RLS — системная очередь как
  supplier_manual_sync_queue), миграция 2026_06_25_120000, schema.sql v8.54 + CHANGELOG.
  RLS-ревью пройдено (no-RLS консистентно прецеденту; формулировки GRANT/метрик уточнены).

Тесты 6/6 + регрессия онлайн-синка 33/33 зелёные. Под LEFTHOOK=0.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-25 18:07:15 +03:00

68 lines
2.3 KiB
PHP

<?php
declare(strict_types=1);
use App\Jobs\Supplier\FlushDeferredOnlineSyncJob;
use App\Jobs\SyncSupplierProjectJob;
use App\Models\Project;
use App\Models\Tenant;
use Illuminate\Foundation\Testing\DatabaseTransactions;
use Illuminate\Support\Facades\Bus;
use Illuminate\Support\Facades\DB;
use Tests\Concerns\SharesSupplierPdo;
uses(DatabaseTransactions::class, SharesSupplierPdo::class);
/**
* Task 4.2 — джоб досыла отложенной онлайн-очереди в 00:05 МСК.
*
* Для каждого проекта из supplier_deferred_sync диспатчит SyncSupplierProjectJob
* (в 00:05 он вне окна → отработает немедленно) и чистит строку.
*/
function makeDeferredProject(): Project
{
$tenant = Tenant::factory()->create();
$project = Project::factory()->for($tenant)->create([
'signal_type' => 'site', 'signal_identifier' => 'okna.ru', 'is_active' => true, 'daily_limit_target' => 10,
]);
DB::table('supplier_deferred_sync')->insert([
'project_id' => $project->id,
'created_at' => now(),
]);
return $project;
}
it('досылает отложенные онлайн-правки и чистит очередь', function (): void {
Bus::fake([SyncSupplierProjectJob::class]);
$project = makeDeferredProject();
(new FlushDeferredOnlineSyncJob)->handle();
expect(DB::table('supplier_deferred_sync')->count())->toBe(0);
Bus::assertDispatched(
SyncSupplierProjectJob::class,
fn (SyncSupplierProjectJob $job) => $job->projectId === $project->id,
);
});
it('пустая очередь — ничего не диспатчит, не падает', function (): void {
Bus::fake([SyncSupplierProjectJob::class]);
(new FlushDeferredOnlineSyncJob)->handle();
Bus::assertNotDispatched(SyncSupplierProjectJob::class);
});
it('досылает несколько проектов и полностью очищает очередь', function (): void {
Bus::fake([SyncSupplierProjectJob::class]);
makeDeferredProject();
makeDeferredProject();
makeDeferredProject();
(new FlushDeferredOnlineSyncJob)->handle();
expect(DB::table('supplier_deferred_sync')->count())->toBe(0);
Bus::assertDispatchedTimes(SyncSupplierProjectJob::class, 3);
});