isRawDiffSource()) { $this->startTestsInSandcastle($workflow); } } ////////////////////////////////////////////////////////////////////// /* Run tests in sandcastle */ function postURL($diffID, $url) { $cmd = 'echo \'{"diff_id": "' . $diffID . '", ' . '"name":"click here for sandcastle tests for D' . $diffID . '", ' . '"link":"' . $url . '"}\' | ' . 'http_proxy=fwdproxy.any.facebook.com:8080 ' . 'https_proxy=fwdproxy.any.facebook.com:8080 arc call-conduit ' . 'differential.updateunitresults'; shell_exec($cmd); } function updateTestCommand($diffID, $test, $status) { $cmd = 'echo \'{"diff_id": "' . $diffID . '", ' . '"name":"' . $test . '", ' . '"result":"' . $status . '"}\' | ' . 'http_proxy=fwdproxy.any.facebook.com:8080 ' . 'https_proxy=fwdproxy.any.facebook.com:8080 arc call-conduit ' . 'differential.updateunitresults'; return $cmd; } function updateTest($diffID, $test) { shell_exec($this->updateTestCommand($diffID, $test, "waiting")); } function getSteps($diffID, $username, $test) { $arcrc_content = exec("cat ~/.arcrc | gzip -f | base64 -w0"); // Sandcastle machines don't have arc setup. We copy the user certificate // and authenticate using that in sandcastle $setup = array( "name" => "Setup arcrc", "shell" => "echo " . $arcrc_content . " | base64 --decode" . " | gzip -d > ~/.arcrc", "user" => "root" ); // arc demands certain permission on its config $fix_permission = array( "name" => "Fix environment", "shell" => "chmod 600 ~/.arcrc", "user" => "root" ); // fbcode is a sub-repo. We cannot patch until we add it to ignore otherwise // git thinks it is uncommited change $fix_git_ignore = array( "name" => "Fix git ignore", "shell" => "echo fbcode >> .git/info/exclude", "user" => "root" ); // Patch the code (keep your fingures crossed) $patch = array( "name" => "Patch " . $diffID, "shell" => "HTTPS_PROXY=fwdproxy:8080 arc --arcrc-file ~/.arcrc " . "patch --nocommit --diff " . $diffID, "user" => "root" ); // Clean up the user arc config we are using $cleanup = array( "name" => "Arc cleanup", "shell" => "rm -f ~/.arcrc", "user" => "root" ); // Construct the steps in the order of execution $steps[] = $setup; $steps[] = $fix_permission; $steps[] = $fix_git_ignore; $steps[] = $patch; // Run the actual command $this->updateTest($diffID, $test); $cmd = $this->updateTestCommand($diffID, $test, "running") . ";" . "./build_tools/precommit_checker.py " . $test . "; exit_code=$?; ([[ \$exit_code -eq 0 ]] &&" . $this->updateTestCommand($diffID, $test, "pass") . ")" . "||" . $this->updateTestCommand($diffID, $test, "fail") . "; cat /tmp/precommit-check.log" . "; for f in `ls t/log-*`; do echo \$f; cat \$f; done;" . "[[ \$exit_code -eq 0 ]]"; $run_test = array( "name" => "Run " . $test, "shell" => $cmd, "user" => "root", ); $steps[] = $run_test; $steps[] = $cleanup; return $steps; } function startTestsInSandcastle($workflow) { // extract information we need from workflow or CLI $diffID = $workflow->getDiffId(); $username = exec("whoami"); if ($diffID == null || $username == null) { // there is no diff and we can't extract username // we cannot schedule sandcasstle job return; } if (strcmp(getenv("ROCKSDB_CHECK_ALL"), 1) == 0) { // extract all tests from the CI definition $output = file_get_contents("build_tools/rocksdb-lego-determinator"); preg_match_all('/[ ]{2}([a-zA-Z0-9_]+)[\)]{1}/', $output, $matches); $tests = $matches[1]; } else { // manually list of tests we want to run in sandcastle $tests = array( "unit", "unit_481", "clang_unit", "tsan", "asan", "lite_test", "valgrind" ); } // construct a job definition for each test and add it to the master plan foreach ($tests as $test) { $arg[] = array( "name" => "RocksDB diff " . $diffID . " test " . $test, "steps" => $this->getSteps($diffID, $username, $test) ); } // we cannot submit the parallel execution master plan to sandcastle // we need supply the job plan as a determinator // so we construct a small job that will spit out the master job plan // which sandcastle will parse and execute // Why compress ? Otherwise we run over the max string size. $cmd = "echo " . base64_encode(json_encode($arg)) . " | gzip -f | base64 -w0"; $arg_encoded = shell_exec($cmd); $command = array( "name" => "Run diff " . $diffID . "for user " . $username, "steps" => array() ); $command["steps"][] = array( "name" => "Generate determinator", "shell" => "echo " . $arg_encoded . " | base64 --decode | gzip -d" . " | base64 --decode", "determinator" => true, "user" => "root" ); // submit to sandcastle $url = 'https://interngraph.intern.facebook.com/sandcastle/generate?' .'command=SandcastleUniversalCommand' .'&vcs=rocksdb-git&revision=origin%2Fmaster&type=lego' .'&user=krad&alias=rocksdb-precommit' .'&command-args=' . urlencode(json_encode($command)); if (file_exists('/home/krad/.sandcastle')) { $cmd = 'cat /home/krad/.sandcastle'; } else { $cmd = 'cat ~/.sandcastle'; } $sandcastle_config = explode(':', rtrim(shell_exec($cmd))); if (count($sandcastle_config) != 2) { print('.sandcastle does not contain valid configuration'); return; } $app = $sandcastle_config[0]; $token = $sandcastle_config[1]; $cmd = 'https_proxy= HTTPS_PROXY= curl -s -k -F app=' . $app . ' ' . '-F token=' . $token . ' "' . $url . '"'; $output = shell_exec($cmd); // extract sandcastle URL from the response preg_match('/url": "(.+)"/', $output, $sandcastle_url); if (count($sandcastle_url) > 1) { echo "\nSandcastle URL: " . $sandcastle_url[1] . "\n"; // Ask phabricator to display it on the diff UI $this->postURL($diffID, $sandcastle_url[1]); } else { print("Error submitting job to sandcastle."); print($output); } } }