Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 18 additions & 6 deletions src/buildkite_test_collector/pytest_plugin/buildkite_plugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -106,14 +106,26 @@ def pytest_runtest_logreport(self, report):
logger.debug("-> subtest passed/skipped, ignoring")
return

# This hook is called three times during the lifecycle of a test:
# after the setup phase, the call phase, and the teardown phase.
# We capture outcomes from the call phase, or setup/teardown phase if it failed
# (since setup failures prevent the call phase from running, and teardown
# failures should mark an otherwise passing test as failed).
# This hook fires three times per test: setup, call, teardown.
# We only capture the result when it carries meaningful information:
#
# call: always — this is the actual test result.
# setup: only on failure or skip — the call phase won't run,
# so this is the only outcome we'll get.
# teardown: only on failure — overrides the call result because
# broken cleanup should fail the test.
#
# We intentionally skip setup-passed and teardown-passed/skipped
# because they would overwrite the real test outcome.
#
# See: https://github.com/buildkite/test-collector-python/pull/45
# See: https://github.com/buildkite/test-collector-python/issues/84
if report.when == 'call' or (report.when in ('setup', 'teardown') and report.failed):
should_capture = (
report.when == 'call'
or (report.when == 'setup' and not report.passed)
or (report.when == 'teardown' and report.failed)
)
if should_capture:
# Guard: do not let the parent test's "passed" call-phase
# report overwrite a failure that was set by a SubtestReport.
if (
Expand Down
17 changes: 17 additions & 0 deletions tests/buildkite_test_collector/pytest_plugin/test_plugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,23 @@ def test_pytest_runtest_logreport_simple_skip(fake_env):
# TODO: track skip reason as failure_reason via longrepr


def test_pytest_runtest_logreport_skip_in_setup(fake_env):
"""Tests skipped during setup (e.g. @pytest.mark.skip) should be recorded as skipped"""
payload = Payload.init(fake_env)
plugin = BuildkitePlugin(payload)

location = ("path/to/test.py", 100, "")
longrepr = ("path/to/test.py", 100, "Skipped: unconditional skip")
report = TestReport(nodeid="", location=location, keywords={}, outcome="skipped", longrepr=longrepr, when="setup")

plugin.pytest_runtest_logstart(report.nodeid, location)
plugin.pytest_runtest_logreport(report)

test_data = plugin.in_flight.get(report.nodeid)
assert isinstance(test_data, TestData)
assert isinstance(test_data.result, TestResultSkipped)


def test_save_json_payload_without_merge(fake_env, tmp_path, successful_test):
payload = Payload.init(fake_env)
payload = Payload.started(payload)
Expand Down