2011-04-30 10:11:41 -07:00
|
|
|
<?php
|
|
|
|
|
|
|
|
abstract class PhabricatorTestCase extends ArcanistPhutilTestCase {
|
|
|
|
|
2012-10-31 18:36:38 -07:00
|
|
|
const NAMESPACE_PREFIX = 'phabricator_unittest_';
|
2011-04-30 10:11:59 -07:00
|
|
|
|
|
|
|
/**
|
|
|
|
* 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.
|
|
|
|
*/
|
2012-05-02 12:42:23 -07:00
|
|
|
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';
|
2011-04-30 10:11:59 -07:00
|
|
|
|
|
|
|
private $configuration;
|
2012-04-17 07:52:01 -07:00
|
|
|
private $env;
|
2011-04-30 10:11:59 -07:00
|
|
|
|
2012-05-02 12:42:23 -07:00
|
|
|
private static $storageFixtureReferences = 0;
|
|
|
|
private static $storageFixture;
|
2012-10-22 16:25:00 -07:00
|
|
|
private static $storageFixtureObjectSeed = 0;
|
2013-10-03 19:05:47 -07:00
|
|
|
private static $testsAreRunning = 0;
|
2012-05-02 12:42:23 -07:00
|
|
|
|
2011-04-30 10:11:59 -07:00
|
|
|
protected function getPhabricatorTestCaseConfiguration() {
|
|
|
|
return array();
|
|
|
|
}
|
|
|
|
|
|
|
|
private function getComputedConfiguration() {
|
2012-05-02 12:42:23 -07:00
|
|
|
$config = $this->getPhabricatorTestCaseConfiguration() + array(
|
|
|
|
self::PHABRICATOR_TESTCONFIG_ISOLATE_LISK => true,
|
|
|
|
self::PHABRICATOR_TESTCONFIG_BUILD_STORAGE_FIXTURES => false,
|
2011-04-30 10:11:59 -07:00
|
|
|
);
|
2012-05-02 12:42:23 -07:00
|
|
|
|
|
|
|
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;
|
2011-04-30 10:11:59 -07:00
|
|
|
}
|
|
|
|
|
2013-03-06 13:53:48 -08:00
|
|
|
public function willRunTestCases(array $test_cases) {
|
2011-04-30 10:11:41 -07:00
|
|
|
$root = dirname(phutil_get_library_root('phabricator'));
|
2011-10-01 08:59:42 -07:00
|
|
|
require_once $root.'/scripts/__init_script__.php';
|
2011-04-30 10:11:59 -07:00
|
|
|
|
|
|
|
$config = $this->getComputedConfiguration();
|
|
|
|
|
2012-05-02 12:42:23 -07:00
|
|
|
if ($config[self::PHABRICATOR_TESTCONFIG_BUILD_STORAGE_FIXTURES]) {
|
|
|
|
++self::$storageFixtureReferences;
|
|
|
|
if (!self::$storageFixture) {
|
|
|
|
self::$storageFixture = $this->newStorageFixture();
|
|
|
|
}
|
|
|
|
}
|
2013-10-03 19:05:47 -07:00
|
|
|
|
|
|
|
++self::$testsAreRunning;
|
2013-03-06 13:53:48 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
public function didRunTestCases(array $test_cases) {
|
|
|
|
if (self::$storageFixture) {
|
|
|
|
self::$storageFixtureReferences--;
|
|
|
|
if (!self::$storageFixtureReferences) {
|
|
|
|
self::$storageFixture = null;
|
|
|
|
}
|
|
|
|
}
|
2013-10-03 19:05:47 -07:00
|
|
|
|
|
|
|
--self::$testsAreRunning;
|
2013-03-06 13:53:48 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
protected function willRunTests() {
|
|
|
|
$config = $this->getComputedConfiguration();
|
|
|
|
|
|
|
|
if ($config[self::PHABRICATOR_TESTCONFIG_ISOLATE_LISK]) {
|
|
|
|
LiskDAO::beginIsolateAllLiskEffectsToCurrentProcess();
|
|
|
|
}
|
2012-05-02 12:42:23 -07:00
|
|
|
|
2012-04-17 07:52:01 -07:00
|
|
|
$this->env = PhabricatorEnv::beginScopedEnv();
|
2013-05-16 12:25:26 -07:00
|
|
|
|
|
|
|
// NOTE: While running unit tests, we act as though all applications are
|
|
|
|
// installed, regardless of the install's configuration. Tests which need
|
|
|
|
// to uninstall applications are responsible for adjusting state themselves
|
|
|
|
// (such tests are exceedingly rare).
|
|
|
|
|
|
|
|
$this->env->overrideEnvConfig(
|
|
|
|
'phabricator.uninstalled-applications',
|
|
|
|
array());
|
2013-05-22 09:49:10 -07:00
|
|
|
$this->env->overrideEnvConfig(
|
2014-09-17 18:25:57 -07:00
|
|
|
'phabricator.show-prototypes',
|
2013-05-22 09:49:10 -07:00
|
|
|
true);
|
2013-05-20 10:13:53 -07:00
|
|
|
|
Improve handling of email verification and "activated" accounts
Summary:
Small step forward which improves existing stuff or lays groudwork for future stuff:
- Currently, to check for email verification, we have to single-query the email address on every page. Instead, denoramlize it into the user object.
- Migrate all the existing users.
- When the user verifies an email, mark them as `isEmailVerified` if the email is their primary email.
- Just make the checks look at the `isEmailVerified` field.
- Add a new check, `isUserActivated()`, to cover email-verified plus disabled. Currently, a non-verified-but-not-disabled user could theoretically use Conduit over SSH, if anyone deployed it. Tighten that up.
- Add an `isApproved` flag, which is always true for now. In a future diff, I want to add a default-on admin approval queue for new accounts, to prevent configuration mistakes. The way it will work is:
- When the queue is enabled, registering users are created with `isApproved = false`.
- Admins are sent an email, "[Phabricator] New User Approval (alincoln)", telling them that a new user is waiting for approval.
- They go to the web UI and approve the user.
- Manually-created accounts are auto-approved.
- The email will have instructions for disabling the queue.
I think this queue will be helpful for new installs and give them peace of mind, and when you go to disable it we have a better opportunity to warn you about exactly what that means.
Generally, I want to improve the default safety of registration, since if you just blindly coast through the path of least resistance right now your install ends up pretty open, and realistically few installs are on VPNs.
Test Plan:
- Ran migration, verified `isEmailVerified` populated correctly.
- Created a new user, checked DB for verified (not verified).
- Verified, checked DB (now verified).
- Used Conduit, People, Diffusion.
Reviewers: btrahan
Reviewed By: btrahan
CC: chad, aran
Differential Revision: https://secure.phabricator.com/D7572
2013-11-12 14:37:04 -08:00
|
|
|
// Reset application settings to defaults, particularly policies.
|
|
|
|
$this->env->overrideEnvConfig(
|
|
|
|
'phabricator.application-settings',
|
|
|
|
array());
|
|
|
|
|
2014-08-06 15:27:57 -07:00
|
|
|
// We can't stub this service right now, and it's not generally useful
|
|
|
|
// to publish notifications about test execution.
|
|
|
|
$this->env->overrideEnvConfig(
|
|
|
|
'notification.enabled',
|
|
|
|
false);
|
|
|
|
|
2014-08-18 14:11:06 -07:00
|
|
|
$this->env->overrideEnvConfig(
|
|
|
|
'phabricator.base-uri',
|
|
|
|
'http://phabricator.example.com');
|
2011-04-30 10:11:59 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
protected function didRunTests() {
|
|
|
|
$config = $this->getComputedConfiguration();
|
|
|
|
|
|
|
|
if ($config[self::PHABRICATOR_TESTCONFIG_ISOLATE_LISK]) {
|
|
|
|
LiskDAO::endIsolateAllLiskEffectsToCurrentProcess();
|
|
|
|
}
|
2012-04-17 07:52:01 -07:00
|
|
|
|
|
|
|
try {
|
2013-01-17 11:50:49 -08:00
|
|
|
if (phutil_is_hiphop_runtime()) {
|
|
|
|
$this->env->__destruct();
|
|
|
|
}
|
2012-04-17 07:52:01 -07:00
|
|
|
unset($this->env);
|
|
|
|
} catch (Exception $ex) {
|
|
|
|
throw new Exception(
|
2014-06-09 11:36:49 -07:00
|
|
|
'Some test called PhabricatorEnv::beginScopedEnv(), but is still '.
|
|
|
|
'holding a reference to the scoped environment!');
|
2012-04-17 07:52:01 -07:00
|
|
|
}
|
2011-04-30 10:11:41 -07:00
|
|
|
}
|
|
|
|
|
2012-05-02 12:42:23 -07:00
|
|
|
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);
|
2012-10-31 18:36:38 -07:00
|
|
|
$name = self::NAMESPACE_PREFIX.$bytes;
|
2012-05-02 12:42:23 -07:00
|
|
|
|
|
|
|
return new PhabricatorStorageFixtureScopeGuard($name);
|
|
|
|
}
|
|
|
|
|
2012-09-07 14:21:51 -07:00
|
|
|
protected function getLink($method) {
|
|
|
|
$phabricator_project = 'PHID-APRJ-3f1fc779edeab89b2171';
|
|
|
|
return
|
|
|
|
'https://secure.phabricator.com/diffusion/symbol/'.$method.
|
|
|
|
'/?lang=php&projects='.$phabricator_project.
|
|
|
|
'&jump=true&context='.get_class($this);
|
|
|
|
}
|
|
|
|
|
2012-10-22 16:25:00 -07:00
|
|
|
/**
|
|
|
|
* 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("Test User {$seed}}")
|
2013-11-13 11:24:56 -08:00
|
|
|
->setUserName("test{$seed}")
|
|
|
|
->setIsApproved(1);
|
2012-10-22 16:25:00 -07:00
|
|
|
|
|
|
|
$email = id(new PhabricatorUserEmail())
|
|
|
|
->setAddress("testuser{$seed}@example.com")
|
|
|
|
->setIsVerified(1);
|
|
|
|
|
|
|
|
$editor = new PhabricatorUserEditor();
|
|
|
|
$editor->setActor($user);
|
|
|
|
$editor->createNewUser($user, $email);
|
|
|
|
|
|
|
|
return $user;
|
|
|
|
}
|
|
|
|
|
2013-10-03 19:05:47 -07:00
|
|
|
|
|
|
|
/**
|
|
|
|
* 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(
|
2014-06-09 11:36:49 -07:00
|
|
|
'Executing test code outside of test execution! This code path can '.
|
|
|
|
'only be run during unit tests.');
|
2013-10-03 19:05:47 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-04-30 10:11:41 -07:00
|
|
|
}
|