]> git.immae.eu Git - perso/Immae/Projets/Cryptomonnaies/Cryptoportfolio/Trader.git/blob - tests/test_main.py
Fix ccxt switching currency codes
[perso/Immae/Projets/Cryptomonnaies/Cryptoportfolio/Trader.git] / tests / test_main.py
1 from .helper import *
2 import main, market
3
4 class MainTest(WebMockTestCase):
5 def test_make_order(self):
6 self.m.get_ticker.return_value = {
7 "inverted": False,
8 "average": D("0.1"),
9 "bid": D("0.09"),
10 "ask": D("0.11"),
11 }
12
13 with self.subTest(description="nominal case"):
14 main.make_order(self.m, 10, "ETH")
15
16 self.m.report.log_stage.assert_has_calls([
17 mock.call("make_order_begin"),
18 mock.call("make_order_end"),
19 ])
20 self.m.balances.fetch_balances.assert_has_calls([
21 mock.call(tag="make_order_begin"),
22 mock.call(tag="make_order_end"),
23 ])
24 self.m.trades.all.append.assert_called_once()
25 trade = self.m.trades.all.append.mock_calls[0][1][0]
26 self.assertEqual(False, trade.orders[0].close_if_possible)
27 self.assertEqual(0, trade.value_from)
28 self.assertEqual("ETH", trade.currency)
29 self.assertEqual("BTC", trade.base_currency)
30 self.m.report.log_orders.assert_called_once_with([trade.orders[0]], None, "average")
31 self.m.trades.run_orders.assert_called_once_with()
32 self.m.follow_orders.assert_called_once_with()
33
34 order = trade.orders[0]
35 self.assertEqual(D("0.10"), order.rate)
36
37 self.m.reset_mock()
38 with self.subTest(compute_value="default"):
39 main.make_order(self.m, 10, "ETH", action="dispose",
40 compute_value="ask")
41
42 trade = self.m.trades.all.append.mock_calls[0][1][0]
43 order = trade.orders[0]
44 self.assertEqual(D("0.11"), order.rate)
45
46 self.m.reset_mock()
47 with self.subTest(follow=False):
48 result = main.make_order(self.m, 10, "ETH", follow=False)
49
50 self.m.report.log_stage.assert_has_calls([
51 mock.call("make_order_begin"),
52 mock.call("make_order_end_not_followed"),
53 ])
54 self.m.balances.fetch_balances.assert_called_once_with(tag="make_order_begin")
55
56 self.m.trades.all.append.assert_called_once()
57 trade = self.m.trades.all.append.mock_calls[0][1][0]
58 self.assertEqual(0, trade.value_from)
59 self.assertEqual("ETH", trade.currency)
60 self.assertEqual("BTC", trade.base_currency)
61 self.m.report.log_orders.assert_called_once_with([trade.orders[0]], None, "average")
62 self.m.trades.run_orders.assert_called_once_with()
63 self.m.follow_orders.assert_not_called()
64 self.assertEqual(trade.orders[0], result)
65
66 self.m.reset_mock()
67 with self.subTest(base_currency="USDT"):
68 main.make_order(self.m, 1, "BTC", base_currency="USDT")
69
70 trade = self.m.trades.all.append.mock_calls[0][1][0]
71 self.assertEqual("BTC", trade.currency)
72 self.assertEqual("USDT", trade.base_currency)
73
74 self.m.reset_mock()
75 with self.subTest(close_if_possible=True):
76 main.make_order(self.m, 10, "ETH", close_if_possible=True)
77
78 trade = self.m.trades.all.append.mock_calls[0][1][0]
79 self.assertEqual(True, trade.orders[0].close_if_possible)
80
81 self.m.reset_mock()
82 with self.subTest(action="dispose"):
83 main.make_order(self.m, 10, "ETH", action="dispose")
84
85 trade = self.m.trades.all.append.mock_calls[0][1][0]
86 self.assertEqual(0, trade.value_to)
87 self.assertEqual(1, trade.value_from.value)
88 self.assertEqual("ETH", trade.currency)
89 self.assertEqual("BTC", trade.base_currency)
90
91 self.m.reset_mock()
92 with self.subTest(compute_value="default"):
93 main.make_order(self.m, 10, "ETH", action="dispose",
94 compute_value="bid")
95
96 trade = self.m.trades.all.append.mock_calls[0][1][0]
97 self.assertEqual(D("0.9"), trade.value_from.value)
98
99 def test_get_user_market(self):
100 with mock.patch("main.fetch_markets") as main_fetch_markets,\
101 mock.patch("main.parse_args") as main_parse_args,\
102 mock.patch("main.parse_config") as main_parse_config:
103 with self.subTest(debug=False):
104 main_parse_args.return_value = self.market_args()
105 main_parse_config.return_value = "pg_config"
106 main_fetch_markets.return_value = [(1, {"key": "market_config"}, 3)]
107 m = main.get_user_market("config_path.ini", 1)
108
109 self.assertIsInstance(m, market.Market)
110 self.assertFalse(m.debug)
111 main_parse_args.assert_called_once_with(["--config", "config_path.ini"])
112
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_parse_config.return_value = "pg_config"
117 main_fetch_markets.return_value = [(1, {"key": "market_config"}, 3)]
118 m = main.get_user_market("config_path.ini", 1, debug=True)
119
120 self.assertIsInstance(m, market.Market)
121 self.assertTrue(m.debug)
122 main_parse_args.assert_called_once_with(["--config", "config_path.ini", "--debug"])
123
124 def test_process(self):
125 with mock.patch("market.Market") as market_mock,\
126 mock.patch('sys.stdout', new_callable=StringIO) as stdout_mock:
127
128 args_mock = mock.Mock()
129 args_mock.action = "action"
130 args_mock.config = "config"
131 args_mock.user = "user"
132 args_mock.debug = "debug"
133 args_mock.before = "before"
134 args_mock.after = "after"
135 self.assertEqual("", stdout_mock.getvalue())
136
137 main.process("config", 3, 1, args_mock, "pg_config")
138
139 market_mock.from_config.assert_has_calls([
140 mock.call("config", args_mock, pg_config="pg_config", market_id=3, user_id=1),
141 mock.call().process("action", before="before", after="after"),
142 ])
143
144 with self.subTest(exception=True):
145 market_mock.from_config.side_effect = Exception("boo")
146 main.process(3, "config", 1, args_mock, "pg_config")
147 self.assertEqual("Exception: boo\n", stdout_mock.getvalue())
148
149 def test_main(self):
150 with self.subTest(parallel=False):
151 with mock.patch("main.parse_args") as parse_args,\
152 mock.patch("main.parse_config") as parse_config,\
153 mock.patch("main.fetch_markets") as fetch_markets,\
154 mock.patch("main.process") as process:
155
156 args_mock = mock.Mock()
157 args_mock.parallel = False
158 args_mock.user = "user"
159 parse_args.return_value = args_mock
160
161 parse_config.return_value = "pg_config"
162
163 fetch_markets.return_value = [[3, "config1", 1], [1, "config2", 2]]
164
165 main.main(["Foo", "Bar"])
166
167 parse_args.assert_called_with(["Foo", "Bar"])
168 parse_config.assert_called_with(args_mock)
169 fetch_markets.assert_called_with("pg_config", "user")
170
171 self.assertEqual(2, process.call_count)
172 process.assert_has_calls([
173 mock.call("config1", 3, 1, args_mock, "pg_config"),
174 mock.call("config2", 1, 2, args_mock, "pg_config"),
175 ])
176 with self.subTest(parallel=True):
177 with mock.patch("main.parse_args") as parse_args,\
178 mock.patch("main.parse_config") as parse_config,\
179 mock.patch("main.fetch_markets") as fetch_markets,\
180 mock.patch("main.process") as process,\
181 mock.patch("store.Portfolio.start_worker") as start,\
182 mock.patch("store.Portfolio.stop_worker") as stop:
183
184 args_mock = mock.Mock()
185 args_mock.parallel = True
186 args_mock.user = "user"
187 parse_args.return_value = args_mock
188
189 parse_config.return_value = "pg_config"
190
191 fetch_markets.return_value = [[3, "config1", 1], [1, "config2", 2]]
192
193 main.main(["Foo", "Bar"])
194
195 parse_args.assert_called_with(["Foo", "Bar"])
196 parse_config.assert_called_with(args_mock)
197 fetch_markets.assert_called_with("pg_config", "user")
198
199 stop.assert_called_once_with()
200 start.assert_called_once_with()
201 self.assertEqual(2, process.call_count)
202 process.assert_has_calls([
203 mock.call.__bool__(),
204 mock.call("config1", 3, 1, args_mock, "pg_config"),
205 mock.call.__bool__(),
206 mock.call("config2", 1, 2, args_mock, "pg_config"),
207 ])
208 with self.subTest(quiet=True):
209 with mock.patch("main.parse_args") as parse_args,\
210 mock.patch("main.parse_config") as parse_config,\
211 mock.patch("main.fetch_markets") as fetch_markets,\
212 mock.patch("store.Portfolio.report") as report,\
213 mock.patch("main.process") as process:
214
215 args_mock = mock.Mock()
216 args_mock.parallel = False
217 args_mock.quiet = True
218 args_mock.user = "user"
219 parse_args.return_value = args_mock
220
221 parse_config.return_value = "pg_config"
222
223 fetch_markets.return_value = [[3, "config1", 1], [1, "config2", 2]]
224
225 main.main(["Foo", "Bar"])
226
227 report.set_verbose.assert_called_once_with(False)
228
229 with self.subTest(quiet=False):
230 with mock.patch("main.parse_args") as parse_args,\
231 mock.patch("main.parse_config") as parse_config,\
232 mock.patch("main.fetch_markets") as fetch_markets,\
233 mock.patch("store.Portfolio.report") as report,\
234 mock.patch("main.process") as process:
235
236 args_mock = mock.Mock()
237 args_mock.parallel = False
238 args_mock.quiet = False
239 args_mock.user = "user"
240 parse_args.return_value = args_mock
241
242 parse_config.return_value = "pg_config"
243
244 fetch_markets.return_value = [[3, "config1", 1], [1, "config2", 2]]
245
246 main.main(["Foo", "Bar"])
247
248 report.set_verbose.assert_called_once_with(True)
249
250
251 @mock.patch.object(main.sys, "exit")
252 @mock.patch("main.os")
253 def test_parse_config(self, os, exit):
254 with self.subTest(report_path=None):
255 args = main.configargparse.Namespace(**{
256 "db_host": "host",
257 "db_port": "port",
258 "db_user": "user",
259 "db_password": "password",
260 "db_database": "database",
261 "report_path": None,
262 })
263
264 result = main.parse_config(args)
265 self.assertEqual({ "host": "host", "port": "port", "user":
266 "user", "password": "password", "database": "database"
267 }, result)
268 with self.assertRaises(AttributeError):
269 args.db_password
270
271 with self.subTest(report_path="present"):
272 args = main.configargparse.Namespace(**{
273 "db_host": "host",
274 "db_port": "port",
275 "db_user": "user",
276 "db_password": "password",
277 "db_database": "database",
278 "report_path": "report_path",
279 })
280
281 os.path.exists.return_value = False
282
283 result = main.parse_config(args)
284
285 os.path.exists.assert_called_once_with("report_path")
286 os.makedirs.assert_called_once_with("report_path")
287
288 def test_parse_args(self):
289 with self.subTest(config="config.ini"):
290 args = main.parse_args([])
291 self.assertEqual("config.ini", args.config)
292 self.assertFalse(args.before)
293 self.assertFalse(args.after)
294 self.assertFalse(args.debug)
295
296 args = main.parse_args(["--before", "--after", "--debug"])
297 self.assertTrue(args.before)
298 self.assertTrue(args.after)
299 self.assertTrue(args.debug)
300
301 with self.subTest(config="inexistant"), \
302 self.assertRaises(SystemExit), \
303 mock.patch('sys.stderr', new_callable=StringIO) as stdout_mock:
304 args = main.parse_args(["--config", "foo.bar"])
305
306 @mock.patch.object(main, "psycopg2")
307 def test_fetch_markets(self, psycopg2):
308 connect_mock = mock.Mock()
309 cursor_mock = mock.MagicMock()
310 cursor_mock.__iter__.return_value = ["row_1", "row_2"]
311
312 connect_mock.cursor.return_value = cursor_mock
313 psycopg2.connect.return_value = connect_mock
314
315 with self.subTest(user=None):
316 rows = list(main.fetch_markets({"foo": "bar"}, None))
317
318 psycopg2.connect.assert_called_once_with(foo="bar")
319 cursor_mock.execute.assert_called_once_with("SELECT id,config,user_id FROM market_configs")
320
321 self.assertEqual(["row_1", "row_2"], rows)
322
323 psycopg2.connect.reset_mock()
324 cursor_mock.execute.reset_mock()
325 with self.subTest(user=1):
326 rows = list(main.fetch_markets({"foo": "bar"}, 1))
327
328 psycopg2.connect.assert_called_once_with(foo="bar")
329 cursor_mock.execute.assert_called_once_with("SELECT id,config,user_id FROM market_configs WHERE user_id = %s", 1)
330
331 self.assertEqual(["row_1", "row_2"], rows)
332
333