From d52c1c75544aee98f06be81cbce74d2fb45500b5 Mon Sep 17 00:00:00 2001 From: Bloodhunter4rc Date: Tue, 13 Dec 2022 20:21:06 +0100 Subject: [PATCH] Add unit tests --- docs/includes/pairlists.md | 2 +- freqtrade/plugins/pairlist/RemotePairList.py | 29 ++--- tests/plugins/test_remotepairlist.py | 123 +++++++++++++++++++ 3 files changed, 139 insertions(+), 15 deletions(-) create mode 100644 tests/plugins/test_remotepairlist.py diff --git a/docs/includes/pairlists.md b/docs/includes/pairlists.md index c12683e75..3a6ab7a3c 100644 --- a/docs/includes/pairlists.md +++ b/docs/includes/pairlists.md @@ -2,7 +2,7 @@ Pairlist Handlers define the list of pairs (pairlist) that the bot should trade. They are configured in the `pairlists` section of the configuration settings. -In your configuration, you can use Static Pairlist (defined by the [`StaticPairList`](#static-pair-list) Pairlist Handler), Dynamic Pairlist (defined by the [`VolumePairList`](#volume-pair-list) Pairlist Handler). +In your configuration, you can use Static Pairlist (defined by the [`StaticPairList`](#static-pair-list) Pairlist Handler) and Dynamic Pairlist (defined by the [`VolumePairList`](#volume-pair-list) Pairlist Handler). Additionally, [`AgeFilter`](#agefilter), [`PrecisionFilter`](#precisionfilter), [`PriceFilter`](#pricefilter), [`ShuffleFilter`](#shufflefilter), [`SpreadFilter`](#spreadfilter) and [`VolatilityFilter`](#volatilityfilter) act as Pairlist Filters, removing certain pairs and/or moving their positions in the pairlist. diff --git a/freqtrade/plugins/pairlist/RemotePairList.py b/freqtrade/plugins/pairlist/RemotePairList.py index 7ef038da7..418ac5b0b 100644 --- a/freqtrade/plugins/pairlist/RemotePairList.py +++ b/freqtrade/plugins/pairlist/RemotePairList.py @@ -74,21 +74,22 @@ class RemotePairList(IPairList): info = "Pairlist" try: - with requests.get(self._pairlist_url, headers=headers, - timeout=self._read_timeout) as response: - content_type = response.headers.get('content-type') - time_elapsed = response.elapsed.total_seconds() + response = requests.get(self._pairlist_url, headers=headers, + timeout=self._read_timeout) + content_type = response.headers.get('content-type') + time_elapsed = response.elapsed.total_seconds() - if "application/json" in str(content_type): - jsonparse = response.json() - pairlist = jsonparse['pairs'] - info = jsonparse.get('info', '')[:1000] - else: - raise OperationalException( - 'Remotepairlist is not of type JSON abort') + print(response) - self._refresh_period = jsonparse.get('refresh_period', self._refresh_period) - self._pair_cache = TTLCache(maxsize=1, ttl=self._refresh_period) + if "application/json" in str(content_type): + jsonparse = response.json() + pairlist = jsonparse['pairs'] + info = jsonparse.get('info', '') + else: + raise OperationalException('RemotePairList is not of type JSON abort ') + + self._refresh_period = jsonparse.get('refresh_period', self._refresh_period) + self._pair_cache = TTLCache(maxsize=1, ttl=self._refresh_period) except requests.exceptions.RequestException: self.log_once(f'Was not able to fetch pairlist from:' @@ -127,7 +128,7 @@ class RemotePairList(IPairList): # Load the JSON data into a dictionary jsonparse = json.load(json_file) pairlist = jsonparse['pairs'] - info = jsonparse.get('info', '')[:1000] + info = jsonparse.get('info', '') self._refresh_period = jsonparse.get('refresh_period', self._refresh_period) self._pair_cache = TTLCache(maxsize=1, ttl=self._refresh_period) diff --git a/tests/plugins/test_remotepairlist.py b/tests/plugins/test_remotepairlist.py new file mode 100644 index 000000000..743534bc3 --- /dev/null +++ b/tests/plugins/test_remotepairlist.py @@ -0,0 +1,123 @@ +from unittest.mock import MagicMock + +import pytest + +from freqtrade.exceptions import OperationalException +from freqtrade.plugins.pairlist.RemotePairList import RemotePairList +from freqtrade.plugins.pairlistmanager import PairListManager +from tests.conftest import get_patched_exchange, get_patched_freqtradebot + + +@pytest.fixture(scope="function") +def rpl_config(default_conf): + default_conf['stake_currency'] = 'USDT' + + default_conf['exchange']['pair_whitelist'] = [ + 'ETH/USDT', + 'BTC/USDT', + ] + default_conf['exchange']['pair_blacklist'] = [ + 'BLK/USDT' + ] + return default_conf + + +def test_fetch_pairlist_mock_response_html(mocker, rpl_config): + mock_response = MagicMock() + mock_response.headers = {'content-type': 'text/html'} + mocker.patch('requests.get', return_value=mock_response) + + rpl_config['pairlists'] = [ + { + "method": "RemotePairList", + "pairlist_url": "http://example.com/pairlist", + "number_assets": 10, + "read_timeout": 10, + "keep_pairlist_on_failure": True, + } + ] + + exchange = get_patched_exchange(mocker, rpl_config) + pairlistmanager = PairListManager(exchange, rpl_config) + + mocker.patch("freqtrade.plugins.pairlist.RemotePairList.requests.get", + return_value=mock_response) + remote_pairlist = RemotePairList(exchange, pairlistmanager, rpl_config, + rpl_config['pairlists'][0], 0) + + with pytest.raises(OperationalException, match='RemotePairList is not of type JSON abort'): + remote_pairlist.fetch_pairlist() + + +def test_remote_pairlist_init_no_pairlist_url(mocker, rpl_config): + + rpl_config['pairlists'] = [ + { + "method": "RemotePairList", + "number_assets": 10, + "keep_pairlist_on_failure": True, + } + ] + + get_patched_exchange(mocker, rpl_config) + with pytest.raises(OperationalException, match=r'`pairlist_url` not specified.' + r' Please check your configuration for "pairlist.config.pairlist_url"'): + get_patched_freqtradebot(mocker, rpl_config) + + +def test_remote_pairlist_init_no_number_assets(mocker, rpl_config): + + rpl_config['pairlists'] = [ + { + "method": "RemotePairList", + "pairlist_url": "http://example.com/pairlist", + "keep_pairlist_on_failure": True, + } + ] + + get_patched_exchange(mocker, rpl_config) + + with pytest.raises(OperationalException, match=r'`number_assets` not specified. ' + 'Please check your configuration for "pairlist.config.number_assets"'): + get_patched_freqtradebot(mocker, rpl_config) + + +def test_fetch_pairlist_mock_response_valid(mocker, rpl_config): + + rpl_config['pairlists'] = [ + { + "method": "RemotePairList", + "pairlist_url": "http://example.com/pairlist", + "number_assets": 10, + "refresh_period": 10, + "read_timeout": 10, + "keep_pairlist_on_failure": True, + } + ] + + mock_response = MagicMock() + + mock_response.json.return_value = { + "pairs": ["ETH/BTC", "XRP/BTC", "LTC/BTC", "EOS/BTC"], + "info": "Mock pairlist response", + "refresh_period": 60 + } + + mock_response.headers = { + "content-type": "application/json" + } + + mock_response.elapsed.total_seconds.return_value = 0.4 + mocker.patch("freqtrade.plugins.pairlist.RemotePairList.requests.get", + return_value=mock_response) + + exchange = get_patched_exchange(mocker, rpl_config) + pairlistmanager = PairListManager(exchange, rpl_config) + remote_pairlist = RemotePairList(exchange, pairlistmanager, rpl_config, + rpl_config['pairlists'][0], 0) + pairs, time_elapsed, info = remote_pairlist.fetch_pairlist() + + assert pairs == ["ETH/BTC", "XRP/BTC", "LTC/BTC", "EOS/BTC"] + assert time_elapsed == 0.4 + assert info == "Mock pairlist response" + assert remote_pairlist._refresh_period == 60