]>
git.immae.eu Git - perso/Immae/Projets/Cryptomonnaies/Cryptoportfolio/Trader.git/blob - tests/test_main.py
e3a5677b4f2cabc1226f797fabc17c7e2eb2099b
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
= {
14 with self
.subTest(description
="nominal case"):
15 main
.make_order(self
.m
, 10, "ETH")
17 self
.m
.report
.log_stage
.assert_has_calls([
18 mock
.call("make_order_begin"),
19 mock
.call("make_order_end"),
21 self
.m
.balances
.fetch_balances
.assert_has_calls([
22 mock
.call(tag
="make_order_begin"),
23 mock
.call(tag
="make_order_end"),
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()
35 order
= trade
.orders
[0]
36 self
.assertEqual(D("0.10"), order
.rate
)
39 with self
.subTest(compute_value
="default"):
40 main
.make_order(self
.m
, 10, "ETH", action
="dispose",
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
)
48 with self
.subTest(follow
=False):
49 result
= main
.make_order(self
.m
, 10, "ETH", follow
=False)
51 self
.m
.report
.log_stage
.assert_has_calls([
52 mock
.call("make_order_begin"),
53 mock
.call("make_order_end_not_followed"),
55 self
.m
.balances
.fetch_balances
.assert_called_once_with(tag
="make_order_begin")
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
)
68 with self
.subTest(base_currency
="USDT"):
69 main
.make_order(self
.m
, 1, "BTC", base_currency
="USDT")
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
)
76 with self
.subTest(close_if_possible
=True):
77 main
.make_order(self
.m
, 10, "ETH", close_if_possible
=True)
79 trade
= self
.m
.trades
.all
.append
.mock_calls
[0][1][0]
80 self
.assertEqual(True, trade
.orders
[0].close_if_possible
)
83 with self
.subTest(action
="dispose"):
84 main
.make_order(self
.m
, 10, "ETH", action
="dispose")
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
)
93 with self
.subTest(compute_value
="default"):
94 main
.make_order(self
.m
, 10, "ETH", action
="dispose",
97 trade
= self
.m
.trades
.all
.append
.mock_calls
[0][1][0]
98 self
.assertEqual(D("0.9"), trade
.value_from
.value
)
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"
107 main_fetch_markets
.return_value
= [(1, {"key": "market_config"}
, 3)]
108 m
= main
.get_user_market("config_path.ini", 1)
110 self
.assertIsInstance(m
, market
.Market
)
111 self
.assertFalse(m
.debug
)
112 main_parse_args
.assert_called_once_with(["--config", "config_path.ini"])
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"
118 main_fetch_markets
.return_value
= [(1, {"key": "market_config"}
, 3)]
119 m
= main
.get_user_market("config_path.ini", 1, debug
=True)
121 self
.assertIsInstance(m
, market
.Market
)
122 self
.assertTrue(m
.debug
)
123 main_parse_args
.assert_called_once_with(["--config", "config_path.ini", "--debug"])
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
:
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())
138 main
.process("config", 3, 1, args_mock
, "pg_config")
140 market_mock
.from_config
.assert_has_calls([
141 mock
.call("config", args_mock
, pg_config
="pg_config", market_id
=3, user_id
=1),
142 mock
.call().process("action", before
="before", after
="after"),
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")
148 self
.assertEqual("Exception: boo\n", stdout_mock
.getvalue())
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
:
157 args_mock
= mock
.Mock()
158 args_mock
.parallel
= False
159 args_mock
.user
= "user"
160 parse_args
.return_value
= args_mock
162 parse_config
.return_value
= "pg_config"
164 fetch_markets
.return_value
= [[3, "config1", 1], [1, "config2", 2]]
166 main
.main(["Foo", "Bar"])
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")
172 self
.assertEqual(2, process
.call_count
)
173 process
.assert_has_calls([
174 mock
.call("config1", 3, 1, args_mock
, "pg_config"),
175 mock
.call("config2", 1, 2, args_mock
, "pg_config"),
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
:
185 args_mock
= mock
.Mock()
186 args_mock
.parallel
= True
187 args_mock
.user
= "user"
188 parse_args
.return_value
= args_mock
190 parse_config
.return_value
= "pg_config"
192 fetch_markets
.return_value
= [[3, "config1", 1], [1, "config2", 2]]
194 main
.main(["Foo", "Bar"])
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")
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"),
206 mock
.call
.__bool
__(),
207 mock
.call("config2", 1, 2, args_mock
, "pg_config"),
210 @mock.patch.object(main
.sys
, "exit")
211 @mock.patch("main.os")
212 def test_parse_config(self
, os
, exit
):
213 with self
.subTest(report_path
=None):
214 args
= main
.configargparse
.Namespace(**{
218 "db_password": "password",
219 "db_database": "database",
223 result
= main
.parse_config(args
)
224 self
.assertEqual({ "host": "host", "port": "port", "user":
225 "user", "password": "password", "database": "database"
227 with self
.assertRaises(AttributeError):
230 with self
.subTest(report_path
="present"):
231 args
= main
.configargparse
.Namespace(**{
235 "db_password": "password",
236 "db_database": "database",
237 "report_path": "report_path",
240 os
.path
.exists
.return_value
= False
242 result
= main
.parse_config(args
)
244 os
.path
.exists
.assert_called_once_with("report_path")
245 os
.makedirs
.assert_called_once_with("report_path")
247 def test_parse_args(self
):
248 with self
.subTest(config
="config.ini"):
249 args
= main
.parse_args([])
250 self
.assertEqual("config.ini", args
.config
)
251 self
.assertFalse(args
.before
)
252 self
.assertFalse(args
.after
)
253 self
.assertFalse(args
.debug
)
255 args
= main
.parse_args(["--before", "--after", "--debug"])
256 self
.assertTrue(args
.before
)
257 self
.assertTrue(args
.after
)
258 self
.assertTrue(args
.debug
)
260 with self
.subTest(config
="inexistant"), \
261 self
.assertRaises(SystemExit), \
262 mock
.patch('sys.stderr', new_callable
=StringIO
) as stdout_mock
:
263 args
= main
.parse_args(["--config", "foo.bar"])
265 @mock.patch.object(main
, "psycopg2")
266 def test_fetch_markets(self
, psycopg2
):
267 connect_mock
= mock
.Mock()
268 cursor_mock
= mock
.MagicMock()
269 cursor_mock
.__iter
__.return_value
= ["row_1", "row_2"]
271 connect_mock
.cursor
.return_value
= cursor_mock
272 psycopg2
.connect
.return_value
= connect_mock
274 with self
.subTest(user
=None):
275 rows
= list(main
.fetch_markets({"foo": "bar"}
, None))
277 psycopg2
.connect
.assert_called_once_with(foo
="bar")
278 cursor_mock
.execute
.assert_called_once_with("SELECT id,config,user_id FROM market_configs")
280 self
.assertEqual(["row_1", "row_2"], rows
)
282 psycopg2
.connect
.reset_mock()
283 cursor_mock
.execute
.reset_mock()
284 with self
.subTest(user
=1):
285 rows
= list(main
.fetch_markets({"foo": "bar"}
, 1))
287 psycopg2
.connect
.assert_called_once_with(foo
="bar")
288 cursor_mock
.execute
.assert_called_once_with("SELECT id,config,user_id FROM market_configs WHERE user_id = %s", 1)
290 self
.assertEqual(["row_1", "row_2"], rows
)