def test_migration_check_success(self, tmpfile, caplogger): ddb = Database(provider="sqlite", filename=str(tmpfile)) init_onetable(ddb) s1 = Schema(ddb) s1.version = "0.5.0" v1 = s1.schema def check_cb(check_db): with db_session: assert ( check_db.execute( "select * from sqlite_master").fetchone()[4] == 'CREATE TABLE "bla" ("key" TEXT NOT NULL PRIMARY KEY, "texta" TEXT, "textb" TEXT, "textc" TEXT)' ) m = MakeMigrations(tmpfile, Version("1.3.2"), migrations) assert m(check_cb, lambda x: True) assert "Error" not in caplogger.read() ddb2 = Database(provider="sqlite", filename=str(tmpfile)) s2 = Schema(ddb2) assert ( s2.schema == """CREATE TABLE "bla" ("key" TEXT NOT NULL PRIMARY KEY, "texta" TEXT, "textb" TEXT, "textc" TEXT)\n""" ) assert s2.version == Version("1.3.2")
def test_version_set(): db = Database(provider="sqlite", filename=":memory:") s = Schema(file=db) assert s.version == Version("0") s.version = Version("12.34.56") with db_session: assert s.db.execute("PRAGMA user_version").fetchone()[0] == 123456 assert s.version == Version("12.34.56")
def test_many_migrations_not_all_file(self, onetablefile): m = Migrator(onetablefile, Version("1.3.2"), migrations) m() with db_session: assert ( m.db.execute("select * from sqlite_master").fetchone()[4] == 'CREATE TABLE "bla" ("key" TEXT NOT NULL PRIMARY KEY, "texta" TEXT, "textb" TEXT, "textc" TEXT)' ) assert m.schema.version == Version("1.3.2")
def test_one_migration(self, onetable): m = Migrator(onetable, Version("1"), {"0.9": ["""INSERT INTO "bla" VALUES("deux")"""]}) m() with db_session: assert m.db.execute("select * from bla").fetchall() == [ ("prems", ), ("deux", ), ] assert m.schema.version == Version("1.0")
def test_one_migration_same_version(self, onetable): m = Migrator( onetable, Version("1.5.6"), {"1.5.6": ["""INSERT INTO "bla" VALUES("quinze")"""]}, ) m() with db_session: assert m.db.execute("select * from bla").fetchall() == [ ("prems", ), ("quinze", ), ] assert m.schema.version == Version("1.5.6")
def __init__( self, filename: Union[str, Path], # chemin vers la ddb actual_version: Union[ Version, str] = None, # version actuelle (dans les sources) migrations: dict = None, # pool de migrations ): # migrations = migrations self.actual_version = (actual_version if isinstance( actual_version, Version) else Version(actual_version)) self.old_file = Path(filename) # ddb à faire migrer # création d'une base temporaire pour effectuer les migrations tmp = tempfile.NamedTemporaryFile(suffix=".sqlite", delete=False) tmp.close() self.tmp_file = Path(tmp.name) shutil.copy(self.old_file, self.tmp_file) # duplication de la DDB # outils pour migrations self.tmp_db = Database(provider="sqlite", filename=tmp.name) self.schema = Schema(file=self.tmp_db) if self.schema.version == self.actual_version: logger.info(f"version {self.actual_version}: No migration needed") return self.migrator = Migrator(self.tmp_db, self.actual_version, migrations) logger.info( f"starting migrations from version {self.schema.version} to {self.actual_version}" )
def test_ignore_older_migration_than_base(self, onetable): m = Migrator( onetable, Version("5"), { "2": ["""INSERT INTO "bla" VALUES("skipped")"""], "4": ["""INSERT INTO "bla" VALUES("notskipped")"""], }, ) m.schema.version = Version("3") m() with db_session: assert m.db.execute("select * from bla").fetchall() == [ ("prems", ), ("notskipped", ), ] assert m.schema.version == Version("5")
def test_restore_backup(self, tmpfile): ddb = Database(provider="sqlite", filename=str(tmpfile)) init_onetable(ddb) ddb.disconnect() bck_db = tmpfile.read_bytes() m = MakeMigrations(tmpfile, Version("1.3.2"), {"1.3.2": "AZEZRT ERTERT"}) assert not m(lambda x: True, lambda x: True) assert tmpfile.read_bytes() == bck_db
def test_migrations_same_version_is_cancelled(selfn, tmpfile, caplogger): ddb = Database(provider="sqlite", filename=str(tmpfile)) init_onetable(ddb) s1 = Schema(ddb) s1.version = "1.3.4" m = MakeMigrations(tmpfile, Version("1.3.4"), migrations) assert not hasattr(m, "migrator") m(lambda: True, lambda: True) assert "No migration needed" in caplogger.read()
def test_one_migration_not_null_with_default(self, onetable): m = Migrator( onetable, Version("1"), { "0.9": ["""ALTER TABLE bla ADD "textd" TEXT NOT NULL DEFAULT "a" """] }, ) m() with db_session: assert m.db.execute("select * from bla").fetchone() == ("prems", "a")
def test_migration_check_fail(self, tmpfile, caplogger): ddb = Database(provider="sqlite", filename=str(tmpfile)) init_onetable(ddb) s1 = Schema(ddb) s1.version = "0.54" def check_cb(check_db): with db_session: assert ( check_db.execute( "select * from sqlite_master").fetchone()[4] == 'CREATE TABLE "bla" ("key" TEXT NOT NULL PRIMARY KEY, "textX" TEXT, "textb" TEXT, "textc" TEXT)' ) m = MakeMigrations(tmpfile, Version("1.3.2"), migrations) assert not m(check_cb, lambda x: True) assert "AssertionError" in caplogger.read() # check error then no change ddb2 = Database(provider="sqlite", filename=str(tmpfile)) assert Schema(ddb).schema == Schema(ddb2).schema assert Schema(ddb2).version == Version("0.54")
def select_migrations(self) -> List[str]: """ Les migrations sont choisies si > à la version de la db et <= à la version cible :returns la liste de str de migrations à effectuer """ selected = [] schema_v = self.schema.version if schema_v == self.version: return selected for ver, migs in self.migrations.items(): version = Version(ver) if schema_v < version <= self.version: selected += migs return selected
def test_one_migration_not_null_with_initial_value(self, onetable): m = Migrator( onetable, Version("1"), { "0.9": [ """ALTER TABLE bla ADD "textd" TEXT NOT NULL DEFAULT "";""", """UPDATE bla SET textd="b";""", ] }, ) m() with db_session: assert m.db.execute("select * from bla").fetchone() == ("prems", "b")
def test_generate_mapping_fail(self, tmpfile, caplogger): ddb = Database(provider="sqlite", filename=str(tmpfile)) Schema(ddb).version = "0.5.0" def check_cb(check_db): with db_session: check_db.execute("select * from NewTable").fetchall() return True def generate_cb(generate_db): raise IndexError() m = MakeMigrations(tmpfile, Version("1.3.2"), {}) assert not m(check_cb, generate_cb) assert "IndexError" in caplogger.read()
def test_generate_mapping_success(self, tmpfile): ddb = Database(provider="sqlite", filename=str(tmpfile)) Schema(ddb).version = "0.5.0" def check_cb(check_db): with db_session: check_db.execute("select * from NewTable").fetchall() return True def generate_cb(generate_db): class NewTable(generate_db.Entity): aaa = Required(int) m = MakeMigrations(tmpfile, Version("1.3.2"), {}) res = m(check_cb, generate_cb) assert res
def test_init(self): assert Version("3") == Version("3.0.0") assert Version("30") == Version("30.0.0") assert Version("0") == Version("0.0.0") assert Version("3.2") == Version("3.2.0") assert Version("30.2") == Version("30.2.0") assert Version("30.20") == Version("30.20.0") for v in [ "333", "1.333", "123.1", "123.23.23", "12.233.23", "12.23.323" ]: with pytest.raises(InvalidVersion): Version(v)
def test_version_get(resources, version): base = resources / "db_version" / f"{version}.sqlite" if version == "1.2.2": # exception pour la premiere version = "0" assert Schema(file=base).version == Version(version)
def test_init(self, mm): m = mm(Version("1.0.1"), {}) assert (m._backup_name() == "mycartable_backup-from_0.0.0-to_1.0.1-2017-05-21T12_12_12")
def test_parse_int(self): for v_int, v_str in versions_values: assert Version(v_int) == Version(v_str)
def test_to_int(self): for v_int, v_str in versions_values[1:]: assert Version(v_str).to_int() == v_int
def test_init_bind_create_file_add_schema_version(tmpfilename): ddb = Database() init_bind(ddb, filename=tmpfilename, create_db=True) s = Schema(ddb) assert s.version == Version(schema_version)