stable/freqtrade/tests/test_configuration.py

721 lines
25 KiB
Python
Raw Normal View History

2018-07-29 14:09:44 +00:00
# pragma pylint: disable=missing-docstring, protected-access, invalid-name
import json
2018-07-19 19:12:27 +00:00
import logging
import warnings
from argparse import Namespace
from copy import deepcopy
2019-03-29 19:16:52 +00:00
from pathlib import Path
from unittest.mock import MagicMock
2018-03-17 21:44:47 +00:00
import pytest
from jsonschema import Draft4Validator, ValidationError, validate
from freqtrade import OperationalException, constants
from freqtrade.configuration import Arguments, Configuration
from freqtrade.configuration.check_exchange import check_exchange
from freqtrade.configuration.directory_operations import create_datadir, create_userdata_dir
from freqtrade.configuration.json_schema import validate_config_schema
2018-07-04 07:31:35 +00:00
from freqtrade.constants import DEFAULT_DB_DRYRUN_URL, DEFAULT_DB_PROD_URL
from freqtrade.loggers import _set_loggers
2018-12-25 13:35:48 +00:00
from freqtrade.state import RunMode
from freqtrade.tests.conftest import (log_has, log_has_re,
patched_configuration_load_config_file)
@pytest.fixture(scope="function")
def all_conf():
config_file = Path(__file__).parents[2] / "config_full.json.example"
print(config_file)
configuration = Configuration(Namespace())
conf = configuration._load_config_file(str(config_file))
return conf
2018-03-30 20:14:35 +00:00
def test_load_config_invalid_pair(default_conf) -> None:
default_conf['exchange']['pair_whitelist'].append('ETH-BTC')
with pytest.raises(ValidationError, match=r'.*does not match.*'):
validate_config_schema(default_conf)
2018-03-30 20:14:35 +00:00
def test_load_config_missing_attributes(default_conf) -> None:
default_conf.pop('exchange')
with pytest.raises(ValidationError, match=r'.*\'exchange\' is a required property.*'):
validate_config_schema(default_conf)
2018-06-03 22:48:26 +00:00
def test_load_config_incorrect_stake_amount(default_conf) -> None:
default_conf['stake_amount'] = 'fake'
2018-06-03 22:48:26 +00:00
with pytest.raises(ValidationError, match=r'.*\'fake\' does not match \'unlimited\'.*'):
validate_config_schema(default_conf)
2018-06-03 22:48:26 +00:00
def test_load_config_file(default_conf, mocker, caplog) -> None:
del default_conf['user_data_dir']
file_mock = mocker.patch('freqtrade.configuration.configuration.open', mocker.mock_open(
read_data=json.dumps(default_conf)
))
2018-05-31 19:04:10 +00:00
configuration = Configuration(Namespace())
validated_conf = configuration._load_config_file('somefile')
assert file_mock.call_count == 1
assert validated_conf.items() >= default_conf.items()
def test__args_to_config(caplog):
arg_list = ['--strategy-path', 'TestTest']
args = Arguments(arg_list, '').get_parsed_arg()
configuration = Configuration(args)
config = {}
with warnings.catch_warnings(record=True) as w:
# No warnings ...
configuration._args_to_config(config, argname="strategy_path", logstring="DeadBeef")
assert len(w) == 0
assert log_has("DeadBeef", caplog.record_tuples)
assert config['strategy_path'] == "TestTest"
configuration = Configuration(args)
config = {}
with warnings.catch_warnings(record=True) as w:
# Deprecation warnings!
configuration._args_to_config(config, argname="strategy_path", logstring="DeadBeef",
deprecated_msg="Going away soon!")
assert len(w) == 1
assert issubclass(w[-1].category, DeprecationWarning)
assert "DEPRECATED: Going away soon!" in str(w[-1].message)
assert log_has("DeadBeef", caplog.record_tuples)
assert config['strategy_path'] == "TestTest"
def test_load_config_max_open_trades_zero(default_conf, mocker, caplog) -> None:
default_conf['max_open_trades'] = 0
patched_configuration_load_config_file(mocker, default_conf)
args = Arguments([], '').get_parsed_arg()
configuration = Configuration(args)
validated_conf = configuration.load_config()
assert validated_conf['max_open_trades'] == 0
assert 'internals' in validated_conf
assert log_has('Validating configuration ...', caplog.record_tuples)
def test_load_config_combine_dicts(default_conf, mocker, caplog) -> None:
conf1 = deepcopy(default_conf)
conf2 = deepcopy(default_conf)
del conf1['exchange']['key']
del conf1['exchange']['secret']
del conf2['exchange']['name']
conf2['exchange']['pair_whitelist'] += ['NANO/BTC']
config_files = [conf1, conf2]
configsmock = MagicMock(side_effect=config_files)
2019-07-11 22:41:09 +00:00
mocker.patch(
'freqtrade.configuration.configuration.Configuration._load_config_file',
configsmock
)
arg_list = ['-c', 'test_conf.json', '--config', 'test2_conf.json', ]
args = Arguments(arg_list, '').get_parsed_arg()
configuration = Configuration(args)
validated_conf = configuration.load_config()
exchange_conf = default_conf['exchange']
assert validated_conf['exchange']['name'] == exchange_conf['name']
assert validated_conf['exchange']['key'] == exchange_conf['key']
assert validated_conf['exchange']['secret'] == exchange_conf['secret']
assert validated_conf['exchange']['pair_whitelist'] != conf1['exchange']['pair_whitelist']
assert validated_conf['exchange']['pair_whitelist'] == conf2['exchange']['pair_whitelist']
assert 'internals' in validated_conf
assert log_has('Validating configuration ...', caplog.record_tuples)
def test_load_config_max_open_trades_minus_one(default_conf, mocker, caplog) -> None:
default_conf['max_open_trades'] = -1
patched_configuration_load_config_file(mocker, default_conf)
args = Arguments([], '').get_parsed_arg()
configuration = Configuration(args)
validated_conf = configuration.load_config()
assert validated_conf['max_open_trades'] > 999999999
assert validated_conf['max_open_trades'] == float('inf')
assert log_has('Validating configuration ...', caplog.record_tuples)
2018-12-25 13:35:48 +00:00
assert "runmode" in validated_conf
assert validated_conf['runmode'] == RunMode.DRY_RUN
2018-06-08 00:01:38 +00:00
def test_load_config_file_exception(mocker) -> None:
mocker.patch(
2019-07-11 21:39:42 +00:00
'freqtrade.configuration.configuration.open',
MagicMock(side_effect=FileNotFoundError('File not found'))
)
2018-05-31 19:04:10 +00:00
configuration = Configuration(Namespace())
2018-06-08 00:01:38 +00:00
with pytest.raises(OperationalException, match=r'.*Config file "somefile" not found!*'):
configuration._load_config_file('somefile')
def test_load_config(default_conf, mocker) -> None:
patched_configuration_load_config_file(mocker, default_conf)
args = Arguments([], '').get_parsed_arg()
configuration = Configuration(args)
validated_conf = configuration.load_config()
2018-03-27 16:29:51 +00:00
assert validated_conf.get('strategy') == 'DefaultStrategy'
assert validated_conf.get('strategy_path') is None
2018-12-03 19:31:25 +00:00
assert 'edge' not in validated_conf
def test_load_config_with_params(default_conf, mocker) -> None:
patched_configuration_load_config_file(mocker, default_conf)
2019-07-11 21:39:42 +00:00
2018-05-31 19:04:10 +00:00
arglist = [
'--strategy', 'TestStrategy',
2018-03-27 16:29:51 +00:00
'--strategy-path', '/some/path',
2018-06-07 03:27:55 +00:00
'--db-url', 'sqlite:///someurl',
]
2018-05-31 19:04:10 +00:00
args = Arguments(arglist, '').get_parsed_arg()
configuration = Configuration(args)
validated_conf = configuration.load_config()
2018-03-27 16:29:51 +00:00
assert validated_conf.get('strategy') == 'TestStrategy'
assert validated_conf.get('strategy_path') == '/some/path'
2018-06-07 03:27:55 +00:00
assert validated_conf.get('db_url') == 'sqlite:///someurl'
2018-03-27 16:29:51 +00:00
# Test conf provided db_url prod
conf = default_conf.copy()
conf["dry_run"] = False
conf["db_url"] = "sqlite:///path/to/db.sqlite"
patched_configuration_load_config_file(mocker, conf)
arglist = [
'--strategy', 'TestStrategy',
'--strategy-path', '/some/path'
]
args = Arguments(arglist, '').get_parsed_arg()
configuration = Configuration(args)
validated_conf = configuration.load_config()
assert validated_conf.get('db_url') == "sqlite:///path/to/db.sqlite"
# Test conf provided db_url dry_run
conf = default_conf.copy()
conf["dry_run"] = True
conf["db_url"] = "sqlite:///path/to/db.sqlite"
patched_configuration_load_config_file(mocker, conf)
arglist = [
'--strategy', 'TestStrategy',
'--strategy-path', '/some/path'
]
args = Arguments(arglist, '').get_parsed_arg()
configuration = Configuration(args)
validated_conf = configuration.load_config()
assert validated_conf.get('db_url') == "sqlite:///path/to/db.sqlite"
# Test args provided db_url prod
conf = default_conf.copy()
conf["dry_run"] = False
del conf["db_url"]
patched_configuration_load_config_file(mocker, conf)
arglist = [
2018-07-29 14:09:44 +00:00
'--strategy', 'TestStrategy',
'--strategy-path', '/some/path'
]
args = Arguments(arglist, '').get_parsed_arg()
configuration = Configuration(args)
validated_conf = configuration.load_config()
assert validated_conf.get('db_url') == DEFAULT_DB_PROD_URL
2018-12-25 13:35:48 +00:00
assert "runmode" in validated_conf
assert validated_conf['runmode'] == RunMode.LIVE
# Test args provided db_url dry_run
conf = default_conf.copy()
conf["dry_run"] = True
conf["db_url"] = DEFAULT_DB_PROD_URL
patched_configuration_load_config_file(mocker, conf)
arglist = [
'--strategy', 'TestStrategy',
'--strategy-path', '/some/path'
]
args = Arguments(arglist, '').get_parsed_arg()
configuration = Configuration(args)
validated_conf = configuration.load_config()
assert validated_conf.get('db_url') == DEFAULT_DB_DRYRUN_URL
2018-03-27 16:29:51 +00:00
def test_load_custom_strategy(default_conf, mocker) -> None:
default_conf.update({
2018-03-27 16:29:51 +00:00
'strategy': 'CustomStrategy',
'strategy_path': '/tmp/strategies',
})
patched_configuration_load_config_file(mocker, default_conf)
2018-03-27 16:29:51 +00:00
args = Arguments([], '').get_parsed_arg()
configuration = Configuration(args)
validated_conf = configuration.load_config()
assert validated_conf.get('strategy') == 'CustomStrategy'
assert validated_conf.get('strategy_path') == '/tmp/strategies'
def test_show_info(default_conf, mocker, caplog) -> None:
patched_configuration_load_config_file(mocker, default_conf)
2019-07-11 21:39:42 +00:00
2018-05-31 19:04:10 +00:00
arglist = [
'--strategy', 'TestStrategy',
2018-06-07 03:27:55 +00:00
'--db-url', 'sqlite:///tmp/testdb',
]
2018-05-31 19:04:10 +00:00
args = Arguments(arglist, '').get_parsed_arg()
configuration = Configuration(args)
configuration.get_config()
2018-06-07 03:27:55 +00:00
assert log_has('Using DB: "sqlite:///tmp/testdb"', caplog.record_tuples)
assert log_has('Dry run is enabled', caplog.record_tuples)
def test_setup_configuration_without_arguments(mocker, default_conf, caplog) -> None:
patched_configuration_load_config_file(mocker, default_conf)
2019-07-11 21:39:42 +00:00
2018-05-31 19:04:10 +00:00
arglist = [
'--config', 'config.json',
'--strategy', 'DefaultStrategy',
'backtesting'
]
2018-05-31 19:04:10 +00:00
args = Arguments(arglist, '').get_parsed_arg()
configuration = Configuration(args)
config = configuration.get_config()
assert 'max_open_trades' in config
assert 'stake_currency' in config
assert 'stake_amount' in config
assert 'exchange' in config
assert 'pair_whitelist' in config['exchange']
assert 'datadir' in config
2019-07-21 13:56:32 +00:00
assert 'user_data_dir' in config
assert log_has(
2019-07-04 17:53:50 +00:00
'Using data directory: {} ...'.format(config['datadir']),
caplog.record_tuples
)
assert 'ticker_interval' in config
assert not log_has('Parameter -i/--ticker-interval detected ...', caplog.record_tuples)
assert 'live' not in config
assert not log_has('Parameter -l/--live detected ...', caplog.record_tuples)
assert 'position_stacking' not in config
assert not log_has('Parameter --enable-position-stacking detected ...', caplog.record_tuples)
assert 'refresh_pairs' not in config
assert not log_has('Parameter -r/--refresh-pairs-cached detected ...', caplog.record_tuples)
assert 'timerange' not in config
assert 'export' not in config
def test_setup_configuration_with_arguments(mocker, default_conf, caplog) -> None:
patched_configuration_load_config_file(mocker, default_conf)
2019-07-11 22:41:09 +00:00
mocker.patch(
2019-07-12 00:26:27 +00:00
'freqtrade.configuration.configuration.create_datadir',
lambda c, x: x
2019-07-11 22:41:09 +00:00
)
2019-07-21 12:32:29 +00:00
mocker.patch(
'freqtrade.configuration.configuration.create_userdata_dir',
2019-07-21 13:56:32 +00:00
lambda x: Path(x)
2019-07-21 12:32:29 +00:00
)
2018-05-31 19:04:10 +00:00
arglist = [
'--config', 'config.json',
'--strategy', 'DefaultStrategy',
'--datadir', '/foo/bar',
2019-07-21 12:32:29 +00:00
'--userdir', "/tmp/freqtrade",
'backtesting',
'--ticker-interval', '1m',
'--live',
'--enable-position-stacking',
2018-07-17 19:05:03 +00:00
'--disable-max-market-positions',
'--refresh-pairs-cached',
'--timerange', ':100',
'--export', '/bar/foo'
]
2018-05-31 19:04:10 +00:00
args = Arguments(arglist, '').get_parsed_arg()
configuration = Configuration(args)
config = configuration.get_config()
assert 'max_open_trades' in config
assert 'stake_currency' in config
assert 'stake_amount' in config
assert 'exchange' in config
assert 'pair_whitelist' in config['exchange']
assert 'datadir' in config
assert log_has(
2019-07-21 12:32:29 +00:00
'Using data directory: {} ...'.format("/foo/bar"),
caplog.record_tuples
)
assert log_has(
'Using user-data directory: {} ...'.format("/tmp/freqtrade"),
caplog.record_tuples
)
2019-07-21 13:56:32 +00:00
assert 'user_data_dir' in config
assert 'ticker_interval' in config
2019-04-24 19:24:00 +00:00
assert log_has('Parameter -i/--ticker-interval detected ... Using ticker_interval: 1m ...',
caplog.record_tuples)
assert 'live' in config
assert log_has('Parameter -l/--live detected ...', caplog.record_tuples)
assert 'position_stacking'in config
assert log_has('Parameter --enable-position-stacking detected ...', caplog.record_tuples)
2018-07-17 19:05:03 +00:00
assert 'use_max_market_positions' in config
assert log_has('Parameter --disable-max-market-positions detected ...', caplog.record_tuples)
assert log_has('max_open_trades set to unlimited ...', caplog.record_tuples)
assert 'refresh_pairs'in config
assert log_has('Parameter -r/--refresh-pairs-cached detected ...', caplog.record_tuples)
assert 'timerange' in config
assert log_has(
'Parameter --timerange detected: {} ...'.format(config['timerange']),
caplog.record_tuples
)
assert 'export' in config
assert log_has(
'Parameter --export detected: {} ...'.format(config['export']),
caplog.record_tuples
)
2018-07-28 04:40:39 +00:00
def test_setup_configuration_with_stratlist(mocker, default_conf, caplog) -> None:
"""
Test setup_configuration() function
"""
patched_configuration_load_config_file(mocker, default_conf)
2018-07-28 04:40:39 +00:00
arglist = [
'--config', 'config.json',
'backtesting',
'--ticker-interval', '1m',
'--export', '/bar/foo',
'--strategy-list',
'DefaultStrategy',
'TestStrategy'
]
args = Arguments(arglist, '').get_parsed_arg()
2018-12-25 13:35:48 +00:00
configuration = Configuration(args, RunMode.BACKTEST)
2018-07-28 04:40:39 +00:00
config = configuration.get_config()
2018-12-25 13:35:48 +00:00
assert config['runmode'] == RunMode.BACKTEST
2018-07-28 04:40:39 +00:00
assert 'max_open_trades' in config
assert 'stake_currency' in config
assert 'stake_amount' in config
assert 'exchange' in config
assert 'pair_whitelist' in config['exchange']
assert 'datadir' in config
assert log_has(
2019-07-04 17:53:50 +00:00
'Using data directory: {} ...'.format(config['datadir']),
2018-07-28 04:40:39 +00:00
caplog.record_tuples
)
assert 'ticker_interval' in config
2019-04-24 19:24:00 +00:00
assert log_has('Parameter -i/--ticker-interval detected ... Using ticker_interval: 1m ...',
caplog.record_tuples)
2018-07-28 04:40:39 +00:00
assert 'strategy_list' in config
assert log_has('Using strategy list of 2 Strategies', caplog.record_tuples)
assert 'position_stacking' not in config
assert 'use_max_market_positions' not in config
assert 'timerange' not in config
assert 'export' in config
assert log_has(
'Parameter --export detected: {} ...'.format(config['export']),
caplog.record_tuples
)
def test_hyperopt_with_arguments(mocker, default_conf, caplog) -> None:
patched_configuration_load_config_file(mocker, default_conf)
2019-07-11 21:39:42 +00:00
2018-05-31 19:04:10 +00:00
arglist = [
'hyperopt',
'--epochs', '10',
'--spaces', 'all',
]
2018-05-31 19:04:10 +00:00
args = Arguments(arglist, '').get_parsed_arg()
2018-12-25 13:35:48 +00:00
configuration = Configuration(args, RunMode.HYPEROPT)
config = configuration.get_config()
assert 'epochs' in config
assert int(config['epochs']) == 10
2019-04-24 19:12:23 +00:00
assert log_has('Parameter --epochs detected ... Will run Hyperopt with for 10 epochs ...',
caplog.record_tuples)
assert 'spaces' in config
assert config['spaces'] == ['all']
assert log_has('Parameter -s/--spaces detected: [\'all\']', caplog.record_tuples)
2018-12-25 13:35:48 +00:00
assert "runmode" in config
assert config['runmode'] == RunMode.HYPEROPT
2018-03-30 20:14:35 +00:00
2018-10-04 18:35:28 +00:00
def test_check_exchange(default_conf, caplog) -> None:
2019-06-14 15:40:25 +00:00
# Test an officially supported by Freqtrade team exchange
default_conf.get('exchange').update({'name': 'BITTREX'})
assert check_exchange(default_conf)
assert log_has_re(r"Exchange .* is officially supported by the Freqtrade development team\.",
caplog.record_tuples)
caplog.clear()
2018-03-30 20:14:35 +00:00
2019-06-14 15:40:25 +00:00
# Test an officially supported by Freqtrade team exchange
default_conf.get('exchange').update({'name': 'binance'})
assert check_exchange(default_conf)
assert log_has_re(r"Exchange .* is officially supported by the Freqtrade development team\.",
caplog.record_tuples)
caplog.clear()
2018-03-30 20:14:35 +00:00
2019-06-14 15:40:25 +00:00
# Test an available exchange, supported by ccxt
default_conf.get('exchange').update({'name': 'kraken'})
assert check_exchange(default_conf)
assert log_has_re(r"Exchange .* is supported by ccxt and .* not officially supported "
r"by the Freqtrade development team\. .*",
caplog.record_tuples)
caplog.clear()
2019-06-14 15:40:25 +00:00
# Test a 'bad' exchange, which known to have serious problems
default_conf.get('exchange').update({'name': 'bitmex'})
assert not check_exchange(default_conf)
assert log_has_re(r"Exchange .* is known to not work with the bot yet\. "
r"Use it only for development and testing purposes\.",
caplog.record_tuples)
caplog.clear()
2019-06-14 15:40:25 +00:00
# Test a 'bad' exchange with check_for_bad=False
default_conf.get('exchange').update({'name': 'bitmex'})
assert check_exchange(default_conf, False)
assert log_has_re(r"Exchange .* is supported by ccxt and .* not officially supported "
r"by the Freqtrade development team\. .*",
caplog.record_tuples)
caplog.clear()
2019-06-14 15:40:25 +00:00
# Test an invalid exchange
default_conf.get('exchange').update({'name': 'unknown_exchange'})
2018-03-30 20:14:35 +00:00
with pytest.raises(
OperationalException,
2019-06-12 20:03:16 +00:00
match=r'.*Exchange "unknown_exchange" is not supported by ccxt '
r'and therefore not available for the bot.*'
2018-03-30 20:14:35 +00:00
):
check_exchange(default_conf)
2018-07-19 19:12:27 +00:00
def test_cli_verbose_with_params(default_conf, mocker, caplog) -> None:
patched_configuration_load_config_file(mocker, default_conf)
2019-07-11 21:39:42 +00:00
2018-07-19 19:12:27 +00:00
# Prevent setting loggers
mocker.patch('freqtrade.loggers._set_loggers', MagicMock)
2018-07-19 19:12:27 +00:00
arglist = ['-vvv']
args = Arguments(arglist, '').get_parsed_arg()
configuration = Configuration(args)
validated_conf = configuration.load_config()
assert validated_conf.get('verbosity') == 3
assert log_has('Verbosity set to 3', caplog.record_tuples)
def test_set_loggers() -> None:
# Reset Logging to Debug, otherwise this fails randomly as it's set globally
logging.getLogger('requests').setLevel(logging.DEBUG)
logging.getLogger("urllib3").setLevel(logging.DEBUG)
logging.getLogger('ccxt.base.exchange').setLevel(logging.DEBUG)
logging.getLogger('telegram').setLevel(logging.DEBUG)
previous_value1 = logging.getLogger('requests').level
previous_value2 = logging.getLogger('ccxt.base.exchange').level
previous_value3 = logging.getLogger('telegram').level
_set_loggers()
2018-07-19 19:12:27 +00:00
value1 = logging.getLogger('requests').level
assert previous_value1 is not value1
assert value1 is logging.INFO
value2 = logging.getLogger('ccxt.base.exchange').level
assert previous_value2 is not value2
assert value2 is logging.INFO
value3 = logging.getLogger('telegram').level
assert previous_value3 is not value3
assert value3 is logging.INFO
_set_loggers(verbosity=2)
2018-07-19 19:12:27 +00:00
assert logging.getLogger('requests').level is logging.DEBUG
assert logging.getLogger('ccxt.base.exchange').level is logging.INFO
assert logging.getLogger('telegram').level is logging.INFO
_set_loggers(verbosity=3)
2018-07-19 19:12:27 +00:00
assert logging.getLogger('requests').level is logging.DEBUG
assert logging.getLogger('ccxt.base.exchange').level is logging.DEBUG
assert logging.getLogger('telegram').level is logging.INFO
2019-03-29 19:16:52 +00:00
def test_set_logfile(default_conf, mocker):
patched_configuration_load_config_file(mocker, default_conf)
2019-03-29 19:16:52 +00:00
arglist = [
'--logfile', 'test_file.log',
]
args = Arguments(arglist, '').get_parsed_arg()
configuration = Configuration(args)
validated_conf = configuration.load_config()
assert validated_conf['logfile'] == "test_file.log"
f = Path("test_file.log")
assert f.is_file()
f.unlink()
def test_load_config_warn_forcebuy(default_conf, mocker, caplog) -> None:
default_conf['forcebuy_enable'] = True
patched_configuration_load_config_file(mocker, default_conf)
args = Arguments([], '').get_parsed_arg()
configuration = Configuration(args)
validated_conf = configuration.load_config()
assert validated_conf.get('forcebuy_enable')
assert log_has('`forcebuy` RPC message enabled.', caplog.record_tuples)
def test_validate_default_conf(default_conf) -> None:
validate(default_conf, constants.CONF_SCHEMA, Draft4Validator)
2019-01-01 13:07:40 +00:00
2019-07-12 00:26:27 +00:00
def test_create_datadir(mocker, default_conf, caplog) -> None:
2019-07-17 18:53:29 +00:00
mocker.patch.object(Path, "is_dir", MagicMock(return_value=False))
md = mocker.patch.object(Path, 'mkdir', MagicMock())
2019-07-12 00:26:27 +00:00
create_datadir(default_conf, '/foo/bar')
2019-07-17 18:53:29 +00:00
assert md.call_args[1]['parents'] is True
2019-01-01 13:07:40 +00:00
assert log_has('Created data directory: /foo/bar', caplog.record_tuples)
2019-07-21 11:42:56 +00:00
def test_create_userdata_dir(mocker, default_conf, caplog) -> None:
mocker.patch.object(Path, "is_dir", MagicMock(return_value=False))
md = mocker.patch.object(Path, 'mkdir', MagicMock())
2019-07-21 12:32:29 +00:00
x = create_userdata_dir('/tmp/bar')
2019-07-21 11:42:56 +00:00
assert md.call_count == 6
assert md.call_args[1]['parents'] is False
assert log_has('Created user-data directory: /tmp/bar', caplog.record_tuples)
2019-07-21 13:56:32 +00:00
assert isinstance(x, Path)
assert str(x) == "/tmp/bar"
2019-07-21 11:42:56 +00:00
def test_create_userdata_dir_exists(mocker, default_conf, caplog) -> None:
mocker.patch.object(Path, "is_dir", MagicMock(return_value=True))
md = mocker.patch.object(Path, 'mkdir', MagicMock())
create_userdata_dir('/tmp/bar')
assert md.call_count == 0
2019-03-14 08:26:31 +00:00
def test_validate_tsl(default_conf):
default_conf['trailing_stop'] = True
default_conf['trailing_stop_positive'] = 0
default_conf['trailing_stop_positive_offset'] = 0
default_conf['trailing_only_offset_is_reached'] = True
with pytest.raises(OperationalException,
2019-03-16 09:38:25 +00:00
match=r'The config trailing_only_offset_is_reached needs '
'trailing_stop_positive_offset to be more than 0 in your config.'):
2019-03-14 08:26:31 +00:00
configuration = Configuration(Namespace())
2019-03-16 09:38:25 +00:00
configuration._validate_config_consistency(default_conf)
default_conf['trailing_stop_positive_offset'] = 0.01
default_conf['trailing_stop_positive'] = 0.015
with pytest.raises(OperationalException,
2019-03-16 09:38:25 +00:00
match=r'The config trailing_stop_positive_offset needs '
'to be greater than trailing_stop_positive_offset in your config.'):
2019-03-14 08:26:31 +00:00
configuration = Configuration(Namespace())
2019-03-16 09:38:25 +00:00
configuration._validate_config_consistency(default_conf)
default_conf['trailing_stop_positive'] = 0.01
default_conf['trailing_stop_positive_offset'] = 0.015
Configuration(Namespace())
configuration._validate_config_consistency(default_conf)
2019-04-11 15:07:51 +00:00
def test_load_config_default_exchange(all_conf) -> None:
2019-04-11 19:22:33 +00:00
"""
config['exchange'] subtree has required options in it
so it cannot be omitted in the config
"""
2019-04-11 15:07:51 +00:00
del all_conf['exchange']
assert 'exchange' not in all_conf
with pytest.raises(ValidationError,
match=r'\'exchange\' is a required property'):
validate_config_schema(all_conf)
2019-04-11 15:07:51 +00:00
def test_load_config_default_exchange_name(all_conf) -> None:
2019-04-11 19:22:33 +00:00
"""
config['exchange']['name'] option is required
so it cannot be omitted in the config
"""
2019-04-11 15:07:51 +00:00
del all_conf['exchange']['name']
assert 'name' not in all_conf['exchange']
with pytest.raises(ValidationError,
match=r'\'name\' is a required property'):
validate_config_schema(all_conf)
2019-04-11 15:07:51 +00:00
2019-04-24 07:48:25 +00:00
@pytest.mark.parametrize("keys", [("exchange", "sandbox", False),
("exchange", "key", ""),
("exchange", "secret", ""),
("exchange", "password", ""),
])
def test_load_config_default_subkeys(all_conf, keys) -> None:
2019-04-11 19:22:33 +00:00
"""
2019-04-24 07:48:25 +00:00
Test for parameters with default values in sub-paths
so they can be omitted in the config and the default value
2019-04-24 07:55:53 +00:00
should is added to the config.
2019-04-11 19:22:33 +00:00
"""
2019-04-24 07:48:25 +00:00
# Get first level key
key = keys[0]
# get second level key
subkey = keys[1]
2019-04-11 15:07:51 +00:00
2019-04-24 07:48:25 +00:00
del all_conf[key][subkey]
2019-04-11 15:07:51 +00:00
2019-04-24 07:48:25 +00:00
assert subkey not in all_conf[key]
2019-04-11 15:07:51 +00:00
validate_config_schema(all_conf)
2019-04-24 07:48:25 +00:00
assert subkey in all_conf[key]
assert all_conf[key][subkey] == keys[2]