57 lines
2.8 KiB
PHP
57 lines
2.8 KiB
PHP
|
|
<?php
|
||
|
|
|
||
|
|
declare(strict_types=1);
|
||
|
|
|
||
|
|
use App\Models\AdWallet;
|
||
|
|
use App\Models\Tenant;
|
||
|
|
use App\Services\Advertising\AdWalletService;
|
||
|
|
use Illuminate\Support\Facades\DB;
|
||
|
|
|
||
|
|
/**
|
||
|
|
* 🔴 КЛАСС «тихий ноль». Тесты ходят СУПЕРЮЗЕРОМ, который обходит защиту по клиентам,
|
||
|
|
* и потому физически не могут увидеть эту дыру. На бою очередь работает под обычной
|
||
|
|
* ролью, а защита на таблицах `ad_*` устроена СТРОГО:
|
||
|
|
*
|
||
|
|
* USING (tenant_id = NULLIF(current_setting('app.current_tenant_id', true), '')::bigint)
|
||
|
|
*
|
||
|
|
* Нет контекста — сравнение с NULL, и база молча отдаёт ноль строк. `release()` видит
|
||
|
|
* «кошелька нет», честно выходит, и заморозка клиента остаётся навсегда. Ни ошибки,
|
||
|
|
* ни строки в журнале.
|
||
|
|
*
|
||
|
|
* Этот сторож гоняет деньги ПОД БОЕВОЙ РОЛЬЮ и БЕЗ контекста — то есть ровно так, как
|
||
|
|
* их зовёт джоб проверки модерации.
|
||
|
|
*/
|
||
|
|
function podBoevoyRolyu(callable $chto): void
|
||
|
|
{
|
||
|
|
DB::statement('SET ROLE crm_app_user');
|
||
|
|
try {
|
||
|
|
$chto();
|
||
|
|
} finally {
|
||
|
|
DB::statement('RESET ROLE');
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
it('снимает заморозку под боевой ролью без контекста клиента — как её зовёт джоб модерации', function () {
|
||
|
|
$tenant = Tenant::factory()->create();
|
||
|
|
AdWallet::create(['tenant_id' => $tenant->id, 'balance_rub' => '3000.00', 'frozen_rub' => '0.00']);
|
||
|
|
$svc = app(AdWalletService::class);
|
||
|
|
|
||
|
|
$svc->freeze($tenant->id, 'yandex', 'campaign', 1, '1000.00');
|
||
|
|
|
||
|
|
// Яндекс отклонил весь набор объявлений: джоб возвращает клиенту заморозку целиком.
|
||
|
|
podBoevoyRolyu(fn () => $svc->release($tenant->id, 'yandex', 'campaign', 1));
|
||
|
|
|
||
|
|
// Читаем суперюзером — прибор не должен зависеть от той же защиты, что проверяем.
|
||
|
|
expect((string) AdWallet::where('tenant_id', $tenant->id)->first()->frozen_rub)->toBe('0.00');
|
||
|
|
});
|
||
|
|
|
||
|
|
it('замораживает под боевой ролью без контекста клиента', function () {
|
||
|
|
$tenant = Tenant::factory()->create();
|
||
|
|
AdWallet::create(['tenant_id' => $tenant->id, 'balance_rub' => '3000.00', 'frozen_rub' => '0.00']);
|
||
|
|
$svc = app(AdWalletService::class);
|
||
|
|
|
||
|
|
podBoevoyRolyu(fn () => $svc->freeze($tenant->id, 'yandex', 'campaign', 2, '700.00'));
|
||
|
|
|
||
|
|
expect((string) AdWallet::where('tenant_id', $tenant->id)->first()->frozen_rub)->toBe('700.00');
|
||
|
|
});
|