Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Test/check_stop_trading_abci #319

Merged
merged 2 commits into from
Sep 4, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 5 additions & 5 deletions packages/packages.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,13 @@
"contract/valory/relayer/0.1.0": "bafybeihzgjyvhtorugjw3yldznqsbwo3aqpxowm7k2nrvj6qtwpsc7jl7u",
"skill/valory/market_manager_abci/0.1.0": "bafybeiai6djelf6d4dkxgkv46l24q2gz7736b3jdhbxslvcydpvnvrse6e",
"skill/valory/decision_maker_abci/0.1.0": "bafybeigh2ajmwscmgvl3t4wkwyeclszs5ujykm5omget7yap7zmwironkq",
"skill/valory/trader_abci/0.1.0": "bafybeie3njujc5zdwqncwwr3yhfm33cggtihxwrdjlzpgaom4zdnidy6ka",
"skill/valory/trader_abci/0.1.0": "bafybeifjeeulkss2c4dnhzs24u63556w2vq3xxbfykxn7hcl7wirwvjqcq",
"skill/valory/tx_settlement_multiplexer_abci/0.1.0": "bafybeibyverkghpxz7di3wgxdixwcofrxec35b4tb4ac5pebpseax76eby",
"skill/valory/staking_abci/0.1.0": "bafybeiduborfqevheegy3plk7bzhkl4fukwixvlb57tenijdepintubbdi",
"skill/valory/check_stop_trading_abci/0.1.0": "bafybeiepylk35n3faurvp7dskjkdovehftzfjrjxfkpekzuaovt5gojxne",
"agent/valory/trader/0.1.0": "bafybeiexvarbsj25xevrtuqavwmgpvmz753a74im7su7jzamhhkuqjcl3y",
"service/valory/trader/0.1.0": "bafybeighrps33nlltr7gwdeaftkii3t2itwshvk5ulpazjyxdmed6gmbo4",
"service/valory/trader_pearl/0.1.0": "bafybeihqtqgohejyebrb4jvd2fgccuasmqk3gc456ylyfa7tcn6rucdrxm"
"skill/valory/check_stop_trading_abci/0.1.0": "bafybeiat5hmo6i2r6t6ufyfnidvepixmbnppotdmztu4dad5j4hiewdh64",
"agent/valory/trader/0.1.0": "bafybeibwds53c4mtfnrymruw56o4nzmtv4zwu7nbhbxi7ix2ra4izk6tx4",
"service/valory/trader/0.1.0": "bafybeigwmrak2lnnzjx3o3la6jaxgp7tlm4wr4lks3movgveqgvwou7s7a",
"service/valory/trader_pearl/0.1.0": "bafybeigwl2i45vuovylfaymuid73x4c2efwkwcbau7dthv3k7raohfgqqy"
},
"third_party": {
"protocol/open_aea/signing/1.0.0": "bafybeihv62fim3wl2bayavfcg3u5e5cxu3b7brtu4cn5xoxd6lqwachasi",
Expand Down
4 changes: 2 additions & 2 deletions packages/valory/agents/trader/aea-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -50,9 +50,9 @@ skills:
- valory/tx_settlement_multiplexer_abci:0.1.0:bafybeibyverkghpxz7di3wgxdixwcofrxec35b4tb4ac5pebpseax76eby
- valory/market_manager_abci:0.1.0:bafybeiai6djelf6d4dkxgkv46l24q2gz7736b3jdhbxslvcydpvnvrse6e
- valory/decision_maker_abci:0.1.0:bafybeigh2ajmwscmgvl3t4wkwyeclszs5ujykm5omget7yap7zmwironkq
- valory/trader_abci:0.1.0:bafybeie3njujc5zdwqncwwr3yhfm33cggtihxwrdjlzpgaom4zdnidy6ka
- valory/trader_abci:0.1.0:bafybeifjeeulkss2c4dnhzs24u63556w2vq3xxbfykxn7hcl7wirwvjqcq
- valory/staking_abci:0.1.0:bafybeiduborfqevheegy3plk7bzhkl4fukwixvlb57tenijdepintubbdi
- valory/check_stop_trading_abci:0.1.0:bafybeiepylk35n3faurvp7dskjkdovehftzfjrjxfkpekzuaovt5gojxne
- valory/check_stop_trading_abci:0.1.0:bafybeiat5hmo6i2r6t6ufyfnidvepixmbnppotdmztu4dad5j4hiewdh64
- valory/mech_interact_abci:0.1.0:bafybeih2cck5xu6yaibomwtm5zbcp6llghr3ighdnk56fzwu3ihu5xx35e
customs:
- valory/mike_strat:0.1.0:bafybeihjiol7f4ch4piwfikurdtfwzsh6qydkbsztpbwbwb2yrqdqf726m
Expand Down
2 changes: 1 addition & 1 deletion packages/valory/services/trader/service.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ license: Apache-2.0
fingerprint:
README.md: bafybeigtuothskwyvrhfosps2bu6suauycolj67dpuxqvnicdrdu7yhtvq
fingerprint_ignore_patterns: []
agent: valory/trader:0.1.0:bafybeiexvarbsj25xevrtuqavwmgpvmz753a74im7su7jzamhhkuqjcl3y
agent: valory/trader:0.1.0:bafybeibwds53c4mtfnrymruw56o4nzmtv4zwu7nbhbxi7ix2ra4izk6tx4
number_of_agents: 4
deployment:
agent:
Expand Down
2 changes: 1 addition & 1 deletion packages/valory/services/trader_pearl/service.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ license: Apache-2.0
fingerprint:
README.md: bafybeibg7bdqpioh4lmvknw3ygnllfku32oca4eq5pqtvdrdsgw6buko7e
fingerprint_ignore_patterns: []
agent: valory/trader:0.1.0:bafybeiexvarbsj25xevrtuqavwmgpvmz753a74im7su7jzamhhkuqjcl3y
agent: valory/trader:0.1.0:bafybeibwds53c4mtfnrymruw56o4nzmtv4zwu7nbhbxi7ix2ra4izk6tx4
number_of_agents: 1
deployment:
agent:
Expand Down
2 changes: 2 additions & 0 deletions packages/valory/skills/check_stop_trading_abci/skill.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,10 @@ fingerprint:
payloads.py: bafybeidh5bqywun4chrbsci2xbcrnnzuys5sswxwbxq3yl2ksawi3xsi5q
rounds.py: bafybeigqkzikghmzjj2ceqrnvmiiagtris3livgvn6r5z5ossk73xcfqfy
tests/__init__.py: bafybeihv2cjk4va5bc5ncqtppqg2xmmxcro34bma36trtvk32gtmhdycxu
tests/test_dialogues.py: bafybeia5ac27w7ijx2nyx5dqyrnv4troo4572gjq7nrcxdncexoxucnqti
tests/test_handlers.py: bafybeigpmtx2hyunzn6nxk2x4bvvybek7jvuhbk34fqlj7fgfsszcoqhxy
tests/test_payloads.py: bafybeih7q7kdfxsf4ejxxqwjumwglfwwcrbqcjnuy42mkhnfwccxuhiviy
tests/test_rounds.py: bafybeidgbc7mi7r2fpk7ak6xceohuoq2zkpkberkokcb3sb2uzwkxoluae
fingerprint_ignore_patterns: []
connections: []
contracts:
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# -*- coding: utf-8 -*-
# ------------------------------------------------------------------------------
#
# Copyright 2021-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.
#
# ------------------------------------------------------------------------------

"""Test the dialogues.py module of the skill."""

# pylint: skip-file

import packages.valory.skills.check_stop_trading_abci.dialogues # noqa


def test_import() -> None:
"""Test that the 'dialogues.py' Python module can be imported."""
285 changes: 285 additions & 0 deletions packages/valory/skills/check_stop_trading_abci/tests/test_rounds.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,285 @@
# -*- 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 package contains the tests for the CheckStopTradingAbciApp."""

import json
from dataclasses import dataclass, field
from typing import (
Any,
Callable,
Dict,
FrozenSet,
Hashable,
List,
Mapping,
Optional,
Type,
)
from unittest.mock import MagicMock, Mock

import pytest

from packages.valory.skills.abstract_round_abci.base import (
AbciAppDB,
CollectionRound,
VotingRound,
get_name,
)
from packages.valory.skills.abstract_round_abci.test_tools.rounds import (
BaseVotingRoundTest,
)
from packages.valory.skills.check_stop_trading_abci.payloads import (
CheckStopTradingPayload,
)
from packages.valory.skills.check_stop_trading_abci.rounds import (
CheckStopTradingAbciApp,
CheckStopTradingRound,
Event,
FinishedCheckStopTradingRound,
FinishedWithSkipTradingRound,
SynchronizedData,
)


DUMMY_PAYLOAD_DATA = {"example_key": "example_value"}


@pytest.fixture
def abci_app() -> CheckStopTradingAbciApp:
"""Fixture for CheckStopTradingAbciApp."""
synchronized_data = Mock()
logger = Mock()
context = Mock()

return CheckStopTradingAbciApp(
synchronized_data=synchronized_data, logger=logger, context=context
)


def get_participants() -> FrozenSet[str]:
"""Participants"""
return frozenset([f"agent_{i}" for i in range(MAX_PARTICIPANTS)])


def get_participant_to_votes(
participants: FrozenSet[str], vote: bool
) -> Dict[str, CheckStopTradingPayload]:
"""participant_to_votes"""

return {
participant: CheckStopTradingPayload(sender=participant, vote=vote)
for participant in participants
}


def get_participant_to_votes_serialized(
participants: FrozenSet[str], vote: bool
) -> Dict[str, Dict[str, Any]]:
"""participant_to_votes"""

return CollectionRound.serialize_collection(
get_participant_to_votes(participants, vote)
)


def get_payloads(
payload_cls: Type[CheckStopTradingPayload],
data: Optional[str],
) -> Mapping[str, CheckStopTradingPayload]:
"""Get payloads."""
return {
participant: payload_cls(participant, data is not None)
for participant in get_participants()
}


def get_dummy_check_stop_trading_payload_serialized() -> str:
"""Dummy payload serialization"""
return json.dumps(DUMMY_PAYLOAD_DATA, sort_keys=True)


@dataclass
class RoundTestCase:
"""RoundTestCase"""

name: str
initial_data: Dict[str, Hashable]
payloads: Mapping[str, CheckStopTradingPayload]
final_data: Dict[str, Hashable]
event: Event
most_voted_payload: Any
synchronized_data_attr_checks: List[Callable] = field(default_factory=list)


MAX_PARTICIPANTS: int = 4


class BaseCheckStopTradingRoundTest(BaseVotingRoundTest):
"""Base Test Class for CheckStopTradingRound"""

test_class: Type[VotingRound]
test_payload: Type[CheckStopTradingPayload]

def _test_voting_round(
self, vote: bool, expected_event: Any, threshold_check: Callable
) -> None:
"""Helper method to test voting rounds with positive or negative votes."""

test_round = self.test_class(
synchronized_data=self.synchronized_data, context=MagicMock()
)

self._complete_run(
self._test_round(
test_round=test_round,
round_payloads=get_participant_to_votes(self.participants, vote=vote),
synchronized_data_update_fn=lambda _synchronized_data, _: _synchronized_data.update(
participant_to_votes=get_participant_to_votes_serialized(
self.participants, vote=vote
)
),
synchronized_data_attr_checks=[
lambda _synchronized_data: _synchronized_data.participant_to_votes.keys()
]
if vote
else [],
exit_event=expected_event,
threshold_check=threshold_check,
)
)

def test_positive_votes(self) -> None:
"""Test ValidateRound for positive votes."""
self._test_voting_round(
vote=True,
expected_event=self._event_class.SKIP_TRADING,
threshold_check=lambda x: x.positive_vote_threshold_reached,
)

def test_negative_votes(self) -> None:
"""Test ValidateRound for negative votes."""
self._test_voting_round(
vote=False,
expected_event=self._event_class.DONE,
threshold_check=lambda x: x.negative_vote_threshold_reached,
)


class TestCheckStopTradingRound(BaseCheckStopTradingRoundTest):
"""Tests for CheckStopTradingRound."""

test_class = CheckStopTradingRound
_event_class = Event
_synchronized_data_class = SynchronizedData

@pytest.mark.parametrize(
"test_case",
(
RoundTestCase(
name="Happy path",
initial_data={},
payloads=get_payloads(
payload_cls=CheckStopTradingPayload,
data=get_dummy_check_stop_trading_payload_serialized(),
),
final_data={},
event=Event.SKIP_TRADING,
most_voted_payload=get_dummy_check_stop_trading_payload_serialized(),
synchronized_data_attr_checks=[
lambda sync_data: sync_data.db.get(
get_name(SynchronizedData.participant_to_votes)
)
== CollectionRound.deserialize_collection(
json.loads(get_dummy_check_stop_trading_payload_serialized())
)
],
),
RoundTestCase(
name="No majority",
initial_data={},
payloads=get_payloads(
payload_cls=CheckStopTradingPayload,
data=get_dummy_check_stop_trading_payload_serialized(),
),
final_data={},
event=Event.NO_MAJORITY,
most_voted_payload=get_dummy_check_stop_trading_payload_serialized(),
synchronized_data_attr_checks=[],
),
),
)
def test_run(self, test_case: RoundTestCase) -> None:
"""Run tests."""
if test_case.event == Event.SKIP_TRADING:
self.test_positive_votes()
elif test_case.event == Event.NO_MAJORITY:
self.test_negative_votes()

"""Tests for FinishedCheckStopTradingRound."""

def test_finished_check_stop_trading_round_initialization(self) -> None:
"""Test the initialization of FinishedCheckStopTradingRound."""
round_ = FinishedCheckStopTradingRound(
synchronized_data=MagicMock(), context=MagicMock()
)
assert isinstance(round_, FinishedCheckStopTradingRound)


class TestFinishedWithSkipTradingRound:
"""Tests for FinishedWithSkipTradingRound."""

def test_finished_with_skip_trading_round_initialization(self) -> None:
"""Test the initialization of FinishedWithSkipTradingRound."""
round_ = FinishedWithSkipTradingRound(
synchronized_data=MagicMock(), context=MagicMock()
)
assert isinstance(round_, FinishedWithSkipTradingRound)


def test_abci_app_initialization(abci_app: CheckStopTradingAbciApp) -> None:
"""Test the initialization of CheckStopTradingAbciApp."""
assert abci_app.initial_round_cls is CheckStopTradingRound
assert abci_app.final_states == {
FinishedCheckStopTradingRound,
FinishedWithSkipTradingRound,
}
assert abci_app.transition_function == {
CheckStopTradingRound: {
Event.DONE: FinishedCheckStopTradingRound,
Event.NONE: CheckStopTradingRound,
Event.ROUND_TIMEOUT: CheckStopTradingRound,
Event.NO_MAJORITY: CheckStopTradingRound,
Event.SKIP_TRADING: FinishedWithSkipTradingRound,
},
FinishedCheckStopTradingRound: {},
FinishedWithSkipTradingRound: {},
}
assert abci_app.event_to_timeout == {Event.ROUND_TIMEOUT: 30.0}
assert abci_app.db_pre_conditions == {CheckStopTradingRound: set()}
assert abci_app.db_post_conditions == {
FinishedCheckStopTradingRound: set(),
FinishedWithSkipTradingRound: set(),
}


def test_synchronized_data_initialization() -> None:
"""Test the initialization and attributes of SynchronizedData."""
data = SynchronizedData(db=AbciAppDB(setup_data={"test": ["test"]}))
assert data.db._data == {0: {"test": ["test"]}}
2 changes: 1 addition & 1 deletion packages/valory/skills/trader_abci/skill.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ skills:
- valory/decision_maker_abci:0.1.0:bafybeigh2ajmwscmgvl3t4wkwyeclszs5ujykm5omget7yap7zmwironkq
- valory/tx_settlement_multiplexer_abci:0.1.0:bafybeibyverkghpxz7di3wgxdixwcofrxec35b4tb4ac5pebpseax76eby
- valory/staking_abci:0.1.0:bafybeiduborfqevheegy3plk7bzhkl4fukwixvlb57tenijdepintubbdi
- valory/check_stop_trading_abci:0.1.0:bafybeiepylk35n3faurvp7dskjkdovehftzfjrjxfkpekzuaovt5gojxne
- valory/check_stop_trading_abci:0.1.0:bafybeiat5hmo6i2r6t6ufyfnidvepixmbnppotdmztu4dad5j4hiewdh64
- valory/mech_interact_abci:0.1.0:bafybeih2cck5xu6yaibomwtm5zbcp6llghr3ighdnk56fzwu3ihu5xx35e
behaviours:
main:
Expand Down
Loading