-
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathtest_context_managers.py
More file actions
244 lines (187 loc) · 8.49 KB
/
test_context_managers.py
File metadata and controls
244 lines (187 loc) · 8.49 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
# -*- coding: utf-8 -*-
import logging
import os
import sys
import tempfile
# Add the parent directory to sys.path for imports
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
import pytest
from pythonLogs import (
BasicLog,
SizeRotatingLog,
TimedRotatingLog,
LogLevel,
RotateWhen,
clear_logger_registry,
LoggerFactory,
)
class TestContextManagers:
"""Test context manager functionality for resource management."""
@pytest.fixture(autouse=True)
def setup_temp_dir(self):
"""Set up test fixtures before each test method."""
# Clear any existing loggers
clear_logger_registry()
# Create temporary directory for log files using context manager
with tempfile.TemporaryDirectory() as temp_dir:
self.temp_dir = temp_dir
self.log_file = "test.log"
yield
# Clear registry after each test
clear_logger_registry()
def test_basic_log_context_manager(self):
"""Test BasicLog as context manager."""
logger_name = "test_basic_context"
with BasicLog(name=logger_name, level=LogLevel.INFO.value) as logger:
assert isinstance(logger, logging.Logger)
assert logger.name == logger_name
assert logger.level == logging.INFO
# Test logging
logger.info("Test message in context")
# After context exit, handlers should be cleaned up
assert len(logger.handlers) == 0
def test_size_rotating_context_manager(self):
"""Test SizeRotatingLog as context manager."""
logger_name = "test_size_context"
with SizeRotatingLog(
name=logger_name,
level=LogLevel.DEBUG.value,
directory=self.temp_dir,
filenames=[self.log_file],
maxmbytes=1,
daystokeep=2
) as logger:
assert isinstance(logger, logging.Logger)
assert logger.name == logger_name
assert logger.level == logging.DEBUG
# Should have file handlers
file_handlers = [h for h in logger.handlers if hasattr(h, 'baseFilename')]
assert len(file_handlers) > 0
# Test logging
logger.debug("Test debug message")
logger.info("Test info message")
# After context exit, handlers should be cleaned up
assert len(logger.handlers) == 0
def test_timed_rotating_context_manager(self):
"""Test TimedRotatingLog as context manager."""
logger_name = "test_timed_context"
with TimedRotatingLog(
name=logger_name,
level=LogLevel.WARNING.value,
directory=self.temp_dir,
filenames=[self.log_file],
when=RotateWhen.HOURLY.value,
daystokeep=3
) as logger:
assert isinstance(logger, logging.Logger)
assert logger.name == logger_name
assert logger.level == logging.WARNING
# Should have file handlers
file_handlers = [h for h in logger.handlers if hasattr(h, 'baseFilename')]
assert len(file_handlers) > 0
# Test logging
logger.warning("Test warning message")
logger.error("Test error message")
# After context exit, handlers should be cleaned up
assert len(logger.handlers) == 0
def test_context_manager_exception_handling(self):
"""Test context manager cleanup on exceptions."""
logger_name = "test_exception_context"
logger_ref = None
try:
with BasicLog(name=logger_name, level=LogLevel.ERROR.value) as logger:
logger_ref = logger
logger.error("Test before exception")
raise ValueError("Test exception")
except ValueError:
pass # Expected exception
# Even with exception, handlers should be cleaned up
assert logger_ref is not None
assert len(logger_ref.handlers) == 0
def test_context_manager_without_init(self):
"""Test context manager calls init() if not already called."""
logger_instance = BasicLog(name="test_no_init", level=LogLevel.INFO.value)
# Don't call init() manually - logger should be None initially
assert logger_instance.logger is None
with logger_instance as logger:
# Context manager should have called init()
assert hasattr(logger_instance, 'logger')
assert logger_instance.logger is not None
assert isinstance(logger, logging.Logger)
logger.info("Test message")
# Cleanup should still work
assert len(logger.handlers) == 0
def test_context_manager_with_existing_init(self):
"""Test context manager with logger already initialized."""
logger_instance = BasicLog(name="test_existing_init", level=LogLevel.INFO.value)
# Call init() manually first
manual_logger = logger_instance.init()
assert hasattr(logger_instance, 'logger')
with logger_instance as context_logger:
# Should return the same logger
assert context_logger is manual_logger
context_logger.info("Test message")
# Cleanup should still work
assert len(manual_logger.handlers) == 0
def test_multiple_file_handlers_cleanup(self):
"""Test cleanup of multiple file handlers."""
logger_name = "test_multi_files"
multiple_files = ["test1.log", "test2.log", "test3.log"]
with SizeRotatingLog(
name=logger_name, directory=self.temp_dir, filenames=multiple_files, maxmbytes=1
) as logger:
# Should have multiple file handlers
file_handlers = [h for h in logger.handlers if hasattr(h, 'baseFilename')]
assert len(file_handlers) == len(multiple_files)
logger.info("Test message to multiple files")
# All handlers should be cleaned up
assert len(logger.handlers) == 0
def test_stream_handler_cleanup(self):
"""Test cleanup of stream handlers."""
logger_name = "test_stream_cleanup"
with SizeRotatingLog(
name=logger_name, directory=self.temp_dir, filenames=[self.log_file], streamhandler=True
# Enable stream handler
) as logger:
# Should have both file and stream handlers
stream_handlers = [h for h in logger.handlers if isinstance(h, logging.StreamHandler)]
file_handlers = [h for h in logger.handlers if hasattr(h, 'baseFilename')]
assert len(stream_handlers) > 0
assert len(file_handlers) > 0
logger.info("Test message to file and console")
# All handlers should be cleaned up
assert len(logger.handlers) == 0
def test_nested_context_managers(self):
"""Test nested context managers don't interfere."""
with BasicLog(name="outer_logger", level=LogLevel.INFO.value) as outer_logger:
outer_logger.info("Outer logger message")
with BasicLog(name="inner_logger", level=LogLevel.DEBUG.value) as inner_logger:
inner_logger.debug("Inner logger message")
assert outer_logger.name != inner_logger.name
# Inner logger should be cleaned up
assert len(inner_logger.handlers) == 0
# Outer logger should still work
outer_logger.info("Outer logger still working")
# Both loggers should be cleaned up
assert len(outer_logger.handlers) == 0
assert len(inner_logger.handlers) == 0
def test_shutdown_logger(self):
"""Test shutdown_logger functionality."""
logger_name = "test_shutdown_logger"
# Create a logger using factory (with registry caching)
logger = LoggerFactory.get_or_create_logger("basic", name=logger_name, level=LogLevel.INFO.value)
# Verify logger is in registry
assert logger_name in LoggerFactory._logger_registry
# Add some handlers
handler = logging.StreamHandler()
logger.addHandler(handler)
# Verify handler is attached
assert len(logger.handlers) > 0
# Shutdown the specific logger
LoggerFactory.shutdown_logger(logger_name)
# Verify logger handlers are cleaned up
assert len(logger.handlers) == 0
# Verify logger is removed from registry
assert logger_name not in LoggerFactory._logger_registry
if __name__ == "__main__":
pytest.main([__file__])