Gonka GitHub Discussions · Discussion #1334

Предложение по автоматизации Devshard E2E тестов

Отдельная страница дискуссии с русским переводом и параллельным режимом RU / Original с точным сопоставлением предложений.

Как пользоваться: включите RU / Original и кликните по предложению — соответствующее предложение в другой колонке доскроллится и подсветится.
Discussion #1334

Предложение по автоматизации Devshard E2E тестов

Оригинал: Devshard E2E Test Automation Proposal

aikuznetsov avatar
aikuznetsovCollaboratorАвтор
2026-06-10

Цель

Создайте настоящий уровень интеграционного тестирования для devshard, который запускается на основе тестов Go, но проверяет систему с помощью контейнеров Docker, реальной сети HTTP, реальных границ процессов и реального хранилища.

Этот пакет должен дополнять существующие модульные, пакетные и httptest-тесты. Эти тесты остаются слоем быстрой корректности. Пакет E2E проверяет, что один и тот же протокол работает при запуске, подключении, перезапуске и сбое компонентов, как и реальные службы.

Область применения

Тест-раннер — Go. Среда выполнения — Docker.

Пакет не должен зависеть от действующей цепочки Cosmos, Testermint или decentralized-api. Метаданные, связанные с цепочкой, обслуживаются локальным фиктивным сервисом. Для вывода и проверки используются детерминированные механизмы-заглушки, если в сценарии явно не выбран другой бэкэнд.

За пределами первой версии:

проверка стека наблюдения за добычей

долговременная производительность или тестирование на выдержку

подача расчетов в живой цепочке

реальное выполнение модели машинного обучения

полный поток управления версиями

Их можно будет добавить позже как отдельные профили, как только уровень основного протокола E2E станет стабильным.

Инструменты и платформы тестирования

Первая реализация E2E должна сохранить небольшой набор инструментов и использовать Go-native.

Рекомендуемые инструменты:

Инструменты, которых следует избегать в первой версии:

  • Исполнители сценариев Python: Go сохраняет сценарии близкими к типам devshard, помощникам подписи, помощникам хранилища и существующим утверждениям. Добавление Python создаст вторую среду выполнения тестов до того, как контракт E2E станет стабильным.
  • Docker Compose в качестве основного оркестратора тестов: testcontainers-go дает каждому тесту Go прямой контроль над сетями, контейнерами, портами, журналами, перезапусками и очисткой. Compose может пригодиться позже для ручного воспроизведения.
  • живая цепочка Cosmos или Testermint: первый пакет должен изолировать протокол devshard и поведение транспорта от запуска цепочки, производства блоков, управления и несвязанных сбоев узлов. Mock-chain охватывает мостовой контракт, необходимый devshard.
  • Реальное выполнение модели машинного обучения: детерминированный вывод заглушки обеспечивает быстроту, воспроизводимость тестов и сосредоточенность на поведении протокола, а не на доступности графического процессора/модели или качестве генерации.
  • автоматизация браузера/UI: devshard E2E проверяет HTTP API и состояние протокола. Автоматизация браузера добавит проблемы с медленным пользовательским интерфейсом, которые не являются частью этого предложения.

Структура тестовой среды

Каждый тест запускает изолированную сеть Docker. Процесс тестирования Go остается вне сети и контролирует среду через API-интерфейсы Docker и сопоставленные сервисные порты.

Среда дыма по умолчанию должна развернуться:

один контейнер макетной цепочки

три контейнера devshard-host-N

один контейнер devshardctl

один контейнер Postgres

Сценарии хранения и сбоя добавляют контейнеры или тома по мере необходимости:

постоянные тома SQLite для тестов перезапуска

дополнительные конечные точки управления для каждой службы для детерминированного внедрения ошибок

блок-схема LR TestRunner["Go E2E test runner"] Docker["Docker / testcontainers-go"] Client["HTTP утверждения"] subgraph Net["изолированная сеть Docker"] MockChain["mock-chain\nchain метаданные + API управления"] DevshardCtl["devshardctl\nOpenAI-совместимый API"] Host0["devshard-host-0\nslot 0"] Host1["devshard-host-1\nslot 1"] Host2["devshard-host-2\nslot 2"] Postgres["postgres\nsmoke Storage Backend"] Vol0[("host-0 SQLite Volume")] Vol1[("host-1 SQLite Volume")] Vol2[("host-2 SQLite Volume")] end TestRunner --> Docker TestRunner --> Client Client --> Клиент DevshardCtl -.прямые проверки протокола.-> Клиент Host0 -.прямые проверки протокола.-> Клиент Host1 -.прямые проверки протокола.-> Host2 DevshardCtl --> Host0 DevshardCtl --> Host1 DevshardCtl --> Host2 Host0 <-->|gossip| Хост1 Хост1 <-->|сплетни| Хост2 Хост2 <-->|сплетни| Host0 Host0 --> MockChain Host1 --> MockChain Host2 --> MockChain DevshardCtl --> MockChain Host0 --> Postgres Host1 --> Postgres Host2 --> Postgres Host0 -.sqlite профиль.-> Vol0 Host1 -.sqlite профиль.-> Vol1 Host2 -.sqlite профиль.-> Vol2

Инвентаризация контейнеров:

Первая реализация должна быть стандартизирована для группы из трех хостов, поскольку многие варианты поведения протокола требуют формы, подобной большинству: ротация исполнителей, голосование по тайм-ауту, накопление подписей и сходимость слухов. Жгут может позже подвергать Hosts: N стресс-тестам или тестам в крайних случаях.

Службы времени выполнения

Каждая среда E2E запускает изолированную сеть Docker и небольшой набор сервисов.

макет цепи

Mock-chain — это локальная служба метаданных, которая реализует подмножество поведения моста основной сети, необходимое для devshard.

Первая реализация должна точно соответствовать текущей форме моста REST. Это заставляет E2E сосредоточиться на проверке мостового контракта, который разработчик уже использует, вместо добавления второго API, предназначенного только для макетов. Более чистый API внутреннего контроля можно добавить позже вместе с REST-совместимыми конечными точками, но настройка и восстановление протокола должны продолжать выполняться по тем же путям, что и рабочий код.

Он служит детерминированной локальной конфигурацией для:

идентификатор условного депонирования

адрес создателя условного депонирования

баланс условного депонирования

идентификатор эпохи

хэш приложения

назначение слотов хоста

URL-адреса вывода хоста

цена токена

порог проверки

гранты «теплый ключ»

утвержденные версии devshard, когда они нужны сценарию версии

Он также должен предоставить API управления только для разработчиков для тестовых сценариев:

передовая эпоха

изменить утвержденные версии

изменить метаданные хоста

добавить или удалить гранты «теплых ключей»

ввести задержки ответа

вводить ошибки моста

devshard-host-N

В каждом хост-контейнере работает один участник. Процесс должен использовать реальный хост devshard, транспорт, подпись, хранилище, сплетни и код конечного автомата.

Конфигурируемые входы:

идентификатор условного депонирования

ключ подписывающего лица хоста

адрес пользователя

назначение слота

префикс маршрута

URL-адреса одноранговых хостов

серверная часть хранилища

URL-адрес макетной цепочки

поведение заглушки вывода

поведение проверки заглушки

Хост должен предоставлять стандартные транспортные маршруты devshard, смонтированные либо с префиксом устаревшего маршрута, либо с префиксом версии:

/v1/devshard/* /devshard/<версия>/*

devshardctl

Пакет должен включать сценарии, которые направляют запросы через OpenAI-совместимую поверхность devshardctl. Это подтверждает путь, обращенный к пользователю:

клиент -> devshardctl -> транспортные клиенты devshard -> хост-контейнеры

Некоторые сценарии более низкого уровня могут напрямую обращаться к конечным точкам транспорта хоста, когда это делает утверждение более ясным, но пакет дыма должен использовать devshardctl .

постгрес

Postgres является частью дымовой среды и должен быть базовым хранилищем по умолчанию для дымовых тестов CI. SQLite остается полезным для локальных тестов перезапуска и крайних случаев сохранения состояния одного хоста.

Сценарии хранения должны охватывать:

Перезапуск хоста SQLite

Перезапуск хоста Postgres

перезапуск всех хостов

конфликт версий сеанса

конфликт эпохи сеанса, где это применимо

Тестовые двоичные файлы

Пакету E2E нужны исполняемые команды, которые представляют собой небольшие оболочки существующих пакетов devshard.

Рекомендуемые команды:

devshard/cmd/devshardd/main.go devshard/cmd/mock-chain/main.go

девшардд

devshardd запускает одного хост-участника.

Для первой реализации E2E devshardd должна быть командой только для E2E. Его пока не следует рассматривать как производственный двоичный файл. Это позволяет сосредоточить первую итерацию на проверке интеграции, оставляя при этом место для усиления и продвижения команды позже, если она примет правильную производственную форму.

Он должен подключить:

мостовой клиент

государственная машина

хозяин

транспортный сервер

хранение

коллеги по сплетням

машина вывода

механизм проверки

конечная точка готовности

конечная точка управления только для разработчиков, если она явно включена

Для E2E devshardd может начать с механизмов вывода и проверки заглушки. Важным моментом является то, что сама среда выполнения протокола реальна.

макет цепи

Mock-chain обслуживает локальные метаданные и детерминированное поведение управления. Он должен начинаться как простой HTTP-сервер, соответствующий текущей форме моста REST. Если позже devshard перейдет на другой протокол клиента цепочки, макет должен следовать этой границе.

Внесение ошибок

Детерминированное внесение ошибок должно быть частью проекта тестирования с самого начала. Без него тесты тайм-аута и восстановления становятся медленными и нестабильными.

Первая поверхность управления должна поддерживать:

провалить следующий вывод

отложить следующий вывод

отложить следующий вывод до его отмены

удержать расписку исполнителя

вернуть поврежденный хэш ответа

вернуть неверный результат проверки

приостановить сплетни

возобновить сплетни

отклонять запросы метаданных моста

вернуть устаревшие метаданные моста

предварительная имитация эпохи

изменить утвержденные версии

Средства контроля неисправностей должны быть отключены, если процесс не запущен в явном тестовом режиме.

Набор сценариев

Сценарии дыма

Сценарии дыма должны быть надежными и достаточно быстрыми для каждого запуска CI.

  • Счастливый путь Запустите три хоста и devshardctl. Отправьте несколько запросов на завершение непотокового чата. Завершите сеанс. Подтвердите, что выходные данные расчета присутствуют и все хосты согласны с окончательным состоянием.

Счастливый путь

Запустите три хоста и devshardctl. Отправьте несколько запросов на завершение непотокового чата. Завершите сеанс. Подтвердите, что выходные данные расчета присутствуют и все хосты согласны с окончательным состоянием.

  • Путь потоковой передачи Отправьте запрос на завершение потокового чата через devshardctl. Подтвердите, что клиент получил фрагменты контента и [DONE] . Получение/мета-события протокола Assert devshard обрабатываются внутри и не повреждают поток, совместимый с OpenAI.

Путь потоковой передачи

Отправьте запрос на завершение потокового чата через devshardctl. Подтвердите, что клиент получил фрагменты контента и [DONE] . Получение/мета-события протокола Assert devshard обрабатываются внутри и не повреждают поток, совместимый с OpenAI.

  • Отказ в аутентификации Отправьте запрос защищенного хоста, подписанный неавторизованным ключом. Укажите, что запрос отклонен из-за ошибки авторизации.

Отказ в аутентификации

Отправьте запрос защищенного хоста, подписанный неавторизованным ключом. Укажите, что запрос отклонен из-за ошибки авторизации.

Сценарии протоколов

  • Конвергенция сплетен Отправьте работу, пока все хосты работают. Данные подтверждения nonce, мемпула и подписи распространяются между участниками и сходятся.

Сближение сплетен

Отправляйте работу, пока все хосты работают. Данные подтверждения nonce, мемпула и подписи распространяются между участниками и сходятся.

  • Догон хоста. Позвольте одному хосту пропустить более ранние различия, а затем отправьте ему более поздний запрос с догоняющими различиями. Утвердите, что он достигает того же корня состояния, что и остальная часть группы.

Догонялка хоста

Позвольте одному хосту пропустить более ранние различия, а затем отправьте ему более поздний запрос с догоняющими различиями. Утвердите, что он достигает того же корня состояния, что и остальная часть группы.

  • Сбой и тайм-аут исполнителя. Настройте выбранный исполнитель на сбой или зависание. Собираются голоса за утверждение тайм-аута, применяется транзакция тайм-аута, и сеанс может продолжиться или завершиться в соответствии с правилами протокола.

Сбой исполнителя и тайм-аут

Настройте выбранного исполнителя на сбой или зависание. Собираются голоса за утверждение тайм-аута, применяется транзакция тайм-аута, и сеанс может продолжиться или завершиться в соответствии с правилами протокола.

  • Запрос квитанции Отложите или потеряйте путь ответа исполнителя, а затем запросите у исполнителя запрос на получение. Подтвердите, что квитанция действительна и сеанс пользователя может ее обработать.

Получение вызова

Приостановите или потеряйте путь ответа исполнителя, а затем запросите у исполнителя квитанцию. Подтвердите, что квитанция действительна и сеанс пользователя может ее обработать.

Сценарии восстановления

  • Перезапуск хоста SQLite. Выполните несколько выводов, перезапустите один хост-контейнер с сохраненным томом SQLite, продолжите сеанс и завершите его. Подтвердите отсутствие регрессии nonce и перезапущенный хост подписывает окончательное состояние.

Перезапуск хоста SQLite

Выполните несколько выводов, перезапустите один хост-контейнер с сохраненным томом SQLite, продолжите сеанс и завершите его. Подтвердите отсутствие регрессии nonce и перезапущенный хост подписывает окончательное состояние.

  • Восстановление Postgres. Запустите счастливый путь с включенным хранилищем Postgres. Перезагрузите все хосты и продолжите сеанс. Утверждение восстановления состояния из Postgres работает, и финализация прошла успешно.

Восстановление Postgres

Пройдите счастливый путь с включенным хранилищем Postgres. Перезагрузите все хосты и продолжите сеанс. Утверждение восстановления состояния из Postgres работает, и финализация прошла успешно.

  • Перезапуск всех хостов перед финализацией. Запустите несколько логических выводов, остановите каждый хост, перезапустите их, затем завершите. Утверждайте, что сохраненных различий и подписей достаточно для восстановления.

Перезапуск всего хоста перед финализацией

Запустите несколько выводов, остановите каждый хост, перезапустите их, затем завершите. Утверждайте, что сохраненных различий и подписей достаточно для восстановления.

Версия и сценарии маршрутизации

  • Префикс устаревшего маршрута. Запустите сеанс через /v1/devshard/* и убедитесь, что сохраненная версия сеанса — v1.

Префикс устаревшего маршрута

Запустите сеанс через /v1/devshard/* и убедитесь, что сохраненная версия сеанса — v1 .

  • Префикс версионного маршрута. Запустите сеанс через /devshard/<version>/* и убедитесь, что сохраненная версия сеанса является выбранной версией.

Префикс версионного маршрута

Запустите сеанс через /devshard/<version>/* и убедитесь, что сохраненная версия сеанса является выбранной версией.

  • Конфликт версий. Создайте или восстановите одно и то же условное депонирование в одной версии, а затем попытайтесь прикрепить то же условное депонирование в другой версии. Хранилище утверждений отклоняет конфликт.

Конфликт версий

Создайте или восстановите одно и то же условное депонирование в одной версии, а затем попытайтесь прикрепить то же условное депонирование в другой версии. Хранилище утверждений отклоняет конфликт.

Сценарии метаданных цепочки

  • Авторизация по «теплому ключу» Настройте предоставление «теплого ключа» в Mock-chain. Утверждает, что теплый ключ может аутентифицироваться там, где это разрешено, и отклоняется после удаления разрешения или при использовании не для того участника.

Авторизация по теплому ключу

Настройте предоставление теплого ключа в макетной цепочке. Утверждает, что теплый ключ может аутентифицироваться там, где это разрешено, и отклоняется после удаления разрешения или при использовании не для того участника.

  • Сбой метаданных моста Внедрить ошибку метаданных моста во время создания или восстановления сеанса. Подтвердить, что хост не готов к сбою или возвращает ожидаемый ответ о недоступности службы.

Ошибка метаданных моста

Внедрить ошибку метаданных моста во время создания или восстановления сеанса. Подтвердить, что хост не готов к сбою или возвращает ожидаемый ответ о недоступности службы.

Утверждения

Тесты E2E должны избегать утверждения только кодов состояния HTTP. Полезные утверждения уровня протокола включают в себя:

ожидаемая форма ответа, совместимая с OpenAI

ожидаемая форма потока SSE

монотонная прогрессия nonce

ожидаемые переходы состояний вывода

сопоставление конечного корня состояния между хостами

ожидаемые подписи по слотам

  • Полезная нагрузка расчета включает окончательный номер кода, состояние, версию и подписи.

Выводы метаданных хранилища депонируются до ожидаемой эпохи и версии

перезапущенные хосты восстанавливают последнее известное состояние

неавторизованные подписанты отклоняются

сценарии ошибок создают ожидаемую транзакцию протокола

Расчетный договор

До тех пор, пока пакет E2E не передаст расчет в действующую цепочку, стабильный расчетный контракт должен быть протокольным обязательством, необходимым для проверки на стороне цепочки.

Заявления о базовом урегулировании должны охватывать:

идентификатор условного депонирования

сессионная версия

последний одноразовый номер

окончательный корень состояния или окончательное государственное обязательство

фаза терминального сеанса

конечное состояние для каждого включенного вывода

пороговые подписи

каждая подпись подтверждает окончательное государственное обязательство

каждая подпись сопоставляется с действительным слотом в группе сеансов

дубликаты подписей слотов не учитываются дважды

Экономические поля, такие как учет токенов, комиссии, оставшийся баланс, затраты хоста, пропущенные подсчеты и штрафы за проверку, следует указывать только в специальных сценариях учета. Они не должны быть частью базового контракта по урегулированию дыма до тех пор, пока путь подачи цепочки не станет частью пакета E2E.

Уровни CI

Используйте целенаправленные запуски тестов, а не один большой недифференцированный пакет. CI должен создать необходимые образы Docker с помощью явных целей make перед запуском пакета E2E. Тесты Go должны выбирать уже созданные образы, а не создавать образы для каждого запуска теста.

Примеры целей:

сделать devshard-e2e-images пройти тестирование ./devshard/e2e -run TestE2E_Smoke -count=1 пройти тестирование ./devshard/e2e -run TestE2E_Protocol -count=1 пройти тестирование ./devshard/e2e -run TestE2E_Storage -count=1

devshard-e2e-images должна быть явной целью сборки, которая создает образы, используемые в тестах, включая Mock-chain, devshard-host и devshardctl. Тесты E2E должны быстро провалиться, если эти изображения отсутствуют, вместо того, чтобы автоматически перестраивать их внутри отдельных тестовых случаев.

Рекомендуемые уровни:

a-kuprin avatar
a-kuprinMaintainerMaintainer

@aikuznetsov (https://github.com/aikuznetsov) Пожалуйста, взгляните на это: https://github.com/a-kuprin/gonka/blob/1f0933ad9136cfbcf7070f8210e2c6694731ebaf/devshard/docs/proposals/TESTENV_PROPOSAL.md

Он использует несколько докеров devshardd, 1 devshardctl, 1 dapi-mock и 1 Mock-chain и не использует цепочку.

Он даже уже использовался для тестирования нового протокола синхронизации высоты для devshard: #1209 (https://github.com/gonka-ai/gonka/pull/1209)

Разница в том, что на самом деле используется децентрализованное API (но это имитация протокола). decentrized-api — это MLServer — обслуживающие узлы, а также оракул для параметров и высоты.

Также у меня были некоторые мысли о более высокоуровневых сценариях вместо тестовой среды для создания планов тестирования: https://github.com/a-kuprin/gonka/blob/devshard-testenv/devshard/docs/proposals/PROTOCOL_TESTING_PROPOSAL.md

Русский перевод
aikuznetsov avatar
aikuznetsovCollaboratorАвтор
2026-06-10

Цель

Создайте настоящий уровень интеграционного тестирования для devshard, который запускается на основе тестов Go, но проверяет систему с помощью контейнеров Docker, реальной сети HTTP, реальных границ процессов и реального хранилища.

Этот пакет должен дополнять существующие модульные, пакетные и httptest-тесты. Эти тесты остаются слоем быстрой корректности. Пакет E2E проверяет, что один и тот же протокол работает при запуске, подключении, перезапуске и сбое компонентов, как и реальные службы.

Область применения

Тест-раннер — Go. Среда выполнения — Docker.

Пакет не должен зависеть от действующей цепочки Cosmos, Testermint или decentralized-api. Метаданные, связанные с цепочкой, обслуживаются локальным фиктивным сервисом. Для вывода и проверки используются детерминированные механизмы-заглушки, если в сценарии явно не выбран другой бэкэнд.

За пределами первой версии:

проверка стека наблюдения за добычей

долговременная производительность или тестирование на выдержку

подача расчетов в живой цепочке

реальное выполнение модели машинного обучения

полный поток управления версиями

Их можно будет добавить позже как отдельные профили, как только уровень основного протокола E2E станет стабильным.

Инструменты и платформы тестирования

Первая реализация E2E должна сохранить небольшой набор инструментов и использовать Go-native.

Рекомендуемые инструменты:

Инструменты, которых следует избегать в первой версии:

  • Исполнители сценариев Python: Go сохраняет сценарии близкими к типам devshard, помощникам подписи, помощникам хранилища и существующим утверждениям. Добавление Python создаст вторую среду выполнения тестов до того, как контракт E2E станет стабильным.
  • Docker Compose в качестве основного оркестратора тестов: testcontainers-go дает каждому тесту Go прямой контроль над сетями, контейнерами, портами, журналами, перезапусками и очисткой. Compose может пригодиться позже для ручного воспроизведения.
  • живая цепочка Cosmos или Testermint: первый пакет должен изолировать протокол devshard и поведение транспорта от запуска цепочки, производства блоков, управления и несвязанных сбоев узлов. Mock-chain охватывает мостовой контракт, необходимый devshard.
  • Реальное выполнение модели машинного обучения: детерминированный вывод заглушки обеспечивает быстроту, воспроизводимость тестов и сосредоточенность на поведении протокола, а не на доступности графического процессора/модели или качестве генерации.
  • автоматизация браузера/UI: devshard E2E проверяет HTTP API и состояние протокола. Автоматизация браузера добавит проблемы с медленным пользовательским интерфейсом, которые не являются частью этого предложения.

Структура тестовой среды

Каждый тест запускает изолированную сеть Docker. Процесс тестирования Go остается вне сети и контролирует среду через API-интерфейсы Docker и сопоставленные сервисные порты.

Среда дыма по умолчанию должна развернуться:

один контейнер макетной цепочки

три контейнера devshard-host-N

один контейнер devshardctl

один контейнер Postgres

Сценарии хранения и сбоя добавляют контейнеры или тома по мере необходимости:

постоянные тома SQLite для тестов перезапуска

дополнительные конечные точки управления для каждой службы для детерминированного внедрения ошибок

блок-схема LR TestRunner["Go E2E test runner"] Docker["Docker / testcontainers-go"] Client["HTTP утверждения"] subgraph Net["изолированная сеть Docker"] MockChain["mock-chain\nchain метаданные + API управления"] DevshardCtl["devshardctl\nOpenAI-совместимый API"] Host0["devshard-host-0\nslot 0"] Host1["devshard-host-1\nslot 1"] Host2["devshard-host-2\nslot 2"] Postgres["postgres\nsmoke Storage Backend"] Vol0[("host-0 SQLite Volume")] Vol1[("host-1 SQLite Volume")] Vol2[("host-2 SQLite Volume")] end TestRunner --> Docker TestRunner --> Client Client --> Клиент DevshardCtl -.прямые проверки протокола.-> Клиент Host0 -.прямые проверки протокола.-> Клиент Host1 -.прямые проверки протокола.-> Host2 DevshardCtl --> Host0 DevshardCtl --> Host1 DevshardCtl --> Host2 Host0 <-->|gossip| Хост1 Хост1 <-->|сплетни| Хост2 Хост2 <-->|сплетни| Host0 Host0 --> MockChain Host1 --> MockChain Host2 --> MockChain DevshardCtl --> MockChain Host0 --> Postgres Host1 --> Postgres Host2 --> Postgres Host0 -.sqlite профиль.-> Vol0 Host1 -.sqlite профиль.-> Vol1 Host2 -.sqlite профиль.-> Vol2

Инвентаризация контейнеров:

Первая реализация должна быть стандартизирована для группы из трех хостов, поскольку многие варианты поведения протокола требуют формы, подобной большинству: ротация исполнителей, голосование по тайм-ауту, накопление подписей и сходимость слухов. Жгут может позже подвергать Hosts: N стресс-тестам или тестам в крайних случаях.

Службы времени выполнения

Каждая среда E2E запускает изолированную сеть Docker и небольшой набор сервисов.

макет цепи

Mock-chain — это локальная служба метаданных, которая реализует подмножество поведения моста основной сети, необходимое для devshard.

Первая реализация должна точно соответствовать текущей форме моста REST. Это заставляет E2E сосредоточиться на проверке мостового контракта, который разработчик уже использует, вместо добавления второго API, предназначенного только для макетов. Более чистый API внутреннего контроля можно добавить позже вместе с REST-совместимыми конечными точками, но настройка и восстановление протокола должны продолжать выполняться по тем же путям, что и рабочий код.

Он служит детерминированной локальной конфигурацией для:

идентификатор условного депонирования

адрес создателя условного депонирования

баланс условного депонирования

идентификатор эпохи

хэш приложения

назначение слотов хоста

URL-адреса вывода хоста

цена токена

порог проверки

гранты «теплый ключ»

утвержденные версии devshard, когда они нужны сценарию версии

Он также должен предоставить API управления только для разработчиков для тестовых сценариев:

передовая эпоха

изменить утвержденные версии

изменить метаданные хоста

добавить или удалить гранты «теплых ключей»

ввести задержки ответа

вводить ошибки моста

devshard-host-N

В каждом хост-контейнере работает один участник. Процесс должен использовать реальный хост devshard, транспорт, подпись, хранилище, сплетни и код конечного автомата.

Конфигурируемые входы:

идентификатор условного депонирования

ключ подписывающего лица хоста

адрес пользователя

назначение слота

префикс маршрута

URL-адреса одноранговых хостов

серверная часть хранилища

URL-адрес макетной цепочки

поведение заглушки вывода

поведение проверки заглушки

Хост должен предоставлять стандартные транспортные маршруты devshard, смонтированные либо с префиксом устаревшего маршрута, либо с префиксом версии:

/v1/devshard/* /devshard/<версия>/*

devshardctl

Пакет должен включать сценарии, которые направляют запросы через OpenAI-совместимую поверхность devshardctl. Это подтверждает путь, обращенный к пользователю:

клиент -> devshardctl -> транспортные клиенты devshard -> хост-контейнеры

Некоторые сценарии более низкого уровня могут напрямую обращаться к конечным точкам транспорта хоста, когда это делает утверждение более ясным, но пакет дыма должен использовать devshardctl .

постгрес

Postgres является частью дымовой среды и должен быть базовым хранилищем по умолчанию для дымовых тестов CI. SQLite остается полезным для локальных тестов перезапуска и крайних случаев сохранения состояния одного хоста.

Сценарии хранения должны охватывать:

Перезапуск хоста SQLite

Перезапуск хоста Postgres

перезапуск всех хостов

конфликт версий сеанса

конфликт эпохи сеанса, где это применимо

Тестовые двоичные файлы

Пакету E2E нужны исполняемые команды, которые представляют собой небольшие оболочки существующих пакетов devshard.

Рекомендуемые команды:

devshard/cmd/devshardd/main.go devshard/cmd/mock-chain/main.go

девшардд

devshardd запускает одного хост-участника.

Для первой реализации E2E devshardd должна быть командой только для E2E. Его пока не следует рассматривать как производственный двоичный файл. Это позволяет сосредоточить первую итерацию на проверке интеграции, оставляя при этом место для усиления и продвижения команды позже, если она примет правильную производственную форму.

Он должен подключить:

мостовой клиент

государственная машина

хозяин

транспортный сервер

хранение

коллеги по сплетням

машина вывода

механизм проверки

конечная точка готовности

конечная точка управления только для разработчиков, если она явно включена

Для E2E devshardd может начать с механизмов вывода и проверки заглушки. Важным моментом является то, что сама среда выполнения протокола реальна.

макет цепи

Mock-chain обслуживает локальные метаданные и детерминированное поведение управления. Он должен начинаться как простой HTTP-сервер, соответствующий текущей форме моста REST. Если позже devshard перейдет на другой протокол клиента цепочки, макет должен следовать этой границе.

Внесение ошибок

Детерминированное внесение ошибок должно быть частью проекта тестирования с самого начала. Без него тесты тайм-аута и восстановления становятся медленными и нестабильными.

Первая поверхность управления должна поддерживать:

провалить следующий вывод

отложить следующий вывод

отложить следующий вывод до его отмены

удержать расписку исполнителя

вернуть поврежденный хэш ответа

вернуть неверный результат проверки

приостановить сплетни

возобновить сплетни

отклонять запросы метаданных моста

вернуть устаревшие метаданные моста

предварительная имитация эпохи

изменить утвержденные версии

Средства контроля неисправностей должны быть отключены, если процесс не запущен в явном тестовом режиме.

Набор сценариев

Сценарии дыма

Сценарии дыма должны быть надежными и достаточно быстрыми для каждого запуска CI.

  • Счастливый путь Запустите три хоста и devshardctl. Отправьте несколько запросов на завершение непотокового чата. Завершите сеанс. Подтвердите, что выходные данные расчета присутствуют и все хосты согласны с окончательным состоянием.

Счастливый путь

Запустите три хоста и devshardctl. Отправьте несколько запросов на завершение непотокового чата. Завершите сеанс. Подтвердите, что выходные данные расчета присутствуют и все хосты согласны с окончательным состоянием.

  • Путь потоковой передачи Отправьте запрос на завершение потокового чата через devshardctl. Подтвердите, что клиент получил фрагменты контента и [DONE] . Получение/мета-события протокола Assert devshard обрабатываются внутри и не повреждают поток, совместимый с OpenAI.

Путь потоковой передачи

Отправьте запрос на завершение потокового чата через devshardctl. Подтвердите, что клиент получил фрагменты контента и [DONE] . Получение/мета-события протокола Assert devshard обрабатываются внутри и не повреждают поток, совместимый с OpenAI.

  • Отказ в аутентификации Отправьте запрос защищенного хоста, подписанный неавторизованным ключом. Укажите, что запрос отклонен из-за ошибки авторизации.

Отказ в аутентификации

Отправьте запрос защищенного хоста, подписанный неавторизованным ключом. Укажите, что запрос отклонен из-за ошибки авторизации.

Сценарии протоколов

  • Конвергенция сплетен Отправьте работу, пока все хосты работают. Данные подтверждения nonce, мемпула и подписи распространяются между участниками и сходятся.

Сближение сплетен

Отправляйте работу, пока все хосты работают. Данные подтверждения nonce, мемпула и подписи распространяются между участниками и сходятся.

  • Догон хоста. Позвольте одному хосту пропустить более ранние различия, а затем отправьте ему более поздний запрос с догоняющими различиями. Утвердите, что он достигает того же корня состояния, что и остальная часть группы.

Догонялка хоста

Позвольте одному хосту пропустить более ранние различия, а затем отправьте ему более поздний запрос с догоняющими различиями. Утвердите, что он достигает того же корня состояния, что и остальная часть группы.

  • Сбой и тайм-аут исполнителя. Настройте выбранный исполнитель на сбой или зависание. Собираются голоса за утверждение тайм-аута, применяется транзакция тайм-аута, и сеанс может продолжиться или завершиться в соответствии с правилами протокола.

Сбой исполнителя и тайм-аут

Настройте выбранного исполнителя на сбой или зависание. Собираются голоса за утверждение тайм-аута, применяется транзакция тайм-аута, и сеанс может продолжиться или завершиться в соответствии с правилами протокола.

  • Запрос квитанции Отложите или потеряйте путь ответа исполнителя, а затем запросите у исполнителя запрос на получение. Подтвердите, что квитанция действительна и сеанс пользователя может ее обработать.

Получение вызова

Приостановите или потеряйте путь ответа исполнителя, а затем запросите у исполнителя квитанцию. Подтвердите, что квитанция действительна и сеанс пользователя может ее обработать.

Сценарии восстановления

  • Перезапуск хоста SQLite. Выполните несколько выводов, перезапустите один хост-контейнер с сохраненным томом SQLite, продолжите сеанс и завершите его. Подтвердите отсутствие регрессии nonce и перезапущенный хост подписывает окончательное состояние.

Перезапуск хоста SQLite

Выполните несколько выводов, перезапустите один хост-контейнер с сохраненным томом SQLite, продолжите сеанс и завершите его. Подтвердите отсутствие регрессии nonce и перезапущенный хост подписывает окончательное состояние.

  • Восстановление Postgres. Запустите счастливый путь с включенным хранилищем Postgres. Перезагрузите все хосты и продолжите сеанс. Утверждение восстановления состояния из Postgres работает, и финализация прошла успешно.

Восстановление Postgres

Пройдите счастливый путь с включенным хранилищем Postgres. Перезагрузите все хосты и продолжите сеанс. Утверждение восстановления состояния из Postgres работает, и финализация прошла успешно.

  • Перезапуск всех хостов перед финализацией. Запустите несколько логических выводов, остановите каждый хост, перезапустите их, затем завершите. Утверждайте, что сохраненных различий и подписей достаточно для восстановления.

Перезапуск всего хоста перед финализацией

Запустите несколько выводов, остановите каждый хост, перезапустите их, затем завершите. Утверждайте, что сохраненных различий и подписей достаточно для восстановления.

Версия и сценарии маршрутизации

  • Префикс устаревшего маршрута. Запустите сеанс через /v1/devshard/* и убедитесь, что сохраненная версия сеанса — v1.

Префикс устаревшего маршрута

Запустите сеанс через /v1/devshard/* и убедитесь, что сохраненная версия сеанса — v1 .

  • Префикс версионного маршрута. Запустите сеанс через /devshard/<version>/* и убедитесь, что сохраненная версия сеанса является выбранной версией.

Префикс версионного маршрута

Запустите сеанс через /devshard/<version>/* и убедитесь, что сохраненная версия сеанса является выбранной версией.

  • Конфликт версий. Создайте или восстановите одно и то же условное депонирование в одной версии, а затем попытайтесь прикрепить то же условное депонирование в другой версии. Хранилище утверждений отклоняет конфликт.

Конфликт версий

Создайте или восстановите одно и то же условное депонирование в одной версии, а затем попытайтесь прикрепить то же условное депонирование в другой версии. Хранилище утверждений отклоняет конфликт.

Сценарии метаданных цепочки

  • Авторизация по «теплому ключу» Настройте предоставление «теплого ключа» в Mock-chain. Утверждает, что теплый ключ может аутентифицироваться там, где это разрешено, и отклоняется после удаления разрешения или при использовании не для того участника.

Авторизация по теплому ключу

Настройте предоставление теплого ключа в макетной цепочке. Утверждает, что теплый ключ может аутентифицироваться там, где это разрешено, и отклоняется после удаления разрешения или при использовании не для того участника.

  • Сбой метаданных моста Внедрить ошибку метаданных моста во время создания или восстановления сеанса. Подтвердить, что хост не готов к сбою или возвращает ожидаемый ответ о недоступности службы.

Ошибка метаданных моста

Внедрить ошибку метаданных моста во время создания или восстановления сеанса. Подтвердить, что хост не готов к сбою или возвращает ожидаемый ответ о недоступности службы.

Утверждения

Тесты E2E должны избегать утверждения только кодов состояния HTTP. Полезные утверждения уровня протокола включают в себя:

ожидаемая форма ответа, совместимая с OpenAI

ожидаемая форма потока SSE

монотонная прогрессия nonce

ожидаемые переходы состояний вывода

сопоставление конечного корня состояния между хостами

ожидаемые подписи по слотам

  • Полезная нагрузка расчета включает окончательный номер кода, состояние, версию и подписи.

Выводы метаданных хранилища депонируются до ожидаемой эпохи и версии

перезапущенные хосты восстанавливают последнее известное состояние

неавторизованные подписанты отклоняются

сценарии ошибок создают ожидаемую транзакцию протокола

Расчетный договор

До тех пор, пока пакет E2E не передаст расчет в действующую цепочку, стабильный расчетный контракт должен быть протокольным обязательством, необходимым для проверки на стороне цепочки.

Заявления о базовом урегулировании должны охватывать:

идентификатор условного депонирования

сессионная версия

последний одноразовый номер

окончательный корень состояния или окончательное государственное обязательство

фаза терминального сеанса

конечное состояние для каждого включенного вывода

пороговые подписи

каждая подпись подтверждает окончательное государственное обязательство

каждая подпись сопоставляется с действительным слотом в группе сеансов

дубликаты подписей слотов не учитываются дважды

Экономические поля, такие как учет токенов, комиссии, оставшийся баланс, затраты хоста, пропущенные подсчеты и штрафы за проверку, следует указывать только в специальных сценариях учета. Они не должны быть частью базового контракта по урегулированию дыма до тех пор, пока путь подачи цепочки не станет частью пакета E2E.

Уровни CI

Используйте целенаправленные запуски тестов, а не один большой недифференцированный пакет. CI должен создать необходимые образы Docker с помощью явных целей make перед запуском пакета E2E. Тесты Go должны выбирать уже созданные образы, а не создавать образы для каждого запуска теста.

Примеры целей:

сделать devshard-e2e-images пройти тестирование ./devshard/e2e -run TestE2E_Smoke -count=1 пройти тестирование ./devshard/e2e -run TestE2E_Protocol -count=1 пройти тестирование ./devshard/e2e -run TestE2E_Storage -count=1

devshard-e2e-images должна быть явной целью сборки, которая создает образы, используемые в тестах, включая Mock-chain, devshard-host и devshardctl. Тесты E2E должны быстро провалиться, если эти изображения отсутствуют, вместо того, чтобы автоматически перестраивать их внутри отдельных тестовых случаев.

Рекомендуемые уровни:

a-kuprin avatar
a-kuprinMaintainerMaintainer

@aikuznetsov (https://github.com/aikuznetsov) Пожалуйста, взгляните на это: https://github.com/a-kuprin/gonka/blob/1f0933ad9136cfbcf7070f8210e2c6694731ebaf/devshard/docs/proposals/TESTENV_PROPOSAL.md

Он использует несколько докеров devshardd, 1 devshardctl, 1 dapi-mock и 1 Mock-chain и не использует цепочку.

Он даже уже использовался для тестирования нового протокола синхронизации высоты для devshard: #1209 (https://github.com/gonka-ai/gonka/pull/1209)

Разница в том, что на самом деле используется децентрализованное API (но это имитация протокола). decentrized-api — это MLServer — обслуживающие узлы, а также оракул для параметров и высоты.

Также у меня были некоторые мысли о более высокоуровневых сценариях вместо тестовой среды для создания планов тестирования: https://github.com/a-kuprin/gonka/blob/devshard-testenv/devshard/docs/proposals/PROTOCOL_TESTING_PROPOSAL.md

Оригинал
aikuznetsov avatar
aikuznetsovCollaboratorАвтор
2026-06-10

Goal

Build a real integration test layer for devshard that runs from Go tests but validates the system across Docker containers, real HTTP networking, real process boundaries, and real storage.

This suite should complement the existing unit, package, and httptest tests. Those tests remain the fast correctness layer. The E2E suite verifies that the same protocol works when the pieces are started, wired, restarted, and failed like real services.

Scope

The test runner is Go. The runtime is Docker.

The suite should not depend on a live Cosmos chain, Testermint, or decentralized-api . Chain-facing metadata is served by a local mock service. Inference and validation use deterministic stub engines unless a scenario explicitly opts into a different backend.

Out of scope for the first version:

production observability stack validation

long-running performance or soak testing

live chain settlement submission

real ML model execution

full versiond governance flow

Those can be added later as separate profiles once the core protocol E2E layer is stable.

Test Tools And Frameworks

The first E2E implementation should keep the toolchain small and Go-native.

Recommended tools:

Tools to avoid in the first version:

  • Python scenario runners: Go keeps the scenarios close to devshard types, signing helpers, storage helpers, and existing assertions. Adding Python would create a second test runtime before the E2E contract is stable.
  • Docker Compose as the primary test orchestrator: testcontainers-go gives each Go test direct control over networks, containers, ports, logs, restarts, and cleanup. Compose can still be useful later for manual reproduction.
  • live Cosmos chain or Testermint: the first suite should isolate devshard protocol and transport behavior from chain startup, block production, governance, and unrelated node failures. mock-chain covers the bridge contract needed by devshard.
  • real ML model execution: deterministic stub inference keeps tests fast, reproducible, and focused on protocol behavior rather than GPU/model availability or generation quality.
  • browser/UI automation: devshard E2E validates HTTP APIs and protocol state. Browser automation would add slow UI concerns that are not part of this proposal.

Test Environment Structure

Each test starts an isolated Docker network. The Go test process stays outside the network and controls the environment through Docker APIs and mapped service ports.

The default smoke environment should spin up:

one mock-chain container

three devshard-host-N containers

one devshardctl container

one postgres container

Storage and fault scenarios add containers or volumes as needed:

persistent SQLite volumes for restart tests

optional per-service control endpoints for deterministic fault injection

flowchart LR TestRunner["Go E2E test runner"] Docker["Docker / testcontainers-go"] Client["HTTP assertions"] subgraph Net["isolated Docker network"] MockChain["mock-chain\nchain metadata + control API"] DevshardCtl["devshardctl\nOpenAI-compatible API"] Host0["devshard-host-0\nslot 0"] Host1["devshard-host-1\nslot 1"] Host2["devshard-host-2\nslot 2"] Postgres["postgres\nsmoke storage backend"] Vol0[("host-0 SQLite volume")] Vol1[("host-1 SQLite volume")] Vol2[("host-2 SQLite volume")] end TestRunner --> Docker TestRunner --> Client Client --> DevshardCtl Client -.direct protocol checks.-> Host0 Client -.direct protocol checks.-> Host1 Client -.direct protocol checks.-> Host2 DevshardCtl --> Host0 DevshardCtl --> Host1 DevshardCtl --> Host2 Host0 <-->|gossip| Host1 Host1 <-->|gossip| Host2 Host2 <-->|gossip| Host0 Host0 --> MockChain Host1 --> MockChain Host2 --> MockChain DevshardCtl --> MockChain Host0 --> Postgres Host1 --> Postgres Host2 --> Postgres Host0 -.sqlite profile.-> Vol0 Host1 -.sqlite profile.-> Vol1 Host2 -.sqlite profile.-> Vol2

Container inventory:

The first implementation should standardize on a three-host group because many protocol behaviors need a majority-like shape: executor rotation, timeout votes, signature accumulation, and gossip convergence. The harness can expose Hosts: N later for stress or edge-case tests.

Runtime Services

Each E2E environment starts an isolated Docker network and a small set of services.

mock-chain

mock-chain is a local metadata service that implements the subset of mainnet bridge behavior needed by devshard.

The first implementation should match the current REST bridge shape exactly. That keeps E2E focused on validating the bridge contract devshard already uses instead of adding a second mock-only API. A cleaner internal control API can be added alongside the REST-compatible endpoints later, but protocol setup and recovery should continue to exercise the same paths as production code.

It serves deterministic local config for:

escrow ID

escrow creator address

escrow balance

epoch ID

app hash

host slot assignments

host inference URLs

token price

validation threshold

warm key grants

approved devshard versions, when a version scenario needs them

It should also expose a dev-only control API for test scenarios:

advance epoch

change approved versions

change host metadata

add or remove warm key grants

inject response delays

inject bridge errors

devshard-host-N

Each host container runs one participant. The process should use the real devshard host, transport, signing, storage, gossip, and state machine code.

Configurable inputs:

escrow ID

host signer key

user address

slot assignment

route prefix

peer host URLs

storage backend

mock-chain URL

stub inference behavior

stub validation behavior

The host should expose the standard devshard transport routes, mounted under either the legacy route prefix or a versioned prefix:

/v1/devshard/* /devshard/<version>/*

devshardctl

The suite should include scenarios that drive requests through the OpenAI-compatible devshardctl surface. This validates the user-facing path:

client -> devshardctl -> devshard transport clients -> host containers

Some lower-level scenarios can talk directly to host transport endpoints when that makes the assertion clearer, but the smoke suite should use devshardctl .

postgres

Postgres is part of the smoke environment and should be the default storage backend for CI smoke tests. SQLite remains useful for local restart tests and single-host persistence edge cases.

Storage scenarios should cover:

SQLite host restart

Postgres host restart

all-host restart

session version conflict

session epoch conflict where applicable

Test Binaries

The E2E suite needs runnable commands that are small wrappers around existing devshard packages.

Recommended commands:

devshard/cmd/devshardd/ main.go devshard/cmd/mock-chain/ main.go

devshardd

devshardd runs one host participant.

For the first E2E implementation, devshardd should be an E2E-only command. It should not be treated as a production binary yet. This keeps the first iteration focused on integration validation, while leaving room to harden and promote the command later if it becomes the right production shape.

It should wire:

bridge client

state machine

host

transport server

storage

gossip peers

inference engine

validation engine

readiness endpoint

dev-only control endpoint when explicitly enabled

For E2E, devshardd can start with stub inference and validation engines. The important point is that the protocol runtime itself is real.

mock-chain

mock-chain serves local metadata and deterministic control behavior. It should start as a simple HTTP server matching the current REST bridge shape. If devshard later moves to a different chain client protocol, the mock should follow that boundary.

Fault Injection

Deterministic fault injection should be part of the test design from the beginning. Without it, timeout and recovery tests become slow and flaky.

The first control surface should support:

fail next inference

delay next inference

hang next inference until cancelled

withhold executor receipt

return a corrupt response hash

return invalid validation result

pause gossip

resume gossip

reject bridge metadata requests

return stale bridge metadata

advance mock epoch

change approved versions

Fault controls must be disabled unless the process is started in explicit test mode.

Scenario Set

Smoke Scenarios

Smoke scenarios should be reliable and fast enough for every CI run.

  • Happy path Start three hosts and devshardctl . Send several non-streaming chat completion requests. Finalize the session. Assert the settlement output is present and all hosts agree on the final state.

Happy path

Start three hosts and devshardctl . Send several non-streaming chat completion requests. Finalize the session. Assert the settlement output is present and all hosts agree on the final state.

  • Streaming path Send a streaming chat completion request through devshardctl . Assert the client receives content chunks and [DONE] . Assert devshard protocol receipt/meta events are handled internally and do not corrupt the OpenAI-compatible stream.

Streaming path

Send a streaming chat completion request through devshardctl . Assert the client receives content chunks and [DONE] . Assert devshard protocol receipt/meta events are handled internally and do not corrupt the OpenAI-compatible stream.

  • Auth rejection Send a protected host request signed by an unauthorized key. Assert the request is rejected with an authorization error.

Auth rejection

Send a protected host request signed by an unauthorized key. Assert the request is rejected with an authorization error.

Protocol Scenarios

  • Gossip convergence Submit work while all hosts are running. Assert nonce, mempool, and signature data propagate between participants and converge.

Gossip convergence

Submit work while all hosts are running. Assert nonce, mempool, and signature data propagate between participants and converge.

  • Host catch-up Let one host miss earlier diffs, then send it a later request with catch-up diffs. Assert it reaches the same state root as the rest of the group.

Host catch-up

Let one host miss earlier diffs, then send it a later request with catch-up diffs. Assert it reaches the same state root as the rest of the group.

  • Executor failure and timeout Configure the selected executor to fail or hang. Assert timeout votes are collected, the timeout transaction is applied, and the session can continue or finalize according to protocol rules.

Executor failure and timeout

Configure the selected executor to fail or hang. Assert timeout votes are collected, the timeout transaction is applied, and the session can continue or finalize according to protocol rules.

  • Receipt challenge Withhold or lose the executor response path, then challenge the executor for a receipt. Assert the receipt is valid and the user session can process it.

Receipt challenge

Withhold or lose the executor response path, then challenge the executor for a receipt. Assert the receipt is valid and the user session can process it.

Recovery Scenarios

  • SQLite host restart Run several inferences, restart one host container with its SQLite volume preserved, continue the session, and finalize. Assert there is no nonce regression and the restarted host signs the final state.

SQLite host restart

Run several inferences, restart one host container with its SQLite volume preserved, continue the session, and finalize. Assert there is no nonce regression and the restarted host signs the final state.

  • Postgres recovery Run the happy path with Postgres storage enabled. Restart all hosts and continue the session. Assert state recovery from Postgres works and finalization succeeds.

Postgres recovery

Run the happy path with Postgres storage enabled. Restart all hosts and continue the session. Assert state recovery from Postgres works and finalization succeeds.

  • All-host restart before finalization Run several inferences, stop every host, restart them, then finalize. Assert persisted diffs and signatures are sufficient to recover.

All-host restart before finalization

Run several inferences, stop every host, restart them, then finalize. Assert persisted diffs and signatures are sufficient to recover.

Version And Routing Scenarios

  • Legacy route prefix Run a session through /v1/devshard/* and assert the stored session version is v1 .

Legacy route prefix

Run a session through /v1/devshard/* and assert the stored session version is v1 .

  • Versioned route prefix Run a session through /devshard/<version>/* and assert the stored session version is the selected version.

Versioned route prefix

Run a session through /devshard/<version>/* and assert the stored session version is the selected version.

  • Version conflict Create or recover the same escrow under one version, then attempt to attach the same escrow under a different version. Assert storage rejects the conflict.

Version conflict

Create or recover the same escrow under one version, then attempt to attach the same escrow under a different version. Assert storage rejects the conflict.

Chain Metadata Scenarios

  • Warm key authorization Configure a warm key grant in mock-chain . Assert the warm key can authenticate where allowed and is rejected after the grant is removed or when used for the wrong participant.

Warm key authorization

Configure a warm key grant in mock-chain . Assert the warm key can authenticate where allowed and is rejected after the grant is removed or when used for the wrong participant.

  • Bridge metadata failure Inject a bridge metadata error during session creation or recovery. Assert the host fails ready or returns the expected service-unavailable response.

Bridge metadata failure

Inject a bridge metadata error during session creation or recovery. Assert the host fails ready or returns the expected service-unavailable response.

Assertions

E2E tests should avoid asserting only HTTP status codes. Useful protocol-level assertions include:

expected OpenAI-compatible response shape

expected SSE stream shape

monotonic nonce progression

expected inference status transitions

matching final state root across hosts

expected signatures by slot

settlement payload includes final nonce, state, version, and signatures

storage metadata pins escrow to the expected epoch and version

restarted hosts recover latest known state

unauthorized signers are rejected

fault scenarios produce the expected protocol transaction

Settlement Contract

Until the E2E suite submits settlement to a live chain, the stable settlement contract should be the protocol commitment needed for chain-side verification.

Baseline settlement assertions should cover:

escrow ID

session version

final nonce

final state root or final state commitment

terminal session phase

terminal state for every included inference

threshold-sufficient signatures

each signature verifies over the final state commitment

each signature maps to a valid slot in the session group

duplicate slot signatures are not counted twice

Economic fields such as token accounting, fees, remaining balance, host costs, missed counts, and validation penalties should be asserted only in dedicated accounting scenarios. They should not be part of the baseline smoke settlement contract until the chain submission path is part of the E2E suite.

CI Tiers

Use focused go test runs rather than one large undifferentiated suite. CI should build the required Docker images through explicit make targets before running the E2E suite. The Go tests should select already-built images rather than building images per test run.

Example targets:

make devshard-e2e-images go test ./devshard/e2e -run TestE2E_Smoke -count=1 go test ./devshard/e2e -run TestE2E_Protocol -count=1 go test ./devshard/e2e -run TestE2E_Storage -count=1

devshard-e2e-images should be an explicit build target that produces the images used by the tests, including mock-chain , devshard-host , and devshardctl . The E2E tests should fail fast if those images are missing instead of silently rebuilding them inside individual test cases.

Recommended tiers:

a-kuprin avatar
a-kuprinMaintainerMaintainer

@aikuznetsov (https://github.com/aikuznetsov) Please take a look on this: https://github.com/a-kuprin/gonka/blob/1f0933ad9136cfbcf7070f8210e2c6694731ebaf/devshard/docs/proposals/TESTENV_PROPOSAL.md

It is using multiple devshardd, 1 devshardctl, 1 dapi-mock and 1 mock-chain dockers and doesn't use chain.

It even already used for testing new height-sync protocol for devshard: #1209 (https://github.com/gonka-ai/gonka/pull/1209)

The difference is that actually decentralized-api is used (but mock for protocol). decentralized-api is the MLServer - serving nodes, and also oracle for parameters and height.

Also I had some thoughts on more high-level scripting over test-environment for creating test plans: https://github.com/a-kuprin/gonka/blob/devshard-testenv/devshard/docs/proposals/PROTOCOL_TESTING_PROPOSAL.md