# Тестирование интеграции с ЕСИА

Этот документ описывает два способа проверки интеграции:

1. **Офлайн** — как устроено тестирование самой библиотеки и как гонять его
   локально без доступа к ЕСИА.
2. **Реальный тестовый стенд ЕСИА** — на что настроена библиотека по умолчанию и
   почему живую проверку мы описать не можем.

> [!WARNING]
> И промышленный контур, и тестовый стенд `esia-portal1.test.gosuslugi.ru`
> доступны только из РФ и требуют зарегистрированной информационной системы (ИС)
> и ГОСТ-сертификата. У авторов и контрибьюторов такого доступа может не быть,
> поэтому изменения проверяются офлайн — **обновляйтесь на свой страх и риск** и
> делитесь результатом в обсуждении
> [«Отчёты о совместимости с реальной средой ЕСИА»](https://github.com/fr05t1k/esia/discussions/93).

---

## 1. Офлайн-тестирование

Официальная документация ЕСИА **не предусматривает** изолированного тестирования:
единственный поддерживаемый путь — удалённый стенд, которому нужны сеть, тестовая
организация и ГОСТ-сертификат. Нет ни песочницы, ни спецификации мок-сервера, ни
готовых фикстур подписанных сообщений. Поэтому реальное офлайн-покрытие — это
ответственность самой библиотеки, и оно строится из четырёх частей.

### 1.1. HTTP-моки (юнит-тесты)

Библиотека работает поверх PSR-18/PSR-17, поэтому в тестах вместо реального
клиента подставляется [`php-http/mock-client`](https://github.com/php-http/mock-client).
Мок-клиент отдаёт заранее заданные PSR-7 ответы, а тесты проверяют, что
`buildUrl()`, `getToken()` и методы `rs/prns/*` (`getPersonInfo()`,
`getContactInfo()`, `getRoles()`, `getOrganizations()` и т. д.) формируют
правильные запросы и корректно разбирают ответы. См. `tests/unit/OpenIdTest.php`.

### 1.2. JWT-фикстуры

Маркер доступа приходит как JWT. Проверка подписи и claim'ов (`JwtValidator`)
тестируется на ключе, сгенерированном на лету, и на фикстурных ключах в
`tests/_data/` (`jwt-signing-key.pem`, `jwt-signing-pub.pem`). Так проверяется
и happy-path, и отклонение поддельного/просроченного маркера.

### 1.3. Локальный ГОСТ round-trip

ЕСИА требует подпись **ГОСТ Р 34.10-2012**. Тест `CliSignerRoundTripTest`
(`@group gost`) подписывает сообщение через OpenSSL с gost-engine и тут же
проверяет подпись — полностью локально, без ЕСИА. В CI это отдельная джоба
`gost-roundtrip`.

### 1.4. End-to-end против локального мок-сервера ЕСИА

Набор `tests/e2e` поднимает встроенный веб-сервер PHP с фикстурным роутером
(`tests/_support/mock_esia_router.php`), который имитирует эндпоинты ЕСИА:
обмен кода на маркер (`aas/oauth2/v3/te`, возвращает JWT с `urn:esia:sbj_id`) и
ресурсы `rs/prns/*` с реалистичными коллекциями (`size`/`elements`, абсолютные
ссылки на элементы). Затем прогоняется полный сценарий через **настоящий**
PSR-18 клиент (`symfony/http-client`):

```
buildUrl → getToken → getPersonInfo → getContactInfo → getRoles → getOrganizations
```

Так детерминированно и на любой машине проверяется весь HTTP-транспорт и разбор
ответов. Мок-сервер намеренно **не проверяет** подпись — его задача покрыть
транспорт, а не криптографию ЕСИА.

### 1.5. Как запустить локально

```bash
composer install
vendor/bin/codecept build   # генерирует акторов для наборов unit и e2e
vendor/bin/codecept run     # все наборы
vendor/bin/codecept run e2e # только end-to-end против мок-сервера
vendor/bin/codecept run unit OpenIdTest # конкретный тест
```

**ГОСТ-тесты** (`-g gost`) требуют OpenSSL с установленным gost-engine. Как в CI
(Ubuntu):

```bash
sudo apt-get install -y libengine-gost-openssl1.1
sudo cp tests/openssl.cnf /usr/lib/ssl/openssl.cnf
vendor/bin/codecept run -g gost
```

Без gost-engine эти тесты падают локально, но проходят в CI — это ожидаемо.

**Живой тест КриптоПро** (`CliCryptoProSignerTest`) выполняется только если задано
имя контейнера ключа в переменной окружения `ESIA_CRYPTOPRO_CONTAINER`
(опционально `ESIA_CRYPTOPRO_CSPTEST` — путь до `csptest`, `ESIA_CRYPTOPRO_PASSWORD` —
пароль контейнера); иначе он пропускается.

---

## 2. Реальный тестовый стенд ЕСИА

По умолчанию библиотека настроена на стенд
**`https://esia-portal1.test.gosuslugi.ru/`**. Значения по умолчанию берутся из
`Config` (проверяемо по коду):

| Назначение | Путь по умолчанию |
| --- | --- |
| Авторизационный код | `aas/oauth2/v2/ac` |
| Маркер идентификации (токен) | `aas/oauth2/v3/te` |
| Ресурсы персоны | `rs/prns/{oid}` |

> [!NOTE]
> Пошаговую процедуру получения доступа к реальному стенду мы здесь **намеренно
> не приводим**: у мейнтейнеров нет доступа к этой среде (она доступна только из
> РФ и требует зарегистрированной ИС и ГОСТ-сертификата), поэтому такие
> инструкции невозможно проверить и легко ошибиться. За актуальным порядком
> регистрации ИС, выпуска сертификата и получения `client_id`/scope обращайтесь к
> **официальной документации ЕСИА** и в техподдержку.

Для подписи запросов в любом случае понадобится ГОСТ-2012 сертификат и один из
бэкендов подписи (КриптоПро CSP или OpenSSL с gost-engine) — их настройка описана
в разделе [«Подпись запросов (сигнеры)»](../README.md#подпись-запросов-сигнеры)
README.

Если вам удалось (или не удалось) проверить обновление на реальном ЕСИА,
пожалуйста, поделитесь результатом в обсуждении
[#93](https://github.com/fr05t1k/esia/discussions/93) — это поможет остальным.
