mirror of
https://github.com/LukeHagar/ytdl-sub.git
synced 2025-12-09 12:57:43 +00:00
249 lines
8.1 KiB
Python
249 lines
8.1 KiB
Python
import os.path
|
|
import re
|
|
import shutil
|
|
import sys
|
|
import tempfile
|
|
import time
|
|
from pathlib import Path
|
|
from typing import Callable
|
|
from typing import Optional
|
|
from unittest.mock import patch
|
|
|
|
import mergedeep
|
|
import pytest
|
|
from conftest import assert_logs
|
|
|
|
from ytdl_sub.cli.main import _download_subscriptions_from_yaml_files
|
|
from ytdl_sub.cli.main import logger as main_logger
|
|
from ytdl_sub.cli.main import main
|
|
from ytdl_sub.config.config_file import ConfigFile
|
|
from ytdl_sub.subscriptions.subscription import Subscription
|
|
from ytdl_sub.utils.file_handler import FileHandler
|
|
from ytdl_sub.utils.file_handler import FileHandlerTransactionLog
|
|
from ytdl_sub.utils.file_handler import FileMetadata
|
|
from ytdl_sub.utils.logger import Logger
|
|
|
|
####################################################################################################
|
|
# SHARED FIXTURES
|
|
|
|
|
|
@pytest.fixture
|
|
def mock_subscription_download_factory():
|
|
def _mock_subscription_download_factory(mock_success_output: bool) -> Callable:
|
|
def _mock_download(self: Subscription, dry_run: bool) -> FileHandlerTransactionLog:
|
|
Logger.get().info(
|
|
"name=%s success=%s dry_run=%s", self.name, mock_success_output, dry_run
|
|
)
|
|
time.sleep(1)
|
|
if not mock_success_output:
|
|
raise ValueError("error")
|
|
return (
|
|
FileHandlerTransactionLog()
|
|
.log_created_file("created_file.txt", FileMetadata())
|
|
.log_modified_file("modified_file.txt", FileMetadata())
|
|
.log_removed_file("deleted_file.txt")
|
|
)
|
|
|
|
return _mock_download
|
|
|
|
return _mock_subscription_download_factory
|
|
|
|
|
|
@pytest.fixture
|
|
def mock_subscription_download_success(mock_subscription_download_factory: Callable):
|
|
with patch.object(
|
|
Subscription,
|
|
"download",
|
|
new=mock_subscription_download_factory(mock_success_output=True),
|
|
):
|
|
yield
|
|
|
|
|
|
####################################################################################################
|
|
# PERSIST LOGS FIXTURES + TESTS
|
|
|
|
|
|
@pytest.fixture
|
|
def persist_logs_directory() -> str:
|
|
# Delete the temp_dir on creation
|
|
with tempfile.TemporaryDirectory() as temp_dir:
|
|
pass
|
|
|
|
yield temp_dir
|
|
|
|
if os.path.isdir(temp_dir):
|
|
shutil.rmtree(temp_dir)
|
|
|
|
|
|
@pytest.fixture
|
|
def persist_logs_config_factory(
|
|
music_video_config: ConfigFile, persist_logs_directory: str
|
|
) -> Callable:
|
|
def _persist_logs_config_factory(keep_successful_logs: bool) -> ConfigFile:
|
|
return ConfigFile.from_dict(
|
|
dict(
|
|
mergedeep.merge(
|
|
music_video_config.as_dict(),
|
|
{
|
|
"configuration": {
|
|
"persist_logs": {
|
|
"logs_directory": persist_logs_directory,
|
|
"keep_successful_logs": keep_successful_logs,
|
|
},
|
|
}
|
|
},
|
|
)
|
|
)
|
|
)
|
|
|
|
return _persist_logs_config_factory
|
|
|
|
|
|
@pytest.mark.parametrize("dry_run", [True, False])
|
|
@pytest.mark.parametrize("mock_success_output", [True, False])
|
|
@pytest.mark.parametrize("keep_successful_logs", [True, False])
|
|
def test_subscription_logs_write_to_file(
|
|
persist_logs_directory: str,
|
|
persist_logs_config_factory: Callable,
|
|
mock_subscription_download_factory: Callable,
|
|
music_video_subscription_path: Path,
|
|
dry_run: bool,
|
|
mock_success_output: bool,
|
|
keep_successful_logs: bool,
|
|
):
|
|
num_subscriptions = 2
|
|
config = persist_logs_config_factory(keep_successful_logs=keep_successful_logs)
|
|
subscription_paths = [str(music_video_subscription_path)] * num_subscriptions
|
|
|
|
with patch.object(
|
|
Subscription,
|
|
"download",
|
|
new=mock_subscription_download_factory(mock_success_output=mock_success_output),
|
|
):
|
|
try:
|
|
_download_subscriptions_from_yaml_files(
|
|
config=config, subscription_paths=subscription_paths, dry_run=dry_run
|
|
)
|
|
except ValueError:
|
|
assert not mock_success_output
|
|
|
|
log_directory_files = list(Path(persist_logs_directory).rglob("*"))
|
|
|
|
# If dry run or success but success logging disabled, expect 0 log files
|
|
if dry_run or (mock_success_output and not keep_successful_logs):
|
|
assert len(log_directory_files) == 0
|
|
return
|
|
# If not success, expect 1 log file
|
|
elif not mock_success_output:
|
|
assert len(log_directory_files) == 1
|
|
log_path = log_directory_files[0]
|
|
assert bool(re.match(r"\d{4}-\d{2}-\d{2}-\d{6}\.john_smith\.error\.log", log_path.name))
|
|
with open(log_path, "r", encoding="utf-8") as log_file:
|
|
assert log_file.readlines()[-1] == (
|
|
f"Please upload the error log file '{str(log_path)}' and make a Github issue "
|
|
f"at https://github.com/jmbannon/ytdl-sub/issues with your config and "
|
|
f"command/subscription yaml file to reproduce. Thanks for trying ytdl-sub!\n"
|
|
)
|
|
# If success and success logging, expect 3 log files
|
|
else:
|
|
assert len(log_directory_files) == num_subscriptions
|
|
for log_file_path in log_directory_files:
|
|
assert bool(
|
|
re.match(r"\d{4}-\d{2}-\d{2}-\d{6}\.john_smith\.success\.log", log_file_path.name)
|
|
)
|
|
with open(log_file_path, "r", encoding="utf-8") as log_file:
|
|
assert (
|
|
log_file.readlines()[-1]
|
|
== "[ytdl-sub] name=john_smith success=True dry_run=False\n"
|
|
)
|
|
|
|
|
|
####################################################################################################
|
|
# TRANSACTION LOGS FIXTURES + TESTS
|
|
|
|
|
|
@pytest.fixture
|
|
def transaction_log_file_path() -> str:
|
|
# Delete the temp_file on creation
|
|
with tempfile.NamedTemporaryFile() as temp_file:
|
|
pass
|
|
|
|
yield temp_file.name
|
|
|
|
if os.path.isfile(temp_file.name):
|
|
FileHandler.delete(temp_file.name)
|
|
|
|
|
|
@pytest.mark.parametrize("file_transaction_log", [None, "output.log"])
|
|
def test_suppress_transaction_log(
|
|
mock_subscription_download_success,
|
|
music_video_config_path: Path,
|
|
music_video_subscription_path: Path,
|
|
file_transaction_log: Optional[str],
|
|
) -> None:
|
|
with patch.object(
|
|
sys,
|
|
"argv",
|
|
[
|
|
"ytdl-sub",
|
|
"--config",
|
|
str(music_video_config_path),
|
|
"sub",
|
|
str(music_video_subscription_path),
|
|
"--suppress-transaction-log",
|
|
]
|
|
+ (["--transaction-log", file_transaction_log] if file_transaction_log else []),
|
|
), patch("ytdl_sub.cli.main._output_transaction_log") as mock_transaction_log:
|
|
transaction_logs = main()
|
|
|
|
assert transaction_logs
|
|
assert mock_transaction_log.call_count == 0
|
|
|
|
|
|
def test_transaction_log_to_file(
|
|
mock_subscription_download_success,
|
|
music_video_config_path: Path,
|
|
music_video_subscription_path: Path,
|
|
transaction_log_file_path: Path,
|
|
) -> None:
|
|
with patch.object(
|
|
sys,
|
|
"argv",
|
|
[
|
|
"ytdl-sub",
|
|
"--config",
|
|
str(music_video_config_path),
|
|
"sub",
|
|
str(music_video_subscription_path),
|
|
"--transaction-log",
|
|
str(transaction_log_file_path),
|
|
],
|
|
):
|
|
transaction_logs = main()
|
|
assert transaction_logs
|
|
|
|
with open(transaction_log_file_path, "r", encoding="utf-8") as transaction_log_file:
|
|
assert transaction_log_file.readlines()[0] == "Transaction log for john_smith:\n"
|
|
|
|
|
|
def test_transaction_log_to_logger(
|
|
mock_subscription_download_success,
|
|
music_video_config_path: Path,
|
|
music_video_subscription_path: Path,
|
|
) -> None:
|
|
with patch.object(
|
|
sys,
|
|
"argv",
|
|
[
|
|
"ytdl-sub",
|
|
"--config",
|
|
str(music_video_config_path),
|
|
"sub",
|
|
str(music_video_subscription_path),
|
|
],
|
|
), assert_logs(
|
|
logger=main_logger, expected_message="Transaction log for john_smith:\n", log_level="info"
|
|
):
|
|
transaction_logs = main()
|
|
assert transaction_logs
|