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: add test for zklendLoanEntity #279

Merged
merged 4 commits into from
Nov 2, 2024
Merged
Changes from 2 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
178 changes: 178 additions & 0 deletions apps/data_handler/tests/loan_state/test_zklend_loan_entity.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,178 @@
import pytest
import decimal
from unittest.mock import MagicMock, patch
from shared.types import InterestRateModels, Portfolio, Prices, TokenParameters
from data_handler.handlers.loan_states.zklend.events import ZkLendLoanEntity
from shared.loan_entity import LoanEntity

@pytest.fixture
def zklend_loan_entity():
"""Fixture providing a basic ZkLendLoanEntity instance with mocked methods."""
with patch.object(LoanEntity, 'compute_collateral_usd') as mock_collateral_usd, \
patch.object(LoanEntity, 'compute_debt_usd') as mock_debt_usd:

# Setup default return values for the mocked methods
mock_collateral_usd.return_value = decimal.Decimal('2000')
mock_debt_usd.return_value = decimal.Decimal('1000')

entity = ZkLendLoanEntity()
entity.compute_collateral_usd = mock_collateral_usd
entity.compute_debt_usd = mock_debt_usd
return entity

@pytest.fixture
def mock_token_parameters():
"""Fixture providing mock token parameters."""
eth_params = MagicMock()
eth_params.collateral_factor = decimal.Decimal('0.8')
eth_params.liquidation_bonus = decimal.Decimal('0.1')
eth_params.underlying_address = 'ETH'

usdc_params = MagicMock()
usdc_params.collateral_factor = decimal.Decimal('0.85')
usdc_params.liquidation_bonus = decimal.Decimal('0.1')
usdc_params.underlying_address = 'USDC'

return {
'ETH': eth_params,
'USDC': usdc_params
}

@pytest.fixture
def mock_prices():
"""Fixture providing mock token prices."""
return {
'ETH': decimal.Decimal('2000'),
'USDC': decimal.Decimal('1')
}

@pytest.fixture
def mock_interest_rate_models():
"""Fixture providing mock interest rate models."""
return {
'ETH': decimal.Decimal('1.05'),
'USDC': decimal.Decimal('1.02')
}

class TestZkLendLoanEntity:
def test_initialization(self, zklend_loan_entity):
"""Test proper initialization of ZkLendLoanEntity."""
assert isinstance(zklend_loan_entity.deposit, Portfolio)
assert isinstance(zklend_loan_entity.collateral_enabled, dict)
assert len(zklend_loan_entity.deposit) == 0
assert len(zklend_loan_entity.collateral_enabled) == 0

def test_compute_health_factor_no_debt(self, zklend_loan_entity, mock_prices):
"""Test health factor computation when there's no debt."""
zklend_loan_entity.collateral['ETH'] = decimal.Decimal('1.0')
zklend_loan_entity.compute_debt_usd.return_value = decimal.Decimal('0')

health_factor = zklend_loan_entity.compute_health_factor(
standardized=False,
prices=mock_prices
)

assert health_factor == decimal.Decimal('Inf')

def test_compute_health_factor_with_debt(self, zklend_loan_entity, mock_prices, mock_interest_rate_models):
"""Test health factor computation with both collateral and debt."""
zklend_loan_entity.collateral['ETH'] = decimal.Decimal('1.0')
zklend_loan_entity.debt['USDC'] = decimal.Decimal('1000.0')

zklend_loan_entity.compute_collateral_usd.return_value = decimal.Decimal('2000')
zklend_loan_entity.compute_debt_usd.return_value = decimal.Decimal('1000')

health_factor = zklend_loan_entity.compute_health_factor(
standardized=False,
collateral_interest_rate_models=mock_interest_rate_models,
debt_interest_rate_models=mock_interest_rate_models,
prices=mock_prices
)

assert float(health_factor) == pytest.approx(2.0)

def test_compute_health_factor_with_risk_adjustment(
self, zklend_loan_entity, mock_prices, mock_token_parameters, mock_interest_rate_models
):
"""Test health factor computation with risk adjustment factors."""
risk_adjusted_collateral_usd = decimal.Decimal('1600') # 2000 * 0.8
debt_usd = decimal.Decimal('1000')

health_factor = zklend_loan_entity.compute_health_factor(
standardized=True,
prices=mock_prices,
risk_adjusted_collateral_usd=risk_adjusted_collateral_usd,
debt_usd=debt_usd
)

assert float(health_factor) == pytest.approx(1.6)

@pytest.mark.parametrize("collateral_amount,debt_amount,health_factor,expected_result", [
(0, 1000, decimal.Decimal('0.5'), True),
(1, 3000, decimal.Decimal('0.8'), True),
(1, 1000, decimal.Decimal('2.0'), False),
(2, 1000, decimal.Decimal('4.0'), False),
])
def test_is_liquidatable(
self,
zklend_loan_entity,
mock_prices,
collateral_amount,
debt_amount,
health_factor,
expected_result
):
"""Tests different scenarios for liquidation eligibility."""
zklend_loan_entity.collateral['ETH'] = decimal.Decimal(str(collateral_amount))
zklend_loan_entity.debt['USDC'] = decimal.Decimal(str(debt_amount))

# Setup the mock to return our predetermined health factor
collateral_usd = decimal.Decimal(str(collateral_amount)) * decimal.Decimal('2000')
debt_usd = decimal.Decimal(str(debt_amount))
zklend_loan_entity.compute_collateral_usd.return_value = collateral_usd
zklend_loan_entity.compute_debt_usd.return_value = debt_usd

actual_health_factor = zklend_loan_entity.compute_health_factor(
standardized=False,
prices=mock_prices
)

is_liquidatable = actual_health_factor < decimal.Decimal('1.0')
assert is_liquidatable == expected_result

def test_negative_values(self, zklend_loan_entity):
"""Test handling of negative values."""
with patch.object(Portfolio, 'increase_value') as mock_increase:
mock_increase.side_effect = ValueError("Value cannot be negative")
with pytest.raises(ValueError):
zklend_loan_entity.collateral.increase_value('ETH', decimal.Decimal('-1.0'))

with pytest.raises(ValueError):
zklend_loan_entity.debt.increase_value('USDC', decimal.Decimal('-1000.0'))

def test_deposit_and_collateral_enabled_interaction(self, zklend_loan_entity):
"""Test interaction between deposit and collateral_enabled flags."""
token = 'ETH'
deposit_amount = decimal.Decimal('1.0')

# Add deposit
zklend_loan_entity.deposit[token] = deposit_amount
assert zklend_loan_entity.deposit[token] == deposit_amount

# Initially, collateral should not be enabled
assert not zklend_loan_entity.collateral_enabled.get(token, False)
assert token not in zklend_loan_entity.collateral

# Enable collateral
zklend_loan_entity.collateral_enabled[token] = True
zklend_loan_entity.collateral[token] = deposit_amount

assert zklend_loan_entity.collateral[token] == zklend_loan_entity.deposit[token]

def test_token_settings(self):
"""Test token settings configuration."""
assert hasattr(ZkLendLoanEntity, 'TOKEN_SETTINGS')
assert isinstance(ZkLendLoanEntity.TOKEN_SETTINGS, dict)

if __name__ == '__main__':
pytest.main(['-v'])
Loading