|
| 1 | +import io |
| 2 | +import logging |
| 3 | + |
1 | 4 | import numpy as np |
2 | 5 | import pandas as pd |
3 | 6 | import pytest |
|
8 | 11 | from malariagen_data import ag3 as _ag3 |
9 | 12 | from malariagen_data import adir1 as _adir1 |
10 | 13 | from malariagen_data.anoph.base import AnophelesBase |
| 14 | +from malariagen_data.util import LoggingHelper |
11 | 15 |
|
12 | 16 |
|
13 | 17 | @pytest.fixture |
@@ -258,6 +262,32 @@ def test_lookup_study(fixture, api): |
258 | 262 | api.lookup_study("foobar") |
259 | 263 |
|
260 | 264 |
|
| 265 | +def test_logging_helper_no_handler_accumulation(): |
| 266 | + # Regression test: repeated LoggingHelper construction on the same logger |
| 267 | + # name must not accumulate handlers (StreamHandler leak, FileHandler FD leak). |
| 268 | + logger_name = "test_logging_helper_no_handler_accumulation" |
| 269 | + for _ in range(10): |
| 270 | + LoggingHelper(name=logger_name, out=io.StringIO()) |
| 271 | + logger = logging.getLogger(logger_name) |
| 272 | + assert ( |
| 273 | + len(logger.handlers) <= 1 |
| 274 | + ), f"Handler leak: {len(logger.handlers)} handlers after 10 instantiations" |
| 275 | + |
| 276 | + |
| 277 | +def test_logging_helper_no_duplicate_output(): |
| 278 | + # Regression test: a message emitted after N instantiations must appear |
| 279 | + # exactly once in the output stream. |
| 280 | + logger_name = "test_logging_helper_no_duplicate_output" |
| 281 | + out = io.StringIO() |
| 282 | + for _ in range(5): |
| 283 | + helper = LoggingHelper(name=logger_name, out=out) |
| 284 | + helper.info("sentinel") |
| 285 | + output = out.getvalue() |
| 286 | + assert ( |
| 287 | + output.count("sentinel") == 1 |
| 288 | + ), f"Duplicate log output: 'sentinel' appeared {output.count('sentinel')} times" |
| 289 | + |
| 290 | + |
261 | 291 | def _strip_terms_of_use_from_manifest(manifest_path): |
262 | 292 | """Rewrite a manifest TSV file without terms-of-use columns.""" |
263 | 293 | df = pd.read_csv(manifest_path, sep="\t") |
|
0 commit comments