493 lines
		
	
	
		
			16 KiB
		
	
	
	
		
			PHP
		
	
	
		
			Executable File
		
	
	
			
		
		
	
	
			493 lines
		
	
	
		
			16 KiB
		
	
	
	
		
			PHP
		
	
	
		
			Executable File
		
	
	
<?php
 | 
						|
/**
 | 
						|
 * Copyright © Magento, Inc. All rights reserved.
 | 
						|
 * See COPYING.txt for license details.
 | 
						|
 */
 | 
						|
 | 
						|
namespace Magento\Setup;
 | 
						|
 | 
						|
use Magento\Framework\App\ResourceConnection;
 | 
						|
use Magento\Framework\Setup\Declaration\Schema\Diff\SchemaDiff;
 | 
						|
use Magento\Framework\Setup\Declaration\Schema\SchemaConfigInterface;
 | 
						|
use Magento\Framework\Setup\Declaration\Schema\Sharding;
 | 
						|
use Magento\TestFramework\Deploy\CliCommand;
 | 
						|
use Magento\TestFramework\Deploy\DescribeTable;
 | 
						|
use Magento\TestFramework\Deploy\TestModuleManager;
 | 
						|
use Magento\TestFramework\Helper\Bootstrap;
 | 
						|
use Magento\TestFramework\TestCase\SetupTestCase;
 | 
						|
 | 
						|
/**
 | 
						|
 * The purpose of this test is verifying declarative installation works.
 | 
						|
 */
 | 
						|
class DeclarativeInstallerTest extends SetupTestCase
 | 
						|
{
 | 
						|
    /**
 | 
						|
     * @var  TestModuleManager
 | 
						|
     */
 | 
						|
    private $moduleManager;
 | 
						|
 | 
						|
    /**
 | 
						|
     * @var CliCommand
 | 
						|
     */
 | 
						|
    private $cliCommand;
 | 
						|
 | 
						|
    /**
 | 
						|
     * @var SchemaDiff
 | 
						|
     */
 | 
						|
    private $schemaDiff;
 | 
						|
 | 
						|
    /**
 | 
						|
     * @var SchemaConfigInterface
 | 
						|
     */
 | 
						|
    private $schemaConfig;
 | 
						|
 | 
						|
    /**
 | 
						|
     * @var ResourceConnection
 | 
						|
     */
 | 
						|
    private $resourceConnection;
 | 
						|
 | 
						|
    /**
 | 
						|
     * @var DescribeTable
 | 
						|
     */
 | 
						|
    private $describeTable;
 | 
						|
 | 
						|
    /**
 | 
						|
     * @inheritdoc
 | 
						|
     */
 | 
						|
    protected function setUp(): void
 | 
						|
    {
 | 
						|
        $objectManager = Bootstrap::getObjectManager();
 | 
						|
        $this->moduleManager = $objectManager->get(TestModuleManager::class);
 | 
						|
        $this->cliCommand = $objectManager->get(CliCommand::class);
 | 
						|
        $this->describeTable = $objectManager->get(DescribeTable::class);
 | 
						|
        $this->schemaDiff = $objectManager->get(SchemaDiff::class);
 | 
						|
        $this->schemaConfig = $objectManager->get(SchemaConfigInterface::class);
 | 
						|
        $this->resourceConnection = $objectManager->get(ResourceConnection::class);
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * @moduleName Magento_TestSetupDeclarationModule1
 | 
						|
     * @dataProviderFromFile Magento/TestSetupDeclarationModule1/fixture/declarative_installer/installation.php
 | 
						|
     */
 | 
						|
    public function testInstallation()
 | 
						|
    {
 | 
						|
        $this->cliCommand->install(
 | 
						|
            ['Magento_TestSetupDeclarationModule1']
 | 
						|
        );
 | 
						|
 | 
						|
        $diff = $this->schemaDiff->diff(
 | 
						|
            $this->schemaConfig->getDeclarationConfig(),
 | 
						|
            $this->schemaConfig->getDbConfig()
 | 
						|
        );
 | 
						|
 | 
						|
        //Second time installation should not find anything as we do not change anything
 | 
						|
        self::assertNull($diff->getAll());
 | 
						|
        $this->compareStructures();
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Compare structure of DB and declared structure.
 | 
						|
     */
 | 
						|
    private function compareStructures()
 | 
						|
    {
 | 
						|
        $shardData = $this->describeTable->describeShard(Sharding::DEFAULT_CONNECTION);
 | 
						|
        foreach ($this->getTrimmedData() as $tableName => $sql) {
 | 
						|
            $this->assertArrayHasKey($tableName, $shardData);
 | 
						|
            /**
 | 
						|
             * MySQL 8.0 and above does not provide information about the ON DELETE instruction
 | 
						|
             * if ON DELETE NO ACTION
 | 
						|
             */
 | 
						|
            if (preg_match('#ON DELETE\s+NO ACTION#i', $shardData[$tableName] === 1)) {
 | 
						|
                preg_replace('#ON DELETE\s+NO ACTION#i', '', $sql);
 | 
						|
                self::assertEquals($sql, $shardData[$tableName]);
 | 
						|
            }
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * @moduleName Magento_TestSetupDeclarationModule1
 | 
						|
     * @dataProviderFromFile Magento/TestSetupDeclarationModule1/fixture/declarative_installer/column_modification.php
 | 
						|
     * @throws \Exception
 | 
						|
     */
 | 
						|
    public function testInstallationWithColumnsModification()
 | 
						|
    {
 | 
						|
        $this->cliCommand->install(
 | 
						|
            ['Magento_TestSetupDeclarationModule1']
 | 
						|
        );
 | 
						|
 | 
						|
        //Move InstallSchema file and tried to install
 | 
						|
        $this->moduleManager->updateRevision(
 | 
						|
            'Magento_TestSetupDeclarationModule1',
 | 
						|
            'column_modifications',
 | 
						|
            'db_schema.xml',
 | 
						|
            'etc'
 | 
						|
        );
 | 
						|
 | 
						|
        $this->cliCommand->install(
 | 
						|
            ['Magento_TestSetupDeclarationModule1']
 | 
						|
        );
 | 
						|
 | 
						|
        $diff = $this->schemaDiff->diff(
 | 
						|
            $this->schemaConfig->getDeclarationConfig(),
 | 
						|
            $this->schemaConfig->getDbConfig()
 | 
						|
        );
 | 
						|
        self::assertNull($diff->getAll());
 | 
						|
        $this->compareStructures();
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Updates revision for db_schema and db_schema_whitelist files
 | 
						|
     *
 | 
						|
     * @param string $revisionName
 | 
						|
     */
 | 
						|
    private function updateDbSchemaRevision($revisionName)
 | 
						|
    {
 | 
						|
        //Move InstallSchema file and tried to install
 | 
						|
        $this->moduleManager->updateRevision(
 | 
						|
            'Magento_TestSetupDeclarationModule1',
 | 
						|
            $revisionName,
 | 
						|
            'db_schema.xml',
 | 
						|
            'etc'
 | 
						|
        );
 | 
						|
        //Move InstallSchema file and tried to install
 | 
						|
        $this->moduleManager->updateRevision(
 | 
						|
            'Magento_TestSetupDeclarationModule1',
 | 
						|
            $revisionName,
 | 
						|
            'db_schema_whitelist.json',
 | 
						|
            'etc'
 | 
						|
        );
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * @moduleName Magento_TestSetupDeclarationModule1
 | 
						|
     * @dataProviderFromFile Magento/TestSetupDeclarationModule1/fixture/declarative_installer/column_removal.php
 | 
						|
     * @throws \Exception
 | 
						|
     */
 | 
						|
    public function testInstallationWithColumnsRemoval()
 | 
						|
    {
 | 
						|
        $this->cliCommand->install(
 | 
						|
            ['Magento_TestSetupDeclarationModule1']
 | 
						|
        );
 | 
						|
        $this->updateDbSchemaRevision('column_removals');
 | 
						|
        $this->cliCommand->install(
 | 
						|
            ['Magento_TestSetupDeclarationModule1']
 | 
						|
        );
 | 
						|
 | 
						|
        $diff = $this->schemaDiff->diff(
 | 
						|
            $this->schemaConfig->getDeclarationConfig(),
 | 
						|
            $this->schemaConfig->getDbConfig()
 | 
						|
        );
 | 
						|
        self::assertNull($diff->getAll());
 | 
						|
        $this->compareStructures();
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * As sometimes we want to ignore spaces and other special characters,
 | 
						|
     * we need to trim data before compare it
 | 
						|
     *
 | 
						|
     * @return array
 | 
						|
     */
 | 
						|
    private function getTrimmedData()
 | 
						|
    {
 | 
						|
        $data = [];
 | 
						|
        foreach ($this->getData() as $key => $createTable) {
 | 
						|
            $data[$key] = preg_replace('/(\s)\n/', '$1', $createTable);
 | 
						|
        }
 | 
						|
 | 
						|
        return $data;
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * @moduleName Magento_TestSetupDeclarationModule1
 | 
						|
     * @dataProviderFromFile Magento/TestSetupDeclarationModule1/fixture/declarative_installer/constraint_modification.php
 | 
						|
     * @throws \Exception
 | 
						|
     */
 | 
						|
    public function testInstallationWithConstraintsModification()
 | 
						|
    {
 | 
						|
        $this->cliCommand->install(
 | 
						|
            ['Magento_TestSetupDeclarationModule1']
 | 
						|
        );
 | 
						|
        $this->updateDbSchemaRevision('constraint_modifications');
 | 
						|
        $this->cliCommand->upgrade();
 | 
						|
 | 
						|
        $diff = $this->schemaDiff->diff(
 | 
						|
            $this->schemaConfig->getDeclarationConfig(),
 | 
						|
            $this->schemaConfig->getDbConfig()
 | 
						|
        );
 | 
						|
        self::assertNull($diff->getAll());
 | 
						|
        $shardData = $this->describeTable->describeShard(Sharding::DEFAULT_CONNECTION);
 | 
						|
        $this->assertTableCreationStatements($this->getTrimmedData(), $shardData);
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * @moduleName Magento_TestSetupDeclarationModule1
 | 
						|
     * @dataProviderFromFile Magento/TestSetupDeclarationModule1/fixture/declarative_installer/table_removal.php
 | 
						|
     * @throws \Exception
 | 
						|
     */
 | 
						|
    public function testInstallationWithDroppingTables()
 | 
						|
    {
 | 
						|
        $this->cliCommand->install(
 | 
						|
            ['Magento_TestSetupDeclarationModule1']
 | 
						|
        );
 | 
						|
 | 
						|
        //Move db_schema.xml file and tried to install
 | 
						|
        $this->moduleManager->updateRevision(
 | 
						|
            'Magento_TestSetupDeclarationModule1',
 | 
						|
            'drop_table',
 | 
						|
            'db_schema.xml',
 | 
						|
            'etc'
 | 
						|
        );
 | 
						|
 | 
						|
        $this->cliCommand->upgrade();
 | 
						|
 | 
						|
        $diff = $this->schemaDiff->diff(
 | 
						|
            $this->schemaConfig->getDeclarationConfig(),
 | 
						|
            $this->schemaConfig->getDbConfig()
 | 
						|
        );
 | 
						|
        self::assertNull($diff->getAll());
 | 
						|
        $shardData = $this->describeTable->describeShard(Sharding::DEFAULT_CONNECTION);
 | 
						|
        $this->assertTableCreationStatements($this->getData(), $shardData);
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * @moduleName Magento_TestSetupDeclarationModule1
 | 
						|
     * @moduleName Magento_TestSetupDeclarationModule3
 | 
						|
     */
 | 
						|
    public function testInstallationWithDroppingTablesFromSecondaryModule()
 | 
						|
    {
 | 
						|
        $modules = [
 | 
						|
            'Magento_TestSetupDeclarationModule1',
 | 
						|
            'Magento_TestSetupDeclarationModule3',
 | 
						|
        ];
 | 
						|
 | 
						|
        $this->moduleManager->updateRevision(
 | 
						|
            'Magento_TestSetupDeclarationModule3',
 | 
						|
            'drop_table_with_external_dependency',
 | 
						|
            'db_schema.xml',
 | 
						|
            'etc'
 | 
						|
        );
 | 
						|
 | 
						|
        foreach ($modules as $moduleName) {
 | 
						|
            $this->moduleManager->updateRevision(
 | 
						|
                $moduleName,
 | 
						|
                'without_setup_version',
 | 
						|
                'module.xml',
 | 
						|
                'etc'
 | 
						|
            );
 | 
						|
        }
 | 
						|
 | 
						|
        try {
 | 
						|
            $this->cliCommand->install($modules);
 | 
						|
        } catch (\Exception $e) {
 | 
						|
            $installException = $e->getPrevious();
 | 
						|
            self::assertSame(1, $installException->getCode());
 | 
						|
            self::assertStringContainsString(
 | 
						|
                'The reference table named "reference_table" is disabled',
 | 
						|
                $installException->getMessage()
 | 
						|
            );
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * @moduleName Magento_TestSetupDeclarationModule1
 | 
						|
     * @dataProviderFromFile Magento/TestSetupDeclarationModule1/fixture/declarative_installer/rollback.php
 | 
						|
     * @throws \Exception
 | 
						|
     */
 | 
						|
    public function testInstallWithCodeBaseRollback()
 | 
						|
    {
 | 
						|
        //Move db_schema.xml file and tried to install
 | 
						|
        $this->moduleManager->updateRevision(
 | 
						|
            'Magento_TestSetupDeclarationModule1',
 | 
						|
            'before_rollback',
 | 
						|
            'db_schema.xml',
 | 
						|
            'etc'
 | 
						|
        );
 | 
						|
        $this->cliCommand->install(
 | 
						|
            ['Magento_TestSetupDeclarationModule1']
 | 
						|
        );
 | 
						|
 | 
						|
        if ($this->isUsingAuroraDb()) {
 | 
						|
            $this->markTestSkipped('Test skipped in AWS Aurora');
 | 
						|
        }
 | 
						|
        $beforeRollback = $this->describeTable->describeShard('default');
 | 
						|
        self::assertEquals($this->getTrimmedData()['before'], $beforeRollback);
 | 
						|
        //Move db_schema.xml file and tried to install
 | 
						|
        $this->moduleManager->updateRevision(
 | 
						|
            'Magento_TestSetupDeclarationModule1',
 | 
						|
            'after_rollback',
 | 
						|
            'db_schema.xml',
 | 
						|
            'etc'
 | 
						|
        );
 | 
						|
 | 
						|
        $this->cliCommand->upgrade();
 | 
						|
        $afterRollback = $this->describeTable->describeShard('default');
 | 
						|
        self::assertEquals($this->getData()['after'], $afterRollback);
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * @moduleName Magento_TestSetupDeclarationModule1
 | 
						|
     * @dataProviderFromFile Magento/TestSetupDeclarationModule1/fixture/declarative_installer/table_rename.php
 | 
						|
     * @throws \Exception
 | 
						|
     */
 | 
						|
    public function testTableRename()
 | 
						|
    {
 | 
						|
        $dataToMigrate = ['some_column' => 'Some Value'];
 | 
						|
        //Move db_schema.xml file and tried to install
 | 
						|
        $this->moduleManager->updateRevision(
 | 
						|
            'Magento_TestSetupDeclarationModule1',
 | 
						|
            'table_rename',
 | 
						|
            'db_schema.xml',
 | 
						|
            'etc'
 | 
						|
        );
 | 
						|
        $this->cliCommand->install(
 | 
						|
            ['Magento_TestSetupDeclarationModule1']
 | 
						|
        );
 | 
						|
        $before = $this->describeTable->describeShard('default');
 | 
						|
        $adapter = $this->resourceConnection->getConnection('default');
 | 
						|
        $adapter->insert(
 | 
						|
            $this->resourceConnection->getTableName('some_table'),
 | 
						|
            $dataToMigrate
 | 
						|
        );
 | 
						|
        $this->isUsingAuroraDb() ?
 | 
						|
            $this->assertStringContainsString($before['some_table'], $this->getTrimmedData()['before']) :
 | 
						|
            $this->assertEquals($this->getData()['before'], $before['some_table']);
 | 
						|
        //Move db_schema.xml file and tried to install
 | 
						|
        $this->moduleManager->updateRevision(
 | 
						|
            'Magento_TestSetupDeclarationModule1',
 | 
						|
            'table_rename_after',
 | 
						|
            'db_schema.xml',
 | 
						|
            'etc'
 | 
						|
        );
 | 
						|
 | 
						|
        $this->cliCommand->upgrade();
 | 
						|
        $after = $this->describeTable->describeShard('default');
 | 
						|
        $this->isUsingAuroraDb() ?
 | 
						|
            $this->assertStringContainsString($after['some_table_renamed'], $this->getTrimmedData()['after']) :
 | 
						|
            $this->assertEquals($this->getData()['after'], $after['some_table_renamed']);
 | 
						|
        $select = $adapter->select()
 | 
						|
            ->from($this->resourceConnection->getTableName('some_table_renamed'));
 | 
						|
        self::assertEquals([$dataToMigrate], $adapter->fetchAll($select));
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * @moduleName Magento_TestSetupDeclarationModule8
 | 
						|
     * @throws \Exception
 | 
						|
     */
 | 
						|
    public function testForeignKeyReferenceId()
 | 
						|
    {
 | 
						|
        $this->cliCommand->install(
 | 
						|
            ['Magento_TestSetupDeclarationModule8']
 | 
						|
        );
 | 
						|
        $this->moduleManager->updateRevision(
 | 
						|
            'Magento_TestSetupDeclarationModule8',
 | 
						|
            'unpatterned_fk_name',
 | 
						|
            'db_schema.xml',
 | 
						|
            'etc'
 | 
						|
        );
 | 
						|
        $this->cliCommand->upgrade();
 | 
						|
        $tableStatements = $this->describeTable->describeShard('default');
 | 
						|
        $tableSql = $tableStatements['dependent'];
 | 
						|
        $this->assertMatchesRegularExpression('/CONSTRAINT\s`DEPENDENT_PAGE_ID_ON_TEST_TABLE_PAGE_ID`/', $tableSql);
 | 
						|
        $this->assertMatchesRegularExpression(
 | 
						|
            '/CONSTRAINT\s`DEPENDENT_SCOPE_ID_ON_TEST_SCOPE_TABLE_SCOPE_ID`/',
 | 
						|
            $tableSql
 | 
						|
        );
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * @moduleName Magento_TestSetupDeclarationModule1
 | 
						|
     * @moduleName Magento_TestSetupDeclarationModule8
 | 
						|
     * @throws \Exception
 | 
						|
     */
 | 
						|
    public function testDisableIndexByExternalModule()
 | 
						|
    {
 | 
						|
        $this->cliCommand->install(
 | 
						|
            ['Magento_TestSetupDeclarationModule1', 'Magento_TestSetupDeclarationModule8']
 | 
						|
        );
 | 
						|
        $this->moduleManager->updateRevision(
 | 
						|
            'Magento_TestSetupDeclarationModule1',
 | 
						|
            'index_to_disable',
 | 
						|
            'db_schema.xml',
 | 
						|
            'etc'
 | 
						|
        );
 | 
						|
        $this->moduleManager->updateRevision(
 | 
						|
            'Magento_TestSetupDeclarationModule8',
 | 
						|
            'disable_index_by_external_module',
 | 
						|
            'db_schema.xml',
 | 
						|
            'etc'
 | 
						|
        );
 | 
						|
        $this->moduleManager->updateRevision(
 | 
						|
            'Magento_TestSetupDeclarationModule8',
 | 
						|
            'disable_index_by_external_module',
 | 
						|
            'db_schema_whitelist.json',
 | 
						|
            'etc'
 | 
						|
        );
 | 
						|
        $this->moduleManager->updateRevision(
 | 
						|
            'Magento_TestSetupDeclarationModule8',
 | 
						|
            'disable_index_by_external_module',
 | 
						|
            'module.xml',
 | 
						|
            'etc'
 | 
						|
        );
 | 
						|
        $this->cliCommand->upgrade();
 | 
						|
        $tableStatements = $this->describeTable->describeShard('default');
 | 
						|
        $tableSql = $tableStatements['test_table'];
 | 
						|
        $this->assertDoesNotMatchRegularExpression(
 | 
						|
            '/KEY\s+`TEST_TABLE_VARCHAR`\s+\(`varchar`\)/',
 | 
						|
            $tableSql,
 | 
						|
            'Index is not being disabled by external module'
 | 
						|
        );
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * @moduleName Magento_TestSetupDeclarationModule8
 | 
						|
     * @moduleName Magento_TestSetupDeclarationModule9
 | 
						|
     * @dataProviderFromFile Magento/TestSetupDeclarationModule9/fixture/declarative_installer/disabling_tables.php
 | 
						|
     * @throws \Exception
 | 
						|
     */
 | 
						|
    public function testInstallationWithDisablingTables()
 | 
						|
    {
 | 
						|
        $modules = [
 | 
						|
            'Magento_TestSetupDeclarationModule8',
 | 
						|
            'Magento_TestSetupDeclarationModule9',
 | 
						|
        ];
 | 
						|
 | 
						|
        foreach ($modules as $moduleName) {
 | 
						|
            $this->moduleManager->updateRevision(
 | 
						|
                $moduleName,
 | 
						|
                'disabling_tables',
 | 
						|
                'db_schema.xml',
 | 
						|
                'etc'
 | 
						|
            );
 | 
						|
        }
 | 
						|
        $this->cliCommand->install($modules);
 | 
						|
 | 
						|
        $diff = $this->schemaDiff->diff(
 | 
						|
            $this->schemaConfig->getDeclarationConfig(),
 | 
						|
            $this->schemaConfig->getDbConfig()
 | 
						|
        );
 | 
						|
        self::assertNull($diff->getAll());
 | 
						|
        $shardData = $this->describeTable->describeShard(Sharding::DEFAULT_CONNECTION);
 | 
						|
        $this->assertTableCreationStatements($this->getData(), $shardData);
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Assert table creation statements
 | 
						|
     *
 | 
						|
     * @param array $expectedData
 | 
						|
     * @param array $actualData
 | 
						|
     */
 | 
						|
    private function assertTableCreationStatements(array $expectedData, array $actualData): void
 | 
						|
    {
 | 
						|
        if (!$this->isUsingAuroraDb()) {
 | 
						|
            $this->assertEquals($expectedData, $actualData);
 | 
						|
        } else {
 | 
						|
            ksort($expectedData);
 | 
						|
            ksort($actualData);
 | 
						|
            $this->assertSameSize($expectedData, $actualData);
 | 
						|
            foreach ($expectedData as $key => $value) {
 | 
						|
                $this->assertStringContainsString($actualData[$key], $value);
 | 
						|
            }
 | 
						|
        }
 | 
						|
    }
 | 
						|
}
 |