DeclarativeInstallerTest.php 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461
  1. <?php
  2. /**
  3. * Copyright © Magento, Inc. All rights reserved.
  4. * See COPYING.txt for license details.
  5. */
  6. namespace Magento\Setup;
  7. use Magento\Framework\App\ResourceConnection;
  8. use Magento\Framework\Setup\Declaration\Schema\Diff\SchemaDiff;
  9. use Magento\Framework\Setup\Declaration\Schema\SchemaConfigInterface;
  10. use Magento\Framework\Setup\Declaration\Schema\Sharding;
  11. use Magento\TestFramework\Deploy\CliCommand;
  12. use Magento\TestFramework\Deploy\DescribeTable;
  13. use Magento\TestFramework\Deploy\TestModuleManager;
  14. use Magento\TestFramework\Helper\Bootstrap;
  15. use Magento\TestFramework\TestCase\SetupTestCase;
  16. /**
  17. * The purpose of this test is verifying declarative installation works.
  18. */
  19. class DeclarativeInstallerTest extends SetupTestCase
  20. {
  21. /**
  22. * @var TestModuleManager
  23. */
  24. private $moduleManager;
  25. /**
  26. * @var CliCommand
  27. */
  28. private $cliCommand;
  29. /**
  30. * @var SchemaDiff
  31. */
  32. private $schemaDiff;
  33. /**
  34. * @var SchemaConfigInterface
  35. */
  36. private $schemaConfig;
  37. /**
  38. * @var ResourceConnection
  39. */
  40. private $resourceConnection;
  41. /**
  42. * @var DescribeTable
  43. */
  44. private $describeTable;
  45. /**
  46. * @inheritdoc
  47. */
  48. public function setUp()
  49. {
  50. $objectManager = Bootstrap::getObjectManager();
  51. $this->moduleManager = $objectManager->get(TestModuleManager::class);
  52. $this->cliCommand = $objectManager->get(CliCommand::class);
  53. $this->describeTable = $objectManager->get(DescribeTable::class);
  54. $this->schemaDiff = $objectManager->get(SchemaDiff::class);
  55. $this->schemaConfig = $objectManager->get(SchemaConfigInterface::class);
  56. $this->resourceConnection = $objectManager->get(ResourceConnection::class);
  57. }
  58. /**
  59. * @moduleName Magento_TestSetupDeclarationModule1
  60. * @dataProviderFromFile Magento/TestSetupDeclarationModule1/fixture/declarative_installer/installation.php
  61. */
  62. public function testInstallation()
  63. {
  64. $this->cliCommand->install(
  65. ['Magento_TestSetupDeclarationModule1']
  66. );
  67. $diff = $this->schemaDiff->diff(
  68. $this->schemaConfig->getDeclarationConfig(),
  69. $this->schemaConfig->getDbConfig()
  70. );
  71. //Second time installation should not find anything as we do not change anything
  72. self::assertNull($diff->getAll());
  73. $this->compareStructures();
  74. }
  75. /**
  76. * Compare structure of DB and declared structure.
  77. */
  78. private function compareStructures()
  79. {
  80. $shardData = $this->describeTable->describeShard(Sharding::DEFAULT_CONNECTION);
  81. foreach ($this->getTrimmedData() as $tableName => $sql) {
  82. $this->assertArrayHasKey($tableName, $shardData);
  83. /**
  84. * MySQL 8.0 and above does not provide information about the ON DELETE instruction
  85. * if ON DELETE NO ACTION
  86. */
  87. if (preg_match('#ON DELETE\s+NO ACTION#i', $shardData[$tableName] === 1)) {
  88. preg_replace('#ON DELETE\s+NO ACTION#i', '', $sql);
  89. self::assertEquals($sql, $shardData[$tableName]);
  90. }
  91. }
  92. }
  93. /**
  94. * @moduleName Magento_TestSetupDeclarationModule1
  95. * @dataProviderFromFile Magento/TestSetupDeclarationModule1/fixture/declarative_installer/column_modification.php
  96. * @throws \Exception
  97. */
  98. public function testInstallationWithColumnsModification()
  99. {
  100. $this->cliCommand->install(
  101. ['Magento_TestSetupDeclarationModule1']
  102. );
  103. //Move InstallSchema file and tried to install
  104. $this->moduleManager->updateRevision(
  105. 'Magento_TestSetupDeclarationModule1',
  106. 'column_modifications',
  107. 'db_schema.xml',
  108. 'etc'
  109. );
  110. $this->cliCommand->install(
  111. ['Magento_TestSetupDeclarationModule1']
  112. );
  113. $diff = $this->schemaDiff->diff(
  114. $this->schemaConfig->getDeclarationConfig(),
  115. $this->schemaConfig->getDbConfig()
  116. );
  117. self::assertNull($diff->getAll());
  118. $this->compareStructures();
  119. }
  120. /**
  121. * Updates revision for db_schema and db_schema_whitelist files
  122. *
  123. * @param string $revisionName
  124. */
  125. private function updateDbSchemaRevision($revisionName)
  126. {
  127. //Move InstallSchema file and tried to install
  128. $this->moduleManager->updateRevision(
  129. 'Magento_TestSetupDeclarationModule1',
  130. $revisionName,
  131. 'db_schema.xml',
  132. 'etc'
  133. );
  134. //Move InstallSchema file and tried to install
  135. $this->moduleManager->updateRevision(
  136. 'Magento_TestSetupDeclarationModule1',
  137. $revisionName,
  138. 'db_schema_whitelist.json',
  139. 'etc'
  140. );
  141. }
  142. /**
  143. * @moduleName Magento_TestSetupDeclarationModule1
  144. * @dataProviderFromFile Magento/TestSetupDeclarationModule1/fixture/declarative_installer/column_removal.php
  145. * @throws \Exception
  146. */
  147. public function testInstallationWithColumnsRemoval()
  148. {
  149. $this->cliCommand->install(
  150. ['Magento_TestSetupDeclarationModule1']
  151. );
  152. $this->updateDbSchemaRevision('column_removals');
  153. $this->cliCommand->install(
  154. ['Magento_TestSetupDeclarationModule1']
  155. );
  156. $diff = $this->schemaDiff->diff(
  157. $this->schemaConfig->getDeclarationConfig(),
  158. $this->schemaConfig->getDbConfig()
  159. );
  160. self::assertNull($diff->getAll());
  161. $this->compareStructures();
  162. }
  163. /**
  164. * As sometimes we want to ignore spaces and other special characters,
  165. * we need to trim data before compare it
  166. *
  167. * @return array
  168. */
  169. private function getTrimmedData()
  170. {
  171. $data = [];
  172. foreach ($this->getData() as $key => $createTable) {
  173. $data[$key] = preg_replace('/(\s)\n/', '$1', $createTable);
  174. }
  175. return $data;
  176. }
  177. /**
  178. * @moduleName Magento_TestSetupDeclarationModule1
  179. * @dataProviderFromFile Magento/TestSetupDeclarationModule1/fixture/declarative_installer/constraint_modification.php
  180. * @throws \Exception
  181. */
  182. public function testInstallationWithConstraintsModification()
  183. {
  184. $this->cliCommand->install(
  185. ['Magento_TestSetupDeclarationModule1']
  186. );
  187. $this->updateDbSchemaRevision('constraint_modifications');
  188. $this->cliCommand->upgrade();
  189. $diff = $this->schemaDiff->diff(
  190. $this->schemaConfig->getDeclarationConfig(),
  191. $this->schemaConfig->getDbConfig()
  192. );
  193. self::assertNull($diff->getAll());
  194. $shardData = $this->describeTable->describeShard(Sharding::DEFAULT_CONNECTION);
  195. self::assertEquals($this->getTrimmedData(), $shardData);
  196. }
  197. /**
  198. * @moduleName Magento_TestSetupDeclarationModule1
  199. * @dataProviderFromFile Magento/TestSetupDeclarationModule1/fixture/declarative_installer/table_removal.php
  200. * @throws \Exception
  201. */
  202. public function testInstallationWithDroppingTables()
  203. {
  204. $this->cliCommand->install(
  205. ['Magento_TestSetupDeclarationModule1']
  206. );
  207. //Move db_schema.xml file and tried to install
  208. $this->moduleManager->updateRevision(
  209. 'Magento_TestSetupDeclarationModule1',
  210. 'drop_table',
  211. 'db_schema.xml',
  212. 'etc'
  213. );
  214. $this->cliCommand->upgrade();
  215. $diff = $this->schemaDiff->diff(
  216. $this->schemaConfig->getDeclarationConfig(),
  217. $this->schemaConfig->getDbConfig()
  218. );
  219. self::assertNull($diff->getAll());
  220. $shardData = $this->describeTable->describeShard(Sharding::DEFAULT_CONNECTION);
  221. self::assertEquals($this->getData(), $shardData);
  222. }
  223. /**
  224. * @moduleName Magento_TestSetupDeclarationModule1
  225. * @moduleName Magento_TestSetupDeclarationModule3
  226. */
  227. public function testInstallationWithDroppingTablesFromSecondaryModule()
  228. {
  229. $modules = [
  230. 'Magento_TestSetupDeclarationModule1',
  231. 'Magento_TestSetupDeclarationModule3',
  232. ];
  233. $this->moduleManager->updateRevision(
  234. 'Magento_TestSetupDeclarationModule3',
  235. 'drop_table_with_external_dependency',
  236. 'db_schema.xml',
  237. 'etc'
  238. );
  239. foreach ($modules as $moduleName) {
  240. $this->moduleManager->updateRevision(
  241. $moduleName,
  242. 'without_setup_version',
  243. 'module.xml',
  244. 'etc'
  245. );
  246. }
  247. try {
  248. $this->cliCommand->install($modules);
  249. } catch (\Exception $e) {
  250. $installException = $e->getPrevious();
  251. self::assertSame(1, $installException->getCode());
  252. self::assertContains(
  253. 'The reference table named "reference_table" is disabled',
  254. $installException->getMessage()
  255. );
  256. }
  257. }
  258. /**
  259. * @moduleName Magento_TestSetupDeclarationModule1
  260. * @dataProviderFromFile Magento/TestSetupDeclarationModule1/fixture/declarative_installer/rollback.php
  261. * @throws \Exception
  262. */
  263. public function testInstallWithCodeBaseRollback()
  264. {
  265. //Move db_schema.xml file and tried to install
  266. $this->moduleManager->updateRevision(
  267. 'Magento_TestSetupDeclarationModule1',
  268. 'before_rollback',
  269. 'db_schema.xml',
  270. 'etc'
  271. );
  272. $this->cliCommand->install(
  273. ['Magento_TestSetupDeclarationModule1']
  274. );
  275. $beforeRollback = $this->describeTable->describeShard('default');
  276. self::assertEquals($this->getTrimmedData()['before'], $beforeRollback);
  277. //Move db_schema.xml file and tried to install
  278. $this->moduleManager->updateRevision(
  279. 'Magento_TestSetupDeclarationModule1',
  280. 'after_rollback',
  281. 'db_schema.xml',
  282. 'etc'
  283. );
  284. $this->cliCommand->upgrade();
  285. $afterRollback = $this->describeTable->describeShard('default');
  286. self::assertEquals($this->getData()['after'], $afterRollback);
  287. }
  288. /**
  289. * @moduleName Magento_TestSetupDeclarationModule1
  290. * @dataProviderFromFile Magento/TestSetupDeclarationModule1/fixture/declarative_installer/table_rename.php
  291. * @throws \Exception
  292. */
  293. public function testTableRename()
  294. {
  295. $dataToMigrate = ['some_column' => 'Some Value'];
  296. //Move db_schema.xml file and tried to install
  297. $this->moduleManager->updateRevision(
  298. 'Magento_TestSetupDeclarationModule1',
  299. 'table_rename',
  300. 'db_schema.xml',
  301. 'etc'
  302. );
  303. $this->cliCommand->install(
  304. ['Magento_TestSetupDeclarationModule1']
  305. );
  306. $before = $this->describeTable->describeShard('default');
  307. $adapter = $this->resourceConnection->getConnection('default');
  308. $adapter->insert(
  309. $this->resourceConnection->getTableName('some_table'),
  310. $dataToMigrate
  311. );
  312. self::assertEquals($this->getData()['before'], $before['some_table']);
  313. //Move db_schema.xml file and tried to install
  314. $this->moduleManager->updateRevision(
  315. 'Magento_TestSetupDeclarationModule1',
  316. 'table_rename_after',
  317. 'db_schema.xml',
  318. 'etc'
  319. );
  320. $this->cliCommand->upgrade();
  321. $after = $this->describeTable->describeShard('default');
  322. self::assertEquals($this->getData()['after'], $after['some_table_renamed']);
  323. $select = $adapter->select()
  324. ->from($this->resourceConnection->getTableName('some_table_renamed'));
  325. self::assertEquals([$dataToMigrate], $adapter->fetchAll($select));
  326. }
  327. /**
  328. * @moduleName Magento_TestSetupDeclarationModule8
  329. * @throws \Exception
  330. */
  331. public function testForeignKeyReferenceId()
  332. {
  333. $this->cliCommand->install(
  334. ['Magento_TestSetupDeclarationModule8']
  335. );
  336. $this->moduleManager->updateRevision(
  337. 'Magento_TestSetupDeclarationModule8',
  338. 'unpatterned_fk_name',
  339. 'db_schema.xml',
  340. 'etc'
  341. );
  342. $this->cliCommand->upgrade();
  343. $tableStatements = $this->describeTable->describeShard('default');
  344. $tableSql = $tableStatements['dependent'];
  345. $this->assertRegExp('/CONSTRAINT\s`DEPENDENT_PAGE_ID_ON_TEST_TABLE_PAGE_ID`/', $tableSql);
  346. $this->assertRegExp('/CONSTRAINT\s`DEPENDENT_SCOPE_ID_ON_TEST_SCOPE_TABLE_SCOPE_ID`/', $tableSql);
  347. }
  348. /**
  349. * @moduleName Magento_TestSetupDeclarationModule1
  350. * @moduleName Magento_TestSetupDeclarationModule8
  351. * @throws \Exception
  352. */
  353. public function testDisableIndexByExternalModule()
  354. {
  355. $this->cliCommand->install(
  356. ['Magento_TestSetupDeclarationModule1', 'Magento_TestSetupDeclarationModule8']
  357. );
  358. $this->moduleManager->updateRevision(
  359. 'Magento_TestSetupDeclarationModule1',
  360. 'index_to_disable',
  361. 'db_schema.xml',
  362. 'etc'
  363. );
  364. $this->moduleManager->updateRevision(
  365. 'Magento_TestSetupDeclarationModule8',
  366. 'disable_index_by_external_module',
  367. 'db_schema.xml',
  368. 'etc'
  369. );
  370. $this->moduleManager->updateRevision(
  371. 'Magento_TestSetupDeclarationModule8',
  372. 'disable_index_by_external_module',
  373. 'db_schema_whitelist.json',
  374. 'etc'
  375. );
  376. $this->moduleManager->updateRevision(
  377. 'Magento_TestSetupDeclarationModule8',
  378. 'disable_index_by_external_module',
  379. 'module.xml',
  380. 'etc'
  381. );
  382. $this->cliCommand->upgrade();
  383. $tableStatements = $this->describeTable->describeShard('default');
  384. $tableSql = $tableStatements['test_table'];
  385. $this->assertNotRegExp(
  386. '/KEY\s+`TEST_TABLE_VARCHAR`\s+\(`varchar`\)/',
  387. $tableSql,
  388. 'Index is not being disabled by external module'
  389. );
  390. }
  391. /**
  392. * @moduleName Magento_TestSetupDeclarationModule8
  393. * @moduleName Magento_TestSetupDeclarationModule9
  394. * @dataProviderFromFile Magento/TestSetupDeclarationModule9/fixture/declarative_installer/disabling_tables.php
  395. * @throws \Exception
  396. */
  397. public function testInstallationWithDisablingTables()
  398. {
  399. $modules = [
  400. 'Magento_TestSetupDeclarationModule8',
  401. 'Magento_TestSetupDeclarationModule9',
  402. ];
  403. foreach ($modules as $moduleName) {
  404. $this->moduleManager->updateRevision(
  405. $moduleName,
  406. 'disabling_tables',
  407. 'db_schema.xml',
  408. 'etc'
  409. );
  410. }
  411. $this->cliCommand->install($modules);
  412. $diff = $this->schemaDiff->diff(
  413. $this->schemaConfig->getDeclarationConfig(),
  414. $this->schemaConfig->getDbConfig()
  415. );
  416. self::assertNull($diff->getAll());
  417. $shardData = $this->describeTable->describeShard(Sharding::DEFAULT_CONNECTION);
  418. self::assertEquals($this->getData(), $shardData);
  419. }
  420. }