170 lines
7.1 KiB
Python
170 lines
7.1 KiB
Python
import json
|
|
import logging
|
|
import os
|
|
import tempfile
|
|
import pytest
|
|
from unittest.mock import patch
|
|
|
|
|
|
class TestLoggingModule:
|
|
@pytest.fixture(autouse=True)
|
|
def setup_and_teardown(self):
|
|
for handler in logging.root.handlers[:]:
|
|
logging.root.removeHandler(handler)
|
|
|
|
tradingagents_logger = logging.getLogger("tradingagents")
|
|
for handler in tradingagents_logger.handlers[:]:
|
|
tradingagents_logger.removeHandler(handler)
|
|
tradingagents_logger.setLevel(logging.NOTSET)
|
|
|
|
yield
|
|
|
|
for handler in logging.root.handlers[:]:
|
|
logging.root.removeHandler(handler)
|
|
tradingagents_logger = logging.getLogger("tradingagents")
|
|
for handler in tradingagents_logger.handlers[:]:
|
|
tradingagents_logger.removeHandler(handler)
|
|
|
|
def test_setup_logging_initializes_handlers_based_on_env_vars(self):
|
|
with tempfile.TemporaryDirectory() as tmpdir:
|
|
env_vars = {
|
|
"TRADINGAGENTS_LOG_LEVEL": "DEBUG",
|
|
"TRADINGAGENTS_LOG_DIR": tmpdir,
|
|
"TRADINGAGENTS_LOG_CONSOLE": "false",
|
|
"TRADINGAGENTS_LOG_FILE": "true",
|
|
}
|
|
with patch.dict(os.environ, env_vars, clear=False):
|
|
import importlib
|
|
import tradingagents.logging as log_module
|
|
importlib.reload(log_module)
|
|
|
|
root_logger = log_module.setup_logging()
|
|
|
|
assert root_logger is not None
|
|
assert root_logger.name == "tradingagents"
|
|
assert root_logger.level == logging.DEBUG
|
|
|
|
has_file_handler = any(
|
|
hasattr(h, "baseFilename") for h in root_logger.handlers
|
|
)
|
|
assert has_file_handler, "File handler should be present when LOG_FILE=true"
|
|
|
|
def test_get_logger_returns_properly_configured_logger_with_hierarchy(self):
|
|
with tempfile.TemporaryDirectory() as tmpdir:
|
|
env_vars = {
|
|
"TRADINGAGENTS_LOG_LEVEL": "INFO",
|
|
"TRADINGAGENTS_LOG_DIR": tmpdir,
|
|
"TRADINGAGENTS_LOG_CONSOLE": "false",
|
|
"TRADINGAGENTS_LOG_FILE": "true",
|
|
}
|
|
with patch.dict(os.environ, env_vars, clear=False):
|
|
import importlib
|
|
import tradingagents.logging as log_module
|
|
importlib.reload(log_module)
|
|
|
|
log_module.setup_logging()
|
|
child_logger = log_module.get_logger("tradingagents.dataflows.interface")
|
|
|
|
assert child_logger.name == "tradingagents.dataflows.interface"
|
|
assert child_logger.parent.name == "tradingagents.dataflows" or child_logger.parent.name == "tradingagents"
|
|
|
|
def test_json_file_handler_writes_valid_json_with_required_fields(self):
|
|
with tempfile.TemporaryDirectory() as tmpdir:
|
|
env_vars = {
|
|
"TRADINGAGENTS_LOG_LEVEL": "DEBUG",
|
|
"TRADINGAGENTS_LOG_DIR": tmpdir,
|
|
"TRADINGAGENTS_LOG_CONSOLE": "false",
|
|
"TRADINGAGENTS_LOG_FILE": "true",
|
|
}
|
|
with patch.dict(os.environ, env_vars, clear=False):
|
|
import importlib
|
|
import tradingagents.logging as log_module
|
|
importlib.reload(log_module)
|
|
|
|
logger = log_module.setup_logging()
|
|
logger.info("Test message for JSON validation")
|
|
|
|
for handler in logger.handlers:
|
|
handler.flush()
|
|
|
|
log_file_path = os.path.join(tmpdir, "tradingagents.log")
|
|
assert os.path.exists(log_file_path), f"Log file should exist at {log_file_path}"
|
|
|
|
with open(log_file_path, "r") as f:
|
|
log_content = f.read().strip()
|
|
|
|
assert log_content, "Log file should not be empty"
|
|
|
|
log_entry = json.loads(log_content.split("\n")[0])
|
|
|
|
required_fields = ["timestamp", "level", "logger", "message", "filename", "funcName", "lineno"]
|
|
for field in required_fields:
|
|
assert field in log_entry, f"JSON log should contain '{field}' field"
|
|
|
|
assert "T" in log_entry["timestamp"], "Timestamp should be in ISO 8601 format"
|
|
assert log_entry["level"] == "INFO"
|
|
assert log_entry["message"] == "Test message for JSON validation"
|
|
|
|
def test_log_rotation_triggers_at_configured_file_size(self):
|
|
with tempfile.TemporaryDirectory() as tmpdir:
|
|
env_vars = {
|
|
"TRADINGAGENTS_LOG_LEVEL": "DEBUG",
|
|
"TRADINGAGENTS_LOG_DIR": tmpdir,
|
|
"TRADINGAGENTS_LOG_CONSOLE": "false",
|
|
"TRADINGAGENTS_LOG_FILE": "true",
|
|
}
|
|
with patch.dict(os.environ, env_vars, clear=False):
|
|
import importlib
|
|
import tradingagents.logging as log_module
|
|
importlib.reload(log_module)
|
|
|
|
logger = log_module.setup_logging()
|
|
|
|
file_handler = None
|
|
for handler in logger.handlers:
|
|
if hasattr(handler, "maxBytes"):
|
|
file_handler = handler
|
|
break
|
|
|
|
assert file_handler is not None, "RotatingFileHandler should be configured"
|
|
assert file_handler.maxBytes == 10 * 1024 * 1024, "Max file size should be 10MB"
|
|
assert file_handler.backupCount == 5, "Backup count should be 5"
|
|
|
|
def test_console_handler_disabled_when_env_var_false(self):
|
|
with tempfile.TemporaryDirectory() as tmpdir:
|
|
env_vars = {
|
|
"TRADINGAGENTS_LOG_LEVEL": "INFO",
|
|
"TRADINGAGENTS_LOG_DIR": tmpdir,
|
|
"TRADINGAGENTS_LOG_CONSOLE": "false",
|
|
"TRADINGAGENTS_LOG_FILE": "true",
|
|
}
|
|
with patch.dict(os.environ, env_vars, clear=False):
|
|
import importlib
|
|
import tradingagents.logging as log_module
|
|
importlib.reload(log_module)
|
|
|
|
logger = log_module.setup_logging()
|
|
|
|
from rich.logging import RichHandler
|
|
has_rich_handler = any(isinstance(h, RichHandler) for h in logger.handlers)
|
|
assert not has_rich_handler, "RichHandler should NOT be present when LOG_CONSOLE=false"
|
|
|
|
def test_console_handler_enabled_when_env_var_true(self):
|
|
with tempfile.TemporaryDirectory() as tmpdir:
|
|
env_vars = {
|
|
"TRADINGAGENTS_LOG_LEVEL": "INFO",
|
|
"TRADINGAGENTS_LOG_DIR": tmpdir,
|
|
"TRADINGAGENTS_LOG_CONSOLE": "true",
|
|
"TRADINGAGENTS_LOG_FILE": "false",
|
|
}
|
|
with patch.dict(os.environ, env_vars, clear=False):
|
|
import importlib
|
|
import tradingagents.logging as log_module
|
|
importlib.reload(log_module)
|
|
|
|
logger = log_module.setup_logging()
|
|
|
|
from rich.logging import RichHandler
|
|
has_rich_handler = any(isinstance(h, RichHandler) for h in logger.handlers)
|
|
assert has_rich_handler, "RichHandler should be present when LOG_CONSOLE=true"
|