Skip to content

[APMSVLS-497][APMSVLS-498] test: add fake-intake for APM payload-level tests#1194

Open
lucaspimentel wants to merge 14 commits intolpimentel/stats-flusher-url-paramfrom
lpimentel/fake-intake-phase-1
Open

[APMSVLS-497][APMSVLS-498] test: add fake-intake for APM payload-level tests#1194
lucaspimentel wants to merge 14 commits intolpimentel/stats-flusher-url-paramfrom
lpimentel/fake-intake-phase-1

Conversation

@lucaspimentel
Copy link
Copy Markdown
Member

@lucaspimentel lucaspimentel commented Apr 21, 2026

Overview

Adds an in-process fake Datadog intake for bottlecap so APM flush paths can be asserted at the payload-field level, not just "a request was made".

Stacked on top of #1210 (the StatsFlusher::new URL-parameter refactor). This PR targets lpimentel/stats-flusher-url-param and should be merged after #1210 lands.

Before this PR, no APM payload flushed by bottlecap was covered by integration tests. The existing httpmock-based tests for logs and metrics only check body_contains(<substring>) on raw bytes, so they can't catch regressions in stats bucket structure, span attribution, peer tags, or any other decoded field.

This PR implements phase 1 of the fake-intake work (APMSVLS-496), covering both sub-tickets:

  • APMSVLS-497 — fake-intake scaffold + StatsPayload msgpack decode + first stats integration test.
  • APMSVLS-498 — AgentPayload protobuf decode + first trace-payload integration test.

Changes:

  • bottlecap/tests/common/fake_intake.rs — axum server on a random local port accepting /api/v0.2/stats (msgpack + gzip) and /api/v0.2/traces (protobuf with zstd/gzip/identity decompression). Decodes each body on arrival and stores pb::StatsPayload / pb::AgentPayload for tests to query. Decompression failures return HTTP 400; unknown Content-Encoding values are warned.
  • bottlecap/tests/apm_integration_test.rs — two new integration tests:
    • stats_payload_roundtrip_through_fake_intake: drives StatsFlusher::send and asserts on hit counts, span kind, peer tags, and HTTP metadata.
    • trace_payload_roundtrip_through_fake_intake: drives TraceFlusher::flush through the real aggregator and asserts on trace/span IDs and service metadata.
  • bottlecap/Cargo.toml — adds rmp-serde and flate2 as dev-dependencies.

Phase 2 will extract this module into a shared crate consumed by both bottlecap and SCL; the module is deliberately bottlecap-type-free to make that extraction mechanical.

Testing

  • cargo test --test apm_integration_test — both new tests pass locally and on Linux CI
  • cargo test — full bottlecap test suite passes locally (522 unit tests + integration/doc tests), no regressions
  • RUSTFLAGS="-D warnings" cargo clippy --workspace --all-targets --features default — clean locally and on Linux CI
  • cargo fmt --all -- --check — clean locally

"Finally, a way to ask our StatsPayloads how they're really feeling, and not just whether they showed up to work." — Claude

@lucaspimentel lucaspimentel changed the title [APMSVLS-494] test: add in-process fake-intake for APM payload-level tests [APMSVLS-494] test: add fake-intake for APM payload-level tests Apr 21, 2026
@lucaspimentel lucaspimentel marked this pull request as ready for review April 21, 2026 03:12
@lucaspimentel lucaspimentel requested a review from a team as a code owner April 21, 2026 03:12
@lucaspimentel lucaspimentel requested review from Copilot and duncanista and removed request for Copilot April 21, 2026 03:12
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR introduces an in-process “fake Datadog intake” test harness for Bottlecap APM payload-level integration testing, enabling assertions on decoded stats/traces payload fields rather than only verifying that an HTTP request occurred.

Changes:

  • Add FakeIntake axum server that accepts /api/v0.2/stats and /api/v0.2/traces, decodes bodies, and stores pb::StatsPayload / pb::AgentPayload for tests.
  • Add new APM integration tests that exercise the stats and traces flush paths and assert on decoded payload fields.
  • Make StatsFlusher::new accept an explicit stats intake URL so tests can redirect it to the fake intake; update the production call site accordingly.

Reviewed changes

Copilot reviewed 6 out of 7 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
bottlecap/tests/common/mod.rs Adds a shared tests/common module exposing fake_intake.
bottlecap/tests/common/fake_intake.rs Implements the in-process fake intake server with decoding and captured payload storage.
bottlecap/tests/apm_integration_test.rs Adds payload-level integration tests for stats and traces flush paths.
bottlecap/src/traces/stats_flusher.rs Accepts stats_url in the constructor and logs the actual endpoint used.
bottlecap/src/bin/bottlecap/main.rs Passes trace_stats_url(&config.site) into StatsFlusher::new.
bottlecap/Cargo.toml Adds dev-dependencies for msgpack and gzip decoding used by the fake intake.
bottlecap/Cargo.lock Updates lockfile for the new dev-dependencies.

Comment thread bottlecap/tests/common/fake_intake.rs Outdated
Comment thread bottlecap/tests/common/fake_intake.rs
Comment thread bottlecap/tests/common/fake_intake.rs Outdated
Comment thread bottlecap/tests/common/mod.rs Outdated
@lucaspimentel lucaspimentel changed the title [APMSVLS-494] test: add fake-intake for APM payload-level tests [APMSVLS-497][APMSVLS-498] test: add fake-intake for APM payload-level tests Apr 21, 2026
@lucaspimentel lucaspimentel requested a review from a team as a code owner April 23, 2026 20:12
Copy link
Copy Markdown
Contributor

@duncanista duncanista left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems like the stats URL change is different to what this PR claims, do we really need them together?

@lucaspimentel lucaspimentel force-pushed the lpimentel/fake-intake-phase-1 branch from 2b10774 to 2e77c12 Compare April 24, 2026 17:36
@lucaspimentel lucaspimentel changed the base branch from main to lpimentel/stats-flusher-url-param April 24, 2026 17:36
@lucaspimentel
Copy link
Copy Markdown
Member Author

lucaspimentel commented Apr 24, 2026

@duncanista

Seems like the stats URL change is different to what this PR claims, do we really need them together?

I split that small refactor out into #1210 and stacked this PR on that one.

@lucaspimentel lucaspimentel force-pushed the lpimentel/stats-flusher-url-param branch from 8f52b41 to 6fbe14b Compare April 24, 2026 21:07
lucaspimentel and others added 11 commits April 24, 2026 17:10
…tests

Spawns an axum server on a random local port that accepts POSTs on
/api/v0.2/stats (msgpack + gzip) and /api/v0.2/traces (protobuf, with
zstd/gzip/identity decompression), decodes each body on arrival, and
stores the decoded pb::StatsPayload / pb::AgentPayload for tests to
query via typed methods.

Two integration tests cover both flush paths:

- stats_payload_roundtrip_through_fake_intake: drives StatsFlusher::send
  directly and asserts on decoded hit counts, span kind, peer tags, and
  HTTP metadata.
- trace_payload_roundtrip_through_fake_intake: drives TraceFlusher::flush
  through the real aggregator and asserts on decoded trace/span IDs and
  service metadata.

Tests redirect StatsFlusher at the fake-intake by passing
FakeIntake::stats_url() to StatsFlusher::new, which was lifted to take
the URL as a parameter in a prior commit.

Prototype for APMSVLS-494 phase 1; extraction to a shared
datadog/apm-agent-parity-rs crate is planned for phase 2.

Co-Authored-By: Claude <noreply@anthropic.com>
service_source and span_derived_primary_tags were added in 2.0.0
(crates.io) but the workspace pins the git version (1.0.0).

🤖 Co-Authored-By: Claude Code <noreply@anthropic.com>
🤖 Co-Authored-By: Claude Code <noreply@anthropic.com>
🤖 Co-Authored-By: Claude Code <noreply@anthropic.com>
- Return Result instead of panicking on bad decompression; axum
  converts handler panics to TCP aborts, not 500s, which produces
  opaque test failures
- Warn on unrecognized Content-Encoding instead of silently
  treating as identity
- Make base_url() private; stats_url()/traces_url() cover all uses

🤖 Co-Authored-By: Claude Code <noreply@anthropic.com>
🤖 Co-Authored-By: Claude Code <noreply@anthropic.com>
🤖 Co-Authored-By: Claude Code <noreply@anthropic.com>
🤖 Co-Authored-By: Claude Code <noreply@anthropic.com>
base_url() was private and never called; stats_url() and traces_url()
accessed the field directly. Removing it also makes the blanket
#![allow(dead_code)] in common/mod.rs unnecessary.

🤖 Co-Authored-By: Claude Code <noreply@anthropic.com>
@lucaspimentel lucaspimentel force-pushed the lpimentel/fake-intake-phase-1 branch from 2e77c12 to 027f404 Compare April 24, 2026 21:11
fake_intake was re-exported from tests/common/mod.rs, causing it to be
compiled into every test binary. logs_integration_test and
metrics_integration_test never use it, so the compiler emitted dead-code
errors under RUSTFLAGS=-D warnings.

Remove the re-export from common/mod.rs and include the module directly
in apm_integration_test via #[path]. Remove the now-unused `mod common;`
declarations from logs and metrics test files.

🤖 Co-Authored-By: Claude Code <noreply@anthropic.com>
The Drop impl already sends the shutdown signal and aborts the task.
The explicit shutdown() method was never called in any test.

🤖 Co-Authored-By: Claude Code <noreply@anthropic.com>
🤖 Co-Authored-By: Claude Code <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants