Skip to content
Snippets Groups Projects
UpTest.php 7.71 KiB
<?php

namespace Breyta\Test\Migrations;

use Breyta\Migration\CreateMigrationTable;
use Breyta\Model\Statement;
use Breyta\Test\Example\CreateAnimalsTable;
use Breyta\Test\TestCase;

class UpTest extends TestCase
{
    /** @test */
    public function executesMigrationsInSeparateTransactions()
    {
        list($migrationTableMigration, $animalsTableMigration) = $this->mockMigrations([
            'file' => '@breyta/CreateMigrationTable.php',
            'class' => CreateMigrationTable::class,
            'status' => 'new'
        ], [
            'file' => 'CreateAnimalsTable.php',
            'class' => CreateAnimalsTable::class,
            'status' => 'new'
        ]);

        $this->pdo->shouldReceive('beginTransaction')->once()->ordered();
        $migrationTableMigration->mock->shouldReceive('up')->once()->ordered();
        $this->pdo->shouldReceive('commit')->once()->ordered();
        $this->pdo->shouldReceive('beginTransaction')->once()->ordered();
        $animalsTableMigration->mock->shouldReceive('up')->once()->ordered();
        $this->pdo->shouldReceive('commit')->once()->ordered();

        $result = $this->migrations->up($migrationTableMigration->model, $animalsTableMigration->model);

        self::assertTrue($result);
    }

    /** @test */
    public function savesTheMigrationStatus()
    {
        $migration = $this->mockMigration('@breyta/CreateMigrationTable.php', CreateMigrationTable::class);

        $migration->mock->shouldReceive('up')->with()->once()->ordered();
        $this->mockPreparedStatement('/^insert into migrations/i')
            ->shouldReceive('execute')->withArgs(function (array $values) {
                self::assertCount(5, $values);
                self::assertSame('@breyta/CreateMigrationTable.php', array_shift($values));
                self::assertSame(date('c'), array_shift($values));
                self::assertSame('done', array_shift($values));
                self::assertSame('[]', array_shift($values));
                self::assertInternalType('double', array_shift($values));
                return true;
            })->once()->andReturn(1)->ordered();

        $result = $this->migrations->up($migration->model);

        self::assertTrue($result);
    }

    /** @test */
    public function updatesTheMigrationStatus()
    {
        $migration = $this->mockMigration('@breyta/CreateMigrationTable.php', CreateMigrationTable::class, 'failed');

        $migration->mock->shouldReceive('up')->with()->once()->ordered();
        $this->mockPreparedStatement('/^update migrations set/i')
            ->shouldReceive('execute')->withArgs(function (array $values) {
                self::assertCount(6, $values);
                self::assertSame(date('c'), array_shift($values));
                self::assertSame(null, array_shift($values));
                self::assertSame('done', array_shift($values));
                self::assertSame('[]', array_shift($values));
                self::assertInternalType('double', array_shift($values));
                self::assertSame('@breyta/CreateMigrationTable.php', array_shift($values));
                return true;
            })->once()->andReturn(1)->ordered();

        $result = $this->migrations->up($migration->model);

        self::assertTrue($result);
    }

    /** @test */
    public function pdoExceptionCausesARollback()
    {
        $migration = $this->mockMigration('@breyta/CreateMigrationTable.php', CreateMigrationTable::class);

        $migration->mock->shouldReceive('up')->with()->once()->andThrows(\PDOException::class)->ordered();
        $this->pdo->shouldReceive('rollback')->once()->ordered();

        self::expectException(\PDOException::class);
        $this->migrations->up($migration->model);
    }

    /** @test */
    public function savesFailedStatus()
    {
        $migration = $this->mockMigration('@breyta/CreateMigrationTable.php', CreateMigrationTable::class);

        $migration->mock->shouldReceive('up')->with()->once()->andThrows(\PDOException::class)->ordered();
        $this->mockPreparedStatement('/^insert into migrations/i')
            ->shouldReceive('execute')->withArgs(function (array $values) {
                self::assertCount(5, $values);
                self::assertSame('@breyta/CreateMigrationTable.php', array_shift($values));
                self::assertSame(date('c'), array_shift($values));
                self::assertSame('failed', array_shift($values));
                self::assertSame('[]', array_shift($values));
                self::assertInternalType('double', array_shift($values));
                return true;
            })->once()->andReturn(1)->ordered();

        self::expectException(\PDOException::class);
        $this->migrations->up($migration->model);
    }

    /** @test */
    public function executorRequiresAStatement()
    {
        $migration = $this->mockMigration('@breyta/CreateMigrationTable.php', CreateMigrationTable::class);

        $migration->mock->shouldReceive('up')->with()
            ->once()->andReturnUsing(function () {
                call_user_func($this->executor, 'CREATE TABLE migrations (col INT NOT NULL, PRIMARY KEY (col))');
            });

        self::expectException(\Error::class);
        self::expectExceptionMessage(' must be an instance of Breyta\Model\Statement, string given');

        $this->migrations->up($migration->model);
    }

    /** @test */
    public function executorExecutesTheStatement()
    {
        $migration = $this->mockMigration('@breyta/CreateMigrationTable.php', CreateMigrationTable::class);

        $migration->mock->shouldReceive('up')->with()
            ->once()->andReturnUsing(function () {
                call_user_func($this->executor, Statement::createInstance([
                    'raw' => 'CREATE TABLE migrations (col INT NOT NULL, PRIMARY KEY (col))',
                ]));
            })->ordered();
        $this->pdo->shouldReceive('exec')->with('CREATE TABLE migrations (col INT NOT NULL, PRIMARY KEY (col))')
            ->once()->andReturn(1);

        $this->migrations->up($migration->model);
    }

    /** @test */
    public function addsExecutionTimeToStatement()
    {
        $statement = Statement::createInstance([
            'raw' => 'CREATE TABLE migrations (col INT NOT NULL, PRIMARY KEY (col))',
        ]);

        $this->mockExecuteStatement($statement);

        self::assertInternalType('double', $statement->executionTime);
    }

    /** @test */
    public function addsThrownExceptionToStatement()
    {
        $statement = Statement::createInstance([
                'raw' => 'CREATE TABLE migrations (col INT NOT NULL, PRIMARY KEY (col))',
        ]);

        try {
            $this->mockExecuteStatement($statement, new \PDOException('Failed'));
            $this->fail('Expected PDOException');
        } catch (\PDOException $exception) {
            self::assertSame($exception, $statement->exception);
            self::assertInternalType('double', $statement->executionTime);
        }
    }

    /** @test */
    public function addsStatementsToMigrationStatus()
    {
        $statement = Statement::createInstance([
            'raw' => 'CREATE TABLE migrations (col INT NOT NULL, PRIMARY KEY (col))',
            'teaser' => 'CREATE TABLE migrations',
            'action' => 'create',
            'type' => 'table',
            'name' => 'migrations',
        ]);

        $this->mockPreparedStatement('/^insert into migrations/i')
            ->shouldReceive('execute')->withArgs(function (array $values) use ($statement) {
                self::assertCount(5, $values);
                self::assertSame(
                    json_encode([$statement]),
                    $values[3]
                );
                return true;
            })->once()->andReturn(1);

        $this->mockExecuteStatement($statement);
    }
}