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);
|
||
});
|