Skip to content
GitLab
Explore
Sign in
Register
Primary navigation
Search or go to…
Project
B
breyta
Manage
Activity
Members
Labels
Plan
Issues
0
Issue boards
Milestones
Wiki
Code
Merge requests
0
Repository
Branches
Commits
Tags
Repository graph
Compare revisions
Snippets
Build
Pipelines
Jobs
Pipeline schedules
Artifacts
Deploy
Releases
Package Registry
Model registry
Operate
Environments
Terraform modules
Monitor
Incidents
Service Desk
Analyze
Value stream analytics
Contributor analytics
CI/CD analytics
Repository analytics
Model experiments
Help
Help
Support
GitLab documentation
Compare GitLab plans
Community forum
Contribute to GitLab
Provide feedback
Keyboard shortcuts
?
Snippets
Groups
Projects
Show more breadcrumbs
Thomas Flori
breyta
Commits
6865b715
Unverified
Commit
6865b715
authored
6 years ago
by
Thomas Flori
Browse files
Options
Downloads
Patches
Plain Diff
test and refactor migrate prototype
parent
fc653edd
No related branches found
No related tags found
No related merge requests found
Changes
3
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
src/Migrations.php
+21
-28
21 additions, 28 deletions
src/Migrations.php
tests/Migrations/MigrateTest.php
+199
-12
199 additions, 12 deletions
tests/Migrations/MigrateTest.php
tests/TestCase.php
+20
-2
20 additions, 2 deletions
tests/TestCase.php
with
240 additions
and
42 deletions
src/Migrations.php
+
21
−
28
View file @
6865b715
...
@@ -43,6 +43,7 @@ class Migrations
...
@@ -43,6 +43,7 @@ class Migrations
$this
->
db
=
$db
;
$this
->
db
=
$db
;
$this
->
path
=
rtrim
(
$path
,
'/'
);
$this
->
path
=
rtrim
(
$path
,
'/'
);
/** @codeCoverageIgnore the default resolver is a) trivial and b) not testable */
$this
->
resolver
=
$resolver
??
function
(
$class
,
...
$args
)
{
$this
->
resolver
=
$resolver
??
function
(
$class
,
...
$args
)
{
if
(
$class
===
AdapterInterface
::
class
)
{
if
(
$class
===
AdapterInterface
::
class
)
{
return
new
BasicAdapter
(
...
$args
);
return
new
BasicAdapter
(
...
$args
);
...
@@ -72,16 +73,10 @@ class Migrations
...
@@ -72,16 +73,10 @@ class Migrations
public
function
migrate
(
string
$file
=
null
):
bool
public
function
migrate
(
string
$file
=
null
):
bool
{
{
$status
=
$this
->
getStatus
();
$status
=
$this
->
getStatus
();
$toExecute
=
array_filter
(
$status
->
migrations
,
function
(
Model
\Migration
$migration
)
{
$toExecute
=
array_filter
(
$status
->
migrations
,
function
(
Model
\Migration
$migration
)
use
(
$file
)
{
return
$migration
->
status
!==
'done'
;
return
$migration
->
status
!==
'done'
&&
(
!
$file
||
strpos
(
$migration
->
file
,
$file
)
!==
false
)
;
});
});
if
(
$file
&&
!
isset
(
$toExecute
[
$file
]))
{
return
true
;
// nothing to migrate?
}
elseif
(
$file
)
{
$toExecute
=
[
$toExecute
[
$file
]];
}
/**
/**
* @var string $file
* @var string $file
* @var Model\Migration $migration
* @var Model\Migration $migration
...
@@ -97,9 +92,9 @@ class Migrations
...
@@ -97,9 +92,9 @@ class Migrations
$this
->
saveMigration
(
$migration
,
'done'
,
microtime
(
true
)
-
$start
);
$this
->
saveMigration
(
$migration
,
'done'
,
microtime
(
true
)
-
$start
);
$this
->
db
->
commit
();
$this
->
db
->
commit
();
}
catch
(
\Exception
$exception
)
{
}
catch
(
\
PDO
Exception
$exception
)
{
$this
->
db
->
rollBack
();
$this
->
db
->
rollBack
();
$this
->
saveMigration
(
$migration
,
'failed'
,
microtime
(
true
)
-
$start
);
//
$this->saveMigration($migration, 'failed', microtime(true) - $start);
return
false
;
return
false
;
}
}
}
}
...
@@ -129,7 +124,7 @@ class Migrations
...
@@ -129,7 +124,7 @@ class Migrations
]);
]);
}
}
protected
function
loadMigrations
()
:
array
protected
function
loadMigrations
()
{
{
if
(
!
$this
->
migrations
)
{
if
(
!
$this
->
migrations
)
{
$this
->
migrations
=
$this
->
findMigrations
();
$this
->
migrations
=
$this
->
findMigrations
();
...
@@ -151,8 +146,6 @@ class Migrations
...
@@ -151,8 +146,6 @@ class Migrations
// the table does not exist - so nothing to do here
// the table does not exist - so nothing to do here
}
}
}
}
return
$this
->
migrations
;
}
}
protected
function
findMigrations
():
array
protected
function
findMigrations
():
array
...
@@ -235,19 +228,19 @@ class Migrations
...
@@ -235,19 +228,19 @@ class Migrations
return
$migrations
;
return
$migrations
;
}
}
protected
function
executeStatement
(
Model
\Statement
$statement
)
//
protected function executeStatement(Model\Statement $statement)
{
//
{
$start
=
microtime
(
true
);
//
$start = microtime(true);
try
{
//
try {
$statement
->
result
=
$this
->
db
->
exec
(
$statement
);
//
$statement->result = $this->db->exec($statement);
$statement
->
exception
=
null
;
//
$statement->exception = null;
}
catch
(
\PDOException
$exception
)
{
//
} catch (\PDOException $exception) {
$statement
->
exception
=
$exception
;
//
$statement->exception = $exception;
throw
$exception
;
//
throw $exception;
}
finally
{
//
} finally {
$statement
->
executionTime
=
microtime
(
true
)
-
$start
;
//
$statement->executionTime = microtime(true) - $start;
}
//
}
}
//
}
protected
function
getAdapter
():
AdapterInterface
protected
function
getAdapter
():
AdapterInterface
{
{
...
@@ -256,8 +249,8 @@ class Migrations
...
@@ -256,8 +249,8 @@ class Migrations
$this
->
resolver
,
$this
->
resolver
,
AdapterInterface
::
class
,
AdapterInterface
::
class
,
function
(
Model
\Statement
$statement
)
{
function
(
Model
\Statement
$statement
)
{
$this
->
statements
[]
=
$statement
;
//
$this->statements[] = $statement;
$this
->
executeStatement
(
$statement
);
//
$this->executeStatement($statement);
}
}
);
);
}
}
...
...
This diff is collapsed.
Click to expand it.
tests/Migrations/MigrateTest.php
+
199
−
12
View file @
6865b715
...
@@ -2,8 +2,12 @@
...
@@ -2,8 +2,12 @@
namespace
Breyta\Test\Migrations
;
namespace
Breyta\Test\Migrations
;
use
Breyta\AdapterInterface
;
use
Breyta\BasicAdapter
;
use
Breyta\Migration\CreateMigrationTable
;
use
Breyta\Migrations
;
use
Breyta\Migrations
;
use
Breyta\Model\Migration
;
use
Breyta\Model\Migration
;
use
Breyta\Test\Example\CreateAnimalsTable
;
use
Breyta\Test\TestCase
;
use
Breyta\Test\TestCase
;
use
Mockery
as
m
;
use
Mockery
as
m
;
...
@@ -25,26 +29,209 @@ class MigrateTest extends TestCase
...
@@ -25,26 +29,209 @@ class MigrateTest extends TestCase
$resolver
=
$this
->
resolver
=
m
::
spy
(
function
(
$class
,
...
$args
)
{
$resolver
=
$this
->
resolver
=
m
::
spy
(
function
(
$class
,
...
$args
)
{
return
new
$class
(
...
$args
);
return
new
$class
(
...
$args
);
});
});
$migrations
=
$this
->
migrations
=
m
::
mock
(
Migrations
::
class
,
[
$this
->
pdo
,
__DIR__
.
'/../Example'
,
$resolver
])
$this
->
migrations
=
m
::
mock
(
Migrations
::
class
,
[
$this
->
pdo
,
__DIR__
.
'/../Example'
,
$resolver
])
->
makePartial
();
->
makePartial
();
$resolver
->
shouldReceive
(
'__invoke'
)
->
with
(
AdapterInterface
::
class
,
m
::
type
(
\Closure
::
class
))
->
andReturn
(
m
::
mock
(
BasicAdapter
::
class
))
->
byDefault
();
$this
->
mockPreparedStatement
(
'/^insert into migrations/i'
,
true
);
$this
->
mockPreparedStatement
(
'/^delete from migrations/i'
,
true
,
0
);
}
/** @test */
public
function
returnsSuccessWhenNoMigrationsNeedToBeExecuted
()
{
$this
->
mockStatus
(
Migration
::
createInstance
([
'file'
=>
'@breyta/CreateMigrationTable.php'
,
'status'
=>
'done'
]))
->
once
();
$result
=
$this
->
migrations
->
migrate
();
self
::
assertTrue
(
$result
);
}
/** @test */
public
function
executesNewMigrations
()
{
$migration
=
$this
->
mockMigration
(
'@breyta/CreateMigrationTable.php'
,
CreateMigrationTable
::
class
);
$this
->
mockStatus
(
Migration
::
createInstance
([
'file'
=>
'@breyta/CreateMigrationTable.php'
,
'status'
=>
'new'
]))
->
once
()
->
ordered
();
$migration
->
shouldReceive
(
'up'
)
->
with
()
->
once
()
->
ordered
();
$result
=
$this
->
migrations
->
migrate
();
self
::
assertTrue
(
$result
);
}
/** @test */
public
function
executesFailedMigrations
()
{
$migration
=
$this
->
mockMigration
(
'@breyta/CreateMigrationTable.php'
,
CreateMigrationTable
::
class
);
$this
->
mockStatus
(
Migration
::
createInstance
([
'file'
=>
'@breyta/CreateMigrationTable.php'
,
'status'
=>
'failed'
]))
->
once
()
->
ordered
();
$migration
->
shouldReceive
(
'up'
)
->
with
()
->
once
()
->
ordered
();
$result
=
$this
->
migrations
->
migrate
();
self
::
assertTrue
(
$result
);
}
/** @test */
public
function
executesOnlyMatchingMigrations
()
{
$migrationTableMigration
=
$this
->
mockMigration
(
'@breyta/CreateMigrationTable.php'
,
CreateMigrationTable
::
class
);
$animalsTableMigration
=
$this
->
mockMigration
(
'CreateAnimalsTable.php'
,
CreateAnimalsTable
::
class
);
$this
->
mockStatus
(
Migration
::
createInstance
([
'file'
=>
'@breyta/CreateMigrationTable.php'
,
'status'
=>
'new'
]),
Migration
::
createInstance
([
'file'
=>
'CreateAnimalsTable.php'
,
'status'
=>
'new'
]))
->
once
()
->
ordered
();
$migrationTableMigration
->
shouldReceive
(
'up'
)
->
with
()
->
once
()
->
ordered
();
$animalsTableMigration
->
shouldNotReceive
(
'up'
);
$result
=
$this
->
migrations
->
migrate
(
'MigrationTable'
);
self
::
assertTrue
(
$result
);
}
$migrations
->
shouldReceive
(
'getStatus'
)
->
with
()
/** @test */
->
andReturn
((
object
)[
public
function
executesMigrationsInSeparateTransactions
()
'migrations'
=>
[
{
Migration
::
createInstance
([
$migrationTableMigration
=
$this
->
mockMigration
(
'file'
=>
'@breyta/CreateMigrationTable.php'
,
'@breyta/CreateMigrationTable.php'
,
'status'
=>
'done'
CreateMigrationTable
::
class
]),
);
],
$animalsTableMigration
=
$this
->
mockMigration
(
'CreateAnimalsTable.php'
,
CreateAnimalsTable
::
class
);
'count'
=>
0
,
$this
->
mockStatus
(
Migration
::
createInstance
([
])
->
byDefault
();
'file'
=>
'@breyta/CreateMigrationTable.php'
,
'status'
=>
'new'
]),
Migration
::
createInstance
([
'file'
=>
'CreateAnimalsTable.php'
,
'status'
=>
'new'
]))
->
once
()
->
ordered
();
$this
->
pdo
->
shouldReceive
(
'beginTransaction'
)
->
once
()
->
ordered
();
$migrationTableMigration
->
shouldReceive
(
'up'
)
->
once
()
->
ordered
();
$this
->
pdo
->
shouldReceive
(
'commit'
)
->
once
()
->
ordered
();
$this
->
pdo
->
shouldReceive
(
'beginTransaction'
)
->
once
()
->
ordered
();
$animalsTableMigration
->
shouldReceive
(
'up'
)
->
once
()
->
ordered
();
$this
->
pdo
->
shouldReceive
(
'commit'
)
->
once
()
->
ordered
();
$result
=
$this
->
migrations
->
migrate
();
self
::
assertTrue
(
$result
);
}
/** @test */
public
function
savesTheMigrationStatus
()
{
$migration
=
$this
->
mockMigration
(
'@breyta/CreateMigrationTable.php'
,
CreateMigrationTable
::
class
);
$this
->
mockStatus
(
Migration
::
createInstance
([
'file'
=>
'@breyta/CreateMigrationTable.php'
,
'status'
=>
'new'
]))
->
once
()
->
ordered
();
$migration
->
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
->
migrate
();
self
::
assertTrue
(
$result
);
}
}
/** @test */
/** @test */
public
function
re
turnsSuccessAsBoolean
()
public
function
re
movesPreviousStatus
()
{
{
$migration
=
$this
->
mockMigration
(
'@breyta/CreateMigrationTable.php'
,
CreateMigrationTable
::
class
);
$this
->
mockStatus
(
Migration
::
createInstance
([
'file'
=>
'@breyta/CreateMigrationTable.php'
,
'status'
=>
'failed'
]))
->
once
()
->
ordered
();
$migration
->
shouldReceive
(
'up'
)
->
with
()
->
once
()
->
ordered
();
$this
->
mockPreparedStatement
(
'/^delete from migrations/i'
)
->
shouldReceive
(
'execute'
)
->
with
([
'@breyta/CreateMigrationTable.php'
])
->
once
()
->
andReturn
(
1
)
->
ordered
();
$result
=
$this
->
migrations
->
migrate
();
$result
=
$this
->
migrations
->
migrate
();
self
::
assertTrue
(
$result
);
self
::
assertTrue
(
$result
);
}
}
/** @test */
public
function
pdoExceptionCausesARollback
()
{
$migration
=
$this
->
mockMigration
(
'@breyta/CreateMigrationTable.php'
,
CreateMigrationTable
::
class
);
$this
->
mockStatus
(
Migration
::
createInstance
([
'file'
=>
'@breyta/CreateMigrationTable.php'
,
'status'
=>
'new'
]))
->
once
()
->
ordered
();
$migration
->
shouldReceive
(
'up'
)
->
with
()
->
once
()
->
andThrows
(
\PDOException
::
class
)
->
ordered
();
$this
->
pdo
->
shouldReceive
(
'rollback'
)
->
once
()
->
ordered
();
$result
=
$this
->
migrations
->
migrate
();
self
::
assertFalse
(
$result
);
}
/**
* @param Migration ...$migrations
* @return m\CompositeExpectation|m\Expectation
*/
protected
function
mockStatus
(
Migration
...
$migrations
):
m
\CompositeExpectation
{
$status
=
(
object
)[
'migrations'
=>
array_combine
(
array_map
(
function
(
Migration
$migration
)
{
return
$migration
->
file
;
},
$migrations
),
$migrations
),
'count'
=>
count
(
array_filter
(
$migrations
,
function
(
Migration
$migration
)
{
return
$migration
->
status
!==
'done'
;
}))
];
return
$this
->
migrations
->
shouldReceive
(
'getStatus'
)
->
with
()
->
andReturn
(
$status
);
}
/**
* @param string $file
* @param string $class
* @return m\MockInterface
*/
protected
function
mockMigration
(
string
$file
,
string
$class
):
m
\MockInterface
{
// add the file -> class mapping
$reflection
=
new
\ReflectionClass
(
$this
->
migrations
);
$property
=
$reflection
->
getProperty
(
'classes'
);
$property
->
setAccessible
(
true
);
$classes
=
$property
->
getValue
(
$this
->
migrations
);
$classes
[
$file
]
=
$class
;
$property
->
setValue
(
$this
->
migrations
,
$classes
);
$this
->
resolver
->
shouldReceive
(
'__invoke'
)
->
with
(
$class
,
m
::
type
(
AdapterInterface
::
class
))
->
andReturn
(
$migrationInstance
=
m
::
mock
(
CreateMigrationTable
::
class
));
return
$migrationInstance
;
}
}
}
This diff is collapsed.
Click to expand it.
tests/TestCase.php
+
20
−
2
View file @
6865b715
...
@@ -7,16 +7,34 @@ use Mockery as m;
...
@@ -7,16 +7,34 @@ use Mockery as m;
abstract
class
TestCase
extends
MockeryTestCase
abstract
class
TestCase
extends
MockeryTestCase
{
{
/** @var m\Mock
|\PDO
*/
/** @var m\Mock */
protected
$pdo
;
protected
$pdo
;
protected
function
setUp
()
protected
function
setUp
()
{
{
parent
::
setUp
(
);
date_default_timezone_set
(
'UTC'
);
$pdo
=
$this
->
pdo
=
m
::
mock
(
\PDO
::
class
);
$pdo
=
$this
->
pdo
=
m
::
mock
(
\PDO
::
class
);
$pdo
->
shouldReceive
(
'setAttribute'
)
->
with
(
\PDO
::
ATTR_ERRMODE
,
\PDO
::
ERRMODE_EXCEPTION
)
$pdo
->
shouldReceive
(
'setAttribute'
)
->
with
(
\PDO
::
ATTR_ERRMODE
,
\PDO
::
ERRMODE_EXCEPTION
)
->
andReturn
(
true
)
->
byDefault
();
->
andReturn
(
true
)
->
byDefault
();
$pdo
->
shouldReceive
(
'beginTransaction'
)
->
byDefault
();
$pdo
->
shouldReceive
(
'commit'
)
->
byDefault
();
$pdo
->
shouldReceive
(
'rollback'
)
->
byDefault
();
$pdo
->
shouldReceive
(
'query'
)
->
andReturn
(
false
)
->
byDefault
();
$pdo
->
shouldReceive
(
'query'
)
->
andReturn
(
false
)
->
byDefault
();
}
}
protected
function
mockPreparedStatement
(
string
$pattern
,
$byDefault
=
false
,
$defaultResult
=
1
)
{
$statement
=
m
::
mock
(
\PDOStatement
::
class
);
$statement
->
shouldReceive
(
'execute'
)
->
byDefault
()
->
andReturn
(
$defaultResult
);
$expectation
=
$this
->
pdo
->
shouldReceive
(
'prepare'
)
->
with
(
m
::
pattern
(
$pattern
));
if
(
$byDefault
)
{
$expectation
->
byDefault
()
->
andReturn
(
$statement
);
}
else
{
$expectation
->
once
()
->
andReturn
(
$statement
);
}
return
$statement
;
}
}
}
This diff is collapsed.
Click to expand it.
Preview
0%
Loading
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Save comment
Cancel
Please
register
or
sign in
to comment