From 42001496ebdc8344dd2dac1b75c484dbd29d145a Mon Sep 17 00:00:00 2001 From: Matt Button Date: Thu, 17 Feb 2011 23:53:15 +0000 Subject: [PATCH] Adding tests for/fixing fetch_required_migrations() / resolve_target() --- classes/model/minion/migration.php | 156 ++++++++++++++++++++++++----- tests/minion/migration/model.php | 108 +++++++++++++++++--- 2 files changed, 225 insertions(+), 39 deletions(-) diff --git a/classes/model/minion/migration.php b/classes/model/minion/migration.php index 3c37ba2..eb82211 100644 --- a/classes/model/minion/migration.php +++ b/classes/model/minion/migration.php @@ -285,12 +285,23 @@ class Model_Minion_Migration extends Model */ public function fetch_required_migrations($group = NULL, $target = TRUE) { - $migrations = array(); + $migrations = array(); + $current_groups = $this->fetch_groups(TRUE); + + foreach ( (array) $group as $group_name) + { + if ( ! isset($current_groups[$group_name])) + { + throw new Kohana_Exception("Migration group :group does not exist", array(':group' => $group_name)); + } + } $query = $this->_select(); if (is_bool($target)) { + $up = $target; + // If we want to limit this migration to certain groups if ($group !== NULL) { @@ -303,21 +314,6 @@ class Model_Minion_Migration extends Model $query->where('group', '=', $group); } } - - // If we're migrating up - if ($target === TRUE) - { - $query - ->where('applied', '=', 0) - ->order_by('timestamp', 'ASC'); - } - // If we're migrating down - else - { - $query - ->where('applied', '>', 0) - ->order_by('timestamp', 'DESC'); - } } else { @@ -327,19 +323,133 @@ class Model_Minion_Migration extends Model if ($up) { - $query - ->where('timestamp', '<=', $target) - ->where('applied', '=', 0) - ->order_by('timestamp', 'ASC'); + $query->where('timestamp', '<=', $target); } else { - $query - ->where('timestamp', '>', $target) - ->order_by('timestamp', 'DESC'); + $query->where('timestamp', '>', $target); } } + + // If we're migrating up + if ($up) + { + $query + ->where('applied', '=', 0) + ->order_by('timestamp', 'ASC'); + } + // If we're migrating down + else + { + $query + ->where('applied', '>', 0) + ->order_by('timestamp', 'DESC'); + } + return $query->execute($this->_db)->as_array(); } + + /** + * Resolve a (potentially relative) target for a group to a definite timestamp + * + * @param string Group name + * @param string|int Target + * @return array First element timestamp, second is boolean (TRUE if up, FALSE if down) + */ + public function resolve_target($group, $target) + { + if (empty($group)) + { + throw new Kohana_Exception("No group specified"); + } + + if (is_array($group)) + { + if (count($group) > 1) + { + throw new Kohana_Exception("A target can only be expressed for a single group"); + } + + $group = $group[0]; + } + + $amount = NULL; + $query = $this->_select(); + $statuses = $this->fetch_current_versions(); + $target = (string) $target; + $group_applied = isset($statuses[$group]); + $up = NULL; + $timestamp = $group_applied ? $statuses[$group]['timestamp'] : NULL; + + // If this target is relative to the current state of the group + if ($target[0] === '+' OR $target[0] === '-') + { + $amount = substr($target, 1); + $up = $target[0] === '+'; + + if ($up) + { + if ($group_applied) + { + $query->where('timestamp', '>', $timestamp); + } + } + else + { + if ( ! $group_applied) + { + throw new Kohana_Exception( + "Cannot migrate group :group down as none of its migrations have been applied", + array(':group' => $group) + ); + } + + $query->where('timestamp', '<=', $timestamp); + } + + $query->limit($amount); + } + // Else this is an absolute target + else + { + if ($group_applied) + { + $up = ( (int) $timestamp < (int) $target); + + $query->where('timestamp', ($up ? '>' : '<='), $timestamp); + } + else + { + $up = TRUE; + } + + if ($up) + { + $query->where('timestamp', '<=', $target); + } + else + { + $query->where('timestamp', '>', $target); + } + } + + if ( ! $up) + { + $query->where('applied', '>', 0); + } + + $query->where('group', '=', $group); + + $query->order_by('timestamp', ($up ? 'ASC' : 'DESC')); + + $results = $query->execute($this->_db); + + if ($amount !== NULL AND count($results) != $amount) + { + return array(NULL, $up); + } + + return array((float) $query->execute($this->_db)->get('timestamp'), $up); + } } diff --git a/tests/minion/migration/model.php b/tests/minion/migration/model.php index 2f5b205..6e5797f 100644 --- a/tests/minion/migration/model.php +++ b/tests/minion/migration/model.php @@ -99,15 +99,15 @@ class Minion_Migration_ModelTest extends Kohana_Unittest_Database_TestCase return array( // Test going up in a specific group array( - array ( - array ( + array( + array( 'timestamp' => '20101215165000', 'description' => 'add-name-column-to-members', 'group' => 'app', 'applied' => '0', 'id' => 'app:20101215165000', ), - array ( + array( 'timestamp' => '20101216000000', 'description' => 'add-index-on-name', 'group' => 'app', @@ -120,15 +120,15 @@ class Minion_Migration_ModelTest extends Kohana_Unittest_Database_TestCase ), // Testing going down with a specific group array( - array ( - array ( + array( + array( 'timestamp' => '20101216080000', 'description' => 'remove-password-salt-column', 'group' => 'app', 'applied' => '1', 'id' => 'app:20101216080000', ), - array ( + array( 'timestamp' => '20101215164400', 'description' => 'create-tables', 'group' => 'app', @@ -141,22 +141,22 @@ class Minion_Migration_ModelTest extends Kohana_Unittest_Database_TestCase ), // Testing going up across all groups array( - array ( - array ( + array( + array( 'timestamp' => '20101215165000', 'description' => 'add-name-column-to-members', 'group' => 'app', 'applied' => '0', 'id' => 'app:20101215165000', ), - array ( + array( 'timestamp' => '20101216000000', 'description' => 'add-index-on-name', 'group' => 'app', 'applied' => '0', 'id' => 'app:20101216000000', ), - array ( + array( 'timestamp' => '20101226112100', 'description' => 'add-pk', 'group' => 'dblogger', @@ -169,29 +169,29 @@ class Minion_Migration_ModelTest extends Kohana_Unittest_Database_TestCase ), // Testing going down across all groups array( - array ( - array ( + array( + array( 'timestamp' => '20101225000000', 'description' => 'remove-unique-index', 'group' => 'dblogger', 'applied' => '1', 'id' => 'dblogger:20101225000000', ), - array ( + array( 'timestamp' => '20101216080000', 'description' => 'remove-password-salt-column', 'group' => 'app', 'applied' => '1', 'id' => 'app:20101216080000', ), - array ( + array( 'timestamp' => '20101215164500', 'description' => 'create-table', 'group' => 'dblogger', 'applied' => '1', 'id' => 'dblogger:20101215164500', ), - array ( + array( 'timestamp' => '20101215164400', 'description' => 'create-tables', 'group' => 'app', @@ -201,7 +201,27 @@ class Minion_Migration_ModelTest extends Kohana_Unittest_Database_TestCase ), NULL, FALSE - ) + ), + array( + array( + array( + 'timestamp' => '20101216080000', + 'description' => 'remove-password-salt-column', + 'group' => 'app', + 'applied' => '1', + 'id' => 'app:20101216080000', + ), + array( + 'timestamp' => '20101215164400', + 'description' => 'create-tables', + 'group' => 'app', + 'applied' => '1', + 'id' => 'app:20101215164400', + ), + ), + 'app', + 20101216080000 + ), ); } @@ -355,4 +375,60 @@ class Minion_Migration_ModelTest extends Kohana_Unittest_Database_TestCase $model->get_migration($migration['group'], $migration['timestamp']) ); } + + /** + * Provides test data for test_resolve_target() + * + * @return array + */ + public function provider_resolve_target() + { + return array( + array( + array(20101216080000, FALSE), + 'app', + '-1' + ), + array( + array(NULL, FALSE), + 'dblogger', + '-10' + ), + array( + array(20101226112100, TRUE), + 'dblogger', + '+1', + ), + array( + array(NULL, TRUE), + 'app', + '+10' + ), + array( + array(NULL, TRUE), + 'dblogger', + '+100' + ), + ); + } + + /** + * Test that we can resolve a target version for a group. + * + * Target version can be relative (+migrations_up / -migrations_down) or absolute (i.e. timestamp) + * + * @test + * @dataProvider provider_resolve_target + * @covers Model_Minion_Migration::resolve_target + * @param array Expected output + * @param string Group name + * @param string Target version + */ + public function test_resolve_target($expected, $group, $target) + { + $this->assertSame( + $expected, + $this->getModel()->resolve_target($group, $target) + ); + } }