4b6817381b
Benchmark image — build + push to ECR (any adapter) / build + push (push) Waiting to run
CI / quality (ubuntu-latest) (push) Waiting to run
CI / test (tools-runtime) (push) Waiting to run
CI / test (e2e-general) (push) Waiting to run
CI / test (cli-runtime) (push) Waiting to run
CI / test (e2e-provider-and-openclaw) (push) Waiting to run
CI / test (integrations-and-misc) (push) Waiting to run
CI / coverage-report (push) Blocked by required conditions
CI / test-kubernetes (push) Waiting to run
CI / should-run-thorough (push) Waiting to run
CI / test-thorough (cloudwatch-demo) (push) Blocked by required conditions
CI / test-thorough (flink-ecs) (push) Blocked by required conditions
CI / test-thorough (upstream-lambda) (push) Blocked by required conditions
CI / test-thorough (prefect-ecs-fargate) (push) Blocked by required conditions
CodeQL / Analyze (python) (push) Waiting to run
Release / build-binaries (zip, opensre.exe, onefile, windows-latest, windows-x64) (push) Blocked by required conditions
Release / publish-release (push) Blocked by required conditions
Release / publish-main-release (push) Blocked by required conditions
Release / prepare (push) Waiting to run
Release / verify (push) Blocked by required conditions
Release / build-python-dist (push) Blocked by required conditions
Release / build-binaries (tar.gz, opensre, onedir, macos-15-intel, darwin-x64) (push) Blocked by required conditions
Release / build-binaries (tar.gz, opensre, onedir, macos-latest, darwin-arm64) (push) Blocked by required conditions
Release / build-binaries (tar.gz, opensre, onedir, ubuntu-22.04, linux-x64) (push) Blocked by required conditions
Release / build-binaries (tar.gz, opensre, onedir, ubuntu-22.04-arm, linux-arm64) (push) Blocked by required conditions
Synthetic Deterministic Tests / Synthetic offline (deterministic) (push) Waiting to run
Interactive Shell Live (PR + post-merge) / turn-checks (no-LLM) (push) Waiting to run
Interactive Shell Live (PR + post-merge) / turn-live shard ${{ matrix.shard_index }} (push) Waiting to run
CI (OpenClaw E2E) / openclaw test (push) Has been cancelled
181 lines
6.1 KiB
Python
181 lines
6.1 KiB
Python
"""Tests for evidence compaction utilities."""
|
|
|
|
from __future__ import annotations
|
|
|
|
from platform.common.evidence_compaction import (
|
|
DEFAULT_LOG_LIMIT,
|
|
DEFAULT_MESSAGE_CHARS,
|
|
compact_invocations,
|
|
compact_logs,
|
|
compact_metrics,
|
|
compact_traces,
|
|
summarize_counts,
|
|
truncate_list,
|
|
truncate_log_entry,
|
|
truncate_message,
|
|
)
|
|
|
|
|
|
class TestTruncateList:
|
|
def test_truncate_list_with_explicit_limit(self) -> None:
|
|
items = [1, 2, 3, 4, 5]
|
|
result = truncate_list(items, limit=3)
|
|
assert result == [1, 2, 3]
|
|
|
|
def test_truncate_list_with_default_limit(self) -> None:
|
|
items = list(range(100))
|
|
result = truncate_list(items, limit=None)
|
|
assert len(result) == DEFAULT_LOG_LIMIT
|
|
|
|
def test_truncate_list_no_truncation_needed(self) -> None:
|
|
items = [1, 2, 3]
|
|
result = truncate_list(items, limit=10)
|
|
assert result == [1, 2, 3]
|
|
|
|
def test_truncate_list_empty(self) -> None:
|
|
result = truncate_list([], limit=10)
|
|
assert result == []
|
|
|
|
|
|
class TestTruncateMessage:
|
|
def test_truncate_message_short(self) -> None:
|
|
msg = "short message"
|
|
result = truncate_message(msg, max_chars=100)
|
|
assert result == msg
|
|
|
|
def test_truncate_message_long(self) -> None:
|
|
msg = "a" * 2000
|
|
result = truncate_message(msg, max_chars=100)
|
|
assert result.endswith("...")
|
|
assert len(result) == 100
|
|
|
|
def test_truncate_message_exact_limit(self) -> None:
|
|
msg = "a" * 100
|
|
result = truncate_message(msg, max_chars=100)
|
|
assert result == msg
|
|
|
|
|
|
class TestTruncateLogEntry:
|
|
def test_truncate_log_entry_message(self) -> None:
|
|
log = {"message": "a" * 2000, "timestamp": "2024-01-01"}
|
|
result = truncate_log_entry(log)
|
|
assert result["message"].endswith("...")
|
|
assert len(result["message"]) == DEFAULT_MESSAGE_CHARS
|
|
assert result["timestamp"] == "2024-01-01"
|
|
|
|
def test_truncate_log_entry_no_message(self) -> None:
|
|
log = {"timestamp": "2024-01-01", "level": "INFO"}
|
|
result = truncate_log_entry(log)
|
|
assert result == log
|
|
|
|
def test_truncate_log_entry_non_dict(self) -> None:
|
|
log = "not a dict"
|
|
result = truncate_log_entry(log) # type: ignore
|
|
assert result == log
|
|
|
|
|
|
class TestCompactLogs:
|
|
def test_compact_logs_truncates_list(self) -> None:
|
|
logs = [{"message": f"log {i}"} for i in range(100)]
|
|
result = compact_logs(logs, limit=10)
|
|
assert len(result) == 10
|
|
|
|
def test_compact_logs_truncates_messages(self) -> None:
|
|
logs = [{"message": "a" * 5000}]
|
|
result = compact_logs(logs)
|
|
assert result[0]["message"].endswith("...")
|
|
|
|
def test_compact_logs_empty(self) -> None:
|
|
result = compact_logs([])
|
|
assert result == []
|
|
|
|
|
|
class TestCompactTraces:
|
|
def test_compact_traces_truncates_list(self) -> None:
|
|
traces = [{"id": i} for i in range(50)]
|
|
result = compact_traces(traces, limit=10)
|
|
assert len(result) == 10
|
|
|
|
def test_compact_traces_limits_spans(self) -> None:
|
|
trace = {"id": 1, "spans": [{"name": f"span {i}"} for i in range(100)]}
|
|
result = compact_traces([trace], limit=1, max_spans_per_trace=20)
|
|
assert len(result[0]["spans"]) == 20
|
|
assert result[0].get("span_count_total") == 100
|
|
|
|
def test_compact_traces_no_spans(self) -> None:
|
|
trace = {"id": 1}
|
|
result = compact_traces([trace], limit=1)
|
|
assert result[0] == trace
|
|
|
|
|
|
class TestCompactMetrics:
|
|
def test_compact_metrics_truncates_list(self) -> None:
|
|
metrics = [{"name": f"metric {i}"} for i in range(100)]
|
|
result = compact_metrics(metrics, limit=10)
|
|
assert len(result) == 10
|
|
|
|
def test_compact_metrics_limits_datapoints(self) -> None:
|
|
metric = {
|
|
"name": "cpu",
|
|
"datapoints": [{"value": i} for i in range(100)],
|
|
}
|
|
result = compact_metrics([metric], limit=1, max_datapoints=20)
|
|
assert len(result[0]["datapoints"]) == 20
|
|
assert result[0].get("datapoints_total") == 100
|
|
|
|
def test_compact_metrics_limits_values(self) -> None:
|
|
metric = {
|
|
"name": "cpu",
|
|
"values": [{"value": i} for i in range(100)],
|
|
}
|
|
result = compact_metrics([metric], limit=1, max_datapoints=20)
|
|
assert len(result[0]["values"]) == 20
|
|
|
|
|
|
class TestCompactInvocations:
|
|
def test_compact_invocations_truncates_list(self) -> None:
|
|
invocations = [{"request_id": f"req-{i}"} for i in range(100)]
|
|
result = compact_invocations(invocations, limit=10)
|
|
assert len(result) == 10
|
|
|
|
def test_compact_invocations_limits_logs(self) -> None:
|
|
invocation = {
|
|
"request_id": "req-1",
|
|
"logs": [{"message": f"log {i}"} for i in range(50)],
|
|
}
|
|
result = compact_invocations([invocation], limit=1, max_logs_per_invocation=10)
|
|
assert len(result[0]["logs"]) == 10
|
|
assert result[0].get("log_count_total") == 50
|
|
|
|
|
|
class TestSummarizeCounts:
|
|
def test_summarize_counts_truncated(self) -> None:
|
|
result = summarize_counts(100, 50, "logs")
|
|
assert result == "Showing 50 of 100 logs"
|
|
|
|
def test_summarize_counts_not_truncated(self) -> None:
|
|
result = summarize_counts(50, 50, "logs")
|
|
assert result is None
|
|
|
|
def test_summarize_counts_less_than_limit(self) -> None:
|
|
result = summarize_counts(30, 50, "logs")
|
|
assert result is None
|
|
|
|
|
|
class TestConstants:
|
|
def test_default_limits_are_reasonable(self) -> None:
|
|
"""Ensure default limits prevent prompt overflow while preserving useful data."""
|
|
from platform.common.evidence_compaction import (
|
|
DEFAULT_ERROR_LOG_LIMIT,
|
|
DEFAULT_LOG_LIMIT,
|
|
DEFAULT_MESSAGE_CHARS,
|
|
DEFAULT_METRICS_LIMIT,
|
|
DEFAULT_TRACE_LIMIT,
|
|
)
|
|
|
|
assert DEFAULT_LOG_LIMIT <= 100 # Prevent overwhelming logs
|
|
assert DEFAULT_ERROR_LOG_LIMIT <= DEFAULT_LOG_LIMIT # Errors subset of logs
|
|
assert DEFAULT_TRACE_LIMIT <= 50 # Traces are larger
|
|
assert DEFAULT_METRICS_LIMIT <= 100 # Metrics can be numerous
|
|
assert DEFAULT_MESSAGE_CHARS <= 2000 # Prevent huge log messages
|