-
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathtest_factory_windows.py
More file actions
412 lines (349 loc) · 16.7 KB
/
test_factory_windows.py
File metadata and controls
412 lines (349 loc) · 16.7 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
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
#!/usr/bin/env python3
"""Windows-specific tests for the factory pattern implementation."""
import os
import pytest
import sys
# Add parent directory to path for imports
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
from pythonlogs import (
BasicLog,
LogLevel,
RotateWhen,
SizeRotatingLog,
TimedRotatingLog,
)
from pythonlogs.core.factory import LoggerFactory, LoggerType, clear_logger_registry
# Import Windows-safe utilities for test cleanup
from tests.core.test_log_utils import (
cleanup_all_loggers,
windows_safe_temp_directory,
)
class TestLoggerFactoryWindows:
"""Windows-specific test cases for the LoggerFactory pattern."""
def setup_method(self):
"""Clear registry before each test."""
cleanup_all_loggers()
clear_logger_registry()
def teardown_method(self):
"""Clean up after each test."""
cleanup_all_loggers()
clear_logger_registry()
@pytest.mark.skipif(sys.platform != "win32", reason="Windows-specific tests")
def test_size_rotating_logger_creation_windows(self):
"""Test size rotating logger creation using convenience function on Windows."""
with windows_safe_temp_directory() as temp_dir:
size_logger = SizeRotatingLog(name="test_size_win", directory=temp_dir, maxmbytes=5)
assert size_logger.name == "test_size_win"
@pytest.mark.skipif(sys.platform != "win32", reason="Windows-specific tests")
def test_timed_rotating_logger_creation_windows(self):
"""Test timed rotating logger creation on Windows."""
with windows_safe_temp_directory() as temp_dir:
timed_logger = TimedRotatingLog(name="test_timed_win", directory=temp_dir, when="midnight")
assert timed_logger.name == "test_timed_win"
@pytest.mark.skipif(sys.platform != "win32", reason="Windows-specific tests")
def test_logger_with_file_output_windows(self):
"""Test logger creation with actual file output on Windows."""
with windows_safe_temp_directory() as temp_dir:
logger = SizeRotatingLog(name="file_test_win", directory=temp_dir, filenames=["test.log"], level="INFO")
# Test logging
logger.info("Test message")
logger.warning("Test warning")
# Verify logger is working
assert logger.name == "file_test_win"
assert logger.level == 20 # INFO level
@pytest.mark.skipif(sys.platform != "win32", reason="Windows-specific tests")
def test_factory_create_size_rotating_logger_windows(self):
"""Test factory create_size_rotating_logger method on Windows."""
with windows_safe_temp_directory() as temp_dir:
logger = LoggerFactory.create_logger(
LoggerType.SIZE_ROTATING,
name="size_factory_test_win",
directory=temp_dir,
maxmbytes=10,
level=LogLevel.INFO,
)
assert logger.name == "size_factory_test_win"
@pytest.mark.skipif(sys.platform != "win32", reason="Windows-specific tests")
def test_factory_create_timed_rotating_logger_windows(self):
"""Test factory create_timed_rotating_logger method on Windows."""
with windows_safe_temp_directory() as temp_dir:
logger = LoggerFactory.create_logger(
LoggerType.TIMED_ROTATING,
name="timed_factory_test_win",
directory=temp_dir,
when=RotateWhen.DAILY,
level="ERROR",
)
assert logger.name == "timed_factory_test_win"
@pytest.mark.skipif(sys.platform != "win32", reason="Windows-specific tests")
def test_convenience_functions_comprehensive_windows(self):
"""Test all convenience functions with various parameters on Windows."""
# Test BasicLog
basic_log = BasicLog(name="conv_basic_win", level="DEBUG")
assert basic_log.name == "conv_basic_win"
# Test SizeRotatingLog
with windows_safe_temp_directory() as temp_dir:
size_log = SizeRotatingLog(
name="conv_size_win",
directory=temp_dir,
filenames=["test1.log", "test2.log"],
maxmbytes=5,
daystokeep=30,
)
assert size_log.name == "conv_size_win"
# Test TimedRotatingLog
timed_log = TimedRotatingLog(
name="conv_timed_win",
directory=temp_dir,
when="midnight",
sufix="%Y%m%d",
daystokeep=7,
)
assert timed_log.name == "conv_timed_win"
@pytest.mark.skipif(sys.platform != "win32", reason="Windows-specific tests")
def test_factory_pattern_match_case_coverage_windows(self):
"""Test all pattern match cases in factory create_logger on Windows."""
with windows_safe_temp_directory() as temp_dir:
# Test BASIC case
basic = LoggerFactory.create_logger(LoggerType.BASIC, name="match_basic_win")
assert basic.name == "match_basic_win"
# Test SIZE_ROTATING case
size = LoggerFactory.create_logger(LoggerType.SIZE_ROTATING, name="match_size_win", directory=temp_dir)
assert size.name == "match_size_win"
# Test TIMED_ROTATING case
timed = LoggerFactory.create_logger(LoggerType.TIMED_ROTATING, name="match_timed_win", directory=temp_dir)
assert timed.name == "match_timed_win"
@pytest.mark.skipif(sys.platform != "win32", reason="Windows-specific tests")
def test_file_based_size_rotating_logger_windows(self):
"""Test file-based size rotating logger example on Windows."""
with windows_safe_temp_directory() as temp_dir:
logger = SizeRotatingLog(
name="app_logger_win",
directory=temp_dir,
filenames=["app.log", "debug.log"],
maxmbytes=1,
# Small size for testing
daystokeep=7,
level=LogLevel.DEBUG,
streamhandler=False, # No console output for test
)
# Generate some log messages
for i in range(10):
logger.info(f"Log message {i}")
logger.error(f"Error message {i}")
# Verify logger is working
assert logger.name == "app_logger_win"
@pytest.mark.skipif(sys.platform != "win32", reason="Windows-specific tests")
def test_time_based_rotating_logger_windows(self):
"""Test time-based rotating logger example on Windows."""
with windows_safe_temp_directory() as temp_dir:
logger = TimedRotatingLog(
name="scheduled_app_win",
directory=temp_dir,
filenames=["scheduled.log"],
when=RotateWhen.DAILY,
level=LogLevel.WARNING,
streamhandler=False,
)
logger.warning("Scheduled task started")
logger.error("Task encountered an error")
logger.critical("Critical system failure")
# Verify logger is working
assert logger.name == "scheduled_app_win"
@pytest.mark.skipif(sys.platform != "win32", reason="Windows-specific tests")
def test_production_like_multi_logger_setup_windows(self):
"""Test production-like setup with multiple loggers on Windows."""
with windows_safe_temp_directory() as temp_dir:
# Application logger
app_logger = LoggerFactory.create_logger(
LoggerType.SIZE_ROTATING,
name="production_app_win",
directory=temp_dir,
filenames=["app.log"],
maxmbytes=50,
daystokeep=30,
level=LogLevel.INFO,
streamhandler=False,
showlocation=True,
timezone="UTC",
)
# Error logger
error_logger = LoggerFactory.create_logger(
LoggerType.SIZE_ROTATING,
name="production_errors_win",
directory=temp_dir,
filenames=["errors.log"],
maxmbytes=10,
daystokeep=90,
level=LogLevel.ERROR,
streamhandler=False,
)
# Audit logger
audit_logger = LoggerFactory.create_logger(
LoggerType.TIMED_ROTATING,
name="audit_log_win",
directory=temp_dir,
filenames=["audit.log"],
when=RotateWhen.MIDNIGHT,
level=LogLevel.INFO,
streamhandler=False,
)
# Test logging to different loggers
app_logger.info("Application started successfully")
error_logger.error("Database connection failed")
audit_logger.info("User login: admin")
# Verify all loggers are different instances
assert app_logger.name != error_logger.name != audit_logger.name
@pytest.mark.skipif(sys.platform != "win32", reason="Windows-specific tests")
def test_logger_registry_in_production_scenario_windows(self):
"""Test logger registry usage in production scenario on Windows."""
with windows_safe_temp_directory() as temp_dir:
# First module gets logger
module1_logger = LoggerFactory.get_or_create_logger(
LoggerType.SIZE_ROTATING,
name="shared_app_logger_win",
directory=temp_dir,
level=LogLevel.INFO,
)
# The Second module gets the same logger (cached)
module2_logger = LoggerFactory.get_or_create_logger(
LoggerType.SIZE_ROTATING,
name="shared_app_logger_win",
directory=temp_dir, # Must provide same params
)
# Should be the same instance
assert module1_logger is module2_logger
# Both modules can log
module1_logger.info("Message from module 1")
module2_logger.info("Message from module 2")
@pytest.mark.skipif(sys.platform != "win32", reason="Windows-specific tests")
def test_mixed_enum_string_usage_example_windows(self):
"""Test realistic mixed usage of enums and strings on Windows."""
with windows_safe_temp_directory() as temp_dir:
# Configuration from environment (strings)
config_level = "INFO"
config_when = "midnight"
# Create logger with mix of config and enums
logger = TimedRotatingLog(
name="config_driven_app_win",
directory=temp_dir,
level=config_level, # String from config
when=RotateWhen.MIDNIGHT, # Enum for type safety
streamhandler=True,
)
logger.info("Configuration loaded successfully")
assert logger.name == "config_driven_app_win"
@pytest.mark.skipif(sys.platform != "win32", reason="Windows-specific tests")
def test_logger_customization_example_windows(self):
"""Test logger with extensive customization on Windows."""
with windows_safe_temp_directory() as temp_dir:
logger = LoggerFactory.create_logger(
LoggerType.TIMED_ROTATING,
name="custom_app_win",
directory=temp_dir,
filenames=["custom.log", "custom_debug.log"],
level=LogLevel.DEBUG,
when=RotateWhen.HOURLY,
daystokeep=14,
encoding="utf-8",
datefmt="%Y-%m-%d %H:%M:%S",
timezone="UTC",
streamhandler=True,
showlocation=True,
)
# Test all log levels
logger.debug("Debug information")
logger.info("Informational message")
logger.warning("Warning message")
logger.error("Error occurred")
logger.critical("Critical failure")
assert logger.name == "custom_app_win"
assert logger.level == 10 # DEBUG level
@pytest.mark.skipif(sys.platform != "win32", reason="Windows-specific tests")
def test_convenience_functions_examples_windows(self):
"""Test all convenience functions with realistic scenarios on Windows."""
# Basic logger for console output
console_logger = BasicLog(name="console_win", level=LogLevel.WARNING)
console_logger.warning("Console warning message")
# Size rotating for application logs
with windows_safe_temp_directory() as temp_dir:
app_logger = SizeRotatingLog(
name="application_win",
directory=temp_dir,
maxmbytes=5,
level=LogLevel.INFO,
)
app_logger.info("Application log message")
# Timed rotating for audit logs
audit_logger = TimedRotatingLog(
name="audit_win",
directory=temp_dir,
when=RotateWhen.DAILY,
level=LogLevel.INFO,
)
audit_logger.info("Audit log message")
# Verify all loggers have different names
names = {console_logger.name, app_logger.name, audit_logger.name}
assert len(names) == 3 # All unique names
@pytest.mark.skipif(sys.platform != "win32", reason="Windows-specific tests")
def test_factory_lru_eviction_comprehensive_windows(self):
"""Test comprehensive LRU eviction scenarios on Windows with timing considerations."""
import time
# Set a small limit for testing
LoggerFactory.set_memory_limits(max_loggers=2, ttl_seconds=3600)
# Create loggers in specific order with deliberate delays to ensure timestamp ordering
logger1 = LoggerFactory.get_or_create_logger(LoggerType.BASIC, name="lru1_win")
time.sleep(0.01) # Small delay to ensure different timestamps
logger2 = LoggerFactory.get_or_create_logger(LoggerType.BASIC, name="lru2_win")
time.sleep(0.01) # Small delay to ensure different timestamps
# Access logger1 to update its timestamp
logger1_again = LoggerFactory.get_or_create_logger(LoggerType.BASIC, name="lru1_win")
assert logger1 is logger1_again
time.sleep(0.01) # Small delay to ensure timestamp update
# Create third logger - should evict logger2 (oldest)
logger3 = LoggerFactory.get_or_create_logger(LoggerType.BASIC, name="lru3_win")
registry = LoggerFactory.get_registered_loggers()
assert len(registry) == 2
# On Windows, timing might be less precise, so let's be more flexible
# We know one of the first two loggers should be evicted
assert "lru3_win" in registry # Newly created should always be there
# Either lru1 or lru2 was evicted, but not both
lru1_present = "lru1_win" in registry
lru2_present = "lru2_win" in registry
assert lru1_present != lru2_present # Exactly one should be present (XOR)
# Ideally, lru1 should be present (recently accessed) and lru2 should be evicted,
# But on Windows, we'll accept either outcome due to timing precision issues
evicted_logger = "lru2_win" if lru1_present else "lru1_win"
remaining_logger = "lru1_win" if lru1_present else "lru2_win"
assert remaining_logger in registry
assert evicted_logger not in registry
@pytest.mark.skipif(sys.platform != "win32", reason="Windows-specific tests")
def test_windows_file_locking_resilience_factory(self):
"""Test that Windows file locking resilience works with factory-created loggers."""
with windows_safe_temp_directory() as temp_dir:
# Create multiple loggers that write to the same directory
logger1 = LoggerFactory.create_logger(
LoggerType.SIZE_ROTATING,
name="resilience_test1_win",
directory=temp_dir,
filenames=["resilience1.log"],
maxmbytes=1,
level=LogLevel.INFO,
)
logger2 = LoggerFactory.create_logger(
LoggerType.TIMED_ROTATING,
name="resilience_test2_win",
directory=temp_dir,
filenames=["resilience2.log"],
when=RotateWhen.HOURLY,
level=LogLevel.INFO,
)
# Log messages to both loggers
for i in range(10):
logger1.info(f"Size rotating message {i}")
logger2.info(f"Timed rotating message {i}")
# Verify loggers are working
assert logger1.name == "resilience_test1_win"
assert logger2.name == "resilience_test2_win"
if __name__ == "__main__":
pytest.main([__file__])