diff --git a/packages/packages.json b/packages/packages.json index 75e5077e9..62f487b72 100644 --- a/packages/packages.json +++ b/packages/packages.json @@ -15,15 +15,15 @@ "contract/valory/mech_activity/0.1.0": "bafybeiec6nnvfs6captlncrtjfygpp275vkfajvj4frrnab7thsca6337e", "contract/valory/staking_token/0.1.0": "bafybeig4fl35dn7d5gnprux2nwsqbirm7zkiujz3xvrwcjuktz6hkq4as4", "contract/valory/relayer/0.1.0": "bafybeihzgjyvhtorugjw3yldznqsbwo3aqpxowm7k2nrvj6qtwpsc7jl7u", - "skill/valory/market_manager_abci/0.1.0": "bafybeihuianzp5qrlxysdokrxzjrkt4pkruickdbzew5sngysel5obkwfm", - "skill/valory/decision_maker_abci/0.1.0": "bafybeifrmophhnc3dg6ii57im66wwkvglvec6bew5zqy2rhtrcnsx5vx5i", - "skill/valory/trader_abci/0.1.0": "bafybeihs25eobxugzytyoi7yy7f4srd3pp26dlx7k7jw3majqg4kwv7kti", - "skill/valory/tx_settlement_multiplexer_abci/0.1.0": "bafybeibyf7zwnvjbpk6nca7hj7mj7zxygr4j67jyq2vbk6gs22jwqma7eq", - "skill/valory/staking_abci/0.1.0": "bafybeiafzonb4h4ahn2n5mmbx4vtkckbylbzrxnr2gmrhhltw6xa35d6ve", - "skill/valory/check_stop_trading_abci/0.1.0": "bafybeieyw7kanelhv3dnbd5ypo26ivnyqfg3ueiqt6s4wkvoz3gvfisihe", - "agent/valory/trader/0.1.0": "bafybeia5e322is7dbiaao4x2zjfmiloijqjkffotljodrr2gjjnwb65e74", - "service/valory/trader/0.1.0": "bafybeibmp75hhxzt5w655jvulooiu44ibzrlkzqzp634fzcjzrf6scwlmi", - "service/valory/trader_pearl/0.1.0": "bafybeicffhnw4zj7qwxjanjrneqtwoglgwm4vpcu6drjjsts435tuit3be" + "skill/valory/market_manager_abci/0.1.0": "bafybeiai6djelf6d4dkxgkv46l24q2gz7736b3jdhbxslvcydpvnvrse6e", + "skill/valory/decision_maker_abci/0.1.0": "bafybeigykiciajiq5za7szupck5jbj6z6dvnmoufdam7eyigpn4mr6c6bq", + "skill/valory/trader_abci/0.1.0": "bafybeid23zogdrlauifqprlogztejgb2yl3ohcvqcat7nab2hgvez4bzru", + "skill/valory/tx_settlement_multiplexer_abci/0.1.0": "bafybeidcw2bzonvlgtyuv76zkutjs7qv5j4wgvi6azthqpyefds6i5cvdm", + "skill/valory/staking_abci/0.1.0": "bafybeiduborfqevheegy3plk7bzhkl4fukwixvlb57tenijdepintubbdi", + "skill/valory/check_stop_trading_abci/0.1.0": "bafybeiepylk35n3faurvp7dskjkdovehftzfjrjxfkpekzuaovt5gojxne", + "agent/valory/trader/0.1.0": "bafybeicdbgv3sricq6uafa6ps7rdjvqhelkbqktp5j4i6wzr2eetm4fn74", + "service/valory/trader/0.1.0": "bafybeiamvc7vbylrdgy5topv45bqailxjynxwq7xmhf4q3ly72prxyygqa", + "service/valory/trader_pearl/0.1.0": "bafybeigt6n7qc6mdh7gbdkqpkudm6khi25wks45mup73e45p2tf5vrvh2y" }, "third_party": { "protocol/open_aea/signing/1.0.0": "bafybeihv62fim3wl2bayavfcg3u5e5cxu3b7brtu4cn5xoxd6lqwachasi", diff --git a/packages/valory/agents/trader/aea-config.yaml b/packages/valory/agents/trader/aea-config.yaml index 7970b41f0..041ac7761 100644 --- a/packages/valory/agents/trader/aea-config.yaml +++ b/packages/valory/agents/trader/aea-config.yaml @@ -47,12 +47,12 @@ skills: - valory/reset_pause_abci:0.1.0:bafybeiameewywqigpupy3u2iwnkfczeiiucue74x2l5lbge74rmw6bgaie - valory/termination_abci:0.1.0:bafybeif2zim2de356eo3sipkmoev5emwadpqqzk3huwqarywh4tmqt3vzq - valory/transaction_settlement_abci:0.1.0:bafybeic3tccdjypuge2lewtlgprwkbb53lhgsgn7oiwzyrcrrptrbeyote -- valory/tx_settlement_multiplexer_abci:0.1.0:bafybeibyf7zwnvjbpk6nca7hj7mj7zxygr4j67jyq2vbk6gs22jwqma7eq -- valory/market_manager_abci:0.1.0:bafybeihuianzp5qrlxysdokrxzjrkt4pkruickdbzew5sngysel5obkwfm -- valory/decision_maker_abci:0.1.0:bafybeifrmophhnc3dg6ii57im66wwkvglvec6bew5zqy2rhtrcnsx5vx5i -- valory/trader_abci:0.1.0:bafybeihs25eobxugzytyoi7yy7f4srd3pp26dlx7k7jw3majqg4kwv7kti -- valory/staking_abci:0.1.0:bafybeiafzonb4h4ahn2n5mmbx4vtkckbylbzrxnr2gmrhhltw6xa35d6ve -- valory/check_stop_trading_abci:0.1.0:bafybeieyw7kanelhv3dnbd5ypo26ivnyqfg3ueiqt6s4wkvoz3gvfisihe +- valory/tx_settlement_multiplexer_abci:0.1.0:bafybeidcw2bzonvlgtyuv76zkutjs7qv5j4wgvi6azthqpyefds6i5cvdm +- valory/market_manager_abci:0.1.0:bafybeiai6djelf6d4dkxgkv46l24q2gz7736b3jdhbxslvcydpvnvrse6e +- valory/decision_maker_abci:0.1.0:bafybeigykiciajiq5za7szupck5jbj6z6dvnmoufdam7eyigpn4mr6c6bq +- valory/trader_abci:0.1.0:bafybeid23zogdrlauifqprlogztejgb2yl3ohcvqcat7nab2hgvez4bzru +- valory/staking_abci:0.1.0:bafybeiduborfqevheegy3plk7bzhkl4fukwixvlb57tenijdepintubbdi +- valory/check_stop_trading_abci:0.1.0:bafybeiepylk35n3faurvp7dskjkdovehftzfjrjxfkpekzuaovt5gojxne - valory/mech_interact_abci:0.1.0:bafybeih2cck5xu6yaibomwtm5zbcp6llghr3ighdnk56fzwu3ihu5xx35e customs: - valory/mike_strat:0.1.0:bafybeihjiol7f4ch4piwfikurdtfwzsh6qydkbsztpbwbwb2yrqdqf726m diff --git a/packages/valory/services/trader/service.yaml b/packages/valory/services/trader/service.yaml index 087d0bb9d..7eea28539 100644 --- a/packages/valory/services/trader/service.yaml +++ b/packages/valory/services/trader/service.yaml @@ -7,7 +7,7 @@ license: Apache-2.0 fingerprint: README.md: bafybeigtuothskwyvrhfosps2bu6suauycolj67dpuxqvnicdrdu7yhtvq fingerprint_ignore_patterns: [] -agent: valory/trader:0.1.0:bafybeia5e322is7dbiaao4x2zjfmiloijqjkffotljodrr2gjjnwb65e74 +agent: valory/trader:0.1.0:bafybeicdbgv3sricq6uafa6ps7rdjvqhelkbqktp5j4i6wzr2eetm4fn74 number_of_agents: 4 deployment: agent: diff --git a/packages/valory/services/trader_pearl/service.yaml b/packages/valory/services/trader_pearl/service.yaml index ac736da27..db0c6a161 100644 --- a/packages/valory/services/trader_pearl/service.yaml +++ b/packages/valory/services/trader_pearl/service.yaml @@ -8,7 +8,7 @@ license: Apache-2.0 fingerprint: README.md: bafybeibg7bdqpioh4lmvknw3ygnllfku32oca4eq5pqtvdrdsgw6buko7e fingerprint_ignore_patterns: [] -agent: valory/trader:0.1.0:bafybeia5e322is7dbiaao4x2zjfmiloijqjkffotljodrr2gjjnwb65e74 +agent: valory/trader:0.1.0:bafybeicdbgv3sricq6uafa6ps7rdjvqhelkbqktp5j4i6wzr2eetm4fn74 number_of_agents: 1 deployment: agent: diff --git a/packages/valory/skills/check_stop_trading_abci/skill.yaml b/packages/valory/skills/check_stop_trading_abci/skill.yaml index 1620ea12c..46f4a866d 100644 --- a/packages/valory/skills/check_stop_trading_abci/skill.yaml +++ b/packages/valory/skills/check_stop_trading_abci/skill.yaml @@ -16,6 +16,7 @@ fingerprint: payloads.py: bafybeidh5bqywun4chrbsci2xbcrnnzuys5sswxwbxq3yl2ksawi3xsi5q rounds.py: bafybeigqkzikghmzjj2ceqrnvmiiagtris3livgvn6r5z5ossk73xcfqfy tests/__init__.py: bafybeihv2cjk4va5bc5ncqtppqg2xmmxcro34bma36trtvk32gtmhdycxu + tests/test_handlers.py: bafybeigpmtx2hyunzn6nxk2x4bvvybek7jvuhbk34fqlj7fgfsszcoqhxy tests/test_payloads.py: bafybeih7q7kdfxsf4ejxxqwjumwglfwwcrbqcjnuy42mkhnfwccxuhiviy fingerprint_ignore_patterns: [] connections: [] @@ -24,7 +25,7 @@ contracts: protocols: [] skills: - valory/abstract_round_abci:0.1.0:bafybeiar2yhzxacfe3qqamqhaihtlcimquwedffctw55sowx6rac3cm3ui -- valory/staking_abci:0.1.0:bafybeiafzonb4h4ahn2n5mmbx4vtkckbylbzrxnr2gmrhhltw6xa35d6ve +- valory/staking_abci:0.1.0:bafybeiduborfqevheegy3plk7bzhkl4fukwixvlb57tenijdepintubbdi behaviours: main: args: {} diff --git a/packages/valory/skills/check_stop_trading_abci/tests/test_handlers.py b/packages/valory/skills/check_stop_trading_abci/tests/test_handlers.py new file mode 100644 index 000000000..bb1d25447 --- /dev/null +++ b/packages/valory/skills/check_stop_trading_abci/tests/test_handlers.py @@ -0,0 +1,76 @@ +# -*- coding: utf-8 -*- +# ------------------------------------------------------------------------------ +# +# Copyright 2024 Valory AG +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# ------------------------------------------------------------------------------ +"""This module contains tests for the handlers for the check stop trading abci.""" + +from unittest.mock import MagicMock + +import pytest +from aea.configurations.data_types import PublicId +from aea.skills.base import Handler + +from packages.valory.skills.abstract_round_abci.handlers import ABCIRoundHandler +from packages.valory.skills.abstract_round_abci.handlers import ( + ContractApiHandler as BaseContractApiHandler, +) +from packages.valory.skills.abstract_round_abci.handlers import ( + HttpHandler as BaseHttpHandler, +) +from packages.valory.skills.abstract_round_abci.handlers import ( + IpfsHandler as BaseIpfsHandler, +) +from packages.valory.skills.abstract_round_abci.handlers import ( + LedgerApiHandler as BaseLedgerApiHandler, +) +from packages.valory.skills.abstract_round_abci.handlers import ( + SigningHandler as BaseSigningHandler, +) +from packages.valory.skills.abstract_round_abci.handlers import ( + TendermintHandler as BaseTendermintHandler, +) +from packages.valory.skills.check_stop_trading_abci.handlers import ( + ABCICheckStopTradingHandler, + ContractApiHandler, + HttpHandler, + IpfsHandler, + LedgerApiHandler, + SigningHandler, + TendermintHandler, +) + + +@pytest.mark.parametrize( + "handler, base_handler", + [ + (ABCICheckStopTradingHandler, ABCIRoundHandler), + (HttpHandler, BaseHttpHandler), + (SigningHandler, BaseSigningHandler), + (LedgerApiHandler, BaseLedgerApiHandler), + (ContractApiHandler, BaseContractApiHandler), + (TendermintHandler, BaseTendermintHandler), + (IpfsHandler, BaseIpfsHandler), + ], +) +def test_handler(handler: Handler, base_handler: Handler) -> None: + """Test that the 'handlers.py' of the CheckStopTradingAbci can be imported.""" + handler = handler( + name="dummy_handler", + skill_context=MagicMock(skill_id=PublicId.from_str("dummy/skill:0.1.0")), + ) + + assert isinstance(handler, base_handler) diff --git a/packages/valory/skills/decision_maker_abci/skill.yaml b/packages/valory/skills/decision_maker_abci/skill.yaml index 292192d00..f82606e4d 100644 --- a/packages/valory/skills/decision_maker_abci/skill.yaml +++ b/packages/valory/skills/decision_maker_abci/skill.yaml @@ -59,6 +59,7 @@ fingerprint: tests/behaviours/dummy_strategy/dummy_strategy.py: bafybeig5e3xfr7gxsakfj4stbxqcwdiljl7klvgahkuwe3obzxgkg3qt2e tests/behaviours/test_base.py: bafybeiagdrveenk62parzchxg2nd2krpzm2pflfv3p4gszjfpnv3r2kpf4 tests/conftest.py: bafybeidy5hw56kw5mxudnfbhvogofn6k4rqb4ux2bd45baedrrhmgyrude + tests/test_handlers.py: bafybeihpkgtjjm3uegpup6zkznpoaxqpu6kmp3ujiggrzbe73p5fzlq7im tests/test_payloads.py: bafybeigsftkoc7ursy7okfznbwfiy3pk2kitndfgbn35ebbz4yoptkw3zy utils/__init__.py: bafybeiazrfg3kwfdl5q45azwz6b6mobqxngxpf4hazmrnkhinpk4qhbbf4 utils/nevermined.py: bafybeigallaqxhqopznhjhefr6bukh4ojkz5vdtqyzod5dksshrf24fjgi @@ -84,7 +85,7 @@ protocols: - valory/http:1.0.0:bafybeifugzl63kfdmwrxwphrnrhj7bn6iruxieme3a4ntzejf6kmtuwmae skills: - valory/abstract_round_abci:0.1.0:bafybeiar2yhzxacfe3qqamqhaihtlcimquwedffctw55sowx6rac3cm3ui -- valory/market_manager_abci:0.1.0:bafybeihuianzp5qrlxysdokrxzjrkt4pkruickdbzew5sngysel5obkwfm +- valory/market_manager_abci:0.1.0:bafybeiai6djelf6d4dkxgkv46l24q2gz7736b3jdhbxslvcydpvnvrse6e - valory/transaction_settlement_abci:0.1.0:bafybeic3tccdjypuge2lewtlgprwkbb53lhgsgn7oiwzyrcrrptrbeyote - valory/mech_interact_abci:0.1.0:bafybeih2cck5xu6yaibomwtm5zbcp6llghr3ighdnk56fzwu3ihu5xx35e behaviours: diff --git a/packages/valory/skills/decision_maker_abci/tests/test_handlers.py b/packages/valory/skills/decision_maker_abci/tests/test_handlers.py new file mode 100644 index 000000000..f934bbbe4 --- /dev/null +++ b/packages/valory/skills/decision_maker_abci/tests/test_handlers.py @@ -0,0 +1,381 @@ +# -*- coding: utf-8 -*- +# ------------------------------------------------------------------------------ +# +# Copyright 2024 Valory AG +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# ------------------------------------------------------------------------------ +"""This module contains the tests for the handlers for the decision maker abci.""" +import json +from dataclasses import dataclass +from typing import Any, Dict, Union +from unittest import mock +from unittest.mock import MagicMock, patch + +import pytest +from aea.configurations.data_types import PublicId +from aea.skills.base import Handler + +from packages.valory.connections.http_server.connection import ( + PUBLIC_ID as HTTP_SERVER_PUBLIC_ID, +) +from packages.valory.protocols.http import HttpMessage +from packages.valory.protocols.ipfs import IpfsMessage +from packages.valory.skills.abstract_round_abci.handlers import ( + ABCIRoundHandler as BaseABCIRoundHandler, +) +from packages.valory.skills.abstract_round_abci.handlers import ( + ContractApiHandler as BaseContractApiHandler, +) +from packages.valory.skills.abstract_round_abci.handlers import ( + HttpHandler as BaseHttpHandler, +) +from packages.valory.skills.abstract_round_abci.handlers import ( + LedgerApiHandler as BaseLedgerApiHandler, +) +from packages.valory.skills.abstract_round_abci.handlers import ( + SigningHandler as BaseSigningHandler, +) +from packages.valory.skills.abstract_round_abci.handlers import ( + TendermintHandler as BaseTendermintHandler, +) +from packages.valory.skills.decision_maker_abci.handlers import ( + ABCIHandler, + ContractApiHandler, + HttpHandler, + HttpMethod, + IpfsHandler, + LedgerApiHandler, + SigningHandler, + TendermintHandler, +) + + +@dataclass +class GetHandlerTestCase: + """Get Handler test case.""" + + name: str + url: str + method: str + expected_handler: Union[str, None] + + +@dataclass +class HandleTestCase: + """Handle test case.""" + + name: str + message_performative: str + message_sender: str + get_handler_return_value: tuple + message_url: Union[str, None] = None + message_method: Union[str, None] = None + update_return_value: Union[MagicMock, None] = None + expected_logger_call: Union[str, None] = None + expected_handler_call: bool = False + + +@pytest.mark.parametrize( + "handler, base_handler", + [ + (ABCIHandler, BaseABCIRoundHandler), + (SigningHandler, BaseSigningHandler), + (LedgerApiHandler, BaseLedgerApiHandler), + (ContractApiHandler, BaseContractApiHandler), + (TendermintHandler, BaseTendermintHandler), + ], +) +def test_handler(handler: Handler, base_handler: Handler) -> None: + """Test that the 'handlers.py' of the DecisionMakerAbci can be imported.""" + handler = handler( + name="dummy_handler", + skill_context=MagicMock(skill_id=PublicId.from_str("dummy/skill:0.1.0")), + ) + + assert isinstance(handler, base_handler) + + +class TestIpfsHandler: + """Class for testing the IPFS Handler.""" + + def setup(self) -> None: + """Set up the tests.""" + self.context = MagicMock() + self.handler = IpfsHandler(name="", skill_context=self.context) + + def test_handle(self) -> None: + """Test the 'handle' method.""" + callback = MagicMock() + request_reference = "reference" + self.handler.shared_state.req_to_callback = {} + self.handler.shared_state.req_to_callback[request_reference] = callback + + mock_dialogue = MagicMock() + mock_dialogue.dialogue_label.dialogue_reference = [request_reference] + + with mock.patch.object( + self.handler.context.ipfs_dialogues, "update", return_value=mock_dialogue + ): + mock_message = MagicMock(performative=IpfsMessage.Performative.FILES) + self.handler.handle(mock_message) + + callback.assert_called_once_with(mock_message, mock_dialogue) + + def test_handle_negative_performative_not_allowed(self) -> None: + """Test the 'handle' method, negative case (performative not allowed).""" + self.handler.handle(MagicMock()) + + +class TestHttpHandler: + """Class for testing the Http Handler.""" + + def setup(self) -> None: + """Set up the tests.""" + self.context = MagicMock() + self.context.logger = MagicMock() + self.handler = HttpHandler(name="", skill_context=self.context) + self.handler.context.params.service_endpoint = "http://localhost:8080/some/path" + self.handler.setup() + + def test_setup(self) -> None: + """Test the setup method of HttpHandler.""" + + config_uri_base_hostname = "localhost" + propel_uri_base_hostname = ( + r"https?:\/\/[a-zA-Z0-9]{16}.agent\.propel\.(staging\.)?autonolas\.tech" + ) + local_ip_regex = r"192\.168(\.\d{1,3}){2}" + hostname_regex = rf".*({config_uri_base_hostname}|{propel_uri_base_hostname}|{local_ip_regex}|localhost|127.0.0.1|0.0.0.0)(:\d+)?" + health_url_regex = rf"{hostname_regex}\/healthcheck" + assert self.handler.handler_url_regex == rf"{hostname_regex}\/.*" + assert self.handler.routes == { + (HttpMethod.GET.value, HttpMethod.HEAD.value): [ + (health_url_regex, self.handler._handle_get_health), + ], + } + assert self.handler.json_content_header == "Content-Type: application/json\n" + + @pytest.mark.parametrize( + "test_case", + [ + GetHandlerTestCase( + name="Happy Path", + url="http://localhost:8080/healthcheck", + method=HttpMethod.GET.value, + expected_handler="_handle_get_health", + ), + GetHandlerTestCase( + name="No url match", + url="http://invalid.url/not/matching", + method=HttpMethod.GET.value, + expected_handler=None, + ), + GetHandlerTestCase( + name="No method match", + url="http://localhost:8080/some/path", + method=HttpMethod.POST.value, + expected_handler="_handle_bad_request", + ), + ], + ) + def test_get_handler(self, test_case: GetHandlerTestCase) -> None: + """Test _get_handler.""" + url = test_case.url + method = test_case.method + + if test_case.expected_handler is not None: + expected_handler = getattr(self.handler, test_case.expected_handler) + else: + expected_handler = test_case.expected_handler + expected_captures: Dict[Any, Any] = {} + + handler, captures = self.handler._get_handler(url, method) + + assert handler == expected_handler + assert captures == expected_captures + + @pytest.mark.parametrize( + "test_case", + [ + HandleTestCase( + name="Test Handle", + message_performative=HttpMessage.Performative.RESPONSE, + message_sender="incorrect sender", + get_handler_return_value=(None, {}), + ), + HandleTestCase( + name="Test Handle No Handler", + message_performative=HttpMessage.Performative.REQUEST, + message_sender=str(HTTP_SERVER_PUBLIC_ID.without_hash()), + message_url="http://localhost/test", + message_method="GET", + get_handler_return_value=(None, {}), + ), + HandleTestCase( + name="Test Handle Invalid Dialogue", + message_performative=HttpMessage.Performative.REQUEST, + message_sender=str(HTTP_SERVER_PUBLIC_ID.without_hash()), + message_url="http://localhost/test", + message_method="GET", + get_handler_return_value=(lambda x, y: None, {}), + update_return_value=None, + expected_logger_call="Received invalid http message={}, unidentified dialogue.", + ), + HandleTestCase( + name="Test Handle Valid Message", + message_performative=HttpMessage.Performative.REQUEST, + message_sender=str(HTTP_SERVER_PUBLIC_ID.without_hash()), + message_url="http://localhost/test", + message_method="GET", + get_handler_return_value=(MagicMock(), {"key": "value"}), + update_return_value=MagicMock(), + expected_handler_call=True, + expected_logger_call="Received http request with method={}, url={} and body={!r}", + ), + ], + ) + def test_handle(self, test_case: HandleTestCase) -> None: + """Parameterized test for 'handle' method.""" + + self.message = MagicMock(performative=test_case.message_performative) + self.message.sender = test_case.message_sender + self.message.url = test_case.message_url + self.message.method = test_case.message_method + + with patch.object( + self.handler, + "_get_handler", + return_value=test_case.get_handler_return_value, + ), patch.object( + BaseHttpHandler, "handle", return_value=None + ) as mock_super_handle: + if not test_case.expected_logger_call: + self.handler.handle(self.message) + mock_super_handle.assert_called_once_with(self.message) + else: + http_dialogues_mock = MagicMock() + self.context.http_dialogues = http_dialogues_mock + http_dialogues_mock.update.return_value = test_case.update_return_value + self.handler.handle(self.message) + + if not test_case.expected_handler_call: + self.context.logger.info.assert_called_with( + test_case.expected_logger_call.format(self.message) + ) + else: + test_case.get_handler_return_value[0].assert_called_with( + self.message, + http_dialogues_mock.update.return_value, + key="value", + ) + self.context.logger.info.assert_called_with( + test_case.expected_logger_call.format( + self.message.method, self.message.url, self.message.body + ) + ) + + def test_handle_bad_request(self) -> None: + """Test handle with a bad request.""" + http_msg = MagicMock() + http_dialogue = MagicMock() + + # Configure the mocks + http_msg.version = "1.1" + http_msg.headers = {"Content-Type": "application/json"} + http_dialogue.reply.return_value = MagicMock() + + # Call the method + self.handler._handle_bad_request(http_msg, http_dialogue) + + # Verify that the reply method was called with the correct arguments + http_dialogue.reply.assert_called_once_with( + performative=HttpMessage.Performative.RESPONSE, + target_message=http_msg, + version=http_msg.version, + status_code=400, + status_text="Bad request", + headers=http_msg.headers, + body=b"", + ) + + # Verify that the logger was called with the expected message + http_response = http_dialogue.reply.return_value + self.handler.context.logger.info.assert_called_once_with( + "Responding with: {}".format(http_response) + ) + + # Verify that the message was put into the outbox + self.handler.context.outbox.put_message.assert_called_once_with( + message=http_response + ) + + def test_send_ok_response(self) -> None: + """Test send_ok_response function.""" + http_msg = MagicMock() + http_dialogue = MagicMock() + data = {"key": "value"} + + mock_response = MagicMock() + http_dialogue.reply.return_value = mock_response + + # Call the method + self.handler._send_ok_response(http_msg, http_dialogue, data) + + # Verify that the reply method was called with the correct arguments + http_dialogue.reply.assert_called_once_with( + performative=HttpMessage.Performative.RESPONSE, + target_message=http_msg, + version=http_msg.version, + status_code=200, + status_text="Success", + headers=f"{self.handler.json_content_header}{http_msg.headers}", + body=json.dumps(data).encode("utf-8"), + ) + + self.handler.context.logger.info.assert_called_once_with( + "Responding with: {}".format(mock_response) + ) + self.handler.context.outbox.put_message.assert_called_once_with( + message=mock_response + ) + + def test_send_not_found_response(self) -> None: + """Test _send_not_found_response.""" + + http_msg = MagicMock() + http_dialogue = MagicMock() + + # Create a mock response + mock_response = MagicMock() + http_dialogue.reply.return_value = mock_response + + self.handler._send_not_found_response(http_msg, http_dialogue) + + http_dialogue.reply.assert_called_once_with( + performative=HttpMessage.Performative.RESPONSE, + target_message=http_msg, + version=http_msg.version, + status_code=404, + status_text="Not found", + headers=http_msg.headers, + body=b"", + ) + + self.handler.context.logger.info.assert_called_once_with( + "Responding with: {}".format(mock_response) + ) + self.handler.context.outbox.put_message.assert_called_once_with( + message=mock_response + ) diff --git a/packages/valory/skills/market_manager_abci/skill.yaml b/packages/valory/skills/market_manager_abci/skill.yaml index 340acd5d5..ea81341a8 100644 --- a/packages/valory/skills/market_manager_abci/skill.yaml +++ b/packages/valory/skills/market_manager_abci/skill.yaml @@ -26,6 +26,7 @@ fingerprint: payloads.py: bafybeicfymvvtdpkcgmkvthfzmb7dqakepkzslqrz6rcs7nxkz7qq3mrzy rounds.py: bafybeigdwc4sr7gvxth4suaz36x7fmrn3jhlertwq4rcch4clyuxq435wa tests/__init__.py: bafybeigaewntxawezvygss345kytjijo56bfwddjtfm6egzxfajsgojam4 + tests/test_handlers.py: bafybeiaz3idwevvlplcyieaqo5oeikuthlte6e2gi4ajw452ylvimwgiki tests/test_payloads.py: bafybeidvld43p5c4wpwi7m6rfzontkheqqgxdchjnme5b54wmldojc5dmm fingerprint_ignore_patterns: [] connections: [] diff --git a/packages/valory/skills/market_manager_abci/tests/test_handlers.py b/packages/valory/skills/market_manager_abci/tests/test_handlers.py new file mode 100644 index 000000000..16f555389 --- /dev/null +++ b/packages/valory/skills/market_manager_abci/tests/test_handlers.py @@ -0,0 +1,77 @@ +# -*- coding: utf-8 -*- +# ------------------------------------------------------------------------------ +# +# Copyright 2023-2024 Valory AG +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# ------------------------------------------------------------------------------ + + +"""This module contains the tests for the handlers for the 'market_manager_abci' skill.""" +from unittest.mock import MagicMock + +import pytest +from aea.configurations.data_types import PublicId +from aea.skills.base import Handler + +from packages.valory.skills.abstract_round_abci.handlers import ABCIRoundHandler +from packages.valory.skills.abstract_round_abci.handlers import ( + ContractApiHandler as BaseContractApiHandler, +) +from packages.valory.skills.abstract_round_abci.handlers import ( + HttpHandler as BaseHttpHandler, +) +from packages.valory.skills.abstract_round_abci.handlers import ( + IpfsHandler as BaseIpfsHandler, +) +from packages.valory.skills.abstract_round_abci.handlers import ( + LedgerApiHandler as BaseLedgerApiHandler, +) +from packages.valory.skills.abstract_round_abci.handlers import ( + SigningHandler as BaseSigningHandler, +) +from packages.valory.skills.abstract_round_abci.handlers import ( + TendermintHandler as BaseTendermintHandler, +) +from packages.valory.skills.market_manager_abci.handlers import ( + ABCIMarketManagerHandler, + ContractApiHandler, + HttpHandler, + IpfsHandler, + LedgerApiHandler, + SigningHandler, + TendermintHandler, +) + + +@pytest.mark.parametrize( + "handler, base_handler", + [ + (ABCIMarketManagerHandler, ABCIRoundHandler), + (HttpHandler, BaseHttpHandler), + (SigningHandler, BaseSigningHandler), + (LedgerApiHandler, BaseLedgerApiHandler), + (ContractApiHandler, BaseContractApiHandler), + (TendermintHandler, BaseTendermintHandler), + (IpfsHandler, BaseIpfsHandler), + ], +) +def test_handler(handler: Handler, base_handler: Handler) -> None: + """Test that the 'handlers.py' of the TraderAbci can be imported.""" + handler = handler( + name="dummy_handler", + skill_context=MagicMock(skill_id=PublicId.from_str("dummy/skill:0.1.0")), + ) + + assert isinstance(handler, base_handler) diff --git a/packages/valory/skills/staking_abci/skill.yaml b/packages/valory/skills/staking_abci/skill.yaml index e419908d1..39144ec26 100644 --- a/packages/valory/skills/staking_abci/skill.yaml +++ b/packages/valory/skills/staking_abci/skill.yaml @@ -16,6 +16,7 @@ fingerprint: payloads.py: bafybeibnub5ehb2mvpcoan3x23pp5oz4azpofwrtcl32abswcfl4cmjlwq rounds.py: bafybeic7kre4hriounn6at63fjzttw45zoivxatg23cmojok4ah6fca7ca tests/__init__.py: bafybeid7m6ynosqeb4mvsss2hqg75aly5o2d47r7yfg2xtgwzkkilv2d2m + tests/test_handers.py: bafybeibnxlwznx3tsdpjpzh62bnp6lq7zdpolyjxfvxeumzz52ljxfzpme tests/test_payloads.py: bafybeiaq2dxpbein6qhipalibi57x6niiydxi6kvbpeqripzlngcgpb3qq fingerprint_ignore_patterns: [] connections: [] diff --git a/packages/valory/skills/staking_abci/tests/test_handers.py b/packages/valory/skills/staking_abci/tests/test_handers.py new file mode 100644 index 000000000..ebab67ce4 --- /dev/null +++ b/packages/valory/skills/staking_abci/tests/test_handers.py @@ -0,0 +1,76 @@ +# -*- coding: utf-8 -*- +# ------------------------------------------------------------------------------ +# +# Copyright 2024 Valory AG +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# ------------------------------------------------------------------------------ +"""This module contains the tests for the handlers for the staking abci.""" + +from unittest.mock import MagicMock + +import pytest +from aea.configurations.data_types import PublicId +from aea.skills.base import Handler + +from packages.valory.skills.abstract_round_abci.handlers import ABCIRoundHandler +from packages.valory.skills.abstract_round_abci.handlers import ( + ContractApiHandler as BaseContractApiHandler, +) +from packages.valory.skills.abstract_round_abci.handlers import ( + HttpHandler as BaseHttpHandler, +) +from packages.valory.skills.abstract_round_abci.handlers import ( + IpfsHandler as BaseIpfsHandler, +) +from packages.valory.skills.abstract_round_abci.handlers import ( + LedgerApiHandler as BaseLedgerApiHandler, +) +from packages.valory.skills.abstract_round_abci.handlers import ( + SigningHandler as BaseSigningHandler, +) +from packages.valory.skills.abstract_round_abci.handlers import ( + TendermintHandler as BaseTendermintHandler, +) +from packages.valory.skills.staking_abci.handlers import ( + ABCIStakingHandler, + ContractApiHandler, + HttpHandler, + IpfsHandler, + LedgerApiHandler, + SigningHandler, + TendermintHandler, +) + + +@pytest.mark.parametrize( + "handler, base_handler", + [ + (ABCIStakingHandler, ABCIRoundHandler), + (HttpHandler, BaseHttpHandler), + (SigningHandler, BaseSigningHandler), + (LedgerApiHandler, BaseLedgerApiHandler), + (ContractApiHandler, BaseContractApiHandler), + (TendermintHandler, BaseTendermintHandler), + (IpfsHandler, BaseIpfsHandler), + ], +) +def test_handler(handler: Handler, base_handler: Handler) -> None: + """Test that the 'handlers.py' of the StakingAbci can be imported.""" + handler = handler( + name="dummy_handler", + skill_context=MagicMock(skill_id=PublicId.from_str("dummy/skill:0.1.0")), + ) + + assert isinstance(handler, base_handler) diff --git a/packages/valory/skills/trader_abci/skill.yaml b/packages/valory/skills/trader_abci/skill.yaml index 14d05c872..5f1303133 100644 --- a/packages/valory/skills/trader_abci/skill.yaml +++ b/packages/valory/skills/trader_abci/skill.yaml @@ -14,6 +14,8 @@ fingerprint: fsm_specification.yaml: bafybeig72lgkum7aeieb52jch6qkfdtarzdc2w64562hutck4rowzo3dcy handlers.py: bafybeibbxybbi66em63ad33cllymypr3za3f5xvor3m2krhuxoyxnqjnxu models.py: bafybeidrtcycxhuig776kjhnuonwlvjmn4kb2n3uvxdrpmc3hwn65qsolm + tests/__init__.py: bafybeiadatapyjh3e7ucg2ehz77oms3ihrbutwb2cs2tkjehy54utwvuyi + tests/tests_handlers.py: bafybeifxvd63qblqpsmyvj7k4dbqubab2pshao5zd2zs2srs7rt32zvciu fingerprint_ignore_patterns: [] connections: [] contracts: [] @@ -24,11 +26,11 @@ skills: - valory/reset_pause_abci:0.1.0:bafybeiameewywqigpupy3u2iwnkfczeiiucue74x2l5lbge74rmw6bgaie - valory/transaction_settlement_abci:0.1.0:bafybeic3tccdjypuge2lewtlgprwkbb53lhgsgn7oiwzyrcrrptrbeyote - valory/termination_abci:0.1.0:bafybeif2zim2de356eo3sipkmoev5emwadpqqzk3huwqarywh4tmqt3vzq -- valory/market_manager_abci:0.1.0:bafybeihuianzp5qrlxysdokrxzjrkt4pkruickdbzew5sngysel5obkwfm -- valory/decision_maker_abci:0.1.0:bafybeifrmophhnc3dg6ii57im66wwkvglvec6bew5zqy2rhtrcnsx5vx5i -- valory/tx_settlement_multiplexer_abci:0.1.0:bafybeibyf7zwnvjbpk6nca7hj7mj7zxygr4j67jyq2vbk6gs22jwqma7eq -- valory/staking_abci:0.1.0:bafybeiafzonb4h4ahn2n5mmbx4vtkckbylbzrxnr2gmrhhltw6xa35d6ve -- valory/check_stop_trading_abci:0.1.0:bafybeieyw7kanelhv3dnbd5ypo26ivnyqfg3ueiqt6s4wkvoz3gvfisihe +- valory/market_manager_abci:0.1.0:bafybeiai6djelf6d4dkxgkv46l24q2gz7736b3jdhbxslvcydpvnvrse6e +- valory/decision_maker_abci:0.1.0:bafybeigykiciajiq5za7szupck5jbj6z6dvnmoufdam7eyigpn4mr6c6bq +- valory/tx_settlement_multiplexer_abci:0.1.0:bafybeidcw2bzonvlgtyuv76zkutjs7qv5j4wgvi6azthqpyefds6i5cvdm +- valory/staking_abci:0.1.0:bafybeiduborfqevheegy3plk7bzhkl4fukwixvlb57tenijdepintubbdi +- valory/check_stop_trading_abci:0.1.0:bafybeiepylk35n3faurvp7dskjkdovehftzfjrjxfkpekzuaovt5gojxne - valory/mech_interact_abci:0.1.0:bafybeih2cck5xu6yaibomwtm5zbcp6llghr3ighdnk56fzwu3ihu5xx35e behaviours: main: diff --git a/packages/valory/skills/trader_abci/tests/__init__.py b/packages/valory/skills/trader_abci/tests/__init__.py new file mode 100644 index 000000000..18184313e --- /dev/null +++ b/packages/valory/skills/trader_abci/tests/__init__.py @@ -0,0 +1,19 @@ +# -*- coding: utf-8 -*- +# ------------------------------------------------------------------------------ +# +# Copyright 2024 Valory AG +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# ------------------------------------------------------------------------------ +"""This module contains the tests for trader abci.""" diff --git a/packages/valory/skills/trader_abci/tests/tests_handlers.py b/packages/valory/skills/trader_abci/tests/tests_handlers.py new file mode 100644 index 000000000..9b62aae4c --- /dev/null +++ b/packages/valory/skills/trader_abci/tests/tests_handlers.py @@ -0,0 +1,76 @@ +# -*- coding: utf-8 -*- +# ------------------------------------------------------------------------------ +# +# Copyright 2024 Valory AG +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# ------------------------------------------------------------------------------ +"""This module contains the tests for the handlers for the trader abci.""" + +from unittest.mock import MagicMock + +import pytest +from aea.configurations.data_types import PublicId +from aea.skills.base import Handler + +from packages.valory.skills.abstract_round_abci.handlers import ABCIRoundHandler +from packages.valory.skills.abstract_round_abci.handlers import ( + ContractApiHandler as BaseContractApiHandler, +) +from packages.valory.skills.abstract_round_abci.handlers import ( + LedgerApiHandler as BaseLedgerApiHandler, +) +from packages.valory.skills.abstract_round_abci.handlers import ( + SigningHandler as BaseSigningHandler, +) +from packages.valory.skills.abstract_round_abci.handlers import ( + TendermintHandler as BaseTendermintHandler, +) +from packages.valory.skills.decision_maker_abci.handlers import ( + HttpHandler as BaseHttpHandler, +) +from packages.valory.skills.decision_maker_abci.handlers import ( + IpfsHandler as BaseIpfsHandler, +) +from packages.valory.skills.trader_abci.handlers import ( + ContractApiHandler, + HttpHandler, + IpfsHandler, + LedgerApiHandler, + SigningHandler, + TendermintHandler, + TraderHandler, +) + + +@pytest.mark.parametrize( + "handler, base_handler", + [ + (TraderHandler, ABCIRoundHandler), + (HttpHandler, BaseHttpHandler), + (SigningHandler, BaseSigningHandler), + (LedgerApiHandler, BaseLedgerApiHandler), + (ContractApiHandler, BaseContractApiHandler), + (TendermintHandler, BaseTendermintHandler), + (IpfsHandler, BaseIpfsHandler), + ], +) +def test_handler(handler: Handler, base_handler: Handler) -> None: + """Test that the 'handlers.py' of the TraderAbci can be imported.""" + handler = handler( + name="dummy_handler", + skill_context=MagicMock(skill_id=PublicId.from_str("dummy/skill:0.1.0")), + ) + + assert isinstance(handler, base_handler) diff --git a/packages/valory/skills/tx_settlement_multiplexer_abci/skill.yaml b/packages/valory/skills/tx_settlement_multiplexer_abci/skill.yaml index e59a7ded1..ee919d92b 100644 --- a/packages/valory/skills/tx_settlement_multiplexer_abci/skill.yaml +++ b/packages/valory/skills/tx_settlement_multiplexer_abci/skill.yaml @@ -14,6 +14,8 @@ fingerprint: handlers.py: bafybeiafbqr7ojfcbwohvee7x4zzswad3ymfrrbjlfz7uuuttmn3qdfs6q models.py: bafybeigtmxoecoow663hgqnyinxarlrttyyt5ghpbdamdv4tc4kikcfx3a rounds.py: bafybeig3dhhrf5tkj63b3bk2mqfprcwzk3galz2ukzvdenz4g2femaixku + tests/__init__.py: bafybeiat74pbtmxvylsz7karp57qp2v7y6wtrsz572jkrghbcssoudgjay + tests/test_handlers.py: bafybeiayuktfupylm3p3ygufjb66swzxhpbmioqoffwuauakfgbkwrv7ma fingerprint_ignore_patterns: [] connections: [] contracts: [] @@ -21,8 +23,8 @@ protocols: - valory/ledger_api:1.0.0:bafybeihdk6psr4guxmbcrc26jr2cbgzpd5aljkqvpwo64bvaz7tdti2oni skills: - valory/abstract_round_abci:0.1.0:bafybeiar2yhzxacfe3qqamqhaihtlcimquwedffctw55sowx6rac3cm3ui -- valory/decision_maker_abci:0.1.0:bafybeifrmophhnc3dg6ii57im66wwkvglvec6bew5zqy2rhtrcnsx5vx5i -- valory/staking_abci:0.1.0:bafybeiafzonb4h4ahn2n5mmbx4vtkckbylbzrxnr2gmrhhltw6xa35d6ve +- valory/decision_maker_abci:0.1.0:bafybeigykiciajiq5za7szupck5jbj6z6dvnmoufdam7eyigpn4mr6c6bq +- valory/staking_abci:0.1.0:bafybeiduborfqevheegy3plk7bzhkl4fukwixvlb57tenijdepintubbdi - valory/mech_interact_abci:0.1.0:bafybeih2cck5xu6yaibomwtm5zbcp6llghr3ighdnk56fzwu3ihu5xx35e behaviours: main: diff --git a/packages/valory/skills/tx_settlement_multiplexer_abci/tests/__init__.py b/packages/valory/skills/tx_settlement_multiplexer_abci/tests/__init__.py new file mode 100644 index 000000000..0d6412538 --- /dev/null +++ b/packages/valory/skills/tx_settlement_multiplexer_abci/tests/__init__.py @@ -0,0 +1,19 @@ +# -*- coding: utf-8 -*- +# ------------------------------------------------------------------------------ +# +# Copyright 2024 Valory AG +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# ------------------------------------------------------------------------------ +"""This module contains the tests for tx settlement multiplexer abci.""" diff --git a/packages/valory/skills/tx_settlement_multiplexer_abci/tests/test_handlers.py b/packages/valory/skills/tx_settlement_multiplexer_abci/tests/test_handlers.py new file mode 100644 index 000000000..3287c3c47 --- /dev/null +++ b/packages/valory/skills/tx_settlement_multiplexer_abci/tests/test_handlers.py @@ -0,0 +1,75 @@ +# -*- coding: utf-8 -*- +# ------------------------------------------------------------------------------ +# +# Copyright 2024 Valory AG +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# ------------------------------------------------------------------------------ +"""This module contains the tests for the handlers of the tx settlement multiplexer abci.""" +from unittest.mock import MagicMock + +import pytest +from aea.configurations.data_types import PublicId +from aea.skills.base import Handler + +from packages.valory.skills.abstract_round_abci.handlers import ABCIRoundHandler +from packages.valory.skills.abstract_round_abci.handlers import ( + ContractApiHandler as BaseContractApiHandler, +) +from packages.valory.skills.abstract_round_abci.handlers import ( + HttpHandler as BaseHttpHandler, +) +from packages.valory.skills.abstract_round_abci.handlers import ( + IpfsHandler as BaseIpfsHandler, +) +from packages.valory.skills.abstract_round_abci.handlers import ( + LedgerApiHandler as BaseLedgerApiHandler, +) +from packages.valory.skills.abstract_round_abci.handlers import ( + SigningHandler as BaseSigningHandler, +) +from packages.valory.skills.abstract_round_abci.handlers import ( + TendermintHandler as BaseTendermintHandler, +) +from packages.valory.skills.tx_settlement_multiplexer_abci.handlers import ( + ContractApiHandler, + HttpHandler, + IpfsHandler, + LedgerApiHandler, + SigningHandler, + TendermintHandler, + TxSettlementMultiplexerHandler, +) + + +@pytest.mark.parametrize( + "handler, base_handler", + [ + (TxSettlementMultiplexerHandler, ABCIRoundHandler), + (HttpHandler, BaseHttpHandler), + (SigningHandler, BaseSigningHandler), + (LedgerApiHandler, BaseLedgerApiHandler), + (ContractApiHandler, BaseContractApiHandler), + (TendermintHandler, BaseTendermintHandler), + (IpfsHandler, BaseIpfsHandler), + ], +) +def test_handler(handler: Handler, base_handler: Handler) -> None: + """Test that the 'handlers.py' of the TxSettlementMultiplexerAbci can be imported.""" + handler = handler( + name="dummy_handler", + skill_context=MagicMock(skill_id=PublicId.from_str("dummy/skill:0.1.0")), + ) + + assert isinstance(handler, base_handler)