Skip to content

Commit

Permalink
Merge 1d1f116 into 812873f
Browse files Browse the repository at this point in the history
  • Loading branch information
cgrabenstein committed Jan 16, 2021
2 parents 812873f + 1d1f116 commit 10626e2
Show file tree
Hide file tree
Showing 3 changed files with 179 additions and 42 deletions.
2 changes: 1 addition & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
"laminas/laminas-zendframework-bridge": "^1.0"
},
"require-dev": {
"doctrine/migrations": "^1.0 || ^2.0",
"doctrine/migrations": "^1.0 || ^2.0 || ^3.0",
"guzzlehttp/guzzle": "^5.3.3 || ^6.3.3",
"laminas/laminas-coding-standard": "~1.0.0",
"laminas/laminas-loader": "^2.0",
Expand Down
65 changes: 54 additions & 11 deletions src/Check/DoctrineMigration.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,24 +8,51 @@

namespace Laminas\Diagnostics\Check;

use Doctrine\Migrations\Configuration\Configuration;
use Doctrine\Migrations\DependencyFactory;
use Doctrine\Migrations\Metadata\AvailableMigration;
use Doctrine\Migrations\Metadata\ExecutedMigration;
use InvalidArgumentException;
use Laminas\Diagnostics\Result\Failure;
use Laminas\Diagnostics\Result\ResultInterface;
use Laminas\Diagnostics\Result\Success;

class DoctrineMigration extends AbstractCheck
{
/**
* @var Configuration
* @var array
*/
private $migrationConfiguration;
private $availableVersions;

/**
* @param Configuration $migrationConfiguration
* @var array
*/
public function __construct(Configuration $migrationConfiguration)
private $migratedVersions;

public function __construct($input)
{
$this->migrationConfiguration = $migrationConfiguration;
if ($input instanceof DependencyFactory) {
$this->availableVersions = $this->getAvailableVersionsFromDependencyFactory($input);
$this->migratedVersions = $this->getMigratedVersionsFromDependencyFactory($input);
return;
}

if ($input instanceof Doctrine\Migrations\Configuration\Configuration
&& method_exists($input, 'getAvailableVersions')
&& method_exists($input, 'getMigratedVersions')
) {
$this->availableVersions = $input->getAvailableVersions();
$this->migratedVersions = $input->getMigratedVersions();
return;
}

// phpcs:disable Generic.Files.LineLength.MaxExceeded,Generic.Files.LineLength.TooLong
throw new InvalidArgumentException(
'Invalid Argument for DoctrineMigration check.' . PHP_EOL
. 'If you are using doctrine/migrations ^3.0, pass the Doctrine\Migrations\DependencyFactory as argument.' . PHP_EOL
. 'If you are using doctrine/migrations ^2.0, pass the Doctrine\Migrations\Configuration\Configuration as argument.' . PHP_EOL
. 'If you are using doctrine/migrations ^1.0, pass the Doctrine\DBAL\Migrations\Configuration\Configuration as argument.'
);
// phpcs:enable
}

/**
Expand All @@ -35,19 +62,35 @@ public function __construct(Configuration $migrationConfiguration)
*/
public function check()
{
$availableVersions = $this->migrationConfiguration->getAvailableVersions();
$migratedVersions = $this->migrationConfiguration->getMigratedVersions();

$notMigratedVersions = array_diff($availableVersions, $migratedVersions);
$notMigratedVersions = array_diff($this->availableVersions, $this->migratedVersions);
if (! empty($notMigratedVersions)) {
return new Failure('Not all migrations applied', $notMigratedVersions);
}

$notAvailableVersion = array_diff($migratedVersions, $availableVersions);
$notAvailableVersion = array_diff($this->migratedVersions, $this->availableVersions);
if (! empty($notAvailableVersion)) {
return new Failure('Migrations applied which are not available', $notMigratedVersions);
}

return new Success();
}


private function getAvailableVersionsFromDependencyFactory(DependencyFactory $dependencyFactory)
{
$allMigrations = $dependencyFactory->getMigrationRepository()->getMigrations();

return array_map(static function (AvailableMigration $availableMigration) {
return $availableMigration->getVersion();
}, $allMigrations->getItems());
}

private function getMigratedVersionsFromDependencyFactory(DependencyFactory $dependencyFactory)
{
$executedMigrations = $dependencyFactory->getMetadataStorage()->getExecutedMigrations();

return array_map(static function (ExecutedMigration $executedMigration) {
return $executedMigration->getVersion();
}, $executedMigrations->getItems());
}
}
154 changes: 124 additions & 30 deletions test/DoctrineMigrationTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,77 +8,171 @@

namespace LaminasTest\Diagnostics;

use Doctrine\Migrations\Configuration\Configuration;
use Doctrine\Migrations\DependencyFactory;
use Doctrine\Migrations\Metadata\Storage\MetadataStorage;
use Doctrine\Migrations\MigrationsRepository;
use Laminas\Diagnostics\Check\DoctrineMigration;
use Laminas\Diagnostics\Result\FailureInterface;
use Laminas\Diagnostics\Result\SuccessInterface;
use PHPUnit\Framework\TestCase;

class DoctrineMigrationTest extends TestCase
{
public function testEverythingMigrated()
{
$configuration = $this->getMockBuilder(Configuration::class)
/**
* @dataProvider provideMigrationTestCases
*/
public function testDoctrineMigrationsVersion3(
array $availableVersions,
array $migratedVersions,
string $expectedResult
): void {
if (!$this->isDoctrineVersion3Installed()) {
self::markTestSkipped('Doctrine Version 3 is not installed, skipping test.');
}

$migrationRepository = $this->getMockBuilder(MigrationsRepository::class)
->disableOriginalConstructor()
->getMock();

$configuration
->expects($this->once())
->method('getAvailableVersions')
->will($this->returnValue(['Version1', 'Version2']));
$migrationRepository
->expects(self::once())
->method('getMigrations')
->willReturn($availableVersions);

$configuration
->expects($this->once())
->method('getMigratedVersions')
->will($this->returnValue(['Version1', 'Version2']));
$metadataStorage = $this->getMockBuilder(MetadataStorage::class)
->disableOriginalConstructor()
->getMock();

$check = new DoctrineMigration($configuration);
$metadataStorage
->expects(self::once())
->method('getExecutedMigrations')
->willReturn($migratedVersions);

$dependencyFactory = $this->getMockBuilder(DependencyFactory::class)
->disableOriginalConstructor()
->getMock();

$dependencyFactory
->expects(self::once())
->method('getMigrationRepository')
->willReturn($migrationRepository);

$dependencyFactory
->expects(self::once())
->method('getMetadataStorage')
->willReturn($metadataStorage);

$check = new DoctrineMigration($dependencyFactory);
$result = $check->check();

$this->assertInstanceof(SuccessInterface::class, $result);
self::assertInstanceof($expectedResult, $result);
}

public function testNotAllMigrationsMigrated()
{
$configuration = $this->getMockBuilder(Configuration::class)
/**
* @dataProvider provideMigrationTestCases
*/
public function testDoctrineMigrationsVersion2(
array $availableVersions,
array $migratedVersions,
string $expectedResult
): void {
if (!$this->isDoctrineVersion2Installed()) {
self::markTestSkipped('Doctrine Version 2 is not installed, skipping test.');
}

$configuration = $this->getMockBuilder(\Doctrine\Migrations\Configuration\Configuration::class)
->disableOriginalConstructor()
->getMock();

$configuration
->expects($this->once())
->expects(self::once())
->method('getAvailableVersions')
->will($this->returnValue(['Version1', 'Version2']));
->willReturn($availableVersions);

$configuration
->expects($this->once())
->expects(self::once())
->method('getMigratedVersions')
->will($this->returnValue(['Version1']));
->willReturn($migratedVersions);

$check = new DoctrineMigration($configuration);
$result = $check->check();

$this->assertInstanceof(FailureInterface::class, $result);
self::assertInstanceof($expectedResult, $result);
}

public function testNoExistingMigrationMigrated()
{
$configuration = $this->getMockBuilder(Configuration::class)
/**
* @dataProvider provideMigrationTestCases
*/
public function testDoctrineMigrationsVersion1(
array $availableVersions,
array $migratedVersions,
string $expectedResult
): void {
if (!$this->isDoctrineVersion1Installed()) {
self::markTestSkipped('Doctrine Version 1 is not installed, skipping test.');
}

$configuration = $this->getMockBuilder(\Doctrine\DBAL\Migrations\Configuration\Configuration::class)
->disableOriginalConstructor()
->getMock();

$configuration
->expects($this->once())
->expects(self::once())
->method('getAvailableVersions')
->will($this->returnValue(['Version1']));
->willReturn($availableVersions);

$configuration
->expects($this->once())
->expects(self::once())
->method('getMigratedVersions')
->will($this->returnValue(['Version1', 'Version2']));
->willReturn($migratedVersions);

$check = new DoctrineMigration($configuration);
$result = $check->check();

$this->assertInstanceof(FailureInterface::class, $result);
self::assertInstanceof($expectedResult, $result);
}

public function testThrowsExceptionForInvalidInput(): void
{
$this->expectException(\InvalidArgumentException::class);
$this->expectExceptionMessage('Invalid Argument for DoctrineMigration check.');

new DoctrineMigration(new \stdClass());
}

public function provideMigrationTestCases(): iterable
{
yield 'everything migrated' => [
['Version1', 'Version2'],
['Version1', 'Version2'],
SuccessInterface::class
];
yield 'not all migration migrated' => [
['Version1', 'Version2'],
['Version1'],
FailureInterface::class
];
yield 'not existing migration migrated' => [
['Version1'],
['Version1', 'Version2'],
FailureInterface::class
];
}

private function isDoctrineVersion1Installed(): bool
{
return class_exists('\Doctrine\DBAL\Migrations\Configuration\Configuration');
}

private function isDoctrineVersion2Installed(): bool
{
return class_exists('\Doctrine\Migrations\Configuration\Configuration') &&
method_exists('\Doctrine\Migrations\Configuration\Configuration', 'getAvailableVersions') &&
method_exists('\Doctrine\Migrations\Configuration\Configuration', 'getMigratedVersions');
}

private function isDoctrineVersion3Installed(): bool
{
return class_exists(MigrationsRepository::class);
}
}

0 comments on commit 10626e2

Please sign in to comment.