Files
portal/app/tests/Unit/Autopodbor/Fetch/SelfRenderClientTest.php
T
Дмитрий 55bf6348b3 feat(autopodbor): SelfRenderClient — HTTP-клиент к рендер-сервису (фаза 5)
HTTP-клиент к своей виртуалке (замена xf4). Реализует BatchPageFetcher (и
PageFetcher): для 2ГИС просит initialState, для Яндекса/сайтов — HTML. Секрет
в заголовке X-Render-Key (из .env). Без ключа/адреса — молча пусто (деградация).
Http::pool для батча, ретраи. 7/7 тестов, Pint чисто.

- config services.self_render (endpoint/key/concurrency, всё из .env).
- config autopodbor: флаги self_render + гранулярные self_render_2gis/_yandex
  (наследуют master), дефолт ВЫКЛ.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-05 18:56:10 +03:00

82 lines
3.1 KiB
PHP

<?php
declare(strict_types=1);
use App\Services\Autopodbor\Agent\Fetch\BatchPageFetcher;
use App\Services\Autopodbor\Agent\Fetch\PageFetcher;
use App\Services\Autopodbor\Agent\Fetch\SelfRenderClient;
use Illuminate\Support\Facades\Http;
// SelfRenderClient — HTTP-клиент к рендер-сервису на виртуалке (замена xf4). Как XfetchClient: и
// PageFetcher (html), и BatchPageFetcher (htmlBatch). Для 2ГИС просит initialState, для Яндекса — HTML.
// Без ключа/адреса — молча пусто (деградация, не падение).
const EP = 'https://render.local/render';
function client(array $over = []): SelfRenderClient
{
return new SelfRenderClient(
endpoint: $over['endpoint'] ?? EP,
key: $over['key'] ?? 'secret',
concurrency: $over['concurrency'] ?? 4,
retries: $over['retries'] ?? 2,
);
}
it('реализует оба интерфейса', function () {
expect(client())->toBeInstanceOf(PageFetcher::class)
->and(client())->toBeInstanceOf(BatchPageFetcher::class);
});
it('html: POST на endpoint, тип initialState для 2ГИС, отдаёт data', function () {
Http::fake([EP => Http::response(['data' => '{"state":1}'], 200)]);
$out = client()->html('https://2gis.ru/krasnoyarsk/search/ломбард');
expect($out)->toBe('{"state":1}');
Http::assertSent(fn ($r) => $r->url() === EP
&& $r['url'] === 'https://2gis.ru/krasnoyarsk/search/ломбард'
&& $r['type'] === 'initialState'
&& $r->hasHeader('X-Render-Key', 'secret'));
});
it('html: тип html для Яндекса и прочего', function () {
Http::fake([EP => Http::response(['data' => '<html>ya</html>'], 200)]);
expect(client()->html('https://yandex.ru/maps/org/1'))->toBe('<html>ya</html>');
Http::assertSent(fn ($r) => $r['type'] === 'html');
});
it('без ключа или адреса → пусто, запрос не шлётся (деградация)', function () {
Http::fake([EP => Http::response(['data' => 'x'], 200)]);
expect(client(['key' => ''])->html('https://2gis.ru/x'))->toBe('')
->and(client(['endpoint' => ''])->html('https://2gis.ru/x'))->toBe('');
Http::assertNothingSent();
});
it('htmlBatch: карта url => data', function () {
Http::fake([EP => function ($request) {
return Http::response(['data' => 'R:'.$request['url']], 200);
}]);
$urls = ['https://2gis.ru/a', 'https://2gis.ru/b'];
expect(client()->htmlBatch($urls))->toBe([
'https://2gis.ru/a' => 'R:https://2gis.ru/a',
'https://2gis.ru/b' => 'R:https://2gis.ru/b',
]);
});
it('htmlBatch: пустой ключ → все пусто, без запросов', function () {
Http::fake([EP => Http::response(['data' => 'x'], 200)]);
expect(client(['key' => ''])->htmlBatch(['https://2gis.ru/a']))->toBe(['https://2gis.ru/a' => '']);
Http::assertNothingSent();
});
it('html: неуспешный ответ → пусто', function () {
Http::fake([EP => Http::response('', 500)]);
expect(client()->html('https://2gis.ru/x'))->toBe('');
});