89 lines
3.9 KiB
PHP
89 lines
3.9 KiB
PHP
|
|
<?php
|
|||
|
|
|
|||
|
|
declare(strict_types=1);
|
|||
|
|
|
|||
|
|
use Illuminate\Foundation\Testing\DatabaseTransactions;
|
|||
|
|
use Illuminate\Support\Facades\DB;
|
|||
|
|
use Tests\Concerns\SharesSupplierPdo;
|
|||
|
|
|
|||
|
|
uses(DatabaseTransactions::class);
|
|||
|
|
uses(SharesSupplierPdo::class);
|
|||
|
|
|
|||
|
|
function rossvyazFixture(): string
|
|||
|
|
{
|
|||
|
|
return base_path('tests/Fixtures/rossvyaz/sample.csv');
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
it('dry-run parses csv, maps regions to subject_code, builds staging, does not swap', function (): void {
|
|||
|
|
$this->artisan('phone-ranges:import', ['--file' => rossvyazFixture(), '--dry-run' => true])
|
|||
|
|
->assertSuccessful();
|
|||
|
|
|
|||
|
|
// Staging построен (dry-run не свапает и не дропает staging — данные видны в той же tx).
|
|||
|
|
expect(DB::table('phone_ranges_staging')->count())->toBe(3);
|
|||
|
|
|
|||
|
|
$r495 = DB::selectOne('SELECT subject_code FROM phone_ranges_staging WHERE def_code = 495');
|
|||
|
|
$r921 = DB::selectOne('SELECT subject_code FROM phone_ranges_staging WHERE def_code = 921');
|
|||
|
|
$r999 = DB::selectOne('SELECT subject_code FROM phone_ranges_staging WHERE def_code = 999');
|
|||
|
|
|
|||
|
|
expect((int) $r495->subject_code)->toBe(82) // Москва
|
|||
|
|
->and((int) $r921->subject_code)->toBe(83) // Санкт-Петербург
|
|||
|
|
->and($r999->subject_code)->toBeNull(); // Атлантида — не маппится
|
|||
|
|
|
|||
|
|
// Живой phone_ranges не тронут (свапа не было).
|
|||
|
|
expect(DB::table('phone_ranges')->count())->toBe(0);
|
|||
|
|
|
|||
|
|
// Журнал импорта: dry-run → rolled_back, несматчившийся регион в error.
|
|||
|
|
$imp = DB::table('phone_ranges_imports')->orderByDesc('id')->first();
|
|||
|
|
expect($imp->status)->toBe('rolled_back')
|
|||
|
|
->and($imp->error)->toContain('Атлантида');
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
it('maps all matched rows and counts unmatched separately', function (): void {
|
|||
|
|
$this->artisan('phone-ranges:import', ['--file' => rossvyazFixture(), '--dry-run' => true])
|
|||
|
|
->assertSuccessful();
|
|||
|
|
|
|||
|
|
$matched = DB::table('phone_ranges_staging')->whereNotNull('subject_code')->count();
|
|||
|
|
$unmatched = DB::table('phone_ranges_staging')->whereNull('subject_code')->count();
|
|||
|
|
|
|||
|
|
expect($matched)->toBe(2)->and($unmatched)->toBe(1);
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
it('skips swap when checksum matches a completed import (idempotency)', function (): void {
|
|||
|
|
$checksum = hash_file('sha256', rossvyazFixture());
|
|||
|
|
DB::table('phone_ranges_imports')->insert([
|
|||
|
|
'source_url' => 'https://rossvyaz.gov.ru/prev',
|
|||
|
|
'checksum_sha256' => $checksum,
|
|||
|
|
'status' => 'completed',
|
|||
|
|
'imported_at' => now(),
|
|||
|
|
'completed_at' => now(),
|
|||
|
|
]);
|
|||
|
|
|
|||
|
|
// Не dry-run: но checksum совпал с completed → короткое замыкание ДО свапа.
|
|||
|
|
$this->artisan('phone-ranges:import', ['--file' => rossvyazFixture()])
|
|||
|
|
->assertSuccessful();
|
|||
|
|
|
|||
|
|
expect(DB::table('phone_ranges')->count())->toBe(0); // свапа не было
|
|||
|
|
|
|||
|
|
$latest = DB::table('phone_ranges_imports')->orderByDesc('id')->first();
|
|||
|
|
expect($latest->status)->toBe('rolled_back');
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
it('force flag bypasses idempotency note even with matching checksum', function (): void {
|
|||
|
|
// С --dry-run + --force: идемпотентность игнорируется, но dry-run всё равно не свапает.
|
|||
|
|
$checksum = hash_file('sha256', rossvyazFixture());
|
|||
|
|
DB::table('phone_ranges_imports')->insert([
|
|||
|
|
'source_url' => 'https://rossvyaz.gov.ru/prev',
|
|||
|
|
'checksum_sha256' => $checksum,
|
|||
|
|
'status' => 'completed',
|
|||
|
|
'imported_at' => now(),
|
|||
|
|
'completed_at' => now(),
|
|||
|
|
]);
|
|||
|
|
|
|||
|
|
$this->artisan('phone-ranges:import', ['--file' => rossvyazFixture(), '--dry-run' => true, '--force' => true])
|
|||
|
|
->assertSuccessful();
|
|||
|
|
|
|||
|
|
// --force обошёл idempotency → staging построен заново (3 строки), но dry-run не свапнул.
|
|||
|
|
expect(DB::table('phone_ranges_staging')->count())->toBe(3);
|
|||
|
|
expect(DB::table('phone_ranges')->count())->toBe(0);
|
|||
|
|
});
|