[ Index ] |
PHP Cross Reference of Phabricator |
[Summary view] [Print] [Text view]
1 <?php 2 3 abstract class PhabricatorTestCase extends ArcanistPhutilTestCase { 4 5 const NAMESPACE_PREFIX = 'phabricator_unittest_'; 6 7 /** 8 * If true, put Lisk in process-isolated mode for the duration of the tests so 9 * that it will establish only isolated, side-effect-free database 10 * connections. Defaults to true. 11 * 12 * NOTE: You should disable this only in rare circumstances. Unit tests should 13 * not rely on external resources like databases, and should not produce 14 * side effects. 15 */ 16 const PHABRICATOR_TESTCONFIG_ISOLATE_LISK = 'isolate-lisk'; 17 18 /** 19 * If true, build storage fixtures before running tests, and connect to them 20 * during test execution. This will impose a performance penalty on test 21 * execution (currently, it takes roughly one second to build the fixture) 22 * but allows you to perform tests which require data to be read from storage 23 * after writes. The fixture is shared across all test cases in this process. 24 * Defaults to false. 25 * 26 * NOTE: All connections to fixture storage open transactions when established 27 * and roll them back when tests complete. Each test must independently 28 * write data it relies on; data will not persist across tests. 29 * 30 * NOTE: Enabling this implies disabling process isolation. 31 */ 32 const PHABRICATOR_TESTCONFIG_BUILD_STORAGE_FIXTURES = 'storage-fixtures'; 33 34 private $configuration; 35 private $env; 36 37 private static $storageFixtureReferences = 0; 38 private static $storageFixture; 39 private static $storageFixtureObjectSeed = 0; 40 private static $testsAreRunning = 0; 41 42 protected function getPhabricatorTestCaseConfiguration() { 43 return array(); 44 } 45 46 private function getComputedConfiguration() { 47 $config = $this->getPhabricatorTestCaseConfiguration() + array( 48 self::PHABRICATOR_TESTCONFIG_ISOLATE_LISK => true, 49 self::PHABRICATOR_TESTCONFIG_BUILD_STORAGE_FIXTURES => false, 50 ); 51 52 if ($config[self::PHABRICATOR_TESTCONFIG_BUILD_STORAGE_FIXTURES]) { 53 // Fixtures don't make sense with process isolation. 54 $config[self::PHABRICATOR_TESTCONFIG_ISOLATE_LISK] = false; 55 } 56 57 return $config; 58 } 59 60 public function willRunTestCases(array $test_cases) { 61 $root = dirname(phutil_get_library_root('phabricator')); 62 require_once $root.'/scripts/__init_script__.php'; 63 64 $config = $this->getComputedConfiguration(); 65 66 if ($config[self::PHABRICATOR_TESTCONFIG_BUILD_STORAGE_FIXTURES]) { 67 ++self::$storageFixtureReferences; 68 if (!self::$storageFixture) { 69 self::$storageFixture = $this->newStorageFixture(); 70 } 71 } 72 73 ++self::$testsAreRunning; 74 } 75 76 public function didRunTestCases(array $test_cases) { 77 if (self::$storageFixture) { 78 self::$storageFixtureReferences--; 79 if (!self::$storageFixtureReferences) { 80 self::$storageFixture = null; 81 } 82 } 83 84 --self::$testsAreRunning; 85 } 86 87 protected function willRunTests() { 88 $config = $this->getComputedConfiguration(); 89 90 if ($config[self::PHABRICATOR_TESTCONFIG_ISOLATE_LISK]) { 91 LiskDAO::beginIsolateAllLiskEffectsToCurrentProcess(); 92 } 93 94 $this->env = PhabricatorEnv::beginScopedEnv(); 95 96 // NOTE: While running unit tests, we act as though all applications are 97 // installed, regardless of the install's configuration. Tests which need 98 // to uninstall applications are responsible for adjusting state themselves 99 // (such tests are exceedingly rare). 100 101 $this->env->overrideEnvConfig( 102 'phabricator.uninstalled-applications', 103 array()); 104 $this->env->overrideEnvConfig( 105 'phabricator.show-prototypes', 106 true); 107 108 // Reset application settings to defaults, particularly policies. 109 $this->env->overrideEnvConfig( 110 'phabricator.application-settings', 111 array()); 112 113 // We can't stub this service right now, and it's not generally useful 114 // to publish notifications about test execution. 115 $this->env->overrideEnvConfig( 116 'notification.enabled', 117 false); 118 119 $this->env->overrideEnvConfig( 120 'phabricator.base-uri', 121 'http://phabricator.example.com'); 122 } 123 124 protected function didRunTests() { 125 $config = $this->getComputedConfiguration(); 126 127 if ($config[self::PHABRICATOR_TESTCONFIG_ISOLATE_LISK]) { 128 LiskDAO::endIsolateAllLiskEffectsToCurrentProcess(); 129 } 130 131 try { 132 if (phutil_is_hiphop_runtime()) { 133 $this->env->__destruct(); 134 } 135 unset($this->env); 136 } catch (Exception $ex) { 137 throw new Exception( 138 'Some test called PhabricatorEnv::beginScopedEnv(), but is still '. 139 'holding a reference to the scoped environment!'); 140 } 141 } 142 143 protected function willRunOneTest($test) { 144 $config = $this->getComputedConfiguration(); 145 146 if ($config[self::PHABRICATOR_TESTCONFIG_BUILD_STORAGE_FIXTURES]) { 147 LiskDAO::beginIsolateAllLiskEffectsToTransactions(); 148 } 149 } 150 151 protected function didRunOneTest($test) { 152 $config = $this->getComputedConfiguration(); 153 154 if ($config[self::PHABRICATOR_TESTCONFIG_BUILD_STORAGE_FIXTURES]) { 155 LiskDAO::endIsolateAllLiskEffectsToTransactions(); 156 } 157 } 158 159 protected function newStorageFixture() { 160 $bytes = Filesystem::readRandomCharacters(24); 161 $name = self::NAMESPACE_PREFIX.$bytes; 162 163 return new PhabricatorStorageFixtureScopeGuard($name); 164 } 165 166 protected function getLink($method) { 167 $phabricator_project = 'PHID-APRJ-3f1fc779edeab89b2171'; 168 return 169 'https://secure.phabricator.com/diffusion/symbol/'.$method. 170 '/?lang=php&projects='.$phabricator_project. 171 '&jump=true&context='.get_class($this); 172 } 173 174 /** 175 * Returns an integer seed to use when building unique identifiers (e.g., 176 * non-colliding usernames). The seed is unstable and its value will change 177 * between test runs, so your tests must not rely on it. 178 * 179 * @return int A unique integer. 180 */ 181 protected function getNextObjectSeed() { 182 self::$storageFixtureObjectSeed += mt_rand(1, 100); 183 return self::$storageFixtureObjectSeed; 184 } 185 186 protected function generateNewTestUser() { 187 $seed = $this->getNextObjectSeed(); 188 189 $user = id(new PhabricatorUser()) 190 ->setRealName("Test User {$seed}}") 191 ->setUserName("test{$seed}") 192 ->setIsApproved(1); 193 194 $email = id(new PhabricatorUserEmail()) 195 ->setAddress("testuser{$seed}@example.com") 196 ->setIsVerified(1); 197 198 $editor = new PhabricatorUserEditor(); 199 $editor->setActor($user); 200 $editor->createNewUser($user, $email); 201 202 return $user; 203 } 204 205 206 /** 207 * Throws unless tests are currently executing. This method can be used to 208 * guard code which is specific to unit tests and should not normally be 209 * reachable. 210 * 211 * If tests aren't currently being executed, throws an exception. 212 */ 213 public static function assertExecutingUnitTests() { 214 if (!self::$testsAreRunning) { 215 throw new Exception( 216 'Executing test code outside of test execution! This code path can '. 217 'only be run during unit tests.'); 218 } 219 } 220 221 222 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Sun Nov 30 09:20:46 2014 | Cross-referenced by PHPXref 0.7.1 |