Files
portal/app/tests/Feature/ValidationRejectionLogTest.php
T

73 lines
3.4 KiB
PHP
Raw Normal View History

<?php
declare(strict_types=1);
use App\Models\Tenant;
use App\Models\User;
use Illuminate\Foundation\Testing\DatabaseTransactions;
use Illuminate\Support\Facades\Log;
uses(DatabaseTransactions::class);
/**
* Инцидент 14.07.2026: клиент получил 14 отказов подряд (формы «Добавить конкурента»,
* «Создать проект», «Удалить»), и в логах не осталось НИ СЛОВА о том, что именно порталу
* не понравилось. Причину пришлось час восстанавливать по размеру HTTP-ответа в nginx.
*
* Теперь каждый отказ по проверке полей пишется в журнал: маршрут, клиент и ИМЕНА полей.
* Уровень — warning: на проде LOG_LEVEL=warning, info в журнал не попадает вовсе.
* ЗНАЧЕНИЯ полей НЕ пишем — там персональные данные (телефоны, имена, ИНН), 152-ФЗ.
*/
it('пишет в журнал причину отказа: маршрут, клиента и имена полей', function () {
$tenant = Tenant::factory()->create();
$user = User::factory()->create(['tenant_id' => $tenant->id]);
Log::shouldReceive('warning')
->once()
->withArgs(function (string $event, array $ctx) use ($tenant) {
return $event === 'validation.rejected'
&& $ctx['path'] === 'api/projects'
&& $ctx['tenant_id'] === $tenant->id
&& in_array('name', $ctx['fields'], true);
});
Log::shouldReceive('info')->zeroOrMoreTimes();
Log::shouldReceive('error')->zeroOrMoreTimes();
Log::shouldReceive('debug')->zeroOrMoreTimes();
$this->actingAs($user)->postJson('/api/projects', [
'name' => '', // пусто → отказ
'signal_type' => 'call',
'signal_identifier' => '79991234567',
'daily_limit_target' => 10,
'regions' => [],
'delivery_days_mask' => 127,
])->assertStatus(422);
});
it('НЕ пишет в журнал значения полей — там персональные данные', function () {
$tenant = Tenant::factory()->create();
$user = User::factory()->create(['tenant_id' => $tenant->id]);
$logged = [];
Log::shouldReceive('warning')->andReturnUsing(function (string $event, array $ctx) use (&$logged) {
$logged[] = $ctx;
});
Log::shouldReceive('info')->zeroOrMoreTimes();
Log::shouldReceive('error')->zeroOrMoreTimes();
Log::shouldReceive('debug')->zeroOrMoreTimes();
$this->actingAs($user)->postJson('/api/projects', [
'name' => 'Стоматология Дениса',
'signal_type' => 'call',
'signal_identifier' => '79221364286', // личный телефон клиента
'daily_limit_target' => 10,
'regions' => [],
'delivery_days_mask' => 0, // отказ по дням недели
])->assertStatus(422);
$flat = json_encode($logged, JSON_UNESCAPED_UNICODE);
expect($flat)->toContain('delivery_days_mask') // имя поля — да
->and($flat)->not->toContain('79221364286') // телефон — ни в коем случае
->and($flat)->not->toContain('Стоматология Дениса');
});