-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathconftest.py
More file actions
93 lines (73 loc) · 3.55 KB
/
Copy pathconftest.py
File metadata and controls
93 lines (73 loc) · 3.55 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
"""Pytest configuration for mongodol.
Two responsibilities:
1. Keep the ``mongodol/scrap`` directory out of collection (via the modern
pytest ``pytest_ignore_collect(collection_path, config)`` hook — the
``path`` argument of the pre-pytest-9 signature was removed in pytest 9,
which turned the old hook into a hard ``PluginValidationError``).
2. Let the suite stay green **without a live MongoDB**. mongodol is a MongoDB
data-object layer, so nearly every unit test and most module doctests need a
reachable server. When none is reachable (e.g. CI without a Mongo service)
the MongoDB-dependent items are *skipped* rather than left to fail; when a
server is available (local dev, or CI wired to one) they run normally.
"""
import os
import pathlib
from mongodol.constants import DFLT_TEST_HOST
#: Directory whose contents must never be collected.
_SCRAP_DIR = pathlib.Path(__file__).parent.resolve() / "mongodol" / "scrap"
#: Package-module stems whose doctests do NOT touch MongoDB and are therefore
#: safe to run without a server. Kept deliberately conservative: any module not
#: listed here has its doctests skipped when no MongoDB is reachable, so a new
#: MongoDB-using doctest can never silently fail CI. Widen only after verifying
#: a module's doctests are genuinely server-free.
_MONGO_FREE_DOCTEST_STEMS = frozenset({"util"})
def pytest_ignore_collect(collection_path, config):
"""Skip the scrap directory during collection.
Modern (pytest >= 7) signature: ``collection_path`` is a
:class:`pathlib.Path`. Returning ``True`` ignores the path.
"""
return str(_SCRAP_DIR) in str(collection_path)
def _mongo_available(*, timeout_ms=500):
"""Return ``True`` iff a MongoDB server answers a ping quickly.
Probes ``DFLT_TEST_HOST`` by default; set ``MONGODOL_MONGO_PROBE_HOST`` to
point the probe elsewhere (e.g. to validate the skip behaviour, or to an
external server) without touching the tests' own connection defaults.
"""
host = os.environ.get("MONGODOL_MONGO_PROBE_HOST", DFLT_TEST_HOST)
try:
from pymongo import MongoClient
client = MongoClient(host, serverSelectionTimeoutMS=timeout_ms)
try:
client.admin.command("ping")
finally:
client.close()
return True
except Exception:
return False
def _requires_mongo(item):
"""Whether a collected item needs a live MongoDB to run.
Every test under ``mongodol/tests`` exercises real collections, and every
package-module doctest except those in :data:`_MONGO_FREE_DOCTEST_STEMS`
demonstrates a live store.
"""
path = pathlib.Path(str(getattr(item, "path", None) or item.fspath))
if "tests" in path.parts:
return True
return path.stem not in _MONGO_FREE_DOCTEST_STEMS
def pytest_collection_modifyitems(config, items):
"""Drop MongoDB-dependent items when no server is reachable.
Uses *deselection* rather than a skip marker: some MongoDB-store classes are
built dynamically (via dol store decorators), so their doctest items have no
resolvable source line, and pytest >= 9 raises an ``INTERNALERROR`` while
building a *skip report* for such an item. Deselected items never reach
report generation, so this keeps CI green without a server and is robust
across pytest versions.
"""
if _mongo_available():
return
kept, deselected = [], []
for item in items:
(deselected if _requires_mongo(item) else kept).append(item)
if deselected:
config.hook.pytest_deselected(items=deselected)
items[:] = kept