diff --git a/pyproject.toml b/pyproject.toml index 197b45dfc..463870eaf 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -33,6 +33,7 @@ include = ["ops/*.py", "ops/_private/*.py", "test/test_infra.py", "test/test_jujuversion.py", "test/test_log.py", + "test/test_helpers.py", "test/test_lib.py", ] pythonVersion = "3.8" # check no python > 3.8 features are used diff --git a/test/test_helpers.py b/test/test_helpers.py index 34f951e57..ada79af09 100755 --- a/test/test_helpers.py +++ b/test/test_helpers.py @@ -17,6 +17,7 @@ import shutil import subprocess import tempfile +import typing import unittest import ops @@ -24,7 +25,7 @@ from ops.storage import SQLiteStorage -def fake_script(test_case, name, content): +def fake_script(test_case: unittest.TestCase, name: str, content: str): if not hasattr(test_case, 'fake_script_path'): fake_script_path = tempfile.mkdtemp('-fake_script') old_path = os.environ["PATH"] @@ -35,40 +36,42 @@ def cleanup(): os.environ['PATH'] = old_path test_case.addCleanup(cleanup) - test_case.fake_script_path = pathlib.Path(fake_script_path) + test_case.fake_script_path = pathlib.Path(fake_script_path) # type: ignore - template_args = { + template_args: typing.Dict[str, str] = { 'name': name, - 'path': test_case.fake_script_path.as_posix(), + 'path': test_case.fake_script_path.as_posix(), # type: ignore 'content': content, } - path = test_case.fake_script_path / name - with path.open('wt') as f: + path: pathlib.Path = test_case.fake_script_path / name # type: ignore + with path.open('wt') as f: # type: ignore # Before executing the provided script, dump the provided arguments in calls.txt. # ASCII 1E is RS 'record separator', and 1C is FS 'file separator', which seem appropriate. - f.write('''#!/bin/sh + f.write( # type: ignore + '''#!/bin/sh {{ printf {name}; printf "\\036%s" "$@"; printf "\\034"; }} >> {path}/calls.txt {content}'''.format_map(template_args)) - os.chmod(str(path), 0o755) + os.chmod(str(path), 0o755) # type: ignore # TODO: this hardcodes the path to bash.exe, which works for now but might # need to be set via environ or something like that. - path.with_suffix(".bat").write_text( + path.with_suffix(".bat").write_text( # type: ignore f'@"C:\\Program Files\\git\\bin\\bash.exe" {path} %*\n') -def fake_script_calls(test_case, clear=False): - calls_file = test_case.fake_script_path / 'calls.txt' - if not calls_file.exists(): +def fake_script_calls(test_case: unittest.TestCase, + clear: bool = False) -> typing.List[typing.List[str]]: + calls_file: pathlib.Path = test_case.fake_script_path / 'calls.txt' # type: ignore + if not calls_file.exists(): # type: ignore return [] # newline and encoding forced to linuxy defaults because on # windows they're written from git-bash - with calls_file.open('r+t', newline='\n', encoding='utf8') as f: - calls = [line.split('\x1e') for line in f.read().split('\x1c')[:-1]] + with calls_file.open('r+t', newline='\n', encoding='utf8') as f: # type: ignore + calls = [line.split('\x1e') for line in f.read().split('\x1c')[:-1]] # type: ignore if clear: - f.truncate(0) - return calls + f.truncate(0) # type: ignore + return calls # type: ignore class FakeScriptTest(unittest.TestCase): @@ -105,7 +108,10 @@ def test_fake_script_clear(self): class BaseTestCase(unittest.TestCase): - def create_framework(self, *, model=None, tmpdir=None): + def create_framework(self, + *, + model: typing.Optional[ops.Model] = None, + tmpdir: typing.Optional[pathlib.Path] = None): """Create a Framework object. By default operate in-memory; pass a temporary directory via the 'tmpdir' @@ -122,8 +128,8 @@ def create_framework(self, *, model=None, tmpdir=None): framework = ops.Framework( SQLiteStorage(data_fpath), charm_dir, - meta=None, - model=model) + meta=model._cache._meta if model else ops.CharmMeta(), + model=model) # type: ignore self.addCleanup(framework.close) return framework