91 lines
3.0 KiB
Python
91 lines
3.0 KiB
Python
from __future__ import annotations
|
|
|
|
from pathlib import Path
|
|
|
|
import yaml
|
|
|
|
|
|
ROOT = Path(__file__).resolve().parents[3]
|
|
MANIFEST = ROOT / "k8s" / "observability" / "event-exporter.yaml"
|
|
|
|
|
|
def test_event_exporter_watches_only_events_and_namespaces() -> None:
|
|
documents = [
|
|
doc for doc in yaml.safe_load_all(MANIFEST.read_text(encoding="utf-8")) if doc
|
|
]
|
|
role = next(doc for doc in documents if doc["kind"] == "ClusterRole")
|
|
rules = role["rules"]
|
|
assert rules == [
|
|
{
|
|
"apiGroups": [""],
|
|
"resources": ["events"],
|
|
"verbs": ["get", "watch", "list"],
|
|
},
|
|
{
|
|
"apiGroups": [""],
|
|
"resources": ["namespaces"],
|
|
"verbs": ["get", "watch", "list"],
|
|
},
|
|
]
|
|
|
|
|
|
def test_event_exporter_metadata_rules_never_write_or_delete() -> None:
|
|
documents = [
|
|
doc for doc in yaml.safe_load_all(MANIFEST.read_text(encoding="utf-8")) if doc
|
|
]
|
|
role = next(doc for doc in documents if doc["kind"] == "ClusterRole")
|
|
forbidden = {"create", "update", "patch", "delete", "deletecollection"}
|
|
assert not any(forbidden.intersection(rule["verbs"]) for rule in role["rules"])
|
|
|
|
|
|
def _event_exporter_config() -> dict:
|
|
documents = [
|
|
doc for doc in yaml.safe_load_all(MANIFEST.read_text(encoding="utf-8")) if doc
|
|
]
|
|
configmap = next(doc for doc in documents if doc["kind"] == "ConfigMap")
|
|
return yaml.safe_load(configmap["data"]["config.yaml"])
|
|
|
|
|
|
def test_event_exporter_webhook_emits_a_real_otlp_json_envelope() -> None:
|
|
config = _event_exporter_config()
|
|
receivers = config["receivers"]
|
|
assert [receiver["name"] for receiver in receivers] == ["signoz-otlp"]
|
|
|
|
webhook = receivers[0]["webhook"]
|
|
assert webhook["endpoint"].endswith("/v1/logs")
|
|
assert webhook["headers"]["Content-Type"] == "application/json"
|
|
|
|
resource_logs = webhook["layout"]["resourceLogs"]
|
|
log_record = resource_logs[0]["scopeLogs"][0]["logRecords"][0]
|
|
assert log_record["body"]["stringValue"] == "{{ .Message }}"
|
|
assert log_record["severityText"] == "{{ .Type }}"
|
|
attribute_keys = {item["key"] for item in log_record["attributes"]}
|
|
assert {
|
|
"k8s.event.reason",
|
|
"k8s.event.type",
|
|
"k8s.namespace.name",
|
|
"k8s.object.kind",
|
|
"k8s.object.name",
|
|
} <= attribute_keys
|
|
|
|
|
|
def test_event_exporter_has_one_route_and_drops_only_known_normal_noise() -> None:
|
|
config = _event_exporter_config()
|
|
routes = config["route"]["routes"]
|
|
assert len(routes) == 1
|
|
assert routes[0]["match"] == [{"receiver": "signoz-otlp"}]
|
|
assert {item["type"] for item in routes[0]["drop"]} == {"Normal"}
|
|
assert {item["reason"] for item in routes[0]["drop"]} == {
|
|
"Scheduled",
|
|
"Pulling",
|
|
"Pulled",
|
|
"Created",
|
|
"Started",
|
|
}
|
|
|
|
|
|
def test_event_exporter_keeps_late_events_without_object_lookups() -> None:
|
|
config = _event_exporter_config()
|
|
assert config["omitLookup"] is True
|
|
assert config["maxEventAgeSeconds"] == 120
|