mirror of
https://we.phorge.it/source/arcanist.git
synced 2025-03-28 20:18:12 +01:00
Summary: Ref T11968. This future-level parameter has no nontrivial callers and makes the "fate of FutureGraph" changes more difficult. Callers that are genuinely interested in this behavior can wrap the Future in a FutureIterator and use "setUpdateInterval()" to get the same behavior. Test Plan: Grepped for "resolve()" and "resolvex()", updated callers. Maniphest Tasks: T11968 Differential Revision: https://secure.phabricator.com/D21031
173 lines
4.6 KiB
PHP
173 lines
4.6 KiB
PHP
<?php
|
|
|
|
final class ExecFutureTestCase extends PhutilTestCase {
|
|
|
|
public function testEmptyWrite() {
|
|
// NOTE: This is mostly testing that we don't hang while doing an empty
|
|
// write.
|
|
|
|
list($stdout) = $this->newCat()
|
|
->write('')
|
|
->resolvex();
|
|
|
|
$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() {
|
|
// NOTE: This is mostly testing the semantics of $keep_pipe in write().
|
|
|
|
list($stdout) = $this->newCat()
|
|
->write('', true)
|
|
->start()
|
|
->write('x', true)
|
|
->write('y', true)
|
|
->write('z', false)
|
|
->resolvex();
|
|
|
|
$this->assertEqual('xyz', $stdout);
|
|
}
|
|
|
|
public function testLargeBuffer() {
|
|
// NOTE: This is mostly a coverage test to hit branches where we're still
|
|
// flushing a buffer.
|
|
|
|
$data = str_repeat('x', 1024 * 1024 * 4);
|
|
list($stdout) = $this->newCat()->write($data)->resolvex();
|
|
|
|
$this->assertEqual($data, $stdout);
|
|
}
|
|
|
|
public function testBufferLimit() {
|
|
$data = str_repeat('x', 1024 * 1024);
|
|
list($stdout) = $this->newCat()
|
|
->setStdoutSizeLimit(1024)
|
|
->write($data)
|
|
->resolvex();
|
|
|
|
$this->assertEqual(substr($data, 0, 1024), $stdout);
|
|
}
|
|
|
|
public function testResolveTimeoutTestShouldRunLessThan1Sec() {
|
|
// NOTE: This tests interactions between the resolve() timeout and the
|
|
// resolution timeout, which are somewhat similar but not identical.
|
|
|
|
$future = $this->newSleep(32000)->start();
|
|
$future->setTimeout(32000);
|
|
|
|
// We expect this to return in 0.01s.
|
|
$iterator = (new FutureIterator(array($future)))
|
|
->setUpdateInterval(0.01);
|
|
foreach ($iterator as $resolved_result) {
|
|
$result = $resolved_result;
|
|
break;
|
|
}
|
|
$this->assertEqual($result, null);
|
|
|
|
// 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
|
|
// seconds!)
|
|
$future->setTimeout(0.01);
|
|
$future->resolve();
|
|
}
|
|
|
|
public function testTerminateWithoutStart() {
|
|
// We never start this future, but it should be fine to kill a future from
|
|
// any state.
|
|
$future = $this->newSleep(1);
|
|
$future->resolveKill();
|
|
|
|
$this->assertTrue(true);
|
|
}
|
|
|
|
public function testTimeoutTestShouldRunLessThan1Sec() {
|
|
// NOTE: This is partly testing that we choose appropriate select wait
|
|
// times; this test should run for significantly less than 1 second.
|
|
|
|
$future = $this->newSleep(32000);
|
|
list($err) = $future->setTimeout(0.01)->resolve();
|
|
|
|
$this->assertTrue($err > 0);
|
|
$this->assertTrue($future->getWasKilledByTimeout());
|
|
}
|
|
|
|
public function testMultipleTimeoutsTestShouldRunLessThan1Sec() {
|
|
$futures = array();
|
|
for ($ii = 0; $ii < 4; $ii++) {
|
|
$futures[] = $this->newSleep(32000)->setTimeout(0.01);
|
|
}
|
|
|
|
foreach (new FutureIterator($futures) as $future) {
|
|
list($err) = $future->resolve();
|
|
|
|
$this->assertTrue($err > 0);
|
|
$this->assertTrue($future->getWasKilledByTimeout());
|
|
}
|
|
}
|
|
|
|
public function testMultipleResolves() {
|
|
// It should be safe to call resolve(), resolvex(), resolveKill(), etc.,
|
|
// as many times as you want on the same process.
|
|
$bin = $this->getSupportExecutable('echo');
|
|
|
|
$future = new ExecFuture('php -f %R -- quack', $bin);
|
|
$future->resolve();
|
|
$future->resolvex();
|
|
list($err) = $future->resolveKill();
|
|
|
|
$this->assertEqual(0, $err);
|
|
}
|
|
|
|
public function testReadBuffering() {
|
|
$str_len_8 = 'abcdefgh';
|
|
$str_len_4 = 'abcd';
|
|
|
|
// This is a write/read with no read buffer.
|
|
$future = $this->newCat();
|
|
$future->write($str_len_8);
|
|
|
|
do {
|
|
$future->isReady();
|
|
list($read) = $future->read();
|
|
if (strlen($read)) {
|
|
break;
|
|
}
|
|
} while (true);
|
|
|
|
// We expect to get the entire string back in the read.
|
|
$this->assertEqual($str_len_8, $read);
|
|
$future->resolve();
|
|
|
|
|
|
// This is a write/read with a read buffer.
|
|
$future = $this->newCat();
|
|
$future->write($str_len_8);
|
|
|
|
// Set the read buffer size.
|
|
$future->setReadBufferSize(4);
|
|
do {
|
|
$future->isReady();
|
|
list($read) = $future->read();
|
|
if (strlen($read)) {
|
|
break;
|
|
}
|
|
} while (true);
|
|
|
|
// We expect to get the entire string back in the read.
|
|
$this->assertEqual($str_len_4, $read);
|
|
|
|
// Remove the limit so we can resolve the future.
|
|
$future->setReadBufferSize(null);
|
|
$future->resolve();
|
|
}
|
|
|
|
}
|