def test_rollback_to_rev_id(self): wd = WorkDirectory(self.work_dir) migr_ctx = create_migration_ctx(wd.get_migration_ctx_config()) self.assertIsNone(migr_ctx.head) one = gen_rev_id() two = gen_rev_id() three = gen_rev_id() revisions = [ Revision(one, "adding table foo", datetime.now(), upgrade_sql="create table test.foo (a string);", downgrade_sql="drop table test.foo;"), Revision(two, "adding table bar", datetime.now(), upgrade_sql="create table test.bar (a string);", downgrade_sql="drop table test.bar;"), Revision(three, "add column b foo", datetime.now(), upgrade_sql="alter table test.foo add column b string;", downgrade_sql="alter table test.foo drop column b;") ] for rev in revisions: wd.add_revision(rev) runner = CliRunner() res = runner.invoke(upgrade) self.assertTrue(res.exit_code == 0) self.assertIsNotNone(migr_ctx.head) self.assertTrue(len(migr_ctx.revisions) == 3) res = runner.invoke(rollback, ['-r', two]) self.assertTrue(res.exit_code == 0) self.assertTrue(len(migr_ctx.revisions) == 1)
def test_rollback_step_cmd(self): wd = WorkDirectory(self.work_dir) migr_ctx = create_migration_ctx(wd.get_migration_ctx_config()) self.assertIsNone(migr_ctx.head) runner = CliRunner() wd.add_revision( Revision(gen_rev_id(), "adding table foo", datetime.now(), upgrade_sql="create table test.foo (a string);", downgrade_sql="drop table test.foo")) res = runner.invoke(upgrade) self.assertTrue(res.exit_code == 0) wd.add_revision( Revision(gen_rev_id(), "adding table bar", datetime.now(), upgrade_sql="create table test.bar (a string);", downgrade_sql="drop table test.bar")) res = runner.invoke(upgrade) self.assertTrue(res.exit_code == 0) self.assertIsNotNone(migr_ctx.head) self.assertTrue(len(migr_ctx.revisions) == 2) res = runner.invoke(rollback, ['-n', 2]) self.assertIsNone(migr_ctx.head)
def ensure_init(): ensure_setup() config = Config.from_file(MROLL_CONFIG_FILE) wd = WorkDirectory(config.work_dir) try: ctx = create_migration_ctx(wd.get_migration_ctx_config()) head = ctx.head except: raise SystemExit("Error: mroll not initialized! Run init command first.")
def test_upgrade_raise(self): wd = WorkDirectory(self.work_dir) migr_ctx = create_migration_ctx(wd.get_migration_ctx_config()) self.assertIsNone(migr_ctx.head) wd.add_revision( Revision(gen_rev_id(), "adding table foo", datetime.now())) self.assertTrue(len(wd.revisions) == 1) runner = CliRunner() res = runner.invoke(upgrade) self.assertTrue(res.exit_code == 1)
def test_migr_ctx_head(self): wd = WorkDirectory(path=self.work_dir) ctx = create_migration_ctx(wd.get_migration_ctx_config()) ctx.create_revisions_tbl() self.assertIsNone(ctx.head) conn = pymonetdb.connect(self.db_name) sql = """insert into sys.mroll_revisions values ('{}', '{}', '{}')""".format( gen_rev_id(), "bla bla", datetime.now()) conn.execute(sql) conn.commit() self.assertIsNotNone(ctx.head)
def test_ctx_revisions(self): wd = WorkDirectory(path=self.work_dir) ctx = create_migration_ctx(wd.get_migration_ctx_config()) ctx.create_revisions_tbl() self.assertTrue(len(ctx.revisions) == 0) conn = pymonetdb.connect(self.db_name) sql = """insert into sys.mroll_revisions values ('{}', '{}', '{}'), ('{}', '{}', '{}');""".format( gen_rev_id(), "revision 1", datetime.now(), gen_rev_id(), "revision 2", datetime.now()) conn.execute(sql) conn.commit() self.assertTrue(len(ctx.revisions) == 2)
def applied_revisions(show_patch=False): config = Config.from_file(MROLL_CONFIG_FILE) wd = WorkDirectory(config.work_dir) migr_ctx = create_migration_ctx(wd.get_migration_ctx_config()) if migr_ctx.head is None: print('No revisions have being applied yet!') return # create lookup lookup = {} for r in migr_ctx.revisions: lookup[r.id] = r working_set: List[Revision] = list(filter(lambda rev: lookup.get(rev.id, None) is not None, wd.revisions)) for rev in working_set: if show_patch: print(rev.serialize()) else: print(rev)
def rollback(step, rev_id): """ Downgrades to previous revision by default. """ ensure_init() config = Config.from_file(MROLL_CONFIG_FILE) wd = WorkDirectory(config.work_dir) migr_ctx = create_migration_ctx(wd.get_migration_ctx_config()) if migr_ctx.head is None: raise SystemExit('Nothing to do!') # create lookup lookup = {} for r in migr_ctx.revisions: lookup[r.id] = r working_set: List[Revision] = list(filter(lambda rev: lookup.get(rev.id, None) is not None, wd.revisions)) count = 0 buff=[] for rev in reversed(working_set): if rev_id is None and count==step: break if rev_id is not None: if rev.id == rev_id: buff.append(rev) break buff.append(rev) count+=1 working_set: List[Revision] = [] + buff # insure idempotency for rev in working_set: if rev.downgrade_sql is None: msg=""" Error: No downgrade sql script @{}! """.format(rev.id) if rev.upgrade_sql is not None: msg=""" Error: No downgrade sql script @{}, while there is a upgrade sql: {} Scripts should be idempotent. """.format(rev.id, rev.upgrade_sql) raise SystemExit(msg) try: migr_ctx.remove_revisions(working_set) except RevisionOperationError as e: raise SystemExit(repr(e)) print('Done')
def pending_revisions(show_patch=False): """ Shows pending revisions not yet applied. """ config = Config.from_file(MROLL_CONFIG_FILE) wd = WorkDirectory(config.work_dir) migr_ctx = create_migration_ctx(wd.get_migration_ctx_config()) # create lookup lookup = {} for r in migr_ctx.revisions: lookup[r.id] = r working_set: List[Revision] = list(filter(lambda rev: lookup.get(rev.id, None) is None, wd.revisions)) for r in working_set: if show_patch: print(r.serialize()) else: print(r)
def test_rollback_raises(self): wd = WorkDirectory(self.work_dir) migr_ctx = create_migration_ctx(wd.get_migration_ctx_config()) self.assertIsNone(migr_ctx.head) runner = CliRunner() # add revison with no downgrade_sql wd.add_revision( Revision( gen_rev_id(), "adding table foo", datetime.now(), upgrade_sql="create table test.foo (a string);", )) res = runner.invoke(upgrade) self.assertTrue(res.exit_code == 0) self.assertIsNotNone(migr_ctx.head) self.assertTrue(len(migr_ctx.revisions) == 1) res = runner.invoke(rollback) self.assertNotEqual(res.exit_code, 0)
def test_ctx_add_revisions(self): wd = WorkDirectory(path=self.work_dir) ctx = create_migration_ctx(wd.get_migration_ctx_config()) ctx.create_revisions_tbl() self.assertTrue(len(ctx.revisions) == 0) revisions = [ Revision(gen_rev_id(), "adding table foo", datetime.now(), upgrade_sql="create table test.foo (a string);", downgrade_sql="drop table test.foo;"), Revision(gen_rev_id(), "adding table bar", datetime.now(), upgrade_sql="create table test.bar (a string);", downgrade_sql="drop table test.bar;") ] ctx.add_revisions(revisions) self.assertTrue(len(ctx.revisions) == 2)
def test_show_pending_revisions(self): wd = WorkDirectory(self.work_dir) wd.add_revision( Revision(gen_rev_id(), "adding table bar", datetime.now(), upgrade_sql="create table test.bar (a string);", downgrade_sql="drop table test.bar;")) self.assertTrue(len(wd.revisions) == 1) runner = CliRunner() res = runner.invoke(upgrade) self.assertTrue(res.exit_code == 0) migr_ctx = create_migration_ctx(wd.get_migration_ctx_config()) self.assertIsNotNone(migr_ctx.head) self.assertTrue(len(migr_ctx.revisions) == 1) self.add_rev_cmd('add column a to bar') self.add_rev_cmd('add column a to baz') self.assertTrue(len(wd.revisions) == 3) res = runner.invoke(show, ['pending']) self.assertTrue(res.exit_code == 0)
def test_rollback_default_cmd(self): # test rollback no cli options wd = WorkDirectory(self.work_dir) migr_ctx = create_migration_ctx(wd.get_migration_ctx_config()) self.assertIsNone(migr_ctx.head) rev = Revision(gen_rev_id(), "adding table foo", datetime.now(), upgrade_sql="create table test.foo (a string);", downgrade_sql="drop table test.foo;") wd.add_revision(rev) self.assertTrue(len(wd.revisions) == 1) runner = CliRunner() res = runner.invoke(upgrade) self.assertTrue(res.exit_code == 0) self.assertIsNotNone(migr_ctx.head) self.assertTrue(len(migr_ctx.revisions) == 1) res = runner.invoke(rollback) self.assertTrue(res.exit_code == 0) self.assertIsNone(migr_ctx.head) self.assertTrue(len(migr_ctx.revisions) == 0)
def init(): """ Creates mroll_revisions tbl. Should be run once. """ ensure_setup() config = Config.from_file(MROLL_CONFIG_FILE) wd = WorkDirectory(config.work_dir) migr_ctx_config = wd.get_migration_ctx_config() migr_ctx = create_migration_ctx(migr_ctx_config) try: # if following succeeds then mroll revisons tbl exist. migr_ctx.head return print("Nothing to do! Mroll revisions table already exist.") except: pass try: migr_ctx.create_revisions_tbl() except Exception as e: raise SystemExit(e) print('{} table created'.format(migr_ctx_config.tbl_name)) print('Done')
def test_upgrade_num_command(self): # Test upgrade cmd with a step wd = WorkDirectory(self.work_dir) revisions = [ Revision(gen_rev_id(), "adding table foo", datetime.now(), upgrade_sql="create table test.foo (a string);", downgrade_sql="drop table test.foo;"), Revision(gen_rev_id(), "adding table bar", datetime.now(), upgrade_sql="create table test.bar (a string);", downgrade_sql="drop table test.bar;") ] for rev in revisions: wd.add_revision(rev) self.assertTrue(len(wd.revisions) == 2) runner = CliRunner() res = runner.invoke(upgrade, ['-n', 1]) self.assertTrue(res.exit_code == 0) migr_ctx = create_migration_ctx(wd.get_migration_ctx_config()) self.assertIsNotNone(migr_ctx.head) self.assertTrue(len(migr_ctx.revisions) == 1)
def upgrade(step): """ Applies revisions in work dir not yet applied. """ ensure_init() config = Config.from_file(MROLL_CONFIG_FILE) wd = WorkDirectory(config.work_dir) migr_ctx = create_migration_ctx(wd.get_migration_ctx_config()) # create lookup lookup = {} for r in migr_ctx.revisions: lookup[r.id] = r working_set: List[Revision] = list(filter(lambda rev: lookup.get(rev.id, None) is None, wd.revisions)) ptr = step or len(working_set) # adjust working set working_set = working_set[:ptr] # ensure idempotency for rev in working_set: if rev.upgrade_sql is None: msg=""" Error: No upgrade sql script @{}! """.format(rev.id) if rev.downgrade_sql is not None: msg=""" Error: No upgrade sql script @{}, while there is a downgrade sql: {} Scripts should be idempotent. """.format(rev.id, rev.downgrade_sql) raise SystemExit(msg) # execute try: migr_ctx.add_revisions(working_set) except RevisionOperationError as e: raise SystemExit(repr(e)) print('Done')
def test_create_migr_ctx(self): wd = WorkDirectory(path=self.work_dir) ctx = create_migration_ctx(wd.get_migration_ctx_config()) self.assertIsNotNone(ctx)