Testing is the bedrock of the SRE Agent. Because this agent performs autonomous operations on production infrastructure, its behavior must be fully verifiable, correct, and predictable.
Our philosophy is simple: If it is not tested, it is broken.
Coverage policy: 80% minimum gate enforced in CI. 100% target on all new tools and core logic. PRs that drop project coverage below 80% will be rejected.
- Shift Left: Bugs are cheapest when caught during development. Developers are responsible for their own tests.
- Test-Driven Development (TDD): Specs must be translated into tests before the code is written. For coding agents, this is a strict rule.
- 100% Path Coverage: We do not just test the "happy path." Every branch, every error condition, and every edge case must have a corresponding test.
- Deterministic behavior: Tests must be hermetic and repeatable. Use robust mocking for all external GCP APIs.
- Verifiable Correctness: Coverage is a metric, but correctness is the goal. Tests must assert on the integrity of the logic, not just that the lines were executed.
As of 2026-04-04, the project has 239 Python test files and 41 Flutter test files.
| Level | Path | Tool | Description |
|---|---|---|---|
| Behavioral | openspec/specs/ |
OpenSpec | "Source of Truth" specs defining behavior and acceptance criteria. |
| Unit | tests/unit/ |
pytest |
Isolated logic, pure functions, tool implementations with mocked clients. |
| Integration | tests/integration/ |
pytest |
Interactions between services (e.g., Session Service + DB), state management, council pipeline, auth, middleware. |
| Component | tests/sre_agent/ |
pytest |
Core engine tests (runner, policy engine, approval, graph service, prompt composer, summarizer, context compactor). |
| Server | tests/server/ |
pytest |
FastAPI endpoint tests, GenUI event streaming, cancellation, widget logic, session rename, debug UI. |
| API | tests/api/ |
pytest |
HTTP API endpoint tests (help endpoint). |
| Frontend | autosre/test/ |
flutter test |
Widget tests, layout verification, service injection testing. |
| Agent Eval | eval/ |
ADK Eval | Reasoning validation. Uses LLM-as-a-judge and trajectory scoring. |
| E2E | tests/e2e/ |
pytest |
Full agent loops, user query to final remediation plan, investigation pipelines. |
While unit tests verify the code, Agent Evaluations verify the Reasoning. We use the Vertex AI GenAI Evaluation Service to ensure the agent's logic remains correct.
We measure the accuracy of the agent's tool-selection path.
- Goal: 100% Match with the "Golden Trajectory" (Aggregate > Triage > Deep Dive).
We use gemini-1.5-pro to grade responses on:
- Technical Precision: Specificity of GCP signal evidence.
- Root Cause Causality: "Why" it happened vs just "What" happened.
- Actionability: Clear, recommended shell commands or fixes.
For implementation details, see docs/EVALUATIONS.md.
Test files must mirror the source directory structure exactly.
- Source:
sre_agent/tools/clients/trace.py - Test:
tests/unit/sre_agent/tools/clients/test_trace.py
Each test file MUST begin with a docstring explaining its purpose and the specific behavior it verifies.
"""
Goal: Verify the Cloud Trace client correctly handles EUC propagation and error states.
Patterns: Client Factory Mocking, Tool Context Simulation.
"""- Files:
test_<module_name>.py - Classes:
Test<ClassName> - Functions:
test_<function_name>_<condition>_<expected_outcome>(e.g.,test_fetch_trace_not_found_returns_error_json)
Never use live tokens or real GCP projects in unit tests. Use unittest.mock (patch, AsyncMock, MagicMock).
- Clients: Mock the factory returned from
sre_agent.tools.clients.factory. - Telemetry: Ensure
adk_toolspans are ignored or asserted on correctly. - MCP: Use
USE_MOCK_MCP=trueenvironment variable to substitute real MCP toolsets withMockMcpTool/MockMcpToolsetfromsre_agent.tools.mcp.mock_mcp. See the MCP Mocking section below.
Important
Case Study: Project Isolation in BigQueryClient
When refactoring initialization logic, ensure that project resolution does not accidentally pick up environment variables (like GOOGLE_CLOUD_PROJECT) in unit tests. Tools should use get_project_id_with_fallback() to allow tests to properly mock "no project" scenarios by patching that specific function. This avoids "leaking" real environment state into isolated unit tests.
Since our tools rely on ToolContext for session and credentials, use specialized fixtures to create mock contexts. The shared conftest.py provides a mock_tool_context fixture for this purpose.
All async tests must use the @pytest.mark.asyncio decorator:
@pytest.mark.asyncio
async def test_my_async_tool_returns_success():
"""Test that the tool returns expected data."""
result = await my_async_tool(arg="value", tool_context=mock_ctx)
assert result["status"] == "success"Tests run in parallel using pytest-xdist with automatic worker detection:
addopts = "--import-mode=importlib -n auto --dist worksteal"
This means all workers share the same test session but execute different test files concurrently using the worksteal distribution strategy. Tests must be isolated and hermetic to avoid interference between workers.
Running parallel tests with SQLite-backed session storage causes database is locked errors. The project resolves this by forcing InMemorySessionService during testing:
# In tests/conftest.py (session-scoped, autouse)
os.environ["USE_DATABASE_SESSIONS"] = "false"This session-scoped fixture runs once at the start of the entire test session and sets the environment variable so that all session management code uses InMemorySessionService instead of DatabaseSessionService. Individual integration tests that need to test database behavior explicitly set this variable themselves.
The Model Context Protocol (MCP) tools connect to real BigQuery, Cloud Logging, and Cloud Monitoring backends. For testing, the project provides a complete mock layer:
- Environment variable: Set
USE_MOCK_MCP=trueto activate mock MCP toolsets. - Mock classes:
MockMcpToolandMockMcpToolsetinsre_agent/tools/mcp/mock_mcp.py. - Supported mock tools:
list_log_entries,list_timeseries,query_range/query_promql,list_dataset_ids,list_table_ids,execute_sql,get_table_info. - Fallback behavior: When
USE_MOCK_MCP=true, the MCP GCP module (sre_agent/tools/mcp/gcp.py) returns mock toolsets instead of connecting to real MCP servers. - MCP fallback tests:
tests/unit/sre_agent/tools/clients/test_mcp_fallback.pyverifies that when MCP calls fail, the system falls back to direct API calls.
# Example: Testing with mock MCP
@pytest.mark.asyncio
async def test_mcp_tool_returns_mock_data():
tool = MockMcpTool("list_log_entries")
result = await tool.run_async({}, None)
assert "entries" in resultThe tests/fixtures/synthetic_otel_data.py module provides factory classes for generating realistic OpenTelemetry data following the Google Cloud Observability schema:
| Generator Class | Purpose |
|---|---|
SpanEventGenerator |
Creates span events (exceptions with stacktraces, log events) |
SpanLinkGenerator |
Creates span links (follows_from, batch, async) |
OtelSpanGenerator |
Creates complete OTel spans with configurable attributes (HTTP server, database, linked spans) |
TraceGenerator |
Creates complete multi-span traces (simple HTTP, fanout, async, multi-service with latency strategies) |
BigQueryResultGenerator |
Creates mock BigQuery response data (aggregate metrics, time-series, exemplar traces, exception events) |
CloudTraceAPIGenerator |
Creates mock Cloud Trace API responses (single trace, list traces) |
CloudLoggingAPIGenerator |
Creates mock Cloud Logging API responses (structured log entries, log entry lists) |
Helper functions: generate_trace_id(), generate_span_id(), generate_timestamp(), generate_random_string().
The TraceGenerator supports multiple trace topologies:
- Simple HTTP trace: Single request with optional database call and error injection
- Fanout trace: One root service calling multiple child services in parallel
- Async trace: Producer/consumer pattern with span links between disjoint traces
- Multi-service trace: Chain of services with configurable latency strategies (
normal,creep,spike)
The tests/conftest.py file provides shared resources available to all tests:
| Fixture | Description |
|---|---|
sanitize_environment |
Session-scoped autouse fixture that cleans env vars (removes GOOGLE_API_KEY, GEMINI_API_KEY, SRE_AGENT_ID; sets USE_DATABASE_SESSIONS=false) |
sample_text_payload_logs |
5 log entries with textPayload (INFO, ERROR, WARNING) |
sample_json_payload_logs |
4 log entries with jsonPayload (various field names: message, msg, log) |
sample_proto_payload_logs |
1 audit log entry with protoPayload |
baseline_period_logs |
23 log entries simulating a healthy period (20 INFO + 3 WARNING) |
incident_period_logs |
43 log entries simulating an incident (connection refused, lock timeouts, retries) |
mixed_payload_logs |
7 log entries mixing all payload types for extraction testing |
sample_trace_spans |
2 spans forming a simple HTTP+DB trace |
mock_logging_client |
MagicMock for Cloud Logging client |
mock_trace_client |
MagicMock for Cloud Trace client |
mock_bigquery_client |
MagicMock for BigQuery client |
mock_tool_context |
MagicMock for ADK ToolContext |
Helper functions defined in conftest: generate_trace_id(), generate_span_id(), generate_timestamp().
The following environment variables are set by the test poe task:
| Variable | Value | Purpose |
|---|---|---|
GOOGLE_CLOUD_PROJECT |
test-project |
Provides a project ID without requiring real GCP access |
STRICT_EUC_ENFORCEMENT |
false |
Allows tests to run without real user credentials |
DISABLE_TELEMETRY |
true |
Prevents OTel span export during tests |
GOOGLE_GENAI_USE_VERTEXAI |
false |
Disables Vertex AI client to avoid credential requirements |
SRE_AGENT_DEPLOYMENT_MODE |
true |
Skips heavyweight module imports (e.g., ADK agent loading) at module level |
USE_DATABASE_SESSIONS |
false |
Set by conftest.py to use InMemorySessionService (prevents SQLite lock conflicts) |
USE_MOCK_MCP |
true |
(Optional) Enables mock MCP toolsets instead of real MCP connections |
Every major feature or fix should be anchored in an OpenSpec change located in openspec/changes/.
When building a new capability, use the tdd schema:
spec: Define the behavior, input/output contracts, and success criteria.tests: Draft the test cases (Gherkin/Functional).implementation: Write code to pass the tests.archive: Permanently move verified specs toopenspec/specs/.
For critical existing modules (like the chat_agent), we maintain "Base Specs" in openspec/specs/ to serve as the definitive source of truth for behavior.
- OpenSpec First: No PR should be submitted for a new feature without a corresponding OpenSpec artifact.
- TDD Rule: For all new features, you must produce a test file demonstrating the intended behavior before modifying
sre_agent/. - Coverage Gate: PRs that drop the project coverage level below 80% will be rejected.
- Regression Zero: Every bug fix must include a regression test that fails without the fix.
- Documentation Rule: Every new feature MUST include updates to internal architecture docs and the public Help Center (
docs/help). - No Placeholders: Do not use
TODOin tests. Tests must be complete and assert on all relevant fields in responses.
# Run full test suite with coverage gate (parallel via pytest-xdist)
uv run poe test
# Run tests without coverage (fastest iteration)
uv run poe test-fast
# Run with detailed coverage report (manual)
uv run pytest tests --cov=sre_agent --cov-report=term-missing --cov-fail-under=80
# Run a single test file
uv run pytest tests/unit/sre_agent/tools/clients/test_trace.py -v
# Run tests matching a keyword
uv run pytest tests -k "test_fetch_trace" -v# Run Flutter tests via poe
uv run poe test-flutter
# Run from the autosre/ directory
cd autosre && flutter test
# Run a specific test file
cd autosre && flutter test test/council_panel_test.dart# Run both backend and frontend tests
uv run poe test-all# Run agent quality evaluations (trajectory + rubric scoring)
uv run poe evalFor details on how to test the Flutter dashboard and use the test_helper.dart utility, see docs/testing/frontend_testing.md.
*Last verified: 2026-02-21