-
-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
I found out you can actually pass plugin instance to pytester when running it inline: this means we can grab the list of spans in a sub-pytest if we run it inline. This simplifies the overall architecture to split the tests in two mode: - either we run them in a subprocess to test the whole lifecycle (e.g. upload errors are printed) - either we run them inprocess and we can read the list of spans This will make it easier in the future to replace pytest-opentelemetry and test the spans that are emitted. Change-Id: I75fd5057fef668c8e6dcbfe1f240f260df7e0bde
- Loading branch information
Showing
5 changed files
with
96 additions
and
162 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,46 +1,49 @@ | ||
import collections.abc | ||
import typing | ||
|
||
import pytest | ||
import _pytest.pytester | ||
from opentelemetry.sdk import trace | ||
|
||
import _pytest.config | ||
|
||
from pytest_mergify import tracer | ||
import pytest_mergify | ||
|
||
pytest_plugins = ["pytester"] | ||
|
||
|
||
ReconfigureT = typing.Callable[[dict[str, str]], None] | ||
|
||
|
||
@pytest.fixture | ||
def reconfigure_mergify_tracer( | ||
pytestconfig: _pytest.config.Config, | ||
@pytest.fixture(autouse=True) | ||
def set_api_url( | ||
monkeypatch: pytest.MonkeyPatch, | ||
) -> collections.abc.Generator[ReconfigureT, None, None]: | ||
) -> None: | ||
# Always override API | ||
monkeypatch.setenv("MERGIFY_API_URL", "http://localhost:9999") | ||
|
||
plugin = pytestconfig.pluginmanager.get_plugin("PytestMergify") | ||
assert plugin is not None | ||
old_tracer: tracer.MergifyTracer = plugin.mergify_tracer | ||
|
||
def _reconfigure(env: dict[str, str]) -> None: | ||
# Set environment variables | ||
for key, value in env.items(): | ||
monkeypatch.setenv(key, value) | ||
plugin.reconfigure() | ||
PytesterWithSpanReturnT = tuple[_pytest.pytester.RunResult, list[trace.ReadableSpan]] | ||
|
||
yield _reconfigure | ||
if plugin.mergify_tracer.tracer_provider is not None: | ||
plugin.mergify_tracer.tracer_provider.shutdown() | ||
plugin.mergify_tracer = old_tracer | ||
|
||
class PytesterWithSpanT(typing.Protocol): | ||
def __call__(self, code: str = ..., /) -> PytesterWithSpanReturnT: ... | ||
|
||
|
||
_DEFAULT_PYTESTER_CODE = "def test_pass(): pass" | ||
|
||
|
||
@pytest.fixture | ||
def reconfigure_mergify_tracer_gha( | ||
reconfigure_mergify_tracer: ReconfigureT, | ||
) -> None: | ||
reconfigure_mergify_tracer( | ||
{"GITHUB_ACTIONS": "true", "GITHUB_REPOSITORY": "Mergifyio/pytest-mergify"} | ||
) | ||
def pytester_with_spans( | ||
pytester: _pytest.pytester.Pytester, monkeypatch: pytest.MonkeyPatch | ||
) -> PytesterWithSpanT: | ||
def _run( | ||
code: str = _DEFAULT_PYTESTER_CODE, | ||
) -> PytesterWithSpanReturnT: | ||
monkeypatch.setenv("_PYTEST_MERGIFY_TEST", "true") | ||
plugin = pytest_mergify.PytestMergify() | ||
pytester.makepyfile(code) | ||
result = pytester.runpytest_inprocess(plugins=[plugin]) | ||
if code is _DEFAULT_PYTESTER_CODE: | ||
result.assert_outcomes(passed=1) | ||
assert plugin.mergify_tracer.exporter is not None | ||
spans: list[trace.ReadableSpan] = ( | ||
plugin.mergify_tracer.exporter.get_finished_spans() # type: ignore[attr-defined] | ||
) | ||
return result, spans | ||
|
||
return _run |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,82 +1,46 @@ | ||
import _pytest.pytester | ||
import _pytest.config | ||
import re | ||
import typing | ||
|
||
import pytest | ||
|
||
|
||
from tests import conftest | ||
|
||
from pytest_mergify import utils | ||
|
||
|
||
def test_span_resources_attributes_ci( | ||
pytester: _pytest.pytester.Pytester, | ||
reconfigure_mergify_tracer: conftest.ReconfigureT, | ||
pytester_with_spans: conftest.PytesterWithSpanT, | ||
) -> None: | ||
reconfigure_mergify_tracer({"_PYTEST_MERGIFY_TEST": "true"}) | ||
pytester.makepyfile( | ||
""" | ||
import pytest | ||
from pytest_mergify import utils | ||
def test_span(pytestconfig): | ||
plugin = pytestconfig.pluginmanager.get_plugin("PytestMergify") | ||
assert plugin is not None | ||
assert plugin.mergify_tracer.exporter is not None | ||
spans = plugin.mergify_tracer.exporter.get_finished_spans() | ||
assert spans[0].resource.attributes["cicd.provider.name"] == utils.get_ci_provider() | ||
""" | ||
result, spans = pytester_with_spans() | ||
assert all( | ||
span.resource.attributes["cicd.provider.name"] == utils.get_ci_provider() | ||
for span in spans | ||
) | ||
result = pytester.runpytest_subprocess() | ||
result.assert_outcomes(passed=1) | ||
|
||
|
||
def test_span_resources_attributes_pytest( | ||
pytester: _pytest.pytester.Pytester, | ||
reconfigure_mergify_tracer: conftest.ReconfigureT, | ||
pytester_with_spans: conftest.PytesterWithSpanT, | ||
) -> None: | ||
reconfigure_mergify_tracer({"_PYTEST_MERGIFY_TEST": "true"}) | ||
pytester.makepyfile( | ||
""" | ||
import re | ||
import pytest | ||
def test_span(pytestconfig): | ||
plugin = pytestconfig.pluginmanager.get_plugin("PytestMergify") | ||
assert plugin is not None | ||
assert plugin.mergify_tracer.exporter is not None | ||
spans = plugin.mergify_tracer.exporter.get_finished_spans() | ||
assert spans[0].resource.attributes["test.framework"] == "pytest" | ||
assert re.match(r"\d\.", spans[0].resource.attributes["test.framework.version"]) | ||
""" | ||
result, spans = pytester_with_spans() | ||
assert all( | ||
re.match( | ||
r"\d\.", | ||
typing.cast(str, span.resource.attributes["test.framework.version"]), | ||
) | ||
for span in spans | ||
) | ||
result = pytester.runpytest_subprocess() | ||
result.assert_outcomes(passed=1) | ||
|
||
|
||
def test_span_github_actions( | ||
pytester: _pytest.pytester.Pytester, | ||
reconfigure_mergify_tracer: conftest.ReconfigureT, | ||
monkeypatch: pytest.MonkeyPatch, | ||
pytester_with_spans: conftest.PytesterWithSpanT, | ||
) -> None: | ||
# Do a partial reconfig, half GHA, half local to have spans | ||
reconfigure_mergify_tracer( | ||
{ | ||
"GITHUB_ACTIONS": "true", | ||
"GITHUB_REPOSITORY": "Mergifyio/pytest-mergify", | ||
"_PYTEST_MERGIFY_TEST": "true", | ||
}, | ||
) | ||
pytester.makepyfile( | ||
""" | ||
import pytest | ||
from pytest_mergify import utils | ||
def test_span(pytestconfig): | ||
plugin = pytestconfig.pluginmanager.get_plugin("PytestMergify") | ||
assert plugin is not None | ||
assert plugin.mergify_tracer.exporter is not None | ||
spans = plugin.mergify_tracer.exporter.get_finished_spans() | ||
assert spans[0].resource.attributes["vcs.repository.name"] == "Mergifyio/pytest-mergify" | ||
""" | ||
monkeypatch.setenv("GITHUB_ACTIONS", "true") | ||
monkeypatch.setenv("GITHUB_REPOSITORY", "Mergifyio/pytest-mergify") | ||
result, spans = pytester_with_spans() | ||
assert ( | ||
spans[0].resource.attributes["vcs.repository.name"] | ||
== "Mergifyio/pytest-mergify" | ||
) | ||
result = pytester.runpytest_subprocess() | ||
result.assert_outcomes(passed=1) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,27 +1,12 @@ | ||
import _pytest.pytester | ||
import _pytest.config | ||
|
||
from tests import conftest | ||
|
||
|
||
def test_span( | ||
pytester: _pytest.pytester.Pytester, | ||
reconfigure_mergify_tracer: conftest.ReconfigureT, | ||
pytester_with_spans: conftest.PytesterWithSpanT, | ||
) -> None: | ||
reconfigure_mergify_tracer({"_PYTEST_MERGIFY_TEST": "true"}) | ||
pytester.makepyfile( | ||
""" | ||
import pytest | ||
from pytest_mergify import utils | ||
def test_span(pytestconfig): | ||
plugin = pytestconfig.pluginmanager.get_plugin("PytestMergify") | ||
assert plugin is not None | ||
assert plugin.mergify_tracer.exporter is not None | ||
spans = plugin.mergify_tracer.exporter.get_finished_spans() | ||
assert any(s.name == "pytestconfig setup" for s in spans) | ||
""" | ||
) | ||
result = pytester.runpytest_subprocess() | ||
result.assert_outcomes(passed=1) | ||
result, spans = pytester_with_spans() | ||
assert any(s.name == "test run" for s in spans) | ||
assert any(s.name == "test_span.py::test_pass" for s in spans) | ||
assert any(s.name == "test_span.py::test_pass::setup" for s in spans) | ||
assert any(s.name == "test_span.py::test_pass::call" for s in spans) | ||
assert any(s.name == "test_span.py::test_pass::teardown" for s in spans) |