Files
portal/app/tests/Feature/ClientTg/TelegramRobotQueueTest.php
T
Дмитрий e75bb76adf feat телеграм-робот: очередь заданий — поставить, выдать по одному, вернуть зависшее
Выдача строго по одному: у робота один профиль браузера и одна сессия кабинета.
Задание, по которому робот не отчитался за срок аренды, возвращается в очередь.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-31 08:07:27 +03:00

84 lines
3.4 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<?php
declare(strict_types=1);
use App\Models\ClientTg\Campaign;
use App\Models\ClientTg\RobotJob;
use App\Models\Tenant;
use App\Services\ClientTg\TelegramRobotQueue;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Support\Facades\DB;
uses(RefreshDatabase::class);
// Фабрики у ClientTg\Campaign нет — состав полей списан с CampaignChargeServiceTest.
function tgJobCampaign(int $tenantId, string $status = Campaign::STATUS_QUEUED): Campaign
{
return Campaign::query()->create([
'tenant_id' => $tenantId,
'status' => $status,
'ad_text' => 'Приходите к нам за услугой',
'ad_link' => 'https://example.test/promo',
'ord_category' => 'Размещение рекламы',
'budget_cap_rub' => '500.00',
'audience_kind' => Campaign::AUDIENCE_LIST,
'planned_count' => 2,
'estimated_cost_rub' => '315.00',
'created_by' => 1,
]);
}
// Тенант и кампания настоящие: у задания внешние ключи на обе таблицы, выдуманные
// номера база просто не пропустит.
beforeEach(function () {
$this->tenant = Tenant::factory()->create(['balance_rub' => '1000.00']);
DB::statement('SET LOCAL app.current_tenant_id = '.$this->tenant->id);
$this->campaign = tgJobCampaign($this->tenant->id);
});
it('ставит задание и не задваивает его для одной кампании', function () {
$queue = app(TelegramRobotQueue::class);
$first = $queue->enqueue($this->tenant->id, $this->campaign->id, RobotJob::MODE_DRAFT, ['adText' => 'а']);
$second = $queue->enqueue($this->tenant->id, $this->campaign->id, RobotJob::MODE_DRAFT, ['adText' => 'а']);
expect($second->id)->toBe($first->id);
expect(RobotJob::where('campaign_id', $this->campaign->id)->count())->toBe(1);
});
it('выдаёт очередное задание и переводит его в работу', function () {
$queue = app(TelegramRobotQueue::class);
$queue->enqueue($this->tenant->id, $this->campaign->id, RobotJob::MODE_DRAFT, []);
$taken = $queue->takeNext();
expect($taken)->not->toBeNull();
expect($taken->status)->toBe(RobotJob::STATUS_TAKEN);
expect($taken->taken_at)->not->toBeNull();
expect($taken->attempts)->toBe(1);
});
it('второму роботу не выдаёт задание, пока первое в работе', function () {
$second = tgJobCampaign($this->tenant->id);
$queue = app(TelegramRobotQueue::class);
$queue->enqueue($this->tenant->id, $this->campaign->id, RobotJob::MODE_DRAFT, []);
$queue->enqueue($this->tenant->id, $second->id, RobotJob::MODE_DRAFT, []);
expect($queue->takeNext())->not->toBeNull();
expect($queue->takeNext())->toBeNull();
});
it('возвращает в очередь задание, зависшее дольше срока аренды', function () {
config()->set('client_tg.robot.poll_lease_minutes', 20);
$queue = app(TelegramRobotQueue::class);
$job = $queue->enqueue($this->tenant->id, $this->campaign->id, RobotJob::MODE_DRAFT, []);
$queue->takeNext();
RobotJob::where('id', $job->id)->update(['taken_at' => now()->subMinutes(21)]);
$again = $queue->takeNext();
expect($again)->not->toBeNull();
expect($again->id)->toBe($job->id);
expect($again->attempts)->toBe(2);
});