Rotary Logger  1.0.2
The middleware rotary logger
Loading...
Searching...
No Matches
test_rotary_integration.py
Go to the documentation of this file.
1"""
2# +==== BEGIN rotary_logger =================+
3# LOGO:
4# ..........####...####..........
5# ......###.....#.#########......
6# ....##........#.###########....
7# ...#..........#.############...
8# ...#..........#.#####.######...
9# ..#.....##....#.###..#...####..
10# .#.....#.##...#.##..##########.
11# #.....##########....##...######
12# #.....#...##..#.##..####.######
13# .#...##....##.#.##..###..#####.
14# ..#.##......#.#.####...######..
15# ..#...........#.#############..
16# ..#...........#.#############..
17# ...##.........#.############...
18# ......#.......#.#########......
19# .......#......#.########.......
20# .........#####...#####.........
21# /STOP
22# PROJECT: rotary_logger
23# FILE: test_rotary_integration.py
24# CREATION DATE: 01-11-2025
25# LAST Modified: 3:44:19 04-03-2026
26# DESCRIPTION:
27# A module that provides a universal python light on iops way of logging to files your program execution.
28# /STOP
29# COPYRIGHT: (c) Asperguide
30# PURPOSE: This is the file in charge of making sure that the Rotary logger class works and does what is expected of it.
31# // AR
32# +==== END rotary_logger =================+
33"""
34import sys
35import shutil
36from pathlib import Path
37
38from rotary_logger.rotary_logger_cls import RotaryLogger
39
40
41def test_start_logging_wires_and_writes(tmp_path: Path) -> None:
42 parent = tmp_path
43 # Construct a FileInstance-backed TeeStream and write to it to verify
44 # that the wiring results in log files being created.
45 from rotary_logger.file_instance import FileInstance
46 from rotary_logger.tee_stream import TeeStream
47
48 orig = sys.stdout
49 try:
50 fi = FileInstance(parent / 'logs.log', max_size_mb=1)
51 ts = TeeStream(fi, orig)
52 ts.write('integration test line\n')
53 ts.flush()
54 logs = list(parent.rglob('*.log'))
55 assert logs, 'No logs created by TeeStream/FileInstance'
56 content = logs[0].read_text(
57 encoding=fi.get_encoding(), errors='ignore')
58 assert 'integration test line' in content
59 finally:
60 try:
61 shutil.rmtree(parent)
62 except Exception:
63 pass
64
65
66def test_destructor_safe_on_closed_files(tmp_path: Path) -> None:
67 root = tmp_path / 'logs'
68 # Create and immediately close underlying streams to simulate shutdown
69 import io
70 import gc
71 orig = io.StringIO()
72 # create a TeeStream directly to test destructor
73 from rotary_logger.tee_stream import TeeStream
74 ts = TeeStream(root, orig, max_size_mb=1)
75 # close underlying file descriptor (best-effort) and original stream
76 try:
77 fi = getattr(ts, "file_instance", None)
78 if fi and fi.file and getattr(fi.file, "descriptor", None):
79 try:
80 fi.file.descriptor.close()
81 except Exception:
82 pass
83 except Exception:
84 pass
85 orig.close()
86 # deleting ts should not raise; collect to trigger __del__
87 del ts
88 gc.collect()
89
90
91def test_log_to_file_false_writes_no_content(tmp_path: Path) -> None:
92 """With log_to_file=False, no content should be written to any log file."""
93 SENTINEL = "SENTINEL_MUST_NOT_APPEAR_IN_LOG_XYZ"
94 rl = RotaryLogger()
95 orig_out = sys.stdout
96 orig_err = sys.stderr
97 try:
98 rl.start_logging(log_folder=tmp_path, merged=True, log_to_file=False)
99 sys.stdout.write(f"{SENTINEL}\n")
100 try:
101 sys.stdout.flush()
102 except Exception:
103 pass
104 finally:
105 sys.stdout = orig_out
106 sys.stderr = orig_err
107
108 for log_file in tmp_path.rglob("*.log"):
109 content = log_file.read_text(encoding="utf-8", errors="ignore")
110 assert SENTINEL not in content, (
111 f"Sentinel unexpectedly logged to {log_file} when log_to_file=False"
112 )
113
114
115def test_stdout_prefix_appears_in_log(tmp_path: Path) -> None:
116 """When prefix_out_stream=True the [STDOUT] prefix should appear in the log."""
117 from rotary_logger import constants as CONST
118
119 rl = RotaryLogger(prefix_out_stream=True)
120 orig_out = sys.stdout
121 orig_err = sys.stderr
122 try:
123 rl.start_logging(log_folder=tmp_path, merged=True, log_to_file=True)
124 sys.stdout.write("prefixed line\n")
125 try:
126 sys.stdout.flush()
127 except Exception:
128 pass
129 finally:
130 sys.stdout = orig_out
131 sys.stderr = orig_err
132
133 log_files = list(tmp_path.rglob("*.log"))
134 assert log_files, "No log file was created"
135 content = log_files[0].read_text(encoding="utf-8")
136 assert CONST.PREFIX_STDOUT in content, (
137 f"Expected {CONST.PREFIX_STDOUT!r} in log, got: {content!r}"
138 )
None test_start_logging_wires_and_writes(Path tmp_path)
None test_destructor_safe_on_closed_files(Path tmp_path)
None test_log_to_file_false_writes_no_content(Path tmp_path)
None test_stdout_prefix_appears_in_log(Path tmp_path)