Something went wrong. Try again.
@recaptime-dev's working patches + fork for Phorge, a community fork of Phabricator. (Upstream dev and stable branches are at upstream/main hq.recaptime.dev/wiki/Phorge
phorge phabricator
Something went wrong. Try again.
8.2 kB · 260 lines
PHP
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261<?php
abstract class PhabricatorTestCase extends PhutilTestCase {
const NAMESPACE_PREFIX = 'phabricator_unittest_';
/** * If true, put Lisk in process-isolated mode for the duration of the tests so * that it will establish only isolated, side-effect-free database * connections. Defaults to true. * * NOTE: You should disable this only in rare circumstances. Unit tests should * not rely on external resources like databases, and should not produce * side effects. */ const PHABRICATOR_TESTCONFIG_ISOLATE_LISK = 'isolate-lisk';
/** * If true, build storage fixtures before running tests, and connect to them * during test execution. This will impose a performance penalty on test * execution (currently, it takes roughly one second to build the fixture) * but allows you to perform tests which require data to be read from storage * after writes. The fixture is shared across all test cases in this process. * Defaults to false. * * NOTE: All connections to fixture storage open transactions when established * and roll them back when tests complete. Each test must independently * write data it relies on; data will not persist across tests. * * NOTE: Enabling this implies disabling process isolation. */ const PHABRICATOR_TESTCONFIG_BUILD_STORAGE_FIXTURES = 'storage-fixtures';
private $configuration; private $env;
private static $storageFixtureReferences = 0; private static $storageFixture; private static $storageFixtureObjectSeed = 0; private static $testsAreRunning = 0;
protected function getPhabricatorTestCaseConfiguration() { return array(); }
private function getComputedConfiguration() { $config = $this->getPhabricatorTestCaseConfiguration() + array( self::PHABRICATOR_TESTCONFIG_ISOLATE_LISK => true, self::PHABRICATOR_TESTCONFIG_BUILD_STORAGE_FIXTURES => false, );
if ($config[self::PHABRICATOR_TESTCONFIG_BUILD_STORAGE_FIXTURES]) { // Fixtures don't make sense with process isolation. $config[self::PHABRICATOR_TESTCONFIG_ISOLATE_LISK] = false; }
return $config; }
/** @phutil-external-symbol function init_phabricator_script */ public function willRunTestCases(array $test_cases) { $root = dirname(phutil_get_library_root('phabricator')); if (!function_exists('init_phabricator_script')) { // Run the initialization routines only if nothing else already did require_once $root.'/scripts/init/lib.php'; init_phabricator_script( array( 'config.optional' => false, 'no-extensions' => true, )); }
$config = $this->getComputedConfiguration();
if ($config[self::PHABRICATOR_TESTCONFIG_BUILD_STORAGE_FIXTURES]) { ++self::$storageFixtureReferences; if (!self::$storageFixture) { self::$storageFixture = $this->newStorageFixture(); } }
++self::$testsAreRunning; }
public function didRunTestCases(array $test_cases) { if (self::$storageFixture) { self::$storageFixtureReferences--; if (!self::$storageFixtureReferences) { self::$storageFixture = null; } }
--self::$testsAreRunning; }
protected function willRunTests() { $config = $this->getComputedConfiguration();
if ($config[self::PHABRICATOR_TESTCONFIG_ISOLATE_LISK]) { LiskDAO::beginIsolateAllLiskEffectsToCurrentProcess(); }
$this->env = PhabricatorEnv::beginScopedEnv();
// NOTE: While running unit tests, we act as though all applications are // enabled, regardless of the install's configuration. Tests which need // to disable applications are responsible for adjusting state themselves // (such tests are exceedingly rare).
$this->env->overrideEnvConfig( 'phabricator.uninstalled-applications', array()); $this->env->overrideEnvConfig( 'phabricator.show-prototypes', true);
// Reset application settings to defaults, particularly policies. $this->env->overrideEnvConfig( 'phabricator.application-settings', array());
// We can't stub this service right now, and it's not generally useful // to publish notifications about test execution. $this->env->overrideEnvConfig( 'notification.servers', array());
$this->env->overrideEnvConfig( 'phabricator.base-uri', 'http://phabricator.example.com');
$this->env->overrideEnvConfig( 'auth.email-domains', array());
// Tests do their own stubbing/voiding for events. $this->env->overrideEnvConfig('phabricator.silent', false);
$this->env->overrideEnvConfig('cluster.read-only', false);
$this->env->overrideEnvConfig( 'maniphest.custom-field-definitions', array()); }
protected function didRunTests() { $config = $this->getComputedConfiguration();
if ($config[self::PHABRICATOR_TESTCONFIG_ISOLATE_LISK]) { LiskDAO::endIsolateAllLiskEffectsToCurrentProcess(); }
try { if (phutil_is_hiphop_runtime()) { $this->env->__destruct(); } unset($this->env); } catch (Exception $ex) { throw new Exception( pht( 'Some test called %s, but is still holding '. 'a reference to the scoped environment!', 'PhabricatorEnv::beginScopedEnv()')); } }
protected function willRunOneTest($test) { $config = $this->getComputedConfiguration();
if ($config[self::PHABRICATOR_TESTCONFIG_BUILD_STORAGE_FIXTURES]) { LiskDAO::beginIsolateAllLiskEffectsToTransactions(); } }
protected function didRunOneTest($test) { $config = $this->getComputedConfiguration();
if ($config[self::PHABRICATOR_TESTCONFIG_BUILD_STORAGE_FIXTURES]) { LiskDAO::endIsolateAllLiskEffectsToTransactions(); } }
protected function newStorageFixture() { $bytes = Filesystem::readRandomCharacters(24); $name = self::NAMESPACE_PREFIX.$bytes;
return new PhabricatorStorageFixtureScopeGuard($name); }
/** * Returns an integer seed to use when building unique identifiers (e.g., * non-colliding usernames). The seed is unstable and its value will change * between test runs, so your tests must not rely on it. * * @return int A unique integer. */ protected function getNextObjectSeed() { self::$storageFixtureObjectSeed += mt_rand(1, 100); return self::$storageFixtureObjectSeed; }
protected function generateNewTestUser() { $seed = $this->getNextObjectSeed();
$user = id(new PhabricatorUser()) ->setRealName(pht('Test User %s', $seed)) ->setUserName("test{$seed}") ->setIsApproved(1);
$email = id(new PhabricatorUserEmail()) ->setAddress("testuser{$seed}@example.com") ->setIsVerified(1);
$editor = new PhabricatorUserEditor(); $editor->setActor($user); $editor->createNewUser($user, $email);
// When creating a new test user, we prefill their setting cache as empty. // This is a little more efficient than doing a query to load the empty // settings. $user->attachRawCacheData( array( PhabricatorUserPreferencesCacheType::KEY_PREFERENCES => '[]', ));
return $user; }
/** * Throws unless tests are currently executing. This method can be used to * guard code which is specific to unit tests and should not normally be * reachable. * * If tests aren't currently being executed, throws an exception. */ public static function assertExecutingUnitTests() { if (!self::$testsAreRunning) { throw new Exception( pht( 'Executing test code outside of test execution! '. 'This code path can only be run during unit tests.')); } }
protected function requireBinaryForTest($binary) { if (!Filesystem::binaryExists($binary)) { $this->assertSkipped( pht( 'No binary "%s" found on this system, skipping test.', $binary)); } }
protected function newContentSource() { return PhabricatorContentSource::newForSource( PhabricatorUnitTestContentSource::SOURCECONST); }
}