Exemplo n.º 1
0
 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 = new ExecFuture('sleep 32000');
     list($err) = $future->setTimeout(0.01)->resolve();
     $this->assertEqual(true, $err > 0);
     $this->assertEqual(true, $future->getWasKilledByTimeout());
 }
Exemplo n.º 2
0
 protected function configureFuture(ExecFuture $future)
 {
     if ($this->getTimeout()) {
         $future->setTimeout($this->getTimeout());
     }
     if ($this->getByteLimit()) {
         $future->setStdoutSizeLimit($this->getByteLimit());
         $future->setStderrSizeLimit($this->getByteLimit());
     }
 }
 public function testCloseExecWriteChannel()
 {
     $future = new ExecFuture('cat');
     // If this test breaks, we want to explode, not hang forever.
     $future->setTimeout(5);
     $exec_channel = new PhutilExecChannel($future);
     $exec_channel->write('quack');
     $exec_channel->closeWriteChannel();
     // If `closeWriteChannel()` did what it is supposed to, this will just
     // echo "quack" and exit with no error code. If the channel did not close,
     // this will time out after 5 seconds and throw.
     $future->resolvex();
     $this->assertTrue(true);
 }
Exemplo n.º 4
0
 public function run()
 {
     $results = array();
     $build_start = microtime(true);
     $config_manager = $this->getConfigurationManager();
     if ($this->getEnableCoverage() !== false) {
         $command = $config_manager->getConfigFromAnySource('unit.engine.tap.cover');
     } else {
         $command = $config_manager->getConfigFromAnySource('unit.engine.tap.command');
     }
     $timeout = $config_manager->getConfigFromAnySource('unit.engine.tap.timeout');
     if (!$timeout) {
         $timeout = 15;
     }
     $future = new ExecFuture('%C', $command);
     $future->setTimeout($timeout);
     $result = new ArcanistUnitTestResult();
     $result->setName($command ? $command : 'unknown');
     try {
         list($stdout, $stderr) = $future->resolvex();
         $result->setResult(ArcanistUnitTestResult::RESULT_PASS);
         if ($this->getEnableCoverage() !== false) {
             $coverage = $this->readCoverage('coverage/cobertura-coverage.xml');
             $result->setCoverage($coverage);
         }
     } catch (CommandException $exc) {
         $result->setResult(ArcanistUnitTestResult::RESULT_FAIL);
         if ($future->getWasKilledByTimeout()) {
             print "Process stdout:\n" . $exc->getStdout() . "\nProcess stderr:\n" . $exc->getStderr() . "\nExceeded timeout of {$timeout} secs.\nMake unit tests faster.";
         } else {
             $result->setUserdata($exc->getStdout() . $exc->getStderr());
         }
     }
     $result->setDuration(microtime(true) - $build_start);
     $results[] = $result;
     return $results;
 }
 public function markupContent($content, array $argv)
 {
     if (!Filesystem::binaryExists('cowsay')) {
         return $this->markupError(pht('Unable to locate the `%s` binary. Install cowsay.', 'cowsay'));
     }
     $bin = idx($argv, 'think') ? 'cowthink' : 'cowsay';
     $eyes = idx($argv, 'eyes', 'oo');
     $tongue = idx($argv, 'tongue', '  ');
     $cow = idx($argv, 'cow', 'default');
     // NOTE: Strip this aggressively to prevent nonsense like
     // `cow=/etc/passwd`. We could build a whiltelist with `cowsay -l`.
     $cow = preg_replace('/[^a-z.-]+/', '', $cow);
     $future = new ExecFuture('%s -e %s -T %s -f %s ', $bin, $eyes, $tongue, $cow);
     $future->setTimeout(15);
     $future->write($content);
     list($err, $stdout, $stderr) = $future->resolve();
     if ($err) {
         return $this->markupError(pht('Execution of `%s` failed: %s', 'cowsay', $stderr));
     }
     if ($this->getEngine()->isTextMode()) {
         return $stdout;
     }
     return phutil_tag('div', array('class' => 'PhabricatorMonospaced remarkup-cowsay'), $stdout);
 }
 public function loadChangesetsForCommit($identifier)
 {
     $byte_limit = HeraldCommitAdapter::getEnormousByteLimit();
     $time_limit = HeraldCommitAdapter::getEnormousTimeLimit();
     $vcs = $this->getRepository()->getVersionControlSystem();
     switch ($vcs) {
         case PhabricatorRepositoryType::REPOSITORY_TYPE_GIT:
         case PhabricatorRepositoryType::REPOSITORY_TYPE_MERCURIAL:
             // For git and hg, we can use normal commands.
             $drequest = DiffusionRequest::newFromDictionary(array('repository' => $this->getRepository(), 'user' => $this->getViewer(), 'commit' => $identifier));
             $raw_diff = DiffusionRawDiffQuery::newFromDiffusionRequest($drequest)->setTimeout($time_limit)->setByteLimit($byte_limit)->setLinesOfContext(0)->loadRawDiff();
             break;
         case PhabricatorRepositoryType::REPOSITORY_TYPE_SVN:
             // TODO: This diff has 3 lines of context, which produces slightly
             // incorrect "added file content" and "removed file content" results.
             // This may also choke on binaries, but "svnlook diff" does not support
             // the "--diff-cmd" flag.
             // For subversion, we need to use `svnlook`.
             $future = new ExecFuture('svnlook diff -t %s %s', $this->subversionTransaction, $this->subversionRepository);
             $future->setTimeout($time_limit);
             $future->setStdoutSizeLimit($byte_limit);
             $future->setStderrSizeLimit($byte_limit);
             list($raw_diff) = $future->resolvex();
             break;
         default:
             throw new Exception(pht("Unknown VCS '%s!'", $vcs));
     }
     if (strlen($raw_diff) >= $byte_limit) {
         throw new Exception(pht('The raw text of this change is enormous (larger than %d ' . 'bytes). Herald can not process it.', $byte_limit));
     }
     if (!strlen($raw_diff)) {
         // If the commit is actually empty, just return no changesets.
         return array();
     }
     $parser = new ArcanistDiffParser();
     $changes = $parser->parseDiff($raw_diff);
     $diff = DifferentialDiff::newEphemeralFromRawChanges($changes);
     return $diff->getChangesets();
 }
 protected function applyImagemagick(array $argv)
 {
     $tmp = new TempFile();
     Filesystem::writeFile($tmp, $this->getData());
     $out = new TempFile();
     $future = new ExecFuture('convert %s %Ls %s', $tmp, $argv, $out);
     // Don't spend more than 60 seconds resizing; just fail if it takes longer
     // than that.
     $future->setTimeout(60)->resolvex();
     $data = Filesystem::readFile($out);
     return $this->newFileFromData($data);
 }
 private function applyMemeWithImagemagick($input, $above, $below, $count, $img_type)
 {
     $output = new TempFile();
     $future = new ExecFuture('convert %s -coalesce +adjoin %s_%s', $input, $input, '%09d');
     $future->setTimeout(10)->resolvex();
     $output_files = array();
     for ($ii = 0; $ii < $count; $ii++) {
         $frame_name = sprintf('%s_%09d', $input, $ii);
         $output_name = sprintf('%s_%09d', $output, $ii);
         $output_files[] = $output_name;
         $frame_data = Filesystem::readFile($frame_name);
         $memed_frame_data = $this->applyMemeTo($frame_data, $above, $below, $img_type);
         Filesystem::writeFile($output_name, $memed_frame_data);
     }
     $future = new ExecFuture('convert -loop 0 %Ls %s', $output_files, $output);
     $future->setTimeout(10)->resolvex();
     return Filesystem::readFile($output);
 }
 /**
  * @task pull
  */
 private function buildUpdateFuture(PhabricatorRepository $repository, $no_discovery)
 {
     $bin = dirname(phutil_get_library_root('phabricator')) . '/bin/repository';
     $flags = array();
     if ($no_discovery) {
         $flags[] = '--no-discovery';
     }
     $callsign = $repository->getCallsign();
     $future = new ExecFuture('%s update %Ls -- %s', $bin, $flags, $callsign);
     // Sometimes, the underlying VCS commands will hang indefinitely. We've
     // observed this occasionally with GitHub, and other users have observed
     // it with other VCS servers.
     // To limit the damage this can cause, kill the update out after a
     // reasonable amount of time, under the assumption that it has hung.
     // Since it's hard to know what a "reasonable" amount of time is given that
     // users may be downloading a repository full of pirated movies over a
     // potato, these limits are fairly generous. Repositories exceeding these
     // limits can be manually pulled with `bin/repository update X`, which can
     // just run for as long as it wants.
     if ($repository->isImporting()) {
         $timeout = phutil_units('4 hours in seconds');
     } else {
         $timeout = phutil_units('15 minutes in seconds');
     }
     $future->setTimeout($timeout);
     return $future;
 }
 public function runIntegrationTests($tests)
 {
     // Now find all the test programs
     $root = $this->getProjectRoot();
     $test_dir = $root . "/tests/integration/";
     if (!$tests) {
         $paths = glob($test_dir . "*.php");
         $paths[] = 'ruby/ruby-watchman/spec/ruby_watchman_spec.rb';
     } else {
         $paths = $tests;
     }
     foreach (array('/tmp/watchman-test.log', '/tmp/watchman-valgrind.log', '/tmp/watchman-valgrind.xml', '/tmp/watchman-callgrind.txt') as $log) {
         @unlink($log);
     }
     foreach ($paths as $path) {
         if (preg_match("/\\.php\$/", $path) && file_exists($path)) {
             // Don't pull in files starting with "_"; we're using
             // those as helpers for triggers
             $base = basename($path);
             if ($base[0] != '_') {
                 require_once $path;
             }
         }
     }
     // We test for this in a test case
     putenv("WATCHMAN_EMPTY_ENV_VAR=");
     $coverage = $this->getEnableCoverage();
     if (!$this->first_inst) {
         $this->first_inst = new WatchmanInstance($root, $coverage);
     }
     $first_inst = $this->first_inst;
     $instances = array($first_inst);
     // Helper for python or other language tests
     putenv("WATCHMAN_SOCK=" . $first_inst->getFullSockName());
     // Exercise the different serialization combinations
     $cli_matrix = array();
     // Find all the test cases that were declared
     $results = array();
     foreach (get_declared_classes() as $name) {
         $ref = new ReflectionClass($name);
         if (!$ref->isSubclassOf('WatchmanTestCase')) {
             continue;
         }
         // Good enough; let's use it
         $test_case = newv($name, array());
         $config = $test_case->getGlobalConfig();
         if ($config) {
             $instance = new WatchmanInstance($root, $coverage, $config);
             $instances[] = $instance;
         } else {
             $instance = $first_inst;
         }
         $test_case->setWatchmanInstance($instance);
         if (!$instance->getProcessID()) {
             $res = new ArcanistUnitTestResult();
             $res->setName('dead');
             $res->setUserData('died before test start');
             $res->setResult(ArcanistUnitTestResult::RESULT_FAIL);
             $results[] = array($res);
             break;
         }
         $test_case->setRoot($root);
         $test_case->setPaths($paths);
         $results[] = $test_case->run();
         if (!$test_case->needsLiveConnection()) {
             foreach ($cli_matrix as $mname => $args) {
                 $test_case->useCLI($args);
                 $cli_results = $test_case->run();
                 foreach ($cli_results as $res) {
                     $res->setName($res->getName() . " [CLI: {$mname}]");
                 }
                 $results[] = $cli_results;
             }
         }
     }
     foreach ($paths as $path) {
         if (!preg_match('/\\.rb$/', $path)) {
             continue;
         }
         if (!file_exists($path)) {
             // Was deleted in this (pending) rev
             continue;
         }
         $start = microtime(true);
         $future = new ExecFuture("PATH=\"{$root}:\$PATH\" \${MAKE:-make} rb-tests");
         $future->setTimeout(10);
         list($status, $out, $err) = $future->resolve();
         $end = microtime(true);
         $res = new ArcanistUnitTestResult();
         $res->setName($path);
         $res->setUserData($out . $err);
         $res->setDuration($end - $start);
         $res->setResult($status == 0 ? ArcanistUnitTestResult::RESULT_PASS : ArcanistUnitTestResult::RESULT_FAIL);
         $results[] = array($res);
     }
     foreach ($instances as $instance) {
         $results[] = $instance->generateValgrindTestResults();
     }
     $results = array_mergev($results);
     return $results;
 }
 public function runIntegrationTests($tests)
 {
     $this->make('all');
     // Now find all the test programs
     $root = $this->getProjectRoot();
     $test_dir = $root . "/tests/integration/";
     if (!$tests) {
         $paths = glob($test_dir . "*.php");
         foreach (glob('python/tests/*.py') as $file) {
             $paths[] = $file;
         }
         $paths[] = 'ruby/ruby-watchman/spec/ruby_watchman_spec.rb';
     } else {
         $paths = $tests;
     }
     foreach (array('/tmp/watchman-test.log', '/tmp/watchman-valgrind.log', '/tmp/watchman-valgrind.xml', '/tmp/watchman-callgrind.txt') as $log) {
         @unlink($log);
     }
     foreach ($paths as $path) {
         if (preg_match("/\\.php\$/", $path) && file_exists($path)) {
             require_once $path;
         }
     }
     // We test for this in a test case
     putenv("WATCHMAN_EMPTY_ENV_VAR=");
     $coverage = $this->getEnableCoverage();
     $first_inst = new WatchmanInstance($root, $coverage);
     $instances = array($first_inst);
     // Helper for python or other language tests
     putenv("WATCHMAN_SOCK=" . $first_inst->getFullSockName());
     // Exercise the different serialization combinations
     $cli_matrix = array('bser/json' => '--server-encoding=bser --output-encoding=json', 'json/json' => '--server-encoding=json --output-encoding=json');
     // Find all the test cases that were declared
     $results = array();
     foreach (get_declared_classes() as $name) {
         $ref = new ReflectionClass($name);
         if (!$ref->isSubclassOf('WatchmanTestCase')) {
             continue;
         }
         // Good enough; let's use it
         $test_case = newv($name, array());
         $config = $test_case->getGlobalConfig();
         if ($config) {
             $instance = new WatchmanInstance($root, $coverage, $config);
             $instances[] = $instance;
         } else {
             $instance = $first_inst;
         }
         $test_case->setWatchmanInstance($instance);
         if (!$instance->getProcessID()) {
             $res = new ArcanistUnitTestResult();
             $res->setName('dead');
             $res->setUserData('died before test start');
             $res->setResult(ArcanistUnitTestResult::RESULT_FAIL);
             $results[] = array($res);
             break;
         }
         $test_case->setRoot($root);
         $test_case->setPaths($paths);
         $results[] = $test_case->run();
         if (!$test_case->needsLiveConnection()) {
             foreach ($cli_matrix as $mname => $args) {
                 $test_case->useCLI($args);
                 $cli_results = $test_case->run();
                 foreach ($cli_results as $res) {
                     $res->setName($res->getName() . " [CLI: {$mname}]");
                 }
                 $results[] = $cli_results;
             }
         }
     }
     // Also run the python tests if we built them
     foreach ($paths as $path) {
         if (!preg_match('/test.*\\.py$/', $path)) {
             continue;
         }
         if (!file_exists($path)) {
             // Was deleted in this (pending) rev
             continue;
         }
         if (!file_exists("python/pywatchman/bser.so")) {
             // Not enabled by the build
             continue;
         }
         // Note that this implicitly starts the instance if we haven't
         // yet done so.  This is important if the only test paths are
         // python paths
         if (!$first_inst->getProcessID()) {
             $res = new ArcanistUnitTestResult();
             $res->setName('dead');
             $res->setUserData('died before test start');
             $res->setResult(ArcanistUnitTestResult::RESULT_FAIL);
             $results[] = array($res);
             break;
         }
         // our Makefile contains the detected python, so just run the
         // rule from the makefile to pick it up
         $start = microtime(true);
         $future = new ExecFuture("PATH=\"{$root}:\$PATH\" PYTHONPATH={$root}/python " . "TESTNAME={$path} \${MAKE:-make} py-tests");
         $future->setTimeout(10);
         list($status, $out, $err) = $future->resolve();
         $end = microtime(true);
         $res = new ArcanistUnitTestResult();
         $res->setName($path);
         $res->setUserData($out . $err);
         $res->setDuration($end - $start);
         $res->setResult($status == 0 ? ArcanistUnitTestResult::RESULT_PASS : ArcanistUnitTestResult::RESULT_FAIL);
         $results[] = array($res);
     }
     foreach ($paths as $path) {
         if (!preg_match('/\\.rb$/', $path)) {
             continue;
         }
         if (!file_exists($path)) {
             // Was deleted in this (pending) rev
             continue;
         }
         $start = microtime(true);
         $future = new ExecFuture("PATH=\"{$root}:\$PATH\" \${MAKE:-make} rb-tests");
         $future->setTimeout(10);
         list($status, $out, $err) = $future->resolve();
         $end = microtime(true);
         $res = new ArcanistUnitTestResult();
         $res->setName($path);
         $res->setUserData($out . $err);
         $res->setDuration($end - $start);
         $res->setResult($status == 0 ? ArcanistUnitTestResult::RESULT_PASS : ArcanistUnitTestResult::RESULT_FAIL);
         $results[] = array($res);
     }
     foreach ($instances as $instance) {
         $results[] = $instance->generateValgrindTestResults();
     }
     $results = array_mergev($results);
     return $results;
 }