2015-05-04 1 views
3

Это довольно продвинутый вопрос, возможно, знание Symfony и Behat, возможно, не является необходимым для понимания проблемы.Инициирование интерактивной команды CLI с Expect-выходами с 0 ранним запуском в качестве процесса Symfony в контексте Behat

Так что для того, чтобы проверить ввод и вывод интерактивного приложения bin/albumgrab CLI я написал в PHP с помощью компонента Symfony консоли, я настроил свой 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); 

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

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

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

ответ

1

В соответствии с ответом на Expect Script wait Command Hangs вам нужно ждать 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()); 
} 
+1

Кстати, если вы тестируете команду Symfony Console, есть лучшие способы ее тестирования: http://symfony.com/doc/current/components/console/helpers/questionhelper.html#testing-a-command -that-expects-input –

+0

Cheers Kuba, он работает! Мне пришлось запустить мою команду без вывода ANSI и [заменить символы управления новой строкой с помощью PHP_EOL] (https://github.com/adamelso/albumgrab/pull/13/files#diff-8a50a8f3567ab9a03107fd86eeaf827eR124) –

+0

, который сказал, что было бы лучше используйте тестер команд Symfony, но я думаю, что есть ценность в проведении одного теста на дым (если я хочу отойти от Symfony ... не то, что я хотел бы). –

1

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

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

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

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

Как использовать эти хелперы описано в главе поваренной Testing a Command that expects input.

+0

Интересно, что даже без вызова 'setTty()' и 'setPty()' команда по-прежнему получает ответ на оба вопроса. Он не перешел бы к второму вопросу, если бы не получил ответ за первый (правда?). Из-за чего более странно, почему после ответа на второй вопрос команда неожиданно выходит ...? –

Смежные вопросы