Merge "Support unique labels for alembic branches"

This commit is contained in:
Jenkins 2016-07-05 12:55:03 +00:00 committed by Gerrit Code Review
commit d112b65c5f
7 changed files with 205 additions and 97 deletions

View File

@ -418,6 +418,20 @@ following directive should be added in the contraction script::
depends_on = ('<expansion-revision>',) depends_on = ('<expansion-revision>',)
Expand and Contract Branch Labeling
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Before the Newton release, neutron and each sub-project had its own alembic
environment and each repo could re-use the labels ``contract`` and ``expand``
for their alembic branches. With the Newton release, all neutron sub-projects
use neutron's alembic environment, and this requires globally unique branch
labels.
To be compatible with the Newton release of neutron, all projects must use
unique alembic branch labels of the form ``<project>-contract`` and
``<project>-expand``.
HEAD files for conflict management HEAD files for conflict management
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

View File

@ -25,7 +25,7 @@ from neutron.db.migration import cli
# revision identifiers, used by Alembic. # revision identifiers, used by Alembic.
revision = '30018084ec99' revision = '30018084ec99'
down_revision = 'kilo' down_revision = 'kilo'
branch_labels = (cli.CONTRACT_BRANCH,) branch_labels = ('neutron-' + cli.CONTRACT_BRANCH,)
def upgrade(): def upgrade():

View File

@ -30,7 +30,7 @@ from neutron.db.migration import cli
# revision identifiers, used by Alembic. # revision identifiers, used by Alembic.
revision = '354db87e3225' revision = '354db87e3225'
down_revision = 'kilo' down_revision = 'kilo'
branch_labels = (cli.EXPAND_BRANCH,) branch_labels = ('neutron-' + cli.EXPAND_BRANCH,)
def upgrade(): def upgrade():

View File

@ -54,7 +54,8 @@ def _migration_script_ops(context, directive, phase):
version_path = cli._get_version_branch_path( version_path = cli._get_version_branch_path(
context.config, release=cli.CURRENT_RELEASE, branch=phase) context.config, release=cli.CURRENT_RELEASE, branch=phase)
autogen_kwargs = {} autogen_kwargs = {}
cli._check_bootstrap_new_branch(phase, version_path, autogen_kwargs) cli._check_bootstrap_new_branch(context.config, phase, version_path,
autogen_kwargs)
op = ops.MigrationScript( op = ops.MigrationScript(
new_rev_id(), new_rev_id(),

View File

@ -93,11 +93,14 @@ CONF.register_cli_opts(_db_opts, 'database')
def do_alembic_command(config, cmd, revision=None, desc=None, **kwargs): def do_alembic_command(config, cmd, revision=None, desc=None, **kwargs):
project = config.get_main_option('neutron_project')
args = [] args = []
if revision: if revision:
# We use unique branch labels from Newton onwards.
if revision.split('@')[0] in MIGRATION_BRANCHES:
revision = '-'.join([project, revision])
args.append(revision) args.append(revision)
project = config.get_main_option('neutron_project')
if desc: if desc:
alembic_util.msg(_('Running %(cmd)s (%(desc)s) for %(project)s ...') % alembic_util.msg(_('Running %(cmd)s (%(desc)s) for %(project)s ...') %
{'cmd': cmd, 'desc': desc, 'project': project}) {'cmd': cmd, 'desc': desc, 'project': project})
@ -142,13 +145,13 @@ def add_branch_options(parser):
def _find_milestone_revisions(config, milestone, branch=None): def _find_milestone_revisions(config, milestone, branch=None):
"""Return the revision(s) for a given milestone.""" """Return the revision(s) for a given milestone."""
script = alembic_script.ScriptDirectory.from_config(config) script = alembic_script.ScriptDirectory.from_config(config)
return [ milestone_revisions = []
(m.revision, label) for m in _get_revisions(script):
for m in _get_revisions(script) for branch_label in (m.branch_labels or [None]):
for label in (m.branch_labels or [None]) if milestone in getattr(m.module, 'neutron_milestone', []):
if milestone in getattr(m.module, 'neutron_milestone', []) and if branch is None or branch_label.endswith(branch):
(branch is None or branch in m.branch_labels) milestone_revisions.append((m.revision, branch))
] return milestone_revisions
def do_upgrade(config, cmd): def do_upgrade(config, cmd):
@ -161,11 +164,11 @@ def do_upgrade(config, cmd):
if CONF.command.expand: if CONF.command.expand:
branch = EXPAND_BRANCH branch = EXPAND_BRANCH
revision = _get_branch_head(EXPAND_BRANCH) revision = _get_branch_head(config, EXPAND_BRANCH)
elif CONF.command.contract: elif CONF.command.contract:
branch = CONTRACT_BRANCH branch = CONTRACT_BRANCH
revision = _get_branch_head(CONTRACT_BRANCH) revision = _get_branch_head(config, CONTRACT_BRANCH)
elif not CONF.command.revision and not CONF.command.delta: elif not CONF.command.revision and not CONF.command.delta:
raise SystemExit(_('You must provide a revision or relative delta')) raise SystemExit(_('You must provide a revision or relative delta'))
@ -217,14 +220,26 @@ def do_stamp(config, cmd):
sql=CONF.command.sql) sql=CONF.command.sql)
def _get_branch_head(branch): def _get_branch_head(config, branch):
'''Get the latest @head specification for a branch.''' '''Get the latest @head specification for a branch.'''
script_dir = alembic_script.ScriptDirectory.from_config(config)
revs = script_dir.revision_map.get_revisions('heads')
for rev in revs:
for branch_label in rev.branch_labels:
# For forwards and backwards compatibility we handle branch
# names of either
# 'contract/expand'
# or
# 'subproject-contract/subproject-expand'.
if branch_label.endswith(branch):
branch = branch_label
break
return '%s@head' % branch return '%s@head' % branch
def _check_bootstrap_new_branch(branch, version_path, addn_kwargs): def _check_bootstrap_new_branch(config, branch, version_path, addn_kwargs):
addn_kwargs['version_path'] = version_path addn_kwargs['version_path'] = version_path
addn_kwargs['head'] = _get_branch_head(branch) addn_kwargs['head'] = _get_branch_head(config, branch)
if not os.path.exists(version_path): if not os.path.exists(version_path):
# Bootstrap initial directory structure # Bootstrap initial directory structure
utils.ensure_dir(version_path) utils.ensure_dir(version_path)
@ -251,7 +266,7 @@ def do_revision(config, cmd):
args = copy.copy(kwargs) args = copy.copy(kwargs)
version_path = _get_version_branch_path( version_path = _get_version_branch_path(
config, release=CURRENT_RELEASE, branch=branch) config, release=CURRENT_RELEASE, branch=branch)
_check_bootstrap_new_branch(branch, version_path, args) _check_bootstrap_new_branch(config, branch, version_path, args)
do_alembic_command(config, cmd, **args) do_alembic_command(config, cmd, **args)
else: else:
# autogeneration code will take care of enforcing proper directories # autogeneration code will take care of enforcing proper directories
@ -260,32 +275,15 @@ def do_revision(config, cmd):
update_head_files(config) update_head_files(config)
def _get_release_labels(labels):
result = set()
for label in labels:
# release labels were introduced Liberty for a short time and dropped
# in that same release cycle
result.add('%s_%s' % (migration.LIBERTY, label))
return result
def _compare_labels(revision, expected_labels): def _compare_labels(revision, expected_labels):
# validate that the script has expected labels only # validate that the script has expected labels only
bad_labels = revision.branch_labels - expected_labels expected_branch_labels = set()
for label in revision.branch_labels:
for expected_label in expected_labels:
if label.endswith(expected_label):
expected_branch_labels.add(label)
bad_labels = revision.branch_labels - expected_branch_labels
if bad_labels: if bad_labels:
# NOTE(ihrachyshka): this hack is temporary to accommodate those
# projects that already initialized their branches with liberty_*
# labels. Let's notify them about the deprecation for now and drop it
# later.
bad_labels_with_release = (revision.branch_labels -
_get_release_labels(expected_labels))
if not bad_labels_with_release:
alembic_util.warn(
_('Release aware branch labels (%s) are deprecated. '
'Please switch to expand@ and contract@ '
'labels.') % bad_labels)
return
script_name = os.path.basename(revision.path) script_name = os.path.basename(revision.path)
alembic_util.err( alembic_util.err(
_('Unexpected label for script %(script_name)s: %(labels)s') % _('Unexpected label for script %(script_name)s: %(labels)s') %
@ -339,6 +337,14 @@ def _get_revisions(script):
return list(script.walk_revisions(base='base', head='heads')) return list(script.walk_revisions(base='base', head='heads'))
def _get_branch_type(revision):
for branch_label in revision.branch_labels:
if branch_label.endswith(CONTRACT_BRANCH):
return CONTRACT_BRANCH
if branch_label.endswith(EXPAND_BRANCH):
return EXPAND_BRANCH
def _get_branch_points(script): def _get_branch_points(script):
branchpoints = [] branchpoints = []
for revision in _get_revisions(script): for revision in _get_revisions(script):
@ -352,10 +358,7 @@ def _get_heads_map(config):
heads = script.get_heads() heads = script.get_heads()
head_map = {} head_map = {}
for head in heads: for head in heads:
if CONTRACT_BRANCH in script.get_revision(head).branch_labels: head_map[_get_branch_type(script.get_revision(head))] = head
head_map[CONTRACT_BRANCH] = head
else:
head_map[EXPAND_BRANCH] = head
return head_map return head_map

View File

@ -235,7 +235,12 @@ class TestModelsMigrationsMysql(testlib_api.MySQLTestCaseMixin,
script = alembic_script.ScriptDirectory.from_config( script = alembic_script.ScriptDirectory.from_config(
self.alembic_config) self.alembic_config)
for m in list(script.walk_revisions(base='base', head='heads')): for m in list(script.walk_revisions(base='base', head='heads')):
branches = m.branch_labels or [] branches = set()
for bl in m.branch_labels:
if bl.endswith(migration.CONTRACT_BRANCH):
branches.add(migration.CONTRACT_BRANCH)
elif bl.endswith(migration.EXPAND_BRANCH):
branches.add(migration.EXPAND_BRANCH)
if migration.CONTRACT_BRANCH in branches: if migration.CONTRACT_BRANCH in branches:
method_name = 'contract_creation_exceptions' method_name = 'contract_creation_exceptions'
exceptions_dict = creation_exceptions exceptions_dict = creation_exceptions

View File

@ -148,7 +148,28 @@ class TestCli(base.BaseTestCase):
attrs=attrs) attrs=attrs)
cli.migration_entrypoints[project] = entrypoint cli.migration_entrypoints[project] = entrypoint
def _main_test_helper(self, argv, func_name, exp_kwargs=[{}]): self.old_labels_revs = {
'a': FakeRevision(labels={cli.CONTRACT_BRANCH}),
'b': FakeRevision(labels={cli.EXPAND_BRANCH})
}
self.new_labels_revs = {
'x': FakeRevision(labels={'foo-' + cli.CONTRACT_BRANCH}),
'y': FakeRevision(labels={'foo-' + cli.EXPAND_BRANCH})
}
@staticmethod
def _old_and_new_label_combination_helper(test_method):
old_cb = cli.CONTRACT_BRANCH
new_cb = 'foo-' + cli.CONTRACT_BRANCH
old_eb = cli.EXPAND_BRANCH
new_eb = 'foo-' + cli.EXPAND_BRANCH
# Test all combinations of old and new branch labels.
test_method(old_cb, old_eb)
test_method(old_cb, new_eb)
test_method(new_cb, old_eb)
test_method(new_cb, new_eb)
def _main_test_helper(self, argv, func_name, exp_kwargs=None):
with mock.patch.object(sys, 'argv', argv),\ with mock.patch.object(sys, 'argv', argv),\
mock.patch.object(cli, 'run_sanity_checks'),\ mock.patch.object(cli, 'run_sanity_checks'),\
mock.patch.object(cli, 'validate_revisions'): mock.patch.object(cli, 'validate_revisions'):
@ -163,7 +184,7 @@ class TestCli(base.BaseTestCase):
self.do_alembic_cmd.assert_has_calls( self.do_alembic_cmd.assert_has_calls(
[mock.call(mock.ANY, func_name, **_append_version_path(kwargs)) [mock.call(mock.ANY, func_name, **_append_version_path(kwargs))
for kwargs in exp_kwargs] for kwargs in (exp_kwargs or [{}])]
) )
def test_stamp(self): def test_stamp(self):
@ -207,10 +228,11 @@ class TestCli(base.BaseTestCase):
self._main_test_helper(['prog', 'check_migration'], 'branches') self._main_test_helper(['prog', 'check_migration'], 'branches')
self.assertEqual(len(self.projects), validate.call_count) self.assertEqual(len(self.projects), validate.call_count)
def _test_database_sync_revision(self, separate_branches=True): def _test_database_sync_revision(self, revs):
with mock.patch.object(cli, 'update_head_files') as update: with mock.patch.object(cli, 'update_head_files') as update,\
if separate_branches: mock.patch('alembic.script.ScriptDirectory.from_config') as fc:
mock.patch('os.path.exists').start() fc.return_value.get_revisions.side_effect = revs
mock.patch('os.path.exists').start()
expected_kwargs = [{ expected_kwargs = [{
'message': 'message', 'sql': False, 'autogenerate': True, 'message': 'message', 'sql': False, 'autogenerate': True,
}] }]
@ -226,7 +248,7 @@ class TestCli(base.BaseTestCase):
'message': 'message', 'message': 'message',
'sql': True, 'sql': True,
'autogenerate': False, 'autogenerate': False,
'head': cli._get_branch_head(branch) 'head': cli._get_branch_head(self.configs[0], branch)
} for branch in cli.MIGRATION_BRANCHES] } for branch in cli.MIGRATION_BRANCHES]
for kwarg in expected_kwargs: for kwarg in expected_kwargs:
kwarg['autogenerate'] = False kwarg['autogenerate'] = False
@ -264,12 +286,11 @@ class TestCli(base.BaseTestCase):
) )
self.assertEqual(len(self.projects), update.call_count) self.assertEqual(len(self.projects), update.call_count)
def test_database_sync_revision(self): def test_database_sync_revision_old_branch_labels(self):
self._test_database_sync_revision() self._test_database_sync_revision(self.old_labels_revs)
def test_database_sync_revision_no_branches(self): def test_database_sync_revision_new_branch_labels(self):
# Test that old branchless approach is still supported self._test_database_sync_revision(self.new_labels_revs)
self._test_database_sync_revision(separate_branches=False)
def test_upgrade_revision(self): def test_upgrade_revision(self):
self._main_test_helper( self._main_test_helper(
@ -292,14 +313,22 @@ class TestCli(base.BaseTestCase):
[{'desc': None, 'revision': 'kilo+3', 'sql': False}] [{'desc': None, 'revision': 'kilo+3', 'sql': False}]
) )
def test_upgrade_expand(self): def _test_upgrade_expand(self, revs):
self._main_test_helper( with mock.patch('alembic.script.ScriptDirectory.from_config') as fc:
['prog', 'upgrade', '--expand'], fc.return_value.get_revisions.side_effect = revs
'upgrade', self._main_test_helper(
[{'desc': cli.EXPAND_BRANCH, ['prog', 'upgrade', '--expand'],
'revision': 'expand@head', 'upgrade',
'sql': False}] [{'desc': cli.EXPAND_BRANCH,
) 'revision': 'expand@head',
'sql': False}]
)
def test_upgrade_expand_old_labels(self):
self._test_upgrade_expand(self.old_labels_revs)
def test_upgrade_expand_new_labels(self):
self._test_upgrade_expand(self.new_labels_revs)
def test_upgrade_expand_contract_are_mutually_exclusive(self): def test_upgrade_expand_contract_are_mutually_exclusive(self):
with testlib_api.ExpectedException(SystemExit): with testlib_api.ExpectedException(SystemExit):
@ -342,20 +371,31 @@ class TestCli(base.BaseTestCase):
def test_upgrade_contract_conflicts_with_delta(self): def test_upgrade_contract_conflicts_with_delta(self):
self._test_upgrade_conflicts_with_delta('contract') self._test_upgrade_conflicts_with_delta('contract')
def test_upgrade_contract(self): def _test_upgrade_contract(self, revs):
self._main_test_helper( with mock.patch('alembic.script.ScriptDirectory.from_config') as fc:
['prog', 'upgrade', '--contract'], fc.return_value.get_revisions.side_effect = revs
'upgrade', self._main_test_helper(
[{'desc': cli.CONTRACT_BRANCH, ['prog', 'upgrade', '--contract'],
'revision': 'contract@head', 'upgrade',
'sql': False}] [{'desc': cli.CONTRACT_BRANCH,
) 'revision': 'contract@head',
'sql': False}]
)
def test_upgrade_contract_old_labels(self):
self._test_upgrade_contract(self.old_labels_revs)
def test_upgrade_contract_new_labels(self):
self._test_upgrade_contract(self.new_labels_revs)
@mock.patch('alembic.script.ScriptDirectory.walk_revisions') @mock.patch('alembic.script.ScriptDirectory.walk_revisions')
def test_upgrade_milestone_expand_before_contract(self, walk_mock): def _test_upgrade_milestone_expand_before_contract(self,
c_revs = [FakeRevision(labels={cli.CONTRACT_BRANCH}) for r in range(5)] contract_label,
expand_label,
walk_mock):
c_revs = [FakeRevision(labels={contract_label}) for r in range(5)]
c_revs[1].module.neutron_milestone = [migration.LIBERTY] c_revs[1].module.neutron_milestone = [migration.LIBERTY]
e_revs = [FakeRevision(labels={cli.EXPAND_BRANCH}) for r in range(5)] e_revs = [FakeRevision(labels={expand_label}) for r in range(5)]
e_revs[3].module.neutron_milestone = [migration.LIBERTY] e_revs[3].module.neutron_milestone = [migration.LIBERTY]
walk_mock.return_value = c_revs + e_revs walk_mock.return_value = c_revs + e_revs
self._main_test_helper( self._main_test_helper(
@ -369,6 +409,10 @@ class TestCli(base.BaseTestCase):
'sql': False}] 'sql': False}]
) )
def test_upgrade_milestone_expand_before_contract(self):
self._old_and_new_label_combination_helper(
self._test_upgrade_milestone_expand_before_contract)
def assert_command_fails(self, command): def assert_command_fails(self, command):
# Avoid cluttering stdout with argparse error messages # Avoid cluttering stdout with argparse error messages
mock.patch('argparse.ArgumentParser._print_message').start() mock.patch('argparse.ArgumentParser._print_message').start()
@ -388,8 +432,8 @@ class TestCli(base.BaseTestCase):
def test_upgrade_rejects_delta_with_relative_revision(self): def test_upgrade_rejects_delta_with_relative_revision(self):
self.assert_command_fails(['prog', 'upgrade', '+2', '--delta', '3']) self.assert_command_fails(['prog', 'upgrade', '+2', '--delta', '3'])
def _test_validate_head_files_helper(self, heads, contract_head='', def _test_validate_head_files_common(self, heads, revs,
expand_head=''): contract_head='', expand_head=''):
fake_config = self.configs[0] fake_config = self.configs[0]
head_files_not_exist = (contract_head == expand_head == '') head_files_not_exist = (contract_head == expand_head == '')
with mock.patch('alembic.script.ScriptDirectory.from_config') as fc,\ with mock.patch('alembic.script.ScriptDirectory.from_config') as fc,\
@ -400,9 +444,6 @@ class TestCli(base.BaseTestCase):
os_mock.return_value = True os_mock.return_value = True
fc.return_value.get_heads.return_value = heads fc.return_value.get_heads.return_value = heads
revs = {heads[0]: FakeRevision(labels=cli.CONTRACT_BRANCH),
heads[1]: FakeRevision(labels=cli.EXPAND_BRANCH)}
fc.return_value.get_revision.side_effect = revs.__getitem__ fc.return_value.get_revision.side_effect = revs.__getitem__
mock_open_con = self.useFixture( mock_open_con = self.useFixture(
tools.OpenFixture(cli._get_contract_head_file_path( tools.OpenFixture(cli._get_contract_head_file_path(
@ -433,6 +474,23 @@ class TestCli(base.BaseTestCase):
if not head_files_not_exist: if not head_files_not_exist:
fc.assert_called_once_with(fake_config) fc.assert_called_once_with(fake_config)
def _test_validate_head_files_helper(self, heads,
contract_head='', expand_head=''):
old_labels_revs = {
heads[0]: FakeRevision(labels={cli.CONTRACT_BRANCH}),
heads[1]: FakeRevision(labels={cli.EXPAND_BRANCH})
}
new_labels_revs = {
heads[0]: FakeRevision(labels={'foo-' + cli.CONTRACT_BRANCH}),
heads[1]: FakeRevision(labels={'foo-' + cli.EXPAND_BRANCH})
}
self._test_validate_head_files_common(heads, old_labels_revs,
contract_head=contract_head,
expand_head=expand_head)
self._test_validate_head_files_common(heads, new_labels_revs,
contract_head=contract_head,
expand_head=expand_head)
def test_validate_head_files_success(self): def test_validate_head_files_success(self):
self._test_validate_head_files_helper(['a', 'b'], contract_head='a', self._test_validate_head_files_helper(['a', 'b'], contract_head='a',
expand_head='b') expand_head='b')
@ -445,8 +503,14 @@ class TestCli(base.BaseTestCase):
expand_head='d') expand_head='d')
@mock.patch.object(fileutils, 'delete_if_exists') @mock.patch.object(fileutils, 'delete_if_exists')
def test_update_head_files_success(self, *mocks): def _test_update_head_files_success(self, revs, *mocks):
heads = ['a', 'b'] contract_head = expand_head = None
for rev, revision in revs.items():
for branch_label in revision.branch_labels:
if branch_label.endswith(cli.CONTRACT_BRANCH):
contract_head = rev
if branch_label.endswith(cli.EXPAND_BRANCH):
expand_head = rev
mock_open_con = self.useFixture( mock_open_con = self.useFixture(
tools.OpenFixture(cli._get_contract_head_file_path( tools.OpenFixture(cli._get_contract_head_file_path(
self.configs[0]))).mock_open self.configs[0]))).mock_open
@ -454,14 +518,13 @@ class TestCli(base.BaseTestCase):
tools.OpenFixture(cli._get_expand_head_file_path( tools.OpenFixture(cli._get_expand_head_file_path(
self.configs[0]))).mock_open self.configs[0]))).mock_open
with mock.patch('alembic.script.ScriptDirectory.from_config') as fc: with mock.patch('alembic.script.ScriptDirectory.from_config') as fc:
fc.return_value.get_heads.return_value = heads fc.return_value.get_heads.return_value = list(revs)
revs = {heads[0]: FakeRevision(labels=cli.CONTRACT_BRANCH),
heads[1]: FakeRevision(labels=cli.EXPAND_BRANCH)}
fc.return_value.get_revision.side_effect = revs.__getitem__ fc.return_value.get_revision.side_effect = revs.__getitem__
cli.update_head_files(self.configs[0]) cli.update_head_files(self.configs[0])
mock_open_con.return_value.write.assert_called_with( mock_open_con.return_value.write.assert_called_with(
heads[0] + '\n') contract_head + '\n')
mock_open_ex.return_value.write.assert_called_with(heads[1] + '\n') mock_open_ex.return_value.write.assert_called_with(
expand_head + '\n')
old_head_file = cli._get_head_file_path( old_head_file = cli._get_head_file_path(
self.configs[0]) self.configs[0])
@ -473,6 +536,12 @@ class TestCli(base.BaseTestCase):
self.assertIn(mock.call(old_heads_file), self.assertIn(mock.call(old_heads_file),
delete_if_exists.call_args_list) delete_if_exists.call_args_list)
def test_update_head_files_success_old_labels(self):
self._test_update_head_files_success(self.old_labels_revs)
def test_update_head_files_success_new_labels(self):
self._test_update_head_files_success(self.new_labels_revs)
def test_get_project_base(self): def test_get_project_base(self):
config = alembic_config.Config() config = alembic_config.Config()
config.set_main_option('script_location', 'a.b.c:d') config.set_main_option('script_location', 'a.b.c:d')
@ -589,7 +658,7 @@ class TestCli(base.BaseTestCase):
@mock.patch('alembic.script.ScriptDirectory.walk_revisions') @mock.patch('alembic.script.ScriptDirectory.walk_revisions')
def test__get_branch_points(self, walk_mock): def test__get_branch_points(self, walk_mock):
revisions = [FakeRevision(is_branch_point=tools.get_random_boolean) revisions = [FakeRevision(is_branch_point=tools.get_random_boolean())
for i in range(50)] for i in range(50)]
walk_mock.return_value = revisions walk_mock.return_value = revisions
script_dir = alembic_script.ScriptDirectory.from_config( script_dir = alembic_script.ScriptDirectory.from_config(
@ -663,8 +732,10 @@ class TestCli(base.BaseTestCase):
) )
directives = [migration_script] directives = [migration_script]
context = mock.Mock()
context.config = self.configs[0]
autogen.process_revision_directives( autogen.process_revision_directives(
mock.Mock(), mock.Mock(), directives context, mock.Mock(), directives
) )
expand = directives[0] expand = directives[0]
@ -699,23 +770,33 @@ class TestCli(base.BaseTestCase):
) )
@mock.patch('alembic.script.ScriptDirectory.walk_revisions') @mock.patch('alembic.script.ScriptDirectory.walk_revisions')
def test__find_milestone_revisions_one_branch(self, walk_mock): def _test__find_milestone_revisions_one_branch(self,
c_revs = [FakeRevision(labels={cli.CONTRACT_BRANCH}) for r in range(5)] contract_label,
expand_label,
walk_mock):
c_revs = [FakeRevision(labels={contract_label}) for r in range(5)]
c_revs[1].module.neutron_milestone = [migration.LIBERTY] c_revs[1].module.neutron_milestone = [migration.LIBERTY]
walk_mock.return_value = c_revs walk_mock.return_value = c_revs
m = cli._find_milestone_revisions(self.configs[0], 'liberty', m = cli._find_milestone_revisions(self.configs[0], 'liberty',
cli.CONTRACT_BRANCH) contract_label)
self.assertEqual(1, len(m)) self.assertEqual(1, len(m))
m = cli._find_milestone_revisions(self.configs[0], 'liberty', m = cli._find_milestone_revisions(self.configs[0], 'liberty',
cli.EXPAND_BRANCH) expand_label)
self.assertEqual(0, len(m)) self.assertEqual(0, len(m))
def test__find_milestone_revisions_one_branch(self):
self._old_and_new_label_combination_helper(
self._test__find_milestone_revisions_one_branch)
@mock.patch('alembic.script.ScriptDirectory.walk_revisions') @mock.patch('alembic.script.ScriptDirectory.walk_revisions')
def test__find_milestone_revisions_two_branches(self, walk_mock): def _test__find_milestone_revisions_two_branches(self,
c_revs = [FakeRevision(labels={cli.CONTRACT_BRANCH}) for r in range(5)] contract_label,
expand_label,
walk_mock):
c_revs = [FakeRevision(labels={contract_label}) for r in range(5)]
c_revs[1].module.neutron_milestone = [migration.LIBERTY] c_revs[1].module.neutron_milestone = [migration.LIBERTY]
e_revs = [FakeRevision(labels={cli.EXPAND_BRANCH}) for r in range(5)] e_revs = [FakeRevision(labels={expand_label}) for r in range(5)]
e_revs[3].module.neutron_milestone = [migration.LIBERTY] e_revs[3].module.neutron_milestone = [migration.LIBERTY]
walk_mock.return_value = c_revs + e_revs walk_mock.return_value = c_revs + e_revs
@ -725,6 +806,10 @@ class TestCli(base.BaseTestCase):
m = cli._find_milestone_revisions(self.configs[0], 'mitaka') m = cli._find_milestone_revisions(self.configs[0], 'mitaka')
self.assertEqual(0, len(m)) self.assertEqual(0, len(m))
def test__find_milestone_revisions_two_branches(self):
self._old_and_new_label_combination_helper(
self._test__find_milestone_revisions_two_branches)
@mock.patch('alembic.script.ScriptDirectory.walk_revisions') @mock.patch('alembic.script.ScriptDirectory.walk_revisions')
def test__find_milestone_revisions_branchless(self, walk_mock): def test__find_milestone_revisions_branchless(self, walk_mock):
revisions = [FakeRevision() for r in range(5)] revisions = [FakeRevision() for r in range(5)]