def test_apply_multiple_success(self, apply: Mock) -> None: f1 = FileInfo("foo.sql", "schema", "dialect", 123, 14) f2 = FileInfo("bar.sql", "schema", "dialect", 124, 15) result = apply_files("invalid:///", [f1, f2]) assert result == ([f1, f2], None) apply.assert_has_calls( [call("invalid:///", f1), call("invalid:///", f2)])
def test_execute__without_transaction(self, open: Mock, update_sql: Mock) -> None: open.return_value = StringIO("") info = FileInfo("/foo/bar", "myschema", "sqlite", 45, 3) info.transaction = False apply_file("sqlite:///", info) open.assert_called_once_with("/foo/bar", "r") update_sql.assert_called_once_with("sqlite:///", "", "myschema", 45, 3, transaction=False)
def test_apply_multiple_fail(self, apply: Mock) -> None: def apply_impl(url: str, file_info: FileInfo) -> None: if file_info == f2: raise SQLAlchemyError apply.side_effect = apply_impl f1 = FileInfo("foo.sql", "schema", "dialect", 123, 14) f2 = FileInfo("bar.sql", "schema", "dialect", 124, 15) f3 = FileInfo("not-called.sql", "schema", "dialect", 125, 15) result = apply_files("invalid:///", [f1, f2, f3]) assert result == ([f1], f2) apply.assert_has_calls( [call("invalid:///", f1), call("invalid:///", f2)])
def test_order(self, parse_sql_files: Mock, apply_files: Mock) -> None: fi123 = FileInfo("", "myschema", "postgres", 123, 0) fi122 = FileInfo("", "myschema", "postgres", 122, 0) fi124 = FileInfo("", "myschema", "postgres", 124, 0) parse_sql_files.return_value = [fi123, fi122, fi124] with patch("dbupgrade.upgrade.Filter") as filter_: filter_.return_value.return_value.matches.return_value = True db_upgrade( "myschema", "postgres://localhost/foo", "/tmp", VersionInfo(), ) apply_files.assert_called_once_with(ANY, [fi122, fi123, fi124])
def parse_sql_stream(stream: Iterable[str], filename: str) -> FileInfo: headers = _parse_sql_headers(stream) try: schema = headers["schema"] dialect = headers["dialect"] version = _int_header(headers, "version") api_level = _int_header(headers, "api-level") except KeyError as exc: raise ParseError("missing header: {0.args[0]}".format(exc)) from None info = FileInfo(filename, schema, dialect, version, api_level) if "transaction" in headers: info.transaction = _bool_header(headers, "transaction") return info
def test_json_error(self, parse_args: Mock, db_upgrade: Mock, capsys: CaptureFixture) -> None: parse_args.return_value.json = True db_upgrade.return_value = UpgradeResult( VersionResult(123, 45), VersionResult(123, 45), [], FileInfo("foo.sql", "", "", 124, 46), ) with pytest.raises(SystemExit): main() j = json.loads(capsys.readouterr().out) assert j == { "success": False, "oldVersion": { "version": 123, "apiLevel": 45 }, "newVersion": { "version": 123, "apiLevel": 45 }, "appliedScripts": [], "failedScript": { "filename": "foo.sql", "version": 124, "apiLevel": 46, }, }
def test_json_success(self, parse_args: Mock, db_upgrade: Mock, capsys: CaptureFixture) -> None: parse_args.return_value.json = True db_upgrade.return_value = UpgradeResult( VersionResult(123, 45), VersionResult(124, 46), [FileInfo("foo.sql", "", "", 124, 46)], ) main() j = json.loads(capsys.readouterr().out) assert j == { "success": True, "oldVersion": { "version": 123, "apiLevel": 45 }, "newVersion": { "version": 124, "apiLevel": 46 }, "appliedScripts": [{ "filename": "foo.sql", "version": 124, "apiLevel": 46, }], }
def test_result_error(self, fetch_current_db_versions: Mock, apply_files: Mock) -> None: file_info1 = FileInfo("foo.sql", "myschema", "", 123, 45) file_info2 = FileInfo("foo.sql", "myschema", "", 124, 46) fetch_current_db_versions.return_value = (122, 44) apply_files.return_value = ([file_info1], file_info2) result = db_upgrade( "myschema", "postgres://localhost/foo", "/tmp", VersionInfo(), ) assert result == UpgradeResult( VersionResult(122, 44), VersionResult(123, 45), [file_info1], file_info2, )
def test_filter( self, fetch_current_db_versions: Mock, parse_sql_files: Mock, apply_files: Mock, ) -> None: fetch_current_db_versions.return_value = 130, 34 file_info = FileInfo("", "myschema", "", 0, 0) parse_sql_files.return_value = [ file_info, FileInfo("", "otherschema", "", 0, 0), ] with patch("dbupgrade.upgrade.Filter") as filter_: filter_.return_value.matches = lambda fi: fi.schema == "myschema" db_upgrade( "myschema", "postgres://localhost/foo", "/tmp", VersionInfo(api_level=12), ) filter_.assert_called_once_with( "myschema", "postgres", VersionMatcher(131, MAX_VERSION, 12)) apply_files.assert_called_once_with(ANY, [file_info])
def test_exercise( self, fetch_current_db_versions: Mock, collect_sql_files: Mock, parse_sql_files: Mock, apply_files: Mock, ) -> None: filenames = ["/tmp/foo", "/tmp/bar"] file_infos = [FileInfo("", "myschema", "postgres", 150, 30)] fetch_current_db_versions.return_value = 123, 44 collect_sql_files.return_value = filenames parse_sql_files.return_value = file_infos db_upgrade("myschema", "postgres://localhost/foo", "/tmp", VersionInfo()) fetch_current_db_versions.assert_called_once_with( "postgres://localhost/foo", "myschema") collect_sql_files.assert_called_once_with("/tmp") parse_sql_files.assert_called_once_with(filenames) apply_files.assert_called_once_with("postgres://localhost/foo", file_infos)
def test_matches__api_level_too_large(self) -> None: filter_ = Filter("myschema", "postgres", VersionMatcher(5, 10, 3)) file_info = FileInfo("", "myschema", "postgres", 7, 4) assert not filter_.matches(file_info)
def test_log(self, logging: Mock) -> None: info = FileInfo("/foo/bar", "myschema", "sqlite", 45, 3) apply_file("sqlite:///", info) logging.info.assert_called_once_with("applying #45 (API level 3)")
def test_matches__min_version_too_large(self) -> None: matcher = VersionMatcher(5, 10, 3) file_info = FileInfo("", "", "", 11, 2) assert not matcher.matches(file_info)
def test_lt__non_matching_schemas(self) -> None: fi1 = FileInfo("", "schema1", "postgres", 4, 0) fi2 = FileInfo("", "schema2", "postgres", 5, 0) with pytest.raises(TypeError): fi1 < fi2
def test_matches__wrong_dialect(self) -> None: filter_ = Filter("myschema", "postgres", VersionMatcher(5, 10, 3)) file_info = FileInfo("", "myschema", "mysql", 5, 2) assert not filter_.matches(file_info)
def test_repr(self) -> None: fi = FileInfo("/foo/bar", "myschema", "postgres", 123, 13) assert ( repr(fi) == "FileInfo('/foo/bar', 'myschema', 'postgres', 123, 13)" )
def test_error(self, db_upgrade: Mock) -> None: db_upgrade.return_value = UpgradeResult( vi, vi, [], FileInfo("foo.sql", "", "", 123, 45)) with pytest.raises(SystemExit) as exc: main() assert exc.value.code == 1
def test_success(self, db_upgrade: Mock) -> None: db_upgrade.return_value = UpgradeResult( vi, vi, [FileInfo("foo.sql", "", "", 123, 45)]) main()
def test_matches__api_level_too_large(self) -> None: matcher = VersionMatcher(5, 10, 3) file_info = FileInfo("", "", "", 7, 4) assert not matcher.matches(file_info)
def test_matches__min_version_too_large(self) -> None: filter_ = Filter("myschema", "postgres", VersionMatcher(5, 10, 3)) file_info = FileInfo("", "myschema", "postgres", 11, 2) assert not filter_.matches(file_info)
def test_matches__version_matches_upper(self) -> None: matcher = VersionMatcher(5, 10, 3) file_info = FileInfo("", "", "", 10, 2) assert matcher.matches(file_info)
def _create_file_info(self) -> FileInfo: return FileInfo("", "myschema", "sqlite", 0, 0)
def test_matches__version_in_between(self) -> None: matcher = VersionMatcher(5, 10, 3) file_info = FileInfo("", "", "", 7, 2) assert matcher.matches(file_info)
def test_lt__non_matching_dialects(self) -> None: fi1 = FileInfo("", "schema", "postgres", 4, 0) fi2 = FileInfo("", "schema", "mysql", 5, 0) with pytest.raises(TypeError): fi1 < fi2
def test_matches__api_level_match(self) -> None: matcher = VersionMatcher(5, 10, 3) file_info = FileInfo("", "", "", 7, 3) assert matcher.matches(file_info)
def test_lt(self) -> None: fi1 = FileInfo("", "schema", "postgres", 4, 0) fi2 = FileInfo("", "schema", "postgres", 5, 0) assert fi1 < fi2 assert not (fi2 < fi1)
def test_matches__version_matches_upper(self) -> None: filter_ = Filter("myschema", "postgres", VersionMatcher(5, 10, 3)) file_info = FileInfo("", "myschema", "postgres", 10, 2) assert filter_.matches(file_info)