The Gaudi Framework  master (ff829712)
Loading...
Searching...
No Matches
collect_for_ctest Namespace Reference

Functions

 pytest_addoption (parser, pluginmanager)
 
 pytest_collectstart (collector)
 
 pytest_collection_modifyitems (session, config, items)
 
 pytest_collection_finish (session)
 
 pytest_configure (config)
 

Variables

str TEST_DESC_TEMPLATE
 

Function Documentation

◆ pytest_addoption()

collect_for_ctest.pytest_addoption ( parser,
pluginmanager )

Definition at line 24 of file collect_for_ctest.py.

24def pytest_addoption(parser, pluginmanager):
25 parser.addoption(
26 "--ctest-output-file",
27 help="name of the file to write to communicate to ctest the discovered tests",
28 )
29 parser.addoption(
30 "--ctest-pytest-command",
31 default="pytest",
32 help="how pytest has to be invoked (e.g. using wrapper commands)",
33 )
34 parser.addoption(
35 "--ctest-pytest-root-dir",
36 default=Path.cwd(),
37 help="root directory to compute test names",
38 )
39 parser.addoption(
40 "--ctest-prefix",
41 default="",
42 help="string to prefix to the generated test names",
43 )
44 parser.addoption(
45 "--ctest-label",
46 default=["pytest"],
47 action="append",
48 help="labels to attach to the test (the label pytest is always added)",
49 )
50 parser.addoption(
51 "--ctest-properties",
52 default=[],
53 action="append",
54 help="test properties to set for all discovered tests",
55 )
56 parser.addoption(
57 "--ctest-binary-dir",
58 default=None,
59 help="value of CMAKE_CURRENT_BINARY_DIR from which gaudi_add_pytest was invoked",
60 )
61 parser.addoption(
62 "--ctest-coverage",
63 default="",
64 help="select modules for which produce coverage reports",
65 )
66 parser.addoption(
67 "--ctest-coverage-command",
68 default="coverage report",
69 help="how coverage should be invoked to produce the final report",
70 )
71
72

◆ pytest_collection_finish()

collect_for_ctest.pytest_collection_finish ( session)

Definition at line 109 of file collect_for_ctest.py.

109def pytest_collection_finish(session):
110 args = session.ctest_args
111 output_filename = args.get("output_file")
112
113 if not output_filename:
114 # nothing to do if no output file is specified
115 return
116
117 output = open(output_filename, "w")
118 output_rootdir = Path(output_filename).parent
119
120 coverage = args["coverage"].split(",") if args["coverage"] else []
121 if coverage:
122 args["pytest_command"] += " --cov-report= --cov-reset " + " ".join(
123 f"--cov={module}" for module in coverage
124 )
125
126 properties = 'LABELS "{}" '.format(";".join(args["label"]))
127 if args.get("binary_dir"):
128 properties += f'ENVIRONMENT "CMAKE_CURRENT_BINARY_DIR={args["binary_dir"]}" '
129 properties += " ".join(args["properties"])
130
131 producers = defaultdict(list) # test name -> list of fixtures it produces
132 consumers = defaultdict(list) # test name -> list of fixtures it depends on
133 fixtures = defaultdict(list) # fixture name -> list of tests that produce it
134 names = []
135 for path in sorted(session.ctest_files):
136 name = os.path.relpath(path, args["pytest_root_dir"]).replace("/", ".")
137 if name.endswith(".py"):
138 name = name[:-3]
139 if name == ".":
140 # when we pass a single file to pytest, pytest_root_dir and path are the same
141 # and relpath returns ".", so we take the prefix and drop the final dot
142 # (see https://gitlab.cern.ch/gaudi/Gaudi/-/issues/354)
143 name = args["prefix"][:-1]
144 else:
145 name = args["prefix"] + name
146 pytest_cmd = args["pytest_command"]
147
148 output.write(
149 TEST_DESC_TEMPLATE.format(
150 name=name,
151 path=path,
152 pytest_cmd=pytest_cmd,
153 properties=properties,
154 )
155 )
156
157 if session.ctest_fixture_setup.get(path):
158 for fixture in session.ctest_fixture_setup[path]:
159 producers[name].append(fixture)
160 fixtures[fixture].append(name)
161
162 if session.ctest_fixture_required.get(path):
163 for fixture in session.ctest_fixture_required[path]:
164 consumers[name].append(fixture)
165
166 names.append(name)
167
168 for name in names:
169 if name in producers:
170 output.write(
171 'set_tests_properties('
172 f'{name} PROPERTIES FIXTURES_SETUP "{";".join(producers[name])}")\n'
173 )
174
175 if name in consumers:
176 producer_test_names = []
177 for fixture in consumers[name]:
178 producer_test_names.extend(fixtures[fixture])
179 output.write(
180 'if (DEFINED ENV{PYTEST_DISABLE_FIXTURES_REQUIRED})\n'
181 f' set_tests_properties({name} PROPERTIES DEPENDS "{";".join(producer_test_names)}")\n'
182 'else()\n'
183 f' set_tests_properties({name} PROPERTIES FIXTURES_REQUIRED "{";".join(consumers[name])}")\n'
184 'endif()\n'
185 )
186
187 # we force one test to be run one by one
188 if coverage:
189 # generate one coverage file per test
190 output.write(
191 f"set_tests_properties({name} PROPERTIES ENVIRONMENT COVERAGE_FILE={output_rootdir}/.coverage.{name})\n"
192 f"set_tests_properties({name} PROPERTIES FIXTURES_SETUP {name})\n"
193 )
194
195 if coverage and names:
196 combine_test = (args["prefix"] + "coverage_combine").replace("/", ".")
197 combine_command = re.sub(
198 r" report .*",
199 f" combine {' '.join(f'{output_rootdir}/.coverage.{n}' for n in names)}",
200 args["coverage_command"],
201 )
202 output.write(
203 TEST_DESC_TEMPLATE.format(
204 name=combine_test,
205 path="",
206 pytest_cmd=combine_command,
207 properties=properties,
208 )
209 )
210 output.write(
211 f"set_tests_properties({combine_test} PROPERTIES ENVIRONMENT COVERAGE_FILE={output_rootdir}/.coverage)\n"
212 f"set_tests_properties({combine_test} PROPERTIES FIXTURES_REQUIRED \"{';'.join(names)}\")\n"
213 f"set_tests_properties({combine_test} PROPERTIES FIXTURES_SETUP {combine_test})\n"
214 )
215
216 name = (args["prefix"] + "coverage_report").replace("/", ".")
217 output.write(
218 TEST_DESC_TEMPLATE.format(
219 name=name,
220 path="",
221 pytest_cmd=f"{args['coverage_command']}",
222 properties=properties + " LABELS coverage",
223 )
224 )
225 # coverage reports require all related tests to be run first
226 output.write(
227 f"set_tests_properties({name} PROPERTIES ENVIRONMENT COVERAGE_FILE={output_rootdir}/.coverage)\n"
228 f"set_tests_properties({name} PROPERTIES FIXTURES_REQUIRED {combine_test})\n"
229 )
230
231 output.close()
232
233
GAUDI_API std::string format(const char *,...)
MsgStream format utility "a la sprintf(...)".
Definition MsgStream.cpp:93

◆ pytest_collection_modifyitems()

collect_for_ctest.pytest_collection_modifyitems ( session,
config,
items )

Definition at line 89 of file collect_for_ctest.py.

89def pytest_collection_modifyitems(session, config, items):
90 if not session.ctest_args.get("output_file"):
91 # nothing to do if no output file is specified
92 return
93
94 session.ctest_files = set(item.path for item in items)
95 session.ctest_fixture_setup = defaultdict(set)
96 session.ctest_fixture_required = defaultdict(set)
97 for item in items:
98 for marker in ("ctest_fixture_setup", "ctest_fixture_required"):
99 for mark in item.iter_markers(name=marker):
100 getattr(session, marker)[item.path].update(mark.args)
101
102

◆ pytest_collectstart()

collect_for_ctest.pytest_collectstart ( collector)

Definition at line 73 of file collect_for_ctest.py.

73def pytest_collectstart(collector):
74 session, config = collector.session, collector.config
75 args = {
76 name[6:]: getattr(config.option, name)
77 for name in dir(config.option)
78 if name.startswith("ctest_")
79 }
80
81 if args.get("binary_dir"):
82 # $CMAKE_CURRENT_BINARY_DIR will be set by CTest when the test is run
83 # so, for consistency, we set it at collection time too
84 os.environ["CMAKE_CURRENT_BINARY_DIR"] = args["binary_dir"]
85
86 session.ctest_args = args
87
88

◆ pytest_configure()

collect_for_ctest.pytest_configure ( config)

Definition at line 234 of file collect_for_ctest.py.

234def pytest_configure(config):
235 config.addinivalue_line(
236 "markers",
237 "ctest_fixture_setup(name): mark test to set up a fixture needed by another test",
238 )
239 config.addinivalue_line(
240 "markers",
241 "ctest_fixture_required(name): mark test to require a fixture set up by another test",
242 )

Variable Documentation

◆ TEST_DESC_TEMPLATE

str collect_for_ctest.TEST_DESC_TEMPLATE
Initial value:
1= """
2add_test({name} {pytest_cmd} {path})
3set_tests_properties({name} PROPERTIES {properties})
4"""

Definition at line 103 of file collect_for_ctest.py.