Files
tracer-cloud--opensre/tests/integrations/test_victoria_logs.py
T
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

211 lines
8.5 KiB
Python

"""Unit tests for the VictoriaLogs integration.
Covers:
- ``VictoriaLogsIntegrationConfig`` model (base_url + tenant_id normalization)
- ``load_env_integrations`` env-var parsing
- ``_classify_service_instance`` DB-store classification
- ``_verify_victoria_logs`` (missing / failed / passed paths)
The verifier is built via ``build_probe_verifier`` and ultimately delegates
to ``VictoriaLogsClient.probe_access()``, which must return ``status='passed'``
on success — ``verification_exit_code()`` checks for that string specifically.
"""
from __future__ import annotations
from typing import Any
from unittest.mock import MagicMock, patch
import httpx
import pytest
from integrations._catalog_impl import _classify_service_instance
from integrations.catalog import load_env_integrations
from integrations.config_models import VictoriaLogsIntegrationConfig
from integrations.victoria_logs.verifier import verify_victoria_logs as _verify_victoria_logs
class TestVictoriaLogsIntegrationConfig:
"""Tests for the Pydantic config model."""
def test_base_url_strip_and_rstrip_slash(self) -> None:
config = VictoriaLogsIntegrationConfig(base_url=" http://vmlogs:9428/ ")
assert config.base_url == "http://vmlogs:9428"
def test_tenant_id_unset_normalizes_to_none(self) -> None:
config = VictoriaLogsIntegrationConfig(base_url="http://vmlogs:9428")
assert config.tenant_id is None
def test_tenant_id_empty_string_normalizes_to_none(self) -> None:
config = VictoriaLogsIntegrationConfig(base_url="http://vmlogs:9428", tenant_id="")
assert config.tenant_id is None
def test_tenant_id_whitespace_normalizes_to_none(self) -> None:
config = VictoriaLogsIntegrationConfig(base_url="http://vmlogs:9428", tenant_id=" ")
assert config.tenant_id is None
def test_tenant_id_explicit_value_preserved(self) -> None:
config = VictoriaLogsIntegrationConfig(base_url="http://vmlogs:9428", tenant_id="acme")
assert config.tenant_id == "acme"
def test_integration_id_default_empty(self) -> None:
config = VictoriaLogsIntegrationConfig(base_url="http://vmlogs:9428")
assert config.integration_id == ""
class TestLoadEnvIntegrations:
"""Tests for VictoriaLogs env-var loading in load_env_integrations."""
def test_url_alone_loads_active_integration(self, monkeypatch: pytest.MonkeyPatch) -> None:
monkeypatch.setenv("VICTORIA_LOGS_URL", "http://vmlogs:9428")
monkeypatch.delenv("VICTORIA_LOGS_TENANT_ID", raising=False)
records = load_env_integrations()
victoria = next((r for r in records if r["service"] == "victoria_logs"), None)
assert victoria is not None
assert victoria["status"] == "active"
assert victoria["credentials"]["base_url"] == "http://vmlogs:9428"
assert victoria["credentials"]["tenant_id"] is None
def test_no_url_means_no_record(self, monkeypatch: pytest.MonkeyPatch) -> None:
monkeypatch.delenv("VICTORIA_LOGS_URL", raising=False)
records = load_env_integrations()
assert all(r["service"] != "victoria_logs" for r in records)
def test_tenant_id_propagates_when_set(self, monkeypatch: pytest.MonkeyPatch) -> None:
monkeypatch.setenv("VICTORIA_LOGS_URL", "http://vmlogs:9428")
monkeypatch.setenv("VICTORIA_LOGS_TENANT_ID", "acme")
records = load_env_integrations()
victoria = next((r for r in records if r["service"] == "victoria_logs"), None)
assert victoria is not None
assert victoria["credentials"]["tenant_id"] == "acme"
class TestClassifyServiceInstance:
"""Tests for _classify_service_instance — the DB-store classification path."""
def test_classifies_victoria_logs_with_base_url(self) -> None:
config, key = _classify_service_instance(
key="victoria_logs",
credentials={"base_url": "http://vmlogs:9428"},
record_id="vl-prod",
)
assert key == "victoria_logs"
assert config is not None
assert config.base_url == "http://vmlogs:9428"
assert config.integration_id == "vl-prod"
def test_skips_when_base_url_missing(self) -> None:
config, key = _classify_service_instance(
key="victoria_logs",
credentials={"base_url": ""},
record_id="vl-broken",
)
assert config is None and key is None
def test_classifies_with_tenant_id(self) -> None:
config, key = _classify_service_instance(
key="victoria_logs",
credentials={"base_url": "http://vmlogs:9428", "tenant_id": "team-a"},
record_id="vl-team-a",
)
assert key == "victoria_logs"
assert config is not None
assert config.tenant_id == "team-a"
class TestVerifyVictoriaLogs:
"""Tests for the verifier — focuses on the status contract."""
def test_missing_when_base_url_absent(self) -> None:
result = _verify_victoria_logs(source="local env", config={"base_url": ""})
assert result["status"] == "missing"
assert result["service"] == "victoria_logs"
def test_passed_on_successful_query(self) -> None:
mock_response = MagicMock()
mock_response.status_code = 200
mock_response.text = '{"_msg":"hello"}\n'
mock_response.raise_for_status.return_value = None
with patch("httpx.Client.get", return_value=mock_response):
result = _verify_victoria_logs(
source="local env",
config={"base_url": "http://vmlogs:9428"},
)
assert result["status"] == "passed", (
"Verifier must return status='passed' on success — "
"verification_exit_code() checks for 'passed' specifically."
)
assert "vmlogs:9428" in result["detail"]
def test_failed_on_http_error(self) -> None:
mock_response = MagicMock()
mock_response.status_code = 500
mock_response.text = "internal error"
mock_response.raise_for_status.side_effect = httpx.HTTPStatusError(
"500 Server Error",
request=MagicMock(),
response=mock_response,
)
with patch("httpx.Client.get", return_value=mock_response):
result = _verify_victoria_logs(
source="local env",
config={"base_url": "http://vmlogs:9428"},
)
assert result["status"] == "failed"
assert "500" in result["detail"]
class TestVictoriaLogsIntegrationCanonicalShape:
"""Sanity checks that the integration shows up where the runtime expects it."""
def test_classified_config_dump_matches_pydantic_model(self) -> None:
"""The classifier returns a typed model that round-trips through model_validate."""
config, _ = _classify_service_instance(
key="victoria_logs",
credentials={"base_url": "http://vmlogs:9428", "tenant_id": "x"},
record_id="vl-1",
)
assert isinstance(config, VictoriaLogsIntegrationConfig)
roundtrip = VictoriaLogsIntegrationConfig.model_validate(
config.model_dump(exclude_none=True)
)
assert roundtrip.base_url == "http://vmlogs:9428"
assert roundtrip.tenant_id == "x"
def test_effective_integrations_field_exists(self) -> None:
"""``victoria_logs`` must be a declared field on EffectiveIntegrations."""
from integrations.effective_models import (
EffectiveIntegrationEntry,
EffectiveIntegrations,
)
entry = EffectiveIntegrationEntry(
source="local env",
config={"base_url": "http://vmlogs:9428"},
)
# Should not raise (EffectiveIntegrations uses extra='forbid').
effective: dict[str, Any] = {"victoria_logs": entry.model_dump()}
EffectiveIntegrations.model_validate(effective)
def test_registry_spec_present(self) -> None:
"""Confirm the registry spec is wired so SERVICE_KEY_MAP and verifier dispatch work."""
from integrations.registry import INTEGRATION_SPECS, SERVICE_KEY_MAP
spec = next((s for s in INTEGRATION_SPECS if s.service == "victoria_logs"), None)
assert spec is not None
assert spec.direct_effective is True
assert spec.has_verifier
from integrations.verification import get_verifier
assert get_verifier("victoria_logs") is _verify_victoria_logs
# Alias map: both spellings normalize to the canonical service.
assert SERVICE_KEY_MAP["victoria_logs"] == "victoria_logs"
assert SERVICE_KEY_MAP["victorialogs"] == "victoria_logs"