Skip to content

Decompose oversized fragment transport test into modular files#425

Merged
leynos merged 6 commits intomainfrom
terragon/refactor-tests-split-large-file-14456g
Jan 30, 2026
Merged

Decompose oversized fragment transport test into modular files#425
leynos merged 6 commits intomainfrom
terragon/refactor-tests-split-large-file-14456g

Conversation

@leynos
Copy link
Copy Markdown
Owner

@leynos leynos commented Jan 25, 2026

Summary

  • Decomposed the oversized fragment_transport test module into modular files and introduced shared helpers.

Changes

  • Shared test helpers:
    • Added tests/common/fragment_helpers.rs with:
      • TestError enum for test-specific errors
      • fragmentation_config builders and helpers
      • fragment_envelope/encode/decode utilities
      • envelope sending/receiving helpers over a framed duplex
      • app construction helpers (make_app, spawn_app)
      • test utilities for building envelopes, reading reassembled responses, and assertion helpers
  • Test organization:
    • Updated tests/common/mod.rs to expose the new fragment_helpers module and document submodules
    • Introduced modular structure for fragment transport tests:
      • New tests/fragment_transport/mod.rs to organize submodules
      • New tests/fragment_transport/eviction.rs for reassembly-timeout eviction tests
      • New tests/fragment_transport/rejection.rs for malformed/out-of-order/duplicate fragment tests
    • Existing fragment_transport.rs content has been reorganized to route into the new modular layout
  • Fragment transport test modules:
    • tests/fragment_transport/mod.rs now acts as the aggregator for fragmentation tests
    • tests/fragment_transport/eviction.rs validates that incomplete fragment sequences are evicted after the reassembly timeout
    • tests/fragment_transport/rejection.rs validates that invalid fragment sequences are rejected (out-of-order, duplicate, malformed)

Why

  • Improves readability and maintainability by breaking a monolithic test module into smaller, focused units and a shared helper library. Reduces compile times and makes it easier to extend tests for fragmentation behavior.

Test plan

  • Run the test suite to verify all fragmentation tests pass:
    • cargo test
  • Specifically verify:
    • Eviction behavior after reassembly timeout
    • Rejection of malformed, out-of-order, and duplicate fragments
    • Round-trip fragmentation scenarios still function as expected with the modularized tests

🌿 Generated by Terry


ℹ️ Tag @terragon-labs to ask questions and address PR feedback

📎 Task: https://www.terragonlabs.com/task/cd1c2264-724a-4112-abd1-037d5231f12a

Decompose the 513-line test file into a modular structure:

- Extract TestError and shared helpers to tests/common/fragment_helpers.rs
- Move rejection tests (FragmentRejectionSetup, mutators, parameterized
  cases) to tests/fragment_transport/rejection.rs
- Move eviction test to tests/fragment_transport/eviction.rs
- Keep round-trip tests and API toggle test in the main file

The main file is now 150 lines, well under the 400-line guideline.
All quality gates pass (check-fmt, lint, test).

Closes #401

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@sourcery-ai
Copy link
Copy Markdown
Contributor

sourcery-ai Bot commented Jan 25, 2026

Reviewer's Guide

Refactors the monolithic fragment transport integration test file into a small shared helper module plus two focused test modules for rejection and eviction behavior, without changing core runtime logic.

File-Level Changes

Change Details Files
Introduce shared fragmentation test helpers to centralize configuration, app wiring, and encode/decode utilities.
  • Add TestError enum to represent common test failure modes for fragmentation scenarios.
  • Provide fragmentation_config and fragmentation_config_with_timeout builders around FragmentationConfig.
  • Add fragment_envelope helper to encode envelopes into fragment payloads and build fragment sequences.
  • Add send_envelopes, read_reassembled_response, read_response_payload utilities for framed I/O over a duplex stream.
  • Add make_handler, make_app, spawn_app, build_envelopes, assert_handler_observed helpers for setting up and asserting fragment transport tests.
tests/common/fragment_helpers.rs
Document and expose the new shared helpers from the common test module.
  • Document fragment_helpers and terminator as notable submodules in the common tests module docs.
tests/common/mod.rs
Extract fragment rejection tests into a dedicated module using the shared helpers.
  • Define FragmentRejectionSetup struct that encapsulates client/server wiring, fragments, and handler receiver channel.
  • Provide test_fragment_rejection harness function that runs a rejection scenario and asserts no payload is delivered to the handler.
  • Implement mutate_out_of_order, mutate_duplicate, and mutate_malformed_header mutators to corrupt fragment sequences in different ways.
  • Define rstest-based fragment_rejection_cases parametrized test using the shared rejection harness.
tests/fragment_transport/rejection.rs
tests/fragment_transport.rs
Extract fragment eviction tests into a dedicated module using the shared helpers.
  • Create expired_fragments_are_evicted test that configures a short reassembly timeout and sends only a partial fragment sequence before delay.
  • Use fragmentation_config_with_timeout and fragment_envelope helpers to construct the test scenario.
  • Assert via timeout that the handler does not receive a payload after eviction, and that the server task completes cleanly.
tests/fragment_transport/eviction.rs
tests/fragment_transport.rs
Introduce a fragment_transport test module to organize the new submodules.
  • Add a small mod.rs that documents the test module layout and re-exports the eviction and rejection submodules for the fragment transport test suite.
tests/fragment_transport/mod.rs

Possibly linked issues

  • #unknown: PR implements the requested split of tests/fragment_transport.rs into smaller eviction/rejection modules and shared helpers.

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Jan 25, 2026

Summary by CodeRabbit

  • Tests
    • Centralised test utilities added to support end-to-end fragmentation scenarios (config, fragmenting, reassembly, I/O, and verification).
    • Integration tests reorganised to reuse shared helpers and return structured errors instead of panics.
    • New tests cover eviction of incomplete reassembly after timeout and rejection of invalid or mutated fragment sequences.
    • Utilities simplify in-process test apps, envelope building, send/read flows and assertions.

✏️ Tip: You can customize this high-level summary in your review settings.

Walkthrough

Summarise the PR: add a shared test helper module for fragment-transport tests and split the large fragmentation test into focused submodules (eviction, rejection) that reuse the new helpers for setup, fragmentation, I/O and assertions.

Changes

Cohort / File(s) Summary
Test Helper Infrastructure
tests/common/fragment_helpers.rs, tests/common/mod.rs
Add public test helpers for end-to-end fragment transport testing: TestError, ROUTE_ID, CORRELATION, fragmentation config builders, fragment_envelope, serialization/I/O helpers (send_envelopes, read_reassembled_response, read_response_payload), app scaffolding (make_app, spawn_app, make_handler), envelope builders and assertion helpers.
Top-level Test Organisation
tests/fragment_transport.rs
Replace inline fragmentation scaffolding with a path-module declaration and import shared helpers from tests/common::fragment_helpers, delegating tests to tests/fragment_transport/*.
Fragment Transport Test Submodules
tests/fragment_transport/mod.rs, tests/fragment_transport/eviction.rs, tests/fragment_transport/rejection.rs
Add organised submodules: eviction.rs tests reassembly eviction after timeout; rejection.rs tests fragment rejection (out-of-order, duplicate, malformed) via mutation strategies and parametrised cases; expose modules in mod.rs.

Sequence Diagram(s)

sequenceDiagram
  participant Client as Client
  participant Fragmenter as Fragmenter
  participant WireframeApp as WireframeApp
  participant Reassembler as Reassembler
  participant Handler as Handler

  Client->>Fragmenter: fragment_envelope(request Envelope)
  Client->>WireframeApp: send_envelopes(framed stream)
  WireframeApp->>Reassembler: receive fragment frames
  Reassembler->>Reassembler: attempt reassembly / timeout eviction
  Reassembler-->>Handler: deliver reassembled payload (if valid)
  Handler-->>WireframeApp: produce response Envelope
  WireframeApp-->>Client: framed response (possibly fragmented)
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related issues

Poem

Fragments split and helpers meet,
Eviction waits, rejections greet,
Tests tidy, small and neat,
Reassembly hums on beat,
Assertions land — the checks complete. 🧩✨

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately summarises the main change: decomposing an oversized test module into modular files, which is the core refactoring undertaken.
Description check ✅ Passed The description clearly relates to the changeset, detailing the decomposition strategy, shared helpers introduction, new modular structure, and rationale for the refactoring.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch terragon/refactor-tests-split-large-file-14456g

Comment @coderabbitai help to get the list of available commands and usage tips.

@leynos leynos marked this pull request as ready for review January 25, 2026 21:53
Copy link
Copy Markdown
Contributor

@sourcery-ai sourcery-ai Bot left a comment

Choose a reason for hiding this comment

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

Hey - I've left some high level feedback:

  • In tests/fragment_transport/rejection.rs, several items (FragmentRejectionSetup, test_fragment_rejection, FragmentMutator, and the mutator functions) are declared pub but appear to be used only within this module; consider reducing their visibility to pub(crate) or private to avoid exposing unnecessary test API surface.
  • Now that spawn_app exists in tests/common/fragment_helpers.rs, the expired_fragments_are_evicted test in tests/fragment_transport/eviction.rs could be simplified by reusing spawn_app instead of duplicating the codec/duplex setup logic.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- In `tests/fragment_transport/rejection.rs`, several items (`FragmentRejectionSetup`, `test_fragment_rejection`, `FragmentMutator`, and the mutator functions) are declared `pub` but appear to be used only within this module; consider reducing their visibility to `pub(crate)` or private to avoid exposing unnecessary test API surface.
- Now that `spawn_app` exists in `tests/common/fragment_helpers.rs`, the `expired_fragments_are_evicted` test in `tests/fragment_transport/eviction.rs` could be simplified by reusing `spawn_app` instead of duplicating the codec/duplex setup logic.

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🤖 Fix all issues with AI agents
In `@tests/common/fragment_helpers.rs`:
- Around line 228-241: The function assert_handler_observed uses assert_eq!
which panics inside a TestResult-returning function; change it to perform an
explicit equality check on the observed and expected slices and on mismatch
return Err(TestError::Assertion(...)) instead of panicking. Locate
assert_handler_observed (params rx, expected) and replace the assert_eq! block
with an if observed != expected { return
Err(TestError::Assertion(format!("observed payload mismatch: expected
{expected:?}, got {observed:?}"))); } so the function returns a
TestError::Assertion on failure and still returns Ok(()) on success.

In `@tests/fragment_transport.rs`:
- Around line 3-7: Update the module-level comment at the top of
tests/fragment_transport.rs: replace the British spelling "organised" with the
Oxford -ize form "organized" in the overview sentence so it reads "Tests are
organized into submodules by concern:"; no code changes beyond that comment edit
are required.

In `@tests/fragment_transport/mod.rs`:
- Around line 1-5: Update the module-level doc comment at the top of the file
(the //! comment block in tests/fragment_transport/mod.rs) to use Oxford -ize
spelling: replace the word "organisation" with "organization" in the first line
so the docstring reads "Module organization for fragment transport integration
tests."

Comment thread tests/common/fragment_helpers.rs
Comment thread tests/fragment_transport.rs
Comment thread tests/fragment_transport/mod.rs Outdated
- Use Oxford -ize spelling ('organized', 'organization') per coding
  guidelines in module doc comments
- Replace assert_eq! with conditional TestError::Assertion return in
  assert_handler_observed to avoid triggering clippy::panic_in_result_fn

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@leynos leynos changed the title Refactor: split oversized test module into smaller files Refactor: modularize fragment transport tests and add shared helpers Jan 28, 2026
@leynos

This comment was marked as resolved.

@coderabbitai

This comment was marked as resolved.

- Use Oxford -ize spelling ('organized', 'organization') per coding
  guidelines in module doc comments
- Replace assert_eq! with conditional TestError::Assertion return in
  assert_handler_observed to avoid triggering clippy::panic_in_result_fn

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@leynos leynos changed the title Refactor: modularize fragment transport tests and add shared helpers Decompose oversized fragment transport test into modular files Jan 29, 2026
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
tests/fragment_transport.rs (1)

42-64: Fix the panic-inducing assertion on line 64 to return an explicit error.

The function run_round_trip_test returns TestResult<Vec<u8>> and uses assert_eq! on line 64, which triggers the panic_in_result_fn lint (denied in Cargo.toml). Replace the assertion with explicit error handling:

Fix
-    assert_eq!(response, payload);
+    if response != payload {
+        return Err(TestError::Assertion(format!(
+            "observed payload mismatch: expected {payload:?}, got {response:?}"
+        ))
+        .into());
+    }

Per coding guidelines: Clippy warnings MUST be disallowed. Fix any warnings emitted during tests in the code itself rather than silencing them.

🤖 Fix all issues with AI agents
In `@tests/common/fragment_helpers.rs`:
- Around line 84-105: Add missing `# Errors` sections to all public helper
functions that return TestResult (e.g., fragmentation_config and
fragmentation_config_with_timeout) describing when they return TestError::Setup
(message limit zero, frame budget failure, or invalid timeout), and add short
doc comments for the helper functions that currently lack any docs (the public
helpers around the noted lines). Ensure each existing doc comment that describes
behavior also includes a `# Errors` block that mentions the specific error
variant(s) (TestError::Setup) and the conditions that trigger them so Clippy's
missing_errors_doc lint is satisfied.
- Around line 174-186: Add a doc comment and #[must_use] to the make_handler
factory: update the function signature for make_handler (returning
Handler<Envelope>) to include the #[must_use] attribute and add a Rust doc
comment that describes the return value should not be ignored and includes a "#
Panics" section explaining that the closure assert!(tx.send(payload).is_ok())
will panic if sending to the channel fails; ensure the doc mentions that the
produced handler must be used by callers so the assert can run.

Comment thread tests/common/fragment_helpers.rs
Comment thread tests/common/fragment_helpers.rs
leynos and others added 2 commits January 29, 2026 21:55
- Use Oxford -ize spelling ('organized', 'organization') per coding
  guidelines in module doc comments
- Replace assert_eq! with conditional TestError::Assertion return in
  assert_handler_observed and run_round_trip_test to avoid triggering
  clippy::panic_in_result_fn
- Reduce visibility of test-internal items in rejection.rs to private
- Simplify eviction.rs by reusing spawn_app helper

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add # Errors sections to all Result-returning public functions and
# Panics section to make_handler. Add #[must_use] attribute to
make_handler to satisfy Clippy lints.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
tests/fragment_transport.rs (2)

105-155: Refactor asserts to error returns and remove the lint expectation.

Replace assert_eq! and assert! with TestError::Assertion-returning logic to eliminate the unnecessary clippy::panic_in_result_fn suppression. This pattern is already used elsewhere in the test suite (e.g., run_round_trip_test).

Proposed fix
-#[expect(
-    clippy::panic_in_result_fn,
-    reason = "asserts provide clearer diagnostics in tests"
-)]
 async fn fragmentation_can_be_disabled_via_public_api() -> TestResult {
@@
-    assert_eq!(
-        observed, payload,
-        "observed payload mismatch: expected {payload:?}, got {observed:?}"
-    );
+    if observed != payload {
+        return Err(TestError::Assertion(format!(
+            "observed payload mismatch: expected {payload:?}, got {observed:?}"
+        ))
+        .into());
+    }
@@
-    assert!(
-        decode_fragment_payload(&response)?.is_none(),
-        "expected no fragmentation when fragmentation is disabled"
-    );
+    if decode_fragment_payload(&response)?.is_some() {
+        return Err(TestError::Assertion(
+            "expected no fragmentation when fragmentation is disabled".to_string(),
+        )
+        .into());
+    }

84-103: Remove the #[expect(...)] lint suppression and use TestError::Assertion instead of assert!() to comply with the coding guideline prohibiting lint silencing.

Replace the panic-based assertion with an explicit error return. The TestError::Assertion variant is already defined and used successfully in helper functions elsewhere in the codebase.

Proposed fix
-#[tokio::test]
-#[expect(
-    clippy::panic_in_result_fn,
-    reason = "asserts provide clearer diagnostics in tests"
-)]
 async fn unfragmented_request_and_response_round_trip() -> TestResult {
     let buffer_capacity = 512;
     let config = fragmentation_config(buffer_capacity)?;
     let cap = config.fragment_payload_cap.get();
     let payload_len = cap.saturating_sub(8).max(1);
     let payload = vec![b's'; payload_len];

     let response = run_round_trip_test(buffer_capacity, payload, false).await?;
-    assert!(
-        decode_fragment_payload(&response)?.is_none(),
-        "small payload should pass through unfragmented"
-    );
+    if decode_fragment_payload(&response)?.is_some() {
+        return Err(TestError::Assertion(
+            "small payload should pass through unfragmented".to_string(),
+        )
+        .into());
+    }

     Ok(())
 }
🤖 Fix all issues with AI agents
In `@tests/common/fragment_helpers.rs`:
- Around line 81-100: The function fragmentation_config currently uses
saturating_mul(16) which hides overflow; change the message_limit computation to
use checked_mul(16).and_then(NonZeroUsize::new) and map None to the existing
TestError::Setup("non-zero message limit") so overflow or zero yields an error;
keep the subsequent call to FragmentationConfig::for_frame_budget(...) and its
TestError::Setup("frame budget must exceed fragment overhead") unchanged.

Comment thread tests/common/fragment_helpers.rs
- Use checked_mul instead of saturating_mul in fragmentation_config
  to properly implement documented overflow error behaviour
- Remove #[expect(clippy::panic_in_result_fn)] lint suppressions
- Replace assert!/assert_eq! with TestError::Assertion returns in
  unfragmented_request_and_response_round_trip and
  fragmentation_can_be_disabled_via_public_api tests

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@leynos leynos merged commit 5c4ef1c into main Jan 30, 2026
6 checks passed
@leynos leynos deleted the terragon/refactor-tests-split-large-file-14456g branch January 30, 2026 18:21
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.

1 participant