From 909b3eaa59104b90c944058b2a274711c09790b9 Mon Sep 17 00:00:00 2001 From: Pietro Pasotti Date: Thu, 14 Sep 2023 15:26:27 +0200 Subject: [PATCH] passed state template to ctx --- interface_tester/interface_test.py | 7 ++-- interface_tester/plugin.py | 56 +++++++++++++++++------------- pyproject.toml | 2 +- 3 files changed, 37 insertions(+), 28 deletions(-) diff --git a/interface_tester/interface_test.py b/interface_tester/interface_test.py index e4ebd77..9745a73 100644 --- a/interface_tester/interface_test.py +++ b/interface_tester/interface_test.py @@ -60,12 +60,14 @@ class _InterfaceTestContext: """Charm actions.yaml""" test_fn: Callable """Test function.""" + state_template: Optional[State] + """Initial state that this test should be run with, according to the charm.""" """The role (provider|requirer) that this test is about.""" schema: Optional["DataBagSchema"] = None """Databag schema to validate the output relation with.""" input_state: Optional[State] = None - """Initial state that this test should be run with.""" + """Initial state that this test should be run with, according to the test.""" def check_test_case_validator_signature(fn: Callable): @@ -206,7 +208,6 @@ def __init__(self, state_in: Optional[State] = None, name: Optional[str] = None) if not self.ctx: raise RuntimeError("Tester can only be initialized inside an interface test context.") - self._state_template = None self._state_in = state_in or State() self._test_name = name or self.ctx.test_fn.__name__ @@ -351,7 +352,7 @@ def _run(self, event: Union[str, Event]): # some required config, a "happy" status, network information, OTHER relations. # Typically, should NOT touch the relation that this interface test is about # -> so we overwrite and warn on conflict: state_template is the baseline, - state = (self._state_template or State()).copy() + state = (self.ctx.state_template or State()).copy() relations = self._generate_relations_state( state, input_state, self.ctx.supported_endpoints, self.ctx.role diff --git a/interface_tester/plugin.py b/interface_tester/plugin.py index 11c3d4a..ab9903f 100644 --- a/interface_tester/plugin.py +++ b/interface_tester/plugin.py @@ -32,10 +32,10 @@ class InterfaceTester: _RAISE_IMMEDIATELY = False def __init__( - self, - repo: str = "https://github.com/canonical/charm-relation-interfaces", - branch: str = "main", - base_path: str = "interfaces", + self, + repo: str = "https://github.com/canonical/charm-relation-interfaces", + branch: str = "main", + base_path: str = "interfaces", ): self._repo = repo self._branch = branch @@ -53,18 +53,18 @@ def __init__( self._charm_spec_cache = None def configure( - self, - *, - charm_type: Optional[Type[CharmType]] = None, - repo: Optional[str] = None, - branch: Optional[str] = None, - base_path: Optional[str] = None, - interface_name: Optional[str] = None, - interface_version: Optional[int] = None, - state_template: Optional[State] = None, - meta: Optional[Dict[str, Any]] = None, - actions: Optional[Dict[str, Any]] = None, - config: Optional[Dict[str, Any]] = None, + self, + *, + charm_type: Optional[Type[CharmType]] = None, + repo: Optional[str] = None, + branch: Optional[str] = None, + base_path: Optional[str] = None, + interface_name: Optional[str] = None, + interface_version: Optional[int] = None, + state_template: Optional[State] = None, + meta: Optional[Dict[str, Any]] = None, + actions: Optional[Dict[str, Any]] = None, + config: Optional[Dict[str, Any]] = None, ): """ @@ -189,11 +189,11 @@ def _collect_interface_test_specs(self) -> InterfaceTestSpec: repo_name = self._repo.split("/")[-1] intf_spec_path = ( - Path(tempdir) - / repo_name - / self._base_path - / self._interface_name.replace("-", "_") - / f"v{self._interface_version}" + Path(tempdir) + / repo_name + / self._base_path + / self._interface_name.replace("-", "_") + / f"v{self._interface_version}" ) if not intf_spec_path.exists(): raise RuntimeError( @@ -239,7 +239,7 @@ def _gather_supported_endpoints(self) -> Dict[RoleLiteral, List[str]]: return supported_endpoints def _yield_tests( - self, + self, ) -> Generator[Tuple[Callable, RoleLiteral, DataBagSchema], None, None]: """Yield all test cases applicable to this charm and interface. @@ -306,6 +306,7 @@ def run(self) -> bool: interface_name=self._interface_name, version=self._interface_version, charm_type=self._charm_type, + state_template=self._state_template, meta=self.meta, config=self.config, actions=self.actions, @@ -318,12 +319,19 @@ def run(self) -> bool: except Exception as e: if self._RAISE_IMMEDIATELY: raise e - errors.append(e) + errors.append((ctx, e)) ran_some = True # todo: consider raising custom exceptions here. if errors: - raise InterfaceTestsFailed(f"interface tests completed with errors. {errors}") + + msgs = [] + for ctx, e in errors: + msgs.append(f" - {ctx.interface_name}[v{ctx.version}]@{ctx.role}:{ctx.test_fn} raised {e}") + long_msg = "\n".join(msgs) + + raise InterfaceTestsFailed( + f"interface tests completed with {len(errors)} errors. \n" + long_msg) if not ran_some: msg = f"no tests gathered for {self._interface_name}/v{self._interface_version}" diff --git a/pyproject.toml b/pyproject.toml index 4f41cff..7d7b884 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -11,7 +11,7 @@ build-backend = "setuptools.build_meta" [project] name = "pytest-interface-tester" -version = "1.0.1" +version = "1.0.2" authors = [ { name = "Pietro Pasotti", email = "pietro.pasotti@canonical.com" }, ]