TestBase.php 49 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419
  1. <?php
  2. namespace Drupal\simpletest;
  3. use Drupal\Component\Assertion\Handle;
  4. use Drupal\Component\Render\FormattableMarkup;
  5. use Drupal\Component\Render\MarkupInterface;
  6. use Drupal\Component\Utility\Crypt;
  7. use Drupal\Component\Utility\Environment;
  8. use Drupal\Core\Database\Database;
  9. use Drupal\Core\File\FileSystemInterface;
  10. use Drupal\Core\Site\Settings;
  11. use Drupal\Core\StreamWrapper\PublicStream;
  12. use Drupal\Core\Test\TestDatabase;
  13. use Drupal\Core\Test\TestDiscovery;
  14. use Drupal\Core\Test\TestSetupTrait;
  15. use Drupal\Core\Utility\Error;
  16. use Drupal\Tests\AssertHelperTrait as BaseAssertHelperTrait;
  17. use Drupal\Tests\ConfigTestTrait;
  18. use Drupal\Tests\RandomGeneratorTrait;
  19. use Drupal\Tests\Traits\Core\GeneratePermutationsTrait;
  20. /**
  21. * Base class for Drupal tests.
  22. *
  23. * Do not extend this class directly; use \Drupal\simpletest\WebTestBase.
  24. *
  25. * @deprecated in drupal:8.8.0 and is removed from drupal:9.0.0. Instead,
  26. * use one of the phpunit base test classes like
  27. * Drupal\Tests\BrowserTestBase. See https://www.drupal.org/node/3030340.
  28. */
  29. abstract class TestBase {
  30. use BaseAssertHelperTrait;
  31. use TestSetupTrait;
  32. use RandomGeneratorTrait;
  33. use GeneratePermutationsTrait;
  34. // For backwards compatibility switch the visibility of the methods to public.
  35. use ConfigTestTrait {
  36. configImporter as public;
  37. copyConfig as public;
  38. }
  39. /**
  40. * The database prefix of this test run.
  41. *
  42. * @var string
  43. */
  44. protected $databasePrefix = NULL;
  45. /**
  46. * Time limit for the test.
  47. *
  48. * @var int
  49. */
  50. protected $timeLimit = 500;
  51. /**
  52. * Current results of this test case.
  53. *
  54. * @var array
  55. */
  56. public $results = [
  57. '#pass' => 0,
  58. '#fail' => 0,
  59. '#exception' => 0,
  60. '#debug' => 0,
  61. ];
  62. /**
  63. * Assertions thrown in that test case.
  64. *
  65. * @var array
  66. */
  67. protected $assertions = [];
  68. /**
  69. * This class is skipped when looking for the source of an assertion.
  70. *
  71. * When displaying which function an assert comes from, it's not too useful
  72. * to see "WebTestBase->drupalLogin()', we would like to see the test
  73. * that called it. So we need to skip the classes defining these helper
  74. * methods.
  75. */
  76. protected $skipClasses = [__CLASS__ => TRUE];
  77. /**
  78. * TRUE if verbose debugging is enabled.
  79. *
  80. * @var bool
  81. */
  82. public $verbose;
  83. /**
  84. * Incrementing identifier for verbose output filenames.
  85. *
  86. * @var int
  87. */
  88. protected $verboseId = 0;
  89. /**
  90. * Safe class name for use in verbose output filenames.
  91. *
  92. * Namespaces separator (\) replaced with _.
  93. *
  94. * @var string
  95. */
  96. protected $verboseClassName;
  97. /**
  98. * Directory where verbose output files are put.
  99. *
  100. * @var string
  101. */
  102. protected $verboseDirectory;
  103. /**
  104. * URL to the verbose output file directory.
  105. *
  106. * @var string
  107. */
  108. protected $verboseDirectoryUrl;
  109. /**
  110. * The original configuration (variables), if available.
  111. *
  112. * @var string
  113. * @todo Remove all remnants of $GLOBALS['conf'].
  114. * @see https://www.drupal.org/node/2183323
  115. */
  116. protected $originalConf;
  117. /**
  118. * The original configuration (variables).
  119. *
  120. * @var string
  121. */
  122. protected $originalConfig;
  123. /**
  124. * The original configuration directories.
  125. *
  126. * An array of paths keyed by the CONFIG_*_DIRECTORY constants defined by
  127. * core/includes/bootstrap.inc.
  128. *
  129. * @var array
  130. */
  131. protected $originalConfigDirectories;
  132. /**
  133. * The original container.
  134. *
  135. * @var \Symfony\Component\DependencyInjection\ContainerInterface
  136. */
  137. protected $originalContainer;
  138. /**
  139. * The original file directory, before it was changed for testing purposes.
  140. *
  141. * @var string
  142. */
  143. protected $originalFileDirectory = NULL;
  144. /**
  145. * The original language.
  146. *
  147. * @var \Drupal\Core\Language\LanguageInterface
  148. */
  149. protected $originalLanguage;
  150. /**
  151. * The original database prefix when running inside Simpletest.
  152. *
  153. * @var string
  154. */
  155. protected $originalPrefix;
  156. /**
  157. * The name of the session cookie of the test-runner.
  158. *
  159. * @var string
  160. */
  161. protected $originalSessionName;
  162. /**
  163. * The settings array.
  164. *
  165. * @var array
  166. */
  167. protected $originalSettings;
  168. /**
  169. * The original array of shutdown function callbacks.
  170. *
  171. * @var array
  172. */
  173. protected $originalShutdownCallbacks;
  174. /**
  175. * The original user, before testing began.
  176. *
  177. * @var \Drupal\Core\Session\AccountProxyInterface
  178. */
  179. protected $originalUser;
  180. /**
  181. * The translation file directory for the test environment.
  182. *
  183. * This is set in TestBase::prepareEnvironment().
  184. *
  185. * @var string
  186. */
  187. protected $translationFilesDirectory;
  188. /**
  189. * Whether to die in case any test assertion fails.
  190. *
  191. * @var bool
  192. *
  193. * @see run-tests.sh
  194. */
  195. public $dieOnFail = FALSE;
  196. /**
  197. * The config importer that can used in a test.
  198. *
  199. * @var \Drupal\Core\Config\ConfigImporter
  200. */
  201. protected $configImporter;
  202. /**
  203. * HTTP authentication method (specified as a CURLAUTH_* constant).
  204. *
  205. * @var int
  206. * @see http://php.net/manual/function.curl-setopt.php
  207. */
  208. protected $httpAuthMethod = CURLAUTH_BASIC;
  209. /**
  210. * HTTP authentication credentials (<username>:<password>).
  211. *
  212. * @var string
  213. */
  214. protected $httpAuthCredentials = NULL;
  215. /**
  216. * Constructor for Test.
  217. *
  218. * @param $test_id
  219. * Tests with the same id are reported together.
  220. */
  221. public function __construct($test_id = NULL) {
  222. $this->testId = $test_id;
  223. }
  224. /**
  225. * Fail the test if it belongs to a PHPUnit-based framework.
  226. *
  227. * This would probably be caused by automated test conversions such as those
  228. * in https://www.drupal.org/project/drupal/issues/2770921.
  229. */
  230. public function checkTestHierarchyMismatch() {
  231. // We can use getPhpunitTestSuite() because it uses a regex on the class'
  232. // namespace to deduce the PHPUnit test suite.
  233. if (TestDiscovery::getPhpunitTestSuite(get_class($this)) !== FALSE) {
  234. $this->fail(get_class($this) . ' incorrectly subclasses ' . __CLASS__ . ', it should probably extend \Drupal\Tests\BrowserTestBase instead.');
  235. }
  236. }
  237. /**
  238. * Performs setup tasks before each individual test method is run.
  239. */
  240. abstract protected function setUp();
  241. /**
  242. * Checks the matching requirements for Test.
  243. *
  244. * @return
  245. * Array of errors containing a list of unmet requirements.
  246. */
  247. protected function checkRequirements() {
  248. return [];
  249. }
  250. /**
  251. * Helper method to store an assertion record in the configured database.
  252. *
  253. * This method decouples database access from assertion logic.
  254. *
  255. * @param array $assertion
  256. * Keyed array representing an assertion, as generated by assert().
  257. *
  258. * @see self::assert()
  259. *
  260. * @return \Drupal\Core\Database\StatementInterface|int|null
  261. * The message ID.
  262. */
  263. protected function storeAssertion(array $assertion) {
  264. return self::getDatabaseConnection()
  265. ->insert('simpletest', ['return' => Database::RETURN_INSERT_ID])
  266. ->fields($assertion)
  267. ->execute();
  268. }
  269. /**
  270. * Internal helper: stores the assert.
  271. *
  272. * @param $status
  273. * Can be 'pass', 'fail', 'exception', 'debug'.
  274. * TRUE is a synonym for 'pass', FALSE for 'fail'.
  275. * @param string|\Drupal\Component\Render\MarkupInterface $message
  276. * (optional) A message to display with the assertion. Do not translate
  277. * messages: use \Drupal\Component\Render\FormattableMarkup to embed
  278. * variables in the message text, not t(). If left blank, a default message
  279. * will be displayed.
  280. * @param $group
  281. * (optional) The group this message is in, which is displayed in a column
  282. * in test output. Use 'Debug' to indicate this is debugging output. Do not
  283. * translate this string. Defaults to 'Other'; most tests do not override
  284. * this default.
  285. * @param $caller
  286. * By default, the assert comes from a function whose name starts with
  287. * 'test'. Instead, you can specify where this assert originates from
  288. * by passing in an associative array as $caller. Key 'file' is
  289. * the name of the source file, 'line' is the line number and 'function'
  290. * is the caller function itself.
  291. */
  292. protected function assert($status, $message = '', $group = 'Other', array $caller = NULL) {
  293. if ($message instanceof MarkupInterface) {
  294. $message = (string) $message;
  295. }
  296. // Convert boolean status to string status.
  297. if (is_bool($status)) {
  298. $status = $status ? 'pass' : 'fail';
  299. }
  300. // Increment summary result counter.
  301. $this->results['#' . $status]++;
  302. // Get the function information about the call to the assertion method.
  303. if (!$caller) {
  304. $caller = $this->getAssertionCall();
  305. }
  306. // Creation assertion array that can be displayed while tests are running.
  307. $assertion = [
  308. 'test_id' => $this->testId,
  309. 'test_class' => get_class($this),
  310. 'status' => $status,
  311. 'message' => $message,
  312. 'message_group' => $group,
  313. 'function' => $caller['function'],
  314. 'line' => $caller['line'],
  315. 'file' => $caller['file'],
  316. ];
  317. // Store assertion for display after the test has completed.
  318. $message_id = $this->storeAssertion($assertion);
  319. $assertion['message_id'] = $message_id;
  320. $this->assertions[] = $assertion;
  321. // We do not use a ternary operator here to allow a breakpoint on
  322. // test failure.
  323. if ($status == 'pass') {
  324. return TRUE;
  325. }
  326. else {
  327. if ($this->dieOnFail && ($status == 'fail' || $status == 'exception')) {
  328. exit(1);
  329. }
  330. return FALSE;
  331. }
  332. }
  333. /**
  334. * Store an assertion from outside the testing context.
  335. *
  336. * This is useful for inserting assertions that can only be recorded after
  337. * the test case has been destroyed, such as PHP fatal errors. The caller
  338. * information is not automatically gathered since the caller is most likely
  339. * inserting the assertion on behalf of other code. In all other respects
  340. * the method behaves just like \Drupal\simpletest\TestBase::assert() in terms
  341. * of storing the assertion.
  342. *
  343. * @return
  344. * Message ID of the stored assertion.
  345. *
  346. * @deprecated in drupal:8.8.0 and is removed from drupal:9.0.0. Use
  347. * simpletest_insert_assert() instead.
  348. *
  349. * @see https://www.drupal.org/node/3030340
  350. * @see \Drupal\simpletest\TestBase::assert()
  351. * @see \Drupal\simpletest\TestBase::deleteAssert()
  352. */
  353. public static function insertAssert($test_id, $test_class, $status, $message = '', $group = 'Other', array $caller = []) {
  354. // Convert boolean status to string status.
  355. if (is_bool($status)) {
  356. $status = $status ? 'pass' : 'fail';
  357. }
  358. $caller += [
  359. 'function' => 'Unknown',
  360. 'line' => 0,
  361. 'file' => 'Unknown',
  362. ];
  363. $assertion = [
  364. 'test_id' => $test_id,
  365. 'test_class' => $test_class,
  366. 'status' => $status,
  367. 'message' => $message,
  368. 'message_group' => $group,
  369. 'function' => $caller['function'],
  370. 'line' => $caller['line'],
  371. 'file' => $caller['file'],
  372. ];
  373. // We can't use storeAssertion() because this method is static.
  374. return self::getDatabaseConnection()
  375. ->insert('simpletest')
  376. ->fields($assertion)
  377. ->execute();
  378. }
  379. /**
  380. * Delete an assertion record by message ID.
  381. *
  382. * @param $message_id
  383. * Message ID of the assertion to delete.
  384. *
  385. * @return
  386. * TRUE if the assertion was deleted, FALSE otherwise.
  387. *
  388. * @see \Drupal\simpletest\TestBase::insertAssert()
  389. */
  390. public static function deleteAssert($message_id) {
  391. // We can't use storeAssertion() because this method is static.
  392. return (bool) self::getDatabaseConnection()
  393. ->delete('simpletest')
  394. ->condition('message_id', $message_id)
  395. ->execute();
  396. }
  397. /**
  398. * Cycles through backtrace until the first non-assertion method is found.
  399. *
  400. * @return
  401. * Array representing the true caller.
  402. */
  403. protected function getAssertionCall() {
  404. $backtrace = debug_backtrace();
  405. // The first element is the call. The second element is the caller.
  406. // We skip calls that occurred in one of the methods of our base classes
  407. // or in an assertion function.
  408. while (($caller = $backtrace[1]) &&
  409. ((isset($caller['class']) && isset($this->skipClasses[$caller['class']])) ||
  410. substr($caller['function'], 0, 6) == 'assert')) {
  411. // We remove that call.
  412. array_shift($backtrace);
  413. }
  414. return Error::getLastCaller($backtrace);
  415. }
  416. /**
  417. * Check to see if a value is not false.
  418. *
  419. * False values are: empty string, 0, NULL, and FALSE.
  420. *
  421. * @param $value
  422. * The value on which the assertion is to be done.
  423. * @param $message
  424. * (optional) A message to display with the assertion. Do not translate
  425. * messages: use \Drupal\Component\Render\FormattableMarkup to embed
  426. * variables in the message text, not t(). If left blank, a default message
  427. * will be displayed.
  428. * @param $group
  429. * (optional) The group this message is in, which is displayed in a column
  430. * in test output. Use 'Debug' to indicate this is debugging output. Do not
  431. * translate this string. Defaults to 'Other'; most tests do not override
  432. * this default.
  433. *
  434. * @return
  435. * TRUE if the assertion succeeded, FALSE otherwise.
  436. */
  437. protected function assertTrue($value, $message = '', $group = 'Other') {
  438. return $this->assert((bool) $value, $message ? $message : new FormattableMarkup('Value @value is TRUE.', ['@value' => var_export($value, TRUE)]), $group);
  439. }
  440. /**
  441. * Check to see if a value is false.
  442. *
  443. * False values are: empty string, 0, NULL, and FALSE.
  444. *
  445. * @param $value
  446. * The value on which the assertion is to be done.
  447. * @param $message
  448. * (optional) A message to display with the assertion. Do not translate
  449. * messages: use \Drupal\Component\Render\FormattableMarkup to embed
  450. * variables in the message text, not t(). If left blank, a default message
  451. * will be displayed.
  452. * @param $group
  453. * (optional) The group this message is in, which is displayed in a column
  454. * in test output. Use 'Debug' to indicate this is debugging output. Do not
  455. * translate this string. Defaults to 'Other'; most tests do not override
  456. * this default.
  457. *
  458. * @return
  459. * TRUE if the assertion succeeded, FALSE otherwise.
  460. */
  461. protected function assertFalse($value, $message = '', $group = 'Other') {
  462. return $this->assert(!$value, $message ? $message : new FormattableMarkup('Value @value is FALSE.', ['@value' => var_export($value, TRUE)]), $group);
  463. }
  464. /**
  465. * Check to see if a value is NULL.
  466. *
  467. * @param $value
  468. * The value on which the assertion is to be done.
  469. * @param $message
  470. * (optional) A message to display with the assertion. Do not translate
  471. * messages: use \Drupal\Component\Render\FormattableMarkup to embed
  472. * variables in the message text, not t(). If left blank, a default message
  473. * will be displayed.
  474. * @param $group
  475. * (optional) The group this message is in, which is displayed in a column
  476. * in test output. Use 'Debug' to indicate this is debugging output. Do not
  477. * translate this string. Defaults to 'Other'; most tests do not override
  478. * this default.
  479. *
  480. * @return
  481. * TRUE if the assertion succeeded, FALSE otherwise.
  482. */
  483. protected function assertNull($value, $message = '', $group = 'Other') {
  484. return $this->assert(!isset($value), $message ? $message : new FormattableMarkup('Value @value is NULL.', ['@value' => var_export($value, TRUE)]), $group);
  485. }
  486. /**
  487. * Check to see if a value is not NULL.
  488. *
  489. * @param $value
  490. * The value on which the assertion is to be done.
  491. * @param $message
  492. * (optional) A message to display with the assertion. Do not translate
  493. * messages: use \Drupal\Component\Render\FormattableMarkup to embed
  494. * variables in the message text, not t(). If left blank, a default message
  495. * will be displayed.
  496. * @param $group
  497. * (optional) The group this message is in, which is displayed in a column
  498. * in test output. Use 'Debug' to indicate this is debugging output. Do not
  499. * translate this string. Defaults to 'Other'; most tests do not override
  500. * this default.
  501. *
  502. * @return
  503. * TRUE if the assertion succeeded, FALSE otherwise.
  504. */
  505. protected function assertNotNull($value, $message = '', $group = 'Other') {
  506. return $this->assert(isset($value), $message ? $message : new FormattableMarkup('Value @value is not NULL.', ['@value' => var_export($value, TRUE)]), $group);
  507. }
  508. /**
  509. * Check to see if two values are equal.
  510. *
  511. * @param $first
  512. * The first value to check.
  513. * @param $second
  514. * The second value to check.
  515. * @param $message
  516. * (optional) A message to display with the assertion. Do not translate
  517. * messages: use \Drupal\Component\Render\FormattableMarkup to embed
  518. * variables in the message text, not t(). If left blank, a default message
  519. * will be displayed.
  520. * @param $group
  521. * (optional) The group this message is in, which is displayed in a column
  522. * in test output. Use 'Debug' to indicate this is debugging output. Do not
  523. * translate this string. Defaults to 'Other'; most tests do not override
  524. * this default.
  525. *
  526. * @return
  527. * TRUE if the assertion succeeded, FALSE otherwise.
  528. */
  529. protected function assertEqual($first, $second, $message = '', $group = 'Other') {
  530. // Cast objects implementing MarkupInterface to string instead of
  531. // relying on PHP casting them to string depending on what they are being
  532. // comparing with.
  533. $first = $this->castSafeStrings($first);
  534. $second = $this->castSafeStrings($second);
  535. $is_equal = $first == $second;
  536. if (!$is_equal || !$message) {
  537. $default_message = new FormattableMarkup('Value @first is equal to value @second.', ['@first' => var_export($first, TRUE), '@second' => var_export($second, TRUE)]);
  538. $message = $message ? $message . PHP_EOL . $default_message : $default_message;
  539. }
  540. return $this->assert($is_equal, $message, $group);
  541. }
  542. /**
  543. * Check to see if two values are not equal.
  544. *
  545. * @param $first
  546. * The first value to check.
  547. * @param $second
  548. * The second value to check.
  549. * @param $message
  550. * (optional) A message to display with the assertion. Do not translate
  551. * messages: use \Drupal\Component\Render\FormattableMarkup to embed
  552. * variables in the message text, not t(). If left blank, a default message
  553. * will be displayed.
  554. * @param $group
  555. * (optional) The group this message is in, which is displayed in a column
  556. * in test output. Use 'Debug' to indicate this is debugging output. Do not
  557. * translate this string. Defaults to 'Other'; most tests do not override
  558. * this default.
  559. *
  560. * @return
  561. * TRUE if the assertion succeeded, FALSE otherwise.
  562. */
  563. protected function assertNotEqual($first, $second, $message = '', $group = 'Other') {
  564. // Cast objects implementing MarkupInterface to string instead of
  565. // relying on PHP casting them to string depending on what they are being
  566. // comparing with.
  567. $first = $this->castSafeStrings($first);
  568. $second = $this->castSafeStrings($second);
  569. $not_equal = $first != $second;
  570. if (!$not_equal || !$message) {
  571. $default_message = new FormattableMarkup('Value @first is not equal to value @second.', ['@first' => var_export($first, TRUE), '@second' => var_export($second, TRUE)]);
  572. $message = $message ? $message . PHP_EOL . $default_message : $default_message;
  573. }
  574. return $this->assert($not_equal, $message, $group);
  575. }
  576. /**
  577. * Check to see if two values are identical.
  578. *
  579. * @param $first
  580. * The first value to check.
  581. * @param $second
  582. * The second value to check.
  583. * @param $message
  584. * (optional) A message to display with the assertion. Do not translate
  585. * messages: use \Drupal\Component\Render\FormattableMarkup to embed
  586. * variables in the message text, not t(). If left blank, a default message
  587. * will be displayed.
  588. * @param $group
  589. * (optional) The group this message is in, which is displayed in a column
  590. * in test output. Use 'Debug' to indicate this is debugging output. Do not
  591. * translate this string. Defaults to 'Other'; most tests do not override
  592. * this default.
  593. *
  594. * @return
  595. * TRUE if the assertion succeeded, FALSE otherwise.
  596. */
  597. protected function assertIdentical($first, $second, $message = '', $group = 'Other') {
  598. $is_identical = $first === $second;
  599. if (!$is_identical || !$message) {
  600. $default_message = new FormattableMarkup('Value @first is identical to value @second.', ['@first' => var_export($first, TRUE), '@second' => var_export($second, TRUE)]);
  601. $message = $message ? $message . PHP_EOL . $default_message : $default_message;
  602. }
  603. return $this->assert($is_identical, $message, $group);
  604. }
  605. /**
  606. * Check to see if two values are not identical.
  607. *
  608. * @param $first
  609. * The first value to check.
  610. * @param $second
  611. * The second value to check.
  612. * @param $message
  613. * (optional) A message to display with the assertion. Do not translate
  614. * messages: use \Drupal\Component\Render\FormattableMarkup to embed
  615. * variables in the message text, not t(). If left blank, a default message
  616. * will be displayed.
  617. * @param $group
  618. * (optional) The group this message is in, which is displayed in a column
  619. * in test output. Use 'Debug' to indicate this is debugging output. Do not
  620. * translate this string. Defaults to 'Other'; most tests do not override
  621. * this default.
  622. *
  623. * @return
  624. * TRUE if the assertion succeeded, FALSE otherwise.
  625. */
  626. protected function assertNotIdentical($first, $second, $message = '', $group = 'Other') {
  627. $not_identical = $first !== $second;
  628. if (!$not_identical || !$message) {
  629. $default_message = new FormattableMarkup('Value @first is not identical to value @second.', ['@first' => var_export($first, TRUE), '@second' => var_export($second, TRUE)]);
  630. $message = $message ? $message . PHP_EOL . $default_message : $default_message;
  631. }
  632. return $this->assert($not_identical, $message, $group);
  633. }
  634. /**
  635. * Checks to see if two objects are identical.
  636. *
  637. * @param object $object1
  638. * The first object to check.
  639. * @param object $object2
  640. * The second object to check.
  641. * @param $message
  642. * (optional) A message to display with the assertion. Do not translate
  643. * messages: use \Drupal\Component\Render\FormattableMarkup to embed
  644. * variables in the message text, not t(). If left blank, a default message
  645. * will be displayed.
  646. * @param $group
  647. * (optional) The group this message is in, which is displayed in a column
  648. * in test output. Use 'Debug' to indicate this is debugging output. Do not
  649. * translate this string. Defaults to 'Other'; most tests do not override
  650. * this default.
  651. *
  652. * @return
  653. * TRUE if the assertion succeeded, FALSE otherwise.
  654. */
  655. protected function assertIdenticalObject($object1, $object2, $message = '', $group = 'Other') {
  656. $message = $message ?: new FormattableMarkup('@object1 is identical to @object2', [
  657. '@object1' => var_export($object1, TRUE),
  658. '@object2' => var_export($object2, TRUE),
  659. ]);
  660. $identical = TRUE;
  661. foreach ($object1 as $key => $value) {
  662. $identical = $identical && isset($object2->$key) && $object2->$key === $value;
  663. }
  664. return $this->assertTrue($identical, $message, $group);
  665. }
  666. /**
  667. * Asserts that no errors have been logged to the PHP error.log thus far.
  668. *
  669. * @return bool
  670. * TRUE if the assertion succeeded, FALSE otherwise.
  671. *
  672. * @see \Drupal\simpletest\TestBase::prepareEnvironment()
  673. * @see \Drupal\Core\DrupalKernel::bootConfiguration()
  674. */
  675. protected function assertNoErrorsLogged() {
  676. // Since PHP only creates the error.log file when an actual error is
  677. // triggered, it is sufficient to check whether the file exists.
  678. return $this->assertFalse(file_exists(DRUPAL_ROOT . '/' . $this->siteDirectory . '/error.log'), 'PHP error.log is empty.');
  679. }
  680. /**
  681. * Asserts that a specific error has been logged to the PHP error log.
  682. *
  683. * @param string $error_message
  684. * The expected error message.
  685. *
  686. * @return bool
  687. * TRUE if the assertion succeeded, FALSE otherwise.
  688. *
  689. * @see \Drupal\simpletest\TestBase::prepareEnvironment()
  690. * @see \Drupal\Core\DrupalKernel::bootConfiguration()
  691. */
  692. protected function assertErrorLogged($error_message) {
  693. $error_log_filename = DRUPAL_ROOT . '/' . $this->siteDirectory . '/error.log';
  694. if (!file_exists($error_log_filename)) {
  695. $this->error('No error logged yet.');
  696. }
  697. $content = file_get_contents($error_log_filename);
  698. $rows = explode(PHP_EOL, $content);
  699. // We iterate over the rows in order to be able to remove the logged error
  700. // afterwards.
  701. $found = FALSE;
  702. foreach ($rows as $row_index => $row) {
  703. if (strpos($content, $error_message) !== FALSE) {
  704. $found = TRUE;
  705. unset($rows[$row_index]);
  706. }
  707. }
  708. file_put_contents($error_log_filename, implode("\n", $rows));
  709. return $this->assertTrue($found, sprintf('The %s error message was logged.', $error_message));
  710. }
  711. /**
  712. * Fire an assertion that is always positive.
  713. *
  714. * @param $message
  715. * (optional) A message to display with the assertion. Do not translate
  716. * messages: use \Drupal\Component\Render\FormattableMarkup to embed
  717. * variables in the message text, not t(). If left blank, a default message
  718. * will be displayed.
  719. * @param $group
  720. * (optional) The group this message is in, which is displayed in a column
  721. * in test output. Use 'Debug' to indicate this is debugging output. Do not
  722. * translate this string. Defaults to 'Other'; most tests do not override
  723. * this default.
  724. *
  725. * @return
  726. * TRUE.
  727. */
  728. protected function pass($message = NULL, $group = 'Other') {
  729. return $this->assert(TRUE, $message, $group);
  730. }
  731. /**
  732. * Fire an assertion that is always negative.
  733. *
  734. * @param $message
  735. * (optional) A message to display with the assertion. Do not translate
  736. * messages: use \Drupal\Component\Render\FormattableMarkup to embed
  737. * variables in the message text, not t(). If left blank, a default message
  738. * will be displayed.
  739. * @param $group
  740. * (optional) The group this message is in, which is displayed in a column
  741. * in test output. Use 'Debug' to indicate this is debugging output. Do not
  742. * translate this string. Defaults to 'Other'; most tests do not override
  743. * this default.
  744. *
  745. * @return
  746. * FALSE.
  747. */
  748. protected function fail($message = NULL, $group = 'Other') {
  749. return $this->assert(FALSE, $message, $group);
  750. }
  751. /**
  752. * Fire an error assertion.
  753. *
  754. * @param $message
  755. * (optional) A message to display with the assertion. Do not translate
  756. * messages: use \Drupal\Component\Render\FormattableMarkup to embed
  757. * variables in the message text, not t(). If left blank, a default message
  758. * will be displayed.
  759. * @param $group
  760. * (optional) The group this message is in, which is displayed in a column
  761. * in test output. Use 'Debug' to indicate this is debugging output. Do not
  762. * translate this string. Defaults to 'Other'; most tests do not override
  763. * this default.
  764. * @param $caller
  765. * The caller of the error.
  766. *
  767. * @return
  768. * FALSE.
  769. */
  770. protected function error($message = '', $group = 'Other', array $caller = NULL) {
  771. if ($group == 'User notice') {
  772. // Since 'User notice' is set by trigger_error() which is used for debug
  773. // set the message to a status of 'debug'.
  774. return $this->assert('debug', $message, 'Debug', $caller);
  775. }
  776. return $this->assert('exception', $message, $group, $caller);
  777. }
  778. /**
  779. * Logs a verbose message in a text file.
  780. *
  781. * The link to the verbose message will be placed in the test results as a
  782. * passing assertion with the text '[verbose message]'.
  783. *
  784. * @param $message
  785. * The verbose message to be stored.
  786. *
  787. * @see simpletest_verbose()
  788. */
  789. protected function verbose($message) {
  790. // Do nothing if verbose debugging is disabled.
  791. if (!$this->verbose) {
  792. return;
  793. }
  794. $message = '<hr />ID #' . $this->verboseId . ' (<a href="' . $this->verboseClassName . '-' . ($this->verboseId - 1) . '-' . $this->testId . '.html">Previous</a> | <a href="' . $this->verboseClassName . '-' . ($this->verboseId + 1) . '-' . $this->testId . '.html">Next</a>)<hr />' . $message;
  795. $verbose_filename = $this->verboseClassName . '-' . $this->verboseId . '-' . $this->testId . '.html';
  796. if (file_put_contents($this->verboseDirectory . '/' . $verbose_filename, $message)) {
  797. $url = $this->verboseDirectoryUrl . '/' . $verbose_filename;
  798. // Not using \Drupal\Core\Utility\LinkGeneratorInterface::generate()
  799. // to avoid invoking the theme system, so that unit tests
  800. // can use verbose() as well.
  801. $url = '<a href="' . $url . '" target="_blank">Verbose message</a>';
  802. $this->error($url, 'User notice');
  803. }
  804. $this->verboseId++;
  805. }
  806. /**
  807. * Run all tests in this class.
  808. *
  809. * Regardless of whether $methods are passed or not, only method names
  810. * starting with "test" are executed.
  811. *
  812. * @param $methods
  813. * (optional) A list of method names in the test case class to run; e.g.,
  814. * array('testFoo', 'testBar'). By default, all methods of the class are
  815. * taken into account, but it can be useful to only run a few selected test
  816. * methods during debugging.
  817. */
  818. public function run(array $methods = []) {
  819. $this->checkTestHierarchyMismatch();
  820. $class = get_class($this);
  821. if ($missing_requirements = $this->checkRequirements()) {
  822. $object_info = new \ReflectionObject($this);
  823. $caller = [
  824. 'file' => $object_info->getFileName(),
  825. ];
  826. foreach ($missing_requirements as $missing_requirement) {
  827. TestBase::insertAssert($this->testId, $class, FALSE, $missing_requirement, 'Requirements check', $caller);
  828. }
  829. return;
  830. }
  831. TestServiceProvider::$currentTest = $this;
  832. $simpletest_config = $this->config('simpletest.settings');
  833. // Unless preset from run-tests.sh, retrieve the current verbose setting.
  834. if (!isset($this->verbose)) {
  835. $this->verbose = $simpletest_config->get('verbose');
  836. }
  837. if ($this->verbose) {
  838. // Initialize verbose debugging.
  839. $this->verbose = TRUE;
  840. $this->verboseDirectory = PublicStream::basePath() . '/simpletest/verbose';
  841. $this->verboseDirectoryUrl = file_create_url($this->verboseDirectory);
  842. if (\Drupal::service('file_system')->prepareDirectory($this->verboseDirectory, FileSystemInterface::CREATE_DIRECTORY) && !file_exists($this->verboseDirectory . '/.htaccess')) {
  843. file_put_contents($this->verboseDirectory . '/.htaccess', "<IfModule mod_expires.c>\nExpiresActive Off\n</IfModule>\n");
  844. }
  845. $this->verboseClassName = str_replace("\\", "_", $class);
  846. }
  847. // HTTP auth settings (<username>:<password>) for the simpletest browser
  848. // when sending requests to the test site.
  849. $this->httpAuthMethod = (int) $simpletest_config->get('httpauth.method');
  850. $username = $simpletest_config->get('httpauth.username');
  851. $password = $simpletest_config->get('httpauth.password');
  852. if (!empty($username) && !empty($password)) {
  853. $this->httpAuthCredentials = $username . ':' . $password;
  854. }
  855. // Force assertion failures to be thrown as exceptions.
  856. Handle::register();
  857. set_error_handler([$this, 'errorHandler']);
  858. // Iterate through all the methods in this class, unless a specific list of
  859. // methods to run was passed.
  860. $test_methods = array_filter(get_class_methods($class), function ($method) {
  861. return strpos($method, 'test') === 0;
  862. });
  863. if (empty($test_methods)) {
  864. // Call $this->assert() here because we need to pass along custom caller
  865. // information, lest the wrong originating code file/line be identified.
  866. $this->assert(FALSE, 'No test methods found.', 'Requirements', ['function' => __METHOD__ . '()', 'file' => __FILE__, 'line' => __LINE__]);
  867. }
  868. if ($methods) {
  869. $test_methods = array_intersect($test_methods, $methods);
  870. }
  871. foreach ($test_methods as $method) {
  872. // Insert a fail record. This will be deleted on completion to ensure
  873. // that testing completed.
  874. $method_info = new \ReflectionMethod($class, $method);
  875. $caller = [
  876. 'file' => $method_info->getFileName(),
  877. 'line' => $method_info->getStartLine(),
  878. 'function' => $class . '->' . $method . '()',
  879. ];
  880. $test_completion_check_id = TestBase::insertAssert($this->testId, $class, FALSE, 'The test did not complete due to a fatal error.', 'Completion check', $caller);
  881. try {
  882. $this->prepareEnvironment();
  883. }
  884. catch (\Exception $e) {
  885. $this->exceptionHandler($e);
  886. // The prepareEnvironment() method isolates the test from the parent
  887. // Drupal site by creating a random database prefix and test site
  888. // directory. If this fails, a test would possibly operate in the
  889. // parent site. Therefore, the entire test run for this test class
  890. // has to be aborted.
  891. // restoreEnvironment() cannot be called, because we do not know
  892. // where exactly the environment setup failed.
  893. break;
  894. }
  895. try {
  896. $this->setUp();
  897. }
  898. catch (\Exception $e) {
  899. $this->exceptionHandler($e);
  900. // Abort if setUp() fails, since all test methods will fail.
  901. // But ensure to clean up and restore the environment, since
  902. // prepareEnvironment() succeeded.
  903. $this->restoreEnvironment();
  904. break;
  905. }
  906. try {
  907. $this->$method();
  908. }
  909. catch (\Exception $e) {
  910. $this->exceptionHandler($e);
  911. }
  912. try {
  913. $this->tearDown();
  914. }
  915. catch (\Exception $e) {
  916. $this->exceptionHandler($e);
  917. // If a test fails to tear down, abort the entire test class, since
  918. // it is likely that all tests will fail in the same way and a
  919. // failure here only results in additional test artifacts that have
  920. // to be manually deleted.
  921. $this->restoreEnvironment();
  922. break;
  923. }
  924. $this->restoreEnvironment();
  925. // Remove the test method completion check record.
  926. TestBase::deleteAssert($test_completion_check_id);
  927. }
  928. TestServiceProvider::$currentTest = NULL;
  929. // Clear out the error messages and restore error handler.
  930. \Drupal::messenger()->deleteAll();
  931. restore_error_handler();
  932. }
  933. /**
  934. * Generates a database prefix for running tests.
  935. *
  936. * The database prefix is used by prepareEnvironment() to setup a public files
  937. * directory for the test to be run, which also contains the PHP error log,
  938. * which is written to in case of a fatal error. Since that directory is based
  939. * on the database prefix, all tests (even unit tests) need to have one, in
  940. * order to access and read the error log.
  941. *
  942. * @see TestBase::prepareEnvironment()
  943. *
  944. * The generated database table prefix is used for the Drupal installation
  945. * being performed for the test. It is also used as user agent HTTP header
  946. * value by the cURL-based browser of WebTestBase, which is sent to the Drupal
  947. * installation of the test. During early Drupal bootstrap, the user agent
  948. * HTTP header is parsed, and if it matches, all database queries use the
  949. * database table prefix that has been generated here.
  950. *
  951. * @see WebTestBase::curlInitialize()
  952. * @see drupal_valid_test_ua()
  953. */
  954. private function prepareDatabasePrefix() {
  955. $test_db = new TestDatabase();
  956. $this->siteDirectory = $test_db->getTestSitePath();
  957. $this->databasePrefix = $test_db->getDatabasePrefix();
  958. // As soon as the database prefix is set, the test might start to execute.
  959. // All assertions as well as the SimpleTest batch operations are associated
  960. // with the testId, so the database prefix has to be associated with it.
  961. $affected_rows = self::getDatabaseConnection()->update('simpletest_test_id')
  962. ->fields(['last_prefix' => $this->databasePrefix])
  963. ->condition('test_id', $this->testId)
  964. ->execute();
  965. if (!$affected_rows) {
  966. throw new \RuntimeException('Failed to set up database prefix.');
  967. }
  968. }
  969. /**
  970. * Act on global state information before the environment is altered for a test.
  971. *
  972. * Allows e.g. KernelTestBase to prime system/extension info from the
  973. * parent site (and inject it into the test environment so as to improve
  974. * performance).
  975. */
  976. protected function beforePrepareEnvironment() {
  977. }
  978. /**
  979. * Prepares the current environment for running the test.
  980. *
  981. * Backups various current environment variables and resets them, so they do
  982. * not interfere with the Drupal site installation in which tests are executed
  983. * and can be restored in TestBase::restoreEnvironment().
  984. *
  985. * Also sets up new resources for the testing environment, such as the public
  986. * filesystem and configuration directories.
  987. *
  988. * This method is private as it must only be called once by TestBase::run()
  989. * (multiple invocations for the same test would have unpredictable
  990. * consequences) and it must not be callable or overridable by test classes.
  991. *
  992. * @see TestBase::beforePrepareEnvironment()
  993. */
  994. private function prepareEnvironment() {
  995. $user = \Drupal::currentUser();
  996. // Allow (base) test classes to backup global state information.
  997. $this->beforePrepareEnvironment();
  998. // Create the database prefix for this test.
  999. $this->prepareDatabasePrefix();
  1000. $language_interface = \Drupal::languageManager()->getCurrentLanguage();
  1001. // When running the test runner within a test, back up the original database
  1002. // prefix.
  1003. if (DRUPAL_TEST_IN_CHILD_SITE) {
  1004. $this->originalPrefix = drupal_valid_test_ua();
  1005. }
  1006. // Backup current in-memory configuration.
  1007. $site_path = \Drupal::service('site.path');
  1008. $this->originalSite = $site_path;
  1009. $this->originalSettings = Settings::getAll();
  1010. $this->originalConfig = $GLOBALS['config'];
  1011. // @todo Remove all remnants of $GLOBALS['conf'].
  1012. // @see https://www.drupal.org/node/2183323
  1013. $this->originalConf = isset($GLOBALS['conf']) ? $GLOBALS['conf'] : NULL;
  1014. // Backup statics and globals.
  1015. $this->originalContainer = \Drupal::getContainer();
  1016. $this->originalLanguage = $language_interface;
  1017. // Save further contextual information.
  1018. // Use the original files directory to avoid nesting it within an existing
  1019. // simpletest directory if a test is executed within a test.
  1020. $this->originalFileDirectory = Settings::get('file_public_path', $site_path . '/files');
  1021. $this->originalUser = isset($user) ? clone $user : NULL;
  1022. // Prevent that session data is leaked into the UI test runner by closing
  1023. // the session and then setting the session-name (i.e. the name of the
  1024. // session cookie) to a random value. If a test starts a new session, then
  1025. // it will be associated with a different session-name. After the test-run
  1026. // it can be safely destroyed.
  1027. // @see TestBase::restoreEnvironment()
  1028. if (PHP_SAPI !== 'cli' && session_status() === PHP_SESSION_ACTIVE) {
  1029. session_write_close();
  1030. }
  1031. $this->originalSessionName = session_name();
  1032. session_name('SIMPLETEST' . Crypt::randomBytesBase64());
  1033. // Save and clean the shutdown callbacks array because it is static cached
  1034. // and will be changed by the test run. Otherwise it will contain callbacks
  1035. // from both environments and the testing environment will try to call the
  1036. // handlers defined by the original one.
  1037. $callbacks = &drupal_register_shutdown_function();
  1038. $this->originalShutdownCallbacks = $callbacks;
  1039. $callbacks = [];
  1040. // Create test directory ahead of installation so fatal errors and debug
  1041. // information can be logged during installation process.
  1042. \Drupal::service('file_system')->prepareDirectory($this->siteDirectory, FileSystemInterface::CREATE_DIRECTORY | FileSystemInterface::MODIFY_PERMISSIONS);
  1043. // Prepare filesystem directory paths.
  1044. $this->publicFilesDirectory = $this->siteDirectory . '/files';
  1045. $this->privateFilesDirectory = $this->siteDirectory . '/private';
  1046. $this->tempFilesDirectory = $this->siteDirectory . '/temp';
  1047. $this->translationFilesDirectory = $this->siteDirectory . '/translations';
  1048. $this->generatedTestFiles = FALSE;
  1049. // Ensure the configImporter is refreshed for each test.
  1050. $this->configImporter = NULL;
  1051. // Unregister all custom stream wrappers of the parent site.
  1052. // Availability of Drupal stream wrappers varies by test base class:
  1053. // - KernelTestBase supports and maintains stream wrappers in a custom
  1054. // way.
  1055. // - WebTestBase re-initializes Drupal stream wrappers after installation.
  1056. // The original stream wrappers are restored after the test run.
  1057. // @see TestBase::restoreEnvironment()
  1058. $this->originalContainer->get('stream_wrapper_manager')->unregister();
  1059. // Reset statics.
  1060. drupal_static_reset();
  1061. // Ensure there is no service container.
  1062. $this->container = NULL;
  1063. \Drupal::unsetContainer();
  1064. // Unset globals.
  1065. unset($GLOBALS['config_directories']);
  1066. unset($GLOBALS['config']);
  1067. unset($GLOBALS['conf']);
  1068. // Log fatal errors.
  1069. ini_set('log_errors', 1);
  1070. ini_set('error_log', DRUPAL_ROOT . '/' . $this->siteDirectory . '/error.log');
  1071. // Change the database prefix.
  1072. $this->changeDatabasePrefix();
  1073. // After preparing the environment and changing the database prefix, we are
  1074. // in a valid test environment.
  1075. drupal_valid_test_ua($this->databasePrefix);
  1076. // Reset settings.
  1077. new Settings([
  1078. // For performance, simply use the database prefix as hash salt.
  1079. 'hash_salt' => $this->databasePrefix,
  1080. 'container_yamls' => [],
  1081. ]);
  1082. Environment::setTimeLimit($this->timeLimit);
  1083. }
  1084. /**
  1085. * Performs cleanup tasks after each individual test method has been run.
  1086. */
  1087. protected function tearDown() {
  1088. }
  1089. /**
  1090. * Cleans up the test environment and restores the original environment.
  1091. *
  1092. * Deletes created files, database tables, and reverts environment changes.
  1093. *
  1094. * This method needs to be invoked for both unit and integration tests.
  1095. *
  1096. * @see TestBase::prepareDatabasePrefix()
  1097. * @see TestBase::changeDatabasePrefix()
  1098. * @see TestBase::prepareEnvironment()
  1099. */
  1100. private function restoreEnvironment() {
  1101. // Destroy the session if one was started during the test-run.
  1102. $_SESSION = [];
  1103. if (PHP_SAPI !== 'cli' && session_status() === PHP_SESSION_ACTIVE) {
  1104. session_destroy();
  1105. $params = session_get_cookie_params();
  1106. setcookie(session_name(), '', REQUEST_TIME - 3600, $params['path'], $params['domain'], $params['secure'], $params['httponly']);
  1107. }
  1108. session_name($this->originalSessionName);
  1109. // Reset all static variables.
  1110. // Unsetting static variables will potentially invoke destruct methods,
  1111. // which might call into functions that prime statics and caches again.
  1112. // In that case, all functions are still operating on the test environment,
  1113. // which means they may need to access its filesystem and database.
  1114. drupal_static_reset();
  1115. if ($this->container && $this->container->has('state') && $state = $this->container->get('state')) {
  1116. $captured_emails = $state->get('system.test_mail_collector') ?: [];
  1117. $emailCount = count($captured_emails);
  1118. if ($emailCount) {
  1119. $message = $emailCount == 1 ? '1 email was sent during this test.' : $emailCount . ' emails were sent during this test.';
  1120. $this->pass($message, 'Email');
  1121. }
  1122. }
  1123. // Sleep for 50ms to allow shutdown functions and terminate events to
  1124. // complete. Further information: https://www.drupal.org/node/2194357.
  1125. usleep(50000);
  1126. // Remove all prefixed tables.
  1127. $original_connection_info = Database::getConnectionInfo('simpletest_original_default');
  1128. $original_prefix = $original_connection_info['default']['prefix']['default'];
  1129. $test_connection_info = Database::getConnectionInfo('default');
  1130. $test_prefix = $test_connection_info['default']['prefix']['default'];
  1131. if ($original_prefix != $test_prefix) {
  1132. $tables = Database::getConnection()->schema()->findTables('%');
  1133. foreach ($tables as $table) {
  1134. if (Database::getConnection()->schema()->dropTable($table)) {
  1135. unset($tables[$table]);
  1136. }
  1137. }
  1138. }
  1139. // In case a fatal error occurred that was not in the test process read the
  1140. // log to pick up any fatal errors.
  1141. (new TestDatabase($this->databasePrefix))->logRead($this->testId, get_class($this));
  1142. // Restore original dependency injection container.
  1143. $this->container = $this->originalContainer;
  1144. \Drupal::setContainer($this->originalContainer);
  1145. // Delete test site directory.
  1146. \Drupal::service('file_system')->deleteRecursive($this->siteDirectory, [$this, 'filePreDeleteCallback']);
  1147. // Restore original database connection.
  1148. Database::removeConnection('default');
  1149. Database::renameConnection('simpletest_original_default', 'default');
  1150. // Reset all static variables.
  1151. // All destructors of statically cached objects have been invoked above;
  1152. // this second reset is guaranteed to reset everything to nothing.
  1153. drupal_static_reset();
  1154. // Restore original in-memory configuration.
  1155. $GLOBALS['config'] = $this->originalConfig;
  1156. $GLOBALS['conf'] = $this->originalConf;
  1157. new Settings($this->originalSettings);
  1158. // Re-initialize original stream wrappers of the parent site.
  1159. // This must happen after static variables have been reset and the original
  1160. // container and $config_directories are restored, as simpletest_log_read()
  1161. // uses the public stream wrapper to locate the error.log.
  1162. $this->originalContainer->get('stream_wrapper_manager')->register();
  1163. if (isset($this->originalPrefix)) {
  1164. drupal_valid_test_ua($this->originalPrefix);
  1165. }
  1166. else {
  1167. drupal_valid_test_ua(FALSE);
  1168. }
  1169. // Restore original shutdown callbacks.
  1170. $callbacks = &drupal_register_shutdown_function();
  1171. $callbacks = $this->originalShutdownCallbacks;
  1172. }
  1173. /**
  1174. * Handle errors during test runs.
  1175. *
  1176. * Because this is registered in set_error_handler(), it has to be public.
  1177. *
  1178. * @see set_error_handler
  1179. */
  1180. public function errorHandler($severity, $message, $file = NULL, $line = NULL) {
  1181. if ($severity & error_reporting()) {
  1182. $error_map = [
  1183. E_STRICT => 'Run-time notice',
  1184. E_WARNING => 'Warning',
  1185. E_NOTICE => 'Notice',
  1186. E_CORE_ERROR => 'Core error',
  1187. E_CORE_WARNING => 'Core warning',
  1188. E_USER_ERROR => 'User error',
  1189. E_USER_WARNING => 'User warning',
  1190. E_USER_NOTICE => 'User notice',
  1191. E_RECOVERABLE_ERROR => 'Recoverable error',
  1192. E_DEPRECATED => 'Deprecated',
  1193. E_USER_DEPRECATED => 'User deprecated',
  1194. ];
  1195. $backtrace = debug_backtrace();
  1196. // Add verbose backtrace for errors, but not for debug() messages.
  1197. if ($severity !== E_USER_NOTICE) {
  1198. $verbose_backtrace = $backtrace;
  1199. array_shift($verbose_backtrace);
  1200. $message .= '<pre class="backtrace">' . Error::formatBacktrace($verbose_backtrace) . '</pre>';
  1201. }
  1202. $this->error($message, $error_map[$severity], Error::getLastCaller($backtrace));
  1203. }
  1204. return TRUE;
  1205. }
  1206. /**
  1207. * Handle exceptions.
  1208. *
  1209. * @see set_exception_handler
  1210. */
  1211. protected function exceptionHandler($exception) {
  1212. $backtrace = $exception->getTrace();
  1213. $verbose_backtrace = $backtrace;
  1214. // Push on top of the backtrace the call that generated the exception.
  1215. array_unshift($backtrace, [
  1216. 'line' => $exception->getLine(),
  1217. 'file' => $exception->getFile(),
  1218. ]);
  1219. $decoded_exception = Error::decodeException($exception);
  1220. unset($decoded_exception['backtrace']);
  1221. $message = new FormattableMarkup('%type: @message in %function (line %line of %file). <pre class="backtrace">@backtrace</pre>', $decoded_exception + [
  1222. '@backtrace' => Error::formatBacktrace($verbose_backtrace),
  1223. ]);
  1224. $this->error($message, 'Uncaught exception', Error::getLastCaller($backtrace));
  1225. }
  1226. /**
  1227. * Changes in memory settings.
  1228. *
  1229. * @param $name
  1230. * The name of the setting to return.
  1231. * @param $value
  1232. * The value of the setting.
  1233. *
  1234. * @see \Drupal\Core\Site\Settings::get()
  1235. */
  1236. protected function settingsSet($name, $value) {
  1237. $settings = Settings::getAll();
  1238. $settings[$name] = $value;
  1239. new Settings($settings);
  1240. }
  1241. /**
  1242. * Ensures test files are deletable.
  1243. *
  1244. * Some tests chmod generated files to be read only. During
  1245. * TestBase::restoreEnvironment() and other cleanup operations, these files
  1246. * need to get deleted too.
  1247. *
  1248. * @see \Drupal\Core\File\FileSystemInterface::deleteRecursive()
  1249. */
  1250. public static function filePreDeleteCallback($path) {
  1251. // When the webserver runs with the same system user as the test runner, we
  1252. // can make read-only files writable again. If not, chmod will fail while
  1253. // the file deletion still works if file permissions have been configured
  1254. // correctly. Thus, we ignore any problems while running chmod.
  1255. @chmod($path, 0700);
  1256. }
  1257. /**
  1258. * Configuration accessor for tests. Returns non-overridden configuration.
  1259. *
  1260. * @param $name
  1261. * Configuration name.
  1262. *
  1263. * @return \Drupal\Core\Config\Config
  1264. * The configuration object with original configuration data.
  1265. */
  1266. protected function config($name) {
  1267. return \Drupal::configFactory()->getEditable($name);
  1268. }
  1269. /**
  1270. * Gets the database prefix.
  1271. *
  1272. * @return string
  1273. * The database prefix
  1274. */
  1275. public function getDatabasePrefix() {
  1276. return $this->databasePrefix;
  1277. }
  1278. /**
  1279. * Gets the temporary files directory.
  1280. *
  1281. * @return string
  1282. * The temporary files directory.
  1283. */
  1284. public function getTempFilesDirectory() {
  1285. return $this->tempFilesDirectory;
  1286. }
  1287. }