From 4c08bdbd0f5e5c29f6e55469f359735c5ef8cc80 Mon Sep 17 00:00:00 2001 From: vestor-dev <182824106+vestor-dev@users.noreply.github.com> Date: Tue, 26 Nov 2024 07:32:08 +0000 Subject: [PATCH 1/3] test: add test for test_health_ratio --- .../test_health_ratio_tests.py | 133 ++++++++++++++++++ 1 file changed, 133 insertions(+) create mode 100644 apps/data_handler/tests/health_ratio_test/test_health_ratio_tests.py diff --git a/apps/data_handler/tests/health_ratio_test/test_health_ratio_tests.py b/apps/data_handler/tests/health_ratio_test/test_health_ratio_tests.py new file mode 100644 index 00000000..d0e02bc8 --- /dev/null +++ b/apps/data_handler/tests/health_ratio_test/test_health_ratio_tests.py @@ -0,0 +1,133 @@ +import pytest +from decimal import Decimal +from unittest.mock import MagicMock, patch +from datetime import datetime + +from data_handler.handlers.health_ratio_level.health_ratio_handlers import BaseHealthRatioHandler +from shared.state import State, LoanEntity +from shared.types import TokenValues +from shared.constants import ProtocolIDs + +class MockState(State): + """Mock State class for testing""" + pass + +class MockLoanEntity(LoanEntity): + """Mock LoanEntity class for testing""" + pass + +@pytest.fixture +def mock_loan_data(): + """Fixture for sample loan data""" + return [ + MagicMock( + user="user1", + debt={"ETH": Decimal("1.5")}, + collateral={"USDC": Decimal("3000")} + ), + MagicMock( + user="user2", + debt={"ETH": Decimal("2.0")}, + collateral={"USDC": Decimal("4000")} + ) + ] + +@pytest.fixture +def mock_interest_rates(): + """Fixture for sample interest rate data""" + return MagicMock( + collateral={"USDC": Decimal("0.05")}, + debt={"ETH": Decimal("0.08")} + ) + +class TestBaseHealthRatioHandler: + + @pytest.fixture + def handler(self): + """Create a BaseHealthRatioHandler instance for testing""" + return BaseHealthRatioHandler( + state_class=MockState, + loan_entity_class=MockLoanEntity + ) + + def test_initialization(self, handler): + """Test proper initialization of BaseHealthRatioHandler""" + assert isinstance(handler, BaseHealthRatioHandler) + assert handler.state_class == MockState + assert handler.loan_entity_class == MockLoanEntity + assert handler.db_connector is not None + + def test_fetch_data(self, handler, mock_db_connector, mock_loan_data, mock_interest_rates): + """Test fetch_data method""" + handler.db_connector = mock_db_connector + mock_db_connector.get_latest_block_loans.return_value = mock_loan_data + mock_db_connector.get_last_interest_rate_record_by_protocol_id.return_value = mock_interest_rates + + loan_states, interest_rates = handler.fetch_data(ProtocolIDs.ZKLEND) + + assert loan_states == mock_loan_data + assert interest_rates == mock_interest_rates + mock_db_connector.get_latest_block_loans.assert_called_once() + mock_db_connector.get_last_interest_rate_record_by_protocol_id.assert_called_once_with( + protocol_id=ProtocolIDs.ZKLEND + ) + + def test_initialize_loan_entities(self, handler, mock_loan_data): + """Test initialize_loan_entities method""" + state = MockState() + result_state = handler.initialize_loan_entities(state, mock_loan_data) + + assert len(result_state.loan_entities) == 2 + assert "user1" in result_state.loan_entities + assert "user2" in result_state.loan_entities + + # Verify loan entity data + user1_entity = result_state.loan_entities["user1"] + assert isinstance(user1_entity, MockLoanEntity) + assert isinstance(user1_entity.debt, TokenValues) + assert isinstance(user1_entity.collateral, TokenValues) + assert user1_entity.debt.values["ETH"] == Decimal("1.5") + assert user1_entity.collateral.values["USDC"] == Decimal("3000") + + @pytest.mark.parametrize("health_ratio,expected", [ + (Decimal("1.5"), True), + (Decimal("0.8"), True), + (Decimal("0"), False), + (Decimal("-1"), False), + (Decimal("Infinity"), False) + ]) + def test_health_ratio_is_valid(self, handler, health_ratio, expected): + """Test health_ratio_is_valid method with various inputs""" + assert handler.health_ratio_is_valid(health_ratio) == expected + + def test_fetch_data_handles_db_error(self, handler, mock_db_connector): + """Test fetch_data error handling""" + handler.db_connector = mock_db_connector + mock_db_connector.get_latest_block_loans.side_effect = Exception("Database error") + + with pytest.raises(Exception) as exc_info: + handler.fetch_data(ProtocolIDs.ZKLEND) + assert "Database error" in str(exc_info.value) + + def test_initialize_loan_entities_with_empty_data(self, handler): + """Test initialize_loan_entities with empty data""" + state = MockState() + result_state = handler.initialize_loan_entities(state, []) + assert len(result_state.loan_entities) == 0 + + def test_initialize_loan_entities_maintains_existing_state(self, handler, mock_loan_data): + """Test that initialize_loan_entities preserves existing state data""" + state = MockState() + # Add some pre-existing data + existing_entity = MockLoanEntity() + existing_entity.debt = TokenValues(values={"BTC": Decimal("1.0")}) + existing_entity.collateral = TokenValues(values={"ETH": Decimal("10.0")}) + state.loan_entities["existing_user"] = existing_entity + + result_state = handler.initialize_loan_entities(state, mock_loan_data) + + # Check that new data was added + assert len(result_state.loan_entities) == 3 + # Verify existing data remains + assert "existing_user" in result_state.loan_entities + assert result_state.loan_entities["existing_user"].debt.values["BTC"] == Decimal("1.0") \ No newline at end of file From 82ac1fb7ace340719fb5aedda78472ff6d41cf2c Mon Sep 17 00:00:00 2001 From: vestor-dev <182824106+vestor-dev@users.noreply.github.com> Date: Tue, 26 Nov 2024 13:34:34 +0000 Subject: [PATCH 2/3] updates --- .../tests/test_health_ratio_tests.py | 162 ++++++++++++++++++ 1 file changed, 162 insertions(+) create mode 100644 apps/data_handler/tests/test_health_ratio_tests.py diff --git a/apps/data_handler/tests/test_health_ratio_tests.py b/apps/data_handler/tests/test_health_ratio_tests.py new file mode 100644 index 00000000..5b3a9597 --- /dev/null +++ b/apps/data_handler/tests/test_health_ratio_tests.py @@ -0,0 +1,162 @@ +"""Test the health ratio handlers""" + +import pytest +from decimal import Decimal +from unittest.mock import MagicMock, patch +from datetime import datetime + +from data_handler.handlers.health_ratio_level.health_ratio_handlers import ( + BaseHealthRatioHandler, +) +from shared.state import State, LoanEntity +from shared.types import TokenValues +from shared.constants import ProtocolIDs + + +class MockState(State): + """Mock State class for testing""" + + def __init__(self): + self.loan_entities = {} + self.collateral_interest_rate_models = None + self.debt_interest_rate_models = None + self.interest_rate_models = MagicMock(collateral={}, debt={}) + + def compute_liquidable_debt_at_price(self, *args, **kwargs): + """Mock implementation of abstract method""" + return Decimal("100.0") + + +class MockLoanEntity(LoanEntity): + """Mock LoanEntity class for testing""" + + def __init__(self): + self.debt = None + self.collateral = None + + def compute_collateral_usd(self, **kwargs): + return Decimal("1000.0") + + def compute_debt_usd(self, **kwargs): + return Decimal("500.0") + + def compute_health_factor(self, **kwargs): + return Decimal("2.0") + + def compute_liquidable_debt_at_price(self, *args, **kwargs): + """Mock implementation of abstract method""" + return Decimal("100.0") + + def compute_debt_to_be_liquidated(self, *args, **kwargs): + """Mock implementation of abstract method""" + return Decimal("50.0") + + +@pytest.fixture +def mock_loan_data(): + """Fixture for sample loan data""" + return [ + MagicMock( + user="user1", + debt={"ETH": Decimal("1.5")}, + collateral={"USDC": Decimal("3000")}, + ), + MagicMock( + user="user2", + debt={"ETH": Decimal("2.0")}, + collateral={"USDC": Decimal("4000")}, + ), + ] + + +class TestBaseHealthRatioHandler: + + @pytest.fixture(autouse=True) + def setup(self, mock_db_connector): + """Setup test instance""" + with patch( + "data_handler.handlers.health_ratio_level.health_ratio_handlers.DBConnector" + ) as mock_db: + mock_db.return_value = mock_db_connector + self.handler = BaseHealthRatioHandler( + state_class=MockState, loan_entity_class=MockLoanEntity + ) + self.handler.db_connector = mock_db_connector + + def test_fetch_data(self, mock_db_connector): + """Test fetch_data method""" + mock_db_connector.get_latest_block_loans.return_value = [] + mock_db_connector.get_last_interest_rate_record_by_protocol_id.return_value = ( + MagicMock( + collateral={"USDC": Decimal("0.05")}, debt={"ETH": Decimal("0.08")} + ) + ) + + loan_states, interest_rates = self.handler.fetch_data(ProtocolIDs.ZKLEND) + + assert mock_db_connector.get_latest_block_loans.called + assert mock_db_connector.get_last_interest_rate_record_by_protocol_id.called + assert isinstance(interest_rates.collateral, dict) + assert isinstance(interest_rates.debt, dict) + + def test_initialize_loan_entities(self, mock_loan_data): + """Test initialize_loan_entities method""" + state = MockState() + result = self.handler.initialize_loan_entities(state, mock_loan_data) + + assert len(result.loan_entities) == 2 + assert "user1" in result.loan_entities + assert "user2" in result.loan_entities + + user1_entity = result.loan_entities["user1"] + assert isinstance(user1_entity.debt, TokenValues) + assert isinstance(user1_entity.collateral, TokenValues) + assert user1_entity.debt.values["ETH"] == Decimal("1.5") + assert user1_entity.collateral.values["USDC"] == Decimal("3000") + + def test_initialize_loan_entities_with_empty_data(self): + """Test initialize_loan_entities with empty data""" + state = MockState() + result = self.handler.initialize_loan_entities(state, []) + assert len(result.loan_entities) == 0 + + @pytest.mark.parametrize( + "health_ratio,expected", + [ + (Decimal("1.5"), True), + (Decimal("0.8"), True), + (Decimal("0"), False), + (Decimal("-1"), False), + (Decimal("Infinity"), False), + ], + ) + def test_health_ratio_is_valid(self, health_ratio, expected): + """Test health_ratio_is_valid with various inputs""" + assert self.handler.health_ratio_is_valid(health_ratio) == expected + + def test_fetch_data_handles_db_error(self, mock_db_connector): + """Test fetch_data error handling""" + mock_db_connector.get_latest_block_loans.side_effect = Exception( + "Database error" + ) + + with pytest.raises(Exception) as exc_info: + self.handler.fetch_data(ProtocolIDs.ZKLEND) + assert "Database error" in str(exc_info.value) + + def test_initialize_loan_entities_maintains_existing_state(self, mock_loan_data): + """Test that initialize_loan_entities preserves existing state""" + state = MockState() + # Add pre-existing data + existing_entity = MockLoanEntity() + existing_entity.debt = TokenValues(values={"BTC": Decimal("1.0")}) + existing_entity.collateral = TokenValues(values={"ETH": Decimal("10.0")}) + state.loan_entities["existing_user"] = existing_entity + + result_state = self.handler.initialize_loan_entities(state, mock_loan_data) + + assert len(result_state.loan_entities) == 3 + assert "existing_user" in result_state.loan_entities + assert result_state.loan_entities["existing_user"].debt.values[ + "BTC" + ] == Decimal("1.0") From 4edad4e05ee776b33e79986891f09e52dd7ff4b2 Mon Sep 17 00:00:00 2001 From: vestor-dev <182824106+vestor-dev@users.noreply.github.com> Date: Tue, 26 Nov 2024 23:58:06 +0000 Subject: [PATCH 3/3] updates --- .../test_health_ratio_tests.py | 133 ------------------ 1 file changed, 133 deletions(-) delete mode 100644 apps/data_handler/tests/health_ratio_test/test_health_ratio_tests.py diff --git a/apps/data_handler/tests/health_ratio_test/test_health_ratio_tests.py b/apps/data_handler/tests/health_ratio_test/test_health_ratio_tests.py deleted file mode 100644 index d0e02bc8..00000000 --- a/apps/data_handler/tests/health_ratio_test/test_health_ratio_tests.py +++ /dev/null @@ -1,133 +0,0 @@ -import pytest -from decimal import Decimal -from unittest.mock import MagicMock, patch -from datetime import datetime - -from data_handler.handlers.health_ratio_level.health_ratio_handlers import BaseHealthRatioHandler -from shared.state import State, LoanEntity -from shared.types import TokenValues -from shared.constants import ProtocolIDs - -class MockState(State): - """Mock State class for testing""" - pass - -class MockLoanEntity(LoanEntity): - """Mock LoanEntity class for testing""" - pass - -@pytest.fixture -def mock_loan_data(): - """Fixture for sample loan data""" - return [ - MagicMock( - user="user1", - debt={"ETH": Decimal("1.5")}, - collateral={"USDC": Decimal("3000")} - ), - MagicMock( - user="user2", - debt={"ETH": Decimal("2.0")}, - collateral={"USDC": Decimal("4000")} - ) - ] - -@pytest.fixture -def mock_interest_rates(): - """Fixture for sample interest rate data""" - return MagicMock( - collateral={"USDC": Decimal("0.05")}, - debt={"ETH": Decimal("0.08")} - ) - -class TestBaseHealthRatioHandler: - - @pytest.fixture - def handler(self): - """Create a BaseHealthRatioHandler instance for testing""" - return BaseHealthRatioHandler( - state_class=MockState, - loan_entity_class=MockLoanEntity - ) - - def test_initialization(self, handler): - """Test proper initialization of BaseHealthRatioHandler""" - assert isinstance(handler, BaseHealthRatioHandler) - assert handler.state_class == MockState - assert handler.loan_entity_class == MockLoanEntity - assert handler.db_connector is not None - - def test_fetch_data(self, handler, mock_db_connector, mock_loan_data, mock_interest_rates): - """Test fetch_data method""" - handler.db_connector = mock_db_connector - mock_db_connector.get_latest_block_loans.return_value = mock_loan_data - mock_db_connector.get_last_interest_rate_record_by_protocol_id.return_value = mock_interest_rates - - loan_states, interest_rates = handler.fetch_data(ProtocolIDs.ZKLEND) - - assert loan_states == mock_loan_data - assert interest_rates == mock_interest_rates - mock_db_connector.get_latest_block_loans.assert_called_once() - mock_db_connector.get_last_interest_rate_record_by_protocol_id.assert_called_once_with( - protocol_id=ProtocolIDs.ZKLEND - ) - - def test_initialize_loan_entities(self, handler, mock_loan_data): - """Test initialize_loan_entities method""" - state = MockState() - result_state = handler.initialize_loan_entities(state, mock_loan_data) - - assert len(result_state.loan_entities) == 2 - assert "user1" in result_state.loan_entities - assert "user2" in result_state.loan_entities - - # Verify loan entity data - user1_entity = result_state.loan_entities["user1"] - assert isinstance(user1_entity, MockLoanEntity) - assert isinstance(user1_entity.debt, TokenValues) - assert isinstance(user1_entity.collateral, TokenValues) - assert user1_entity.debt.values["ETH"] == Decimal("1.5") - assert user1_entity.collateral.values["USDC"] == Decimal("3000") - - @pytest.mark.parametrize("health_ratio,expected", [ - (Decimal("1.5"), True), - (Decimal("0.8"), True), - (Decimal("0"), False), - (Decimal("-1"), False), - (Decimal("Infinity"), False) - ]) - def test_health_ratio_is_valid(self, handler, health_ratio, expected): - """Test health_ratio_is_valid method with various inputs""" - assert handler.health_ratio_is_valid(health_ratio) == expected - - def test_fetch_data_handles_db_error(self, handler, mock_db_connector): - """Test fetch_data error handling""" - handler.db_connector = mock_db_connector - mock_db_connector.get_latest_block_loans.side_effect = Exception("Database error") - - with pytest.raises(Exception) as exc_info: - handler.fetch_data(ProtocolIDs.ZKLEND) - assert "Database error" in str(exc_info.value) - - def test_initialize_loan_entities_with_empty_data(self, handler): - """Test initialize_loan_entities with empty data""" - state = MockState() - result_state = handler.initialize_loan_entities(state, []) - assert len(result_state.loan_entities) == 0 - - def test_initialize_loan_entities_maintains_existing_state(self, handler, mock_loan_data): - """Test that initialize_loan_entities preserves existing state data""" - state = MockState() - # Add some pre-existing data - existing_entity = MockLoanEntity() - existing_entity.debt = TokenValues(values={"BTC": Decimal("1.0")}) - existing_entity.collateral = TokenValues(values={"ETH": Decimal("10.0")}) - state.loan_entities["existing_user"] = existing_entity - - result_state = handler.initialize_loan_entities(state, mock_loan_data) - - # Check that new data was added - assert len(result_state.loan_entities) == 3 - # Verify existing data remains - assert "existing_user" in result_state.loan_entities - assert result_state.loan_entities["existing_user"].debt.values["BTC"] == Decimal("1.0") \ No newline at end of file