def test_first_migration_was_executed(self): migrations = [ Migration("1.0.0", None, None, None, None), Migration("1.2.0", None, None, None, None), Migration("1.3.0", None, None, None, None), ] executed_migrations = [ Migration("1.0.0", None, None, None, None, status=[MigrationStatus.SUCCESS]) ] merged_migrations = MigrationMergeService().merge( migrations, executed_migrations) self.assertEqual(3, len(merged_migrations)) self.assertEqual(MigrationStatus.SUCCESS, merged_migrations[0].get_status_as_string()) self.assertEqual(executed_migrations[0], merged_migrations[0]) self.assertEqual(MigrationStatus.PENDING, merged_migrations[1].get_status_as_string()) self.assertEqual(MigrationStatus.PENDING, merged_migrations[2].get_status_as_string())
def test_incorrect_checksum(self): migrations = [ Migration("1.0.0", None, "1234", None, None), Migration("1.2.0", None, None, None, None), ] executed_migrations = [ Migration("1.0.0", None, "4321", None, None, status=[MigrationStatus.SUCCESS]), Migration("1.2.0", None, None, None, None, status=[MigrationStatus.SUCCESS]), ] merged_migrations = MigrationMergeService().merge( migrations, executed_migrations) self.assertEqual(2, len(merged_migrations)) self.assertEqual( [MigrationStatus.SUCCESS, MigrationStatus.CHECKSUM_MISMATCH], merged_migrations[0].status)
def test_single_migration(self): def call_single_migration(expected_version: str, expected_entries_in_table: int, pending_migrations_found: int): with self.assertLogs() as _cm: commandline_parse_phase.start( args=["--migration-path", "/path", "migrate", "--single"]) self.assertIn( "INFO:symigrate.command.migrate_command:Found %d pending migrations" % pending_migrations_found, _cm.output) self.assertIn( "INFO:symigrate.command.migrate_command:Only executing the next pending migration", _cm.output) migration_table_rows = self.database_connection.execute( "SELECT version, status FROM migration").fetchall() self.assertEqual(expected_entries_in_table, len(migration_table_rows)) self.assertEqual(expected_version, migration_table_rows[-1][0]) self.assertEqual("SUCCESS", migration_table_rows[-1][1]) self.migration_script_repository_mock.find_all.return_value = [ Migration(version="1.0.0", description="first migration", checksum="1234", script="", filename="V1.0.0__description.sh"), Migration(version="1.1.0", description="second migration", checksum="2345", script="", filename="V1.1.0_descr.sh"), ] commandline_parse_phase = CommandlineParsePhase() self.migration_script_runner_mock.run_migration_script.return_value = MigrationExecutionResult( success=True) # first single migration call call_single_migration(expected_version="1.0.0", expected_entries_in_table=1, pending_migrations_found=2) # second single migration call call_single_migration(expected_version="1.1.0", expected_entries_in_table=2, pending_migrations_found=1) with self.assertLogs() as cm: commandline_parse_phase.start( args=["--migration-path", "/path", "migrate", "--single"]) self.assertIn( "INFO:symigrate.command.migrate_command:No pending migrations found", cm.output)
def test_push(self): migration = Migration("1.2.3", "some description", status=[MigrationStatus.SUCCESS], checksum="1234", script="echo 'huhu'", execution_result=MigrationExecutionResult(), filename="V1.2.3__some_description.sh") self.executed_migration_repository.init() self.executed_migration_repository.push(migration) rows = self.database_connection.execute( "SELECT version, description, status, " "checksum, scope, script FROM migration").fetchall() self.assertEqual(1, len(rows)) row = rows[0] self.assertEqual("1.2.3", row[0]) self.assertEqual("some description", row[1]) self.assertEqual("SUCCESS", row[2]) self.assertEqual("1234", row[3]) self.assertEqual("DEFAULT", row[4]) self.assertEqual("echo 'huhu'", row[5])
def _get_table_row_from_migration(migration: Migration) -> list: return [ migration.version, migration.description, migration.execution_result.execution_timestamp if migration.execution_result is not None else "", migration.get_status_as_string() ]
def test_one_pending_migration_failed(self): self.migration_script_repository_mock.find_all.return_value = [ Migration(version="1.0.0", description="test migration", checksum="1234", script="", filename="V1.0.0__description.sh") ] commandline_parse_phase = CommandlineParsePhase() self.migration_script_runner_mock.run_migration_script.return_value = MigrationExecutionResult( success=False) with self.assertLogs() as cm: with self.assertRaises(SystemExit): commandline_parse_phase.start( args=["--migration-path", "/path", "migrate"]) expected_path = os.path.join("/path", "V1.0.0__description.sh") self.migration_script_runner_mock.run_migration_script.assert_called_once_with( expected_path) self.assertIn( "INFO:symigrate.command.migrate_command:Found 1 pending migrations", cm.output) self.assertIn( "ERROR:symigrate.main.symigrate:StopOnMigrationError: Stopping migration due to failed " "migration script execution", cm.output) migration_table_row = self.database_connection.execute( "SELECT version, status FROM migration").fetchone() self.assertIsNotNone(migration_table_row) self.assertEqual("1.0.0", migration_table_row[0]) self.assertEqual("FAILED", migration_table_row[1])
def test_all_pending(self): migrations = [ Migration("1.0.0", None, None, None, None), Migration("1.2.0", None, None, None, None), Migration("1.3.0", None, None, None, None), ] executed_migrations = [] merged_migrations = MigrationMergeService().merge( migrations, executed_migrations) self.assertEqual(3, len(merged_migrations)) self.assertEqual(MigrationStatus.PENDING, merged_migrations[0].get_status_as_string()) self.assertEqual(MigrationStatus.PENDING, merged_migrations[1].get_status_as_string()) self.assertEqual(MigrationStatus.PENDING, merged_migrations[2].get_status_as_string())
def test_diff_output(self): self.migration_script_repository_mock.find_by_version.return_value = \ Migration(version="1.0.0", description="test migration", checksum="2345", script="", filename="") commandline_parse_phase = CommandlineParsePhase() with capture_output() as output: commandline_parse_phase.start(args=["diff", "--version", "1.0.0"]) self.assertEqual("- The script", output[0].getvalue())
def push(self, migration: Migration): LOGGER.debug("Saving executed migration %s", migration) self.database_connection.execute( QUERY_INSERT_MIGRATION, (migration.version, migration.description, migration.execution_result.execution_timestamp.strftime( SYMIGRATE_TIMESTAMP_FORMAT), migration.get_status_as_string(), migration.checksum, migration.scope, migration.script, migration.filename)) self.database_connection.commit()
def test_diff_no_difference(self): self.migration_script_repository_mock.find_by_version.return_value = \ Migration(version="1.0.0", description="test migration", checksum="1234", script="", filename="") commandline_parse_phase = CommandlineParsePhase() with self.assertLogs() as log: commandline_parse_phase.start(args=["diff", "--version", "1.0.0"]) self.assertIn( "INFO:symigrate.command.diff_command:No difference found", log.output)
def setUp(self): self.database_connection = sqlite3.connect(":memory:") self.database_connection.execute(DDL_CREATE_MIGRATION_TABLE) self.out_stream = StringIO() self.migration_script_repository_mock = Mock() self.migration_script_repository_mock.find_all = Mock() self.migration_script_repository_mock.find_all.return_value = [ Migration(version="1.0.0", description="test migration", checksum="1234", script="", filename=""), Migration(version="1.1.0", description="another migration", checksum="1234", script="", filename=""), ] InterfaceCreationPhase.database_connection_hook = self.database_connection MainPhase.out_stream_hook = self.out_stream MainPhase.migration_script_checker_hook = Mock() MainPhase.migration_script_repository_hook = self.migration_script_repository_mock
def _create_migration(self, match_result: MigrationFileMatcher.MatchResult): full_file_path = os.path.join(self.path, match_result.filename) migration_script_content = self._get_script_content(full_file_path) migration = Migration( version=match_result.version, description=match_result.description, checksum=self._calculate_checksum(migration_script_content), script=migration_script_content, scope=self.scope, filename=match_result.filename, full_file_path=full_file_path) return migration
def _create_migration_from_row(row): migration_execution_result = MigrationExecutionResult( execution_timestamp=datetime.strptime( row[2], SYMIGRATE_TIMESTAMP_FORMAT), ) migration = Migration(version=row[0], description=row[1], status=row[3].split(","), checksum=row[4], scope=row[5], script=row[6], execution_result=migration_execution_result, filename=row[7]) return migration
def test_missing_migration_script(self): migrations = [ Migration("1.0.0", None, None, None, None), Migration("1.2.0", None, None, None, None), ] executed_migrations = [ Migration("1.0.0", None, None, None, None, status=[MigrationStatus.SUCCESS]), Migration("1.2.0", None, None, None, None, status=[MigrationStatus.SUCCESS]), Migration("1.3.0", None, None, None, None, status=[MigrationStatus.FAILED]) ] merged_migrations = MigrationMergeService().merge( migrations, executed_migrations) self.assertEqual(3, len(merged_migrations)) self.assertEqual(executed_migrations[0], merged_migrations[0]) self.assertEqual(executed_migrations[1], merged_migrations[1]) self.assertEqual(executed_migrations[2], merged_migrations[2]) self.assertEqual( [MigrationStatus.FAILED, MigrationStatus.MISSING_MIGRATION_SCRIPT], merged_migrations[2].status)
def test_no_pending_migrations(self): self.database_connection.execute( "INSERT INTO migration (scope, version, description, status, timestamp, checksum)" "VALUES" "('DEFAULT', '1.0.0', 'test migration', 'SUCCESS', '2018-04-29T11:40:00', '1234')" ) self.migration_script_repository_mock.find_all.return_value = [ Migration(version="1.0.0", description="test migration", checksum="1234", script="", filename="") ] commandline_parse_phase = CommandlineParsePhase() with self.assertLogs() as cm: commandline_parse_phase.start(args=["migrate"]) self.assertIn( "INFO:symigrate.command.migrate_command:No pending migrations found", cm.output)
def test_all_migrations_were_executed(self): migrations = [ Migration("1.0.0", None, None, None, None), Migration("1.2.0", None, None, None, None), Migration("1.3.0", None, None, None, None), ] executed_migrations = [ Migration("1.0.0", None, None, None, None, status=[MigrationStatus.SUCCESS]), Migration("1.2.0", None, None, None, None, status=[MigrationStatus.SUCCESS]), Migration("1.3.0", None, None, None, None, status=[MigrationStatus.FAILED]) ] merged_migrations = MigrationMergeService().merge( migrations, executed_migrations) self.assertEqual(3, len(merged_migrations)) self.assertEqual(executed_migrations[0], merged_migrations[0]) self.assertEqual(executed_migrations[1], merged_migrations[1]) self.assertEqual(executed_migrations[2], merged_migrations[2]) self.assertEqual(MigrationStatus.FAILED, merged_migrations[2].get_status_as_string())