1+ """Tests for the logging module."""
2+
3+ import os
4+ import time
5+ from pathlib import Path
6+
7+ import pytest
8+
9+ from mcpcat .modules .constants import LOG_PATH
10+ from mcpcat .modules .logging import write_to_log
11+
12+
13+ class TestLogging :
14+ """Test the logging functionality."""
15+
16+ def test_write_to_log_creates_file (self , tmp_path ):
17+ """Test that write_to_log creates the log file if it doesn't exist."""
18+ # Use a temporary directory for the test
19+ log_file = tmp_path / "test_mcpcat.log"
20+
21+ # Monkey patch the LOG_PATH constant
22+ import mcpcat .modules .logging
23+ original_log_path = mcpcat .modules .logging .LOG_PATH
24+ mcpcat .modules .logging .LOG_PATH = str (log_file )
25+
26+ try :
27+ # Write a test message
28+ test_message = "Test log message"
29+ write_to_log (test_message )
30+
31+ # Check that the file was created
32+ assert log_file .exists (), "Log file was not created"
33+
34+ # Read the file content
35+ content = log_file .read_text ()
36+
37+ # Verify the message is in the file
38+ assert test_message in content , "Log message not found in file"
39+
40+ # Verify timestamp format (ISO format)
41+ assert "T" in content , "Timestamp not in ISO format"
42+
43+ finally :
44+ # Restore original LOG_PATH
45+ mcpcat .modules .logging .LOG_PATH = original_log_path
46+
47+ def test_write_to_log_appends_messages (self , tmp_path ):
48+ """Test that write_to_log appends to existing log file."""
49+ # Use a temporary directory for the test
50+ log_file = tmp_path / "test_mcpcat.log"
51+
52+ # Monkey patch the LOG_PATH constant
53+ import mcpcat .modules .logging
54+ original_log_path = mcpcat .modules .logging .LOG_PATH
55+ mcpcat .modules .logging .LOG_PATH = str (log_file )
56+
57+ try :
58+ # Write multiple messages
59+ messages = ["First message" , "Second message" , "Third message" ]
60+ for msg in messages :
61+ write_to_log (msg )
62+ time .sleep (0.01 ) # Small delay to ensure different timestamps
63+
64+ # Read the file content
65+ content = log_file .read_text ()
66+ lines = content .strip ().split ('\n ' )
67+
68+ # Verify all messages are present
69+ assert len (lines ) == len (messages ), f"Expected { len (messages )} lines, got { len (lines )} "
70+
71+ for i , msg in enumerate (messages ):
72+ assert msg in lines [i ], f"Message '{ msg } ' not found in line { i } "
73+
74+ # Verify messages are in chronological order
75+ timestamps = []
76+ for line in lines :
77+ # Extract timestamp from [timestamp] format
78+ timestamp = line .split ('] ' )[0 ].strip ('[' )
79+ timestamps .append (timestamp )
80+
81+ # Check timestamps are in ascending order
82+ assert timestamps == sorted (timestamps ), "Log entries are not in chronological order"
83+
84+ finally :
85+ # Restore original LOG_PATH
86+ mcpcat .modules .logging .LOG_PATH = original_log_path
87+
88+ def test_write_to_log_handles_directory_creation (self , tmp_path ):
89+ """Test that write_to_log creates parent directories if needed."""
90+ # Use a nested directory structure
91+ log_file = tmp_path / "nested" / "dirs" / "test_mcpcat.log"
92+
93+ # Monkey patch the LOG_PATH constant
94+ import mcpcat .modules .logging
95+ original_log_path = mcpcat .modules .logging .LOG_PATH
96+ mcpcat .modules .logging .LOG_PATH = str (log_file )
97+
98+ try :
99+ # Write a test message
100+ test_message = "Test with directory creation"
101+ write_to_log (test_message )
102+
103+ # Check that the directories and file were created
104+ assert log_file .exists (), "Log file was not created in nested directory"
105+ assert test_message in log_file .read_text (), "Message not written to file"
106+
107+ finally :
108+ # Restore original LOG_PATH
109+ mcpcat .modules .logging .LOG_PATH = original_log_path
110+
111+ def test_write_to_log_silently_handles_errors (self , tmp_path , monkeypatch ):
112+ """Test that write_to_log doesn't raise exceptions on errors."""
113+ # Use a file that can't be written to
114+ log_file = tmp_path / "test_mcpcat.log"
115+
116+ # Monkey patch the LOG_PATH constant
117+ import mcpcat .modules .logging
118+ original_log_path = mcpcat .modules .logging .LOG_PATH
119+ mcpcat .modules .logging .LOG_PATH = str (log_file )
120+
121+ try :
122+ # Make the parent directory read-only to cause write failure
123+ log_file .parent .chmod (0o444 )
124+
125+ # This should not raise an exception
126+ write_to_log ("This should fail silently" )
127+
128+ # If we get here without exception, the test passes
129+ assert True
130+
131+ finally :
132+ # Restore permissions and original LOG_PATH
133+ log_file .parent .chmod (0o755 )
134+ mcpcat .modules .logging .LOG_PATH = original_log_path
135+
136+ def test_log_format (self , tmp_path ):
137+ """Test the format of log entries."""
138+ # Use a temporary directory for the test
139+ log_file = tmp_path / "test_mcpcat.log"
140+
141+ # Monkey patch the LOG_PATH constant
142+ import mcpcat .modules .logging
143+ original_log_path = mcpcat .modules .logging .LOG_PATH
144+ mcpcat .modules .logging .LOG_PATH = str (log_file )
145+
146+ try :
147+ # Write a test message
148+ test_message = "Test format validation"
149+ write_to_log (test_message )
150+
151+ # Read the log entry
152+ content = log_file .read_text ().strip ()
153+
154+ # Verify format: "[ISO_TIMESTAMP] MESSAGE"
155+ assert content .startswith ('[' ), "Log entry should start with ["
156+ assert '] ' in content , "Log entry should have timestamp in brackets followed by space"
157+
158+ # Extract timestamp and message
159+ bracket_end = content .index ('] ' )
160+ timestamp = content [1 :bracket_end ] # Skip the opening bracket
161+ message = content [bracket_end + 2 :] # Skip '] '
162+
163+ # Verify ISO timestamp format (YYYY-MM-DDTHH:MM:SS.ssssss)
164+ assert len (timestamp ) >= 19 , "Timestamp too short"
165+ assert timestamp [4 ] == '-' , "Invalid year-month separator"
166+ assert timestamp [7 ] == '-' , "Invalid month-day separator"
167+ assert timestamp [10 ] == 'T' , "Invalid date-time separator"
168+ assert timestamp [13 ] == ':' , "Invalid hour-minute separator"
169+ assert timestamp [16 ] == ':' , "Invalid minute-second separator"
170+
171+ # Verify message
172+ assert message == test_message , "Message content doesn't match"
173+
174+ finally :
175+ # Restore original LOG_PATH
176+ mcpcat .modules .logging .LOG_PATH = original_log_path
0 commit comments