*
* @param string|null $db_prefix
* If not provided a new test lock is generated.
+ * @param bool $create_lock
+ * (optional) Whether or not to create a lock file. Defaults to FALSE. If
+ * the environment variable RUN_TESTS_CONCURRENCY is greater than 1 it will
+ * be overridden to TRUE regardless of its initial value.
*
* @throws \InvalidArgumentException
* Thrown when $db_prefix does not match the regular expression.
*/
- public function __construct($db_prefix = NULL) {
+ public function __construct($db_prefix = NULL, $create_lock = FALSE) {
if ($db_prefix === NULL) {
- $this->lockId = $this->getTestLock();
+ $this->lockId = $this->getTestLock($create_lock);
$this->databasePrefix = 'test' . $this->lockId;
}
else {
/**
* Generates a unique lock ID for the test method.
*
+ * @param bool $create_lock
+ * (optional) Whether or not to create a lock file. Defaults to FALSE.
+ *
* @return int
* The unique lock ID for the test method.
*/
- protected function getTestLock() {
- // Ensure that the generated lock ID is not in use, which may happen when
- // tests are run concurrently.
+ protected function getTestLock($create_lock = FALSE) {
+ // There is a risk that the generated random number is a duplicate. This
+ // would cause different tests to try to use the same database prefix.
+ // Therefore, if running with a concurrency of greater than 1, we need to
+ // create a lock.
+ if (getenv('RUN_TESTS_CONCURRENCY') > 1) {
+ $create_lock = TRUE;
+ }
+
do {
$lock_id = mt_rand(10000000, 99999999);
- // If we're only running with a concurrency of 1 there's no need to create
- // a test lock file as there is no chance of the random number generated
- // clashing.
- if (getenv('RUN_TESTS_CONCURRENCY') > 1 && @symlink(__FILE__, $this->getLockFile($lock_id)) === FALSE) {
+ if ($create_lock && @symlink(__FILE__, $this->getLockFile($lock_id)) === FALSE) {
+ // If we can't create a symlink, the lock ID is in use. Generate another
+ // one. Symlinks are used because they are atomic and reliable.
$lock_id = NULL;
}
} while ($lock_id === NULL);
return $lock_id;
}
+ /**
+ * Releases a lock.
+ *
+ * @return bool
+ * TRUE if successful, FALSE if not.
+ */
+ public function releaseLock() {
+ return unlink($this->getLockFile($this->lockId));
+ }
+
/**
* Releases all test locks.
*
* This should only be called once all the test fixtures have been cleaned up.
*/
public static function releaseAllTestLocks() {
- $tmp = file_directory_os_temp();
+ $tmp = FileSystem::getOsTemporaryDirectory();
$dir = dir($tmp);
while (($entry = $dir->read()) !== FALSE) {
if ($entry === '.' || $entry === '..') {