Files
wehub-resource-sync 4b6817381b
CI (OpenClaw E2E) / openclaw test (push) Has been cancelled
CI / coverage-report (push) Has been cancelled
CI / test-kubernetes (push) Has been cancelled
CI / should-run-thorough (push) Has been cancelled
CI / test-thorough (cloudwatch-demo) (push) Has been cancelled
CI / test-thorough (flink-ecs) (push) Has been cancelled
CI / test-thorough (upstream-lambda) (push) Has been cancelled
CI / test-thorough (prefect-ecs-fargate) (push) Has been cancelled
Release / build-binaries (zip, opensre.exe, onefile, windows-latest, windows-x64) (push) Has been cancelled
Benchmark image — build + push to ECR (any adapter) / build + push (push) Has been cancelled
CI / quality (ubuntu-latest) (push) Has been cancelled
CI / test (tools-runtime) (push) Has been cancelled
CI / test (e2e-general) (push) Has been cancelled
CI / test (cli-runtime) (push) Has been cancelled
CI / test (e2e-provider-and-openclaw) (push) Has been cancelled
CI / test (integrations-and-misc) (push) Has been cancelled
Release / verify (push) Has been cancelled
Release / build-python-dist (push) Has been cancelled
Release / build-binaries (tar.gz, opensre, onedir, macos-15-intel, darwin-x64) (push) Has been cancelled
Release / build-binaries (tar.gz, opensre, onedir, macos-latest, darwin-arm64) (push) Has been cancelled
Release / build-binaries (tar.gz, opensre, onedir, ubuntu-22.04, linux-x64) (push) Has been cancelled
Release / publish-release (push) Has been cancelled
Release / publish-main-release (push) Has been cancelled
Interactive Shell Live (PR + post-merge) / turn-checks (no-LLM) (push) Has been cancelled
CodeQL / Analyze (python) (push) Has been cancelled
Interactive Shell Live (PR + post-merge) / turn-live shard ${{ matrix.shard_index }} (push) Has been cancelled
Release / prepare (push) Has been cancelled
Release / build-binaries (tar.gz, opensre, onedir, ubuntu-22.04-arm, linux-arm64) (push) Has been cancelled
Synthetic Deterministic Tests / Synthetic offline (deterministic) (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 13:10:45 +08:00

348 lines
12 KiB
Python

"""Tests for the verification plugin registry (issue #37).
Covers:
* The registry mechanism itself — register / get / list semantics.
* The two factory helpers (``build_probe_verifier`` /
``build_validation_verifier``) including all error branches.
* The shorthand registration helpers (``register_probe_verifier`` /
``register_validation_verifier``).
* Catalog sync — every service in ``SUPPORTED_VERIFY_SERVICES`` resolves
via the registry.
* The Supabase preserved arg-swap behavior — pinned so any "fix the
typo" PR has to consciously break this test.
"""
from __future__ import annotations
import sys
from collections.abc import Iterator
from types import SimpleNamespace
from typing import Any
import pytest
from integrations._verifiers_loader import register_all_verifiers
from integrations.registry import SUPPORTED_VERIFY_SERVICES
from integrations.verification import (
build_probe_verifier,
build_validation_verifier,
get_verifier,
list_verifiers,
register_probe_verifier,
register_validation_verifier,
register_verifier,
result,
)
from integrations.verification.registry import (
_reset_for_testing,
_restore_for_testing,
_snapshot_for_testing,
)
@pytest.fixture(autouse=True, scope="module")
def _ensure_verifiers_registered() -> None:
"""Trigger the loader once for the whole module so the test suite
runs against a populated registry regardless of import order."""
register_all_verifiers()
@pytest.fixture
def _isolated_registry() -> Iterator[None]:
"""Snapshot + restore the registry around each test."""
snapshot = _snapshot_for_testing()
try:
yield
finally:
_restore_for_testing(snapshot)
class TestRegistry:
def test_register_returns_decorated_function_unchanged(self, _isolated_registry: None) -> None:
def _vendor_verifier(source: str, config: dict[str, Any]) -> dict[str, str]:
return result("fake-vendor", source, "passed", "ok")
decorated = register_verifier("fake-vendor")(_vendor_verifier)
assert decorated is _vendor_verifier
def test_get_verifier_returns_the_registered_function(self, _isolated_registry: None) -> None:
def _vendor_verifier(source: str, config: dict[str, Any]) -> dict[str, str]:
return result("fake-vendor", source, "passed", "ok")
register_verifier("fake-vendor")(_vendor_verifier)
assert get_verifier("fake-vendor") is _vendor_verifier
def test_get_verifier_returns_none_for_unknown_service(self, _isolated_registry: None) -> None:
assert get_verifier("does-not-exist") is None
def test_list_verifiers_sorted_includes_registered(self, _isolated_registry: None) -> None:
_reset_for_testing()
def _verify_b(source: str, _config: dict[str, Any]) -> dict[str, str]:
return result("b", source, "passed", "")
def _verify_a(source: str, _config: dict[str, Any]) -> dict[str, str]:
return result("a", source, "passed", "")
register_verifier("b")(_verify_b)
register_verifier("a")(_verify_a)
assert list_verifiers() == ["a", "b"]
def test_re_registering_replaces_silently(self, _isolated_registry: None) -> None:
"""Re-importing a verifier module (e.g. test reloads) must not raise."""
def _first(source: str, _config: dict[str, Any]) -> dict[str, str]:
return result("dup", source, "passed", "first")
def _second(source: str, _config: dict[str, Any]) -> dict[str, str]:
return result("dup", source, "passed", "second")
register_verifier("dup")(_first)
register_verifier("dup")(_second)
assert get_verifier("dup") is _second
class TestRegistryCatalogSync:
def test_list_verifiers_matches_supported_services(self) -> None:
"""Every CLI/catalog service has a registered verifier."""
assert set(list_verifiers()) == set(SUPPORTED_VERIFY_SERVICES)
@pytest.mark.parametrize("service", ("aws", "datadog", "gitlab", "slack"))
def test_loader_discovers_integration_local_verifier_modules(self, service: str) -> None:
"""Verifier discovery loads ``integrations.<name>.verifier`` modules."""
verifier = get_verifier(service)
assert verifier is not None
assert f"integrations.{service}.verifier" in sys.modules
class TestBuildProbeVerifier:
def test_returns_passed_when_config_valid_and_probe_passes(self) -> None:
class _OkProbe:
status = "passed"
detail = "all good"
class _Client:
def __init__(self, _cfg: Any) -> None:
pass
def probe_access(self) -> _OkProbe:
return _OkProbe()
verifier = build_probe_verifier(
"fake",
build_config=lambda raw: {"normalized": raw},
client_factory=_Client,
)
assert verifier("local store", {"key": "val"}) == {
"service": "fake",
"source": "local store",
"status": "passed",
"detail": "all good",
}
def test_returns_missing_when_config_build_raises(self) -> None:
def _bad_build(_raw: dict[str, Any]) -> None:
raise ValueError("missing required field 'token'")
verifier = build_probe_verifier(
"fake",
build_config=_bad_build,
client_factory=lambda _cfg: None,
)
assert verifier("local store", {})["status"] == "missing"
assert "missing required field" in verifier("local store", {})["detail"]
def test_returns_failed_when_probe_raises(self) -> None:
class _Client:
def __init__(self, _cfg: Any) -> None:
pass
def probe_access(self) -> Any:
raise RuntimeError("network down")
verifier = build_probe_verifier(
"fake",
build_config=lambda raw: raw,
client_factory=_Client,
)
assert verifier("local store", {})["status"] == "failed"
assert "network down" in verifier("local store", {})["detail"]
class TestBuildValidationVerifier:
def test_returns_missing_when_build_config_raises(self) -> None:
def _bad_build(_raw: dict[str, Any]) -> None:
raise ValueError("missing required field 'host'")
verifier = build_validation_verifier(
"fake",
build_config=_bad_build,
validate_config=lambda _cfg: SimpleNamespace(ok=True, detail=""),
)
out = verifier("local store", {})
assert out["status"] == "missing"
assert "missing required field" in out["detail"]
def test_returns_failed_when_validate_raises(self) -> None:
def _validate_raises(_cfg: Any) -> None:
raise RuntimeError("validation blew up")
verifier = build_validation_verifier(
"fake",
build_config=lambda raw: raw,
validate_config=_validate_raises,
)
out = verifier("local store", {})
assert out["status"] == "failed"
assert "validation blew up" in out["detail"]
class TestShorthandRegistration:
def test_register_probe_verifier_registers_and_returns_callable(
self, _isolated_registry: None
) -> None:
class _Client:
def __init__(self, _cfg: Any) -> None:
pass
def probe_access(self) -> Any:
return SimpleNamespace(status="passed", detail="ok")
fn = register_probe_verifier(
"shorthand-probe",
config=lambda raw: raw,
client=_Client,
)
assert get_verifier("shorthand-probe") is fn
assert fn("local store", {})["status"] == "passed"
def test_register_validation_verifier_registers_and_returns_callable(
self, _isolated_registry: None
) -> None:
fn = register_validation_verifier(
"shorthand-validate",
build_config=lambda raw: raw,
validate_config=lambda _cfg: SimpleNamespace(ok=True, detail="config looks fine"),
)
assert get_verifier("shorthand-validate") is fn
assert fn("local store", {})["status"] == "passed"
class TestLoaderAutoDiscovery:
"""Pin the loader's contract: ``register_all_verifiers()`` populates
the registry from both vendor locations and is safe to call twice."""
def test_calling_register_all_verifiers_populates_the_registry(self) -> None:
register_all_verifiers()
# The catalog declares which services must have verifiers; auto-
# discovery's job is to make every one of them resolvable.
for service in SUPPORTED_VERIFY_SERVICES:
assert get_verifier(service) is not None, (
f"auto-discovery missed {service!r} — either the verifier "
"module is misnamed or the loader's walk excluded it"
)
def test_register_all_verifiers_is_idempotent(self, _isolated_registry: None) -> None:
"""Re-registration must replace silently (no exception) so that
repeated calls from different entry points don't blow up."""
register_all_verifiers()
before = sorted(list_verifiers())
register_all_verifiers() # second call must not raise
after = sorted(list_verifiers())
assert before == after
def test_loader_skips_shared_verification_package_but_registry_api_remains_available(
self, _isolated_registry: None
) -> None:
import importlib
import integrations.aws.verifier as aws_verifier
from integrations._verifiers_loader import _SKIP_INTEGRATION_PACKAGES
_reset_for_testing()
assert "verification" in _SKIP_INTEGRATION_PACKAGES
assert get_verifier("aws") is None
importlib.reload(aws_verifier)
register_all_verifiers()
assert get_verifier("aws") is not None
class TestVerifyWithValidationResult:
"""Direct tests for ``verify_with_validation_result`` — exercised
indirectly through ``build_validation_verifier`` elsewhere, but
worth pinning the contract directly so future refactors of the
factory don't quietly change the helper's behavior."""
def test_passes_when_validation_ok(self) -> None:
from integrations.verification import verify_with_validation_result
out = verify_with_validation_result(
"fake",
"local store",
{"raw": 1},
build_config=lambda raw: raw,
validate_config=lambda _cfg: SimpleNamespace(ok=True, detail="all good"),
)
assert out == {
"service": "fake",
"source": "local store",
"status": "passed",
"detail": "all good",
}
def test_fails_when_validation_not_ok(self) -> None:
from integrations.verification import verify_with_validation_result
out = verify_with_validation_result(
"fake",
"local env",
{},
build_config=lambda raw: raw,
validate_config=lambda _cfg: SimpleNamespace(ok=False, detail="bad token"),
)
assert out["status"] == "failed"
assert out["detail"] == "bad token"
class TestAlertmanagerRegistration:
def test_alertmanager_is_registered_via_canonical_name(self) -> None:
"""Import the vendor verifier module and check it's reachable
through both the registry and the module-level export."""
from integrations.alertmanager.verifier import verify_alertmanager
assert get_verifier("alertmanager") is verify_alertmanager
class TestSupabaseVerifierRouting:
def test_source_arg_lands_in_source_field_and_service_is_supabase(
self, monkeypatch: pytest.MonkeyPatch
) -> None:
from integrations.supabase import verifier as _supabase_verifier
# Bypass the real config validation chain — we're testing the
# verifier's arg routing, not Supabase config parsing.
monkeypatch.setattr(
_supabase_verifier,
"build_supabase_config",
lambda raw: raw,
)
monkeypatch.setattr(
_supabase_verifier,
"validate_supabase_config",
lambda _cfg: SimpleNamespace(ok=True, detail="ok"),
)
# Reach the registered callable via the registry so we test
# exactly what the dispatcher invokes.
verifier = get_verifier("supabase")
assert verifier is not None
out = verifier("local store", {"placeholder": True})
assert out["service"] == "supabase"
assert out["source"] == "local store"
assert out["status"] == "passed"