]>
Commit | Line | Data |
---|---|---|
1 | from .helper import * | |
2 | import main, market | |
3 | ||
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 = { | |
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() | |
106 | main_parse_config.return_value = ["pg_config", "redis_config"] | |
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) | |
117 | main_parse_config.return_value = ["pg_config", "redis_config"] | |
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 | ||
138 | main.process("config", 3, 1, args_mock, "pg_config", "redis_config") | |
139 | ||
140 | market_mock.from_config.assert_has_calls([ | |
141 | mock.call("config", args_mock, pg_config="pg_config", redis_config="redis_config", market_id=3, user_id=1), | |
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") | |
147 | main.process(3, "config", 1, args_mock, "pg_config", "redis_config") | |
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 | ||
162 | parse_config.return_value = ["pg_config", "redis_config"] | |
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([ | |
174 | mock.call("config1", 3, 1, args_mock, "pg_config", "redis_config"), | |
175 | mock.call("config2", 1, 2, args_mock, "pg_config", "redis_config"), | |
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,\ | |
182 | mock.patch("store.Portfolio.start_worker") as start,\ | |
183 | mock.patch("store.Portfolio.stop_worker") as stop: | |
184 | ||
185 | args_mock = mock.Mock() | |
186 | args_mock.parallel = True | |
187 | args_mock.user = "user" | |
188 | parse_args.return_value = args_mock | |
189 | ||
190 | parse_config.return_value = ["pg_config", "redis_config"] | |
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 | ||
200 | stop.assert_called_once_with() | |
201 | start.assert_called_once_with() | |
202 | self.assertEqual(2, process.call_count) | |
203 | process.assert_has_calls([ | |
204 | mock.call.__bool__(), | |
205 | mock.call("config1", 3, 1, args_mock, "pg_config", "redis_config"), | |
206 | mock.call.__bool__(), | |
207 | mock.call("config2", 1, 2, args_mock, "pg_config", "redis_config"), | |
208 | ]) | |
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 | ||
222 | parse_config.return_value = ["pg_config", "redis_config"] | |
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 | ||
243 | parse_config.return_value = ["pg_config", "redis_config"] | |
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 | ||
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", | |
262 | "redis_host": "rhost", | |
263 | "redis_port": "rport", | |
264 | "redis_database": "rdb", | |
265 | "report_path": None, | |
266 | }) | |
267 | ||
268 | db_config, redis_config = main.parse_config(args) | |
269 | self.assertEqual({ "host": "host", "port": "port", "user": | |
270 | "user", "password": "password", "database": "database" | |
271 | }, db_config) | |
272 | self.assertEqual({ "host": "rhost", "port": "rport", "db": | |
273 | "rdb"}, redis_config) | |
274 | ||
275 | with self.assertRaises(AttributeError): | |
276 | args.db_password | |
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) | |
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", | |
303 | "redis_host": "rhost", | |
304 | "redis_port": "rport", | |
305 | "redis_database": "rdb", | |
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 |