diff --git a/freqtrade/commands/deploy_commands.py b/freqtrade/commands/deploy_commands.py index b43ad5970..e951c962f 100644 --- a/freqtrade/commands/deploy_commands.py +++ b/freqtrade/commands/deploy_commands.py @@ -3,6 +3,8 @@ import sys from pathlib import Path from typing import Any, Dict +import requests + from freqtrade.configuration import setup_utils_configuration from freqtrade.configuration.directory_operations import copy_sample_files, create_userdata_dir from freqtrade.constants import USERPATH_HYPEROPTS, USERPATH_STRATEGIES @@ -140,9 +142,8 @@ def start_new_hyperopt(args: Dict[str, Any]) -> None: def clean_ui_subdir(directory: Path): - print(directory) if directory.is_dir(): - logger.info("Removing UI directory content") + logger.info("Removing UI directory content.") for p in reversed(list(directory.glob('**/*'))): # iterate contents from leaves to root if p.name == '.gitkeep': @@ -153,11 +154,28 @@ def clean_ui_subdir(directory: Path): p.rmdir() -def download_and_install_ui(dest_folder: Path): - import requests +def download_and_install_ui(dest_folder: Path, dl_url: str): from io import BytesIO from zipfile import ZipFile + logger.info(f"Downloading {dl_url}") + resp = requests.get(dl_url).content + with ZipFile(BytesIO(resp)) as zf: + for fn in zf.filelist: + with zf.open(fn) as x: + destfile = dest_folder / fn.filename + if fn.is_dir(): + destfile.mkdir(exist_ok=True) + else: + destfile.write_bytes(x.read()) + + +def start_install_ui(args: Dict[str, Any]) -> None: + + dest_folder = Path(__file__).parents[1] / 'rpc/api_server/ui' + # First make sure the assets are removed. + clean_ui_subdir(dest_folder) + base_url = 'https://api.github.com/repos/freqtrade/frequi/' # Get base UI Repo path @@ -170,24 +188,6 @@ def download_and_install_ui(dest_folder: Path): r = resp.json() dl_url = r[0]['browser_download_url'] - logger.info(f"Downloading {dl_url}") - resp = requests.get(dl_url).content - with ZipFile(BytesIO(resp)) as zf: - for fn in zf.filelist: - with zf.open(fn) as x: - destfile = dest_folder / fn.filename - print(destfile) - if fn.is_dir(): - destfile.mkdir(exist_ok=True) - else: - destfile.write_bytes(x.read()) - - -def start_install_ui(args: Dict[str, Any]) -> None: - - dest_folder = Path(__file__).parents[1] / 'rpc/api_server/ui' - # First make sure the assets are removed. - clean_ui_subdir(dest_folder) # Download a new version - download_and_install_ui(dest_folder) + download_and_install_ui(dest_folder, dl_url) diff --git a/tests/commands/test_commands.py b/tests/commands/test_commands.py index f8ecc8218..12d18b3a7 100644 --- a/tests/commands/test_commands.py +++ b/tests/commands/test_commands.py @@ -1,16 +1,19 @@ +from io import BytesIO import re from pathlib import Path from unittest.mock import MagicMock, PropertyMock +from zipfile import ZipFile import arrow import pytest from freqtrade.commands import (start_convert_data, start_create_userdir, start_download_data, - start_hyperopt_list, start_hyperopt_show, start_list_data, - start_list_exchanges, start_list_hyperopts, start_list_markets, - start_list_strategies, start_list_timeframes, start_new_hyperopt, - start_new_strategy, start_show_trades, start_test_pairlist, - start_trading) + start_hyperopt_list, start_hyperopt_show, start_install_ui, + start_list_data, start_list_exchanges, start_list_hyperopts, + start_list_markets, start_list_strategies, start_list_timeframes, + start_new_hyperopt, start_new_strategy, start_show_trades, + start_test_pairlist, start_trading) +from freqtrade.commands.deploy_commands import clean_ui_subdir, download_and_install_ui from freqtrade.configuration import setup_utils_configuration from freqtrade.exceptions import OperationalException from freqtrade.state import RunMode @@ -546,7 +549,7 @@ def test_start_new_hyperopt_DefaultHyperopt(mocker, caplog): start_new_hyperopt(get_args(args)) -def test_start_new_hyperopt_no_arg(mocker, caplog): +def test_start_new_hyperopt_no_arg(mocker): args = [ "new-hyperopt", ] @@ -555,6 +558,56 @@ def test_start_new_hyperopt_no_arg(mocker, caplog): start_new_hyperopt(get_args(args)) +def test_start_install_ui(mocker): + clean_mock = mocker.patch('freqtrade.commands.deploy_commands.clean_ui_subdir') + download_mock = mocker.patch('freqtrade.commands.deploy_commands.download_and_install_ui') + args = [ + "install-ui", + ] + start_install_ui(args) + assert clean_mock.call_count == 1 + + assert download_mock.call_count == 1 + + +def test_clean_ui_subdir(mocker, tmpdir, caplog): + mocker.patch("freqtrade.commands.deploy_commands.Path.is_dir", + side_effect=[True, True]) + mocker.patch("freqtrade.commands.deploy_commands.Path.is_file", + side_effect=[False, True]) + rd_mock = mocker.patch("freqtrade.commands.deploy_commands.Path.rmdir") + ul_mock = mocker.patch("freqtrade.commands.deploy_commands.Path.unlink") + + mocker.patch("freqtrade.commands.deploy_commands.Path.glob", + return_value=[Path('test1'), Path('test2'), Path('.gitkeep')]) + folder = Path(tmpdir) / "uitests" + clean_ui_subdir(folder) + assert log_has("Removing UI directory content.", caplog) + assert rd_mock.call_count == 1 + assert ul_mock.call_count == 1 + + +def test_download_and_install_ui(mocker, tmpdir, caplog): + # Should be something "zip-like" + requests_mock = MagicMock() + file_like_object = BytesIO() + with ZipFile(file_like_object, mode='w') as zipfile: + for file in ('test1.txt', 'hello/', 'test2.txt'): + zipfile.writestr(file, file) + file_like_object.seek(0) + requests_mock.content = file_like_object.read() + mocker.patch("freqtrade.commands.deploy_commands.requests.get", return_value=requests_mock) + mocker.patch("freqtrade.commands.deploy_commands.Path.is_dir", + side_effect=[True, False]) + mkdir_mock = mocker.patch("freqtrade.commands.deploy_commands.Path.mkdir") + wb_mock = mocker.patch("freqtrade.commands.deploy_commands.Path.write_bytes") + folder = Path(tmpdir) / "uitests_dl" + download_and_install_ui(folder, 'http://whatever.xxx') + + assert mkdir_mock.call_count == 1 + assert wb_mock.call_count == 2 + + def test_download_data_keyboardInterrupt(mocker, caplog, markets): dl_mock = mocker.patch('freqtrade.commands.data_commands.refresh_backtest_ohlcv_data', MagicMock(side_effect=KeyboardInterrupt))