Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ composer.lock
.phpunit.result.cache
.phpunit.cache
.fastunit-cache
.fixture.lock

# scoped & downgraded version
php-scoper.phar
Expand Down
36 changes: 36 additions & 0 deletions src/Testing/PHPUnit/AbstractRectorTestCase.php
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,11 @@ abstract class AbstractRectorTestCase extends AbstractLazyTestCase implements Re

private ?string $inputFilePath = null;

/**
* @var resource|null
*/
private $fixtureDirectoryLock;

/**
* @var array<string, true>
*/
Expand Down Expand Up @@ -133,6 +138,8 @@ protected function tearDown(): void
FileSystem::delete($this->inputFilePath);
}

$this->unlockFixtureDirectory();

// a next test that does not set its own paths would still locate the deleted file
$this->dynamicSourceLocatorProvider->reset();
}
Expand Down Expand Up @@ -177,6 +184,10 @@ protected function doTestFile(string $fixtureFilePath, bool $includeFixtureDirec
throw new ShouldNotHappenException('Fixture file and input file cannot be the same: ' . $fixtureFilePath);
}

// test classes that share a fixture directory write the same temp files,
// so in parallel processes one could delete the other's file
$this->lockFixtureDirectory(dirname($inputFilePath));

// write temp file
FileSystem::write($inputFilePath, $inputFileContents, null);

Expand Down Expand Up @@ -282,6 +293,31 @@ private function processFilePath(string $filePath, bool $includeFixtureDirectory
return new RectorTestResult($changedFileContents, $processResult);
}

private function lockFixtureDirectory(string $directory): void
{
// a test can call doTestFile() more than once; a second lock from this process would wait for the first
$this->unlockFixtureDirectory();

$fixtureDirectoryLock = fopen($directory . '/.fixture.lock', 'c');
if ($fixtureDirectoryLock === false) {
throw new ShouldNotHappenException('Cannot open the lock file in ' . $directory);
}

flock($fixtureDirectoryLock, LOCK_EX);
$this->fixtureDirectoryLock = $fixtureDirectoryLock;
}

private function unlockFixtureDirectory(): void
{
if (! is_resource($this->fixtureDirectoryLock)) {
return;
}

flock($this->fixtureDirectoryLock, LOCK_UN);
fclose($this->fixtureDirectoryLock);
$this->fixtureDirectoryLock = null;
}

private function createInputFilePath(string $fixtureFilePath): string
{
$inputFileDirectory = dirname($fixtureFilePath);
Expand Down
Loading