]>
git.immae.eu Git - perso/Immae/Projets/Cryptomonnaies/Cryptoportfolio/Trader.git/blob - tests/test_main.py
3735a3be58bbe81a7cd948829b77eee27e0249be
4 @unittest.skipUnless ( "unit" in limits
, "Unit skipped" )
5 class MainTest ( WebMockTestCase
):
6 def test_make_order ( self
):
7 self
. m
. get_ticker
. return_value
= {
14 with self
. subTest ( description
= "nominal case" ):
15 main
. make_order ( self
. m
, 10 , "ETH" )
17 self
. m
. report
. log_stage
. assert_has_calls ([
18 mock
. call ( "make_order_begin" ),
19 mock
. call ( "make_order_end" ),
21 self
. m
. balances
. fetch_balances
. assert_has_calls ([
22 mock
. call ( tag
= "make_order_begin" ),
23 mock
. call ( tag
= "make_order_end" ),
25 self
. m
. trades
. all
. append
. assert_called_once ()
26 trade
= self
. m
. trades
. all
. append
. mock_calls
[ 0 ][ 1 ][ 0 ]
27 self
. assertEqual ( False , trade
. orders
[ 0 ]. close_if_possible
)
28 self
. assertEqual ( 0 , trade
. value_from
)
29 self
. assertEqual ( "ETH" , trade
. currency
)
30 self
. assertEqual ( "BTC" , trade
. base_currency
)
31 self
. m
. report
. log_orders
. assert_called_once_with ([ trade
. orders
[ 0 ]], None , "average" )
32 self
. m
. trades
. run_orders
. assert_called_once_with ()
33 self
. m
. follow_orders
. assert_called_once_with ()
35 order
= trade
. orders
[ 0 ]
36 self
. assertEqual ( D ( "0.10" ), order
. rate
)
39 with self
. subTest ( compute_value
= "default" ):
40 main
. make_order ( self
. m
, 10 , "ETH" , action
= "dispose" ,
43 trade
= self
. m
. trades
. all
. append
. mock_calls
[ 0 ][ 1 ][ 0 ]
44 order
= trade
. orders
[ 0 ]
45 self
. assertEqual ( D ( "0.11" ), order
. rate
)
48 with self
. subTest ( follow
= False ):
49 result
= main
. make_order ( self
. m
, 10 , "ETH" , follow
= False )
51 self
. m
. report
. log_stage
. assert_has_calls ([
52 mock
. call ( "make_order_begin" ),
53 mock
. call ( "make_order_end_not_followed" ),
55 self
. m
. balances
. fetch_balances
. assert_called_once_with ( tag
= "make_order_begin" )
57 self
. m
. trades
. all
. append
. assert_called_once ()
58 trade
= self
. m
. trades
. all
. append
. mock_calls
[ 0 ][ 1 ][ 0 ]
59 self
. assertEqual ( 0 , trade
. value_from
)
60 self
. assertEqual ( "ETH" , trade
. currency
)
61 self
. assertEqual ( "BTC" , trade
. base_currency
)
62 self
. m
. report
. log_orders
. assert_called_once_with ([ trade
. orders
[ 0 ]], None , "average" )
63 self
. m
. trades
. run_orders
. assert_called_once_with ()
64 self
. m
. follow_orders
. assert_not_called ()
65 self
. assertEqual ( trade
. orders
[ 0 ], result
)
68 with self
. subTest ( base_currency
= "USDT" ):
69 main
. make_order ( self
. m
, 1 , "BTC" , base_currency
= "USDT" )
71 trade
= self
. m
. trades
. all
. append
. mock_calls
[ 0 ][ 1 ][ 0 ]
72 self
. assertEqual ( "BTC" , trade
. currency
)
73 self
. assertEqual ( "USDT" , trade
. base_currency
)
76 with self
. subTest ( close_if_possible
= True ):
77 main
. make_order ( self
. m
, 10 , "ETH" , close_if_possible
= True )
79 trade
= self
. m
. trades
. all
. append
. mock_calls
[ 0 ][ 1 ][ 0 ]
80 self
. assertEqual ( True , trade
. orders
[ 0 ]. close_if_possible
)
83 with self
. subTest ( action
= "dispose" ):
84 main
. make_order ( self
. m
, 10 , "ETH" , action
= "dispose" )
86 trade
= self
. m
. trades
. all
. append
. mock_calls
[ 0 ][ 1 ][ 0 ]
87 self
. assertEqual ( 0 , trade
. value_to
)
88 self
. assertEqual ( 1 , trade
. value_from
. value
)
89 self
. assertEqual ( "ETH" , trade
. currency
)
90 self
. assertEqual ( "BTC" , trade
. base_currency
)
93 with self
. subTest ( compute_value
= "default" ):
94 main
. make_order ( self
. m
, 10 , "ETH" , action
= "dispose" ,
97 trade
= self
. m
. trades
. all
. append
. mock_calls
[ 0 ][ 1 ][ 0 ]
98 self
. assertEqual ( D ( "0.9" ), trade
. value_from
. value
)
100 def test_get_user_market ( self
):
101 with mock
. patch ( "main.fetch_markets" ) as main_fetch_markets
, \
102 mock
. patch ( "main.parse_args" ) as main_parse_args
, \
103 mock
. patch ( "main.parse_config" ) as main_parse_config
:
104 with self
. subTest ( debug
= False ):
105 main_parse_args
. return_value
= self
. market_args ()
106 main_fetch_markets
. return_value
= [( 1 , {"key": "market_config"}
, 3 , { "foo": "bar" }
)]
107 m
= main
. get_user_market ( "config_path.ini" , 1 )
109 self
. assertIsInstance ( m
, market
. Market
)
110 self
. assertFalse ( m
. debug
)
111 self
. assertEqual ( "bar" , m
. options
[ "foo" ])
112 main_parse_args
. assert_called_once_with ([ "--config" , "config_path.ini" ])
114 main_parse_args
. reset_mock ()
115 with self
. subTest ( debug
= True ):
116 main_parse_args
. return_value
= self
. market_args ( debug
= True )
117 main_fetch_markets
. return_value
= [( 1 , {"key": "market_config"}
, 3 , { "foo": "bar" }
)]
118 m
= main
. get_user_market ( "config_path.ini" , 1 , debug
= True )
120 self
. assertIsInstance ( m
, market
. Market
)
121 self
. assertTrue ( m
. debug
)
122 main_parse_args
. assert_called_once_with ([ "--config" , "config_path.ini" , "--debug" ])
124 def test_parse_liquidity ( self
):
125 self
. assertEqual ( "high" , main
. parse_liquidity ( "high-liquidity" ))
126 self
. assertEqual ( "medium" , main
. parse_liquidity ( "medium-liquidity" ))
127 self
. assertIsNone ( main
. parse_liquidity ( "foo" ))
129 def test_process ( self
):
130 with mock
. patch ( "market.Market" ) as market_mock
, \
131 mock
. patch ( 'sys.stdout' , new_callable
= StringIO
) as stdout_mock
:
133 args_mock
= mock
. Mock ()
134 args_mock
. action
= "action"
135 args_mock
. config
= "config"
136 args_mock
. user
= "user"
137 args_mock
. debug
= "debug"
138 args_mock
. before
= "before"
139 args_mock
. after
= "after"
140 self
. assertEqual ( "" , stdout_mock
. getvalue ())
142 main
. process ( "config" , 3 , 1 , args_mock
, "options" )
144 market_mock
. from_config
. assert_has_calls ([
145 mock
. call ( "config" , args_mock
, market_id
= 3 , user_id
= 1 , options
= "options" ),
146 mock
. call (). process ( "action" , before
= "before" , after
= "after" ),
149 with self
. subTest ( exception
= True ):
150 market_mock
. from_config
. side_effect
= Exception ( "boo" )
151 main
. process ( 3 , "config" , 1 , args_mock
, "options" )
152 self
. assertEqual ( "Exception: boo \n " , stdout_mock
. getvalue ())
155 with self
. subTest ( parallel
= False ):
156 with mock
. patch ( "main.parse_args" ) as parse_args
, \
157 mock
. patch ( "main.parse_config" ) as parse_config
, \
158 mock
. patch ( "main.fetch_markets" ) as fetch_markets
, \
159 mock
. patch ( "main.process" ) as process
:
161 args_mock
= mock
. Mock ()
162 args_mock
. parallel
= False
163 args_mock
. user
= "user"
164 parse_args
. return_value
= args_mock
166 fetch_markets
. return_value
= [
167 [ 3 , "config1" , 1 , "options" ],
168 [ 1 , "config2" , 2 , "options" ]
171 main
. main ([ "Foo" , "Bar" ])
173 parse_args
. assert_called_with ([ "Foo" , "Bar" ])
174 parse_config
. assert_called_with ( args_mock
)
175 fetch_markets
. assert_called_with ( "user" )
177 self
. assertEqual ( 2 , process
. call_count
)
178 process
. assert_has_calls ([
179 mock
. call ( "config1" , 3 , 1 , args_mock
, "options" ),
180 mock
. call ( "config2" , 1 , 2 , args_mock
, "options" ),
183 with self
. subTest ( parallel
= True ):
184 with mock
. patch ( "main.parse_args" ) as parse_args
, \
185 mock
. patch ( "main.parse_config" ) as parse_config
, \
186 mock
. patch ( "main.fetch_markets" ) as fetch_markets
, \
187 mock
. patch ( "main.process" ) as process
, \
188 mock
. patch ( "store.Portfolio.start_worker" ) as start
, \
189 mock
. patch ( "store.Portfolio.stop_worker" ) as stop
:
191 args_mock
= mock
. Mock ()
192 args_mock
. parallel
= True
193 args_mock
. user
= "user"
194 parse_args
. return_value
= args_mock
196 fetch_markets
. return_value
= [
197 [ 3 , "config1" , 1 , "options" ],
198 [ 1 , "config2" , 2 , "options" ]
201 main
. main ([ "Foo" , "Bar" ])
203 parse_args
. assert_called_with ([ "Foo" , "Bar" ])
204 parse_config
. assert_called_with ( args_mock
)
205 fetch_markets
. assert_called_with ( "user" )
207 stop
. assert_called_once_with ()
208 start
. assert_called_once_with ()
209 self
. assertEqual ( 2 , process
. call_count
)
210 process
. assert_has_calls ([
211 mock
. call
.__ bool
__ (),
212 mock
. call ( "config1" , 3 , 1 , args_mock
, "options" ),
213 mock
. call
.__ bool
__ (),
214 mock
. call ( "config2" , 1 , 2 , args_mock
, "options" ),
217 with self
. subTest ( quiet
= True ):
218 with mock
. patch ( "main.parse_args" ) as parse_args
, \
219 mock
. patch ( "main.parse_config" ) as parse_config
, \
220 mock
. patch ( "main.fetch_markets" ) as fetch_markets
, \
221 mock
. patch ( "store.Portfolio.report" ) as report
, \
222 mock
. patch ( "main.process" ) as process
:
224 args_mock
= mock
. Mock ()
225 args_mock
. parallel
= False
226 args_mock
. quiet
= True
227 args_mock
. user
= "user"
228 parse_args
. return_value
= args_mock
230 fetch_markets
. return_value
= [
231 [ 3 , "config1" , 1 , "options" ],
232 [ 1 , "config2" , 2 , "options" ]
235 main
. main ([ "Foo" , "Bar" ])
237 report
. set_verbose
. assert_called_once_with ( False )
239 with self
. subTest ( quiet
= False ):
240 with mock
. patch ( "main.parse_args" ) as parse_args
, \
241 mock
. patch ( "main.parse_config" ) as parse_config
, \
242 mock
. patch ( "main.fetch_markets" ) as fetch_markets
, \
243 mock
. patch ( "store.Portfolio.report" ) as report
, \
244 mock
. patch ( "main.process" ) as process
:
246 args_mock
= mock
. Mock ()
247 args_mock
. parallel
= False
248 args_mock
. quiet
= False
249 args_mock
. user
= "user"
250 parse_args
. return_value
= args_mock
252 fetch_markets
. return_value
= [
253 [ 3 , "config1" , 1 , "options" ],
254 [ 1 , "config2" , 2 , "options" ]
257 main
. main ([ "Foo" , "Bar" ])
259 report
. set_verbose
. assert_called_once_with ( True )
262 @mock.patch.object ( main
. sys
, "exit" )
263 @mock.patch ( "main.os" )
264 def test_parse_config ( self
, os
, exit
):
265 with self
. subTest ( report_path
= None ), \
266 mock
. patch
. object ( main
. dbs
, "connect_psql" ) as psql
, \
267 mock
. patch
. object ( main
. dbs
, "connect_redis" ) as redis
:
268 args
= main
. configargparse
. Namespace (**{
270 "redis_host" : "rhost" ,
274 main
. parse_config ( args
)
275 psql
. assert_called_once_with ( args
)
276 redis
. assert_called_once_with ( args
)
278 with self
. subTest ( report_path
= None , db
= None ), \
279 mock
. patch
. object ( main
. dbs
, "connect_psql" ) as psql
, \
280 mock
. patch
. object ( main
. dbs
, "connect_redis" ) as redis
:
281 args
= main
. configargparse
. Namespace (**{
283 "redis_host" : "rhost" ,
287 main
. parse_config ( args
)
288 psql
. assert_not_called ()
289 redis
. assert_called_once_with ( args
)
291 with self
. subTest ( report_path
= None , redis
= None ), \
292 mock
. patch
. object ( main
. dbs
, "connect_psql" ) as psql
, \
293 mock
. patch
. object ( main
. dbs
, "connect_redis" ) as redis
:
294 args
= main
. configargparse
. Namespace (**{
300 main
. parse_config ( args
)
301 redis
. assert_not_called ()
302 psql
. assert_called_once_with ( args
)
304 with self
. subTest ( report_path
= "present" ), \
305 mock
. patch
. object ( main
. dbs
, "connect_psql" ) as psql
, \
306 mock
. patch
. object ( main
. dbs
, "connect_redis" ) as redis
:
307 args
= main
. configargparse
. Namespace (**{
309 "redis_host" : "rhost" ,
310 "report_path" : "report_path" ,
313 os
. path
. exists
. return_value
= False
315 main
. parse_config ( args
)
317 os
. path
. exists
. assert_called_once_with ( "report_path" )
318 os
. makedirs
. assert_called_once_with ( "report_path" )
320 def test_parse_args ( self
):
321 with self
. subTest ( config
= "config.ini" ):
322 args
= main
. parse_args ([])
323 self
. assertEqual ( "config.ini" , args
. config
)
324 self
. assertFalse ( args
. before
)
325 self
. assertFalse ( args
. after
)
326 self
. assertFalse ( args
. debug
)
328 args
= main
. parse_args ([ "--before" , "--after" , "--debug" ])
329 self
. assertTrue ( args
. before
)
330 self
. assertTrue ( args
. after
)
331 self
. assertTrue ( args
. debug
)
333 with self
. subTest ( config
= "inexistant" ), \
334 self
. assertRaises ( SystemExit ), \
335 mock
. patch ( 'sys.stderr' , new_callable
= StringIO
) as stdout_mock
:
336 args
= main
. parse_args ([ "--config" , "foo.bar" ])
338 @mock.patch.object ( main
. dbs
, "psql" )
339 def test_fetch_markets ( self
, psql
):
340 cursor_mock
= mock
. MagicMock ()
341 cursor_mock
.__ iter
__ . return_value
= [
342 ( 1 , "cfg" , 1 , "high-liquidity" ),
343 ( 2 , "cfg2" , 3 , "medium-liquidity" )
346 psql
. cursor
. return_value
= cursor_mock
348 with self
. subTest ( user
= None ):
349 rows
= list ( main
. fetch_markets ( None ))
351 cursor_mock
. execute
. assert_called_once_with ( "SELECT id,config,user_id,portfolio_profile FROM market_configs_augmented WHERE status='enabled'" )
354 ( 1 , 'cfg' , 1 , {'liquidity': 'high'}
),
355 ( 2 , 'cfg2' , 3 , {'liquidity': 'medium'}
)
358 cursor_mock
. execute
. reset_mock ()
359 with self
. subTest ( user
= 1 ):
360 rows
= list ( main
. fetch_markets ( 1 ))
362 cursor_mock
. execute
. assert_called_once_with ( "SELECT id,config,user_id,portfolio_profile FROM market_configs_augmented WHERE status='enabled' AND user_id = %s " , [ 1 ])
365 ( 1 , 'cfg' , 1 , {'liquidity': 'high'}
),
366 ( 2 , 'cfg2' , 3 , {'liquidity': 'medium'}
)