PageRenderTime 56ms CodeModel.GetById 22ms RepoModel.GetById 1ms app.codeStats 0ms

/Test/Case/Console/Command/MigrationShellTest.php

http://github.com/CakeDC/migrations
PHP | 1094 lines | 796 code | 104 blank | 194 comment | 3 complexity | 111a3b8772c92212625c3b39990ebe72 MD5 | raw file
  1. <?php
  2. /**
  3. * Copyright 2009 - 2014, Cake Development Corporation (http://cakedc.com)
  4. *
  5. * Licensed under The MIT License
  6. * Redistributions of files must retain the above copyright notice.
  7. *
  8. * @copyright Copyright 2009 - 2014, Cake Development Corporation (http://cakedc.com)
  9. * @license MIT License (http://www.opensource.org/licenses/mit-license.php)
  10. */
  11. App::uses('ShellDispatcher', 'Console');
  12. App::uses('MigrationShell', 'Migrations.Console/Command');
  13. /**
  14. * TestMigrationShell
  15. */
  16. class TestMigrationShell extends MigrationShell {
  17. /**
  18. * Output property
  19. *
  20. * @var string
  21. */
  22. public $output = '';
  23. /**
  24. * Out method
  25. *
  26. * @param $string
  27. * @return void
  28. */
  29. public function out($message = null, $newlines = 1, $level = 1) {
  30. $this->output .= $message . "\n";
  31. }
  32. /**
  33. * FromComparison method
  34. *
  35. * @param $migration
  36. * @param $comparison
  37. * @param $oldTables
  38. * @param $currentTables
  39. * @return void
  40. */
  41. public function fromComparison($migration, $comparison, $oldTables, $currentTables) {
  42. return $this->_fromComparison($migration, $comparison, $oldTables, $currentTables);
  43. }
  44. /**
  45. * WriteMigration method
  46. *
  47. * @param $name
  48. * @param $class
  49. * @param $migration
  50. * @return void
  51. */
  52. public function writeMigration($name, $class, $migration) {
  53. return $this->_writeMigration($name, $class, $migration);
  54. }
  55. }
  56. /**
  57. * MigrationShellTest
  58. */
  59. class MigrationShellTest extends CakeTestCase {
  60. /**
  61. * Fixtures property
  62. *
  63. * @var array
  64. */
  65. public $fixtures = array('plugin.migrations.schema_migrations', 'core.article', 'core.post', 'core.user');
  66. /**
  67. * SetUp method
  68. *
  69. * @return void
  70. */
  71. public function setUp() {
  72. parent::setUp();
  73. $out = $this->getMock('ConsoleOutput', array(), array(), '', false);
  74. $in = $this->getMock('ConsoleInput', array(), array(), '', false);
  75. $this->Shell = $this->getMock(
  76. 'TestMigrationShell',
  77. array('in', 'hr', 'createFile', 'error', 'err', '_stop', '_showInfo', 'dispatchShell'),
  78. array($out, $out, $in));
  79. $this->Shell->Version = $this->getMock(
  80. 'MigrationVersion',
  81. array('getMapping', 'getVersion', 'run'),
  82. array(array('connection' => 'test')));
  83. $this->Shell->type = 'TestMigrationPlugin';
  84. $this->Shell->path = TMP . 'tests' . DS;
  85. $this->Shell->connection = 'test';
  86. $plugins = $this->plugins = App::path('plugins');
  87. $plugins[] = dirname(dirname(dirname(dirname(__FILE__)))) . DS . 'test_app' . DS . 'Plugin' . DS;
  88. App::build(array('Plugin' => $plugins), true);
  89. App::objects('plugins', null, false);
  90. CakePlugin::load('TestMigrationPlugin');
  91. CakePlugin::load('TestMigrationPlugin2');
  92. CakePlugin::load('TestMigrationPlugin3');
  93. CakePlugin::load('TestMigrationPlugin4');
  94. Configure::write('Config.language', 'en');
  95. }
  96. /**
  97. * TearDown method
  98. *
  99. * @return void
  100. */
  101. public function tearDown() {
  102. parent::tearDown();
  103. CakePlugin::unload('TestMigrationPlugin');
  104. CakePlugin::unload('TestMigrationPlugin2');
  105. CakePlugin::unload('TestMigrationPlugin3');
  106. CakePlugin::unload('TestMigrationPlugin4');
  107. App::build(array('Plugin' => $this->plugins), true);
  108. App::objects('plugins', null, false);
  109. unset($this->Dispatcher, $this->Shell, $this->plugins);
  110. $this->_unlink(glob(TMP . 'tests' . DS . '*.php'));
  111. }
  112. /**
  113. * Tables property
  114. *
  115. * @var array
  116. */
  117. public $tables = array(
  118. 'users' => array(
  119. 'id' => array('type' => 'integer', 'key' => 'primary'),
  120. 'user' => array('type' => 'string', 'null' => false),
  121. 'password' => array('type' => 'string', 'null' => false),
  122. 'created' => 'datetime',
  123. 'updated' => 'datetime'
  124. ),
  125. 'posts' => array(
  126. 'id' => array('type' => 'integer', 'key' => 'primary'),
  127. 'author_id' => array('type' => 'integer', 'null' => false),
  128. 'title' => array('type' => 'string', 'null' => false),
  129. 'body' => 'text',
  130. 'published' => array('type' => 'string', 'length' => 1, 'default' => 'N'),
  131. 'created' => 'datetime',
  132. 'updated' => 'datetime'
  133. )
  134. );
  135. /**
  136. * TestStartup method
  137. *
  138. * @return void
  139. */
  140. public function testStartup() {
  141. $this->Shell->connection = 'default';
  142. $this->assertEquals($this->Shell->type, 'TestMigrationPlugin');
  143. $this->Shell->params = array(
  144. 'connection' => 'test',
  145. 'name' => 'MigrationName',
  146. 'plugin' => 'Migrations',
  147. 'no-auto-init' => false,
  148. 'dry' => false,
  149. 'skip' => 'test1',
  150. 'precheck' => 'Migrations.PrecheckException'
  151. );
  152. $this->Shell->startup();
  153. $this->assertEquals($this->Shell->migrationName, 'MigrationName');
  154. $this->assertEquals($this->Shell->connection, 'test');
  155. $this->assertEquals($this->Shell->type, 'Migrations');
  156. $this->assertEquals($this->Shell->skip, 'test1');
  157. $this->Shell->expects($this->any())->method('in')->will($this->returnValue('test'));
  158. $this->Shell->expects($this->any())->method('_startMigrationConnection')->will($this->returnValue('test'));
  159. $this->Shell->startup();
  160. $this->assertEquals($this->Shell->migrationConnection, 'test');
  161. }
  162. /**
  163. * TestRun method
  164. *
  165. * @return void
  166. */
  167. public function testRun() {
  168. $mapping = array();
  169. for ($i = 1; $i <= 10; $i++) {
  170. $mapping[$i] = array(
  171. 'version' => $i, 'name' => '001_schema_dump',
  172. 'class' => 'M4af9d151e1484b74ad9d007058157726',
  173. 'type' => $this->Shell->type, 'migrated' => null
  174. );
  175. }
  176. $this->Shell->expects($this->any())->method('_stop')->will($this->returnValue(false));
  177. // cake migration run - no mapping
  178. $this->Shell->Version->expects($this->at(0))->method('getMapping')->will($this->returnValue(false));
  179. $this->Shell->args = array();
  180. $this->assertFalse($this->Shell->run());
  181. // cake migration run up
  182. $this->Shell->Version->expects($this->any())->method('getMapping')->will($this->returnValue($mapping));
  183. $this->Shell->Version->expects($this->at(1))->method('getVersion')->will($this->returnValue(0));
  184. $this->Shell->Version->expects($this->at(2))->method('run')->with($this->equalTo(array(
  185. 'type' => 'TestMigrationPlugin',
  186. 'callback' => $this->Shell,
  187. 'direction' => 'up',
  188. 'version' => 1,
  189. 'dry' => false,
  190. 'precheck' => null,
  191. 'skip' => array()))
  192. );
  193. $this->Shell->args = array('up');
  194. $this->assertTrue($this->Shell->run());
  195. // cake migration run up - on last version == stop
  196. $this->Shell->Version->expects($this->at(1))->method('getVersion')->will($this->returnValue(10));
  197. $this->Shell->args = array('up');
  198. $this->assertFalse($this->Shell->run());
  199. // cake migration run down - on version 0 == stop
  200. $this->Shell->Version->expects($this->at(1))->method('getVersion')->will($this->returnValue(0));
  201. $this->Shell->args = array('down');
  202. $this->assertFalse($this->Shell->run());
  203. // cake migration run down
  204. $this->Shell->Version->expects($this->at(1))->method('getVersion')->will($this->returnValue(1));
  205. $this->Shell->Version->expects($this->at(2))->method('run')->with($this->equalTo(array(
  206. 'type' => 'TestMigrationPlugin',
  207. 'callback' => $this->Shell,
  208. 'direction' => 'down',
  209. 'version' => 1,
  210. 'dry' => false,
  211. 'precheck' => null,
  212. 'skip' => array()))
  213. );
  214. $this->Shell->args = array('down');
  215. $this->assertTrue($this->Shell->run());
  216. // cake migration run all
  217. $this->Shell->Version->expects($this->at(1))->method('getVersion')->will($this->returnValue(1));
  218. $this->Shell->Version->expects($this->at(2))->method('run')->with($this->equalTo(array(
  219. 'type' => 'TestMigrationPlugin',
  220. 'callback' => $this->Shell,
  221. 'version' => 10,
  222. 'direction' => 'up',
  223. 'dry' => false,
  224. 'precheck' => null,
  225. 'skip' => array())));
  226. $this->Shell->args = array('all');
  227. $this->assertTrue($this->Shell->run());
  228. // cake migration run reset
  229. $this->Shell->Version->expects($this->at(1))->method('getVersion')->will($this->returnValue(9));
  230. $this->Shell->Version->expects($this->at(2))->method('run')->with($this->equalTo(array(
  231. 'type' => 'TestMigrationPlugin',
  232. 'callback' => $this->Shell,
  233. 'version' => 0,
  234. 'direction' => 'down',
  235. 'dry' => false,
  236. 'precheck' => null,
  237. 'skip' => array())));
  238. $this->Shell->args = array('reset');
  239. $this->assertTrue($this->Shell->run());
  240. // cake migration run - answers 0, 11, 1
  241. $this->Shell->Version->expects($this->at(1))->method('getVersion')->will($this->returnValue(0));
  242. $this->Shell->Version->expects($this->at(2))->method('run')->with($this->equalTo(array(
  243. 'type' => 'TestMigrationPlugin',
  244. 'callback' => $this->Shell,
  245. 'version' => 1,
  246. 'direction' => 'up',
  247. 'dry' => false)));
  248. $this->Shell->expects($this->at(2))->method('in')->will($this->returnValue(0));
  249. $this->Shell->expects($this->at(4))->method('in')->will($this->returnValue(11));
  250. $this->Shell->expects($this->at(6))->method('in')->will($this->returnValue(1));
  251. $this->Shell->args = array();
  252. $this->assertTrue($this->Shell->run());
  253. // cake migration run - answers 10
  254. $this->Shell->Version->expects($this->at(1))->method('getVersion')->will($this->returnValue(9));
  255. $this->Shell->Version->expects($this->at(2))->method('run')->with($this->equalTo(array(
  256. 'type' => 'TestMigrationPlugin',
  257. 'callback' => $this->Shell,
  258. 'version' => 10,
  259. 'direction' => 'up',
  260. 'dry' => false)));
  261. $this->Shell->expects($this->at(2))->method('in')->will($this->returnValue(10));
  262. $this->Shell->args = array();
  263. $this->assertTrue($this->Shell->run());
  264. // cake migration run 1
  265. $this->Shell->Version->expects($this->at(1))->method('getVersion')->will($this->returnValue(0));
  266. $this->Shell->Version->expects($this->at(2))->method('run')->with($this->equalTo(array(
  267. 'type' => 'TestMigrationPlugin',
  268. 'callback' => $this->Shell,
  269. 'version' => 1,
  270. 'dry' => false)));
  271. $this->Shell->args = array('1');
  272. $this->assertTrue($this->Shell->run());
  273. // cake migration run 11
  274. $this->Shell->Version->expects($this->at(1))->method('getVersion')->will($this->returnValue(0));
  275. $this->Shell->args = array('11');
  276. $this->assertFalse($this->Shell->run());
  277. }
  278. /**
  279. * TestRunWithFailuresOnce method
  280. *
  281. * @return void
  282. */
  283. public function testRunWithFailuresOnce() {
  284. $this->Shell->expects($this->any())->method('_stop')->will($this->returnValue(false));
  285. $mapping = array(1 => array(
  286. 'version' => 1, 'name' => '001_schema_dump',
  287. 'class' => 'M4af9d151e1484b74ad9d007058157726',
  288. 'type' => $this->Shell->type, 'migrated' => null
  289. ));
  290. $migration = new CakeMigration();
  291. $migration->info = $mapping[1];
  292. $exception = new MigrationException($migration, 'Exception message');
  293. $this->Shell->Version->expects($this->any())->method('getMapping')->will($this->returnValue($mapping));
  294. $this->Shell->Version->expects($this->any())->method('getVersion')->will($this->returnValue(0));
  295. $this->Shell->Version->expects($this->at(2))->method('run')->will($this->throwException($exception));
  296. $this->Shell->expects($this->at(1))->method('in')->will($this->returnValue('y'));
  297. $this->Shell->args = array('up');
  298. $this->assertTrue($this->Shell->run());
  299. $result = $this->Shell->output;
  300. $pattern = <<<TEXT
  301. /Running migrations:
  302. An error occurred when processing the migration:
  303. Migration: 001_schema_dump
  304. Error: Exception message
  305. All migrations have completed./
  306. TEXT;
  307. $this->assertRegExp(str_replace("\r\n", "\n", $pattern), str_replace("\r\n", "\n", $result));
  308. }
  309. /**
  310. * TestRunWithFailuresNotOnce method
  311. *
  312. * @return void
  313. */
  314. public function testRunWithFailuresNotOnce() {
  315. $this->Shell->expects($this->any())->method('_stop')->will($this->returnValue(false));
  316. $mapping = array(
  317. 1 => array(
  318. 'version' => 1, 'name' => '001_schema_dump',
  319. 'class' => 'M4af9d151e1484b74ad9d007058157726',
  320. 'type' => $this->Shell->type, 'migrated' => null
  321. ),
  322. );
  323. $migration = new CakeMigration();
  324. $migration->info = $mapping[1];
  325. $exception = new MigrationException($migration, 'Exception message');
  326. $this->Shell->Version->expects($this->any())->method('getMapping')->will($this->returnValue($mapping));
  327. $this->Shell->Version->expects($this->any())->method('getVersion')->will($this->returnValue(0));
  328. $this->Shell->Version->expects($this->at(2))->method('run')->will($this->throwException($exception));
  329. $this->Shell->Version->expects($this->at(3))->method('run')->will($this->returnValue(true));
  330. $this->Shell->expects($this->at(1))->method('in')->will($this->returnValue('y'));
  331. $this->Shell->args = array('all');
  332. $this->assertTrue($this->Shell->run());
  333. $result = $this->Shell->output;
  334. $pattern = <<<TEXT
  335. /Running migrations:
  336. All migrations have completed./
  337. TEXT;
  338. $this->assertRegExp(str_replace("\r\n", "\n", $pattern), str_replace("\n\n", "\n", $result));
  339. }
  340. /**
  341. * TestFromComparisonTableActions method
  342. *
  343. * @return void
  344. */
  345. public function testFromComparisonTableActions() {
  346. $comparison = array(
  347. 'users' => array('add' => $this->tables['users']),
  348. 'posts' => array('add' => $this->tables['posts'])
  349. );
  350. $oldTables = array();
  351. $result = $this->Shell->fromComparison(array(), $comparison, $oldTables, $this->tables);
  352. $expected = array(
  353. 'up' => array('create_table' => $this->tables),
  354. 'down' => array('drop_table' => array('users', 'posts'))
  355. );
  356. $this->assertEquals($result, $expected);
  357. $comparison = array('posts' => array('add' => $this->tables['posts']));
  358. $oldTables = array('users' => $this->tables['users']);
  359. $result = $this->Shell->fromComparison(array(), $comparison, $oldTables, $this->tables);
  360. $expected = array(
  361. 'up' => array(
  362. 'create_table' => array('posts' => $this->tables['posts'])
  363. ),
  364. 'down' => array(
  365. 'drop_table' => array('posts')
  366. )
  367. );
  368. $this->assertEquals($result, $expected);
  369. $comparison = array();
  370. $oldTables = array('posts' => $this->tables['posts'], 'users' => $this->tables['users']);
  371. $currentTables = array('users' => $this->tables['users']);
  372. $result = $this->Shell->fromComparison(array(), $comparison, $oldTables, $currentTables);
  373. $expected = array(
  374. 'up' => array(
  375. 'drop_table' => array('posts')
  376. ),
  377. 'down' => array(
  378. 'create_table' => array('posts' => $this->tables['posts'])
  379. )
  380. );
  381. $this->assertEquals($result, $expected);
  382. }
  383. /**
  384. * TestFromComparisonFieldActions method
  385. *
  386. * @return void
  387. */
  388. public function testFromComparisonFieldActions() {
  389. // Add field/index
  390. $oldTables = array('posts' => $this->tables['posts']);
  391. $newTables = array('posts' => array());
  392. $comparison = array(
  393. 'posts' => array('add' => array(
  394. 'views' => array('type' => 'integer', 'null' => false)
  395. ))
  396. );
  397. $result = $this->Shell->fromComparison(array(), $comparison, $oldTables, $newTables);
  398. $expected = array(
  399. 'up' => array(
  400. 'create_field' => array(
  401. 'posts' => array('views' => array('type' => 'integer', 'null' => false))
  402. )
  403. ),
  404. 'down' => array(
  405. 'drop_field' => array(
  406. 'posts' => array('views')
  407. )
  408. )
  409. );
  410. $this->assertEquals($result, $expected);
  411. $comparison = array(
  412. 'posts' => array('add' => array(
  413. 'indexes' => array('VIEW_COUNT' => array('column' => 'views', 'unique' => false))
  414. ))
  415. );
  416. $result = $this->Shell->fromComparison(array(), $comparison, $oldTables, $newTables);
  417. $expected = array(
  418. 'up' => array(
  419. 'create_field' => array(
  420. 'posts' => array(
  421. 'indexes' => array('VIEW_COUNT' => array('column' => 'views', 'unique' => false))
  422. )
  423. )
  424. ),
  425. 'down' => array(
  426. 'drop_field' => array(
  427. 'posts' => array('indexes' => array('VIEW_COUNT'))
  428. )
  429. )
  430. );
  431. $this->assertEquals($result, $expected);
  432. $comparison = array(
  433. 'posts' => array('add' => array(
  434. 'views' => array('type' => 'integer', 'null' => false),
  435. 'indexes' => array('VIEW_COUNT' => array('column' => 'views', 'unique' => false))
  436. ))
  437. );
  438. $result = $this->Shell->fromComparison(array(), $comparison, $oldTables, $newTables);
  439. $expected = array(
  440. 'up' => array(
  441. 'create_field' => array(
  442. 'posts' => array(
  443. 'views' => array('type' => 'integer', 'null' => false),
  444. 'indexes' => array('VIEW_COUNT' => array('column' => 'views', 'unique' => false))
  445. )
  446. )
  447. ),
  448. 'down' => array(
  449. 'drop_field' => array(
  450. 'posts' => array('views', 'indexes' => array('VIEW_COUNT'))
  451. )
  452. )
  453. );
  454. $this->assertEquals($result, $expected);
  455. // Drop field/index
  456. $oldTables['posts']['views'] = array('type' => 'integer', 'null' => false);
  457. $oldTables['posts']['indexes'] = array('VIEW_COUNT' => array('column' => 'views', 'unique' => false));
  458. $comparison = array(
  459. 'posts' => array('drop' => array(
  460. 'views' => array('type' => 'integer', 'null' => false)
  461. ))
  462. );
  463. $result = $this->Shell->fromComparison(array(), $comparison, $oldTables, $newTables);
  464. $expected = array(
  465. 'up' => array(
  466. 'drop_field' => array(
  467. 'posts' => array('views')
  468. )
  469. ),
  470. 'down' => array(
  471. 'create_field' => array(
  472. 'posts' => array('views' => array('type' => 'integer', 'null' => false))
  473. )
  474. )
  475. );
  476. $this->assertEquals($result, $expected);
  477. $comparison = array(
  478. 'posts' => array('drop' => array(
  479. 'indexes' => array('VIEW_COUNT' => array('column' => 'views', 'unique' => false))
  480. ))
  481. );
  482. $result = $this->Shell->fromComparison(array(), $comparison, $oldTables, $newTables);
  483. $expected = array(
  484. 'up' => array(
  485. 'drop_field' => array(
  486. 'posts' => array('indexes' => array('VIEW_COUNT'))
  487. )
  488. ),
  489. 'down' => array(
  490. 'create_field' => array(
  491. 'posts' => array('indexes' => array('VIEW_COUNT' => array('column' => 'views', 'unique' => false)))
  492. )
  493. )
  494. );
  495. $this->assertEquals($result, $expected);
  496. $comparison = array(
  497. 'posts' => array('drop' => array(
  498. 'views' => array('type' => 'integer', 'null' => false),
  499. 'indexes' => array('VIEW_COUNT' => array('column' => 'views', 'unique' => false))
  500. ))
  501. );
  502. $result = $this->Shell->fromComparison(array(), $comparison, $oldTables, $newTables);
  503. $expected = array(
  504. 'up' => array(
  505. 'drop_field' => array(
  506. 'posts' => array('views', 'indexes' => array('VIEW_COUNT'))
  507. )
  508. ),
  509. 'down' => array(
  510. 'create_field' => array(
  511. 'posts' => array(
  512. 'views' => array('type' => 'integer', 'null' => false),
  513. 'indexes' => array('VIEW_COUNT' => array('column' => 'views', 'unique' => false))
  514. )
  515. )
  516. )
  517. );
  518. $this->assertEquals($result, $expected);
  519. // Change field
  520. $comparison = array(
  521. 'posts' => array('change' => array(
  522. 'views' => array('type' => 'integer', 'null' => false, 'length' => 2),
  523. ))
  524. );
  525. $result = $this->Shell->fromComparison(array(), $comparison, $oldTables, $newTables);
  526. $expected = array(
  527. 'up' => array(
  528. 'alter_field' => array(
  529. 'posts' => array(
  530. 'views' => array('type' => 'integer', 'null' => false, 'length' => 2)
  531. )
  532. )
  533. ),
  534. 'down' => array(
  535. 'alter_field' => array(
  536. 'posts' => array(
  537. 'views' => array('type' => 'integer', 'null' => false)
  538. )
  539. )
  540. )
  541. );
  542. $this->assertEquals($result, $expected);
  543. // Change field with/out length
  544. $oldTables = array('users' => $this->tables['users']);
  545. $newTables = array('users' => array());
  546. $oldTables['users']['last_login'] = array('type' => 'integer', 'null' => false, 'length' => 11);
  547. $comparison = array(
  548. 'users' => array('change' => array(
  549. 'last_login' => array('type' => 'datetime', 'null' => false),
  550. ))
  551. );
  552. $result = $this->Shell->fromComparison(array(), $comparison, $oldTables, $newTables);
  553. $expected = array(
  554. 'up' => array(
  555. 'alter_field' => array(
  556. 'users' => array(
  557. 'last_login' => array('type' => 'datetime', 'null' => false, 'length' => null)
  558. )
  559. )
  560. ),
  561. 'down' => array(
  562. 'alter_field' => array(
  563. 'users' => array(
  564. 'last_login' => array('type' => 'integer', 'null' => false, 'length' => 11)
  565. )
  566. )
  567. )
  568. );
  569. $this->assertEquals($result, $expected);
  570. }
  571. /**
  572. * TestWriteMigration method
  573. *
  574. * @return void
  575. */
  576. public function testWriteMigration() {
  577. // Remove if exists
  578. $this->_unlink(array(TMP . 'tests' . DS . '12345_migration_test_file.php'));
  579. $users = $this->tables['users'];
  580. $users['indexes'] = array('UNIQUE_USER' => array('column' => 'user', 'unique' => true));
  581. $migration = array(
  582. 'up' => array(
  583. 'create_table' => array('users' => $users),
  584. 'create_field' => array(
  585. 'posts' => array(
  586. 'views' => array('type' => 'integer', 'null' => false),
  587. 'indexes' => array('VIEW_COUNT' => array('column' => 'views', 'unique' => false))
  588. )
  589. )
  590. ),
  591. 'down' => array(
  592. 'drop_table' => array('users'),
  593. 'drop_field' => array(
  594. 'posts' => array('views', 'indexes' => array('VIEW_COUNT'))
  595. )
  596. )
  597. );
  598. $this->assertFalse(file_exists(TMP . 'tests' . DS . '12345_migration_test_file.php'));
  599. $this->assertTrue($this->Shell->writeMigration('migration_test_file', 12345, $migration));
  600. $this->assertTrue(file_exists(TMP . 'tests' . DS . '12345_migration_test_file.php'));
  601. $result = $this->_getMigrationVariable(TMP . 'tests' . DS . '12345_migration_test_file.php');
  602. $expected = <<<TEXT
  603. public \$migration = array(
  604. 'up' => array(
  605. 'create_table' => array(
  606. 'users' => array(
  607. 'id' => array('type' => 'integer', 'key' => 'primary'),
  608. 'user' => array('type' => 'string', 'null' => false),
  609. 'password' => array('type' => 'string', 'null' => false),
  610. 'created' => 'datetime',
  611. 'updated' => 'datetime',
  612. 'indexes' => array(
  613. 'UNIQUE_USER' => array('column' => 'user', 'unique' => true),
  614. ),
  615. ),
  616. ),
  617. 'create_field' => array(
  618. 'posts' => array(
  619. 'views' => array('type' => 'integer', 'null' => false),
  620. 'indexes' => array(
  621. 'VIEW_COUNT' => array('column' => 'views', 'unique' => false),
  622. ),
  623. ),
  624. ),
  625. ),
  626. 'down' => array(
  627. 'drop_table' => array(
  628. 'users'
  629. ),
  630. 'drop_field' => array(
  631. 'posts' => array('views', 'indexes' => array('VIEW_COUNT')),
  632. ),
  633. ),
  634. );
  635. TEXT;
  636. $this->assertEquals($result, str_replace("\r\n", "\n", $expected));
  637. $this->_unlink(array(TMP . 'tests' . DS . '12345_migration_test_file.php'));
  638. }
  639. /**
  640. * Test writing migration that only contains index changes
  641. *
  642. * @return void
  643. * @link https://github.com/CakeDC/migrations/issues/189
  644. */
  645. public function testWriteMigrationIndexesOnly() {
  646. $this->_unlink(array(TMP . 'tests' . DS . '12346_migration_test_file.php'));
  647. $users = $this->tables['users'];
  648. $users['indexes'] = array('UNIQUE_USER' => array('column' => 'user', 'unique' => true));
  649. $migration = array(
  650. 'up' => array(
  651. 'create_field' => array(
  652. 'posts' => array(
  653. 'indexes' => array(
  654. 'USER_ID' => array('column' => 'user_id', 'unique' => false)
  655. )
  656. )
  657. )
  658. ),
  659. 'down' => array(
  660. 'drop_field' => array(
  661. 'posts' => array(
  662. 'indexes' => array('USER_ID')
  663. )
  664. )
  665. )
  666. );
  667. $this->assertTrue($this->Shell->writeMigration('migration_test_file', 12346, $migration));
  668. $this->assertTrue(file_exists(TMP . 'tests' . DS . '12346_migration_test_file.php'));
  669. $result = $this->_getMigrationVariable(TMP . 'tests' . DS . '12346_migration_test_file.php');
  670. $expected = <<<TEXT
  671. public \$migration = array(
  672. 'up' => array(
  673. 'create_field' => array(
  674. 'posts' => array(
  675. 'indexes' => array(
  676. 'USER_ID' => array('column' => 'user_id', 'unique' => false),
  677. ),
  678. ),
  679. ),
  680. ),
  681. 'down' => array(
  682. 'drop_field' => array(
  683. 'posts' => array('indexes' => array('USER_ID')),
  684. ),
  685. ),
  686. );
  687. TEXT;
  688. $this->assertEquals($result, str_replace("\r\n", "\n", $expected));
  689. $this->_unlink(array(TMP . 'tests' . DS . '12346_migration_test_file.php'));
  690. }
  691. /**
  692. * TestGenerate method
  693. *
  694. * @return void
  695. */
  696. public function testGenerate() {
  697. $this->Shell->expects($this->at(0))->method('in')->will($this->returnValue('n'));
  698. $this->Shell->expects($this->at(1))->method('in')->will($this->returnValue('n'));
  699. $this->Shell->expects($this->at(2))->method('in')->will($this->returnValue('n'));
  700. $this->Shell->expects($this->at(3))->method('in')->will($this->returnValue('Initial Schema'));
  701. $this->Shell->params['overwrite'] = false;
  702. $this->Shell->generate();
  703. $files = glob(TMP . 'tests' . DS . '*initial_schema.php');
  704. $this->_unlink($files);
  705. $this->assertNotEmpty(preg_grep('/([0-9])+_initial_schema\.php$/i', $files));
  706. }
  707. /**
  708. * TestGenerate2 method
  709. *
  710. * @return void
  711. */
  712. public function testGenerate2() {
  713. $this->Shell->expects($this->atLeastOnce())->method('err');
  714. $this->Shell->expects($this->at(0))->method('in')->will($this->returnValue('n'));
  715. $this->Shell->expects($this->at(1))->method('in')->will($this->returnValue('n'));
  716. $this->Shell->expects($this->at(2))->method('in')->will($this->returnValue('n'));
  717. $this->Shell->expects($this->at(3))->method('in')->will($this->returnValue('002 invalid name'));
  718. $this->Shell->expects($this->at(5))->method('in')->will($this->returnValue('invalid-name'));
  719. $this->Shell->expects($this->at(7))->method('in')->will($this->returnValue('create some sample_data'));
  720. $this->Shell->params['overwrite'] = false;
  721. $this->Shell->generate();
  722. $files = glob(TMP . 'tests' . DS . '*create_some_sample_data.php');
  723. $this->_unlink($files);
  724. $this->assertNotEmpty(preg_grep('/([0-9])+_create_some_sample_data\.php$/i', $files));
  725. }
  726. /**
  727. * TestGenerateComparison method
  728. *
  729. * @return void
  730. */
  731. public function testGenerateComparison() {
  732. $this->Shell->type = 'TestMigrationPlugin4';
  733. $this->Shell->expects($this->at(0))->method('in')->will($this->returnValue('y'));
  734. $this->Shell->expects($this->at(2))->method('in')->will($this->returnValue('n'));
  735. $this->Shell->expects($this->at(3))->method('in')->will($this->returnValue('drop slug field'));
  736. $this->Shell->expects($this->at(4))->method('in')->will($this->returnValue('y'));
  737. $this->Shell->expects($this->at(5))->method('dispatchShell')->with('schema generate --connection test --force --file schema.php --name TestMigrationPlugin4');
  738. $this->Shell->Version->expects($this->any())->method('getMapping')->will($this->returnCallback(array($this, 'returnMapping')));
  739. $this->assertEmpty(glob(TMP . 'tests' . DS . '*drop_slug_field.php'));
  740. $this->Shell->params = array(
  741. 'force' => true,
  742. 'overwrite' => false
  743. );
  744. $this->Shell->generate();
  745. $files = glob(TMP . 'tests' . DS . '*drop_slug_field.php');
  746. $this->assertNotEmpty($files);
  747. $result = $this->_getMigrationVariable(current($files));
  748. $this->_unlink($files);
  749. $this->assertNotRegExp('/\'schema_migrations\'/', $result);
  750. $pattern = <<<TEXT
  751. / 'drop_field' => array\(
  752. 'articles' => array\('slug'\),
  753. \),/
  754. TEXT;
  755. $this->assertRegExp(str_replace("\r\n", "\n", $pattern), $result);
  756. $pattern = <<<TEXT
  757. / 'create_field' => array\(
  758. 'articles' => array\(
  759. 'slug' => array\('type' => 'string', 'null' => false\),
  760. \),
  761. \),/
  762. TEXT;
  763. $this->assertRegExp(str_replace("\r\n", "\n", $pattern), $result);
  764. }
  765. public function returnMapping() {
  766. return array(
  767. gmdate('U') => array('class' => 'M4af9d15154844819b7a0007058157726')
  768. );
  769. }
  770. /**
  771. * TestGenerateInverseComparison method
  772. *
  773. * @return void
  774. */
  775. public function testGenerateInverseComparison() {
  776. $this->Shell->type = 'TestMigrationPlugin4';
  777. $this->Shell->expects($this->at(0))->method('in')->will($this->returnValue('n'));
  778. $this->Shell->expects($this->at(1))->method('in')->will($this->returnValue('y'));
  779. $this->Shell->expects($this->at(3))->method('in')->will($this->returnValue('n'));
  780. $this->Shell->expects($this->at(4))->method('in')->will($this->returnValue('create slug field'));
  781. $this->Shell->Version->expects($this->any())->method('getMapping')->will($this->returnCallback(array($this, 'returnMapping')));
  782. $this->assertEmpty(glob(TMP . 'tests' . DS . '*create_slug_field.php'));
  783. $this->Shell->params = array(
  784. 'force' => true,
  785. 'overwrite' => false
  786. );
  787. $this->Shell->generate();
  788. $files = glob(TMP . 'tests' . DS . '*create_slug_field.php');
  789. $this->assertNotEmpty($files);
  790. $result = $this->_getMigrationVariable(current($files));
  791. $this->_unlink($files);
  792. $this->assertNotRegExp('/\'schema_migrations\'/', $result);
  793. $pattern = <<<TEXT
  794. / 'create_field' => array\(
  795. 'articles' => array\(
  796. 'slug' => array\('type' => 'string', 'null' => false, 'after' => 'title'\),
  797. \),
  798. \),/
  799. TEXT;
  800. $this->assertRegExp(str_replace("\r\n", "\n", $pattern), $result);
  801. $pattern = <<<TEXT
  802. / 'drop_field' => array\(
  803. 'articles' => array\('slug'\),
  804. \),/
  805. TEXT;
  806. $this->assertRegExp(str_replace("\r\n", "\n", $pattern), $result);
  807. }
  808. /**
  809. * testGenerateFromCliParamsCreateTable method
  810. * test the case of using a command such as:
  811. * app/Console/cake Migrations.migration generate create_products id created modified name description:text in_stock:boolean price:float stock_count:integer
  812. *
  813. * @return void
  814. */
  815. public function testGenerateFromCliParamsCreateTable() {
  816. $this->Shell->expects($this->at(0))->method('in')->will($this->returnValue('n'));
  817. $this->assertEmpty(glob(TMP . 'tests' . DS . '*create_products.php'));
  818. $this->Shell->args = array('create_products', 'id', 'created', 'modified', 'name', 'description:text', 'in_stock:boolean', 'price:float', 'stock_count:integer');
  819. $this->Shell->params = array(
  820. 'force' => true,
  821. 'overwrite' => false
  822. );
  823. $this->Shell->generate();
  824. $files = glob(TMP . 'tests' . DS . '*create_products.php');
  825. $this->assertNotEmpty($files);
  826. $result = $this->_getMigrationVariable(current($files));
  827. $this->_unlink($files);
  828. $expected = file_get_contents(CakePlugin::path('Migrations') . '/Test/Fixture/test_migration_create_table_from_cli.txt');
  829. $this->assertEquals($expected, $result);
  830. }
  831. /**
  832. * testGenerateFromCliParamsDropTable method
  833. * test the case of using a command such as:
  834. * app/Console/cake Migrations.migration generate drop_products
  835. *
  836. * @return void
  837. */
  838. public function testGenerateFromCliParamsDropTable() {
  839. $this->Shell->expects($this->at(0))->method('in')->will($this->returnValue('n'));
  840. $this->assertEmpty(glob(TMP . 'tests' . DS . '*drop_products.php'));
  841. $this->Shell->args = array('drop_products');
  842. $this->Shell->params = array(
  843. 'force' => true,
  844. 'overwrite' => false
  845. );
  846. $this->Shell->generate();
  847. $files = glob(TMP . 'tests' . DS . '*drop_products.php');
  848. $this->assertNotEmpty($files);
  849. $result = $this->_getMigrationVariable(current($files));
  850. $this->_unlink($files);
  851. $expected = file_get_contents(CakePlugin::path('Migrations') . '/Test/Fixture/test_migration_drop_table_from_cli.txt');
  852. $this->assertEquals($expected, $result);
  853. }
  854. /**
  855. * testGenerateFromCliParamsAddFields method
  856. * test the case of using a command such as:
  857. * app/Console/cake Migrations.migration generate add_all_fields_to_products id created modified name description:text in_stock:boolean price:float stock_count:integer
  858. *
  859. * @return void
  860. */
  861. public function testGenerateFromCliParamsAddFields() {
  862. $this->Shell->expects($this->at(0))->method('in')->will($this->returnValue('n'));
  863. $this->assertEmpty(glob(TMP . 'tests' . DS . '*add_all_fields_to_products.php'));
  864. $this->Shell->args = array('add_all_fields_to_products', 'id', 'created', 'modified', 'name', 'description:text', 'in_stock:boolean', 'price:float', 'stock_count:integer');
  865. $this->Shell->params = array(
  866. 'force' => true,
  867. 'overwrite' => false
  868. );
  869. $this->Shell->generate();
  870. $files = glob(TMP . 'tests' . DS . '*add_all_fields_to_products.php');
  871. $this->assertNotEmpty($files);
  872. $result = $this->_getMigrationVariable(current($files));
  873. $this->_unlink($files);
  874. $expected = file_get_contents(CakePlugin::path('Migrations') . '/Test/Fixture/test_migration_add_fields_from_cli.txt');
  875. $this->assertEquals($expected, $result);
  876. }
  877. /**
  878. * testGenerateFromCliParamsRemoveFields method
  879. * test the case of using a command such as:
  880. * app/Console/cake Migrations.migration generate remove_name_and_desc_from_products name description
  881. *
  882. * @return void
  883. */
  884. public function testGenerateFromCliParamsRemoveFields() {
  885. $this->Shell->expects($this->at(0))->method('in')->will($this->returnValue('n'));
  886. $this->assertEmpty(glob(TMP . 'tests' . DS . '*remove_name_and_desc_from_products.php'));
  887. $this->Shell->args = array('remove_name_and_desc_from_products', 'name', 'description');
  888. $this->Shell->params = array(
  889. 'force' => true,
  890. 'overwrite' => false
  891. );
  892. $this->Shell->generate();
  893. $files = glob(TMP . 'tests' . DS . '*remove_name_and_desc_from_products.php');
  894. $this->assertNotEmpty($files);
  895. $result = $this->_getMigrationVariable(current($files));
  896. $this->_unlink($files);
  897. $expected = file_get_contents(CakePlugin::path('Migrations') . '/Test/Fixture/test_migration_remove_fields_from_cli.txt');
  898. $this->assertEquals($expected, $result);
  899. }
  900. /**
  901. * TestGenerateDump method
  902. *
  903. * @return void
  904. */
  905. public function testGenerateDump() {
  906. $this->Shell->expects($this->at(0))->method('in')->will($this->returnValue('y'));
  907. $this->Shell->expects($this->at(2))->method('in')->will($this->returnValue('n'));
  908. $this->Shell->expects($this->at(3))->method('in')->will($this->returnValue('schema dump'));
  909. $this->Shell->Version->expects($this->any())->method('getMapping')->will($this->returnCallback(array($this, 'returnMapping')));
  910. $this->assertEmpty(glob(TMP . 'tests' . DS . '*schema_dump.php'));
  911. $this->Shell->type = 'TestMigrationPlugin2';
  912. $this->Shell->params = array(
  913. 'force' => true,
  914. 'dry' => false,
  915. 'precheck' => 'Migrations.PrecheckException',
  916. 'overwrite' => false
  917. );
  918. $this->Shell->generate();
  919. $files = glob(TMP . 'tests' . DS . '*schema_dump.php');
  920. $this->assertNotEmpty($files);
  921. $result = $this->_getMigrationVariable(current($files));
  922. $this->_unlink($files);
  923. $expected = file_get_contents(CakePlugin::path('Migrations') . '/Test/Fixture/test_migration.txt');
  924. $expected = str_replace("\r\n", "\n", $expected);
  925. $this->assertEquals($expected, $result);
  926. }
  927. /**
  928. * TestStatus method
  929. *
  930. * @return void
  931. */
  932. public function testMigrationStatus() {
  933. $this->Shell->Version = new MigrationVersion(array('connection' => 'test'));
  934. $this->Shell->status();
  935. $result = $this->Shell->output;
  936. $pattern = <<<TEXT
  937. /Migrations Plugin
  938. Current version:
  939. #003 003_increase_class_name_length
  940. Latest version:
  941. #003 003_increase_class_name_length/
  942. TEXT;
  943. $this->assertRegExp(str_replace("\r\n", "\n", $pattern), $result);
  944. $this->Shell->Version->setVersion(3, 'migrations', false);
  945. $this->Shell->output = '';
  946. $this->Shell->args = array('outdated');
  947. $this->Shell->status();
  948. $result = $this->Shell->output;
  949. $pattern = <<<TEXT
  950. /Migrations Plugin
  951. Current version:
  952. #002 002_convert_version_to_class_names
  953. Latest version:
  954. #003 003_increase_class_name_length/
  955. TEXT;
  956. $this->assertRegExp(str_replace("\r\n", "\n", $pattern), $result);
  957. }
  958. /**
  959. * Strip all the content surrounding the $migration variable
  960. *
  961. * @param string $file
  962. * @return string
  963. */
  964. protected function _getMigrationVariable($file) {
  965. $result = array();
  966. $array = explode("\n", str_replace("\r\n", "\n", file_get_contents($file)));
  967. foreach ($array as $line) {
  968. if ($line === "\tpublic \$migration = array(") {
  969. $result[] = $line;
  970. } elseif (!empty($result) && $line === "\t);") {
  971. $result[] = $line;
  972. break;
  973. } elseif (!empty($result)) {
  974. $result[] = $line;
  975. }
  976. }
  977. return implode("\n", $result);
  978. }
  979. /**
  980. * Unlink test files from filesystem
  981. *
  982. * @param array Absolute paths to unlink
  983. * @return void
  984. */
  985. protected function _unlink($files) {
  986. foreach ($files as $file) {
  987. @unlink($file);
  988. }
  989. }
  990. }