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