ensureRange( 'deals', Carbon::parse('2024-02-15'), Carbon::parse('2024-04-03'), ); expect($created)->toBeGreaterThanOrEqual(3) ->and(partitionExists('deals_y2024_m02'))->toBeTrue() ->and(partitionExists('deals_y2024_m03'))->toBeTrue() ->and(partitionExists('deals_y2024_m04'))->toBeTrue(); }); test('ensureRange идемпотентна — повторный вызов не падает', function (): void { $manager = app(MonthlyPartitionManager::class); $manager->ensureRange('deals', Carbon::parse('2024-02-15'), Carbon::parse('2024-02-20')); $secondRun = $manager->ensureRange('deals', Carbon::parse('2024-02-15'), Carbon::parse('2024-02-20')); expect($secondRun)->toBe(0); // всё уже существует }); test('ensureRange отвергает неизвестную таблицу', function (): void { app(MonthlyPartitionManager::class)->ensureRange('orders', now(), now()); })->throws(InvalidArgumentException::class); // --------------------------------------------------------------------------- // Hole #2 tests: audit tables (created_at key) // --------------------------------------------------------------------------- test('ensureMonth создаёт партицию auth_log (created_at)', function (): void { $manager = app(MonthlyPartitionManager::class); $month = Carbon::parse('2024-03-01'); $manager->ensureMonth('auth_log', $month); expect(partitionExists('auth_log_y2024_m03'))->toBeTrue(); }); test('ensureMonth создаёт партицию activity_log (created_at)', function (): void { $manager = app(MonthlyPartitionManager::class); $manager->ensureMonth('activity_log', Carbon::parse('2024-03-01')); expect(partitionExists('activity_log_y2024_m03'))->toBeTrue(); }); test('ensureMonth создаёт партицию tenant_operations_log (created_at)', function (): void { $manager = app(MonthlyPartitionManager::class); $manager->ensureMonth('tenant_operations_log', Carbon::parse('2024-03-01')); expect(partitionExists('tenant_operations_log_y2024_m03'))->toBeTrue(); }); test('ensureMonth создаёт партицию webhook_log (received_at)', function (): void { $manager = app(MonthlyPartitionManager::class); $manager->ensureMonth('webhook_log', Carbon::parse('2024-03-01')); expect(partitionExists('webhook_log_y2024_m03'))->toBeTrue(); }); test('ensureMonth создаёт партицию balance_transactions (created_at)', function (): void { $manager = app(MonthlyPartitionManager::class); $manager->ensureMonth('balance_transactions', Carbon::parse('2024-03-01')); expect(partitionExists('balance_transactions_y2024_m03'))->toBeTrue(); }); test('ensureMonth создаёт партицию pd_processing_log (created_at)', function (): void { $manager = app(MonthlyPartitionManager::class); $manager->ensureMonth('pd_processing_log', Carbon::parse('2024-03-01')); expect(partitionExists('pd_processing_log_y2024_m03'))->toBeTrue(); }); test('ensureMonth создаёт партицию saas_admin_audit_log (created_at)', function (): void { $manager = app(MonthlyPartitionManager::class); $manager->ensureMonth('saas_admin_audit_log', Carbon::parse('2024-03-01')); expect(partitionExists('saas_admin_audit_log_y2024_m03'))->toBeTrue(); }); test('partitionName возвращает правильный формат', function (): void { $manager = app(MonthlyPartitionManager::class); expect($manager->partitionName('auth_log', Carbon::parse('2026-05-15'))) ->toBe('auth_log_y2026_m05'); expect($manager->partitionName('deals', Carbon::parse('2024-01-01'))) ->toBe('deals_y2024_m01'); }); test('listPartitions возвращает созданные партиции', function (): void { $manager = app(MonthlyPartitionManager::class); $manager->ensureMonth('auth_log', Carbon::parse('2024-04-01')); $manager->ensureMonth('auth_log', Carbon::parse('2024-05-01')); $partitions = $manager->listPartitions('auth_log'); expect($partitions)->toContain('auth_log_y2024_m04') ->toContain('auth_log_y2024_m05'); }); // --------------------------------------------------------------------------- // Slepok routing: project_routing_snapshots (snapshot_date key, Этап 2, 27.05.2026) // --------------------------------------------------------------------------- test('PARTITIONED_TABLES включает project_routing_snapshots с ключом snapshot_date', function (): void { expect(MonthlyPartitionManager::PARTITIONED_TABLES) ->toHaveKey('project_routing_snapshots') ->and(MonthlyPartitionManager::PARTITIONED_TABLES['project_routing_snapshots']) ->toBe('snapshot_date'); }); test('ensureMonth создаёт партицию project_routing_snapshots (snapshot_date)', function (): void { $manager = app(MonthlyPartitionManager::class); $manager->ensureMonth('project_routing_snapshots', Carbon::parse('2024-07-01')); expect(partitionExists('project_routing_snapshots_y2024_m07'))->toBeTrue(); }); // --------------------------------------------------------------------------- // Task 0.5 (imitation harness): migrate:fresh resilience // ensureMonth must skip gracefully when parent table does not yet exist. // Without this guard, partitions:create-months called from migration 0001 // crashes on tables added by later delta-migrations (project_routing_snapshots, // lead_region_resolution_log) because their DDL runs after the initial schema load. // --------------------------------------------------------------------------- // Task 0.5 (imitation harness): regression guard for migrate:fresh resilience. // Migration 0001_01_01_000000_load_initial_schema calls Artisan::call('partitions:create-months') // which uses MonthlyPartitionManager::ensureMonth for EVERY table in PARTITIONED_TABLES. // Tables added by later delta-migrations (project_routing_snapshots, lead_region_resolution_log) // do not exist when 0001 runs → without the parent-exists guard, migrate:fresh crashes. // This test documents the regression requirement: ensureMonth MUST be callable for 'deals' // (an existing table) and MUST return bool (not throw) after the guard is added. test('ensureMonth для deals возвращает bool (guard регрессия migrate:fresh)', function (): void { $manager = app(MonthlyPartitionManager::class); // deals таблица создана в schema.sql — партиция либо уже существует, либо создаётся. $result = $manager->ensureMonth('deals', Carbon::parse('2025-01-01')); expect($result)->toBeBool(); // Связано: 0001_01_01_000000_load_initial_schema вызывает partitions:create-months. })->group('imitation');