Создание интерактивной команды CLI с Expect завершается с 0 раньше, когда запускается как Symfony Process в контексте Behat

Это довольно сложный вопрос, возможно, знание Symfony и Behat может и не понадобиться для понимания проблемы.

Таким образом, чтобы проверить ввод и вывод интерактивного приложения CLI bin/albumgrab Я написал на PHP с использованием компонента Symfony Console, я настроил свой контекст Behat для создания expect скрипт, запустить через exec,

это exec команда запускается в PHP через Symfony Process,

$expect = <<<BASH
exec expect -c '
    set timeout 180
    spawn bin/albumgrab
    expect "Please enter the name of the directory"
    send "/tmp/php-london\n"
    expect "Please enter the URL to the first image"
    send "https://www.facebook.com/PeeHPLondon/photos/pb.7119218495.-2207520000.1430669248./10153559172718496/?type=3&src=https%3A%2F%2Ffbcdn-sphotos-g-a.akamaihd.net%2Fhphotos-ak-xfp1%2Fv%2Ft1.0-9%2F10986697_10153559172718496_5727444485530442900_n.jpg%3Foh%3Dc47770f4cd15fecc6888bcd504899087%26oe%3D55DA9CB0%26__gda__%3D1439174101_7c78a93bf247dbad6c56681b6db5309c&size=960%2C959&fbid=10153559172718496\\n"
    interact
'

BASH;

$process = new Symfony\Component\Process\Process($expect);

$process->mustRun();

Тем не менее, когда он проходит второй вход, он, похоже, завершается успешно.

Вызов:

$process->setTty(true);

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

Я подумал, что PTY будет более подходящим в любом случае:

$process->setPty(true);

Как это было решение этого вопроса Stackru. Однако это поддерживается не везде, по крайней мере, в Mac OS X.

Вы можете увидеть, что я пытался до сих пор в Github: https://github.com/adamelso/albumgrab/pull/13/files и вывод Travis для последней попытки https://travis-ci.org/adamelso/albumgrab/jobs/61137499

Итак, мой главный вопрос: почему он продолжает выходить с 0 рано и как это предотвратить?

2 ответа

Решение

В соответствии с ответом на Ожидание команды "Ожидание сценария ожидания" необходимо дождаться EOF вместо использования interact команда:

set timeout 180
spawn ./bin/albumgrab
expect "Please enter the name of the directory"
send "/tmp/php-london\n"
expect "Please enter the URL to the first image"
send "https://www.facebook.com/PeeHPLondon/photos/pb.7119218495.-2207520000.1430669248./10153559172718496/\n"
expect EOF

Вот полный скрипт, который я использовал, чтобы протестировать его на OS X:

<?php

require_once __DIR__.'/vendor/autoload.php';

use Symfony\Component\Process\Process;

$expect = <<<BASH
exec expect -c '
    set timeout 180
    spawn ./bin/albumgrab
    expect "Please enter the name of the directory"
    send "/tmp/php-london\n"
    expect "Please enter the URL to the first image"
    send "https://www.facebook.com/PeeHPLondon/photos/pb.7119218495.-2207520000.1430669248./10153559172718496/?type=3&src=https%3A%2F%2Ffbcdn-sphotos-g-a.akamaihd.net%2Fhphotos-ak-xfp1%2Fv%2Ft1.0-9%2F10986697_10153559172718496_5727444485530442900_n.jpg%3Foh%3Dc47770f4cd15fecc6888bcd504899087%26oe%3D55DA9CB0%26__gda__%3D1439174101_7c78a93bf247dbad6c56681b6db5309c&size=960%2C959&fbid=10153559172718496\\n"
    expect EOF
'

BASH;

$process = new Process($expect);
$process->setPty(true);
$process->start();

$process->wait(function ($type, $buffer) {
    if (Process::ERR === $type) {
        echo 'ERR > '.$buffer;
    } else {
        echo 'OUT > '.$buffer;
    }
});

if (!$process->isSuccessful()) {
    throw new \RuntimeException($process->getErrorOutput());
}

Чтобы иметь возможность получить ответ на вопрос - вам определенно нужен терминал (TTY) или псевдотерминал (PTY) для получения любого пользовательского ввода.

Вот почему - без $process->setTty(true) или же setPty(true) - QuestionHelper молча возвращается к значению по умолчанию, и команда завершается успешно с кодом выхода 0.

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

Symfony\Component\Console\Helper\HelperSet 
Symfony\Component\Console\Tester\CommandTester

Как использовать эти помощники, описано в главе "Поваренная книга" " Тестирование команды, ожидающей ввода".

Другие вопросы по тегам