2016-05-25 11:21:56 -05:00
|
|
|
<?php
|
|
|
|
|
|
2017-01-17 14:30:19 +00:00
|
|
|
namespace Illuminate\Tests\Database;
|
|
|
|
|
|
2018-10-03 22:05:43 +02:00
|
|
|
use Illuminate\Console\OutputStyle;
|
|
|
|
|
use Illuminate\Container\Container;
|
2016-05-25 11:21:56 -05:00
|
|
|
use Illuminate\Database\Capsule\Manager as DB;
|
|
|
|
|
use Illuminate\Database\Migrations\DatabaseMigrationRepository;
|
2019-09-10 17:16:05 +02:00
|
|
|
use Illuminate\Database\Migrations\Migrator;
|
|
|
|
|
use Illuminate\Filesystem\Filesystem;
|
|
|
|
|
use Illuminate\Support\Facades\Facade;
|
|
|
|
|
use Illuminate\Support\Str;
|
|
|
|
|
use Mockery as m;
|
|
|
|
|
use PHPUnit\Framework\TestCase;
|
2016-05-25 11:21:56 -05:00
|
|
|
|
2016-12-30 21:31:11 +01:00
|
|
|
class DatabaseMigratorIntegrationTest extends TestCase
|
2016-05-25 11:21:56 -05:00
|
|
|
{
|
|
|
|
|
protected $db;
|
2018-10-04 10:27:50 -03:00
|
|
|
protected $migrator;
|
2016-05-25 11:21:56 -05:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Bootstrap Eloquent.
|
|
|
|
|
*
|
|
|
|
|
* @return void
|
|
|
|
|
*/
|
2019-02-08 23:05:58 +01:00
|
|
|
protected function setUp(): void
|
2016-05-25 11:21:56 -05:00
|
|
|
{
|
|
|
|
|
$this->db = $db = new DB;
|
|
|
|
|
|
|
|
|
|
$db->addConnection([
|
2019-11-30 19:24:13 +08:00
|
|
|
'driver' => 'sqlite',
|
|
|
|
|
'database' => ':memory:',
|
2016-05-25 11:21:56 -05:00
|
|
|
]);
|
|
|
|
|
|
2019-11-30 14:12:39 +08:00
|
|
|
$db->addConnection([
|
2019-11-30 19:24:13 +08:00
|
|
|
'driver' => 'sqlite',
|
|
|
|
|
'database' => ':memory:',
|
2019-11-30 14:12:39 +08:00
|
|
|
], 'sqlite2');
|
|
|
|
|
|
2022-02-22 09:55:52 -05:00
|
|
|
$db->addConnection([
|
|
|
|
|
'driver' => 'sqlite',
|
|
|
|
|
'database' => ':memory:',
|
|
|
|
|
], 'sqlite3');
|
|
|
|
|
|
2016-05-25 11:21:56 -05:00
|
|
|
$db->setAsGlobal();
|
|
|
|
|
|
2018-10-03 22:05:43 +02:00
|
|
|
$container = new Container;
|
2016-05-25 13:01:38 -05:00
|
|
|
$container->instance('db', $db->getDatabaseManager());
|
2021-07-15 12:05:37 +02:00
|
|
|
$container->bind('db.schema', function ($app) {
|
|
|
|
|
return $app['db']->connection()->getSchemaBuilder();
|
|
|
|
|
});
|
2018-10-03 15:08:43 -05:00
|
|
|
|
2018-10-03 22:05:43 +02:00
|
|
|
Facade::setFacadeApplication($container);
|
2016-05-25 13:01:38 -05:00
|
|
|
|
2016-05-25 11:21:56 -05:00
|
|
|
$this->migrator = new Migrator(
|
|
|
|
|
$repository = new DatabaseMigrationRepository($db->getDatabaseManager(), 'migrations'),
|
|
|
|
|
$db->getDatabaseManager(),
|
|
|
|
|
new Filesystem
|
|
|
|
|
);
|
|
|
|
|
|
2018-10-05 14:48:10 +02:00
|
|
|
$output = m::mock(OutputStyle::class);
|
2022-07-14 15:38:53 +01:00
|
|
|
$output->shouldReceive('write');
|
2018-07-11 17:48:10 +02:00
|
|
|
$output->shouldReceive('writeln');
|
2023-08-01 09:47:50 +10:00
|
|
|
$output->shouldReceive('newLinesWritten');
|
2018-07-11 17:48:10 +02:00
|
|
|
|
|
|
|
|
$this->migrator->setOutput($output);
|
|
|
|
|
|
2016-05-25 11:21:56 -05:00
|
|
|
if (! $repository->repositoryExists()) {
|
|
|
|
|
$repository->createRepository();
|
|
|
|
|
}
|
2019-11-30 14:12:39 +08:00
|
|
|
|
|
|
|
|
$repository2 = new DatabaseMigrationRepository($db->getDatabaseManager(), 'migrations');
|
|
|
|
|
$repository2->setSource('sqlite2');
|
2019-11-30 19:24:13 +08:00
|
|
|
|
2019-11-30 14:12:39 +08:00
|
|
|
if (! $repository2->repositoryExists()) {
|
|
|
|
|
$repository2->createRepository();
|
|
|
|
|
}
|
2016-05-25 11:21:56 -05:00
|
|
|
}
|
|
|
|
|
|
2019-02-08 23:05:58 +01:00
|
|
|
protected function tearDown(): void
|
2016-05-25 11:21:56 -05:00
|
|
|
{
|
2018-10-03 22:05:43 +02:00
|
|
|
Facade::clearResolvedInstances();
|
|
|
|
|
Facade::setFacadeApplication(null);
|
2026-01-05 18:12:30 +01:00
|
|
|
|
|
|
|
|
parent::tearDown();
|
2016-05-25 11:21:56 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public function testBasicMigrationOfSingleFolder()
|
|
|
|
|
{
|
2016-05-25 11:25:47 -05:00
|
|
|
$ran = $this->migrator->run([__DIR__.'/migrations/one']);
|
|
|
|
|
|
2026-04-15 14:59:03 +02:00
|
|
|
$this->assertTrue($this->db::schema()->hasTable('users'));
|
|
|
|
|
$this->assertTrue($this->db::schema()->hasTable('password_resets'));
|
2016-05-25 11:25:47 -05:00
|
|
|
|
2022-01-26 16:40:14 +01:00
|
|
|
$this->assertTrue(str_contains($ran[0], 'users'));
|
|
|
|
|
$this->assertTrue(str_contains($ran[1], 'password_resets'));
|
2016-05-25 11:21:56 -05:00
|
|
|
}
|
|
|
|
|
|
2022-02-22 09:55:52 -05:00
|
|
|
public function testMigrationsDefaultConnectionCanBeChanged()
|
|
|
|
|
{
|
|
|
|
|
$ran = $this->migrator->usingConnection('sqlite2', function () {
|
|
|
|
|
return $this->migrator->run([__DIR__.'/migrations/one'], ['database' => 'sqllite3']);
|
|
|
|
|
});
|
|
|
|
|
|
2026-04-15 14:59:03 +02:00
|
|
|
$this->assertFalse($this->db::schema()->hasTable('users'));
|
|
|
|
|
$this->assertFalse($this->db::schema()->hasTable('password_resets'));
|
|
|
|
|
$this->assertTrue($this->db::schema('sqlite2')->hasTable('users'));
|
|
|
|
|
$this->assertTrue($this->db::schema('sqlite2')->hasTable('password_resets'));
|
|
|
|
|
$this->assertFalse($this->db::schema('sqlite3')->hasTable('users'));
|
|
|
|
|
$this->assertFalse($this->db::schema('sqlite3')->hasTable('password_resets'));
|
2022-02-22 09:55:52 -05:00
|
|
|
|
|
|
|
|
$this->assertTrue(Str::contains($ran[0], 'users'));
|
|
|
|
|
$this->assertTrue(Str::contains($ran[1], 'password_resets'));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public function testMigrationsCanEachDefineConnection()
|
|
|
|
|
{
|
|
|
|
|
$ran = $this->migrator->run([__DIR__.'/migrations/connection_configured']);
|
|
|
|
|
|
2026-04-15 14:59:03 +02:00
|
|
|
$this->assertFalse($this->db::schema()->hasTable('failed_jobs'));
|
|
|
|
|
$this->assertFalse($this->db::schema()->hasTable('jobs'));
|
|
|
|
|
$this->assertFalse($this->db::schema('sqlite2')->hasTable('failed_jobs'));
|
|
|
|
|
$this->assertFalse($this->db::schema('sqlite2')->hasTable('jobs'));
|
|
|
|
|
$this->assertTrue($this->db::schema('sqlite3')->hasTable('failed_jobs'));
|
|
|
|
|
$this->assertTrue($this->db::schema('sqlite3')->hasTable('jobs'));
|
2022-02-22 09:55:52 -05:00
|
|
|
|
|
|
|
|
$this->assertTrue(Str::contains($ran[0], 'failed_jobs'));
|
|
|
|
|
$this->assertTrue(Str::contains($ran[1], 'jobs'));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public function testMigratorCannotChangeDefinedMigrationConnection()
|
|
|
|
|
{
|
|
|
|
|
$ran = $this->migrator->usingConnection('sqlite2', function () {
|
|
|
|
|
return $this->migrator->run([__DIR__.'/migrations/connection_configured']);
|
|
|
|
|
});
|
|
|
|
|
|
2026-04-15 14:59:03 +02:00
|
|
|
$this->assertFalse($this->db::schema()->hasTable('failed_jobs'));
|
|
|
|
|
$this->assertFalse($this->db::schema()->hasTable('jobs'));
|
|
|
|
|
$this->assertFalse($this->db::schema('sqlite2')->hasTable('failed_jobs'));
|
|
|
|
|
$this->assertFalse($this->db::schema('sqlite2')->hasTable('jobs'));
|
|
|
|
|
$this->assertTrue($this->db::schema('sqlite3')->hasTable('failed_jobs'));
|
|
|
|
|
$this->assertTrue($this->db::schema('sqlite3')->hasTable('jobs'));
|
2022-02-22 09:55:52 -05:00
|
|
|
|
|
|
|
|
$this->assertTrue(Str::contains($ran[0], 'failed_jobs'));
|
|
|
|
|
$this->assertTrue(Str::contains($ran[1], 'jobs'));
|
|
|
|
|
}
|
|
|
|
|
|
2016-05-25 11:21:56 -05:00
|
|
|
public function testMigrationsCanBeRolledBack()
|
|
|
|
|
{
|
|
|
|
|
$this->migrator->run([__DIR__.'/migrations/one']);
|
2026-04-15 14:59:03 +02:00
|
|
|
$this->assertTrue($this->db::schema()->hasTable('users'));
|
|
|
|
|
$this->assertTrue($this->db::schema()->hasTable('password_resets'));
|
2016-05-25 11:29:42 -05:00
|
|
|
$rolledBack = $this->migrator->rollback([__DIR__.'/migrations/one']);
|
2026-04-15 14:59:03 +02:00
|
|
|
$this->assertFalse($this->db::schema()->hasTable('users'));
|
|
|
|
|
$this->assertFalse($this->db::schema()->hasTable('password_resets'));
|
2016-05-25 11:29:42 -05:00
|
|
|
|
2022-01-26 16:40:14 +01:00
|
|
|
$this->assertTrue(str_contains($rolledBack[0], 'password_resets'));
|
|
|
|
|
$this->assertTrue(str_contains($rolledBack[1], 'users'));
|
2016-05-25 11:21:56 -05:00
|
|
|
}
|
|
|
|
|
|
2023-05-13 01:50:57 +10:00
|
|
|
public function testMigrationsCanBeResetUsingAnString()
|
|
|
|
|
{
|
|
|
|
|
$this->migrator->run([__DIR__.'/migrations/one']);
|
2026-04-15 14:59:03 +02:00
|
|
|
$this->assertTrue($this->db::schema()->hasTable('users'));
|
|
|
|
|
$this->assertTrue($this->db::schema()->hasTable('password_resets'));
|
2023-05-13 01:50:57 +10:00
|
|
|
$rolledBack = $this->migrator->reset(__DIR__.'/migrations/one');
|
2026-04-15 14:59:03 +02:00
|
|
|
$this->assertFalse($this->db::schema()->hasTable('users'));
|
|
|
|
|
$this->assertFalse($this->db::schema()->hasTable('password_resets'));
|
2023-05-13 01:50:57 +10:00
|
|
|
|
|
|
|
|
$this->assertTrue(str_contains($rolledBack[0], 'password_resets'));
|
|
|
|
|
$this->assertTrue(str_contains($rolledBack[1], 'users'));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public function testMigrationsCanBeResetUsingAnArray()
|
2016-05-25 11:21:56 -05:00
|
|
|
{
|
|
|
|
|
$this->migrator->run([__DIR__.'/migrations/one']);
|
2026-04-15 14:59:03 +02:00
|
|
|
$this->assertTrue($this->db::schema()->hasTable('users'));
|
|
|
|
|
$this->assertTrue($this->db::schema()->hasTable('password_resets'));
|
2016-05-25 11:29:42 -05:00
|
|
|
$rolledBack = $this->migrator->reset([__DIR__.'/migrations/one']);
|
2026-04-15 14:59:03 +02:00
|
|
|
$this->assertFalse($this->db::schema()->hasTable('users'));
|
|
|
|
|
$this->assertFalse($this->db::schema()->hasTable('password_resets'));
|
2016-05-25 11:29:42 -05:00
|
|
|
|
2022-01-26 16:40:14 +01:00
|
|
|
$this->assertTrue(str_contains($rolledBack[0], 'password_resets'));
|
|
|
|
|
$this->assertTrue(str_contains($rolledBack[1], 'users'));
|
2016-05-25 11:21:56 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public function testNoErrorIsThrownWhenNoOutstandingMigrationsExist()
|
|
|
|
|
{
|
|
|
|
|
$this->migrator->run([__DIR__.'/migrations/one']);
|
2026-04-15 14:59:03 +02:00
|
|
|
$this->assertTrue($this->db::schema()->hasTable('users'));
|
|
|
|
|
$this->assertTrue($this->db::schema()->hasTable('password_resets'));
|
2016-05-25 11:21:56 -05:00
|
|
|
$this->migrator->run([__DIR__.'/migrations/one']);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public function testNoErrorIsThrownWhenNothingToRollback()
|
|
|
|
|
{
|
|
|
|
|
$this->migrator->run([__DIR__.'/migrations/one']);
|
2026-04-15 14:59:03 +02:00
|
|
|
$this->assertTrue($this->db::schema()->hasTable('users'));
|
|
|
|
|
$this->assertTrue($this->db::schema()->hasTable('password_resets'));
|
2016-05-25 11:21:56 -05:00
|
|
|
$this->migrator->rollback([__DIR__.'/migrations/one']);
|
2026-04-15 14:59:03 +02:00
|
|
|
$this->assertFalse($this->db::schema()->hasTable('users'));
|
|
|
|
|
$this->assertFalse($this->db::schema()->hasTable('password_resets'));
|
2016-05-25 11:21:56 -05:00
|
|
|
$this->migrator->rollback([__DIR__.'/migrations/one']);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public function testMigrationsCanRunAcrossMultiplePaths()
|
|
|
|
|
{
|
|
|
|
|
$this->migrator->run([__DIR__.'/migrations/one', __DIR__.'/migrations/two']);
|
2026-04-15 14:59:03 +02:00
|
|
|
$this->assertTrue($this->db::schema()->hasTable('users'));
|
|
|
|
|
$this->assertTrue($this->db::schema()->hasTable('password_resets'));
|
|
|
|
|
$this->assertTrue($this->db::schema()->hasTable('flights'));
|
2016-05-25 11:21:56 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public function testMigrationsCanBeRolledBackAcrossMultiplePaths()
|
|
|
|
|
{
|
|
|
|
|
$this->migrator->run([__DIR__.'/migrations/one', __DIR__.'/migrations/two']);
|
2026-04-15 14:59:03 +02:00
|
|
|
$this->assertTrue($this->db::schema()->hasTable('users'));
|
|
|
|
|
$this->assertTrue($this->db::schema()->hasTable('password_resets'));
|
|
|
|
|
$this->assertTrue($this->db::schema()->hasTable('flights'));
|
2016-05-25 11:21:56 -05:00
|
|
|
$this->migrator->rollback([__DIR__.'/migrations/one', __DIR__.'/migrations/two']);
|
2026-04-15 14:59:03 +02:00
|
|
|
$this->assertFalse($this->db::schema()->hasTable('users'));
|
|
|
|
|
$this->assertFalse($this->db::schema()->hasTable('password_resets'));
|
|
|
|
|
$this->assertFalse($this->db::schema()->hasTable('flights'));
|
2016-05-25 11:21:56 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public function testMigrationsCanBeResetAcrossMultiplePaths()
|
|
|
|
|
{
|
|
|
|
|
$this->migrator->run([__DIR__.'/migrations/one', __DIR__.'/migrations/two']);
|
2026-04-15 14:59:03 +02:00
|
|
|
$this->assertTrue($this->db::schema()->hasTable('users'));
|
|
|
|
|
$this->assertTrue($this->db::schema()->hasTable('password_resets'));
|
|
|
|
|
$this->assertTrue($this->db::schema()->hasTable('flights'));
|
2016-05-25 11:21:56 -05:00
|
|
|
$this->migrator->reset([__DIR__.'/migrations/one', __DIR__.'/migrations/two']);
|
2026-04-15 14:59:03 +02:00
|
|
|
$this->assertFalse($this->db::schema()->hasTable('users'));
|
|
|
|
|
$this->assertFalse($this->db::schema()->hasTable('password_resets'));
|
|
|
|
|
$this->assertFalse($this->db::schema()->hasTable('flights'));
|
2016-05-25 11:21:56 -05:00
|
|
|
}
|
2019-09-17 13:46:10 +01:00
|
|
|
|
|
|
|
|
public function testMigrationsCanBeProperlySortedAcrossMultiplePaths()
|
|
|
|
|
{
|
|
|
|
|
$paths = [__DIR__.'/migrations/multi_path/vendor', __DIR__.'/migrations/multi_path/app'];
|
|
|
|
|
|
|
|
|
|
$migrationsFilesFullPaths = array_values($this->migrator->getMigrationFiles($paths));
|
|
|
|
|
|
|
|
|
|
$expected = [
|
|
|
|
|
__DIR__.'/migrations/multi_path/app/2016_01_01_000000_create_users_table.php', // This file was not created on the "vendor" directory on purpose
|
|
|
|
|
__DIR__.'/migrations/multi_path/vendor/2016_01_01_200000_create_flights_table.php', // This file was not created on the "app" directory on purpose
|
|
|
|
|
__DIR__.'/migrations/multi_path/app/2019_08_08_000001_rename_table_one.php',
|
|
|
|
|
__DIR__.'/migrations/multi_path/app/2019_08_08_000002_rename_table_two.php',
|
|
|
|
|
__DIR__.'/migrations/multi_path/app/2019_08_08_000003_rename_table_three.php',
|
|
|
|
|
__DIR__.'/migrations/multi_path/app/2019_08_08_000004_rename_table_four.php',
|
|
|
|
|
__DIR__.'/migrations/multi_path/app/2019_08_08_000005_create_table_one.php',
|
|
|
|
|
__DIR__.'/migrations/multi_path/app/2019_08_08_000006_create_table_two.php',
|
|
|
|
|
__DIR__.'/migrations/multi_path/vendor/2019_08_08_000007_create_table_three.php', // This file was not created on the "app" directory on purpose
|
|
|
|
|
__DIR__.'/migrations/multi_path/app/2019_08_08_000008_create_table_four.php',
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
$this->assertEquals($expected, $migrationsFilesFullPaths);
|
|
|
|
|
}
|
2019-11-30 14:12:39 +08:00
|
|
|
|
|
|
|
|
public function testConnectionPriorToMigrationIsNotChangedAfterMigration()
|
|
|
|
|
{
|
|
|
|
|
$this->migrator->setConnection('default');
|
|
|
|
|
$this->migrator->run([__DIR__.'/migrations/one'], ['database' => 'sqlite2']);
|
2020-03-10 03:15:36 +01:00
|
|
|
$this->assertSame('default', $this->migrator->getConnection());
|
2019-11-30 14:12:39 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public function testConnectionPriorToMigrationIsNotChangedAfterRollback()
|
|
|
|
|
{
|
|
|
|
|
$this->migrator->setConnection('default');
|
|
|
|
|
$this->migrator->run([__DIR__.'/migrations/one'], ['database' => 'sqlite2']);
|
|
|
|
|
$this->migrator->rollback([__DIR__.'/migrations/one'], ['database' => 'sqlite2']);
|
2020-03-10 03:15:36 +01:00
|
|
|
$this->assertSame('default', $this->migrator->getConnection());
|
2019-11-30 14:12:39 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public function testConnectionPriorToMigrationIsNotChangedWhenNoOutstandingMigrationsExist()
|
|
|
|
|
{
|
|
|
|
|
$this->migrator->setConnection('default');
|
|
|
|
|
$this->migrator->run([__DIR__.'/migrations/one'], ['database' => 'sqlite2']);
|
|
|
|
|
$this->migrator->setConnection('default');
|
|
|
|
|
$this->migrator->run([__DIR__.'/migrations/one'], ['database' => 'sqlite2']);
|
2020-03-10 03:15:36 +01:00
|
|
|
$this->assertSame('default', $this->migrator->getConnection());
|
2019-11-30 14:12:39 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public function testConnectionPriorToMigrationIsNotChangedWhenNothingToRollback()
|
|
|
|
|
{
|
|
|
|
|
$this->migrator->setConnection('default');
|
|
|
|
|
$this->migrator->run([__DIR__.'/migrations/one'], ['database' => 'sqlite2']);
|
|
|
|
|
$this->migrator->rollback([__DIR__.'/migrations/one'], ['database' => 'sqlite2']);
|
|
|
|
|
$this->migrator->rollback([__DIR__.'/migrations/one'], ['database' => 'sqlite2']);
|
2020-03-10 03:15:36 +01:00
|
|
|
$this->assertSame('default', $this->migrator->getConnection());
|
2019-11-30 14:12:39 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public function testConnectionPriorToMigrationIsNotChangedAfterMigrateReset()
|
|
|
|
|
{
|
|
|
|
|
$this->migrator->setConnection('default');
|
|
|
|
|
$this->migrator->run([__DIR__.'/migrations/one'], ['database' => 'sqlite2']);
|
|
|
|
|
$this->migrator->reset([__DIR__.'/migrations/one'], ['database' => 'sqlite2']);
|
2020-03-10 03:15:36 +01:00
|
|
|
$this->assertSame('default', $this->migrator->getConnection());
|
2019-11-30 14:12:39 +08:00
|
|
|
}
|
2016-05-25 11:21:56 -05:00
|
|
|
}
|