7ed180b76b
Субагент убрал из SyncVkAudienceJob проверку общего рубильника enabled, потому что с ней не проходили тесты. Чинить надо было тесты: без этой проверки владелец выключает рекламу, Яндекс встаёт, а ВК продолжает тратить деньги. Тест на рубильник написан не через Http::assertNothingSent() — при трёх номерах джоб и без защиты не дошёл бы до обращения к ВК, и такой тест зелёный в любом случае (первая редакция именно так и прошла с вырезанной защитой). Наблюдаемая разница одна: с рубильником статус канала остаётся нетронутым, без него уезжает в waiting_volume. Проверено вырезанием. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
110 lines
4.5 KiB
PHP
110 lines
4.5 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
use App\Jobs\SyncVkAudienceJob;
|
|
use App\Models\SalesAdAudienceFirm;
|
|
use App\Models\SalesAdAudiencePhone;
|
|
use App\Models\SalesAdAudienceState;
|
|
use Illuminate\Foundation\Testing\DatabaseTransactions;
|
|
use Illuminate\Support\Facades\Http;
|
|
use Tests\Concerns\SharesSupplierPdo;
|
|
|
|
uses(DatabaseTransactions::class, SharesSupplierPdo::class);
|
|
|
|
beforeEach(function () {
|
|
// Реклама по умолчанию выключена (enabled=false в схеме). Каждый тест канала
|
|
// включает её явно — иначе джоб честно выходит на общем рубильнике и мы бы
|
|
// проверяли не то, что думаем.
|
|
SalesAdAudienceState::current()->update(['enabled' => true]);
|
|
});
|
|
|
|
it('когда реклама выключена рубильником, джоб вообще не работает', function () {
|
|
// 🔴 Выключатель «Реклама» обязан гасить ОБЕ площадки. Иначе владелец
|
|
// выключает рекламу, Яндекс встаёт, а ВК продолжает тратить деньги.
|
|
//
|
|
// 🪤 Проверять здесь Http::assertNothingSent() БЕСПОЛЕЗНО: при трёх номерах
|
|
// джоб и без рубильника не дошёл бы до обращения к ВК, и тест был бы зелёным
|
|
// в любом случае (проверено 19.07 — первая редакция теста проходила и с
|
|
// вырезанной защитой). Наблюдаемая разница одна: с рубильником джоб выходит
|
|
// сразу и статус канала остаётся нетронутым, без рубильника — он успевает
|
|
// проставить 'waiting_volume'.
|
|
SalesAdAudienceState::current()->update(['enabled' => false, 'vk_status' => 'no_access']);
|
|
config(['services.vk_ads.token' => 'test-token']);
|
|
vkFirmWithPhones(3);
|
|
|
|
SyncVkAudienceJob::dispatchSync();
|
|
|
|
expect(SalesAdAudienceState::current()->vk_status)->toBe('no_access');
|
|
});
|
|
|
|
/** Заводит фирму для ВК с нужным числом номеров. */
|
|
function vkFirmWithPhones(int $count): SalesAdAudienceFirm
|
|
{
|
|
$firm = SalesAdAudienceFirm::create([
|
|
'firm_name' => 'Тестовая стоматология',
|
|
'warmup_started_at' => now(),
|
|
'channels' => 'vk',
|
|
]);
|
|
|
|
for ($i = 1; $i <= $count; $i++) {
|
|
SalesAdAudiencePhone::create([
|
|
'phone' => '7999'.str_pad((string) $i, 7, '0', STR_PAD_LEFT),
|
|
'firm_id' => $firm->id,
|
|
'expires_at' => now()->addDays(30),
|
|
'state' => 'active',
|
|
]);
|
|
}
|
|
|
|
return $firm;
|
|
}
|
|
|
|
it('без ключей доступа не трогает ВК и пишет «нет доступа»', function () {
|
|
config(['services.vk_ads.token' => '']);
|
|
vkFirmWithPhones(3);
|
|
|
|
Http::fake();
|
|
|
|
SyncVkAudienceJob::dispatchSync();
|
|
|
|
Http::assertNothingSent();
|
|
expect(SalesAdAudienceState::current()->vk_status)->toBe('no_access');
|
|
});
|
|
|
|
it('пока номеров меньше двух тысяч, не делает ни одного обращения к ВК', function () {
|
|
// 🔴 Порог 2000 — требование самого ВК к загрузке списка программой.
|
|
// Обращаться раньше бессмысленно и опасно: ВК считает попытки.
|
|
config(['services.vk_ads.token' => 'test-token']);
|
|
vkFirmWithPhones(3);
|
|
|
|
Http::fake();
|
|
|
|
SyncVkAudienceJob::dispatchSync();
|
|
|
|
Http::assertNothingSent();
|
|
|
|
$state = SalesAdAudienceState::current();
|
|
|
|
expect($state->vk_status)->toBe('waiting_volume')
|
|
->and($state->vk_last_error)->toBeNull();
|
|
});
|
|
|
|
it('фирмы, помеченные только Яндексом, в счёт для ВК не идут', function () {
|
|
config(['services.vk_ads.token' => 'test-token']);
|
|
|
|
$yandexOnly = SalesAdAudienceFirm::create([
|
|
'firm_name' => 'Только Яндекс', 'warmup_started_at' => now(), 'channels' => 'yandex',
|
|
]);
|
|
SalesAdAudiencePhone::create([
|
|
'phone' => '79990000001', 'firm_id' => $yandexOnly->id,
|
|
'expires_at' => now()->addDays(30), 'state' => 'active',
|
|
]);
|
|
|
|
Http::fake();
|
|
|
|
SyncVkAudienceJob::dispatchSync();
|
|
|
|
Http::assertNothingSent();
|
|
expect(SalesAdAudienceState::current()->vk_status)->toBe('waiting_volume');
|
|
});
|