]>
Commit | Line | Data |
---|---|---|
c682bdf4 IB |
1 | from .helper import * |
2 | import main, market | |
3 | ||
3080f31d | 4 | @unittest.skipUnless("unit" in limits, "Unit skipped") |
c682bdf4 IB |
5 | class 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() | |
c682bdf4 IB |
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) | |
c682bdf4 IB |
116 | main_fetch_markets.return_value = [(1, {"key": "market_config"}, 3)] |
117 | m = main.get_user_market("config_path.ini", 1, debug=True) | |
118 | ||
119 | self.assertIsInstance(m, market.Market) | |
120 | self.assertTrue(m.debug) | |
121 | main_parse_args.assert_called_once_with(["--config", "config_path.ini", "--debug"]) | |
122 | ||
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: | |
126 | ||
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()) | |
135 | ||
30700830 | 136 | main.process("config", 3, 1, args_mock) |
c682bdf4 IB |
137 | |
138 | market_mock.from_config.assert_has_calls([ | |
30700830 | 139 | mock.call("config", args_mock, market_id=3, user_id=1), |
c682bdf4 IB |
140 | mock.call().process("action", before="before", after="after"), |
141 | ]) | |
142 | ||
143 | with self.subTest(exception=True): | |
144 | market_mock.from_config.side_effect = Exception("boo") | |
30700830 | 145 | main.process(3, "config", 1, args_mock) |
c682bdf4 IB |
146 | self.assertEqual("Exception: boo\n", stdout_mock.getvalue()) |
147 | ||
148 | def test_main(self): | |
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: | |
154 | ||
155 | args_mock = mock.Mock() | |
156 | args_mock.parallel = False | |
157 | args_mock.user = "user" | |
158 | parse_args.return_value = args_mock | |
159 | ||
c682bdf4 IB |
160 | fetch_markets.return_value = [[3, "config1", 1], [1, "config2", 2]] |
161 | ||
162 | main.main(["Foo", "Bar"]) | |
163 | ||
164 | parse_args.assert_called_with(["Foo", "Bar"]) | |
165 | parse_config.assert_called_with(args_mock) | |
30700830 | 166 | fetch_markets.assert_called_with("user") |
c682bdf4 IB |
167 | |
168 | self.assertEqual(2, process.call_count) | |
169 | process.assert_has_calls([ | |
30700830 IB |
170 | mock.call("config1", 3, 1, args_mock), |
171 | mock.call("config2", 1, 2, args_mock), | |
c682bdf4 IB |
172 | ]) |
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,\ | |
e7d7c0e5 IB |
178 | mock.patch("store.Portfolio.start_worker") as start,\ |
179 | mock.patch("store.Portfolio.stop_worker") as stop: | |
c682bdf4 IB |
180 | |
181 | args_mock = mock.Mock() | |
182 | args_mock.parallel = True | |
183 | args_mock.user = "user" | |
184 | parse_args.return_value = args_mock | |
185 | ||
c682bdf4 IB |
186 | fetch_markets.return_value = [[3, "config1", 1], [1, "config2", 2]] |
187 | ||
188 | main.main(["Foo", "Bar"]) | |
189 | ||
190 | parse_args.assert_called_with(["Foo", "Bar"]) | |
191 | parse_config.assert_called_with(args_mock) | |
30700830 | 192 | fetch_markets.assert_called_with("user") |
c682bdf4 | 193 | |
e7d7c0e5 | 194 | stop.assert_called_once_with() |
c682bdf4 IB |
195 | start.assert_called_once_with() |
196 | self.assertEqual(2, process.call_count) | |
197 | process.assert_has_calls([ | |
198 | mock.call.__bool__(), | |
30700830 | 199 | mock.call("config1", 3, 1, args_mock), |
c682bdf4 | 200 | mock.call.__bool__(), |
30700830 | 201 | mock.call("config2", 1, 2, args_mock), |
c682bdf4 | 202 | ]) |
a0dcf4e0 IB |
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: | |
209 | ||
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 | |
215 | ||
a0dcf4e0 IB |
216 | fetch_markets.return_value = [[3, "config1", 1], [1, "config2", 2]] |
217 | ||
218 | main.main(["Foo", "Bar"]) | |
219 | ||
220 | report.set_verbose.assert_called_once_with(False) | |
221 | ||
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: | |
228 | ||
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 | |
234 | ||
a0dcf4e0 IB |
235 | fetch_markets.return_value = [[3, "config1", 1], [1, "config2", 2]] |
236 | ||
237 | main.main(["Foo", "Bar"]) | |
238 | ||
239 | report.set_verbose.assert_called_once_with(True) | |
240 | ||
c682bdf4 IB |
241 | |
242 | @mock.patch.object(main.sys, "exit") | |
243 | @mock.patch("main.os") | |
244 | def test_parse_config(self, os, exit): | |
30700830 IB |
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: | |
c682bdf4 IB |
248 | args = main.configargparse.Namespace(**{ |
249 | "db_host": "host", | |
1593c7a9 | 250 | "redis_host": "rhost", |
c682bdf4 IB |
251 | "report_path": None, |
252 | }) | |
253 | ||
30700830 IB |
254 | main.parse_config(args) |
255 | psql.assert_called_once_with(args) | |
256 | redis.assert_called_once_with(args) | |
257 | ||
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(**{ | |
262 | "db_host": None, | |
263 | "redis_host": "rhost", | |
264 | "report_path": None, | |
265 | }) | |
1593c7a9 | 266 | |
30700830 IB |
267 | main.parse_config(args) |
268 | psql.assert_not_called() | |
269 | redis.assert_called_once_with(args) | |
1593c7a9 | 270 | |
30700830 IB |
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: | |
1593c7a9 IB |
274 | args = main.configargparse.Namespace(**{ |
275 | "db_host": "host", | |
30700830 | 276 | "redis_host": None, |
1593c7a9 IB |
277 | "report_path": None, |
278 | }) | |
279 | ||
30700830 IB |
280 | main.parse_config(args) |
281 | redis.assert_not_called() | |
282 | psql.assert_called_once_with(args) | |
c682bdf4 | 283 | |
30700830 IB |
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: | |
c682bdf4 IB |
287 | args = main.configargparse.Namespace(**{ |
288 | "db_host": "host", | |
1593c7a9 | 289 | "redis_host": "rhost", |
c682bdf4 IB |
290 | "report_path": "report_path", |
291 | }) | |
292 | ||
293 | os.path.exists.return_value = False | |
294 | ||
30700830 | 295 | main.parse_config(args) |
c682bdf4 IB |
296 | |
297 | os.path.exists.assert_called_once_with("report_path") | |
298 | os.makedirs.assert_called_once_with("report_path") | |
299 | ||
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) | |
307 | ||
308 | args = main.parse_args(["--before", "--after", "--debug"]) | |
309 | self.assertTrue(args.before) | |
310 | self.assertTrue(args.after) | |
311 | self.assertTrue(args.debug) | |
312 | ||
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"]) | |
317 | ||
30700830 IB |
318 | @mock.patch.object(main.dbs, "psql") |
319 | def test_fetch_markets(self, psql): | |
c682bdf4 IB |
320 | cursor_mock = mock.MagicMock() |
321 | cursor_mock.__iter__.return_value = ["row_1", "row_2"] | |
322 | ||
30700830 | 323 | psql.cursor.return_value = cursor_mock |
c682bdf4 IB |
324 | |
325 | with self.subTest(user=None): | |
30700830 | 326 | rows = list(main.fetch_markets(None)) |
c682bdf4 | 327 | |
c682bdf4 IB |
328 | cursor_mock.execute.assert_called_once_with("SELECT id,config,user_id FROM market_configs") |
329 | ||
330 | self.assertEqual(["row_1", "row_2"], rows) | |
331 | ||
c682bdf4 IB |
332 | cursor_mock.execute.reset_mock() |
333 | with self.subTest(user=1): | |
30700830 | 334 | rows = list(main.fetch_markets(1)) |
c682bdf4 | 335 | |
c682bdf4 IB |
336 | cursor_mock.execute.assert_called_once_with("SELECT id,config,user_id FROM market_configs WHERE user_id = %s", 1) |
337 | ||
338 | self.assertEqual(["row_1", "row_2"], rows) | |
339 | ||
340 |