Skip to content

Commit

Permalink
Merge de83aa9 into 812873f
Browse files Browse the repository at this point in the history
  • Loading branch information
cgrabenstein committed Jan 16, 2021
2 parents 812873f + de83aa9 commit 1f45d99
Show file tree
Hide file tree
Showing 3 changed files with 198 additions and 42 deletions.
2 changes: 1 addition & 1 deletion composer.json
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
68 changes: 57 additions & 11 deletions src/Check/DoctrineMigration.php
Expand Up @@ -8,24 +8,54 @@

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 +65,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());
}
}
170 changes: 140 additions & 30 deletions test/DoctrineMigrationTest.php
Expand Up @@ -8,77 +8,187 @@

namespace LaminasTest\Diagnostics;

use Doctrine\Migrations\Configuration\Configuration;
use Doctrine\Migrations\AbstractMigration;
use Doctrine\Migrations\DependencyFactory;
use Doctrine\Migrations\Metadata\AvailableMigration;
use Doctrine\Migrations\Metadata\AvailableMigrationsSet;
use Doctrine\Migrations\Metadata\ExecutedMigration;
use Doctrine\Migrations\Metadata\ExecutedMigrationsList;
use Doctrine\Migrations\Metadata\Storage\MetadataStorage;
use Doctrine\Migrations\MigrationsRepository;
use Doctrine\Migrations\Version\Version;
use Generator;
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
) {
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']));
$migrationMock = $this->createMock(AbstractMigration::class);
$availableMigrations = array_map(static function ($version) use ($migrationMock) {
return new AvailableMigration(new Version($version), $migrationMock);
}, $availableVersions);

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

$check = new DoctrineMigration($configuration);
$metadataStorage = $this->getMockBuilder(MetadataStorage::class)
->disableOriginalConstructor()
->getMock();

$executedMigrations = array_map(static function ($version) {
return new ExecutedMigration(new Version($version));
}, $migratedVersions);

$metadataStorage
->expects(self::once())
->method('getExecutedMigrations')
->willReturn(new ExecutedMigrationsList($executedMigrations));

$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
) {
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
) {
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()
{
$this->expectException(\InvalidArgumentException::class);
$this->expectExceptionMessage('Invalid Argument for DoctrineMigration check.');

new DoctrineMigration(new \stdClass());
}

public function provideMigrationTestCases()
{
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()
{
return class_exists('\Doctrine\DBAL\Migrations\Configuration\Configuration');
}

private function isDoctrineVersion2Installed()
{
return class_exists('\Doctrine\Migrations\Configuration\Configuration') &&
! class_exists('\Doctrine\DBAL\Migrations\Configuration\Configuration') &&
! interface_exists(MigrationsRepository::class);
}

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

0 comments on commit 1f45d99

Please sign in to comment.