Skip to content

Commit 84b22c4

Browse files
authored
Merge pull request #5 from cidrblock/main
Update to centralize GH logging
2 parents e466831 + b6d640e commit 84b22c4

File tree

3 files changed

+113
-30
lines changed

3 files changed

+113
-30
lines changed

.config/dictionary.txt

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,33 @@
11
addoption
22
addopts
3+
autouse
34
cliargs
45
dataclass
56
dumpxml
7+
endgroup
8+
endgroup
69
filterwarnings
710
fixturenames
811
fqcn
912
getppid
13+
hookwrapper
1014
httpapi
1115
HTTPAPI
1216
libssh
1317
Libssh
18+
makereport
1419
metafunc
1520
netcommon
1621
netconf
1722
pathsep
23+
pluggy
1824
popen
1925
pylibssh
2026
pylibsshext
2127
rootdir
2228
skipif
2329
testpaths
30+
tryfirst
2431
virl
2532
virsh
2633
xmltodict

mypy.ini

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,9 @@ strict_optional = true
1616
# No type hints as of version 0.4.0
1717
ignore_missing_imports = true
1818

19-
19+
[mypy-pluggy.*]
20+
# No type hints as of version 1.0.0
21+
ignore_missing_imports = true
2022

2123
[mypy-xmltodict]
2224
# No type hints as of version 0.12.0

src/pytest_ansible_network_integration/__init__.py

Lines changed: 103 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,21 @@
11
# cspell:ignore nodeid
22
"""Common fixtures for tests."""
3-
import argparse
43
import json
54
import logging
65
import os
76
import time
87

98
from pathlib import Path
109
from typing import Any
10+
from typing import Callable
1111
from typing import Dict
1212
from typing import Generator
1313
from typing import List
1414

1515
import pytest
1616

17+
from pluggy._result import _Result as pluggy_result
18+
1719
from .defs import AnsibleProject
1820
from .defs import CmlWrapper
1921
from .defs import VirshWrapper
@@ -185,6 +187,24 @@ def required_environment_variables() -> Dict[str, str]:
185187
return variables # type: ignore[return-value]
186188

187189

190+
def _github_action_log(message: str) -> None:
191+
"""Log a message to GitHub Actions.
192+
193+
:param message: The message
194+
"""
195+
if os.environ.get("GITHUB_ACTIONS"):
196+
print(f"\n{message}", flush=True)
197+
198+
199+
@pytest.fixture(scope="session", autouse=True)
200+
def github_action_log() -> Callable[[str], None]:
201+
"""Log a message to GitHub Actions.
202+
203+
:returns: The log function
204+
"""
205+
return _github_action_log
206+
207+
188208
@pytest.fixture(scope="session", name="appliance_dhcp_address")
189209
def _appliance_dhcp_address(env_vars: Dict[str, str]) -> Generator[str, None, None]:
190210
"""Build the lab and collect the appliance DHCP address.
@@ -193,45 +213,57 @@ def _appliance_dhcp_address(env_vars: Dict[str, str]) -> Generator[str, None, No
193213
:raises Exception: Missing environment variables, lab, or appliance
194214
:yields: The appliance DHCP address
195215
"""
196-
logger.info("Starting lab provisioning")
216+
_github_action_log("::group::Starting lab provisioning")
197217

198-
if not OPTIONS:
199-
raise Exception("Missing CML lab")
200-
lab_file = OPTIONS.cml_lab
201-
if not os.path.exists(lab_file):
202-
raise Exception(f"Missing lab file '{lab_file}'")
218+
logger.info("Starting lab provisioning")
203219

204-
start = time.time()
205-
cml = CmlWrapper(
206-
host=env_vars["cml_host"],
207-
username=env_vars["cml_ui_user"],
208-
password=env_vars["cml_ui_password"],
209-
)
210-
cml.bring_up(file=lab_file)
211-
lab_id = cml.current_lab_id
220+
try:
212221

213-
virsh = VirshWrapper(
214-
host=env_vars["cml_host"],
215-
user=env_vars["cml_ssh_user"],
216-
password=env_vars["cml_ssh_password"],
217-
port=int(env_vars["cml_ssh_port"]),
218-
)
222+
if not OPTIONS:
223+
raise Exception("Missing CML lab")
224+
lab_file = OPTIONS.cml_lab
225+
if not os.path.exists(lab_file):
226+
raise Exception(f"Missing lab file '{lab_file}'")
227+
228+
start = time.time()
229+
cml = CmlWrapper(
230+
host=env_vars["cml_host"],
231+
username=env_vars["cml_ui_user"],
232+
password=env_vars["cml_ui_password"],
233+
)
234+
cml.bring_up(file=lab_file)
235+
lab_id = cml.current_lab_id
236+
237+
virsh = VirshWrapper(
238+
host=env_vars["cml_host"],
239+
user=env_vars["cml_ssh_user"],
240+
password=env_vars["cml_ssh_password"],
241+
port=int(env_vars["cml_ssh_port"]),
242+
)
243+
244+
try:
245+
ip_address = virsh.get_dhcp_lease(lab_id)
246+
except Exception as exc:
247+
virsh.close()
248+
cml.remove()
249+
raise Exception("Failed to get DHCP lease for the appliance") from exc
250+
251+
end = time.time()
252+
logger.info("Elapsed time to provision %s seconds", end - start)
219253

220-
try:
221-
ip_address = virsh.get_dhcp_lease(lab_id)
222254
except Exception as exc:
223-
virsh.close()
224-
cml.remove()
225-
raise Exception("Failed to get DHCP lease for the appliance") from exc
226-
227-
end = time.time()
228-
logger.info("Elapsed time to provision %s seconds", end - start)
255+
logger.error("Failed to provision lab")
256+
_github_action_log("::endgroup::")
257+
raise Exception("Failed to provision lab") from exc
229258

230259
virsh.close()
260+
_github_action_log("::endgroup::")
231261

232262
yield ip_address
233263

264+
_github_action_log("::group::Removing lab")
234265
cml.remove()
266+
_github_action_log("::endgroup::")
235267

236268

237269
@pytest.fixture
@@ -293,3 +325,45 @@ def environment() -> Dict[str, Any]:
293325
if "VIRTUAL_ENV" in os.environ:
294326
env["PATH"] = os.path.join(os.environ["VIRTUAL_ENV"], "bin") + os.pathsep + env["PATH"]
295327
return env
328+
329+
330+
@pytest.hookimpl(tryfirst=True, hookwrapper=True) # type: ignore[misc]
331+
def pytest_runtest_makereport(
332+
item: pytest.Item, *_args: Any, **_kwargs: Any
333+
) -> Generator[None, pluggy_result, None]:
334+
"""Add additional information to the test item.
335+
336+
:param item: The test item
337+
:param _args: The positional arguments
338+
:param _kwargs: The keyword arguments
339+
:yields: To all other hooks
340+
"""
341+
# execute all other hooks to obtain the report object
342+
outcome = yield
343+
rep = outcome.get_result()
344+
345+
# set a report attribute for each phase of a call, which can
346+
# be "setup", "call", "teardown"
347+
348+
setattr(item, "rep_" + rep.when, rep)
349+
350+
351+
@pytest.fixture(autouse=True)
352+
def github_log(request: pytest.FixtureRequest) -> Generator[None, None, None]:
353+
"""Log a message to GitHub Actions.
354+
355+
:param request: The request
356+
:yields: To the test
357+
"""
358+
if not os.environ.get("GITHUB_ACTIONS"):
359+
return
360+
361+
name = request.node.name
362+
363+
_github_action_log(f"::group::Run integration test: '{name}'")
364+
yield
365+
366+
if request.node.rep_setup.passed and request.node.rep_call.failed:
367+
_github_action_log(f"::error title=Integration test failure::{name}")
368+
369+
_github_action_log("::endgroup::")

0 commit comments

Comments
 (0)