chore: convert lifecycle-free fixture-factories to plain functions (#12462)

#### Description

- Add the fixture-vs-function rule to `.claude/rules/pytest.md`: a
fixture earns its indirection only by owning setup/teardown (`yield` +
cleanup) or provisioning a resource; a stateless action or lookup is a
plain importable function in the matching `tests/fixtures/` module
taking `signoz`/`token` as ordinary arguments.
- Apply it to the three fixture-factories introduced in #12460 that have
no lifecycle: `delete_all_dashboards` (renamed from
`wipe_all_dashboards`) and `run_query_case` are now plain functions,
their modules deregistered from `pytest_plugins`, and all call sites
updated.
- Generalize `Metrics.load_from_file` with a `label_substitutions`
parameter (placeholder rewriting, e.g. `__START_TIME__` → runtime ISO
string) and drop the bespoke `load_pods_metrics`, which duplicated the
base-time rebase logic — `02_pods.py` now loads JSONL the same way as
every other inframonitoring suite file.

Follow-up promised in
https://github.com/SigNoz/signoz/pull/12460#discussion_r3737099384.
This commit is contained in:
Pandey
2026-08-07 22:23:07 +05:30
committed by GitHub
parent 38cc4d2bea
commit fa05a73aef
9 changed files with 119 additions and 190 deletions

View File

@@ -9,6 +9,7 @@ For the Python integration suite under `tests/`. Setup, running, and suite layou
- **No `_`-prefixed helper functions in test modules — this is the rule that matters most.** A reader must be able to see what a test does in its body alone, without chasing private helpers that scatter the meaning across the file. Inline the logic: an expression, a comprehension, a few repeated lines are all fine — repetition across tests is cheaper than indirection. When several tests genuinely share non-trivial setup or assertions, that is what fixtures are for — in `tests/fixtures/`, see the next rule. A module-level `_helper()` is never the answer.
- **Fixtures live in `tests/fixtures/` — never under `integration/tests/`.** Not in test modules, not in suite `conftest.py` files. `tests/fixtures/` is the shared library (auth, signoz, clickhouse, logs/metrics/traces seeding, …): reuse what's there before writing anything new; when a new fixture is genuinely needed, add it to the matching `tests/fixtures/` module and register new modules in `tests/conftest.py` `pytest_plugins`. **The one exception: SigNoz-level fixtures in a suite's `conftest.py`.** A suite that needs its own SigNoz spun up with different envs (`create_signoz`/`create_migrator` with `env_overrides` + `cache_key` — e.g. basepath, metricreduction, querier_json_body) keeps that in its `conftest.py`; that is always okay.
- **Fixture only when there is a lifecycle; otherwise a plain function.** A fixture earns its indirection by owning setup/teardown (`yield` + cleanup — `insert_metrics` truncating on teardown) or by provisioning a resource (containers, SigNoz instances). A stateless action or lookup (`create_saved_view`, `find_saved_view_by_name`, wiping a resource list) is a plain importable function in the matching `tests/fixtures/` module, taking `signoz`/`token` as ordinary arguments — never wrap a plain callable in a fixture-factory just to inject `signoz`.
- **Fixtures own their cleanup.** When a test needs seeded state, put the seed + cleanup pair in a fixture (`yield`, then tear down) so tests in the same suite don't interfere — the pattern `insert_metrics` sets: yield a callable, truncate on teardown.
- **Fixture-factory over indirect parametrization.** A fixture that yields a callable (e.g. `insert_metrics(metrics)`) is clearer than `@pytest.mark.parametrize(..., indirect=True)` + `request.param` — the value is an explicit argument, not resolved by magic.
- **Skip at collection, not inside the test body.** Use `pytest.param(..., marks=pytest.mark.skip(reason="…"))` so a skipped case shows as SKIPPED-with-reason **and** short-circuits before its fixtures run (no environment spin-up for a test that won't execute).

View File

@@ -34,9 +34,6 @@ pytest_plugins = [
"fixtures.role",
"fixtures.savedview",
"fixtures.seed_golden_dataset",
"fixtures.dashboards",
"fixtures.inframonitoring",
"fixtures.querier",
]

View File

@@ -1,7 +1,5 @@
from collections.abc import Callable
from http import HTTPStatus
import pytest
import requests
from fixtures import types
@@ -12,25 +10,21 @@ DASHBOARDS_BASE_URL = "/api/v2/dashboards"
MAX_LIST_LIMIT = 200
@pytest.fixture(name="wipe_all_dashboards", scope="function")
def wipe_all_dashboards(signoz: types.SigNoz) -> Callable[[str], None]:
def _wipe_all_dashboards(token: str) -> None:
while True:
response = requests.get(
signoz.self.host_configs["8080"].get(f"{DASHBOARDS_BASE_URL}?limit={MAX_LIST_LIMIT}"),
def delete_all_dashboards(signoz: types.SigNoz, token: str) -> None:
while True:
response = requests.get(
signoz.self.host_configs["8080"].get(f"{DASHBOARDS_BASE_URL}?limit={MAX_LIST_LIMIT}"),
headers={"Authorization": f"Bearer {token}"},
timeout=5,
)
assert response.status_code == HTTPStatus.OK, response.text
dashboards = response.json()["data"]["dashboards"]
if not dashboards:
return
for dashboard in dashboards:
del_res = requests.delete(
signoz.self.host_configs["8080"].get(f"{DASHBOARDS_BASE_URL}/{dashboard['id']}"),
headers={"Authorization": f"Bearer {token}"},
timeout=5,
)
assert response.status_code == HTTPStatus.OK, response.text
dashboards = response.json()["data"]["dashboards"]
if not dashboards:
return
for dashboard in dashboards:
del_res = requests.delete(
signoz.self.host_configs["8080"].get(f"{DASHBOARDS_BASE_URL}/{dashboard['id']}"),
headers={"Authorization": f"Bearer {token}"},
timeout=5,
)
assert del_res.status_code == HTTPStatus.NO_CONTENT, del_res.text
return _wipe_all_dashboards
assert del_res.status_code == HTTPStatus.NO_CONTENT, del_res.text

View File

@@ -1,15 +1,3 @@
import json
from collections.abc import Callable
from datetime import datetime
import pytest
from fixtures.fs import get_testdata_file_path
from fixtures.metrics import Metrics
from fixtures.time import parse_timestamp
START_TIME_PLACEHOLDER = "__START_TIME__"
# All 18 PodCountsByStatus buckets (camelCase, matches inframonitoringtypes.PodCountsByStatus / the API response).
STATUS_BUCKETS = (
"pending",
@@ -60,45 +48,3 @@ def expected_status_counts(**nonzero: int) -> dict:
counts = {bucket: 0 for bucket in STATUS_BUCKETS}
counts.update(nonzero)
return counts
@pytest.fixture(name="load_pods_metrics", scope="function")
def load_pods_metrics() -> Callable[..., list[Metrics]]:
"""Load pod metrics JSONL with optional k8s.pod.start_time substitution.
Mirrors Metrics.load_from_file's base_time rebase logic but adds a hook
for the start_time label. Lines carrying ``k8s.pod.start_time =
__START_TIME__`` get rewritten to ``start_time.isoformat()`` before
construction, ensuring podAge is deterministic across runs.
"""
def _load_pods_metrics(
file_relpath: str,
base_time: datetime,
start_time: datetime | None = None,
) -> list[Metrics]:
path = get_testdata_file_path(file_relpath)
start_time_iso = start_time.isoformat() if start_time else None
rows = []
with open(path, encoding="utf-8") as f:
for line in f:
line = line.strip()
if not line:
continue
data = json.loads(line)
labels = data.get("labels", {})
if start_time_iso and labels.get("k8s.pod.start_time") == START_TIME_PLACEHOLDER:
labels["k8s.pod.start_time"] = start_time_iso
rows.append(data)
if not rows:
return []
earliest = min(parse_timestamp(r["timestamp"]) for r in rows)
offset = base_time - earliest
metrics = []
for r in rows:
ts = parse_timestamp(r["timestamp"]) + offset
r["timestamp"] = ts.isoformat()
metrics.append(Metrics.from_dict(r))
return metrics
return _load_pods_metrics

View File

@@ -374,6 +374,7 @@ class Metrics(ABC):
file_path: str,
base_time: datetime.datetime | None = None,
metric_name_override: str | None = None,
label_substitutions: dict[str, str] | None = None,
) -> list["Metrics"]:
"""
Load metrics from a JSONL file.
@@ -385,6 +386,9 @@ class Metrics(ABC):
base_time: If provided, all timestamps are shifted so the earliest
timestamp in the file maps to base_time
metric_name_override: If provided, overrides metric_name for all metrics
label_substitutions: If provided, any label whose value equals a key is
rewritten to that key's value (placeholder substitution,
e.g. {"__START_TIME__": start_time.isoformat()})
"""
data_list = []
with open(file_path, encoding="utf-8") as f:
@@ -392,7 +396,13 @@ class Metrics(ABC):
line = line.strip()
if not line:
continue
data_list.append(json.loads(line))
data = json.loads(line)
if label_substitutions:
labels = data.get("labels", {})
for key, value in labels.items():
if value in label_substitutions:
labels[key] = label_substitutions[value]
data_list.append(data)
if not data_list:
return []

View File

@@ -1,10 +1,8 @@
from collections.abc import Callable
from dataclasses import dataclass
from datetime import UTC, datetime, timedelta
from http import HTTPStatus
from typing import Any
import pytest
import requests
from fixtures import types
@@ -1113,49 +1111,45 @@ def make_scalar_query_request(
)
@pytest.fixture(name="run_query_case", scope="function")
def run_query_case(signoz: types.SigNoz) -> Callable[[str, datetime, dict[str, Any]], None]:
def _run_query_case(token: str, now: datetime, case: dict[str, Any]) -> None:
start_ms = case.get("startMs", int((now - timedelta(seconds=10)).timestamp() * 1000))
end_ms = case.get("endMs", int(now.timestamp() * 1000))
def run_query_case(signoz: types.SigNoz, token: str, now: datetime, case: dict[str, Any]) -> None:
start_ms = case.get("startMs", int((now - timedelta(seconds=10)).timestamp() * 1000))
end_ms = case.get("endMs", int(now.timestamp() * 1000))
if case["requestType"] == "raw":
query = build_raw_query(
name=case["name"],
signal="logs",
filter_expression=case.get("expression"),
order=case.get("order") or [build_order_by("timestamp", "desc")],
limit=case.get("limit", 100),
step_interval=case.get("stepInterval") or 60,
)
else:
aggregation = case.get("aggregation")
if aggregation and not isinstance(aggregation, list):
aggregations = [build_aggregation(aggregation)]
elif aggregation:
aggregations = aggregation
else:
aggregations = []
query = build_scalar_query(
name=case["name"],
signal="logs",
aggregations=aggregations,
group_by=case.get("groupBy"),
order=case.get("order"),
limit=case.get("limit", 100),
filter_expression=case.get("expression"),
step_interval=case.get("stepInterval") or 60,
)
response = make_query_request(
signoz=signoz,
token=token,
start_ms=start_ms,
end_ms=end_ms,
queries=[query],
request_type=case["requestType"],
if case["requestType"] == "raw":
query = build_raw_query(
name=case["name"],
signal="logs",
filter_expression=case.get("expression"),
order=case.get("order") or [build_order_by("timestamp", "desc")],
limit=case.get("limit", 100),
step_interval=case.get("stepInterval") or 60,
)
else:
aggregation = case.get("aggregation")
if aggregation and not isinstance(aggregation, list):
aggregations = [build_aggregation(aggregation)]
elif aggregation:
aggregations = aggregation
else:
aggregations = []
query = build_scalar_query(
name=case["name"],
signal="logs",
aggregations=aggregations,
group_by=case.get("groupBy"),
order=case.get("order"),
limit=case.get("limit", 100),
filter_expression=case.get("expression"),
step_interval=case.get("stepInterval") or 60,
)
assert response.status_code == 200, f"HTTP {response.status_code} for case '{case['name']}': {response.text}"
assert case["validate"](response), f"Validation failed for case '{case['name']}': {response.json()}"
return _run_query_case
response = make_query_request(
signoz=signoz,
token=token,
start_ms=start_ms,
end_ms=end_ms,
queries=[query],
request_type=case["requestType"],
)
assert response.status_code == 200, f"HTTP {response.status_code} for case '{case['name']}': {response.text}"
assert case["validate"](response), f"Validation failed for case '{case['name']}': {response.json()}"

View File

@@ -6,6 +6,7 @@ import pytest
import requests
from fixtures.auth import USER_ADMIN_EMAIL, USER_ADMIN_PASSWORD
from fixtures.dashboards import delete_all_dashboards
from fixtures.metrics import Metrics
from fixtures.types import Operation, SigNoz
@@ -602,7 +603,6 @@ def test_dashboard_v2_lifecycle( # pylint: disable=too-many-locals,too-many-sta
signoz: SigNoz,
create_user_admin: Operation, # pylint: disable=unused-argument
get_token: Callable[[str, str], str],
wipe_all_dashboards: Callable[[str], None],
):
token = get_token(USER_ADMIN_EMAIL, USER_ADMIN_PASSWORD)
@@ -610,7 +610,7 @@ def test_dashboard_v2_lifecycle( # pylint: disable=too-many-locals,too-many-sta
# runs, so start from a clean slate: delete every dashboard (which also clears
# pins via the delete cascade). This test then owns the whole dashboard space
# and asserts on global counts.
wipe_all_dashboards(token)
delete_all_dashboards(signoz, token)
dashboard_requests = [
(
@@ -1247,7 +1247,6 @@ def test_dashboard_v2_pin_limit(
signoz: SigNoz,
create_user_admin: Operation, # pylint: disable=unused-argument
get_token: Callable[[str, str], str],
wipe_all_dashboards: Callable[[str], None],
):
max_pinned = 10
@@ -1255,7 +1254,7 @@ def test_dashboard_v2_pin_limit(
# Wipe the dashboard space (see lifecycle) so the per-user pin cap this test
# asserts against starts empty — deleting dashboards clears their pins.
wipe_all_dashboards(token)
delete_all_dashboards(signoz, token)
ids: list[str] = []
for i in range(max_pinned + 1):
@@ -1343,13 +1342,12 @@ def test_dashboard_v2_like_escaping(
signoz: SigNoz,
create_user_admin: Operation, # pylint: disable=unused-argument
get_token: Callable[[str, str], str],
wipe_all_dashboards: Callable[[str], None],
):
token = get_token(USER_ADMIN_EMAIL, USER_ADMIN_PASSWORD)
# Wipe the dashboard space (see lifecycle) so the filter assertions run
# against only the dashboards this test creates.
wipe_all_dashboards(token)
delete_all_dashboards(signoz, token)
dashboard_requests = [
("esc-pct", "Cost 50% Report"),
@@ -1420,7 +1418,6 @@ def test_dashboard_v2_get_by_metric_name(
create_user_admin: Operation, # pylint: disable=unused-argument
get_token: Callable[[str, str], str],
insert_metrics: Callable[[list[Metrics]], None],
wipe_all_dashboards: Callable[[str], None],
) -> None:
"""The v3 endpoint shortlists dashboards via a coarse data prefilter, then
confirms matches by parsing the typed v2 panels. It must find the metric in
@@ -1428,7 +1425,7 @@ def test_dashboard_v2_get_by_metric_name(
the metric appears only in panel names (the prefilter matches but the parse
rejects it)."""
token = get_token(USER_ADMIN_EMAIL, USER_ADMIN_PASSWORD)
wipe_all_dashboards(token)
delete_all_dashboards(signoz, token)
target_metric = "system.network.dropped"
decoy_metric = "system.network.io"

View File

@@ -9,11 +9,14 @@ from fixtures import types
from fixtures.auth import USER_ADMIN_EMAIL, USER_ADMIN_PASSWORD
from fixtures.fs import get_testdata_file_path
from fixtures.inframonitoring import STATUS_BUCKETS, STATUS_TO_BUCKET
from fixtures.metrics import Metrics
from fixtures.querier import compare_values, get_all_warnings
ENDPOINT = "/api/v2/infra_monitoring/pods"
# Placeholder in JSONL labels that gets substituted with a runtime ISO string.
# Placeholder in JSONL labels that gets substituted with a runtime ISO string,
# keeping podAge deterministic across runs.
START_TIME_PLACEHOLDER = "__START_TIME__"
def test_pods_accuracy(
@@ -21,7 +24,6 @@ def test_pods_accuracy(
create_user_admin: None, # pylint: disable=unused-argument
get_token,
insert_metrics,
load_pods_metrics,
) -> None:
"""Seed 2 pods x 7 metrics; assert response shape/contract + exact per-pod
metric values, podAge, and podCountsByStatus against precomputed expected
@@ -29,10 +31,10 @@ def test_pods_accuracy(
now = datetime.now(tz=UTC).replace(microsecond=0)
start_time = now - timedelta(minutes=10)
insert_metrics(
load_pods_metrics(
"inframonitoring/pods_value_accuracy.jsonl",
Metrics.load_from_file(
get_testdata_file_path("inframonitoring/pods_value_accuracy.jsonl"),
base_time=now - timedelta(minutes=4),
start_time=start_time,
label_substitutions={START_TIME_PLACEHOLDER: start_time.isoformat()},
)
)
@@ -150,7 +152,6 @@ def test_pods_warnings(
create_user_admin: None, # pylint: disable=unused-argument
get_token,
insert_metrics,
load_pods_metrics,
case: dict,
) -> None:
"""A never-ingested metric surfaces a non-blocking warning (200 + data), not a
@@ -160,8 +161,8 @@ def test_pods_warnings(
once, for hosts, in 01_hosts.py.)"""
now = datetime.now(tz=UTC).replace(microsecond=0)
insert_metrics(
load_pods_metrics(
f"inframonitoring/{case['dataset']}",
Metrics.load_from_file(
get_testdata_file_path(f"inframonitoring/{case['dataset']}"),
base_time=now - timedelta(minutes=4),
)
)
@@ -249,7 +250,6 @@ def test_pods_filter(
create_user_admin: None, # pylint: disable=unused-argument
get_token,
insert_metrics,
load_pods_metrics,
expression: str,
expected_pods: set,
) -> None:
@@ -269,8 +269,8 @@ def test_pods_filter(
}
now = datetime.now(tz=UTC).replace(microsecond=0)
insert_metrics(
load_pods_metrics(
"inframonitoring/pods_filter_dataset.jsonl",
Metrics.load_from_file(
get_testdata_file_path("inframonitoring/pods_filter_dataset.jsonl"),
base_time=now - timedelta(minutes=4),
)
)
@@ -310,7 +310,6 @@ def test_pods_filter_invalid(
create_user_admin: None, # pylint: disable=unused-argument
get_token,
insert_metrics,
load_pods_metrics,
expression: str,
err_substr,
) -> None:
@@ -318,8 +317,8 @@ def test_pods_filter_invalid(
400 invalid_input with structured errors."""
now = datetime.now(tz=UTC).replace(microsecond=0)
insert_metrics(
load_pods_metrics(
"inframonitoring/pods_filter_dataset.jsonl",
Metrics.load_from_file(
get_testdata_file_path("inframonitoring/pods_filter_dataset.jsonl"),
base_time=now - timedelta(minutes=4),
)
)
@@ -357,7 +356,6 @@ def test_pods_groupby(
create_user_admin: None, # pylint: disable=unused-argument
get_token,
insert_metrics,
load_pods_metrics,
group_key: str,
expected_groups: set,
) -> None:
@@ -367,8 +365,8 @@ def test_pods_groupby(
"""
now = datetime.now(tz=UTC).replace(microsecond=0)
insert_metrics(
load_pods_metrics(
"inframonitoring/pods_groupby.jsonl",
Metrics.load_from_file(
get_testdata_file_path("inframonitoring/pods_groupby.jsonl"),
base_time=now - timedelta(minutes=4),
)
)
@@ -412,15 +410,14 @@ def test_pods_pagination(
create_user_admin: None, # pylint: disable=unused-argument
get_token,
insert_metrics,
load_pods_metrics,
) -> None:
"""Pagination: per-page len matches min(limit, total-offset), total invariant,
pages cover the full set with no overlap. The final offset is beyond total:
it returns empty records while total still reflects dataset size."""
now = datetime.now(tz=UTC).replace(microsecond=0)
insert_metrics(
load_pods_metrics(
"inframonitoring/pods_pagination.jsonl",
Metrics.load_from_file(
get_testdata_file_path("inframonitoring/pods_pagination.jsonl"),
base_time=now - timedelta(minutes=4),
)
)
@@ -475,7 +472,6 @@ def test_pods_orderby( # pylint: disable=too-many-arguments,too-many-positional
create_user_admin: None, # pylint: disable=unused-argument
get_token,
insert_metrics,
load_pods_metrics,
column: str,
record_field,
direction: str,
@@ -484,8 +480,8 @@ def test_pods_orderby( # pylint: disable=too-many-arguments,too-many-positional
sort) and records come back sorted by the requested column."""
now = datetime.now(tz=UTC).replace(microsecond=0)
insert_metrics(
load_pods_metrics(
"inframonitoring/pods_orderby.jsonl",
Metrics.load_from_file(
get_testdata_file_path("inframonitoring/pods_orderby.jsonl"),
base_time=now - timedelta(minutes=4),
)
)
@@ -610,7 +606,6 @@ def test_pods_status_list_mode(
create_user_admin: None, # pylint: disable=unused-argument
get_token,
insert_metrics,
load_pods_metrics,
pod_name: str,
expected_status: str,
) -> None:
@@ -631,8 +626,8 @@ def test_pods_status_list_mode(
"""
now = datetime.now(tz=UTC).replace(microsecond=0)
insert_metrics(
load_pods_metrics(
"inframonitoring/pods_phases.jsonl",
Metrics.load_from_file(
get_testdata_file_path("inframonitoring/pods_phases.jsonl"),
base_time=now - timedelta(minutes=4),
)
)
@@ -679,7 +674,6 @@ def test_pods_restarts_list_mode(
create_user_admin: None, # pylint: disable=unused-argument
get_token,
insert_metrics,
load_pods_metrics,
pod_name: str,
expected_restarts: int,
) -> None:
@@ -688,8 +682,8 @@ def test_pods_restarts_list_mode(
series -> -1 no-data sentinel (kubectl would show 0)."""
now = datetime.now(tz=UTC).replace(microsecond=0)
insert_metrics(
load_pods_metrics(
"inframonitoring/pods_phases.jsonl",
Metrics.load_from_file(
get_testdata_file_path("inframonitoring/pods_phases.jsonl"),
base_time=now - timedelta(minutes=4),
)
)
@@ -719,7 +713,6 @@ def test_pods_status_latest_wins(
create_user_admin: None, # pylint: disable=unused-argument
get_token,
insert_metrics,
load_pods_metrics,
) -> None:
"""A stale container reason from an old incarnation must not win. trans-p's
first incarnation (container.id=aaa) reported CrashLoopBackOff, then it
@@ -728,8 +721,8 @@ def test_pods_status_latest_wins(
ignored via argMax-by-latest-timestamp per (pod, container, reason)."""
now = datetime.now(tz=UTC).replace(microsecond=0)
insert_metrics(
load_pods_metrics(
"inframonitoring/pods_phases_transition.jsonl",
Metrics.load_from_file(
get_testdata_file_path("inframonitoring/pods_phases_transition.jsonl"),
base_time=now - timedelta(minutes=8),
)
)
@@ -758,7 +751,6 @@ def test_pods_restarts_latest_wins(
create_user_admin: None, # pylint: disable=unused-argument
get_token,
insert_metrics,
load_pods_metrics,
) -> None:
"""restartCount is cumulative per container. Across incarnations
(container.id=aaa reported 1, then container.id=bbb reported 5) podRestarts
@@ -766,8 +758,8 @@ def test_pods_restarts_latest_wins(
not be double-counted."""
now = datetime.now(tz=UTC).replace(microsecond=0)
insert_metrics(
load_pods_metrics(
"inframonitoring/pods_phases_transition.jsonl",
Metrics.load_from_file(
get_testdata_file_path("inframonitoring/pods_phases_transition.jsonl"),
base_time=now - timedelta(minutes=8),
)
)
@@ -796,7 +788,6 @@ def test_pods_status_grouped_mode(
create_user_admin: None, # pylint: disable=unused-argument
get_token,
insert_metrics,
load_pods_metrics,
) -> None:
"""groupBy=[k8s.namespace.name] aggregates each pod's display status across
ns-mixed. podStatus is no-data (no single pod identifies the group). Seeded
@@ -804,8 +795,8 @@ def test_pods_status_grouped_mode(
g-fail-1 Error, g-fail-2 Evicted, g-pend-1 Pending."""
now = datetime.now(tz=UTC).replace(microsecond=0)
insert_metrics(
load_pods_metrics(
"inframonitoring/pods_phases_grouped.jsonl",
Metrics.load_from_file(
get_testdata_file_path("inframonitoring/pods_phases_grouped.jsonl"),
base_time=now - timedelta(minutes=4),
)
)
@@ -853,14 +844,13 @@ def test_pods_restarts_grouped_mode(
create_user_admin: None, # pylint: disable=unused-argument
get_token,
insert_metrics,
load_pods_metrics,
) -> None:
"""Grouped podRestarts is the sum of restarts across all pods in the group.
In ns-mixed only g-run-2 has restarts (3); all others 0 -> group total 3."""
now = datetime.now(tz=UTC).replace(microsecond=0)
insert_metrics(
load_pods_metrics(
"inframonitoring/pods_phases_grouped.jsonl",
Metrics.load_from_file(
get_testdata_file_path("inframonitoring/pods_phases_grouped.jsonl"),
base_time=now - timedelta(minutes=4),
)
)
@@ -896,7 +886,6 @@ def test_pods_status_missing_metric_warning(
create_user_admin: None, # pylint: disable=unused-argument
get_token,
insert_metrics,
load_pods_metrics,
) -> None:
"""When the status metrics were never ingested, the status query is gated
off: a warning naming the missing metric(s) is surfaced, podStatus is the
@@ -904,8 +893,8 @@ def test_pods_status_missing_metric_warning(
seeds only k8s.pod.cpu.usage.)"""
now = datetime.now(tz=UTC).replace(microsecond=0)
insert_metrics(
load_pods_metrics(
"inframonitoring/pods_missing_metrics.jsonl",
Metrics.load_from_file(
get_testdata_file_path("inframonitoring/pods_missing_metrics.jsonl"),
base_time=now - timedelta(minutes=4),
)
)

View File

@@ -15,6 +15,7 @@ from fixtures.querier import (
get_rows,
get_scalar_table_data,
make_query_request,
run_query_case,
)
# ============================================================================
@@ -37,11 +38,11 @@ from fixtures.querier import (
def test_primitive_path_operations(
signoz: types.SigNoz,
create_user_admin: None, # pylint: disable=unused-argument
get_token: Callable[[str, str], str],
insert_logs: Callable[[list[Logs]], None],
export_json_types: Callable[[list[Logs]], None],
run_query_case: Callable[[str, datetime, dict[str, Any]], None],
) -> None:
now = datetime.now(tz=UTC)
@@ -323,7 +324,7 @@ def test_primitive_path_operations(
for case in cases:
case.setdefault("groupBy", None)
case.setdefault("stepInterval", None)
run_query_case(token, now, case)
run_query_case(signoz, token, now, case)
# ============================================================================
@@ -335,13 +336,13 @@ def test_primitive_path_operations(
def test_indexed_paths(
signoz: types.SigNoz,
create_user_admin: None, # pylint: disable=unused-argument
get_token: Callable[[str, str], str],
insert_logs: Callable[[list[Logs]], None],
export_json_types: Callable[[list[Logs]], None],
create_json_index: Callable[[str, list[dict[str, Any]]], None],
check_query_log: Callable[[datetime, str, Callable[[str], bool]], None],
run_query_case: Callable[[str, datetime, dict[str, Any]], None],
) -> None:
now = datetime.now(tz=UTC)
@@ -494,7 +495,7 @@ def test_indexed_paths(
case.setdefault("groupBy", None)
case.setdefault("stepInterval", None)
before = datetime.now(tz=UTC)
run_query_case(token, now, case)
run_query_case(signoz, token, now, case)
if "check_query" in case:
check_query_log(
before,
@@ -665,11 +666,11 @@ def test_select_order_by(
def test_array_path_operations(
signoz: types.SigNoz,
create_user_admin: None, # pylint: disable=unused-argument
get_token: Callable[[str, str], str],
insert_logs: Callable[[list[Logs]], None],
export_json_types: Callable[[list[Logs]], None],
run_query_case: Callable[[str, datetime, dict[str, Any]], None],
) -> None:
now = datetime.now(tz=UTC)
@@ -939,7 +940,7 @@ def test_array_path_operations(
for case in cases:
case.setdefault("groupBy", None)
case.setdefault("stepInterval", None)
run_query_case(token, now, case)
run_query_case(signoz, token, now, case)
# ============================================================================
@@ -948,11 +949,11 @@ def test_array_path_operations(
def test_array_membership_operations(
signoz: types.SigNoz,
create_user_admin: None, # pylint: disable=unused-argument
get_token: Callable[[str, str], str],
insert_logs: Callable[[list[Logs]], None],
export_json_types: Callable[[list[Logs]], None],
run_query_case: Callable[[str, datetime, dict[str, Any]], None],
) -> None:
now = datetime.now(tz=UTC)
@@ -1085,7 +1086,7 @@ def test_array_membership_operations(
for case in cases:
case.setdefault("groupBy", None)
case.setdefault("stepInterval", None)
run_query_case(token, now, case)
run_query_case(signoz, token, now, case)
# ============================================================================
@@ -1094,11 +1095,11 @@ def test_array_membership_operations(
def test_message_searches(
signoz: types.SigNoz,
create_user_admin: None, # pylint: disable=unused-argument
get_token: Callable[[str, str], str],
insert_logs: Callable[[list[Logs]], None],
export_json_types: Callable[[list[Logs]], None],
run_query_case: Callable[[str, datetime, dict[str, Any]], None],
) -> None:
now = datetime.now(tz=UTC)
@@ -1215,7 +1216,7 @@ def test_message_searches(
for case in cases:
case.setdefault("groupBy", None)
case.setdefault("stepInterval", None)
run_query_case(token, now, case)
run_query_case(signoz, token, now, case)
# ============================================================================
@@ -1224,11 +1225,11 @@ def test_message_searches(
def test_polluted_data(
signoz: types.SigNoz,
create_user_admin: None, # pylint: disable=unused-argument
get_token: Callable[[str, str], str],
insert_logs: Callable[[list[Logs]], None],
export_json_types: Callable[[list[Logs]], None],
run_query_case: Callable[[str, datetime, dict[str, Any]], None],
) -> None:
now = datetime.now(tz=UTC)
@@ -1342,7 +1343,7 @@ def test_polluted_data(
for case in cases:
case.setdefault("groupBy", None)
case.setdefault("stepInterval", None)
run_query_case(token, now, case)
run_query_case(signoz, token, now, case)
# ============================================================================
@@ -1365,11 +1366,11 @@ def test_polluted_data(
def test_groupby_scalar(
signoz: types.SigNoz,
create_user_admin: None, # pylint: disable=unused-argument
get_token: Callable[[str, str], str],
insert_logs: Callable[[list[Logs]], None],
export_json_types: Callable[[list[Logs]], None],
run_query_case: Callable[[str, datetime, dict[str, Any]], None],
) -> None:
now = datetime.now(tz=UTC)
@@ -1429,4 +1430,4 @@ def test_groupby_scalar(
]
for case in cases:
run_query_case(token, now, case)
run_query_case(signoz, token, now, case)