Files
portal/app/tests/Unit/Autopodbor/Study/ParallelPhoneReverseTest.php
T
Дмитрий 0131ecfc47 fix(autopodbor): якорь по данным клиента на шаге 2 + параллельный разворот
Качество. Привязанные клиентом карточки 2ГИС/Яндекс теперь используются как
«земля» и якорь холдинга (раньше выбрасывались). Слепой поиск по имени берётся
только при наличии якоря; AnchorGate: пустой якорь → drop (было keep-всё — корень
шума). Без сайта чужие фирмы по широкому имени («Притяжение» → стоматология,
салоны, эротический магазин) больше не попадают в карточку конкурента. Доказано на
живых данных (Сибагропромстрой): свежий полный сбор — 0 салонов, только номера
застройщика.

Скорость (за флагом AUTOPODBOR_PHONE_REVERSE_PARALLEL, ВЫКЛ по умолчанию).
ParallelPhoneReverse крутит 2ГИС- и Яндекс-разворот ОДНОВРЕМЕННО (итог по времени
= max, не сумма; оба источника отрабатывают полностью — ничего не режется).
Сверка последовательно vs параллельно: данные один в один, потерь нет. Таймаут
подпроцесса 600с (драйвер process иначе берёт дефолт Symfony 60с и убивал разворот).

Тесты: AnchorGate (пустой якорь → drop; телефон-якорь режет чужое), якорь
привязанной карточки режет салоны, ParallelPhoneReverse (слияние на sync-драйвере).
Весь Autopodbor 464/464, Pint чист.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-06 08:54:48 +03:00

55 lines
3.1 KiB
PHP

<?php
use App\Services\Autopodbor\Agent\Study\ParallelPhoneReverse;
use App\Services\Autopodbor\Agent\Study\PhoneExpansionResult;
use App\Services\Autopodbor\Agent\Study\PhoneReverse;
// ParallelPhoneReverse крутит 2ГИС- и Яндекс-разворот ОДНОВРЕМЕННО (итог = max, не сумма), затем
// сливает находки: сайты дедуп по домену, телефоны по цифрам, 2ГИС (первый) выигрывает при совпадении.
// В тестах — драйвер concurrency 'sync' (детерминированно, в том же процессе).
function parFakeReverse(array $sites, array $phones): PhoneReverse
{
return new class($sites, $phones) implements PhoneReverse
{
public function __construct(private array $sites, private array $phones) {}
public function expand(string $gisSlug, array $seedPhones, array $seedDomains, string $yandexSlug = ''): PhoneExpansionResult
{
return new PhoneExpansionResult($this->sites, $this->phones);
}
};
}
beforeEach(fn () => config()->set('concurrency.default', 'sync'));
it('сливает находки обоих разворотов: дедуп сайтов и телефонов, 2ГИС выигрывает', function () {
$gis = parFakeReverse(
sites: [['domain' => 'a.ru', 'site_url' => 'https://a.ru', 'card_url' => 'gis/a']],
phones: [['digits' => '73912000001', 'url' => 'gis/1', 'source' => '2ГИС'],
['digits' => '73912000009', 'url' => 'gis/9', 'source' => '2ГИС']],
);
$yandex = parFakeReverse(
sites: [['domain' => 'b.ru', 'site_url' => 'https://b.ru', 'card_url' => 'ya/b'],
['domain' => 'a.ru', 'site_url' => 'https://a.ru', 'card_url' => 'ya/a']], // дубль домена a.ru
phones: [['digits' => '73912000002', 'url' => 'ya/2', 'source' => 'Яндекс'],
['digits' => '73912000009', 'url' => 'ya/9', 'source' => 'Яндекс']], // дубль номера ...009
);
$res = (new ParallelPhoneReverse($gis, $yandex))->expand('krasnoyarsk', ['73912000000'], [], '62/krasnoyarsk');
// сайты: a.ru (от 2ГИС) + b.ru — дубль a.ru от Яндекса отброшен
expect($res->sites)->toHaveCount(2)
->and(array_column($res->sites, 'domain'))->toEqualCanonicalizing(['a.ru', 'b.ru'])
->and(collect($res->sites)->firstWhere('domain', 'a.ru')['card_url'])->toBe('gis/a'); // 2ГИС выиграл
// телефоны: 001, 009 (2ГИС), 002 — дубль 009 от Яндекса отброшен
expect(array_column($res->phones, 'digits'))->toEqualCanonicalizing(['73912000001', '73912000009', '73912000002'])
->and(collect($res->phones)->firstWhere('digits', '73912000009')['source'])->toBe('2ГИС');
});
it('пустые находки — пустой результат', function () {
$res = (new ParallelPhoneReverse(parFakeReverse([], []), parFakeReverse([], [])))->expand('krasnoyarsk', [], [], '');
expect($res->sites)->toBe([])->and($res->phones)->toBe([]);
});