comparison core/lib/Drupal/Core/Test/TestDatabase.php @ 0:4c8ae668cc8c

Initial import (non-working)
author Chris Cannam
date Wed, 29 Nov 2017 16:09:58 +0000
parents
children 129ea1e6d783
comparison
equal deleted inserted replaced
-1:000000000000 0:4c8ae668cc8c
1 <?php
2
3 namespace Drupal\Core\Test;
4
5 use Drupal\Component\FileSystem\FileSystem;
6 use Drupal\Core\Database\ConnectionNotDefinedException;
7 use Drupal\Core\Database\Database;
8
9 /**
10 * Provides helper methods for interacting with the Simpletest database.
11 */
12 class TestDatabase {
13
14 /**
15 * A random number used to ensure that test fixtures are unique to each test
16 * method.
17 *
18 * @var int
19 */
20 protected $lockId;
21
22 /**
23 * The test database prefix.
24 *
25 * @var string
26 */
27 protected $databasePrefix;
28
29 /**
30 * Returns the database connection to the site running Simpletest.
31 *
32 * @return \Drupal\Core\Database\Connection
33 * The database connection to use for inserting assertions.
34 *
35 * @see \Drupal\simpletest\TestBase::prepareEnvironment()
36 */
37 public static function getConnection() {
38 // Check whether there is a test runner connection.
39 // @see run-tests.sh
40 // @todo Convert Simpletest UI runner to create + use this connection, too.
41 try {
42 $connection = Database::getConnection('default', 'test-runner');
43 }
44 catch (ConnectionNotDefinedException $e) {
45 // Check whether there is a backup of the original default connection.
46 // @see TestBase::prepareEnvironment()
47 try {
48 $connection = Database::getConnection('default', 'simpletest_original_default');
49 }
50 catch (ConnectionNotDefinedException $e) {
51 // If TestBase::prepareEnvironment() or TestBase::restoreEnvironment()
52 // failed, the test-specific database connection does not exist
53 // yet/anymore, so fall back to the default of the (UI) test runner.
54 $connection = Database::getConnection('default', 'default');
55 }
56 }
57 return $connection;
58 }
59
60 /**
61 * TestDatabase constructor.
62 *
63 * @param string|null $db_prefix
64 * If not provided a new test lock is generated.
65 *
66 * @throws \InvalidArgumentException
67 * Thrown when $db_prefix does not match the regular expression.
68 */
69 public function __construct($db_prefix = NULL) {
70 if ($db_prefix === NULL) {
71 $this->lockId = $this->getTestLock();
72 $this->databasePrefix = 'test' . $this->lockId;
73 }
74 else {
75 $this->databasePrefix = $db_prefix;
76 // It is possible that we're running a test inside a test. In which case
77 // $db_prefix will be something like test12345678test90123456 and the
78 // generated lock ID for the running test method would be 90123456.
79 preg_match('/test(\d+)$/', $db_prefix, $matches);
80 if (!isset($matches[1])) {
81 throw new \InvalidArgumentException("Invalid database prefix: $db_prefix");
82 }
83 $this->lockId = $matches[1];
84 }
85 }
86
87 /**
88 * Gets the relative path to the test site directory.
89 *
90 * @return string
91 * The relative path to the test site directory.
92 */
93 public function getTestSitePath() {
94 return 'sites/simpletest/' . $this->lockId;
95 }
96
97 /**
98 * Gets the test database prefix.
99 *
100 * @return string
101 * The test database prefix.
102 */
103 public function getDatabasePrefix() {
104 return $this->databasePrefix;
105 }
106
107 /**
108 * Generates a unique lock ID for the test method.
109 *
110 * @return int
111 * The unique lock ID for the test method.
112 */
113 protected function getTestLock() {
114 // Ensure that the generated lock ID is not in use, which may happen when
115 // tests are run concurrently.
116 do {
117 $lock_id = mt_rand(10000000, 99999999);
118 // If we're only running with a concurrency of 1 there's no need to create
119 // a test lock file as there is no chance of the random number generated
120 // clashing.
121 if (getenv('RUN_TESTS_CONCURRENCY') > 1 && @symlink(__FILE__, $this->getLockFile($lock_id)) === FALSE) {
122 $lock_id = NULL;
123 }
124 } while ($lock_id === NULL);
125 return $lock_id;
126 }
127
128 /**
129 * Releases all test locks.
130 *
131 * This should only be called once all the test fixtures have been cleaned up.
132 */
133 public static function releaseAllTestLocks() {
134 $tmp = file_directory_os_temp();
135 $dir = dir($tmp);
136 while (($entry = $dir->read()) !== FALSE) {
137 if ($entry === '.' || $entry === '..') {
138 continue;
139 }
140 $entry_path = $tmp . '/' . $entry;
141 if (preg_match('/^test_\d+/', $entry) && is_link($entry_path)) {
142 unlink($entry_path);
143 }
144 }
145 }
146
147 /**
148 * Gets the lock file path.
149 *
150 * @param int $lock_id
151 * The test method lock ID.
152 *
153 * @return string
154 * A file path to the symbolic link that prevents the lock ID being re-used.
155 */
156 protected function getLockFile($lock_id) {
157 return FileSystem::getOsTemporaryDirectory() . '/test_' . $lock_id;
158 }
159
160 }