Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

test: refactor plugin setup #31

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
17 changes: 5 additions & 12 deletions pytest_mergify/__init__.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
import typing

import pytest
import _pytest.main
import _pytest.config
Expand All @@ -12,21 +10,16 @@


class PytestMergify:
__name__ = "PytestMergify"

mergify_tracer: MergifyTracer

# Do this after pytest-opentelemetry has setup things
@pytest.hookimpl(trylast=True)
def pytest_configure(self, config: _pytest.config.Config) -> None:
kwargs = {}
api_url = config.getoption("--mergify-api-url")
if api_url is None:
self.reconfigure()
else:
self.reconfigure(api_url=api_url)

def reconfigure(self, *args: typing.Any, **kwargs: typing.Any) -> None:
self.mergify_tracer = MergifyTracer(*args, **kwargs)
if api_url is not None:
kwargs["api_url"] = api_url
self.mergify_tracer = MergifyTracer(**kwargs)

def pytest_terminal_summary(
self, terminalreporter: _pytest.terminal.TerminalReporter
Expand Down Expand Up @@ -92,4 +85,4 @@ def pytest_addoption(parser: _pytest.config.argparsing.Parser) -> None:


def pytest_configure(config: _pytest.config.Config) -> None:
config.pluginmanager.register(PytestMergify())
config.pluginmanager.register(PytestMergify(), name="PytestMergify")
61 changes: 32 additions & 29 deletions tests/conftest.py
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
61 changes: 25 additions & 36 deletions tests/test_plugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,6 @@

import pytest_mergify

from tests import conftest


def test_plugin_is_loaded(pytestconfig: _pytest.config.Config) -> None:
plugin = pytestconfig.pluginmanager.get_plugin("pytest_mergify")
Expand All @@ -32,16 +30,13 @@ def test_foo():


def test_with_token_gha(
pytester: Pytester, reconfigure_mergify_tracer: conftest.ReconfigureT
pytester: Pytester,
monkeypatch: pytest.MonkeyPatch,
) -> None:
reconfigure_mergify_tracer(
{
"CI": "1",
"GITHUB_REPOSITORY": "Mergifyio/pytest-mergify",
"MERGIFY_TOKEN": "foobar",
"GITHUB_ACTIONS": "true",
},
)
monkeypatch.setenv("CI", "1")
monkeypatch.setenv("GITHUB_ACTIONS", "true")
monkeypatch.setenv("GITHUB_REPOSITORY", "Mergifyio/pytest-mergify")
monkeypatch.setenv("MERGIFY_TOKEN", "foobar")
pytester.makepyfile(
"""
def test_foo():
Expand All @@ -60,21 +55,25 @@ def test_foo():


def test_repo_name_github_actions(
pytestconfig: _pytest.config.Config,
reconfigure_mergify_tracer_gha: None,
pytester: Pytester,
monkeypatch: pytest.MonkeyPatch,
) -> None:
plugin = pytestconfig.pluginmanager.get_plugin("PytestMergify")
assert plugin is not None
monkeypatch.setenv("CI", "true")
monkeypatch.setenv("GITHUB_ACTIONS", "true")
monkeypatch.setenv("GITHUB_REPOSITORY", "Mergifyio/pytest-mergify")
plugin = pytest_mergify.PytestMergify()
pytester.makepyfile("")
pytester.runpytest_inprocess(plugins=[plugin])
assert plugin.mergify_tracer.repo_name == "Mergifyio/pytest-mergify"


def test_with_token_no_ci_provider(
pytester: Pytester,
reconfigure_mergify_tracer: conftest.ReconfigureT,
monkeypatch: pytest.MonkeyPatch,
) -> None:
reconfigure_mergify_tracer(
{"MERGIFY_TOKEN": "x", "CI": "1", "GITHUB_ACTIONS": "false"}
)
monkeypatch.setenv("MERGIFY_TOKEN", "x")
monkeypatch.setenv("CI", "1")
monkeypatch.setenv("GITHUB_ACTIONS", "false")
pytester.makepyfile(
"""
def test_foo():
Expand All @@ -91,27 +90,17 @@ def test_foo():

def test_errors_logs(
pytester: _pytest.pytester.Pytester,
reconfigure_mergify_tracer: conftest.ReconfigureT,
monkeypatch: pytest.MonkeyPatch,
) -> None:
# This will try to upload traces, but we don't have a real exporter so it will log errors.
reconfigure_mergify_tracer(
{
"MERGIFY_TOKEN": "true",
"CI": "1",
"GITHUB_ACTIONS": "true",
"GITHUB_REPOSITORY": "foo/bar",
}
)
monkeypatch.setenv("MERGIFY_TOKEN", "x")
monkeypatch.setenv("CI", "1")
monkeypatch.setenv("GITHUB_ACTIONS", "true")
monkeypatch.setenv("GITHUB_REPOSITORY", "foo/bar")
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
def test_pass():
pass
"""
)
result = pytester.runpytest_subprocess()
Expand Down
90 changes: 27 additions & 63 deletions tests/test_resources.py
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)
29 changes: 7 additions & 22 deletions tests/test_spans.py
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)