2018-02-04 09:21:16 +00:00
|
|
|
"""
|
|
|
|
Unit test file for main.py
|
|
|
|
"""
|
|
|
|
|
2018-06-09 02:29:48 +00:00
|
|
|
from copy import deepcopy
|
2017-11-07 21:27:44 +00:00
|
|
|
from unittest.mock import MagicMock
|
2018-03-17 21:44:47 +00:00
|
|
|
|
2017-11-07 21:27:44 +00:00
|
|
|
import pytest
|
2017-09-08 13:51:00 +00:00
|
|
|
|
2018-06-07 20:28:21 +00:00
|
|
|
from freqtrade import OperationalException
|
2018-06-09 02:29:48 +00:00
|
|
|
from freqtrade.arguments import Arguments
|
|
|
|
from freqtrade.freqtradebot import FreqtradeBot
|
2018-07-19 19:12:27 +00:00
|
|
|
from freqtrade.main import main, reconfigure
|
2018-06-09 02:29:48 +00:00
|
|
|
from freqtrade.state import State
|
2018-06-17 20:38:31 +00:00
|
|
|
from freqtrade.tests.conftest import log_has, patch_exchange
|
2018-01-06 10:21:09 +00:00
|
|
|
|
2018-01-10 09:25:45 +00:00
|
|
|
|
2018-02-04 09:21:16 +00:00
|
|
|
def test_parse_args_backtesting(mocker) -> None:
|
|
|
|
"""
|
|
|
|
Test that main() can start backtesting and also ensure we can pass some specific arguments
|
|
|
|
further argument parsing is done in test_arguments.py
|
|
|
|
"""
|
|
|
|
backtesting_mock = mocker.patch('freqtrade.optimize.backtesting.start', MagicMock())
|
|
|
|
main(['backtesting'])
|
2018-01-06 10:21:09 +00:00
|
|
|
assert backtesting_mock.call_count == 1
|
|
|
|
call_args = backtesting_mock.call_args[0][0]
|
|
|
|
assert call_args.config == 'config.json'
|
|
|
|
assert call_args.live is False
|
2018-07-19 19:12:27 +00:00
|
|
|
assert call_args.loglevel == 0
|
2018-01-06 10:21:09 +00:00
|
|
|
assert call_args.subparser == 'backtesting'
|
|
|
|
assert call_args.func is not None
|
2018-01-30 07:04:28 +00:00
|
|
|
assert call_args.ticker_interval is None
|
2018-01-06 10:21:09 +00:00
|
|
|
|
|
|
|
|
2018-02-04 09:21:16 +00:00
|
|
|
def test_main_start_hyperopt(mocker) -> None:
|
|
|
|
"""
|
2018-03-03 21:39:39 +00:00
|
|
|
Test that main() can start hyperopt
|
2018-02-04 09:21:16 +00:00
|
|
|
"""
|
|
|
|
hyperopt_mock = mocker.patch('freqtrade.optimize.hyperopt.start', MagicMock())
|
|
|
|
main(['hyperopt'])
|
2018-01-06 10:21:09 +00:00
|
|
|
assert hyperopt_mock.call_count == 1
|
|
|
|
call_args = hyperopt_mock.call_args[0][0]
|
|
|
|
assert call_args.config == 'config.json'
|
2018-07-19 19:12:27 +00:00
|
|
|
assert call_args.loglevel == 0
|
2018-01-06 10:21:09 +00:00
|
|
|
assert call_args.subparser == 'hyperopt'
|
|
|
|
assert call_args.func is not None
|
2017-09-08 13:51:00 +00:00
|
|
|
|
|
|
|
|
2018-06-07 20:28:21 +00:00
|
|
|
def test_main_fatal_exception(mocker, default_conf, caplog) -> None:
|
2018-02-04 09:21:16 +00:00
|
|
|
"""
|
2018-03-03 21:39:39 +00:00
|
|
|
Test main() function
|
2018-02-04 09:21:16 +00:00
|
|
|
In this test we are skipping the while True loop by throwing an exception.
|
|
|
|
"""
|
2018-06-17 20:38:31 +00:00
|
|
|
patch_exchange(mocker)
|
2018-02-04 09:21:16 +00:00
|
|
|
mocker.patch.multiple(
|
|
|
|
'freqtrade.freqtradebot.FreqtradeBot',
|
|
|
|
_init_modules=MagicMock(),
|
2018-06-07 20:28:21 +00:00
|
|
|
worker=MagicMock(side_effect=Exception),
|
2018-06-08 23:19:42 +00:00
|
|
|
cleanup=MagicMock(),
|
2017-12-16 02:39:47 +00:00
|
|
|
)
|
2018-06-07 20:28:21 +00:00
|
|
|
mocker.patch(
|
|
|
|
'freqtrade.configuration.Configuration._load_config_file',
|
|
|
|
lambda *args, **kwargs: default_conf
|
|
|
|
)
|
|
|
|
mocker.patch('freqtrade.freqtradebot.CryptoToFiatConverter', MagicMock())
|
|
|
|
mocker.patch('freqtrade.freqtradebot.RPCManager', MagicMock())
|
|
|
|
|
2018-03-03 21:39:39 +00:00
|
|
|
args = ['-c', 'config.json.example']
|
|
|
|
|
2018-02-04 09:21:16 +00:00
|
|
|
# Test Main + the KeyboardInterrupt exception
|
2018-06-07 20:28:21 +00:00
|
|
|
with pytest.raises(SystemExit):
|
2018-03-03 21:39:39 +00:00
|
|
|
main(args)
|
2018-06-07 20:28:21 +00:00
|
|
|
assert log_has('Using config: config.json.example ...', caplog.record_tuples)
|
|
|
|
assert log_has('Fatal exception!', caplog.record_tuples)
|
|
|
|
|
2018-02-04 09:21:16 +00:00
|
|
|
|
2018-06-07 20:28:21 +00:00
|
|
|
def test_main_keyboard_interrupt(mocker, default_conf, caplog) -> None:
|
|
|
|
"""
|
|
|
|
Test main() function
|
|
|
|
In this test we are skipping the while True loop by throwing an exception.
|
|
|
|
"""
|
2018-06-17 20:38:31 +00:00
|
|
|
patch_exchange(mocker)
|
2018-06-07 20:28:21 +00:00
|
|
|
mocker.patch.multiple(
|
|
|
|
'freqtrade.freqtradebot.FreqtradeBot',
|
|
|
|
_init_modules=MagicMock(),
|
|
|
|
worker=MagicMock(side_effect=KeyboardInterrupt),
|
2018-06-08 23:19:42 +00:00
|
|
|
cleanup=MagicMock(),
|
2018-06-07 20:28:21 +00:00
|
|
|
)
|
2018-02-04 09:21:16 +00:00
|
|
|
mocker.patch(
|
2018-06-07 20:28:21 +00:00
|
|
|
'freqtrade.configuration.Configuration._load_config_file',
|
|
|
|
lambda *args, **kwargs: default_conf
|
2018-01-04 14:39:01 +00:00
|
|
|
)
|
2018-06-07 20:28:21 +00:00
|
|
|
mocker.patch('freqtrade.freqtradebot.CryptoToFiatConverter', MagicMock())
|
|
|
|
mocker.patch('freqtrade.freqtradebot.RPCManager', MagicMock())
|
|
|
|
|
|
|
|
args = ['-c', 'config.json.example']
|
|
|
|
|
|
|
|
# Test Main + the KeyboardInterrupt exception
|
|
|
|
with pytest.raises(SystemExit):
|
|
|
|
main(args)
|
|
|
|
assert log_has('Using config: config.json.example ...', caplog.record_tuples)
|
|
|
|
assert log_has('SIGINT received, aborting ...', caplog.record_tuples)
|
|
|
|
|
|
|
|
|
|
|
|
def test_main_operational_exception(mocker, default_conf, caplog) -> None:
|
|
|
|
"""
|
|
|
|
Test main() function
|
|
|
|
In this test we are skipping the while True loop by throwing an exception.
|
|
|
|
"""
|
2018-06-17 20:38:31 +00:00
|
|
|
patch_exchange(mocker)
|
2018-06-07 20:28:21 +00:00
|
|
|
mocker.patch.multiple(
|
|
|
|
'freqtrade.freqtradebot.FreqtradeBot',
|
|
|
|
_init_modules=MagicMock(),
|
|
|
|
worker=MagicMock(side_effect=OperationalException('Oh snap!')),
|
2018-06-08 23:19:42 +00:00
|
|
|
cleanup=MagicMock(),
|
2018-06-07 20:28:21 +00:00
|
|
|
)
|
|
|
|
mocker.patch(
|
|
|
|
'freqtrade.configuration.Configuration._load_config_file',
|
|
|
|
lambda *args, **kwargs: default_conf
|
|
|
|
)
|
|
|
|
mocker.patch('freqtrade.freqtradebot.CryptoToFiatConverter', MagicMock())
|
|
|
|
mocker.patch('freqtrade.freqtradebot.RPCManager', MagicMock())
|
|
|
|
|
|
|
|
args = ['-c', 'config.json.example']
|
|
|
|
|
|
|
|
# Test Main + the KeyboardInterrupt exception
|
2018-02-04 09:21:16 +00:00
|
|
|
with pytest.raises(SystemExit):
|
2018-03-03 21:39:39 +00:00
|
|
|
main(args)
|
2018-06-07 20:28:21 +00:00
|
|
|
assert log_has('Using config: config.json.example ...', caplog.record_tuples)
|
|
|
|
assert log_has('Oh snap!', caplog.record_tuples)
|
2018-06-09 02:29:48 +00:00
|
|
|
|
|
|
|
|
|
|
|
def test_main_reload_conf(mocker, default_conf, caplog) -> None:
|
|
|
|
"""
|
|
|
|
Test main() function
|
|
|
|
In this test we are skipping the while True loop by throwing an exception.
|
|
|
|
"""
|
2018-06-17 20:38:31 +00:00
|
|
|
patch_exchange(mocker)
|
2018-06-09 02:29:48 +00:00
|
|
|
mocker.patch.multiple(
|
|
|
|
'freqtrade.freqtradebot.FreqtradeBot',
|
|
|
|
_init_modules=MagicMock(),
|
|
|
|
worker=MagicMock(return_value=State.RELOAD_CONF),
|
|
|
|
cleanup=MagicMock(),
|
|
|
|
)
|
|
|
|
mocker.patch(
|
|
|
|
'freqtrade.configuration.Configuration._load_config_file',
|
|
|
|
lambda *args, **kwargs: default_conf
|
|
|
|
)
|
|
|
|
mocker.patch('freqtrade.freqtradebot.CryptoToFiatConverter', MagicMock())
|
|
|
|
mocker.patch('freqtrade.freqtradebot.RPCManager', MagicMock())
|
|
|
|
|
|
|
|
# Raise exception as side effect to avoid endless loop
|
|
|
|
reconfigure_mock = mocker.patch(
|
|
|
|
'freqtrade.main.reconfigure', MagicMock(side_effect=Exception)
|
|
|
|
)
|
|
|
|
|
|
|
|
with pytest.raises(SystemExit):
|
|
|
|
main(['-c', 'config.json.example'])
|
|
|
|
|
|
|
|
assert reconfigure_mock.call_count == 1
|
|
|
|
assert log_has('Using config: config.json.example ...', caplog.record_tuples)
|
|
|
|
|
|
|
|
|
|
|
|
def test_reconfigure(mocker, default_conf) -> None:
|
|
|
|
""" Test recreate() function """
|
2018-06-17 20:38:31 +00:00
|
|
|
patch_exchange(mocker)
|
2018-06-09 02:29:48 +00:00
|
|
|
mocker.patch.multiple(
|
|
|
|
'freqtrade.freqtradebot.FreqtradeBot',
|
|
|
|
_init_modules=MagicMock(),
|
|
|
|
worker=MagicMock(side_effect=OperationalException('Oh snap!')),
|
|
|
|
cleanup=MagicMock(),
|
|
|
|
)
|
|
|
|
mocker.patch(
|
|
|
|
'freqtrade.configuration.Configuration._load_config_file',
|
|
|
|
lambda *args, **kwargs: default_conf
|
|
|
|
)
|
|
|
|
mocker.patch('freqtrade.freqtradebot.CryptoToFiatConverter', MagicMock())
|
|
|
|
mocker.patch('freqtrade.freqtradebot.RPCManager', MagicMock())
|
|
|
|
|
|
|
|
freqtrade = FreqtradeBot(default_conf)
|
|
|
|
|
|
|
|
# Renew mock to return modified data
|
|
|
|
conf = deepcopy(default_conf)
|
|
|
|
conf['stake_amount'] += 1
|
|
|
|
mocker.patch(
|
|
|
|
'freqtrade.configuration.Configuration._load_config_file',
|
|
|
|
lambda *args, **kwargs: conf
|
|
|
|
)
|
|
|
|
|
|
|
|
# reconfigure should return a new instance
|
|
|
|
freqtrade2 = reconfigure(
|
|
|
|
freqtrade,
|
|
|
|
Arguments(['-c', 'config.json.example'], '').get_parsed_arg()
|
|
|
|
)
|
|
|
|
|
|
|
|
# Verify we have a new instance with the new config
|
|
|
|
assert freqtrade is not freqtrade2
|
|
|
|
assert freqtrade.config['stake_amount'] + 1 == freqtrade2.config['stake_amount']
|