Skip to content

Commit

Permalink
Remove dependency on ops.testing.
Browse files Browse the repository at this point in the history
  • Loading branch information
tonyandrewmeyer committed Sep 10, 2024
1 parent 29a50b7 commit 69223f2
Show file tree
Hide file tree
Showing 8 changed files with 739 additions and 42 deletions.
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ build-backend = "setuptools.build_meta"
[project]
name = "ops-scenario"

version = "7.0.1"
version = "7.0.2"

authors = [
{ name = "Pietro Pasotti", email = "[email protected]" }
Expand Down
3 changes: 2 additions & 1 deletion scenario/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ def test_base():
assert out.unit_status == UnknownStatus()
"""

from scenario.context import Context, Manager
from scenario.context import Context, ExecArgs, Manager
from scenario.state import (
ActionFailed,
ActiveStatus,
Expand Down Expand Up @@ -119,6 +119,7 @@ def test_base():
"DeferredEvent",
"ErrorStatus",
"Exec",
"ExecArgs",
"ICMPPort",
"JujuLogLine",
"MaintenanceStatus",
Expand Down
38 changes: 33 additions & 5 deletions scenario/context.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,18 @@
# Copyright 2023 Canonical Ltd.
# See LICENSE file for licensing details.

import dataclasses
import functools
import tempfile
from contextlib import contextmanager
from pathlib import Path
from typing import TYPE_CHECKING, Any, Dict, List, Mapping, Optional, Type, Union, cast

import ops
import ops.testing

from scenario.errors import AlreadyEmittedError, ContextSetupError
from scenario.logger import logger as scenario_logger
from scenario.runtime import Runtime
from scenario.runtime import Runtime, _CharmType
from scenario.state import (
ActionFailed,
CheckInfo,
Expand All @@ -36,6 +36,31 @@
_DEFAULT_JUJU_VERSION = "3.5"


# This needs to exactly match the class in ops/testing.py, because it will
# replace that one when Scenario is available in ops.testing. We cannot import
# it here because that would create a circular import.
@dataclasses.dataclass(frozen=True)
class ExecArgs:
"""Represent arguments captured from the :meth:`ops.Container.exec` method call.
These arguments will be available in the :attr:`Context.exec_history` dictionary.
See :meth:`ops.pebble.Client.exec` for documentation of properties.
"""

command: List[str]
environment: Dict[str, str]
working_dir: Optional[str]
timeout: Optional[float]
user_id: Optional[int]
user: Optional[str]
group_id: Optional[int]
group: Optional[str]
stdin: Optional[Union[str, bytes]]
encoding: Optional[str]
combine_stderr: bool


class Manager:
"""Context manager to offer test code some runtime charm object introspection.
Expand Down Expand Up @@ -426,7 +451,7 @@ def test_foo():

def __init__(
self,
charm_type: Type[ops.testing.CharmType],
charm_type: Type[_CharmType],
meta: Optional[Dict[str, Any]] = None,
*,
actions: Optional[Dict[str, Any]] = None,
Expand Down Expand Up @@ -508,7 +533,7 @@ def __init__(
self.juju_log: List["JujuLogLine"] = []
self.app_status_history: List["_EntityStatus"] = []
self.unit_status_history: List["_EntityStatus"] = []
self.exec_history: Dict[str, List[ops.testing.ExecArgs]] = {}
self.exec_history: Dict[str, List[ExecArgs]] = {}
self.workload_version_history: List[str] = []
self.removed_secret_revisions: List[int] = []
self.emitted_events: List[ops.EventBase] = []
Expand Down Expand Up @@ -644,7 +669,10 @@ def run(self, event: "_Event", state: "State") -> "State":
assert self._output_state is not None
if event.action:
if self._action_failure_message is not None:
raise ActionFailed(self._action_failure_message, self._output_state)
raise ActionFailed(
self._action_failure_message,
state=self._output_state,
)
return self._output_state

@contextmanager
Expand Down
Loading

0 comments on commit 69223f2

Please sign in to comment.