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 { | ||||
// Do not use `cat` since on Windows, cat chokes after 8kb of STDIN input | |||||
// Also `cat` is only available through Git for Windows package | |||||
private static function cat() { | |||||
return new ExecFuture('php -r %s', 'while($f=fgets(STDIN)){echo $f;}'); | |||||
BYK: I think I should replace these with `php -r %s`. LMK if you agree and I'll make the change. | |||||
} | |||||
// `sleep` is only available through Git for Windows package on Windows | |||||
private static function sleeper($seconds) { | |||||
return new ExecFuture('php -r %s', "sleep($seconds);"); | |||||
} | |||||
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) = self::cat()->write('')->resolvex(); | ||||
$this->assertEqual('', $stdout); | $this->assertEqual('', $stdout); | ||||
} | } | ||||
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) = self::cat() | ||||
->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) = self::cat()->write($data)->resolvex(); | ||||
$this->assertEqual($data, $stdout); | $this->assertEqual($data, rtrim($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) = self::cat() | ||||
->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 = self::sleeper(32000)->setTimeout(32000)->start(); | ||||
$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 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 = self::sleeper(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[] = self::sleeper(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()); | ||||
} | } | ||||
Show All 11 Lines | public function testMultipleResolves() { | ||||
$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 = self::cat(); | ||||
$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 = self::cat(); | ||||
$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 |
I think I should replace these with php -r %s. LMK if you agree and I'll make the change.