1
+ import pytest
2
+ from decimal import Decimal
3
+ from unittest .mock import AsyncMock , MagicMock , patch
4
+
5
+ from data_handler .handlers .loan_states .vesu .events import VesuLoanEntity
6
+ from data_handler .db .models .liquidable_debt import HealthRatioLevel
7
+
8
+
9
+ @pytest .fixture
10
+ def vesu_entity ():
11
+ """Create VesuLoanEntity instance for testing"""
12
+ with patch ("data_handler.handlers.loan_states.vesu.events.StarknetClient" ), \
13
+ patch ("data_handler.handlers.loan_states.vesu.events.DBConnector" ):
14
+ entity = VesuLoanEntity ()
15
+ entity .session = AsyncMock ()
16
+ return entity
17
+
18
+
19
+ @pytest .fixture
20
+ def mock_session ():
21
+ """Mock database session"""
22
+ session = AsyncMock ()
23
+ session .add = MagicMock ()
24
+ session .commit = AsyncMock ()
25
+ session .refresh = AsyncMock ()
26
+ return session
27
+
28
+
29
+ @pytest .fixture
30
+ def mock_vesu_position ():
31
+ """Mock VesuPosition object"""
32
+ position = MagicMock ()
33
+ position .pool_id = "456"
34
+ position .collateral_asset = "789"
35
+ position .debt_asset = "101112"
36
+ position .get .return_value = 1000000
37
+
38
+
39
+ class TestVesuLoanEntity :
40
+
41
+ @pytest .mark .asyncio
42
+ async def test_save_health_ratio_level (self , vesu_entity , mock_session ):
43
+ """Test saving health ratio level to database"""
44
+ result = await vesu_entity .save_health_ratio_level (
45
+ session = mock_session ,
46
+ timestamp = 1234567890 ,
47
+ user_id = "0x123" ,
48
+ value = Decimal ("1.5" ),
49
+ protocol_id = "vesu" ,
50
+ )
51
+
52
+ mock_session .add .assert_called_once ()
53
+ mock_session .commit .assert_called_once ()
54
+ mock_session .refresh .assert_called_once ()
55
+
56
+ added_record = mock_session .add .call_args [0 ][0 ]
57
+ assert isinstance (added_record , HealthRatioLevel )
58
+ assert added_record .timestamp == 1234567890
59
+ assert added_record .user_id == "0x123"
60
+ assert added_record .value == Decimal ("1.5" )
61
+ assert added_record .protocol_id == "vesu"
62
+
63
+ @pytest .mark .asyncio
64
+ async def test_calculate_health_factor_with_session (
65
+ self , vesu_entity , mock_session , mock_vesu_position
66
+ ):
67
+ """Test calculate_health_factor saves to database when session provided"""
68
+ mock_scalars = MagicMock ()
69
+ mock_scalars .all .return_value = [mock_vesu_position ]
70
+ mock_result = MagicMock ()
71
+ mock_result .scalars .return_value = mock_scalars
72
+ vesu_entity .session .execute = AsyncMock (return_value = mock_result )
73
+
74
+ with patch .object (
75
+ vesu_entity , "_get_position_data"
76
+ ) as mock_position , patch .object (
77
+ vesu_entity , "_get_collateral_value"
78
+ ) as mock_collateral , patch .object (
79
+ vesu_entity , "_get_asset_config"
80
+ ) as mock_asset_config , patch .object (
81
+ vesu_entity , "_calculate_debt"
82
+ ) as mock_debt , patch .object (
83
+ vesu_entity , "get_ltv_config"
84
+ ) as mock_ltv , patch .object (
85
+ vesu_entity , "_get_token_decimals"
86
+ ) as mock_decimals , patch .object (
87
+ vesu_entity , "fetch_token_price"
88
+ ) as mock_price , patch .object (
89
+ vesu_entity , "save_health_ratio_level"
90
+ ) as mock_save :
91
+
92
+ mock_position .return_value = (
93
+ 100 ,
94
+ 0 ,
95
+ 200 ,
96
+ 0 ,
97
+ )
98
+ mock_collateral .return_value = Decimal ("1000" )
99
+ mock_asset_config .return_value = [
100
+ 0
101
+ ] * 16
102
+ mock_debt .return_value = Decimal ("500" )
103
+ mock_ltv .return_value = (Decimal ("80" ),)
104
+ mock_decimals .return_value = Decimal ("1000000" )
105
+ mock_price .return_value = Decimal ("2000" )
106
+
107
+ result = await vesu_entity .calculate_health_factor (
108
+ 123 , session = mock_session
109
+ )
110
+
111
+ mock_save .assert_called_once_with (
112
+ session = mock_session ,
113
+ timestamp = 1000000 ,
114
+ user_id = "123" ,
115
+ value = result ["0x1c8" ],
116
+ protocol_id = 456 ,
117
+ )
118
+
119
+ @pytest .mark .asyncio
120
+ async def test_calculate_health_factor_without_session (self , vesu_entity ):
121
+ """Test calculate_health_factor doesn't save when no session provided"""
122
+ mock_scalars = MagicMock ()
123
+ mock_scalars .all .return_value = []
124
+ mock_result = MagicMock ()
125
+ mock_result .scalars .return_value = mock_scalars
126
+ vesu_entity .session .execute = AsyncMock (return_value = mock_result )
127
+
128
+ with patch .object (vesu_entity , "save_health_ratio_level" ) as mock_save :
129
+ result = await vesu_entity .calculate_health_factor (123 )
130
+
131
+ mock_save .assert_not_called ()
132
+ assert result == {}
0 commit comments