Pull merge.
[yaffs-website] / web / core / lib / Drupal / Core / Test / TestDatabase.php
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    * @param bool $create_lock
66    *   (optional) Whether or not to create a lock file. Defaults to FALSE. If
67    *   the environment variable RUN_TESTS_CONCURRENCY is greater than 1 it will
68    *   be overridden to TRUE regardless of its initial value.
69    *
70    * @throws \InvalidArgumentException
71    *   Thrown when $db_prefix does not match the regular expression.
72    */
73   public function __construct($db_prefix = NULL, $create_lock = FALSE) {
74     if ($db_prefix === NULL) {
75       $this->lockId = $this->getTestLock($create_lock);
76       $this->databasePrefix = 'test' . $this->lockId;
77     }
78     else {
79       $this->databasePrefix = $db_prefix;
80       // It is possible that we're running a test inside a test. In which case
81       // $db_prefix will be something like test12345678test90123456 and the
82       // generated lock ID for the running test method would be 90123456.
83       preg_match('/test(\d+)$/', $db_prefix, $matches);
84       if (!isset($matches[1])) {
85         throw new \InvalidArgumentException("Invalid database prefix: $db_prefix");
86       }
87       $this->lockId = $matches[1];
88     }
89   }
90
91   /**
92    * Gets the relative path to the test site directory.
93    *
94    * @return string
95    *   The relative path to the test site directory.
96    */
97   public function getTestSitePath() {
98     return 'sites/simpletest/' . $this->lockId;
99   }
100
101   /**
102    * Gets the test database prefix.
103    *
104    * @return string
105    *   The test database prefix.
106    */
107   public function getDatabasePrefix() {
108     return $this->databasePrefix;
109   }
110
111   /**
112    * Generates a unique lock ID for the test method.
113    *
114    * @param bool $create_lock
115    *   (optional) Whether or not to create a lock file. Defaults to FALSE.
116    *
117    * @return int
118    *   The unique lock ID for the test method.
119    */
120   protected function getTestLock($create_lock = FALSE) {
121     // There is a risk that the generated random number is a duplicate. This
122     // would cause different tests to try to use the same database prefix.
123     // Therefore, if running with a concurrency of greater than 1, we need to
124     // create a lock.
125     if (getenv('RUN_TESTS_CONCURRENCY') > 1) {
126       $create_lock = TRUE;
127     }
128
129     do {
130       $lock_id = mt_rand(10000000, 99999999);
131       if ($create_lock && @symlink(__FILE__, $this->getLockFile($lock_id)) === FALSE) {
132         // If we can't create a symlink, the lock ID is in use. Generate another
133         // one. Symlinks are used because they are atomic and reliable.
134         $lock_id = NULL;
135       }
136     } while ($lock_id === NULL);
137     return $lock_id;
138   }
139
140   /**
141    * Releases a lock.
142    *
143    * @return bool
144    *   TRUE if successful, FALSE if not.
145    */
146   public function releaseLock() {
147     return unlink($this->getLockFile($this->lockId));
148   }
149
150   /**
151    * Releases all test locks.
152    *
153    * This should only be called once all the test fixtures have been cleaned up.
154    */
155   public static function releaseAllTestLocks() {
156     $tmp = FileSystem::getOsTemporaryDirectory();
157     $dir = dir($tmp);
158     while (($entry = $dir->read()) !== FALSE) {
159       if ($entry === '.' || $entry === '..') {
160         continue;
161       }
162       $entry_path = $tmp . '/' . $entry;
163       if (preg_match('/^test_\d+/', $entry) && is_link($entry_path)) {
164         unlink($entry_path);
165       }
166     }
167   }
168
169   /**
170    * Gets the lock file path.
171    *
172    * @param int $lock_id
173    *   The test method lock ID.
174    *
175    * @return string
176    *   A file path to the symbolic link that prevents the lock ID being re-used.
177    */
178   protected function getLockFile($lock_id) {
179     return FileSystem::getOsTemporaryDirectory() . '/test_' . $lock_id;
180   }
181
182 }