Changeset View
Changeset View
Standalone View
Standalone View
src/future/exec/__tests__/ExecFutureTestCase.php
| <?php | <?php | ||||
| final class ExecFutureTestCase extends PhutilTestCase { | final class ExecFutureTestCase extends PhutilTestCase { | ||||
| public function testEmptyWrite() { | public function testEmptyWrite() { | ||||
| // NOTE: This is mostly testing that we don't hang while doing an empty | // NOTE: This is mostly testing that we don't hang while doing an empty | ||||
| // write. | // write. | ||||
| list($stdout) = id(new ExecFuture('cat'))->write('')->resolvex(); | list($stdout) = $this->newCat() | ||||
| ->write('') | |||||
| ->resolvex(); | |||||
| $this->assertEqual('', $stdout); | $this->assertEqual('', $stdout); | ||||
| } | } | ||||
| private function newCat() { | |||||
| $bin = $this->getSupportExecutable('cat'); | |||||
| return new ExecFuture('php -f %R', $bin); | |||||
| } | |||||
| private function newSleep($duration) { | |||||
| $bin = $this->getSupportExecutable('sleep'); | |||||
| return new ExecFuture('php -f %R -- %s', $bin, $duration); | |||||
| } | |||||
| public function testKeepPipe() { | public function testKeepPipe() { | ||||
| // NOTE: This is mostly testing the semantics of $keep_pipe in write(). | // NOTE: This is mostly testing the semantics of $keep_pipe in write(). | ||||
| list($stdout) = id(new ExecFuture('cat')) | list($stdout) = $this->newCat() | ||||
| ->write('', true) | ->write('', true) | ||||
| ->start() | ->start() | ||||
| ->write('x', true) | ->write('x', true) | ||||
| ->write('y', true) | ->write('y', true) | ||||
| ->write('z', false) | ->write('z', false) | ||||
| ->resolvex(); | ->resolvex(); | ||||
| $this->assertEqual('xyz', $stdout); | $this->assertEqual('xyz', $stdout); | ||||
| } | } | ||||
| public function testLargeBuffer() { | public function testLargeBuffer() { | ||||
| // NOTE: This is mostly a coverage test to hit branches where we're still | // NOTE: This is mostly a coverage test to hit branches where we're still | ||||
| // flushing a buffer. | // flushing a buffer. | ||||
| $data = str_repeat('x', 1024 * 1024 * 4); | $data = str_repeat('x', 1024 * 1024 * 4); | ||||
| list($stdout) = id(new ExecFuture('cat'))->write($data)->resolvex(); | list($stdout) = $this->newCat()->write($data)->resolvex(); | ||||
| $this->assertEqual($data, $stdout); | $this->assertEqual($data, $stdout); | ||||
| } | } | ||||
| public function testBufferLimit() { | public function testBufferLimit() { | ||||
| $data = str_repeat('x', 1024 * 1024); | $data = str_repeat('x', 1024 * 1024); | ||||
| list($stdout) = id(new ExecFuture('cat')) | list($stdout) = $this->newCat() | ||||
| ->setStdoutSizeLimit(1024) | ->setStdoutSizeLimit(1024) | ||||
| ->write($data) | ->write($data) | ||||
| ->resolvex(); | ->resolvex(); | ||||
| $this->assertEqual(substr($data, 0, 1024), $stdout); | $this->assertEqual(substr($data, 0, 1024), $stdout); | ||||
| } | } | ||||
| public function testResolveTimeoutTestShouldRunLessThan1Sec() { | public function testResolveTimeoutTestShouldRunLessThan1Sec() { | ||||
| // NOTE: This tests interactions between the resolve() timeout and the | // NOTE: This tests interactions between the resolve() timeout and the | ||||
| // ExecFuture timeout, which are similar but not identical. | // ExecFuture timeout, which are similar but not identical. | ||||
| $future = id(new ExecFuture('sleep 32000'))->start(); | $future = $this->newSleep(32000)->start(); | ||||
| $future->setTimeout(32000); | $future->setTimeout(32000); | ||||
| // We expect this to return in 0.01s. | // We expect this to return in 0.01s. | ||||
| $result = $future->resolve(0.01); | $result = $future->resolve(0.01); | ||||
| $this->assertEqual($result, null); | $this->assertEqual($result, null); | ||||
| // We expect this to now force the time out / kill immediately. If we don't | // We expect this to now force the time out / kill immediately. If we don't | ||||
| // do this, we'll hang when exiting until our subprocess exits (32000 | // do this, we'll hang when exiting until our subprocess exits (32000 | ||||
| // seconds!) | // seconds!) | ||||
| $future->setTimeout(0.01); | $future->setTimeout(0.01); | ||||
| $future->resolve(); | $future->resolve(); | ||||
| } | } | ||||
| public function testTerminateWithoutStart() { | public function testTerminateWithoutStart() { | ||||
| // We never start this future, but it should be fine to kill a future from | // We never start this future, but it should be fine to kill a future from | ||||
| // any state. | // any state. | ||||
| $future = new ExecFuture('sleep 1'); | $future = $this->newSleep(1); | ||||
| $future->resolveKill(); | $future->resolveKill(); | ||||
| $this->assertTrue(true); | $this->assertTrue(true); | ||||
| } | } | ||||
| public function testTimeoutTestShouldRunLessThan1Sec() { | public function testTimeoutTestShouldRunLessThan1Sec() { | ||||
| // NOTE: This is partly testing that we choose appropriate select wait | // NOTE: This is partly testing that we choose appropriate select wait | ||||
| // times; this test should run for significantly less than 1 second. | // times; this test should run for significantly less than 1 second. | ||||
| $future = new ExecFuture('sleep 32000'); | $future = $this->newSleep(32000); | ||||
| list($err) = $future->setTimeout(0.01)->resolve(); | list($err) = $future->setTimeout(0.01)->resolve(); | ||||
| $this->assertTrue($err > 0); | $this->assertTrue($err > 0); | ||||
| $this->assertTrue($future->getWasKilledByTimeout()); | $this->assertTrue($future->getWasKilledByTimeout()); | ||||
| } | } | ||||
| public function testMultipleTimeoutsTestShouldRunLessThan1Sec() { | public function testMultipleTimeoutsTestShouldRunLessThan1Sec() { | ||||
| $futures = array(); | $futures = array(); | ||||
| for ($ii = 0; $ii < 4; $ii++) { | for ($ii = 0; $ii < 4; $ii++) { | ||||
| $futures[] = id(new ExecFuture('sleep 32000'))->setTimeout(0.01); | $futures[] = $this->newSleep(32000)->setTimeout(0.01); | ||||
| } | } | ||||
| foreach (new FutureIterator($futures) as $future) { | foreach (new FutureIterator($futures) as $future) { | ||||
| list($err) = $future->resolve(); | list($err) = $future->resolve(); | ||||
| $this->assertTrue($err > 0); | $this->assertTrue($err > 0); | ||||
| $this->assertTrue($future->getWasKilledByTimeout()); | $this->assertTrue($future->getWasKilledByTimeout()); | ||||
| } | } | ||||
| } | } | ||||
| public function testMultipleResolves() { | public function testMultipleResolves() { | ||||
| // It should be safe to call resolve(), resolvex(), resolveKill(), etc., | // It should be safe to call resolve(), resolvex(), resolveKill(), etc., | ||||
| // as many times as you want on the same process. | // as many times as you want on the same process. | ||||
| $bin = $this->getSupportExecutable('echo'); | |||||
| $future = new ExecFuture('echo quack'); | $future = new ExecFuture('php -f %R -- quack', $bin); | ||||
| $future->resolve(); | $future->resolve(); | ||||
| $future->resolvex(); | $future->resolvex(); | ||||
| list($err) = $future->resolveKill(); | list($err) = $future->resolveKill(); | ||||
| $this->assertEqual(0, $err); | $this->assertEqual(0, $err); | ||||
| } | } | ||||
| public function testReadBuffering() { | public function testReadBuffering() { | ||||
| $str_len_8 = 'abcdefgh'; | $str_len_8 = 'abcdefgh'; | ||||
| $str_len_4 = 'abcd'; | $str_len_4 = 'abcd'; | ||||
| // This is a write/read with no read buffer. | // This is a write/read with no read buffer. | ||||
| $future = new ExecFuture('cat'); | $future = $this->newCat(); | ||||
| $future->write($str_len_8); | $future->write($str_len_8); | ||||
| do { | do { | ||||
| $future->isReady(); | $future->isReady(); | ||||
| list($read) = $future->read(); | list($read) = $future->read(); | ||||
| if (strlen($read)) { | if (strlen($read)) { | ||||
| break; | break; | ||||
| } | } | ||||
| } while (true); | } while (true); | ||||
| // We expect to get the entire string back in the read. | // We expect to get the entire string back in the read. | ||||
| $this->assertEqual($str_len_8, $read); | $this->assertEqual($str_len_8, $read); | ||||
| $future->resolve(); | $future->resolve(); | ||||
| // This is a write/read with a read buffer. | // This is a write/read with a read buffer. | ||||
| $future = new ExecFuture('cat'); | $future = $this->newCat(); | ||||
| $future->write($str_len_8); | $future->write($str_len_8); | ||||
| // Set the read buffer size. | // Set the read buffer size. | ||||
| $future->setReadBufferSize(4); | $future->setReadBufferSize(4); | ||||
| do { | do { | ||||
| $future->isReady(); | $future->isReady(); | ||||
| list($read) = $future->read(); | list($read) = $future->read(); | ||||
| if (strlen($read)) { | if (strlen($read)) { | ||||
| Show All 13 Lines | |||||