Skip to content
...

Revolt

Revolt — стандартный event loop для асинхронного PHP: цикл, который ждёт готовности ввода-вывода (таймеров, сокетов, потоков) и по очереди возобновляет корутины, которые этого ждали. На нём работают библиотеки amphp. Плагин предоставляет атрибут #[RunInRevolt]#[RunInRevolt()]Запускает тест на event loop Revolt.: тест выполняется на общем для процесса цикле Revolt и может дожидаться асинхронной работы (таймеры, потоки, Future::await()), не блокируя процесс.

Плагин не требует настройки.

Установка

bash
composer require --dev testo/bridge-revolt

#[RunInRevolt]

Запускает тест на event loop Revolt.

#[RunInRevolt()]

Тело теста уходит на event loop, а снаружи вызов остаётся обычным блокирующим: пайплайн ждёт, пока тест доработает.

Работает на методе и на классе (Test Case). На классе атрибут прогоняет через цикл каждый тест, но по одному за раз: следующий тест попадает на цикл только после того, как предыдущий полностью завершился.

Примеры:

Дождаться реальной асинхронной работы (таймер Revolt) внутри теста:

php
use Revolt\EventLoop;
use Testo\Assert;
use Testo\Bridge\Revolt\RunInRevolt;
use Testo\Test;

#[Test]
#[RunInRevolt]
public function resolvesAfterDelay(): void
{
    $suspension = EventLoop::getSuspension();
    EventLoop::delay(0.1, static fn() => $suspension->resume('ready'));

    Assert::same('ready', $suspension->suspend()); // цикл крутится, пока мы ждём
}

Приостановка — только через Suspension\Revolt\EventLoop\Suspension

Файбером теста владеет event loop Revolt, поэтому приостанавливаться нужно через Suspension\Revolt\EventLoop\Suspension, привязанную к событию цикла (таймеру, вводу-выводу): голый \Fiber::suspend() на цикле возобновить некому. А если нужны голые файберы под управлением самого Testo, это уже #[RunInFiber]#[RunInFiber(Schedule $schedule = Schedule::Solo)]Запускает тест (метод) или все тесты кейса (класс) в файберах под кооперативным планировщиком Testo. из плагина Fiber, другая задача.

Валидно и обратное: Future::await() и Suspension\Revolt\EventLoop\Suspension работают только в event loop Revolt (под атрибутом #[RunInRevolt]#[RunInRevolt()]Запускает тест на event loop Revolt.).

Один тест за раз

#[RunInRevolt]#[RunInRevolt()]Запускает тест на event loop Revolt. не выполняет тесты параллельно: на event loop уходит только тело теста, и тесты никогда не делят прогон цикла. Провайдер данных, ретраи и служебная обвязка Testo выполняются снаружи, а следующий тест кейса входит на цикл лишь после того, как полностью завершился предыдущий.

Это осознанный размен: изоляция тестов важнее чередования. Если нужно именно чередовать тесты между собой в поисках гонок, возьмите #[RunInFiber]#[RunInFiber(Schedule $schedule = Schedule::Solo)]Запускает тест (метод) или все тесты кейса (класс) в файберах под кооперативным планировщиком Testo. из плагина Fiber: он работает на обычных файберах, которыми управляет сам Testo.

Почему нельзя запустить все тесты одновременно, как с RunInFiber?

Дело в том, кто управляет файберами. Изоляция под #[RunInFiber]#[RunInFiber(Schedule $schedule = Schedule::Solo)]Запускает тест (метод) или все тесты кейса (класс) в файберах под кооперативным планировщиком Testo. модуля Fiber держится на гардах: тело теста выполняется во вложенном файбере гарда, поэтому каждый \Fiber::suspend() проходит сквозь гард, и тот на приостановке снимает состояние своего теста, а на возобновлении подставляет обратно. Под #[RunInRevolt]#[RunInRevolt()]Запускает тест на event loop Revolt. файберы переходят под контроль Revolt: он приостанавливает и возобновляет их сам, мимо гардов, и переключать состояние некому. Окажись на цикле несколько тестов разом, контекст тестов утёк бы: проверки, сообщения и покрытие засчитывались бы чужим тестам.

RunInRevolt или RunInFiber?

#[RunInRevolt]#[RunInRevolt()]Запускает тест на event loop Revolt. — про асинхронность: дать тесту event loop, чтобы он ждал реальный ввод-вывод (amphp, таймеры и потоки Revolt), изолированно от других тестов. #[RunInFiber]#[RunInFiber(Schedule $schedule = Schedule::Solo)]Запускает тест (метод) или все тесты кейса (класс) в файберах под кооперативным планировщиком Testo. — про конкурентность: чередовать тесты кейса на обычных файберах, чтобы находить гонки в кооперативном коде. Это разные задачи: #[RunInRevolt] не запускает тесты параллельно, а #[RunInFiber] не крутит event loop.