import logging from unittest.mock import mock_open, patch import pytest from control_backend.logging.setup_logging import add_logging_level, setup_logging def test_add_logging_level(): # Add a unique level to avoid conflicts with other tests/libraries level_name = "TESTLEVEL" level_num = 35 add_logging_level(level_name, level_num) assert logging.getLevelName(level_num) == level_name assert hasattr(logging, level_name) assert hasattr(logging.getLoggerClass(), level_name.lower()) # Test functionality logger = logging.getLogger("test_custom_level") with patch.object(logger, "_log") as mock_log: getattr(logger, level_name.lower())("message") mock_log.assert_called_with(level_num, "message", ()) # Test duplicates with pytest.raises(AttributeError): add_logging_level(level_name, level_num) with pytest.raises(AttributeError): add_logging_level("INFO", 20) # Existing level def test_setup_logging_no_file(caplog): with patch("os.path.exists", return_value=False): setup_logging("dummy.yaml") assert "Logging config file not found" in caplog.text def test_setup_logging_yaml_error(caplog): with patch("os.path.exists", return_value=True): with patch("builtins.open", mock_open(read_data="invalid: [yaml")): with patch("logging.config.dictConfig") as mock_dict_config: setup_logging("config.yaml") # Verify we logged the warning assert "Could not load logging configuration" in caplog.text # Verify dictConfig was called with empty dict (which would crash real dictConfig) mock_dict_config.assert_called_with({}) assert "Could not load logging configuration" in caplog.text def test_setup_logging_success(): config_data = """ version: 1 handlers: console: class: logging.StreamHandler root: handlers: [console] level: INFO custom_levels: MYLEVEL: 15 """ with patch("os.path.exists", return_value=True): with patch("builtins.open", mock_open(read_data=config_data)): with patch("logging.config.dictConfig") as mock_dict_config: setup_logging("config.yaml") mock_dict_config.assert_called() assert hasattr(logging, "MYLEVEL") def test_setup_logging_zmq_handler(mock_zmq_context): config_data = """ version: 1 handlers: ui: class: logging.NullHandler # In real config this would be a zmq handler, but for unit test logic # we just want to see if the socket injection happens """ with patch("os.path.exists", return_value=True): with patch("builtins.open", mock_open(read_data=config_data)): with patch("logging.config.dictConfig") as mock_dict_config: setup_logging("config.yaml") args = mock_dict_config.call_args[0][0] assert "interface_or_socket" in args["handlers"]["ui"]