]>
git.immae.eu Git - perso/Immae/Projets/Cryptomonnaies/Cryptoportfolio/Trader.git/blob - tests/test_main.py
4 class MainTest(WebMockTestCase
):
5 def test_make_order(self
):
6 self
.m
.get_ticker
.return_value
= {
13 with self
.subTest(description
="nominal case"):
14 main
.make_order(self
.m
, 10, "ETH")
16 self
.m
.report
.log_stage
.assert_has_calls([
17 mock
.call("make_order_begin"),
18 mock
.call("make_order_end"),
20 self
.m
.balances
.fetch_balances
.assert_has_calls([
21 mock
.call(tag
="make_order_begin"),
22 mock
.call(tag
="make_order_end"),
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()
34 order
= trade
.orders
[0]
35 self
.assertEqual(D("0.10"), order
.rate
)
38 with self
.subTest(compute_value
="default"):
39 main
.make_order(self
.m
, 10, "ETH", action
="dispose",
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
)
47 with self
.subTest(follow
=False):
48 result
= main
.make_order(self
.m
, 10, "ETH", follow
=False)
50 self
.m
.report
.log_stage
.assert_has_calls([
51 mock
.call("make_order_begin"),
52 mock
.call("make_order_end_not_followed"),
54 self
.m
.balances
.fetch_balances
.assert_called_once_with(tag
="make_order_begin")
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
)
67 with self
.subTest(base_currency
="USDT"):
68 main
.make_order(self
.m
, 1, "BTC", base_currency
="USDT")
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
)
75 with self
.subTest(close_if_possible
=True):
76 main
.make_order(self
.m
, 10, "ETH", close_if_possible
=True)
78 trade
= self
.m
.trades
.all
.append
.mock_calls
[0][1][0]
79 self
.assertEqual(True, trade
.orders
[0].close_if_possible
)
82 with self
.subTest(action
="dispose"):
83 main
.make_order(self
.m
, 10, "ETH", action
="dispose")
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
)
92 with self
.subTest(compute_value
="default"):
93 main
.make_order(self
.m
, 10, "ETH", action
="dispose",
96 trade
= self
.m
.trades
.all
.append
.mock_calls
[0][1][0]
97 self
.assertEqual(D("0.9"), trade
.value_from
.value
)
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)
109 self
.assertIsInstance(m
, market
.Market
)
110 self
.assertFalse(m
.debug
)
111 main_parse_args
.assert_called_once_with(["--config", "config_path.ini"])
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)
120 self
.assertIsInstance(m
, market
.Market
)
121 self
.assertTrue(m
.debug
)
122 main_parse_args
.assert_called_once_with(["--config", "config_path.ini", "--debug"])
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
:
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())
137 main
.process("config", 3, 1, args_mock
, "pg_config")
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"),
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())
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
:
156 args_mock
= mock
.Mock()
157 args_mock
.parallel
= False
158 args_mock
.user
= "user"
159 parse_args
.return_value
= args_mock
161 parse_config
.return_value
= "pg_config"
163 fetch_markets
.return_value
= [[3, "config1", 1], [1, "config2", 2]]
165 main
.main(["Foo", "Bar"])
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")
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"),
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
,\
181 mock
.patch("store.Portfolio.start_worker") as start
,\
182 mock
.patch("store.Portfolio.stop_worker") as stop
:
184 args_mock
= mock
.Mock()
185 args_mock
.parallel
= True
186 args_mock
.user
= "user"
187 parse_args
.return_value
= args_mock
189 parse_config
.return_value
= "pg_config"
191 fetch_markets
.return_value
= [[3, "config1", 1], [1, "config2", 2]]
193 main
.main(["Foo", "Bar"])
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")
199 stop
.assert_called_once_with()
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"),
209 @mock.patch.object(main
.sys
, "exit")
210 @mock.patch("main.os")
211 def test_parse_config(self
, os
, exit
):
212 with self
.subTest(report_path
=None):
213 args
= main
.configargparse
.Namespace(**{
217 "db_password": "password",
218 "db_database": "database",
222 result
= main
.parse_config(args
)
223 self
.assertEqual({ "host": "host", "port": "port", "user":
224 "user", "password": "password", "database": "database"
226 with self
.assertRaises(AttributeError):
229 with self
.subTest(report_path
="present"):
230 args
= main
.configargparse
.Namespace(**{
234 "db_password": "password",
235 "db_database": "database",
236 "report_path": "report_path",
239 os
.path
.exists
.return_value
= False
241 result
= main
.parse_config(args
)
243 os
.path
.exists
.assert_called_once_with("report_path")
244 os
.makedirs
.assert_called_once_with("report_path")
246 def test_parse_args(self
):
247 with self
.subTest(config
="config.ini"):
248 args
= main
.parse_args([])
249 self
.assertEqual("config.ini", args
.config
)
250 self
.assertFalse(args
.before
)
251 self
.assertFalse(args
.after
)
252 self
.assertFalse(args
.debug
)
254 args
= main
.parse_args(["--before", "--after", "--debug"])
255 self
.assertTrue(args
.before
)
256 self
.assertTrue(args
.after
)
257 self
.assertTrue(args
.debug
)
259 with self
.subTest(config
="inexistant"), \
260 self
.assertRaises(SystemExit), \
261 mock
.patch('sys.stderr', new_callable
=StringIO
) as stdout_mock
:
262 args
= main
.parse_args(["--config", "foo.bar"])
264 @mock.patch.object(main
, "psycopg2")
265 def test_fetch_markets(self
, psycopg2
):
266 connect_mock
= mock
.Mock()
267 cursor_mock
= mock
.MagicMock()
268 cursor_mock
.__iter
__.return_value
= ["row_1", "row_2"]
270 connect_mock
.cursor
.return_value
= cursor_mock
271 psycopg2
.connect
.return_value
= connect_mock
273 with self
.subTest(user
=None):
274 rows
= list(main
.fetch_markets({"foo": "bar"}
, None))
276 psycopg2
.connect
.assert_called_once_with(foo
="bar")
277 cursor_mock
.execute
.assert_called_once_with("SELECT id,config,user_id FROM market_configs")
279 self
.assertEqual(["row_1", "row_2"], rows
)
281 psycopg2
.connect
.reset_mock()
282 cursor_mock
.execute
.reset_mock()
283 with self
.subTest(user
=1):
284 rows
= list(main
.fetch_markets({"foo": "bar"}
, 1))
286 psycopg2
.connect
.assert_called_once_with(foo
="bar")
287 cursor_mock
.execute
.assert_called_once_with("SELECT id,config,user_id FROM market_configs WHERE user_id = %s", 1)
289 self
.assertEqual(["row_1", "row_2"], rows
)