]>
git.immae.eu Git - perso/Immae/Projets/Cryptomonnaies/Cryptoportfolio/Trader.git/blob - tests/test_main.py
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)]
107 m
= main
.get_user_market("config_path.ini", 1)
109 self
.assertIsInstance(m
, market
.Market
)
110 self
.assertFalse(m
.debug
)
111 main_parse_args
.assert_called_once_with(["--config", "config_path.ini"])
113 main_parse_args
.reset_mock()
114 with self
.subTest(debug
=True):
115 main_parse_args
.return_value
= self
.market_args(debug
=True)
116 main_fetch_markets
.return_value
= [(1, {"key": "market_config"}
, 3)]
117 m
= main
.get_user_market("config_path.ini", 1, debug
=True)
119 self
.assertIsInstance(m
, market
.Market
)
120 self
.assertTrue(m
.debug
)
121 main_parse_args
.assert_called_once_with(["--config", "config_path.ini", "--debug"])
123 def test_process(self
):
124 with mock
.patch("market.Market") as market_mock
,\
125 mock
.patch('sys.stdout', new_callable
=StringIO
) as stdout_mock
:
127 args_mock
= mock
.Mock()
128 args_mock
.action
= "action"
129 args_mock
.config
= "config"
130 args_mock
.user
= "user"
131 args_mock
.debug
= "debug"
132 args_mock
.before
= "before"
133 args_mock
.after
= "after"
134 self
.assertEqual("", stdout_mock
.getvalue())
136 main
.process("config", 3, 1, args_mock
)
138 market_mock
.from_config
.assert_has_calls([
139 mock
.call("config", args_mock
, market_id
=3, user_id
=1),
140 mock
.call().process("action", before
="before", after
="after"),
143 with self
.subTest(exception
=True):
144 market_mock
.from_config
.side_effect
= Exception("boo")
145 main
.process(3, "config", 1, args_mock
)
146 self
.assertEqual("Exception: boo\n", stdout_mock
.getvalue())
149 with self
.subTest(parallel
=False):
150 with mock
.patch("main.parse_args") as parse_args
,\
151 mock
.patch("main.parse_config") as parse_config
,\
152 mock
.patch("main.fetch_markets") as fetch_markets
,\
153 mock
.patch("main.process") as process
:
155 args_mock
= mock
.Mock()
156 args_mock
.parallel
= False
157 args_mock
.user
= "user"
158 parse_args
.return_value
= args_mock
160 fetch_markets
.return_value
= [[3, "config1", 1], [1, "config2", 2]]
162 main
.main(["Foo", "Bar"])
164 parse_args
.assert_called_with(["Foo", "Bar"])
165 parse_config
.assert_called_with(args_mock
)
166 fetch_markets
.assert_called_with("user")
168 self
.assertEqual(2, process
.call_count
)
169 process
.assert_has_calls([
170 mock
.call("config1", 3, 1, args_mock
),
171 mock
.call("config2", 1, 2, args_mock
),
173 with self
.subTest(parallel
=True):
174 with mock
.patch("main.parse_args") as parse_args
,\
175 mock
.patch("main.parse_config") as parse_config
,\
176 mock
.patch("main.fetch_markets") as fetch_markets
,\
177 mock
.patch("main.process") as process
,\
178 mock
.patch("store.Portfolio.start_worker") as start
,\
179 mock
.patch("store.Portfolio.stop_worker") as stop
:
181 args_mock
= mock
.Mock()
182 args_mock
.parallel
= True
183 args_mock
.user
= "user"
184 parse_args
.return_value
= args_mock
186 fetch_markets
.return_value
= [[3, "config1", 1], [1, "config2", 2]]
188 main
.main(["Foo", "Bar"])
190 parse_args
.assert_called_with(["Foo", "Bar"])
191 parse_config
.assert_called_with(args_mock
)
192 fetch_markets
.assert_called_with("user")
194 stop
.assert_called_once_with()
195 start
.assert_called_once_with()
196 self
.assertEqual(2, process
.call_count
)
197 process
.assert_has_calls([
198 mock
.call
.__bool
__(),
199 mock
.call("config1", 3, 1, args_mock
),
200 mock
.call
.__bool
__(),
201 mock
.call("config2", 1, 2, args_mock
),
203 with self
.subTest(quiet
=True):
204 with mock
.patch("main.parse_args") as parse_args
,\
205 mock
.patch("main.parse_config") as parse_config
,\
206 mock
.patch("main.fetch_markets") as fetch_markets
,\
207 mock
.patch("store.Portfolio.report") as report
,\
208 mock
.patch("main.process") as process
:
210 args_mock
= mock
.Mock()
211 args_mock
.parallel
= False
212 args_mock
.quiet
= True
213 args_mock
.user
= "user"
214 parse_args
.return_value
= args_mock
216 fetch_markets
.return_value
= [[3, "config1", 1], [1, "config2", 2]]
218 main
.main(["Foo", "Bar"])
220 report
.set_verbose
.assert_called_once_with(False)
222 with self
.subTest(quiet
=False):
223 with mock
.patch("main.parse_args") as parse_args
,\
224 mock
.patch("main.parse_config") as parse_config
,\
225 mock
.patch("main.fetch_markets") as fetch_markets
,\
226 mock
.patch("store.Portfolio.report") as report
,\
227 mock
.patch("main.process") as process
:
229 args_mock
= mock
.Mock()
230 args_mock
.parallel
= False
231 args_mock
.quiet
= False
232 args_mock
.user
= "user"
233 parse_args
.return_value
= args_mock
235 fetch_markets
.return_value
= [[3, "config1", 1], [1, "config2", 2]]
237 main
.main(["Foo", "Bar"])
239 report
.set_verbose
.assert_called_once_with(True)
242 @mock.patch.object(main
.sys
, "exit")
243 @mock.patch("main.os")
244 def test_parse_config(self
, os
, exit
):
245 with self
.subTest(report_path
=None),\
246 mock
.patch
.object(main
.dbs
, "connect_psql") as psql
,\
247 mock
.patch
.object(main
.dbs
, "connect_redis") as redis
:
248 args
= main
.configargparse
.Namespace(**{
250 "redis_host": "rhost",
254 main
.parse_config(args
)
255 psql
.assert_called_once_with(args
)
256 redis
.assert_called_once_with(args
)
258 with self
.subTest(report_path
=None, db
=None),\
259 mock
.patch
.object(main
.dbs
, "connect_psql") as psql
,\
260 mock
.patch
.object(main
.dbs
, "connect_redis") as redis
:
261 args
= main
.configargparse
.Namespace(**{
263 "redis_host": "rhost",
267 main
.parse_config(args
)
268 psql
.assert_not_called()
269 redis
.assert_called_once_with(args
)
271 with self
.subTest(report_path
=None, redis
=None),\
272 mock
.patch
.object(main
.dbs
, "connect_psql") as psql
,\
273 mock
.patch
.object(main
.dbs
, "connect_redis") as redis
:
274 args
= main
.configargparse
.Namespace(**{
280 main
.parse_config(args
)
281 redis
.assert_not_called()
282 psql
.assert_called_once_with(args
)
284 with self
.subTest(report_path
="present"),\
285 mock
.patch
.object(main
.dbs
, "connect_psql") as psql
,\
286 mock
.patch
.object(main
.dbs
, "connect_redis") as redis
:
287 args
= main
.configargparse
.Namespace(**{
289 "redis_host": "rhost",
290 "report_path": "report_path",
293 os
.path
.exists
.return_value
= False
295 main
.parse_config(args
)
297 os
.path
.exists
.assert_called_once_with("report_path")
298 os
.makedirs
.assert_called_once_with("report_path")
300 def test_parse_args(self
):
301 with self
.subTest(config
="config.ini"):
302 args
= main
.parse_args([])
303 self
.assertEqual("config.ini", args
.config
)
304 self
.assertFalse(args
.before
)
305 self
.assertFalse(args
.after
)
306 self
.assertFalse(args
.debug
)
308 args
= main
.parse_args(["--before", "--after", "--debug"])
309 self
.assertTrue(args
.before
)
310 self
.assertTrue(args
.after
)
311 self
.assertTrue(args
.debug
)
313 with self
.subTest(config
="inexistant"), \
314 self
.assertRaises(SystemExit), \
315 mock
.patch('sys.stderr', new_callable
=StringIO
) as stdout_mock
:
316 args
= main
.parse_args(["--config", "foo.bar"])
318 @mock.patch.object(main
.dbs
, "psql")
319 def test_fetch_markets(self
, psql
):
320 cursor_mock
= mock
.MagicMock()
321 cursor_mock
.__iter
__.return_value
= ["row_1", "row_2"]
323 psql
.cursor
.return_value
= cursor_mock
325 with self
.subTest(user
=None):
326 rows
= list(main
.fetch_markets(None))
328 cursor_mock
.execute
.assert_called_once_with("SELECT id,config,user_id FROM market_configs WHERE status='enabled'")
330 self
.assertEqual(["row_1", "row_2"], rows
)
332 cursor_mock
.execute
.reset_mock()
333 with self
.subTest(user
=1):
334 rows
= list(main
.fetch_markets(1))
336 cursor_mock
.execute
.assert_called_once_with("SELECT id,config,user_id FROM market_configs WHERE status='enabled' AND user_id = %s", 1)
338 self
.assertEqual(["row_1", "row_2"], rows
)