]>
Commit | Line | Data |
---|---|---|
c682bdf4 IB |
1 | from .helper import * |
2 | import main, market | |
3 | ||
c682bdf4 IB |
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,\ | |
e7d7c0e5 IB |
181 | mock.patch("store.Portfolio.start_worker") as start,\ |
182 | mock.patch("store.Portfolio.stop_worker") as stop: | |
c682bdf4 IB |
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 | ||
e7d7c0e5 | 199 | stop.assert_called_once_with() |
c682bdf4 IB |
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 | ]) | |
a0dcf4e0 IB |
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 | ||
c682bdf4 IB |
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 |