1
from alembic.testing.fixtures import TestBase
2
from alembic.testing import mock
3
from alembic.testing import config, eq_, assert_raises, assert_raises_message
5
from sqlalchemy import Table, MetaData, Column, String
6
from sqlalchemy.engine.reflection import Inspector
7
from alembic import migration
9
from alembic.util import CommandError
11
version_table = Table('version_table', MetaData(),
12
Column('version_num', String(32), nullable=False))
15
def _up(from_, to_, branch_presence_changed=False):
16
return migration.StampStep(
17
from_, to_, True, branch_presence_changed
21
def _down(from_, to_, branch_presence_changed=False):
22
return migration.StampStep(
23
from_, to_, False, branch_presence_changed
27
class TestMigrationContext(TestBase):
34
self.connection = self.bind.connect()
35
self.transaction = self.connection.begin()
38
version_table.drop(self.connection, checkfirst=True)
39
self.transaction.rollback()
40
self.connection.close()
42
def make_one(self, **kwargs):
43
return migration.MigrationContext.configure(**kwargs)
45
def get_revision(self):
46
result = self.connection.execute(version_table.select())
47
rows = result.fetchall()
51
return rows[0]['version_num']
53
def test_config_default_version_table_name(self):
54
context = self.make_one(dialect_name='sqlite')
55
eq_(context._version.name, 'alembic_version')
57
def test_config_explicit_version_table_name(self):
58
context = self.make_one(dialect_name='sqlite',
59
opts={'version_table': 'explicit'})
60
eq_(context._version.name, 'explicit')
62
def test_config_explicit_version_table_schema(self):
63
context = self.make_one(dialect_name='sqlite',
64
opts={'version_table_schema': 'explicit'})
65
eq_(context._version.schema, 'explicit')
67
def test_get_current_revision_doesnt_create_version_table(self):
68
context = self.make_one(connection=self.connection,
69
opts={'version_table': 'version_table'})
70
eq_(context.get_current_revision(), None)
71
insp = Inspector(self.connection)
72
assert ('version_table' not in insp.get_table_names())
74
def test_get_current_revision(self):
75
context = self.make_one(connection=self.connection,
76
opts={'version_table': 'version_table'})
77
version_table.create(self.connection)
78
eq_(context.get_current_revision(), None)
79
self.connection.execute(
80
version_table.insert().values(version_num='revid'))
81
eq_(context.get_current_revision(), 'revid')
83
def test_get_current_revision_error_if_starting_rev_given_online(self):
84
context = self.make_one(connection=self.connection,
85
opts={'starting_rev': 'boo'})
88
context.get_current_revision
91
def test_get_current_revision_offline(self):
92
context = self.make_one(dialect_name='sqlite',
93
opts={'starting_rev': 'startrev',
95
eq_(context.get_current_revision(), 'startrev')
97
def test_get_current_revision_multiple_heads(self):
98
version_table.create(self.connection)
99
context = self.make_one(connection=self.connection,
100
opts={'version_table': 'version_table'})
101
updater = migration.HeadMaintainer(context, ())
102
updater.update_to_step(_up(None, 'a', True))
103
updater.update_to_step(_up(None, 'b', True))
104
assert_raises_message(
106
"Version table 'version_table' has more than one head present; "
107
"please use get_current_heads()",
108
context.get_current_revision
111
def test_get_heads(self):
112
version_table.create(self.connection)
113
context = self.make_one(connection=self.connection,
114
opts={'version_table': 'version_table'})
115
updater = migration.HeadMaintainer(context, ())
116
updater.update_to_step(_up(None, 'a', True))
117
updater.update_to_step(_up(None, 'b', True))
118
eq_(context.get_current_heads(), ('a', 'b'))
120
def test_get_heads_offline(self):
121
version_table.create(self.connection)
122
context = self.make_one(connection=self.connection,
125
'version_table': 'version_table',
127
eq_(context.get_current_heads(), ('q', ))
129
def test_stamp_api_creates_table(self):
130
context = self.make_one(connection=self.connection)
133
not in Inspector(self.connection).get_table_names())
135
script = mock.Mock(_stamp_revs=lambda revision, heads: [
136
_up(None, 'a', True),
140
context.stamp(script, 'b')
141
eq_(context.get_current_heads(), ('a', 'b'))
144
in Inspector(self.connection).get_table_names())
147
class UpdateRevTest(TestBase):
151
def setup_class(cls):
155
self.connection = self.bind.connect()
156
self.context = migration.MigrationContext.configure(
157
connection=self.connection,
158
opts={"version_table": "version_table"})
159
version_table.create(self.connection)
160
self.updater = migration.HeadMaintainer(self.context, ())
163
version_table.drop(self.connection, checkfirst=True)
164
self.connection.close()
166
def _assert_heads(self, heads):
167
eq_(set(self.context.get_current_heads()), set(heads))
168
eq_(self.updater.heads, set(heads))
170
def test_update_none_to_single(self):
171
self.updater.update_to_step(_up(None, 'a', True))
172
self._assert_heads(('a',))
174
def test_update_single_to_single(self):
175
self.updater.update_to_step(_up(None, 'a', True))
176
self.updater.update_to_step(_up('a', 'b'))
177
self._assert_heads(('b',))
179
def test_update_single_to_none(self):
180
self.updater.update_to_step(_up(None, 'a', True))
181
self.updater.update_to_step(_down('a', None, True))
182
self._assert_heads(())
184
def test_add_branches(self):
185
self.updater.update_to_step(_up(None, 'a', True))
186
self.updater.update_to_step(_up('a', 'b'))
187
self.updater.update_to_step(_up(None, 'c', True))
188
self._assert_heads(('b', 'c'))
189
self.updater.update_to_step(_up('c', 'd'))
190
self.updater.update_to_step(_up('d', 'e1'))
191
self.updater.update_to_step(_up('d', 'e2', True))
192
self._assert_heads(('b', 'e1', 'e2'))
194
def test_teardown_branches(self):
195
self.updater.update_to_step(_up(None, 'd1', True))
196
self.updater.update_to_step(_up(None, 'd2', True))
197
self._assert_heads(('d1', 'd2'))
199
self.updater.update_to_step(_down('d1', 'c'))
200
self._assert_heads(('c', 'd2'))
202
self.updater.update_to_step(_down('d2', 'c', True))
204
self._assert_heads(('c',))
205
self.updater.update_to_step(_down('c', 'b'))
206
self._assert_heads(('b',))
208
def test_resolve_merges(self):
209
self.updater.update_to_step(_up(None, 'a', True))
210
self.updater.update_to_step(_up('a', 'b'))
211
self.updater.update_to_step(_up('b', 'c1'))
212
self.updater.update_to_step(_up('b', 'c2', True))
213
self.updater.update_to_step(_up('c1', 'd1'))
214
self.updater.update_to_step(_up('c2', 'd2'))
215
self._assert_heads(('d1', 'd2'))
216
self.updater.update_to_step(_up(('d1', 'd2'), 'e'))
217
self._assert_heads(('e',))
219
def test_unresolve_merges(self):
220
self.updater.update_to_step(_up(None, 'e', True))
222
self.updater.update_to_step(_down('e', ('d1', 'd2')))
223
self._assert_heads(('d2', 'd1'))
225
self.updater.update_to_step(_down('d2', 'c2'))
226
self._assert_heads(('c2', 'd1'))
228
def test_update_no_match(self):
229
self.updater.update_to_step(_up(None, 'a', True))
230
self.updater.heads.add('x')
231
assert_raises_message(
233
"Online migration expected to match one row when updating "
234
"'x' to 'b' in 'version_table'; 0 found",
235
self.updater.update_to_step, _up('x', 'b')
238
def test_update_multi_match(self):
239
self.connection.execute(version_table.insert(), version_num='a')
240
self.connection.execute(version_table.insert(), version_num='a')
242
self.updater.heads.add('a')
243
assert_raises_message(
245
"Online migration expected to match one row when updating "
246
"'a' to 'b' in 'version_table'; 2 found",
247
self.updater.update_to_step, _up('a', 'b')
250
def test_delete_no_match(self):
251
self.updater.update_to_step(_up(None, 'a', True))
253
self.updater.heads.add('x')
254
assert_raises_message(
256
"Online migration expected to match one row when "
257
"deleting 'x' in 'version_table'; 0 found",
258
self.updater.update_to_step, _down('x', None, True)
261
def test_delete_multi_match(self):
262
self.connection.execute(version_table.insert(), version_num='a')
263
self.connection.execute(version_table.insert(), version_num='a')
265
self.updater.heads.add('a')
266
assert_raises_message(
268
"Online migration expected to match one row when "
269
"deleting 'a' in 'version_table'; 2 found",
270
self.updater.update_to_step, _down('a', None, True)