Skip to content

Commit 0643e02

Browse files
authored
Merge pull request #39 from sandialabs/tjfulle/cdash-subproject-labels
Add canary_cdash_subproject_label hook for adding cdash subproject labels
2 parents 95c696d + 151cd44 commit 0643e02

File tree

7 files changed

+179
-18
lines changed

7 files changed

+179
-18
lines changed

src/_canary/config/__init__.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
from typing import Generator
99

1010
from .config import Config
11+
from .config import ConfigScope # noqa: F401
1112
from .config import get_scope_filename # noqa: F401
1213
from .rpool import ResourcePool # noqa: F401
1314
from .rpool import ResourceUnavailable # noqa: F401
@@ -53,11 +54,11 @@ def __getattr__(name: str) -> Any:
5354

5455

5556
@contextmanager
56-
def override() -> Generator[None, None, None]:
57+
def override() -> Generator[Config, None, None]:
5758
global _config
5859
save_config = _config
5960
try:
6061
_config = Config()
61-
yield
62+
yield _config
6263
finally:
6364
_config = save_config

src/_canary/main.py

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ def main(argv: Sequence[str] | None = None) -> int:
5757
color.set_color_when(args.color)
5858

5959
config.set_main_options(args)
60+
config.plugin_manager.hook.canary_addhooks(pluginmanager=config.plugin_manager)
6061
config.plugin_manager.hook.canary_configure(config=config)
6162
command = parser.get_command(args.command)
6263
if command is None:
@@ -115,23 +116,25 @@ def __init__(self, command_name: str, debug: bool = False) -> None:
115116
def __call__(self, *args_in: str, fail_on_error: bool = True) -> int:
116117
try:
117118
global reraise
118-
with config.temporary_scope() as scope:
119+
with config.override() as cfg:
119120
save_reraise: bool | None = None
120121
if self.debug:
121-
scope["config:debug"] = True
122+
scope = config.ConfigScope("tmp", None, {"config": {"debug": True}})
123+
cfg.push_scope(scope)
122124
save_reraise = reraise
123125
reraise = True
124126
argv = [self.command.name] + list(args_in)
125127
parser = make_argument_parser()
126-
for command in config.plugin_manager.get_subcommands():
128+
for command in cfg.plugin_manager.get_subcommands():
127129
parser.add_command(command)
128130
with monkeypatch.context() as mp:
129131
mp.setattr(parser, "add_argument", parser.add_plugin_argument)
130132
mp.setattr(parser, "add_argument_group", parser.add_plugin_argument_group)
131-
config.plugin_manager.hook.canary_addoption(parser=parser)
133+
cfg.plugin_manager.hook.canary_addoption(parser=parser)
132134
args = parser.parse_args(argv)
133-
config.set_main_options(args)
134-
config.plugin_manager.hook.canary_configure(config=config)
135+
cfg.set_main_options(args)
136+
cfg.plugin_manager.hook.canary_addhooks(pluginmanager=cfg.plugin_manager)
137+
cfg.plugin_manager.hook.canary_configure(config=cfg)
135138
rc = self.command.execute(args)
136139
self.returncode = rc
137140
except Exception:

src/_canary/plugins/builtin/cdash/__init__.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111

1212
from ....util.string import csvsplit
1313
from ...hookspec import hookimpl
14+
from ...hookspec import hookspec
1415
from ...types import CanaryReporter
1516
from .cdash_html_summary import cdash_summary
1617
from .gitlab_issue_generator import create_issues_from_failed_tests
@@ -19,13 +20,32 @@
1920
if TYPE_CHECKING:
2021
from ....config.argparsing import Parser
2122
from ....session import Session
23+
from ....testcase import TestCase
24+
from ...manager import CanaryPluginManager
25+
26+
27+
class CDashHooks:
28+
@hookspec
29+
def canary_cdash_labels_for_subproject(self) -> list[str] | None:
30+
"""Return a list of subproject labels to be added to Test.xml reports"""
31+
...
32+
33+
@hookspec(firstresult=True)
34+
def canary_cdash_subproject_label(self, case: "TestCase") -> str | None:
35+
"""Return a subproject label for ``case`` that will be added in Test.xml reports"""
36+
...
2237

2338

2439
@hookimpl
2540
def canary_session_reporter() -> CanaryReporter:
2641
return CDashReporter()
2742

2843

44+
@hookimpl
45+
def canary_addhooks(pluginmanager: "CanaryPluginManager"):
46+
pluginmanager.add_hookspecs(CDashHooks)
47+
48+
2949
class CDashReporter(CanaryReporter):
3050
type = "cdash"
3151
description = "CDash reporter"

src/_canary/plugins/builtin/cdash/xml_generator.py

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,16 @@ def create(
9898
else:
9999
self.buildstamp = self.validate_buildstamp(buildstamp)
100100
mkdirp(self.xml_dir)
101+
102+
unique_subproject_labels: set[str] = set(subproject_labels or [])
103+
if label_sets := config.plugin_manager.hook.canary_cdash_labels_for_subproject():
104+
unique_subproject_labels.update([_ for label_set in label_sets for _ in label_set])
105+
for case in self.data.cases:
106+
if label := config.plugin_manager.hook.canary_cdash_subproject_label(case=case):
107+
unique_subproject_labels.add(label)
108+
if unique_subproject_labels:
109+
subproject_labels = list(unique_subproject_labels)
110+
101111
if chunk_size is None:
102112
chunk_size = 500
103113
if chunk_size > 0: # type: ignore
@@ -219,7 +229,7 @@ def write_test_xml(
219229
doc = self.create_document()
220230
root = doc.firstChild
221231

222-
if subproject_labels is not None:
232+
if subproject_labels:
223233
for label in subproject_labels:
224234
subproject = doc.createElement("Subproject")
225235
subproject.setAttribute("name", label)
@@ -342,9 +352,12 @@ def write_test_xml(
342352
filename=os.path.basename(case.file),
343353
)
344354

345-
if case.keywords:
355+
keywords: set[str] = set(case.keywords)
356+
if label := config.plugin_manager.hook.canary_cdash_subproject_label(case=case):
357+
keywords.add(label)
358+
if keywords:
346359
labels = doc.createElement("Labels")
347-
for keyword in case.keywords:
360+
for keyword in keywords:
348361
add_text_node(labels, "Label", keyword)
349362
test_node.appendChild(labels)
350363

src/_canary/plugins/hookspec.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
from ..session import Session
1818
from ..testbatch import TestBatch
1919
from ..testcase import TestCase
20+
from .manager import CanaryPluginManager
2021

2122
project_name = "canary"
2223
hookspec = pluggy.HookspecMarker(project_name)
@@ -255,6 +256,10 @@ def canary_testbatch_finish(batch: "TestBatch") -> None:
255256
The default implementation runs ``batch.finish()``
256257
257258
Args:
258-
The test case.
259+
The test case batch.
259260
260261
"""
262+
263+
264+
@hookspec
265+
def canary_addhooks(pluginmanager: "CanaryPluginManager") -> None: ...

src/_canary/plugins/manager.py

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66
import sys
77
import warnings
88
from typing import TYPE_CHECKING
9-
from typing import Any
109

1110
import pluggy
1211

@@ -36,11 +35,6 @@ def factory(cls) -> "CanaryPluginManager":
3635
self.load_setuptools_entrypoints(hookspec.project_name)
3736
return self
3837

39-
def update(self, arg: dict[str, Any]) -> None:
40-
if plugins := arg.get("plugins"):
41-
for plugin in plugins:
42-
self.consider_plugin(plugin)
43-
4438
def get_subcommands(self) -> list[CanarySubcommand]:
4539
hook = self.hook.canary_subcommand
4640
return hook()

tests/cmake/subproject_labels.py

Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
import os
2+
import subprocess
3+
import sys
4+
import xml.dom.minidom as xml
5+
6+
from _canary.util.filesystem import mkdirp
7+
from _canary.util.filesystem import working_dir
8+
9+
10+
def test_cdash_labels_for_subproject(tmpdir):
11+
"""Test the plugin 'canary_cdash_labels_for_subproject'
12+
13+
The canary_cdash_labels_for_subproject allows adding subproject labels for the entire test
14+
session
15+
"""
16+
with working_dir(tmpdir.strpath, create=True):
17+
setup_cdash_labels_for_subproject()
18+
run_the_thing_and_check()
19+
20+
21+
def test_cdash_subproject_label(tmpdir):
22+
"""Test the plugin 'canary_cdash_subroject_label'
23+
24+
This plugin allows tests to define their CDash subproject label. If the subproject label is
25+
not included in the test case's keywords, it is added
26+
27+
"""
28+
with working_dir(tmpdir.strpath, create=True):
29+
setup_cdash_subproject_label()
30+
run_the_thing_and_check()
31+
32+
33+
def run_the_thing_and_check():
34+
env = dict(os.environ)
35+
env["PYTHONPATH"] = os.getcwd()
36+
subprocess.run([f"{sys.prefix}/bin/canary", "-p", "baz", "run", "."], env=env)
37+
subprocess.run(
38+
[f"{sys.prefix}/bin/canary", "-C", "TestResults", "report", "cdash", "create"], env=env
39+
)
40+
file = "TestResults/CDASH/Test-0.xml"
41+
doc = xml.parse(open(file))
42+
names = get_subproject_labels(doc)
43+
assert sorted(names) == ["baz", "foo"]
44+
names = get_test_labels(doc)
45+
assert sorted(names) == ["baz", "foo"]
46+
47+
48+
def setup_cdash_labels_for_subproject():
49+
mkdirp("baz")
50+
with open("baz/__init__.py", "w") as fh:
51+
fh.write("""\
52+
import canary
53+
@canary.hookimpl
54+
def canary_cdash_labels_for_subproject():
55+
return ['foo', 'baz']
56+
""")
57+
with open("baz.pyt", "w") as fh:
58+
fh.write("""\
59+
import sys
60+
import canary
61+
canary.directives.keywords('baz')
62+
def test():
63+
return 0
64+
if __name__ == '__main__':
65+
sys.exit(test())
66+
""")
67+
with open("foo.pyt", "w") as fh:
68+
fh.write("""\
69+
import sys
70+
import canary
71+
canary.directives.keywords('foo')
72+
def test():
73+
return 0
74+
if __name__ == '__main__':
75+
sys.exit(test())
76+
""")
77+
78+
79+
def setup_cdash_subproject_label():
80+
"""Test the plugin 'canary_cdash_subroject_label'
81+
82+
This plugin allows tests to define their CDash subproject label. If the subproject label is
83+
not included in the test case's keywords, it is added
84+
85+
"""
86+
mkdirp("baz")
87+
with open("baz/__init__.py", "w") as fh:
88+
fh.write("""\
89+
import canary
90+
@canary.hookimpl
91+
def canary_cdash_subproject_label(case):
92+
return case.family
93+
""")
94+
with open("baz.pyt", "w") as fh:
95+
fh.write("""\
96+
import sys
97+
import canary
98+
def test():
99+
return 0
100+
if __name__ == '__main__':
101+
sys.exit(test())
102+
""")
103+
with open("foo.pyt", "w") as fh:
104+
fh.write("""\
105+
import sys
106+
import canary
107+
def test():
108+
return 0
109+
if __name__ == '__main__':
110+
sys.exit(test())
111+
""")
112+
113+
114+
def get_test_labels(doc):
115+
names = []
116+
for el1 in doc.getElementsByTagName("Testing"):
117+
for el2 in el1.getElementsByTagName("Test"):
118+
for el3 in el2.getElementsByTagName("Labels"):
119+
for el4 in el3.getElementsByTagName("Label"):
120+
names.append(el4.childNodes[0].nodeValue)
121+
return names
122+
123+
124+
def get_subproject_labels(doc):
125+
return [el.getAttribute("name") for el in doc.getElementsByTagName("Subproject")]

0 commit comments

Comments
 (0)