X-Git-Url: https://git.immae.eu/?a=blobdiff_plain;f=tests%2Ftest_main.py;fp=tests%2Ftest_main.py;h=6396c07728e3d01677962627e86e1add5203a947;hb=c682bdf4a02a45312ef1aadf8aa26136cf308414;hp=0000000000000000000000000000000000000000;hpb=e6015816224f8f405e9b1c9557f22e73b21246e8;p=perso%2FImmae%2FProjets%2FCryptomonnaies%2FCryptoportfolio%2FTrader.git diff --git a/tests/test_main.py b/tests/test_main.py new file mode 100644 index 0000000..6396c07 --- /dev/null +++ b/tests/test_main.py @@ -0,0 +1,290 @@ +from .helper import * +import main, market + +@unittest.skipUnless("unit" in limits, "Unit skipped") +class MainTest(WebMockTestCase): + def test_make_order(self): + self.m.get_ticker.return_value = { + "inverted": False, + "average": D("0.1"), + "bid": D("0.09"), + "ask": D("0.11"), + } + + with self.subTest(description="nominal case"): + main.make_order(self.m, 10, "ETH") + + self.m.report.log_stage.assert_has_calls([ + mock.call("make_order_begin"), + mock.call("make_order_end"), + ]) + self.m.balances.fetch_balances.assert_has_calls([ + mock.call(tag="make_order_begin"), + mock.call(tag="make_order_end"), + ]) + self.m.trades.all.append.assert_called_once() + trade = self.m.trades.all.append.mock_calls[0][1][0] + self.assertEqual(False, trade.orders[0].close_if_possible) + self.assertEqual(0, trade.value_from) + self.assertEqual("ETH", trade.currency) + self.assertEqual("BTC", trade.base_currency) + self.m.report.log_orders.assert_called_once_with([trade.orders[0]], None, "average") + self.m.trades.run_orders.assert_called_once_with() + self.m.follow_orders.assert_called_once_with() + + order = trade.orders[0] + self.assertEqual(D("0.10"), order.rate) + + self.m.reset_mock() + with self.subTest(compute_value="default"): + main.make_order(self.m, 10, "ETH", action="dispose", + compute_value="ask") + + trade = self.m.trades.all.append.mock_calls[0][1][0] + order = trade.orders[0] + self.assertEqual(D("0.11"), order.rate) + + self.m.reset_mock() + with self.subTest(follow=False): + result = main.make_order(self.m, 10, "ETH", follow=False) + + self.m.report.log_stage.assert_has_calls([ + mock.call("make_order_begin"), + mock.call("make_order_end_not_followed"), + ]) + self.m.balances.fetch_balances.assert_called_once_with(tag="make_order_begin") + + self.m.trades.all.append.assert_called_once() + trade = self.m.trades.all.append.mock_calls[0][1][0] + self.assertEqual(0, trade.value_from) + self.assertEqual("ETH", trade.currency) + self.assertEqual("BTC", trade.base_currency) + self.m.report.log_orders.assert_called_once_with([trade.orders[0]], None, "average") + self.m.trades.run_orders.assert_called_once_with() + self.m.follow_orders.assert_not_called() + self.assertEqual(trade.orders[0], result) + + self.m.reset_mock() + with self.subTest(base_currency="USDT"): + main.make_order(self.m, 1, "BTC", base_currency="USDT") + + trade = self.m.trades.all.append.mock_calls[0][1][0] + self.assertEqual("BTC", trade.currency) + self.assertEqual("USDT", trade.base_currency) + + self.m.reset_mock() + with self.subTest(close_if_possible=True): + main.make_order(self.m, 10, "ETH", close_if_possible=True) + + trade = self.m.trades.all.append.mock_calls[0][1][0] + self.assertEqual(True, trade.orders[0].close_if_possible) + + self.m.reset_mock() + with self.subTest(action="dispose"): + main.make_order(self.m, 10, "ETH", action="dispose") + + trade = self.m.trades.all.append.mock_calls[0][1][0] + self.assertEqual(0, trade.value_to) + self.assertEqual(1, trade.value_from.value) + self.assertEqual("ETH", trade.currency) + self.assertEqual("BTC", trade.base_currency) + + self.m.reset_mock() + with self.subTest(compute_value="default"): + main.make_order(self.m, 10, "ETH", action="dispose", + compute_value="bid") + + trade = self.m.trades.all.append.mock_calls[0][1][0] + self.assertEqual(D("0.9"), trade.value_from.value) + + def test_get_user_market(self): + with mock.patch("main.fetch_markets") as main_fetch_markets,\ + mock.patch("main.parse_args") as main_parse_args,\ + mock.patch("main.parse_config") as main_parse_config: + with self.subTest(debug=False): + main_parse_args.return_value = self.market_args() + main_parse_config.return_value = "pg_config" + main_fetch_markets.return_value = [(1, {"key": "market_config"}, 3)] + m = main.get_user_market("config_path.ini", 1) + + self.assertIsInstance(m, market.Market) + self.assertFalse(m.debug) + main_parse_args.assert_called_once_with(["--config", "config_path.ini"]) + + main_parse_args.reset_mock() + with self.subTest(debug=True): + main_parse_args.return_value = self.market_args(debug=True) + main_parse_config.return_value = "pg_config" + main_fetch_markets.return_value = [(1, {"key": "market_config"}, 3)] + m = main.get_user_market("config_path.ini", 1, debug=True) + + self.assertIsInstance(m, market.Market) + self.assertTrue(m.debug) + main_parse_args.assert_called_once_with(["--config", "config_path.ini", "--debug"]) + + def test_process(self): + with mock.patch("market.Market") as market_mock,\ + mock.patch('sys.stdout', new_callable=StringIO) as stdout_mock: + + args_mock = mock.Mock() + args_mock.action = "action" + args_mock.config = "config" + args_mock.user = "user" + args_mock.debug = "debug" + args_mock.before = "before" + args_mock.after = "after" + self.assertEqual("", stdout_mock.getvalue()) + + main.process("config", 3, 1, args_mock, "pg_config") + + market_mock.from_config.assert_has_calls([ + mock.call("config", args_mock, pg_config="pg_config", market_id=3, user_id=1), + mock.call().process("action", before="before", after="after"), + ]) + + with self.subTest(exception=True): + market_mock.from_config.side_effect = Exception("boo") + main.process(3, "config", 1, args_mock, "pg_config") + self.assertEqual("Exception: boo\n", stdout_mock.getvalue()) + + def test_main(self): + with self.subTest(parallel=False): + with mock.patch("main.parse_args") as parse_args,\ + mock.patch("main.parse_config") as parse_config,\ + mock.patch("main.fetch_markets") as fetch_markets,\ + mock.patch("main.process") as process: + + args_mock = mock.Mock() + args_mock.parallel = False + args_mock.user = "user" + parse_args.return_value = args_mock + + parse_config.return_value = "pg_config" + + fetch_markets.return_value = [[3, "config1", 1], [1, "config2", 2]] + + main.main(["Foo", "Bar"]) + + parse_args.assert_called_with(["Foo", "Bar"]) + parse_config.assert_called_with(args_mock) + fetch_markets.assert_called_with("pg_config", "user") + + self.assertEqual(2, process.call_count) + process.assert_has_calls([ + mock.call("config1", 3, 1, args_mock, "pg_config"), + mock.call("config2", 1, 2, args_mock, "pg_config"), + ]) + with self.subTest(parallel=True): + with mock.patch("main.parse_args") as parse_args,\ + mock.patch("main.parse_config") as parse_config,\ + mock.patch("main.fetch_markets") as fetch_markets,\ + mock.patch("main.process") as process,\ + mock.patch("store.Portfolio.start_worker") as start: + + args_mock = mock.Mock() + args_mock.parallel = True + args_mock.user = "user" + parse_args.return_value = args_mock + + parse_config.return_value = "pg_config" + + fetch_markets.return_value = [[3, "config1", 1], [1, "config2", 2]] + + main.main(["Foo", "Bar"]) + + parse_args.assert_called_with(["Foo", "Bar"]) + parse_config.assert_called_with(args_mock) + fetch_markets.assert_called_with("pg_config", "user") + + start.assert_called_once_with() + self.assertEqual(2, process.call_count) + process.assert_has_calls([ + mock.call.__bool__(), + mock.call("config1", 3, 1, args_mock, "pg_config"), + mock.call.__bool__(), + mock.call("config2", 1, 2, args_mock, "pg_config"), + ]) + + @mock.patch.object(main.sys, "exit") + @mock.patch("main.os") + def test_parse_config(self, os, exit): + with self.subTest(report_path=None): + args = main.configargparse.Namespace(**{ + "db_host": "host", + "db_port": "port", + "db_user": "user", + "db_password": "password", + "db_database": "database", + "report_path": None, + }) + + result = main.parse_config(args) + self.assertEqual({ "host": "host", "port": "port", "user": + "user", "password": "password", "database": "database" + }, result) + with self.assertRaises(AttributeError): + args.db_password + + with self.subTest(report_path="present"): + args = main.configargparse.Namespace(**{ + "db_host": "host", + "db_port": "port", + "db_user": "user", + "db_password": "password", + "db_database": "database", + "report_path": "report_path", + }) + + os.path.exists.return_value = False + + result = main.parse_config(args) + + os.path.exists.assert_called_once_with("report_path") + os.makedirs.assert_called_once_with("report_path") + + def test_parse_args(self): + with self.subTest(config="config.ini"): + args = main.parse_args([]) + self.assertEqual("config.ini", args.config) + self.assertFalse(args.before) + self.assertFalse(args.after) + self.assertFalse(args.debug) + + args = main.parse_args(["--before", "--after", "--debug"]) + self.assertTrue(args.before) + self.assertTrue(args.after) + self.assertTrue(args.debug) + + with self.subTest(config="inexistant"), \ + self.assertRaises(SystemExit), \ + mock.patch('sys.stderr', new_callable=StringIO) as stdout_mock: + args = main.parse_args(["--config", "foo.bar"]) + + @mock.patch.object(main, "psycopg2") + def test_fetch_markets(self, psycopg2): + connect_mock = mock.Mock() + cursor_mock = mock.MagicMock() + cursor_mock.__iter__.return_value = ["row_1", "row_2"] + + connect_mock.cursor.return_value = cursor_mock + psycopg2.connect.return_value = connect_mock + + with self.subTest(user=None): + rows = list(main.fetch_markets({"foo": "bar"}, None)) + + psycopg2.connect.assert_called_once_with(foo="bar") + cursor_mock.execute.assert_called_once_with("SELECT id,config,user_id FROM market_configs") + + self.assertEqual(["row_1", "row_2"], rows) + + psycopg2.connect.reset_mock() + cursor_mock.execute.reset_mock() + with self.subTest(user=1): + rows = list(main.fetch_markets({"foo": "bar"}, 1)) + + psycopg2.connect.assert_called_once_with(foo="bar") + cursor_mock.execute.assert_called_once_with("SELECT id,config,user_id FROM market_configs WHERE user_id = %s", 1) + + self.assertEqual(["row_1", "row_2"], rows) + +