diff --git a/examples/exec.php b/examples/exec-inspect.php similarity index 64% rename from examples/exec.php rename to examples/exec-inspect.php index b9d9f78..a7d40e3 100644 --- a/examples/exec.php +++ b/examples/exec-inspect.php @@ -5,25 +5,32 @@ use React\EventLoop\Factory as LoopFactory; use Clue\React\Docker\Factory; -use Clue\React\Docker\ExecHelper; -use React\Stream\Stream; use Clue\React\Buzz\Message\ResponseException; -$container = isset($argv[1]) ? $argv[1] : 'asd'; +$container = 'asd'; +//$cmd = array('echo', 'hello world'); +//$cmd = array('sleep', '2'); +$cmd = array('sh', '-c', 'echo -n hello && sleep 1 && echo world && sleep 1 && env'); +//$cmd = array('cat', 'invalid-path'); + +if (isset($argv[1])) { + $container = $argv[1]; + $cmd = array_slice($argv, 2); +} $loop = LoopFactory::create(); $factory = new Factory($loop); $client = $factory->createClient(); -$client->execCreate($container, array('Cmd' => array('sleep', '2'), 'AttachStdout' => true))->then(function ($info) use ($client) { +$client->execCreate($container, array('Cmd' => $cmd, 'AttachStdout' => true, 'AttachStderr' => true, 'Tty' => true))->then(function ($info) use ($client) { echo 'Created with info: ' . json_encode($info) . PHP_EOL; return $client->execInspect($info['Id']); })->then(function ($info) use ($client) { echo 'Inspected after creation: ' . json_encode($info, JSON_PRETTY_PRINT) . PHP_EOL; - return $client->execStart($info['ID'], array())->then(function ($out) use ($client, $info) { + return $client->execStart($info['ID'], array('Tty' => true))->then(function ($out) use ($client, $info) { echo 'Starting returned: '; var_dump($out); diff --git a/src/Client.php b/src/Client.php index b511a4a..eebb8ca 100644 --- a/src/Client.php +++ b/src/Client.php @@ -903,15 +903,20 @@ public function execCreate($container, $config) /** * Starts a previously set up exec instance id. * + * This resolves with a string of the command output, i.e. STDOUT and STDERR + * as set up in the `execCreate()` call. + * + * Keep in mind that this means the whole string has to be kept in memory. + * * If detach is true, this API returns after starting the exec command. * Otherwise, this API sets up an interactive session with the exec command. * * @param string $exec exec ID * @param array $config (see link) - * @return PromiseInterface Promise stream of message objects + * @return PromiseInterface Promise buffered exec data * @link https://docs.docker.com/reference/api/docker_remote_api_v1.15/#exec-start */ - public function execStart($exec, $config) + public function execStart($exec, $config = array()) { return $this->postJson( $this->uri->expand( @@ -921,7 +926,7 @@ public function execStart($exec, $config) ) ), $config - )->then(array($this->parser, 'expectJson')); + )->then(array($this->parser, 'expectPlain')); } /** diff --git a/tests/ClientTest.php b/tests/ClientTest.php index 146829a..821393d 100644 --- a/tests/ClientTest.php +++ b/tests/ClientTest.php @@ -386,11 +386,11 @@ public function testExecCreate() public function testExecStart() { - $json = array(); + $data = 'hello world'; $config = array(); - $this->expectRequestFlow('post', '/exec/123/start', $this->createResponseJson($json), 'expectJson'); + $this->expectRequestFlow('post', '/exec/123/start', $this->createResponse($data), 'expectPlain'); - $this->expectPromiseResolveWith($json, $this->client->execStart(123, $config)); + $this->expectPromiseResolveWith($data, $this->client->execStart(123, $config)); } public function testExecResize() diff --git a/tests/FunctionalClientTest.php b/tests/FunctionalClientTest.php index 6111d38..39fa090 100644 --- a/tests/FunctionalClientTest.php +++ b/tests/FunctionalClientTest.php @@ -72,6 +72,103 @@ public function testCreateStartAndRemoveContainer() $this->assertEquals('destroy', $ret[3]['status']); } + public function testStartRunning() + { + $config = array( + 'Image' => 'busybox', + 'Tty' => true, + 'Cmd' => array('sleep', '10') + ); + + $promise = $this->client->containerCreate($config); + $container = Block\await($promise, $this->loop); + + $this->assertNotNull($container['Id']); + $this->assertNull($container['Warnings']); + + $start = microtime(true); + + $promise = $this->client->containerStart($container['Id']); + $ret = Block\await($promise, $this->loop); + + $this->assertEquals('', $ret); + + return $container['Id']; + } + + /** + * @depends testStartRunning + * @param string $container + * @return string + */ + public function testExecCreateWhileRunning($container) + { + $promise = $this->client->execCreate($container, array( + 'Cmd' => array('echo', '-n', 'hello', 'world'), + 'AttachStdout' => true, + 'AttachStderr' => true, + 'Tty' => true + )); + $exec = Block\await($promise, $this->loop); + + $this->assertTrue(is_array($exec)); + $this->assertTrue(is_string($exec['Id'])); + + return $exec['Id']; + } + + /** + * @depends testExecCreateWhileRunning + * @param string $exec + */ + public function testExecInspectBeforeRunning($exec) + { + $promise = $this->client->execInspect($exec); + $info = Block\await($promise, $this->loop); + + $this->assertTrue(is_array($info)); + $this->assertFalse($info['Running']); + $this->assertEquals(null, $info['ExitCode']); + } + + /** + * @depends testExecCreateWhileRunning + * @param string $exec + */ + public function testExecStartWhileRunning($exec) + { + $promise = $this->client->execStart($exec, array('Tty' => true)); + $output = Block\await($promise, $this->loop); + + $this->assertEquals('hello world', $output); + } + + /** + * @depends testExecCreateWhileRunning + * @param string $exec + */ + public function testExecInspectAfterRunning($exec) + { + $promise = $this->client->execInspect($exec); + $info = Block\await($promise, $this->loop); + + $this->assertTrue(is_array($info)); + $this->assertFalse($info['Running']); + $this->assertEquals(0, $info['ExitCode']); + } + + /** + * @depends testStartRunning + * @param string $container + */ + public function testRemoveRunning($container) + { + $promise = $this->client->containerRemove($container, true, true); + $ret = Block\await($promise, $this->loop); + + $this->assertEquals('', $ret); + } + /** * @expectedException RuntimeException */