diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php
index 751c4afcd2..912f746f88 100644
--- a/src/__phutil_library_map__.php
+++ b/src/__phutil_library_map__.php
@@ -568,6 +568,7 @@ phutil_register_library_map(array(
'PhabricatorTimelineIterator' => 'infrastructure/daemon/timeline/cursor/iterator',
'PhabricatorTimer' => 'applications/countdown/storage/timer',
'PhabricatorTransformedFile' => 'applications/files/storage/transformed',
+ 'PhabricatorTrivialTestCase' => 'infrastructure/testing/testcase/__tests__',
'PhabricatorTypeaheadCommonDatasourceController' => 'applications/typeahead/controller/common',
'PhabricatorTypeaheadDatasourceController' => 'applications/typeahead/controller/base',
'PhabricatorUIExample' => 'applications/uiexample/examples/base',
@@ -1096,6 +1097,7 @@ phutil_register_library_map(array(
'PhabricatorTimelineEventData' => 'PhabricatorTimelineDAO',
'PhabricatorTimer' => 'PhabricatorCountdownDAO',
'PhabricatorTransformedFile' => 'PhabricatorFileDAO',
+ 'PhabricatorTrivialTestCase' => 'PhabricatorTestCase',
'PhabricatorTypeaheadCommonDatasourceController' => 'PhabricatorTypeaheadDatasourceController',
'PhabricatorTypeaheadDatasourceController' => 'PhabricatorController',
'PhabricatorUIExampleController' => 'PhabricatorController',
diff --git a/src/docs/developer/unit_tests.diviner b/src/docs/developer/unit_tests.diviner
index b8b58732b4..bfcff05e73 100644
--- a/src/docs/developer/unit_tests.diviner
+++ b/src/docs/developer/unit_tests.diviner
@@ -31,4 +31,57 @@ Once you've added test classes, you can run them with:
- ##arc unit path/to/module/##, to explicitly run module tests.
- ##arc unit##, to run tests for all modules affected by changes in the
working copy.
- - ##arc diff## will also run ##arc unit## for you.
\ No newline at end of file
+ - ##arc diff## will also run ##arc unit## for you.
+
+= Example Test Case =
+
+Here's a simple example test:
+
+ lang=php
+ class PhabricatorTrivialTestCase extends PhabricatorTestCase {
+
+ private $two;
+
+ public function willRunOneTest($test_name) {
+ // You can execute setup steps which will run before each test in this
+ // method.
+ $this->two = 2;
+ }
+
+ public function testAllIsRightWithTheWorld() {
+ $this->assertEqual(4, 2 + 2, '2 + 2 = 4');
+ }
+
+ }
+
+You can see this class at @{class:PhabricatorTrivialTestCase} and run it with:
+
+ phabricator/ $ arc unit src/infrastructure/testing/testcase/
+ PASS <1ms* testAllIsRightWithTheWorld
+
+For more information on writing tests, see
+@{class@arcnaist:ArcanistPhutilTestCase} and @{class:PhabricatorTestCase}.
+
+= Database Isolation =
+
+By default, Phabricator isolates unit tests from the database. It makes a crude
+effort to simulate some side effects (principally, ID assignment on insert), but
+any queries which read data will fail to select any rows and throw an exception
+about isolation. In general, isolation is good, but this can make certain types
+of tests difficult to write. When you encounter issues, you can deal with them
+in a number of ways. From best to worst:
+
+ - Encounter no issues; your tests are fast and isolated.
+ - Add more simulated side effects if you encounter minor issues and simulation
+ is reasonable.
+ - Build a real database simulation layer (fairly complex).
+ - Disable isolation for a single test by using
+ ##LiskDAO::endIsolateAllLiskEffectsToCurrentProcess();## before your test
+ and ##LiskDAO::beginIsolateAllLiskEffectsToCurrentProcess();## after your
+ test. This will disable isolation for one test. NOT RECOMMENDED.
+ - Disable isolation for your entire test case by overriding
+ ##getPhabricatorTestCaseConfiguration()## and providing
+ ##self::PHABRICATOR_TESTCONFIG_ISOLATE_LISK => false## in the configuration
+ dictionary you return. This will disable isolation entirely. STRONGLY NOT
+ RECOMMENDED.
+
diff --git a/src/docs/userguide/remarkup.diviner b/src/docs/userguide/remarkup.diviner
index 4bb3ab6b79..d66f3159a7 100644
--- a/src/docs/userguide/remarkup.diviner
+++ b/src/docs/userguide/remarkup.diviner
@@ -34,7 +34,7 @@ This produces headers like the ones in this document.
Make **lists** by indenting two spaces and beginning each item with a "-":
- lang=demo
+ lang=text
- milk
- eggs
- bread
@@ -51,7 +51,7 @@ Make **code blocks** by indenting two spaces:
You can specify a language for syntax highlighting with "lang=xxx":
- lang=demo
+ lang=text
lang=html
...
@@ -64,7 +64,7 @@ available (in most cases, this means you need to configure Pygments):
You can also use a "COUNTEREXAMPLE" header to show that a block of code is
bad and shouldn't be copied:
- lang=demo
+ lang=text
COUNTEREXAMPLE
function f() {
global $$variable_variable;
diff --git a/src/infrastructure/testing/testcase/__tests__/PhabricatorTrivialTestCase.php b/src/infrastructure/testing/testcase/__tests__/PhabricatorTrivialTestCase.php
new file mode 100644
index 0000000000..b8943907db
--- /dev/null
+++ b/src/infrastructure/testing/testcase/__tests__/PhabricatorTrivialTestCase.php
@@ -0,0 +1,38 @@
+two = 2;
+ }
+
+ public function testAllIsRightWithTheWorld() {
+ $this->assertEqual(4, $this->two + $this->two, '2 + 2 = 4');
+ }
+
+}
diff --git a/src/infrastructure/testing/testcase/__tests__/__init__.php b/src/infrastructure/testing/testcase/__tests__/__init__.php
new file mode 100644
index 0000000000..1dc5f4c568
--- /dev/null
+++ b/src/infrastructure/testing/testcase/__tests__/__init__.php
@@ -0,0 +1,12 @@
+K]*" allows any number of (properly escaped) comments to
+ // appear prior to the INSERT/UPDATE, since this connection escapes them
+ // as "" (above).
+ if (!preg_match('/^[\s<>K]*(INSERT|UPDATE)\s*/i', $raw_query)) {
+ $doc_uri = PhabricatorEnv::getDoclink('article/Writing_Unit_Tests.html');
+ throw new Exception(
+ "Database isolation currently only supports INSERT and UPDATE ".
+ "queries. For more information, see <{$doc_uri}>. You are trying to ".
+ "issue a query which does not begin with INSERT or UPDATE: ".
+ "'".$raw_query."'");
+ }
+
// NOTE: This method is intentionally simplified for now, since we're only
// using it to stub out inserts/updates. In the future it will probably need
// to grow more powerful.
diff --git a/src/storage/connection/isolated/__init__.php b/src/storage/connection/isolated/__init__.php
index 6135420a1e..5ecdcccc94 100644
--- a/src/storage/connection/isolated/__init__.php
+++ b/src/storage/connection/isolated/__init__.php
@@ -6,6 +6,7 @@
+phutil_require_module('phabricator', 'infrastructure/env');
phutil_require_module('phabricator', 'storage/connection/base');
phutil_require_module('phutil', 'utils');