21
21
from lib .topotest import g_extra_config as topotest_extra_config
22
22
from lib .topotest import json_cmp_result
23
23
24
- try :
25
- from _pytest ._code .code import ExceptionInfo
26
-
27
- leak_check_ok = True
28
- except ImportError :
29
- leak_check_ok = False
30
-
31
24
32
25
def pytest_addoption (parser ):
33
26
"""
@@ -138,8 +131,7 @@ def pytest_addoption(parser):
138
131
139
132
140
133
def check_for_memleaks ():
141
- if not topotest_extra_config ["valgrind_memleaks" ]:
142
- return
134
+ assert topotest_extra_config ["valgrind_memleaks" ]
143
135
144
136
leaks = []
145
137
tgen = get_topogen ()
@@ -151,21 +143,25 @@ def check_for_memleaks():
151
143
existing = tgen .valgrind_existing_files
152
144
latest = glob .glob (os .path .join (logdir , "*.valgrind.*" ))
153
145
146
+ daemons = set ()
154
147
for vfile in latest :
155
148
if vfile in existing :
156
149
continue
157
- with open (vfile ) as vf :
150
+ existing .append (vfile )
151
+ with open (vfile , encoding = "ascii" ) as vf :
158
152
vfcontent = vf .read ()
159
153
match = re .search (r"ERROR SUMMARY: (\d+) errors" , vfcontent )
160
154
if match and match .group (1 ) != "0" :
161
155
emsg = "{} in {}" .format (match .group (1 ), vfile )
162
156
leaks .append (emsg )
157
+ daemons .add (re .match (r".*\.valgrind\.(.*)\.\d+" , vfile ).group (1 ))
158
+
159
+ if tgen is not None :
160
+ tgen .valgrind_existing_files = existing
163
161
164
162
if leaks :
165
- if leak_check_ok :
166
- pytest .fail ("Memleaks found:\n \t " + "\n \t " .join (leaks ))
167
- else :
168
- logger .error ("Memleaks found:\n \t " + "\n \t " .join (leaks ))
163
+ logger .error ("valgrind memleaks found:\n \t %s" , "\n \t " .join (leaks ))
164
+ pytest .fail ("valgrind memleaks found for daemons: " + " " .join (daemons ))
169
165
170
166
171
167
def pytest_runtest_logstart (nodeid , location ):
@@ -178,18 +174,21 @@ def pytest_runtest_logfinish(nodeid, location):
178
174
topolog .logfinish (nodeid , location )
179
175
180
176
181
- def pytest_runtest_call ():
182
- """
183
- This function must be run after setup_module(), it does standarized post
184
- setup routines. It is only being used for the 'topology-only' option.
185
- """
177
+ @ pytest . hookimpl ( hookwrapper = True )
178
+ def pytest_runtest_call ( item : pytest . Item ) -> None :
179
+ "Hook the function that is called to execute the test."
180
+
181
+ # For topology only run the CLI then exit
186
182
if topotest_extra_config ["topology_only" ]:
187
- tgen = get_topogen ()
188
- if tgen is not None :
189
- # Allow user to play with the setup.
190
- tgen .cli ()
183
+ get_topogen ().cli ()
184
+ pytest .exit ("exiting after --topology-only" )
185
+
186
+ # Let the default pytest_runtest_call execute the test function
187
+ yield
191
188
192
- pytest .exit ("the topology executed successfully" )
189
+ # Check for leaks if requested
190
+ if topotest_extra_config ["valgrind_memleaks" ]:
191
+ check_for_memleaks ()
193
192
194
193
195
194
def pytest_assertrepr_compare (op , left , right ):
@@ -333,7 +332,10 @@ def assert_feature_windows(b, feature):
333
332
topotest_extra_config ["pause" ] = pause
334
333
assert_feature_windows (pause , "--pause" )
335
334
336
- topotest_extra_config ["topology_only" ] = config .getoption ("--topology-only" )
335
+ topology_only = config .getoption ("--topology-only" )
336
+ if topology_only and is_xdist :
337
+ pytest .exit ("Cannot use --topology-only with distributed test mode" )
338
+ topotest_extra_config ["topology_only" ] = topology_only
337
339
338
340
# Check environment now that we have config
339
341
if not diagnose_env (rundir ):
@@ -373,12 +375,6 @@ def pytest_runtest_makereport(item, call):
373
375
else :
374
376
pause = False
375
377
376
- if call .excinfo is None and call .when == "call" :
377
- try :
378
- check_for_memleaks ()
379
- except :
380
- call .excinfo = ExceptionInfo ()
381
-
382
378
title = "unset"
383
379
384
380
if call .excinfo is None :
0 commit comments