diff options
Diffstat (limited to 'test.py')
-rw-r--r-- | test.py | 428 |
1 files changed, 262 insertions, 166 deletions
@@ -7,7 +7,7 @@ from unittest import mock | |||
7 | import requests | 7 | import requests |
8 | import requests_mock | 8 | import requests_mock |
9 | from io import StringIO | 9 | from io import StringIO |
10 | import portfolio, helper, market | 10 | import portfolio, market, main |
11 | 11 | ||
12 | limits = ["acceptance", "unit"] | 12 | limits = ["acceptance", "unit"] |
13 | for test_type in limits: | 13 | for test_type in limits: |
@@ -907,7 +907,163 @@ class MarketTest(WebMockTestCase): | |||
907 | self.ccxt.transfer_balance.assert_any_call("BTC", 3, "exchange", "margin") | 907 | self.ccxt.transfer_balance.assert_any_call("BTC", 3, "exchange", "margin") |
908 | self.ccxt.transfer_balance.assert_any_call("USDT", 100, "exchange", "margin") | 908 | self.ccxt.transfer_balance.assert_any_call("USDT", 100, "exchange", "margin") |
909 | self.ccxt.transfer_balance.assert_any_call("ETC", 5, "margin", "exchange") | 909 | self.ccxt.transfer_balance.assert_any_call("ETC", 5, "margin", "exchange") |
910 | 910 | ||
911 | def test_store_report(self): | ||
912 | |||
913 | file_open = mock.mock_open() | ||
914 | with self.subTest(file=None), mock.patch("market.open", file_open): | ||
915 | m = market.Market(self.ccxt, user_id=1) | ||
916 | m.store_report() | ||
917 | file_open.assert_not_called() | ||
918 | |||
919 | file_open = mock.mock_open() | ||
920 | m = market.Market(self.ccxt, report_path="present", user_id=1) | ||
921 | with self.subTest(file="present"),\ | ||
922 | mock.patch("market.open", file_open),\ | ||
923 | mock.patch.object(m, "report") as report,\ | ||
924 | mock.patch.object(market, "datetime") as time_mock: | ||
925 | |||
926 | time_mock.now.return_value = datetime.datetime(2018, 2, 25) | ||
927 | report.to_json.return_value = "json_content" | ||
928 | |||
929 | m.store_report() | ||
930 | |||
931 | file_open.assert_any_call("present/2018-02-25T00:00:00_1.json", "w") | ||
932 | file_open().write.assert_called_once_with("json_content") | ||
933 | m.report.to_json.assert_called_once_with() | ||
934 | |||
935 | m = market.Market(self.ccxt, report_path="error", user_id=1) | ||
936 | with self.subTest(file="error"),\ | ||
937 | mock.patch("market.open") as file_open,\ | ||
938 | mock.patch('sys.stdout', new_callable=StringIO) as stdout_mock: | ||
939 | file_open.side_effect = FileNotFoundError | ||
940 | |||
941 | m.store_report() | ||
942 | |||
943 | self.assertRegex(stdout_mock.getvalue(), "impossible to store report file: FileNotFoundError;") | ||
944 | |||
945 | def test_print_orders(self): | ||
946 | m = market.Market(self.ccxt) | ||
947 | with mock.patch.object(m.report, "log_stage") as log_stage,\ | ||
948 | mock.patch.object(m.balances, "fetch_balances") as fetch_balances,\ | ||
949 | mock.patch.object(m, "prepare_trades") as prepare_trades,\ | ||
950 | mock.patch.object(m.trades, "prepare_orders") as prepare_orders: | ||
951 | m.print_orders() | ||
952 | |||
953 | log_stage.assert_called_with("print_orders") | ||
954 | fetch_balances.assert_called_with(tag="print_orders") | ||
955 | prepare_trades.assert_called_with(base_currency="BTC", | ||
956 | compute_value="average") | ||
957 | prepare_orders.assert_called_with(compute_value="average") | ||
958 | |||
959 | def test_print_balances(self): | ||
960 | m = market.Market(self.ccxt) | ||
961 | |||
962 | with mock.patch.object(m.balances, "in_currency") as in_currency,\ | ||
963 | mock.patch.object(m.report, "log_stage") as log_stage,\ | ||
964 | mock.patch.object(m.balances, "fetch_balances") as fetch_balances,\ | ||
965 | mock.patch.object(m.report, "print_log") as print_log: | ||
966 | |||
967 | in_currency.return_value = { | ||
968 | "BTC": portfolio.Amount("BTC", "0.65"), | ||
969 | "ETH": portfolio.Amount("BTC", "0.3"), | ||
970 | } | ||
971 | |||
972 | m.print_balances() | ||
973 | |||
974 | log_stage.assert_called_once_with("print_balances") | ||
975 | fetch_balances.assert_called_with() | ||
976 | print_log.assert_has_calls([ | ||
977 | mock.call("total:"), | ||
978 | mock.call(portfolio.Amount("BTC", "0.95")), | ||
979 | ]) | ||
980 | |||
981 | @mock.patch("market.Processor.process") | ||
982 | @mock.patch("market.ReportStore.log_error") | ||
983 | @mock.patch("market.Market.store_report") | ||
984 | def test_process(self, store_report, log_error, process): | ||
985 | m = market.Market(self.ccxt) | ||
986 | with self.subTest(before=False, after=False): | ||
987 | m.process(None) | ||
988 | |||
989 | process.assert_not_called() | ||
990 | store_report.assert_called_once() | ||
991 | log_error.assert_not_called() | ||
992 | |||
993 | process.reset_mock() | ||
994 | log_error.reset_mock() | ||
995 | store_report.reset_mock() | ||
996 | with self.subTest(before=True, after=False): | ||
997 | m.process(None, before=True) | ||
998 | |||
999 | process.assert_called_once_with("sell_all", steps="before") | ||
1000 | store_report.assert_called_once() | ||
1001 | log_error.assert_not_called() | ||
1002 | |||
1003 | process.reset_mock() | ||
1004 | log_error.reset_mock() | ||
1005 | store_report.reset_mock() | ||
1006 | with self.subTest(before=False, after=True): | ||
1007 | m.process(None, after=True) | ||
1008 | |||
1009 | process.assert_called_once_with("sell_all", steps="after") | ||
1010 | store_report.assert_called_once() | ||
1011 | log_error.assert_not_called() | ||
1012 | |||
1013 | process.reset_mock() | ||
1014 | log_error.reset_mock() | ||
1015 | store_report.reset_mock() | ||
1016 | with self.subTest(before=True, after=True): | ||
1017 | m.process(None, before=True, after=True) | ||
1018 | |||
1019 | process.assert_has_calls([ | ||
1020 | mock.call("sell_all", steps="before"), | ||
1021 | mock.call("sell_all", steps="after"), | ||
1022 | ]) | ||
1023 | store_report.assert_called_once() | ||
1024 | log_error.assert_not_called() | ||
1025 | |||
1026 | process.reset_mock() | ||
1027 | log_error.reset_mock() | ||
1028 | store_report.reset_mock() | ||
1029 | with self.subTest(action="print_balances"),\ | ||
1030 | mock.patch.object(m, "print_balances") as print_balances: | ||
1031 | m.process(["print_balances"]) | ||
1032 | |||
1033 | process.assert_not_called() | ||
1034 | log_error.assert_not_called() | ||
1035 | store_report.assert_called_once() | ||
1036 | print_balances.assert_called_once_with() | ||
1037 | |||
1038 | log_error.reset_mock() | ||
1039 | store_report.reset_mock() | ||
1040 | with self.subTest(action="print_orders"),\ | ||
1041 | mock.patch.object(m, "print_orders") as print_orders,\ | ||
1042 | mock.patch.object(m, "print_balances") as print_balances: | ||
1043 | m.process(["print_orders", "print_balances"]) | ||
1044 | |||
1045 | process.assert_not_called() | ||
1046 | log_error.assert_not_called() | ||
1047 | store_report.assert_called_once() | ||
1048 | print_orders.assert_called_once_with() | ||
1049 | print_balances.assert_called_once_with() | ||
1050 | |||
1051 | log_error.reset_mock() | ||
1052 | store_report.reset_mock() | ||
1053 | with self.subTest(action="unknown"): | ||
1054 | m.process(["unknown"]) | ||
1055 | log_error.assert_called_once_with("market_process", message="Unknown action unknown") | ||
1056 | store_report.assert_called_once() | ||
1057 | |||
1058 | log_error.reset_mock() | ||
1059 | store_report.reset_mock() | ||
1060 | with self.subTest(unhandled_exception=True): | ||
1061 | process.side_effect = Exception("bouh") | ||
1062 | |||
1063 | m.process(None, before=True) | ||
1064 | log_error.assert_called_with("market_process", exception=mock.ANY) | ||
1065 | store_report.assert_called_once() | ||
1066 | |||
911 | @unittest.skipUnless("unit" in limits, "Unit skipped") | 1067 | @unittest.skipUnless("unit" in limits, "Unit skipped") |
912 | class TradeStoreTest(WebMockTestCase): | 1068 | class TradeStoreTest(WebMockTestCase): |
913 | def test_compute_trades(self): | 1069 | def test_compute_trades(self): |
@@ -2752,7 +2908,7 @@ class ReportStoreTest(WebMockTestCase): | |||
2752 | }) | 2908 | }) |
2753 | 2909 | ||
2754 | @unittest.skipUnless("unit" in limits, "Unit skipped") | 2910 | @unittest.skipUnless("unit" in limits, "Unit skipped") |
2755 | class HelperTest(WebMockTestCase): | 2911 | class MainTest(WebMockTestCase): |
2756 | def test_make_order(self): | 2912 | def test_make_order(self): |
2757 | self.m.get_ticker.return_value = { | 2913 | self.m.get_ticker.return_value = { |
2758 | "inverted": False, | 2914 | "inverted": False, |
@@ -2762,7 +2918,7 @@ class HelperTest(WebMockTestCase): | |||
2762 | } | 2918 | } |
2763 | 2919 | ||
2764 | with self.subTest(description="nominal case"): | 2920 | with self.subTest(description="nominal case"): |
2765 | helper.make_order(self.m, 10, "ETH") | 2921 | main.make_order(self.m, 10, "ETH") |
2766 | 2922 | ||
2767 | self.m.report.log_stage.assert_has_calls([ | 2923 | self.m.report.log_stage.assert_has_calls([ |
2768 | mock.call("make_order_begin"), | 2924 | mock.call("make_order_begin"), |
@@ -2787,7 +2943,7 @@ class HelperTest(WebMockTestCase): | |||
2787 | 2943 | ||
2788 | self.m.reset_mock() | 2944 | self.m.reset_mock() |
2789 | with self.subTest(compute_value="default"): | 2945 | with self.subTest(compute_value="default"): |
2790 | helper.make_order(self.m, 10, "ETH", action="dispose", | 2946 | main.make_order(self.m, 10, "ETH", action="dispose", |
2791 | compute_value="ask") | 2947 | compute_value="ask") |
2792 | 2948 | ||
2793 | trade = self.m.trades.all.append.mock_calls[0][1][0] | 2949 | trade = self.m.trades.all.append.mock_calls[0][1][0] |
@@ -2796,7 +2952,7 @@ class HelperTest(WebMockTestCase): | |||
2796 | 2952 | ||
2797 | self.m.reset_mock() | 2953 | self.m.reset_mock() |
2798 | with self.subTest(follow=False): | 2954 | with self.subTest(follow=False): |
2799 | result = helper.make_order(self.m, 10, "ETH", follow=False) | 2955 | result = main.make_order(self.m, 10, "ETH", follow=False) |
2800 | 2956 | ||
2801 | self.m.report.log_stage.assert_has_calls([ | 2957 | self.m.report.log_stage.assert_has_calls([ |
2802 | mock.call("make_order_begin"), | 2958 | mock.call("make_order_begin"), |
@@ -2816,7 +2972,7 @@ class HelperTest(WebMockTestCase): | |||
2816 | 2972 | ||
2817 | self.m.reset_mock() | 2973 | self.m.reset_mock() |
2818 | with self.subTest(base_currency="USDT"): | 2974 | with self.subTest(base_currency="USDT"): |
2819 | helper.make_order(self.m, 1, "BTC", base_currency="USDT") | 2975 | main.make_order(self.m, 1, "BTC", base_currency="USDT") |
2820 | 2976 | ||
2821 | trade = self.m.trades.all.append.mock_calls[0][1][0] | 2977 | trade = self.m.trades.all.append.mock_calls[0][1][0] |
2822 | self.assertEqual("BTC", trade.currency) | 2978 | self.assertEqual("BTC", trade.currency) |
@@ -2824,14 +2980,14 @@ class HelperTest(WebMockTestCase): | |||
2824 | 2980 | ||
2825 | self.m.reset_mock() | 2981 | self.m.reset_mock() |
2826 | with self.subTest(close_if_possible=True): | 2982 | with self.subTest(close_if_possible=True): |
2827 | helper.make_order(self.m, 10, "ETH", close_if_possible=True) | 2983 | main.make_order(self.m, 10, "ETH", close_if_possible=True) |
2828 | 2984 | ||
2829 | trade = self.m.trades.all.append.mock_calls[0][1][0] | 2985 | trade = self.m.trades.all.append.mock_calls[0][1][0] |
2830 | self.assertEqual(True, trade.orders[0].close_if_possible) | 2986 | self.assertEqual(True, trade.orders[0].close_if_possible) |
2831 | 2987 | ||
2832 | self.m.reset_mock() | 2988 | self.m.reset_mock() |
2833 | with self.subTest(action="dispose"): | 2989 | with self.subTest(action="dispose"): |
2834 | helper.make_order(self.m, 10, "ETH", action="dispose") | 2990 | main.make_order(self.m, 10, "ETH", action="dispose") |
2835 | 2991 | ||
2836 | trade = self.m.trades.all.append.mock_calls[0][1][0] | 2992 | trade = self.m.trades.all.append.mock_calls[0][1][0] |
2837 | self.assertEqual(0, trade.value_to) | 2993 | self.assertEqual(0, trade.value_to) |
@@ -2841,19 +2997,19 @@ class HelperTest(WebMockTestCase): | |||
2841 | 2997 | ||
2842 | self.m.reset_mock() | 2998 | self.m.reset_mock() |
2843 | with self.subTest(compute_value="default"): | 2999 | with self.subTest(compute_value="default"): |
2844 | helper.make_order(self.m, 10, "ETH", action="dispose", | 3000 | main.make_order(self.m, 10, "ETH", action="dispose", |
2845 | compute_value="bid") | 3001 | compute_value="bid") |
2846 | 3002 | ||
2847 | trade = self.m.trades.all.append.mock_calls[0][1][0] | 3003 | trade = self.m.trades.all.append.mock_calls[0][1][0] |
2848 | self.assertEqual(D("0.9"), trade.value_from.value) | 3004 | self.assertEqual(D("0.9"), trade.value_from.value) |
2849 | 3005 | ||
2850 | def test_user_market(self): | 3006 | def test_get_user_market(self): |
2851 | with mock.patch("helper.main_fetch_markets") as main_fetch_markets,\ | 3007 | with mock.patch("main.fetch_markets") as main_fetch_markets,\ |
2852 | mock.patch("helper.main_parse_config") as main_parse_config: | 3008 | mock.patch("main.parse_config") as main_parse_config: |
2853 | with self.subTest(debug=False): | 3009 | with self.subTest(debug=False): |
2854 | main_parse_config.return_value = ["pg_config", "report_path"] | 3010 | main_parse_config.return_value = ["pg_config", "report_path"] |
2855 | main_fetch_markets.return_value = [({"key": "market_config"},)] | 3011 | main_fetch_markets.return_value = [({"key": "market_config"},)] |
2856 | m = helper.get_user_market("config_path.ini", 1) | 3012 | m = main.get_user_market("config_path.ini", 1) |
2857 | 3013 | ||
2858 | self.assertIsInstance(m, market.Market) | 3014 | self.assertIsInstance(m, market.Market) |
2859 | self.assertFalse(m.debug) | 3015 | self.assertFalse(m.debug) |
@@ -2861,141 +3017,56 @@ class HelperTest(WebMockTestCase): | |||
2861 | with self.subTest(debug=True): | 3017 | with self.subTest(debug=True): |
2862 | main_parse_config.return_value = ["pg_config", "report_path"] | 3018 | main_parse_config.return_value = ["pg_config", "report_path"] |
2863 | main_fetch_markets.return_value = [({"key": "market_config"},)] | 3019 | main_fetch_markets.return_value = [({"key": "market_config"},)] |
2864 | m = helper.get_user_market("config_path.ini", 1, debug=True) | 3020 | m = main.get_user_market("config_path.ini", 1, debug=True) |
2865 | 3021 | ||
2866 | self.assertIsInstance(m, market.Market) | 3022 | self.assertIsInstance(m, market.Market) |
2867 | self.assertTrue(m.debug) | 3023 | self.assertTrue(m.debug) |
2868 | 3024 | ||
2869 | def test_main_store_report(self): | 3025 | def test_main(self): |
2870 | file_open = mock.mock_open() | 3026 | with mock.patch("main.parse_args") as parse_args,\ |
2871 | with self.subTest(file=None), mock.patch("__main__.open", file_open): | 3027 | mock.patch("main.parse_config") as parse_config,\ |
2872 | helper.main_store_report(None, 1, self.m) | 3028 | mock.patch("main.fetch_markets") as fetch_markets,\ |
2873 | file_open.assert_not_called() | 3029 | mock.patch("market.Market") as market_mock,\ |
2874 | |||
2875 | file_open = mock.mock_open() | ||
2876 | with self.subTest(file="present"), mock.patch("helper.open", file_open),\ | ||
2877 | mock.patch.object(helper, "datetime") as time_mock: | ||
2878 | time_mock.now.return_value = datetime.datetime(2018, 2, 25) | ||
2879 | self.m.report.to_json.return_value = "json_content" | ||
2880 | |||
2881 | helper.main_store_report("present", 1, self.m) | ||
2882 | |||
2883 | file_open.assert_any_call("present/2018-02-25T00:00:00_1.json", "w") | ||
2884 | file_open().write.assert_called_once_with("json_content") | ||
2885 | self.m.report.to_json.assert_called_once_with() | ||
2886 | |||
2887 | with self.subTest(file="error"),\ | ||
2888 | mock.patch("helper.open") as file_open,\ | ||
2889 | mock.patch('sys.stdout', new_callable=StringIO) as stdout_mock: | 3030 | mock.patch('sys.stdout', new_callable=StringIO) as stdout_mock: |
2890 | file_open.side_effect = FileNotFoundError | ||
2891 | 3031 | ||
2892 | helper.main_store_report("error", 1, self.m) | 3032 | args_mock = mock.Mock() |
3033 | args_mock.action = "action" | ||
3034 | args_mock.config = "config" | ||
3035 | args_mock.user = "user" | ||
3036 | args_mock.debug = "debug" | ||
3037 | args_mock.before = "before" | ||
3038 | args_mock.after = "after" | ||
3039 | parse_args.return_value = args_mock | ||
2893 | 3040 | ||
2894 | self.assertRegex(stdout_mock.getvalue(), "impossible to store report file: FileNotFoundError;") | 3041 | parse_config.return_value = ["pg_config", "report_path"] |
2895 | 3042 | ||
2896 | @mock.patch("helper.Processor.process") | 3043 | fetch_markets.return_value = [["config1", 1], ["config2", 2]] |
2897 | def test_main_process_market(self, process): | ||
2898 | with self.subTest(before=False, after=False): | ||
2899 | m = mock.Mock() | ||
2900 | helper.main_process_market(m, None) | ||
2901 | 3044 | ||
2902 | process.assert_not_called() | 3045 | main.main(["Foo", "Bar"]) |
2903 | 3046 | ||
2904 | process.reset_mock() | 3047 | parse_args.assert_called_with(["Foo", "Bar"]) |
2905 | with self.subTest(before=True, after=False): | 3048 | parse_config.assert_called_with("config") |
2906 | helper.main_process_market(m, None, before=True) | 3049 | fetch_markets.assert_called_with("pg_config", "user") |
2907 | 3050 | ||
2908 | process.assert_called_once_with("sell_all", steps="before") | 3051 | self.assertEqual(2, market_mock.from_config.call_count) |
2909 | 3052 | market_mock.from_config.assert_has_calls([ | |
2910 | process.reset_mock() | 3053 | mock.call("config1", debug="debug", user_id=1, report_path="report_path"), |
2911 | with self.subTest(before=False, after=True): | 3054 | mock.call().process("action", before="before", after="after"), |
2912 | helper.main_process_market(m, None, after=True) | 3055 | mock.call("config2", debug="debug", user_id=2, report_path="report_path"), |
2913 | 3056 | mock.call().process("action", before="before", after="after") | |
2914 | process.assert_called_once_with("sell_all", steps="after") | ||
2915 | |||
2916 | process.reset_mock() | ||
2917 | with self.subTest(before=True, after=True): | ||
2918 | helper.main_process_market(m, None, before=True, after=True) | ||
2919 | |||
2920 | process.assert_has_calls([ | ||
2921 | mock.call("sell_all", steps="before"), | ||
2922 | mock.call("sell_all", steps="after"), | ||
2923 | ]) | 3057 | ]) |
2924 | 3058 | ||
2925 | process.reset_mock() | 3059 | self.assertEqual("", stdout_mock.getvalue()) |
2926 | with self.subTest(action="print_balances"),\ | ||
2927 | mock.patch("helper.print_balances") as print_balances: | ||
2928 | helper.main_process_market("user", ["print_balances"]) | ||
2929 | |||
2930 | process.assert_not_called() | ||
2931 | print_balances.assert_called_once_with("user") | ||
2932 | |||
2933 | with self.subTest(action="print_orders"),\ | ||
2934 | mock.patch("helper.print_orders") as print_orders,\ | ||
2935 | mock.patch("helper.print_balances") as print_balances: | ||
2936 | helper.main_process_market("user", ["print_orders", "print_balances"]) | ||
2937 | |||
2938 | process.assert_not_called() | ||
2939 | print_orders.assert_called_once_with("user") | ||
2940 | print_balances.assert_called_once_with("user") | ||
2941 | |||
2942 | with self.subTest(action="unknown"),\ | ||
2943 | self.assertRaises(NotImplementedError): | ||
2944 | helper.main_process_market("user", ["unknown"]) | ||
2945 | |||
2946 | @mock.patch.object(helper, "psycopg2") | ||
2947 | def test_fetch_markets(self, psycopg2): | ||
2948 | connect_mock = mock.Mock() | ||
2949 | cursor_mock = mock.MagicMock() | ||
2950 | cursor_mock.__iter__.return_value = ["row_1", "row_2"] | ||
2951 | |||
2952 | connect_mock.cursor.return_value = cursor_mock | ||
2953 | psycopg2.connect.return_value = connect_mock | ||
2954 | |||
2955 | with self.subTest(user=None): | ||
2956 | rows = list(helper.main_fetch_markets({"foo": "bar"}, None)) | ||
2957 | |||
2958 | psycopg2.connect.assert_called_once_with(foo="bar") | ||
2959 | cursor_mock.execute.assert_called_once_with("SELECT config,user_id FROM market_configs") | ||
2960 | |||
2961 | self.assertEqual(["row_1", "row_2"], rows) | ||
2962 | |||
2963 | psycopg2.connect.reset_mock() | ||
2964 | cursor_mock.execute.reset_mock() | ||
2965 | with self.subTest(user=1): | ||
2966 | rows = list(helper.main_fetch_markets({"foo": "bar"}, 1)) | ||
2967 | |||
2968 | psycopg2.connect.assert_called_once_with(foo="bar") | ||
2969 | cursor_mock.execute.assert_called_once_with("SELECT config,user_id FROM market_configs WHERE user_id = %s", 1) | ||
2970 | |||
2971 | self.assertEqual(["row_1", "row_2"], rows) | ||
2972 | |||
2973 | @mock.patch.object(helper.sys, "exit") | ||
2974 | def test_main_parse_args(self, exit): | ||
2975 | with self.subTest(config="config.ini"): | ||
2976 | args = helper.main_parse_args([]) | ||
2977 | self.assertEqual("config.ini", args.config) | ||
2978 | self.assertFalse(args.before) | ||
2979 | self.assertFalse(args.after) | ||
2980 | self.assertFalse(args.debug) | ||
2981 | |||
2982 | args = helper.main_parse_args(["--before", "--after", "--debug"]) | ||
2983 | self.assertTrue(args.before) | ||
2984 | self.assertTrue(args.after) | ||
2985 | self.assertTrue(args.debug) | ||
2986 | |||
2987 | exit.assert_not_called() | ||
2988 | 3060 | ||
2989 | with self.subTest(config="inexistant"),\ | 3061 | with self.subTest(exception=True): |
2990 | mock.patch('sys.stdout', new_callable=StringIO) as stdout_mock: | 3062 | market_mock.from_config.side_effect = Exception("boo") |
2991 | args = helper.main_parse_args(["--config", "foo.bar"]) | 3063 | main.main(["Foo", "Bar"]) |
2992 | exit.assert_called_once_with(1) | 3064 | self.assertEqual("Exception: boo\nException: boo\n", stdout_mock.getvalue()) |
2993 | self.assertEqual("no config file found, exiting\n", stdout_mock.getvalue()) | ||
2994 | 3065 | ||
2995 | @mock.patch.object(helper.sys, "exit") | 3066 | @mock.patch.object(main.sys, "exit") |
2996 | @mock.patch("helper.configparser") | 3067 | @mock.patch("main.configparser") |
2997 | @mock.patch("helper.os") | 3068 | @mock.patch("main.os") |
2998 | def test_main_parse_config(self, os, configparser, exit): | 3069 | def test_parse_config(self, os, configparser, exit): |
2999 | with self.subTest(pg_config=True, report_path=None): | 3070 | with self.subTest(pg_config=True, report_path=None): |
3000 | config_mock = mock.MagicMock() | 3071 | config_mock = mock.MagicMock() |
3001 | configparser.ConfigParser.return_value = config_mock | 3072 | configparser.ConfigParser.return_value = config_mock |
@@ -3005,7 +3076,7 @@ class HelperTest(WebMockTestCase): | |||
3005 | config_mock.__contains__.side_effect = config | 3076 | config_mock.__contains__.side_effect = config |
3006 | config_mock.__getitem__.return_value = "pg_config" | 3077 | config_mock.__getitem__.return_value = "pg_config" |
3007 | 3078 | ||
3008 | result = helper.main_parse_config("configfile") | 3079 | result = main.parse_config("configfile") |
3009 | 3080 | ||
3010 | config_mock.read.assert_called_with("configfile") | 3081 | config_mock.read.assert_called_with("configfile") |
3011 | 3082 | ||
@@ -3023,7 +3094,7 @@ class HelperTest(WebMockTestCase): | |||
3023 | ] | 3094 | ] |
3024 | 3095 | ||
3025 | os.path.exists.return_value = False | 3096 | os.path.exists.return_value = False |
3026 | result = helper.main_parse_config("configfile") | 3097 | result = main.parse_config("configfile") |
3027 | 3098 | ||
3028 | config_mock.read.assert_called_with("configfile") | 3099 | config_mock.read.assert_called_with("configfile") |
3029 | self.assertEqual(["pg_config", "report_path"], result) | 3100 | self.assertEqual(["pg_config", "report_path"], result) |
@@ -3034,46 +3105,71 @@ class HelperTest(WebMockTestCase): | |||
3034 | mock.patch('sys.stdout', new_callable=StringIO) as stdout_mock: | 3105 | mock.patch('sys.stdout', new_callable=StringIO) as stdout_mock: |
3035 | config_mock = mock.MagicMock() | 3106 | config_mock = mock.MagicMock() |
3036 | configparser.ConfigParser.return_value = config_mock | 3107 | configparser.ConfigParser.return_value = config_mock |
3037 | result = helper.main_parse_config("configfile") | 3108 | result = main.parse_config("configfile") |
3038 | 3109 | ||
3039 | config_mock.read.assert_called_with("configfile") | 3110 | config_mock.read.assert_called_with("configfile") |
3040 | exit.assert_called_once_with(1) | 3111 | exit.assert_called_once_with(1) |
3041 | self.assertEqual("no configuration for postgresql in config file\n", stdout_mock.getvalue()) | 3112 | self.assertEqual("no configuration for postgresql in config file\n", stdout_mock.getvalue()) |
3042 | 3113 | ||
3114 | @mock.patch.object(main.sys, "exit") | ||
3115 | def test_parse_args(self, exit): | ||
3116 | with self.subTest(config="config.ini"): | ||
3117 | args = main.parse_args([]) | ||
3118 | self.assertEqual("config.ini", args.config) | ||
3119 | self.assertFalse(args.before) | ||
3120 | self.assertFalse(args.after) | ||
3121 | self.assertFalse(args.debug) | ||
3043 | 3122 | ||
3044 | def test_print_orders(self): | 3123 | args = main.parse_args(["--before", "--after", "--debug"]) |
3045 | helper.print_orders(self.m) | 3124 | self.assertTrue(args.before) |
3125 | self.assertTrue(args.after) | ||
3126 | self.assertTrue(args.debug) | ||
3046 | 3127 | ||
3047 | self.m.report.log_stage.assert_called_with("print_orders") | 3128 | exit.assert_not_called() |
3048 | self.m.balances.fetch_balances.assert_called_with(tag="print_orders") | 3129 | |
3049 | self.m.prepare_trades.assert_called_with(base_currency="BTC", | 3130 | with self.subTest(config="inexistant"),\ |
3050 | compute_value="average") | 3131 | mock.patch('sys.stdout', new_callable=StringIO) as stdout_mock: |
3051 | self.m.trades.prepare_orders.assert_called_with(compute_value="average") | 3132 | args = main.parse_args(["--config", "foo.bar"]) |
3133 | exit.assert_called_once_with(1) | ||
3134 | self.assertEqual("no config file found, exiting\n", stdout_mock.getvalue()) | ||
3135 | |||
3136 | @mock.patch.object(main, "psycopg2") | ||
3137 | def test_fetch_markets(self, psycopg2): | ||
3138 | connect_mock = mock.Mock() | ||
3139 | cursor_mock = mock.MagicMock() | ||
3140 | cursor_mock.__iter__.return_value = ["row_1", "row_2"] | ||
3141 | |||
3142 | connect_mock.cursor.return_value = cursor_mock | ||
3143 | psycopg2.connect.return_value = connect_mock | ||
3144 | |||
3145 | with self.subTest(user=None): | ||
3146 | rows = list(main.fetch_markets({"foo": "bar"}, None)) | ||
3147 | |||
3148 | psycopg2.connect.assert_called_once_with(foo="bar") | ||
3149 | cursor_mock.execute.assert_called_once_with("SELECT config,user_id FROM market_configs") | ||
3150 | |||
3151 | self.assertEqual(["row_1", "row_2"], rows) | ||
3152 | |||
3153 | psycopg2.connect.reset_mock() | ||
3154 | cursor_mock.execute.reset_mock() | ||
3155 | with self.subTest(user=1): | ||
3156 | rows = list(main.fetch_markets({"foo": "bar"}, 1)) | ||
3157 | |||
3158 | psycopg2.connect.assert_called_once_with(foo="bar") | ||
3159 | cursor_mock.execute.assert_called_once_with("SELECT config,user_id FROM market_configs WHERE user_id = %s", 1) | ||
3160 | |||
3161 | self.assertEqual(["row_1", "row_2"], rows) | ||
3052 | 3162 | ||
3053 | def test_print_balances(self): | ||
3054 | self.m.balances.in_currency.return_value = { | ||
3055 | "BTC": portfolio.Amount("BTC", "0.65"), | ||
3056 | "ETH": portfolio.Amount("BTC", "0.3"), | ||
3057 | } | ||
3058 | |||
3059 | helper.print_balances(self.m) | ||
3060 | |||
3061 | self.m.report.log_stage.assert_called_once_with("print_balances") | ||
3062 | self.m.balances.fetch_balances.assert_called_with() | ||
3063 | self.m.report.print_log.assert_has_calls([ | ||
3064 | mock.call("total:"), | ||
3065 | mock.call(portfolio.Amount("BTC", "0.95")), | ||
3066 | ]) | ||
3067 | 3163 | ||
3068 | @unittest.skipUnless("unit" in limits, "Unit skipped") | 3164 | @unittest.skipUnless("unit" in limits, "Unit skipped") |
3069 | class ProcessorTest(WebMockTestCase): | 3165 | class ProcessorTest(WebMockTestCase): |
3070 | def test_values(self): | 3166 | def test_values(self): |
3071 | processor = helper.Processor(self.m) | 3167 | processor = market.Processor(self.m) |
3072 | 3168 | ||
3073 | self.assertEqual(self.m, processor.market) | 3169 | self.assertEqual(self.m, processor.market) |
3074 | 3170 | ||
3075 | def test_run_action(self): | 3171 | def test_run_action(self): |
3076 | processor = helper.Processor(self.m) | 3172 | processor = market.Processor(self.m) |
3077 | 3173 | ||
3078 | with mock.patch.object(processor, "parse_args") as parse_args: | 3174 | with mock.patch.object(processor, "parse_args") as parse_args: |
3079 | method_mock = mock.Mock() | 3175 | method_mock = mock.Mock() |
@@ -3090,7 +3186,7 @@ class ProcessorTest(WebMockTestCase): | |||
3090 | method_mock.assert_called_with(self.m, foo="bar") | 3186 | method_mock.assert_called_with(self.m, foo="bar") |
3091 | 3187 | ||
3092 | def test_select_step(self): | 3188 | def test_select_step(self): |
3093 | processor = helper.Processor(self.m) | 3189 | processor = market.Processor(self.m) |
3094 | 3190 | ||
3095 | scenario = processor.scenarios["sell_all"] | 3191 | scenario = processor.scenarios["sell_all"] |
3096 | 3192 | ||
@@ -3103,9 +3199,9 @@ class ProcessorTest(WebMockTestCase): | |||
3103 | with self.assertRaises(TypeError): | 3199 | with self.assertRaises(TypeError): |
3104 | processor.select_steps(scenario, ["wait"]) | 3200 | processor.select_steps(scenario, ["wait"]) |
3105 | 3201 | ||
3106 | @mock.patch("helper.Processor.process_step") | 3202 | @mock.patch("market.Processor.process_step") |
3107 | def test_process(self, process_step): | 3203 | def test_process(self, process_step): |
3108 | processor = helper.Processor(self.m) | 3204 | processor = market.Processor(self.m) |
3109 | 3205 | ||
3110 | processor.process("sell_all", foo="bar") | 3206 | processor.process("sell_all", foo="bar") |
3111 | self.assertEqual(3, process_step.call_count) | 3207 | self.assertEqual(3, process_step.call_count) |
@@ -3126,7 +3222,7 @@ class ProcessorTest(WebMockTestCase): | |||
3126 | ccxt = mock.Mock(spec=market.ccxt.poloniexE) | 3222 | ccxt = mock.Mock(spec=market.ccxt.poloniexE) |
3127 | m = market.Market(ccxt) | 3223 | m = market.Market(ccxt) |
3128 | 3224 | ||
3129 | processor = helper.Processor(m) | 3225 | processor = market.Processor(m) |
3130 | 3226 | ||
3131 | method, arguments = processor.method_arguments("wait_for_recent") | 3227 | method, arguments = processor.method_arguments("wait_for_recent") |
3132 | self.assertEqual(portfolio.Portfolio.wait_for_recent, method) | 3228 | self.assertEqual(portfolio.Portfolio.wait_for_recent, method) |
@@ -3152,7 +3248,7 @@ class ProcessorTest(WebMockTestCase): | |||
3152 | self.assertEqual(m.trades.close_trades, method) | 3248 | self.assertEqual(m.trades.close_trades, method) |
3153 | 3249 | ||
3154 | def test_process_step(self): | 3250 | def test_process_step(self): |
3155 | processor = helper.Processor(self.m) | 3251 | processor = market.Processor(self.m) |
3156 | 3252 | ||
3157 | with mock.patch.object(processor, "run_action") as run_action: | 3253 | with mock.patch.object(processor, "run_action") as run_action: |
3158 | step = processor.scenarios["sell_needed"][1] | 3254 | step = processor.scenarios["sell_needed"][1] |
@@ -3186,7 +3282,7 @@ class ProcessorTest(WebMockTestCase): | |||
3186 | self.m.balances.fetch_balances.assert_not_called() | 3282 | self.m.balances.fetch_balances.assert_not_called() |
3187 | 3283 | ||
3188 | def test_parse_args(self): | 3284 | def test_parse_args(self): |
3189 | processor = helper.Processor(self.m) | 3285 | processor = market.Processor(self.m) |
3190 | 3286 | ||
3191 | with mock.patch.object(processor, "method_arguments") as method_arguments: | 3287 | with mock.patch.object(processor, "method_arguments") as method_arguments: |
3192 | method_mock = mock.Mock() | 3288 | method_mock = mock.Mock() |