diff --git a/requirements.txt b/requirements.txt index 75084465..0177501f 100644 --- a/requirements.txt +++ b/requirements.txt @@ -6,19 +6,19 @@ # annotated-types==0.7.0 # via pydantic -anyio==4.4.0 +anyio==4.6.0 # via httpx bcrypt==4.2.0 # via paramiko cachetools==5.5.0 # via google-auth -certifi==2024.7.4 +certifi==2024.8.30 # via # httpcore # httpx # kubernetes # requests -cffi==1.17.0 +cffi==1.17.1 # via # cryptography # pynacl @@ -26,11 +26,13 @@ charset-normalizer==3.3.2 # via requests click==8.1.7 # via typer -cosl==0.0.34 +cosl==0.0.36 # via -r requirements.in cryptography==43.0.1 # via paramiko -google-auth==2.34.0 +durationpy==0.7 + # via kubernetes +google-auth==2.35.0 # via kubernetes h11==0.14.0 # via httpcore @@ -42,7 +44,7 @@ httpx==0.27.2 # lightkube hvac==2.3.0 # via juju -idna==3.8 +idna==3.10 # via # anyio # httpx @@ -55,7 +57,7 @@ jinja2==3.1.4 # via -r requirements.in juju==3.5.2.0 # via -r requirements.in -kubernetes==30.1.0 +kubernetes==31.0.0 # via juju lightkube==0.15.4 # via @@ -77,29 +79,29 @@ oauthlib==3.2.2 # via # kubernetes # requests-oauthlib -ops==2.16.0 +ops==2.17.0 # via # -r requirements.in # cosl # ops-scenario -ops-scenario==6.1.7 +ops-scenario==7.0.5 # via pytest-interface-tester packaging==24.1 # via # juju # pytest -paramiko==3.4.1 +paramiko==3.5.0 # via juju pluggy==1.5.0 # via pytest -protobuf==5.27.4 +protobuf==5.28.2 # via macaroonbakery -pyasn1==0.6.0 +pyasn1==0.6.1 # via # juju # pyasn1-modules # rsa -pyasn1-modules==0.4.0 +pyasn1-modules==0.4.1 # via google-auth pycparser==2.22 # via cffi @@ -126,11 +128,11 @@ pyrfc3339==1.1 # macaroonbakery pytest==8.3.3 # via pytest-interface-tester -pytest-interface-tester==3.1.0 +pytest-interface-tester==3.2.0 # via -r requirements.in python-dateutil==2.9.0.post0 # via kubernetes -pytz==2024.1 +pytz==2024.2 # via pyrfc3339 pyyaml==6.0.2 # via @@ -175,7 +177,7 @@ typing-extensions==4.12.2 # typing-inspect typing-inspect==0.9.0 # via juju -urllib3==2.2.2 +urllib3==2.2.3 # via # kubernetes # requests @@ -183,5 +185,5 @@ websocket-client==1.8.0 # via # kubernetes # ops -websockets==13.0 +websockets==13.1 # via juju diff --git a/test-requirements.txt b/test-requirements.txt index f318903c..84d1b591 100644 --- a/test-requirements.txt +++ b/test-requirements.txt @@ -5,133 +5,194 @@ # pip-compile --constraint=requirements.txt test-requirements.in # annotated-types==0.7.0 - # via pydantic + # via + # -c requirements.txt + # pydantic asttokens==2.4.1 # via stack-data bcrypt==4.2.0 - # via paramiko + # via + # -c requirements.txt + # paramiko cachetools==5.5.0 - # via google-auth -certifi==2024.7.4 # via + # -c requirements.txt + # google-auth +certifi==2024.8.30 + # via + # -c requirements.txt # kubernetes # requests -cffi==1.17.0 +cffi==1.17.1 # via + # -c requirements.txt # cryptography # pynacl charset-normalizer==3.3.2 - # via requests + # via + # -c requirements.txt + # requests click==8.1.7 - # via typer + # via + # -c requirements.txt + # typer codespell==2.3.0 # via -r test-requirements.in coverage[toml]==7.6.1 # via -r test-requirements.in cryptography==43.0.1 - # via paramiko + # via + # -c requirements.txt + # paramiko decorator==5.1.1 # via # ipdb # ipython -executing==2.0.1 +durationpy==0.7 + # via + # -c requirements.txt + # kubernetes +executing==2.1.0 # via stack-data -google-auth==2.34.0 - # via kubernetes +google-auth==2.35.0 + # via + # -c requirements.txt + # kubernetes hvac==2.3.0 - # via juju -idna==3.8 - # via requests + # via + # -c requirements.txt + # juju +idna==3.10 + # via + # -c requirements.txt + # requests iniconfig==2.0.0 - # via pytest + # via + # -c requirements.txt + # pytest ipdb==0.13.13 # via pytest-operator -ipython==8.26.0 +ipython==8.27.0 # via ipdb jedi==0.19.1 # via ipython jinja2==3.1.4 - # via pytest-operator + # via + # -c requirements.txt + # pytest-operator juju==3.5.2.0 # via + # -c requirements.txt # -r test-requirements.in # pytest-operator -kubernetes==30.1.0 - # via juju +kubernetes==31.0.0 + # via + # -c requirements.txt + # juju macaroonbakery==1.3.4 - # via juju + # via + # -c requirements.txt + # juju markupsafe==2.1.5 - # via jinja2 + # via + # -c requirements.txt + # jinja2 matplotlib-inline==0.1.7 # via ipython mypy-extensions==1.0.0 - # via typing-inspect + # via + # -c requirements.txt + # typing-inspect nodeenv==1.9.1 # via pyright oauthlib==3.2.2 # via + # -c requirements.txt # kubernetes # requests-oauthlib -ops==2.16.0 - # via ops-scenario -ops-scenario==6.1.7 +ops==2.17.0 # via + # -c requirements.txt + # ops-scenario +ops-scenario==7.0.5 + # via + # -c requirements.txt # -r test-requirements.in # pytest-interface-tester packaging==24.1 # via + # -c requirements.txt # juju # pytest parameterized==0.9.0 # via -r test-requirements.in -paramiko==3.4.1 - # via juju +paramiko==3.5.0 + # via + # -c requirements.txt + # juju parso==0.8.4 # via jedi pexpect==4.9.0 # via ipython pluggy==1.5.0 - # via pytest -prompt-toolkit==3.0.47 + # via + # -c requirements.txt + # pytest +prompt-toolkit==3.0.48 # via ipython -protobuf==5.27.4 - # via macaroonbakery +protobuf==5.28.2 + # via + # -c requirements.txt + # macaroonbakery ptyprocess==0.7.0 # via pexpect pure-eval==0.2.3 # via stack-data -pyasn1==0.6.0 +pyasn1==0.6.1 # via + # -c requirements.txt # juju # pyasn1-modules # rsa -pyasn1-modules==0.4.0 - # via google-auth +pyasn1-modules==0.4.1 + # via + # -c requirements.txt + # google-auth pycparser==2.22 - # via cffi + # via + # -c requirements.txt + # cffi pydantic==2.9.2 # via + # -c requirements.txt # -r test-requirements.in # pytest-interface-tester pydantic-core==2.23.4 - # via pydantic + # via + # -c requirements.txt + # pydantic pygments==2.18.0 # via ipython pymacaroons==0.13.0 - # via macaroonbakery + # via + # -c requirements.txt + # macaroonbakery pynacl==1.5.0 # via + # -c requirements.txt # macaroonbakery # paramiko # pymacaroons pyrfc3339==1.1 # via + # -c requirements.txt # juju # macaroonbakery -pyright==1.1.381 +pyright==1.1.382.post1 # via -r test-requirements.in pytest==8.3.3 # via + # -c requirements.txt # -r test-requirements.in # pytest-asyncio # pytest-interface-tester @@ -140,16 +201,23 @@ pytest-asyncio==0.21.2 # via # -r test-requirements.in # pytest-operator -pytest-interface-tester==3.1.0 - # via -r test-requirements.in -pytest-operator==0.36.0 +pytest-interface-tester==3.2.0 + # via + # -c requirements.txt + # -r test-requirements.in +pytest-operator==0.37.0 # via -r test-requirements.in python-dateutil==2.9.0.post0 - # via kubernetes -pytz==2024.1 - # via pyrfc3339 + # via + # -c requirements.txt + # kubernetes +pytz==2024.2 + # via + # -c requirements.txt + # pyrfc3339 pyyaml==6.0.2 # via + # -c requirements.txt # juju # kubernetes # ops @@ -157,18 +225,24 @@ pyyaml==6.0.2 # pytest-operator requests==2.32.3 # via + # -c requirements.txt # hvac # kubernetes # macaroonbakery # requests-oauthlib requests-oauthlib==2.0.0 - # via kubernetes + # via + # -c requirements.txt + # kubernetes rsa==4.9 - # via google-auth -ruff==0.6.2 + # via + # -c requirements.txt + # google-auth +ruff==0.6.8 # via -r test-requirements.in six==1.16.0 # via + # -c requirements.txt # asttokens # kubernetes # macaroonbakery @@ -177,29 +251,41 @@ six==1.16.0 stack-data==0.6.3 # via ipython toposort==1.10 - # via juju + # via + # -c requirements.txt + # juju traitlets==5.14.3 # via # ipython # matplotlib-inline typer==0.7.0 - # via pytest-interface-tester + # via + # -c requirements.txt + # pytest-interface-tester typing-extensions==4.12.2 # via + # -c requirements.txt # pydantic # pydantic-core + # pyright # typing-inspect typing-inspect==0.9.0 - # via juju -urllib3==2.2.2 # via + # -c requirements.txt + # juju +urllib3==2.2.3 + # via + # -c requirements.txt # kubernetes # requests wcwidth==0.2.13 # via prompt-toolkit websocket-client==1.8.0 # via + # -c requirements.txt # kubernetes # ops -websockets==13.0 - # via juju +websockets==13.1 + # via + # -c requirements.txt + # juju diff --git a/tests/unit/lib/charms/sdcore_upf/v0/test_fiveg_n3_provider.py b/tests/unit/lib/charms/sdcore_upf/v0/test_fiveg_n3_provider.py index 8b083d26..26a22811 100644 --- a/tests/unit/lib/charms/sdcore_upf/v0/test_fiveg_n3_provider.py +++ b/tests/unit/lib/charms/sdcore_upf/v0/test_fiveg_n3_provider.py @@ -59,17 +59,17 @@ def test_given_fiveg_n3_relation_when_set_upf_information_then_info_added_to_rel relations=[fiveg_n3_relation], ) - action = scenario.Action( - name="publish-upf-information", - params={ - "ip-address": "1.2.3.4", - "relation-id": str(fiveg_n3_relation.relation_id), - }, - ) + params = { + "ip-address": "1.2.3.4", + "relation-id": str(fiveg_n3_relation.id), + } - action_output = self.ctx.run_action(action, state_in) + state_out = self.ctx.run( + self.ctx.on.action("publish-upf-information", params=params), state_in + ) - assert action_output.state.relations[0].local_app_data["upf_ip_address"] == "1.2.3.4" + relation = state_out.get_relation(fiveg_n3_relation.id) + assert relation.local_app_data["upf_ip_address"] == "1.2.3.4" def test_given_invalid_upf_information_when_set_upf_information_then_error_raised( self, @@ -83,16 +83,13 @@ def test_given_invalid_upf_information_when_set_upf_information_then_error_raise relations=[fiveg_n3_relation], ) - action = scenario.Action( - name="publish-upf-information", - params={ - "ip-address": "abcdef", - "relation-id": str(fiveg_n3_relation.relation_id), - }, - ) + params = { + "ip-address": "abcdef", + "relation-id": str(fiveg_n3_relation.id), + } with pytest.raises(Exception) as e: - self.ctx.run_action(action, state_in) + self.ctx.run(self.ctx.on.action("publish-upf-information", params=params), state_in) assert "Invalid UPF IP address" in str(e.value) @@ -108,7 +105,7 @@ def test_given_when_relation_joined_then_fiveg_n3_request_event_emitted( relations=[fiveg_n3_relation], ) - self.ctx.run(fiveg_n3_relation.joined_event, state_in) + self.ctx.run(self.ctx.on.relation_joined(fiveg_n3_relation), state_in) assert len(self.ctx.emitted_events) == 2 assert isinstance(self.ctx.emitted_events[1], FiveGN3RequestEvent) diff --git a/tests/unit/lib/charms/sdcore_upf/v0/test_fiveg_n3_requirer.py b/tests/unit/lib/charms/sdcore_upf/v0/test_fiveg_n3_requirer.py index c29b88a0..81959b28 100644 --- a/tests/unit/lib/charms/sdcore_upf/v0/test_fiveg_n3_requirer.py +++ b/tests/unit/lib/charms/sdcore_upf/v0/test_fiveg_n3_requirer.py @@ -38,7 +38,7 @@ def test_given_upf_ip_address_in_relation_data_when_relation_changed_then_fiveg_ relations=[fiveg_n3_relation], ) - self.ctx.run(fiveg_n3_relation.changed_event, state_in) + self.ctx.run(self.ctx.on.relation_changed(fiveg_n3_relation), state_in) assert len(self.ctx.emitted_events) == 2 assert isinstance(self.ctx.emitted_events[1], N3AvailableEvent) @@ -56,6 +56,6 @@ def test_given_upf_ip_address_not_in_relation_data_when_relation_changed_then_fi relations=[fiveg_n3_relation], ) - self.ctx.run(fiveg_n3_relation.changed_event, state_in) + self.ctx.run(self.ctx.on.relation_changed(fiveg_n3_relation), state_in) assert len(self.ctx.emitted_events) == 1 diff --git a/tests/unit/lib/charms/sdcore_upf/v0/test_fiveg_n4_provider.py b/tests/unit/lib/charms/sdcore_upf/v0/test_fiveg_n4_provider.py index d7ba465c..682324f8 100644 --- a/tests/unit/lib/charms/sdcore_upf/v0/test_fiveg_n4_provider.py +++ b/tests/unit/lib/charms/sdcore_upf/v0/test_fiveg_n4_provider.py @@ -63,19 +63,19 @@ def test_given_fiveg_n4_relation_when_set_upf_information_then_info_added_to_rel relations=[fiveg_n4_relation], ) - action = scenario.Action( - name="publish-upf-information", - params={ - "relation-id": str(fiveg_n4_relation.relation_id), - "hostname": "upf", - "port": "1234", - }, - ) + params = { + "relation-id": str(fiveg_n4_relation.id), + "hostname": "upf", + "port": "1234", + } - action_output = self.ctx.run_action(action, state_in) + state_out = self.ctx.run( + self.ctx.on.action("publish-upf-information", params=params), state_in + ) - assert action_output.state.relations[0].local_app_data["upf_hostname"] == "upf" - assert action_output.state.relations[0].local_app_data["upf_port"] == "1234" + relation = state_out.get_relation(fiveg_n4_relation.id) + assert relation.local_app_data["upf_hostname"] == "upf" + assert relation.local_app_data["upf_port"] == "1234" def test_given_when_relation_joined_then_fiveg_n4_request_event_emitted( self, @@ -89,7 +89,7 @@ def test_given_when_relation_joined_then_fiveg_n4_request_event_emitted( relations=[fiveg_n4_relation], ) - self.ctx.run(fiveg_n4_relation.joined_event, state_in) + self.ctx.run(self.ctx.on.relation_joined(fiveg_n4_relation), state_in) assert len(self.ctx.emitted_events) == 2 assert isinstance(self.ctx.emitted_events[1], FiveGN4RequestEvent) diff --git a/tests/unit/lib/charms/sdcore_upf/v0/test_fiveg_n4_requirer.py b/tests/unit/lib/charms/sdcore_upf/v0/test_fiveg_n4_requirer.py index e04aff79..a036a990 100644 --- a/tests/unit/lib/charms/sdcore_upf/v0/test_fiveg_n4_requirer.py +++ b/tests/unit/lib/charms/sdcore_upf/v0/test_fiveg_n4_requirer.py @@ -41,7 +41,7 @@ def test_given_upf_hostname_in_relation_data_when_relation_changed_then_fiveg_n4 relations=[fiveg_n4_relation], ) - self.ctx.run(fiveg_n4_relation.changed_event, state_in) + self.ctx.run(self.ctx.on.relation_changed(fiveg_n4_relation), state_in) assert len(self.ctx.emitted_events) == 2 assert isinstance(self.ctx.emitted_events[1], N4AvailableEvent) @@ -59,6 +59,6 @@ def test_given_upf_hostname_not_in_relation_data_when_relation_changed_then_five relations=[fiveg_n4_relation], ) - self.ctx.run(fiveg_n4_relation.changed_event, state_in) + self.ctx.run(self.ctx.on.relation_changed(fiveg_n4_relation), state_in) assert len(self.ctx.emitted_events) == 1 diff --git a/tests/unit/test_charm_bessd_pebble_ready.py b/tests/unit/test_charm_bessd_pebble_ready.py index c74471f0..6c21d8d6 100644 --- a/tests/unit/test_charm_bessd_pebble_ready.py +++ b/tests/unit/test_charm_bessd_pebble_ready.py @@ -22,7 +22,7 @@ def test_given_bessd_container_ready_when_bessd_pebble_ready_then_config_file_is with tempfile.TemporaryDirectory() as temp_file: bessd_config_mount = scenario.Mount( location="/etc/bess/conf/", - src=temp_file, + source=temp_file, ) pfcp_agent_container = scenario.Container( name="pfcp-agent", @@ -30,62 +30,44 @@ def test_given_bessd_container_ready_when_bessd_pebble_ready_then_config_file_is layers={ "pfcp-agent": Layer({"services": {"pfcp-agent": {}}}), }, - service_status={"pfcp-agent": ServiceStatus.ACTIVE}, + service_statuses={"pfcp-agent": ServiceStatus.ACTIVE}, ) bessd_container = scenario.Container( name="bessd", mounts={"config": bessd_config_mount}, can_connect=True, - exec_mock={ - ("ip", "route", "show"): scenario.ExecOutput( + execs={ + scenario.Exec( + command_prefix=["ip", "route", "show"], return_code=0, stdout=f"default via {core_gateway_ip}\n {gnb_subnet} via {access_gateway_ip}", # noqa: E501 - stderr="", ), - ("/opt/bess/bessctl/bessctl", "show", "version"): scenario.ExecOutput( + scenario.Exec( + command_prefix=["/opt/bess/bessctl/bessctl", "show", "version"], return_code=0, - stdout="", - stderr="", ), - ("/opt/bess/bessctl/bessctl", "show", "worker"): scenario.ExecOutput( + scenario.Exec( + command_prefix=["/opt/bess/bessctl/bessctl", "show", "worker"], return_code=0, stdout="RUNNING", - stderr="", - ), - ( - "/opt/bess/bessctl/bessctl", - "show", - "module", - "accessRoutes", - ): scenario.ExecOutput( - return_code=0, - stdout="", - stderr="", ), - ( - "/opt/bess/bessctl/bessctl", - "show", - "module", - "coreRoutes", - ): scenario.ExecOutput( + scenario.Exec( + command_prefix=[ + "/opt/bess/bessctl/bessctl", + "show", + "module", + "accessRoutes", + ], return_code=0, - stdout="", - stderr="", ), - ( - "iptables-legacy", - "--check", - "OUTPUT", - "-p", - "icmp", - "--icmp-type", - "port-unreachable", - "-j", - "DROP", - ): scenario.ExecOutput( + scenario.Exec( + command_prefix=[ + "/opt/bess/bessctl/bessctl", + "show", + "module", + "coreRoutes", + ], return_code=0, - stdout="", - stderr="", ), }, ) @@ -100,7 +82,7 @@ def test_given_bessd_container_ready_when_bessd_pebble_ready_then_config_file_is model=scenario.Model(name="whatever"), ) - self.ctx.run(bessd_container.pebble_ready_event, state_in) + self.ctx.run(self.ctx.on.pebble_ready(bessd_container), state_in) with open("tests/unit/expected_upf.json", "r") as f: expected_upf_config = f.read() @@ -120,7 +102,7 @@ def test_given_config_file_already_written_when_bessd_pebble_ready_then_config_f with tempfile.TemporaryDirectory() as temp_file: bessd_config_mount = scenario.Mount( location="/etc/bess/conf/", - src=temp_file, + source=temp_file, ) pfcp_agent_container = scenario.Container( name="pfcp-agent", @@ -128,62 +110,44 @@ def test_given_config_file_already_written_when_bessd_pebble_ready_then_config_f layers={ "pfcp-agent": Layer({"services": {"pfcp-agent": {}}}), }, - service_status={"pfcp-agent": ServiceStatus.ACTIVE}, + service_statuses={"pfcp-agent": ServiceStatus.ACTIVE}, ) bessd_container = scenario.Container( name="bessd", mounts={"config": bessd_config_mount}, can_connect=True, - exec_mock={ - ("ip", "route", "show"): scenario.ExecOutput( + execs={ + scenario.Exec( + command_prefix=["ip", "route", "show"], return_code=0, stdout=f"default via {core_gateway_ip}\n {gnb_subnet} via {access_gateway_ip}", # noqa: E501 - stderr="", ), - ("/opt/bess/bessctl/bessctl", "show", "version"): scenario.ExecOutput( + scenario.Exec( + command_prefix=["/opt/bess/bessctl/bessctl", "show", "version"], return_code=0, - stdout="", - stderr="", ), - ("/opt/bess/bessctl/bessctl", "show", "worker"): scenario.ExecOutput( + scenario.Exec( + command_prefix=["/opt/bess/bessctl/bessctl", "show", "worker"], return_code=0, stdout="RUNNING", - stderr="", ), - ( - "/opt/bess/bessctl/bessctl", - "show", - "module", - "accessRoutes", - ): scenario.ExecOutput( + scenario.Exec( + command_prefix=[ + "/opt/bess/bessctl/bessctl", + "show", + "module", + "accessRoutes", + ], return_code=0, - stdout="", - stderr="", ), - ( - "/opt/bess/bessctl/bessctl", - "show", - "module", - "coreRoutes", - ): scenario.ExecOutput( + scenario.Exec( + command_prefix=[ + "/opt/bess/bessctl/bessctl", + "show", + "module", + "coreRoutes", + ], return_code=0, - stdout="", - stderr="", - ), - ( - "iptables-legacy", - "--check", - "OUTPUT", - "-p", - "icmp", - "--icmp-type", - "port-unreachable", - "-j", - "DROP", - ): scenario.ExecOutput( - return_code=0, - stdout="", - stderr="", ), }, ) @@ -203,7 +167,7 @@ def test_given_config_file_already_written_when_bessd_pebble_ready_then_config_f f.write(expected_upf_config.strip()) config_modification_time = os.stat(f"{temp_file}/upf.json").st_mtime - self.ctx.run(bessd_container.pebble_ready_event, state_in) + self.ctx.run(self.ctx.on.pebble_ready(bessd_container), state_in) with open(f"{temp_file}/upf.json", "r") as f: actual_upf_config = f.read() @@ -220,7 +184,7 @@ def test_given_bessd_container_ready_when_bessd_pebble_ready_then_pebble_layer_i with tempfile.TemporaryDirectory() as temp_file: bessd_config_mount = scenario.Mount( location="/etc/bess/conf/", - src=temp_file, + source=temp_file, ) pfcp_agent_container = scenario.Container( name="pfcp-agent", @@ -228,62 +192,44 @@ def test_given_bessd_container_ready_when_bessd_pebble_ready_then_pebble_layer_i layers={ "pfcp-agent": Layer({"services": {"pfcp-agent": {}}}), }, - service_status={"pfcp-agent": ServiceStatus.ACTIVE}, + service_statuses={"pfcp-agent": ServiceStatus.ACTIVE}, ) bessd_container = scenario.Container( name="bessd", mounts={"config": bessd_config_mount}, can_connect=True, - exec_mock={ - ("ip", "route", "show"): scenario.ExecOutput( + execs={ + scenario.Exec( + command_prefix=["ip", "route", "show"], return_code=0, stdout=f"default via {core_gateway_ip}\n {gnb_subnet} via {access_gateway_ip}", # noqa: E501 - stderr="", ), - ("/opt/bess/bessctl/bessctl", "show", "version"): scenario.ExecOutput( + scenario.Exec( + command_prefix=["/opt/bess/bessctl/bessctl", "show", "version"], return_code=0, - stdout="", - stderr="", ), - ("/opt/bess/bessctl/bessctl", "show", "worker"): scenario.ExecOutput( + scenario.Exec( + command_prefix=["/opt/bess/bessctl/bessctl", "show", "worker"], return_code=0, stdout="RUNNING", - stderr="", - ), - ( - "/opt/bess/bessctl/bessctl", - "show", - "module", - "accessRoutes", - ): scenario.ExecOutput( - return_code=0, - stdout="", - stderr="", ), - ( - "/opt/bess/bessctl/bessctl", - "show", - "module", - "coreRoutes", - ): scenario.ExecOutput( + scenario.Exec( + command_prefix=[ + "/opt/bess/bessctl/bessctl", + "show", + "module", + "accessRoutes", + ], return_code=0, - stdout="", - stderr="", ), - ( - "iptables-legacy", - "--check", - "OUTPUT", - "-p", - "icmp", - "--icmp-type", - "port-unreachable", - "-j", - "DROP", - ): scenario.ExecOutput( + scenario.Exec( + command_prefix=[ + "/opt/bess/bessctl/bessctl", + "show", + "module", + "coreRoutes", + ], return_code=0, - stdout="", - stderr="", ), }, ) @@ -297,9 +243,10 @@ def test_given_bessd_container_ready_when_bessd_pebble_ready_then_pebble_layer_i }, ) - state_out = self.ctx.run(bessd_container.pebble_ready_event, state_in) + state_out = self.ctx.run(self.ctx.on.pebble_ready(bessd_container), state_in) - assert state_out.containers[0].layers == { + container = state_out.get_container("bessd") + assert container.layers == { "bessd": Layer( { "summary": "bessd layer", @@ -353,7 +300,7 @@ def test_given_bessd_not_configured_when_bessd_pebble_ready_then_bessd_configure with tempfile.TemporaryDirectory() as temp_file: bessd_config_mount = scenario.Mount( location="/etc/bess/conf/", - src=temp_file, + source=temp_file, ) pfcp_agent_container = scenario.Container( name="pfcp-agent", @@ -361,51 +308,25 @@ def test_given_bessd_not_configured_when_bessd_pebble_ready_then_bessd_configure layers={ "pfcp-agent": Layer({"services": {"pfcp-agent": {}}}), }, - service_status={"pfcp-agent": ServiceStatus.ACTIVE}, + service_statuses={"pfcp-agent": ServiceStatus.ACTIVE}, ) bessd_container = scenario.Container( name="bessd", mounts={"config": bessd_config_mount}, can_connect=True, - exec_mock={ - ("ip", "route", "show"): scenario.ExecOutput( - return_code=0, - stdout=f"default via {core_gateway_ip}\n {gnb_subnet} via {access_gateway_ip}", # noqa: E501 - stderr="", - ), - ("/opt/bess/bessctl/bessctl", "show", "version"): scenario.ExecOutput( + execs={ + scenario.Exec( + command_prefix=["/opt/bess/bessctl/bessctl", "show", "version"], return_code=0, - stdout="", - stderr="", ), - ("/opt/bess/bessctl/bessctl", "show", "worker"): scenario.ExecOutput( + scenario.Exec( + command_prefix=[ + "/opt/bess/bessctl/bessctl", + "run", + "/opt/bess/bessctl/conf/up4", + ], return_code=0, stdout="", - stderr="", - ), - ( - "iptables-legacy", - "--check", - "OUTPUT", - "-p", - "icmp", - "--icmp-type", - "port-unreachable", - "-j", - "DROP", - ): scenario.ExecOutput( - return_code=0, - stdout="", - stderr="", - ), - ( - "/opt/bess/bessctl/bessctl", - "run", - "/opt/bess/bessctl/conf/up4", - ): scenario.ExecOutput( - return_code=0, - stdout="whatever command output", - stderr="", ), }, ) @@ -419,12 +340,13 @@ def test_given_bessd_not_configured_when_bessd_pebble_ready_then_bessd_configure }, ) - self.ctx.run(bessd_container.pebble_ready_event, state_in) + self.ctx.run(self.ctx.on.pebble_ready(bessd_container), state_in) - # When scenario 7 is out, we should assert that the mock exec was called - # instead of validating log content - # Reference: https://github.com/canonical/ops-scenario/issues/180 - assert "whatever command output" in caplog.text + assert self.ctx.exec_history[bessd_container.name][1].command == [ + "/opt/bess/bessctl/bessctl", + "run", + "/opt/bess/bessctl/conf/up4", + ] def test_given_routes_not_created_when_bessd_pebble_ready_then_routes_created(self, caplog): gnb_subnet = "2.2.2.0/24" @@ -434,7 +356,7 @@ def test_given_routes_not_created_when_bessd_pebble_ready_then_routes_created(se with tempfile.TemporaryDirectory() as temp_file: bessd_config_mount = scenario.Mount( location="/etc/bess/conf/", - src=temp_file, + source=temp_file, ) pfcp_agent_container = scenario.Container( name="pfcp-agent", @@ -442,88 +364,45 @@ def test_given_routes_not_created_when_bessd_pebble_ready_then_routes_created(se layers={ "pfcp-agent": Layer({"services": {"pfcp-agent": {}}}), }, - service_status={"pfcp-agent": ServiceStatus.ACTIVE}, + service_statuses={"pfcp-agent": ServiceStatus.ACTIVE}, ) bessd_container = scenario.Container( name="bessd", mounts={"config": bessd_config_mount}, can_connect=True, - exec_mock={ - ("ip", "route", "show"): scenario.ExecOutput( + execs={ + scenario.Exec( + command_prefix=["ip", "route", "show"], return_code=0, stdout="", # route not created - stderr="", - ), - ("/opt/bess/bessctl/bessctl", "show", "version"): scenario.ExecOutput( - return_code=0, - stdout="", - stderr="", ), - ("/opt/bess/bessctl/bessctl", "show", "worker"): scenario.ExecOutput( + scenario.Exec( + command_prefix=["/opt/bess/bessctl/bessctl", "show", "version"], return_code=0, - stdout="RUNNING", - stderr="", - ), - ( - "iptables-legacy", - "--check", - "OUTPUT", - "-p", - "icmp", - "--icmp-type", - "port-unreachable", - "-j", - "DROP", - ): scenario.ExecOutput( - return_code=0, - stdout="", - stderr="", ), - ( - "/opt/bess/bessctl/bessctl", - "show", - "module", - "accessRoutes", - ): scenario.ExecOutput( + scenario.Exec( + command_prefix=[ + "ip", + "route", + "replace", + "default", + "via", + core_gateway_ip, + "metric", + "110", + ], return_code=0, - stdout="", - stderr="", ), - ( - "/opt/bess/bessctl/bessctl", - "show", - "module", - "coreRoutes", - ): scenario.ExecOutput( + scenario.Exec( + command_prefix=[ + "ip", + "route", + "replace", + gnb_subnet, + "via", + access_gateway_ip, + ], return_code=0, - stdout="", - stderr="", - ), - ( - "ip", - "route", - "replace", - "default", - "via", - core_gateway_ip, - "metric", - "110", - ): scenario.ExecOutput( - return_code=0, - stdout="", - stderr="", - ), - ( - "ip", - "route", - "replace", - gnb_subnet, - "via", - access_gateway_ip, - ): scenario.ExecOutput( - return_code=0, - stdout="", - stderr="", ), }, ) @@ -537,16 +416,29 @@ def test_given_routes_not_created_when_bessd_pebble_ready_then_routes_created(se }, ) - self.ctx.run(bessd_container.pebble_ready_event, state_in) + self.ctx.run(self.ctx.on.pebble_ready(bessd_container), state_in) - # When scenario 7 is out, we should assert that the mock exec was called - # instead of validating log content - # Reference: https://github.com/canonical/ops-scenario/issues/180 - assert "Default core network route created" in caplog.text - assert "Route to gnb-subnet created" in caplog.text + assert self.ctx.exec_history[bessd_container.name][1].command == [ + "ip", + "route", + "replace", + "default", + "via", + core_gateway_ip, + "metric", + "110", + ] + assert self.ctx.exec_history[bessd_container.name][3].command == [ + "ip", + "route", + "replace", + gnb_subnet, + "via", + access_gateway_ip, + ] def test_given_iptables_rule_not_created_when_bessd_pebble_ready_then_rule_created( - self, caplog + self, ): gnb_subnet = "2.2.2.0/24" core_gateway_ip = "1.2.3.4" @@ -555,7 +447,7 @@ def test_given_iptables_rule_not_created_when_bessd_pebble_ready_then_rule_creat with tempfile.TemporaryDirectory() as temp_file: bessd_config_mount = scenario.Mount( location="/etc/bess/conf/", - src=temp_file, + source=temp_file, ) pfcp_agent_container = scenario.Container( name="pfcp-agent", @@ -563,77 +455,30 @@ def test_given_iptables_rule_not_created_when_bessd_pebble_ready_then_rule_creat layers={ "pfcp-agent": Layer({"services": {"pfcp-agent": {}}}), }, - service_status={"pfcp-agent": ServiceStatus.ACTIVE}, + service_statuses={"pfcp-agent": ServiceStatus.ACTIVE}, ) bessd_container = scenario.Container( name="bessd", mounts={"config": bessd_config_mount}, can_connect=True, - exec_mock={ - ("ip", "route", "show"): scenario.ExecOutput( - return_code=0, - stdout=f"default via {core_gateway_ip}\n {gnb_subnet} via {access_gateway_ip}", # noqa: E501 - stderr="", - ), - ("/opt/bess/bessctl/bessctl", "show", "version"): scenario.ExecOutput( - return_code=0, - stdout="", - stderr="", - ), - ("/opt/bess/bessctl/bessctl", "show", "worker"): scenario.ExecOutput( + execs={ + scenario.Exec( + command_prefix=["/opt/bess/bessctl/bessctl", "show", "version"], return_code=0, - stdout="RUNNING", - stderr="", - ), - ( - "iptables-legacy", - "--check", - "OUTPUT", - "-p", - "icmp", - "--icmp-type", - "port-unreachable", - "-j", - "DROP", - ): scenario.ExecOutput( - return_code=1, # rule not created - stdout="", - stderr="", ), - ( - "/opt/bess/bessctl/bessctl", - "show", - "module", - "accessRoutes", - ): scenario.ExecOutput( + scenario.Exec( + command_prefix=[ + "iptables-legacy", + "-I", + "OUTPUT", + "-p", + "icmp", + "--icmp-type", + "port-unreachable", + "-j", + "DROP", + ], return_code=0, - stdout="", - stderr="", - ), - ( - "/opt/bess/bessctl/bessctl", - "show", - "module", - "coreRoutes", - ): scenario.ExecOutput( - return_code=0, - stdout="", - stderr="", - ), - ( - "iptables-legacy", - "-I", - "OUTPUT", - "-p", - "icmp", - "--icmp-type", - "port-unreachable", - "-j", - "DROP", - ): scenario.ExecOutput( - return_code=0, - stdout="", - stderr="", ), }, ) @@ -647,9 +492,16 @@ def test_given_iptables_rule_not_created_when_bessd_pebble_ready_then_rule_creat }, ) - self.ctx.run(bessd_container.pebble_ready_event, state_in) + self.ctx.run(self.ctx.on.pebble_ready(bessd_container), state_in) - # When scenario 7 is out, we should assert that the mock exec was called - # instead of validating log content - # Reference: https://github.com/canonical/ops-scenario/issues/180 - assert "Iptables rule for ICMP created" in caplog.text + assert self.ctx.exec_history[bessd_container.name][0].command == [ + "iptables-legacy", + "-I", + "OUTPUT", + "-p", + "icmp", + "--icmp-type", + "port-unreachable", + "-j", + "DROP", + ] diff --git a/tests/unit/test_charm_collect_status.py b/tests/unit/test_charm_collect_status.py index 88a174ed..7fcb895f 100644 --- a/tests/unit/test_charm_collect_status.py +++ b/tests/unit/test_charm_collect_status.py @@ -19,7 +19,7 @@ def test_given_unit_not_leader_when_collect_unit_status_then_status_is_blocked( leader=False, ) - state_out = self.ctx.run("collect_unit_status", state_in) + state_out = self.ctx.run(self.ctx.on.collect_unit_status(), state_in) assert state_out.unit_status == BlockedStatus("Scaling is not implemented for this charm") @@ -57,7 +57,7 @@ def test_given_invalid_config_when_collect_unit_status_then_status_is_blocked( }, ) - state_out = self.ctx.run("collect_unit_status", state_in) + state_out = self.ctx.run(self.ctx.on.collect_unit_status(), state_in) assert state_out.unit_status == BlockedStatus( f"The following configurations are not valid: ['{config_param}']" @@ -71,7 +71,7 @@ def test_given_upf_mode_set_to_dpdk_and_hugepages_enabled_but_mac_addresses_of_a config={"upf-mode": "dpdk"}, ) - state_out = self.ctx.run("collect_unit_status", state_in) + state_out = self.ctx.run(self.ctx.on.collect_unit_status(), state_in) assert state_out.unit_status == BlockedStatus( "The following configurations are not valid: ['access-interface-mac-address', 'core-interface-mac-address']" # noqa: E501 @@ -85,7 +85,7 @@ def test_given_cpu_incompatible_when_collect_unit_status_then_status_is_blocked( leader=True, ) - state_out = self.ctx.run("collect_unit_status", state_in) + state_out = self.ctx.run(self.ctx.on.collect_unit_status(), state_in) assert state_out.unit_status == BlockedStatus( "CPU is not compatible, see logs for more details" @@ -105,7 +105,7 @@ def test_given_hugepages_unavailable_when_collect_unit_status_then_status_is_blo }, ) - state_out = self.ctx.run("collect_unit_status", state_in) + state_out = self.ctx.run(self.ctx.on.collect_unit_status(), state_in) assert state_out.unit_status == BlockedStatus("Not enough HugePages available") @@ -118,7 +118,7 @@ def test_given_multus_not_available_when_collect_unit_status_then_status_is_bloc config={}, ) - state_out = self.ctx.run("collect_unit_status", state_in) + state_out = self.ctx.run(self.ctx.on.collect_unit_status(), state_in) assert state_out.unit_status == BlockedStatus("Multus is not installed or enabled") @@ -137,7 +137,7 @@ def test_given_cant_connect_to_bessd_container_when_collect_unit_status_then_sta containers=[bessd_container], ) - state_out = self.ctx.run("collect_unit_status", state_in) + state_out = self.ctx.run(self.ctx.on.collect_unit_status(), state_in) assert state_out.unit_status == WaitingStatus("Waiting for bessd container to be ready") @@ -155,7 +155,7 @@ def test_given_multus_not_ready_when_collect_unit_status_then_status_is_waiting( containers=[bessd_container], ) - state_out = self.ctx.run("collect_unit_status", state_in) + state_out = self.ctx.run(self.ctx.on.collect_unit_status(), state_in) assert state_out.unit_status == WaitingStatus("Waiting for Multus to be ready") @@ -167,12 +167,12 @@ def test_given_default_route_not_created_when_collect_unit_status_then_status_is bessd_container = scenario.Container( name="bessd", can_connect=True, - exec_mock={ - ("ip", "route", "show"): scenario.ExecOutput( + execs={ + scenario.Exec( + command_prefix=["ip", "route", "show"], return_code=0, stdout="", - stderr="", - ) + ), }, ) state_in = scenario.State( @@ -180,7 +180,7 @@ def test_given_default_route_not_created_when_collect_unit_status_then_status_is containers=[bessd_container], ) - state_out = self.ctx.run("collect_unit_status", state_in) + state_out = self.ctx.run(self.ctx.on.collect_unit_status(), state_in) assert state_out.unit_status == WaitingStatus("Waiting for default route creation") @@ -193,12 +193,12 @@ def test_given_gnb_route_not_created_when_collect_unit_status_then_status_is_wai bessd_container = scenario.Container( name="bessd", can_connect=True, - exec_mock={ - ("ip", "route", "show"): scenario.ExecOutput( + execs={ + scenario.Exec( + command_prefix=["ip", "route", "show"], return_code=0, stdout=f"default via {core_gateway_ip}", - stderr="", - ) + ), }, ) state_in = scenario.State( @@ -210,7 +210,7 @@ def test_given_gnb_route_not_created_when_collect_unit_status_then_status_is_wai }, ) - state_out = self.ctx.run("collect_unit_status", state_in) + state_out = self.ctx.run(self.ctx.on.collect_unit_status(), state_in) assert state_out.unit_status == WaitingStatus("Waiting for RAN route creation") @@ -225,12 +225,12 @@ def test_given_storage_not_attached_when_collect_unit_status_then_status_is_wait bessd_container = scenario.Container( name="bessd", can_connect=True, - exec_mock={ - ("ip", "route", "show"): scenario.ExecOutput( + execs={ + scenario.Exec( + command_prefix=["ip", "route", "show"], return_code=0, stdout=f"default via {core_gateway_ip}\n {gnb_subnet} via {access_gateway_ip}", - stderr="", - ) + ), }, ) state_in = scenario.State( @@ -243,7 +243,7 @@ def test_given_storage_not_attached_when_collect_unit_status_then_status_is_wait }, ) - state_out = self.ctx.run("collect_unit_status", state_in) + state_out = self.ctx.run(self.ctx.on.collect_unit_status(), state_in) assert state_out.unit_status == WaitingStatus("Waiting for storage to be attached") @@ -258,7 +258,7 @@ def test_given_bessd_service_not_running_when_collect_unit_status_then_status_is with tempfile.TemporaryDirectory() as temp_file: bessd_config_mount = scenario.Mount( location="/etc/bess/conf/", - src=temp_file, + source=temp_file, ) bessd_container = scenario.Container( name="bessd", @@ -266,12 +266,12 @@ def test_given_bessd_service_not_running_when_collect_unit_status_then_status_is mounts={ "config": bessd_config_mount, }, - exec_mock={ - ("ip", "route", "show"): scenario.ExecOutput( + execs={ + scenario.Exec( + command_prefix=["ip", "route", "show"], return_code=0, stdout=f"default via {core_gateway_ip}\n {gnb_subnet} via {access_gateway_ip}", # noqa: E501 - stderr="", - ) + ), }, ) state_in = scenario.State( @@ -284,7 +284,7 @@ def test_given_bessd_service_not_running_when_collect_unit_status_then_status_is }, ) - state_out = self.ctx.run("collect_unit_status", state_in) + state_out = self.ctx.run(self.ctx.on.collect_unit_status(), state_in) assert state_out.unit_status == WaitingStatus("Waiting for bessd service to run") @@ -299,7 +299,7 @@ def test_given_grpc_service_not_ready_when_collect_unit_status_then_status_is_wa with tempfile.TemporaryDirectory() as temp_file: bessd_config_mount = scenario.Mount( location="/etc/bess/conf/", - src=temp_file, + source=temp_file, ) bessd_container = scenario.Container( name="bessd", @@ -308,17 +308,16 @@ def test_given_grpc_service_not_ready_when_collect_unit_status_then_status_is_wa "config": bessd_config_mount, }, layers={"bessd": Layer({"services": {"bessd": {}}})}, - service_status={"bessd": ServiceStatus.ACTIVE}, - exec_mock={ - ("ip", "route", "show"): scenario.ExecOutput( + service_statuses={"bessd": ServiceStatus.ACTIVE}, + execs={ + scenario.Exec( + command_prefix=["ip", "route", "show"], return_code=0, stdout=f"default via {core_gateway_ip}\n {gnb_subnet} via {access_gateway_ip}", # noqa: E501 - stderr="", ), - ("/opt/bess/bessctl/bessctl", "show", "version"): scenario.ExecOutput( + scenario.Exec( + command_prefix=["/opt/bess/bessctl/bessctl", "show", "version"], return_code=1, - stdout="", - stderr="", ), }, ) @@ -332,7 +331,7 @@ def test_given_grpc_service_not_ready_when_collect_unit_status_then_status_is_wa }, ) - state_out = self.ctx.run("collect_unit_status", state_in) + state_out = self.ctx.run(self.ctx.on.collect_unit_status(), state_in) assert state_out.unit_status == WaitingStatus( "Waiting for bessd service to accept configuration messages" @@ -349,7 +348,7 @@ def test_given_bessd_not_configured_when_collect_unit_status_then_status_is_wait with tempfile.TemporaryDirectory() as temp_file: bessd_config_mount = scenario.Mount( location="/etc/bess/conf/", - src=temp_file, + source=temp_file, ) bessd_container = scenario.Container( name="bessd", @@ -358,22 +357,20 @@ def test_given_bessd_not_configured_when_collect_unit_status_then_status_is_wait "config": bessd_config_mount, }, layers={"bessd": Layer({"services": {"bessd": {}}})}, - service_status={"bessd": ServiceStatus.ACTIVE}, - exec_mock={ - ("ip", "route", "show"): scenario.ExecOutput( + service_statuses={"bessd": ServiceStatus.ACTIVE}, + execs={ + scenario.Exec( + command_prefix=["ip", "route", "show"], return_code=0, stdout=f"default via {core_gateway_ip}\n {gnb_subnet} via {access_gateway_ip}", # noqa: E501 - stderr="", ), - ("/opt/bess/bessctl/bessctl", "show", "version"): scenario.ExecOutput( + scenario.Exec( + command_prefix=["/opt/bess/bessctl/bessctl", "show", "version"], return_code=0, - stdout="", - stderr="", ), - ("/opt/bess/bessctl/bessctl", "show", "worker"): scenario.ExecOutput( + scenario.Exec( + command_prefix=["/opt/bess/bessctl/bessctl", "show", "worker"], return_code=1, - stdout="", - stderr="", ), }, ) @@ -387,7 +384,7 @@ def test_given_bessd_not_configured_when_collect_unit_status_then_status_is_wait }, ) - state_out = self.ctx.run("collect_unit_status", state_in) + state_out = self.ctx.run(self.ctx.on.collect_unit_status(), state_in) assert state_out.unit_status == WaitingStatus( "Waiting for bessd configuration to complete" @@ -406,7 +403,7 @@ def test_given_routectl_service_not_running_when_collect_unit_status_then_status with tempfile.TemporaryDirectory() as temp_file: bessd_config_mount = scenario.Mount( location="/etc/bess/conf/", - src=temp_file, + source=temp_file, ) bessd_container = scenario.Container( name="bessd", @@ -415,42 +412,39 @@ def test_given_routectl_service_not_running_when_collect_unit_status_then_status "config": bessd_config_mount, }, layers={"bessd": Layer({"services": {"bessd": {}}})}, - service_status={"bessd": ServiceStatus.ACTIVE}, - exec_mock={ - ("ip", "route", "show"): scenario.ExecOutput( + service_statuses={"bessd": ServiceStatus.ACTIVE}, + execs={ + scenario.Exec( + command_prefix=["ip", "route", "show"], return_code=0, stdout=f"default via {core_gateway_ip}\n {gnb_subnet} via {access_gateway_ip}", # noqa: E501 - stderr="", ), - ("/opt/bess/bessctl/bessctl", "show", "version"): scenario.ExecOutput( + scenario.Exec( + command_prefix=["/opt/bess/bessctl/bessctl", "show", "version"], return_code=0, - stdout="", - stderr="", ), - ("/opt/bess/bessctl/bessctl", "show", "worker"): scenario.ExecOutput( + scenario.Exec( + command_prefix=["/opt/bess/bessctl/bessctl", "show", "worker"], return_code=0, stdout="RUNNING", - stderr="", ), - ( - "/opt/bess/bessctl/bessctl", - "show", - "module", - "accessRoutes", - ): scenario.ExecOutput( + scenario.Exec( + command_prefix=[ + "/opt/bess/bessctl/bessctl", + "show", + "module", + "accessRoutes", + ], return_code=0, - stdout="", - stderr="", ), - ( - "/opt/bess/bessctl/bessctl", - "show", - "module", - "coreRoutes", - ): scenario.ExecOutput( + scenario.Exec( + command_prefix=[ + "/opt/bess/bessctl/bessctl", + "show", + "module", + "coreRoutes", + ], return_code=0, - stdout="", - stderr="", ), }, ) @@ -464,7 +458,7 @@ def test_given_routectl_service_not_running_when_collect_unit_status_then_status }, ) - state_out = self.ctx.run("collect_unit_status", state_in) + state_out = self.ctx.run(self.ctx.on.collect_unit_status(), state_in) assert state_out.unit_status == WaitingStatus("Waiting for routectl service to run") @@ -479,7 +473,7 @@ def test_given_pfcp_service_not_running_when_collect_unit_status_then_status_is_ with tempfile.TemporaryDirectory() as temp_file: bessd_config_mount = scenario.Mount( location="/etc/bess/conf/", - src=temp_file, + source=temp_file, ) pfcp_agent_container = scenario.Container( name="pfcp-agent", @@ -494,42 +488,39 @@ def test_given_pfcp_service_not_running_when_collect_unit_status_then_status_is_ layers={ "bessd": Layer({"services": {"bessd": {}, "routectl": {}}}), }, - service_status={"bessd": ServiceStatus.ACTIVE, "routectl": ServiceStatus.ACTIVE}, - exec_mock={ - ("ip", "route", "show"): scenario.ExecOutput( + service_statuses={"bessd": ServiceStatus.ACTIVE, "routectl": ServiceStatus.ACTIVE}, + execs={ + scenario.Exec( + command_prefix=["ip", "route", "show"], return_code=0, stdout=f"default via {core_gateway_ip}\n {gnb_subnet} via {access_gateway_ip}", # noqa: E501 - stderr="", ), - ("/opt/bess/bessctl/bessctl", "show", "version"): scenario.ExecOutput( + scenario.Exec( + command_prefix=["/opt/bess/bessctl/bessctl", "show", "version"], return_code=0, - stdout="", - stderr="", ), - ("/opt/bess/bessctl/bessctl", "show", "worker"): scenario.ExecOutput( + scenario.Exec( + command_prefix=["/opt/bess/bessctl/bessctl", "show", "worker"], return_code=0, stdout="RUNNING", - stderr="", ), - ( - "/opt/bess/bessctl/bessctl", - "show", - "module", - "accessRoutes", - ): scenario.ExecOutput( + scenario.Exec( + command_prefix=[ + "/opt/bess/bessctl/bessctl", + "show", + "module", + "accessRoutes", + ], return_code=0, - stdout="", - stderr="", ), - ( - "/opt/bess/bessctl/bessctl", - "show", - "module", - "coreRoutes", - ): scenario.ExecOutput( + scenario.Exec( + command_prefix=[ + "/opt/bess/bessctl/bessctl", + "show", + "module", + "coreRoutes", + ], return_code=0, - stdout="", - stderr="", ), }, ) @@ -543,7 +534,7 @@ def test_given_pfcp_service_not_running_when_collect_unit_status_then_status_is_ }, ) - state_out = self.ctx.run("collect_unit_status", state_in) + state_out = self.ctx.run(self.ctx.on.collect_unit_status(), state_in) assert state_out.unit_status == WaitingStatus("Waiting for pfcp agent service to run") @@ -558,7 +549,7 @@ def test_given_services_are_running_when_collect_unit_status_then_status_is_wait with tempfile.TemporaryDirectory() as temp_file: bessd_config_mount = scenario.Mount( location="/etc/bess/conf/", - src=temp_file, + source=temp_file, ) pfcp_agent_container = scenario.Container( name="pfcp-agent", @@ -566,7 +557,7 @@ def test_given_services_are_running_when_collect_unit_status_then_status_is_wait layers={ "pfcp-agent": Layer({"services": {"pfcp-agent": {}}}), }, - service_status={"pfcp-agent": ServiceStatus.ACTIVE}, + service_statuses={"pfcp-agent": ServiceStatus.ACTIVE}, ) bessd_container = scenario.Container( name="bessd", @@ -577,42 +568,39 @@ def test_given_services_are_running_when_collect_unit_status_then_status_is_wait layers={ "bessd": Layer({"services": {"bessd": {}, "routectl": {}}}), }, - service_status={"bessd": ServiceStatus.ACTIVE, "routectl": ServiceStatus.ACTIVE}, - exec_mock={ - ("ip", "route", "show"): scenario.ExecOutput( + service_statuses={"bessd": ServiceStatus.ACTIVE, "routectl": ServiceStatus.ACTIVE}, + execs={ + scenario.Exec( + command_prefix=["ip", "route", "show"], return_code=0, stdout=f"default via {core_gateway_ip}\n {gnb_subnet} via {access_gateway_ip}", # noqa: E501 - stderr="", ), - ("/opt/bess/bessctl/bessctl", "show", "version"): scenario.ExecOutput( + scenario.Exec( + command_prefix=["/opt/bess/bessctl/bessctl", "show", "version"], return_code=0, - stdout="", - stderr="", ), - ("/opt/bess/bessctl/bessctl", "show", "worker"): scenario.ExecOutput( + scenario.Exec( + command_prefix=["/opt/bess/bessctl/bessctl", "show", "worker"], return_code=0, stdout="RUNNING", - stderr="", ), - ( - "/opt/bess/bessctl/bessctl", - "show", - "module", - "accessRoutes", - ): scenario.ExecOutput( + scenario.Exec( + command_prefix=[ + "/opt/bess/bessctl/bessctl", + "show", + "module", + "accessRoutes", + ], return_code=0, - stdout="", - stderr="", ), - ( - "/opt/bess/bessctl/bessctl", - "show", - "module", - "coreRoutes", - ): scenario.ExecOutput( + scenario.Exec( + command_prefix=[ + "/opt/bess/bessctl/bessctl", + "show", + "module", + "coreRoutes", + ], return_code=0, - stdout="", - stderr="", ), }, ) @@ -626,7 +614,7 @@ def test_given_services_are_running_when_collect_unit_status_then_status_is_wait }, ) - state_out = self.ctx.run("collect_unit_status", state_in) + state_out = self.ctx.run(self.ctx.on.collect_unit_status(), state_in) assert state_out.unit_status == ActiveStatus() @@ -647,7 +635,7 @@ def test_given_no_workload_version_when_collect_unit_status_then_workload_versio containers=[bessd_container], ) - state_out = self.ctx.run("collect_unit_status", state_in) + state_out = self.ctx.run(self.ctx.on.collect_unit_status(), state_in) assert state_out.workload_version == "" @@ -662,7 +650,7 @@ def test_given_workload_version_file_when_collect_unit_status_then_workload_vers with tempfile.TemporaryDirectory() as temp_file: workload_version_mount = scenario.Mount( location="/etc", - src=temp_file, + source=temp_file, ) bessd_container = scenario.Container( @@ -677,6 +665,6 @@ def test_given_workload_version_file_when_collect_unit_status_then_workload_vers with open(f"{temp_file}/workload-version", "w") as f: f.write("1.2.3") - state_out = self.ctx.run("collect_unit_status", state_in) + state_out = self.ctx.run(self.ctx.on.collect_unit_status(), state_in) assert state_out.workload_version == "1.2.3" diff --git a/tests/unit/test_charm_config_changed.py b/tests/unit/test_charm_config_changed.py index 448ef2a9..51eed939 100644 --- a/tests/unit/test_charm_config_changed.py +++ b/tests/unit/test_charm_config_changed.py @@ -29,7 +29,7 @@ def test_given_dpdk_when_config_changed_then_bessd_configured_for_dpdk( }, ) - self.ctx.run("config_changed", state_in) + self.ctx.run(self.ctx.on.config_changed(), state_in) self.mock_dpdk.configure.assert_called_once_with(container_name="bessd") @@ -41,13 +41,6 @@ def test_given_n3_integration_when_config_changed_then_n3_information_published( bessd_container = scenario.Container( name="bessd", can_connect=True, - exec_mock={ - ("ip", "route", "show"): scenario.ExecOutput( - return_code=0, - stdout="", - stderr="", - ), - }, ) n3_relation = scenario.Relation( endpoint="fiveg_n3", @@ -61,10 +54,10 @@ def test_given_n3_integration_when_config_changed_then_n3_information_published( config={"access-ip": "1.2.3.4"}, ) - self.ctx.run("config_changed", state_in) + self.ctx.run(self.ctx.on.config_changed(), state_in) self.mock_n3_provides_publish_upf_information.assert_called_once_with( - relation_id=n3_relation.relation_id, + relation_id=n3_relation.id, upf_ip_address="1.2.3.4", ) @@ -77,13 +70,6 @@ def test_given_n4_integration_when_config_changed_then_n4_information_published( bessd_container = scenario.Container( name="bessd", can_connect=True, - exec_mock={ - ("ip", "route", "show"): scenario.ExecOutput( - return_code=0, - stdout="", - stderr="", - ), - }, ) n4_relation = scenario.Relation( endpoint="fiveg_n4", @@ -96,10 +82,10 @@ def test_given_n4_integration_when_config_changed_then_n4_information_published( relations=[n4_relation], ) - self.ctx.run("config_changed", state_in) + self.ctx.run(self.ctx.on.config_changed(), state_in) self.mock_n4_provides_publish_upf_information.assert_called_once_with( - relation_id=n4_relation.relation_id, + relation_id=n4_relation.id, upf_hostname="my-hostname", upf_n4_port=8805, ) diff --git a/tests/unit/test_charm_pfcp_agent_pebble_ready.py b/tests/unit/test_charm_pfcp_agent_pebble_ready.py index f7aedd4d..6b8b0009 100644 --- a/tests/unit/test_charm_pfcp_agent_pebble_ready.py +++ b/tests/unit/test_charm_pfcp_agent_pebble_ready.py @@ -26,44 +26,7 @@ def test_given_pfcp_agent_container_ready_when_pfcp_agent_pebble_ready_then_pebb bessd_container = scenario.Container( name="bessd", can_connect=True, - service_status={"bessd": ServiceStatus.ACTIVE}, - exec_mock={ - ("ip", "route", "show"): scenario.ExecOutput( - return_code=0, - stdout=f"default via {core_gateway_ip}\n {gnb_subnet} via {access_gateway_ip}", # noqa: E501 - stderr="", - ), - ("/opt/bess/bessctl/bessctl", "show", "version"): scenario.ExecOutput( - return_code=0, - stdout="", - stderr="", - ), - ("/opt/bess/bessctl/bessctl", "show", "worker"): scenario.ExecOutput( - return_code=0, - stdout="RUNNING", - stderr="", - ), - ( - "/opt/bess/bessctl/bessctl", - "show", - "module", - "accessRoutes", - ): scenario.ExecOutput( - return_code=0, - stdout="", - stderr="", - ), - ( - "/opt/bess/bessctl/bessctl", - "show", - "module", - "coreRoutes", - ): scenario.ExecOutput( - return_code=0, - stdout="", - stderr="", - ), - }, + service_statuses={"bessd": ServiceStatus.ACTIVE}, layers={ "bessd": Layer( { @@ -83,9 +46,10 @@ def test_given_pfcp_agent_container_ready_when_pfcp_agent_pebble_ready_then_pebb }, ) - state_out = self.ctx.run(pfcp_agent_container.pebble_ready_event, state_in) + state_out = self.ctx.run(self.ctx.on.pebble_ready(pfcp_agent_container), state_in) - assert state_out.containers[1].layers == { + container = state_out.get_container("pfcp-agent") + assert container.layers == { "pfcp-agent": Layer({"services": {"pfcp-agent": {}}}), "pfcp": Layer( { diff --git a/tests/unit/test_charm_remove.py b/tests/unit/test_charm_remove.py index 97f50fb9..276205d8 100644 --- a/tests/unit/test_charm_remove.py +++ b/tests/unit/test_charm_remove.py @@ -16,6 +16,6 @@ def test_given_k8s_service_is_created_when_remove_then_service_is_deleted( leader=True, ) - self.ctx.run("remove", state_in) + self.ctx.run(self.ctx.on.remove(), state_in) self.mock_k8s_service.delete.assert_called_once()