Skip to content

Commit 6b9e7bf

Browse files
refactor(s2n-quic): move tests to s2n-quic-tests (#2716)
1 parent f8bed9a commit 6b9e7bf

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

49 files changed

+281
-98
lines changed

.github/config/cargo-deny.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ skip-tree = [
3434
{ name = "s2n-quic-h3" },
3535
{ name = "s2n-quic-qns" },
3636
{ name = "s2n-quic-sim" },
37+
{ name = "s2n-quic-tests" },
3738
]
3839

3940
[sources]

docs/dev-guide/ci.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ Unit tests validate the expected behavior of individual components of `s2n-quic`
1212

1313
#### Integration Tests
1414

15-
`s2n-quic` integration tests use the public API to validate the end-to-end behavior of the library under specific scenarios and configurations. Integration tests are located in the top-level `s2n-quic` crate, in the [tests module](https://github.com/aws/s2n-quic/tree/main/quic/s2n-quic/src/tests).
15+
`s2n-quic` integration tests use the public API to validate the end-to-end behavior of the library under specific scenarios and configurations. Integration tests are located in the `s2n-quic-tests` crate.
1616

1717
#### Snapshot Tests
1818

quic/s2n-quic-qns/etc/Dockerfile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ RUN set -eux; \
3232
sed -i '/xdp/d' quic/s2n-quic-platform/Cargo.toml; \
3333
sed -i '/xdp/d' quic/s2n-quic-qns/Cargo.toml; \
3434
sed -i '/xdp/d' quic/s2n-quic/Cargo.toml; \
35-
rm -rf quic/s2n-quic-bench quic/s2n-quic-events quic/s2n-quic-sim
35+
rm -rf quic/s2n-quic-bench quic/s2n-quic-events quic/s2n-quic-sim quic/s2n-quic-tests
3636

3737
#################
3838
# Planner image #

quic/s2n-quic-tests/Cargo.toml

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
[package]
2+
name = "s2n-quic-tests"
3+
# this in an unpublished internal crate so the version should not be changed
4+
version = "0.1.0"
5+
description = "Integration tests for s2n-quic"
6+
authors = ["AWS s2n"]
7+
edition = "2021"
8+
rust-version = "1.82"
9+
license = "Apache-2.0"
10+
# this only contains internal tests and should not be published
11+
publish = false
12+
13+
[dependencies]
14+
bytes = { version = "1", default-features = false }
15+
futures = { version = "0.3", default-features = false, features = ["std"] }
16+
rand = "0.9"
17+
rand_chacha = "0.9"
18+
s2n-codec = { path = "../../common/s2n-codec" }
19+
s2n-quic-core = { path = "../s2n-quic-core", features = ["branch-tracing", "event-tracing", "probe-tracing", "testing"] }
20+
s2n-quic = { path = "../s2n-quic", features = ["provider-event-tracing", "unstable-provider-io-testing", "unstable-provider-dc", "unstable-provider-packet-interceptor", "unstable-provider-random"] }
21+
s2n-quic-platform = { path = "../s2n-quic-platform", features = ["tokio-runtime"] }
22+
s2n-quic-transport = { path = "../s2n-quic-transport", features = ["unstable_resumption", "unstable-provider-dc"] }
23+
tokio = { version = "1", features = ["full"] }
24+
tracing = { version = "0.1" }
25+
tracing-subscriber = { version = "0.3", features = ["env-filter"] }
26+
zerocopy = { version = "0.8", features = ["derive"] }
27+
28+
# quiche does not currently build on 32-bit platforms
29+
# see https://github.com/cloudflare/quiche/issues/2097
30+
[target.'cfg(not(target_arch = "x86"))'.dependencies]
31+
quiche = "0.24"
32+
33+
[target.'cfg(unix)'.dependencies]
34+
s2n-quic = { path = "../s2n-quic", features = ["provider-event-tracing", "provider-tls-s2n", "unstable-provider-io-testing", "unstable-provider-dc", "unstable-provider-packet-interceptor", "unstable-provider-random"] }

quic/s2n-quic-tests/README.md

Lines changed: 151 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,151 @@
1+
# s2n-quic-tests
2+
3+
This crate contains integration tests for the s2n-quic implementation. These tests verify the behavior of the QUIC protocol implementation across various scenarios and edge cases.
4+
5+
## Test Organization
6+
7+
The test organization in this crate is inspired by the approach used in the [rust-lang/cargo](https://github.com/rust-lang/cargo) repository. This approach differs from the typical Rust integration test organization described in the [Rust book](https://doc.rust-lang.org/book/ch11-03-test-organization.html) for the reason highlighted in the [Cargo book](https://doc.rust-lang.org/cargo/reference/cargo-targets.html#integration-tests):
8+
9+
>Each integration test results in a separate executable binary, and cargo test will run them serially. In some cases this can be inefficient, as it can take longer to compile, and may not make full use of multiple CPUs when running the tests. If you have a lot of integration tests, you may want to consider creating a single integration test, and split the tests into multiple modules.
10+
11+
To further increase performance, the tests are contained within the `src` folder to avoid having the tests wait for compilation and linking of the intermediate `s2n-quic-tests` lib.
12+
13+
### Platform-specific Tests
14+
15+
Some tests in this crate are platform-specific, particularly those that depend on s2n-tls, which is only available on Unix systems. These tests are conditionally compiled using `cfg[unix]` attributes. For example:
16+
17+
```rust
18+
#[cfg(unix)]
19+
mod resumption;
20+
21+
#[cfg(not(target_os = "windows"))]
22+
mod mtls;
23+
```
24+
25+
This approach ensures that tests only run on platforms where their dependencies are available. The Cargo.toml file also includes platform-specific dependencies to support this.
26+
27+
## Test Structure
28+
29+
The test suite is organized into several categories:
30+
31+
- **Basic Connectivity Tests**: Verify that clients and servers can establish connections and exchange data.
32+
- **Error Handling Tests**: Ensure proper handling of protocol errors, malformed packets, and connection failures.
33+
- **Network Pathology Tests**: Test behavior under various network conditions (latency, packet loss, reordering).
34+
- **Edge Case Tests**: Verify correct behavior in unusual or extreme scenarios.
35+
36+
### Directory Structure
37+
38+
```
39+
src/
40+
├── lib.rs # Contains common test utilities and setup functions
41+
├── recorder.rs # Event recording utilities
42+
├── tests.rs # Main test module that imports all tests
43+
└── tests/ # Contains all the test files
44+
├── blackhole.rs # Individual test files
45+
├── ... # Other test files
46+
└── snapshots/ # Snapshot files for tests
47+
```
48+
49+
## Running Tests
50+
51+
### Running All Tests
52+
53+
To run all tests in the crate:
54+
55+
```bash
56+
cargo test
57+
```
58+
59+
### Running Specific Tests
60+
61+
To run tests in a specific module:
62+
63+
```bash
64+
cargo test -- <module_name>
65+
```
66+
67+
For example, to run the blackhole tests:
68+
69+
```bash
70+
cargo test -- blackhole
71+
```
72+
73+
To run a specific test:
74+
75+
```bash
76+
cargo test -- <module_name>::<test_name>
77+
```
78+
79+
For example:
80+
81+
```bash
82+
cargo test -- blackhole::blackhole_success_test
83+
```
84+
85+
### Running Tests with Logging
86+
87+
To enable trace logging during test execution:
88+
89+
```bash
90+
cargo test -- --nocapture
91+
```
92+
93+
## Testing Philosophy
94+
95+
The s2n-quic-tests crate follows several key principles:
96+
97+
1. **Comprehensive Coverage**: Tests cover both normal operation paths and error handling scenarios.
98+
99+
2. **Deterministic Testing**: Tests are designed to be deterministic and reproducible, avoiding flaky tests that could pass or fail randomly.
100+
101+
3. **Isolation**: Each test runs in isolation to prevent interference between tests.
102+
103+
4. **Realistic Scenarios**: Tests simulate real-world network conditions including packet loss, reordering, and latency.
104+
105+
## Test Utilities
106+
107+
### Network Simulation
108+
109+
The test suite uses the [Bach](https://github.com/camshaft/bach) async simulation framework for simulating various network conditions:
110+
111+
- Packet loss
112+
- Packet reordering
113+
- Network latency
114+
- Bandwidth limitations
115+
- Connection blackholes
116+
117+
### Event Recording
118+
119+
The `recorder.rs` module provides utilities for recording and verifying events during test execution, allowing tests to assert on the sequence and content of events.
120+
121+
### Packet Interceptor
122+
123+
The test suite uses a packet interceptor utility that allows tests to inspect, modify, or drop datagrams or modify remote addresses on datagrams as they flow between the client and server.
124+
125+
Implement the `s2n_quic_core::packet::interceptor::Interceptor` trait and configure it in tests like this:
126+
127+
```rust
128+
let client = Client::builder()
129+
.with_io(handle.builder().build().unwrap())?
130+
.with_packet_interceptor(interceptor)?
131+
.start()?;
132+
```
133+
134+
### Common Setup
135+
136+
`src/lib.rs` provides common utilities for setting up test clients and servers with various configurations.
137+
138+
## Contributing New Tests
139+
140+
When adding new tests:
141+
142+
1. Place the test in an appropriate module based on what it's testing
143+
2. Use the common setup utilities when possible
144+
3. Make tests deterministic and avoid dependencies on external systems
145+
4. Document the purpose of the test and any non-obvious aspects
146+
5. Ensure tests run in a reasonable amount of time
147+
148+
## Integration with CI
149+
150+
These tests are automatically run as part of the CI pipeline for s2n-quic. The CI configuration can be found in the `.github/workflows/ci.yml` file in the root of the repository.
151+

quic/s2n-quic/src/tests/setup.rs renamed to quic/s2n-quic-tests/src/lib.rs

Lines changed: 16 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
22
// SPDX-License-Identifier: Apache-2.0
33

4-
use crate::{
4+
use s2n_quic::{
55
client::Connect,
66
provider::{
77
event,
@@ -10,10 +10,15 @@ use crate::{
1010
stream::PeerStream,
1111
Client, Server,
1212
};
13-
use rand::{Rng, RngCore};
1413
use s2n_quic_core::{crypto::tls::testing::certificates, havoc, stream::testing::Data};
14+
15+
use rand::{Rng, RngCore};
1516
use std::net::SocketAddr;
1617

18+
pub mod recorder;
19+
#[cfg(test)]
20+
mod tests;
21+
1722
pub static SERVER_CERTS: (&str, &str) = (certificates::CERT_PEM, certificates::KEY_PEM);
1823

1924
pub fn tracing_events() -> event::tracing::Subscriber {
@@ -37,7 +42,7 @@ pub fn tracing_events() -> event::tracing::Subscriber {
3742
&self,
3843
w: &mut tracing_subscriber::fmt::format::Writer<'_>,
3944
) -> std::fmt::Result {
40-
write!(w, "{}", crate::provider::io::testing::now())
45+
write!(w, "{}", s2n_quic::provider::io::testing::now())
4146
}
4247
}
4348

@@ -193,7 +198,7 @@ impl RngCore for Random {
193198
}
194199
}
195200

196-
impl crate::provider::random::Provider for Random {
201+
impl s2n_quic::provider::random::Provider for Random {
197202
type Generator = Self;
198203

199204
type Error = core::convert::Infallible;
@@ -203,7 +208,7 @@ impl crate::provider::random::Provider for Random {
203208
}
204209
}
205210

206-
impl crate::provider::random::Generator for Random {
211+
impl s2n_quic::provider::random::Generator for Random {
207212
fn public_random_fill(&mut self, dest: &mut [u8]) {
208213
self.fill_bytes(dest);
209214
}
@@ -216,7 +221,7 @@ impl crate::provider::random::Generator for Random {
216221
#[cfg(not(target_os = "windows"))]
217222
mod mtls {
218223
use super::*;
219-
use crate::provider::tls;
224+
use s2n_quic::provider::tls;
220225

221226
pub fn build_client_mtls_provider(ca_cert: &str) -> Result<tls::default::Client> {
222227
let tls = tls::default::Client::builder()
@@ -243,7 +248,7 @@ mod mtls {
243248
}
244249

245250
mod slow_tls {
246-
use crate::provider::tls::Provider;
251+
use s2n_quic::provider::tls::Provider;
247252
use s2n_quic_core::crypto::tls::{slow_tls::SlowEndpoint, Endpoint};
248253
pub struct SlowTlsProvider<E: Endpoint> {
249254
pub endpoint: E,
@@ -264,10 +269,10 @@ mod slow_tls {
264269
}
265270
}
266271

267-
#[cfg(feature = "s2n-quic-tls")]
268-
mod resumption {
272+
#[cfg(unix)]
273+
pub mod resumption {
269274
use super::*;
270-
use crate::provider::tls::{
275+
use s2n_quic::provider::tls::{
271276
self,
272277
s2n_tls::{
273278
callbacks::{ConnectionFuture, SessionTicket, SessionTicketCallback},
@@ -314,7 +319,7 @@ mod resumption {
314319
pub fn build_server_resumption_provider(
315320
cert: &str,
316321
key: &str,
317-
) -> Result<tls::default::Server<s2n_quic_tls_default::Server>> {
322+
) -> Result<tls::default::Server<Server>> {
318323
let mut tls = Server::builder().with_certificate(cert, key)?;
319324

320325
let config = tls.config_mut();
@@ -346,7 +351,4 @@ mod resumption {
346351
#[cfg(not(target_os = "windows"))]
347352
pub use mtls::*;
348353

349-
#[cfg(feature = "s2n-quic-tls")]
350-
pub use resumption::*;
351-
352354
pub use slow_tls::SlowTlsProvider;

quic/s2n-quic/src/tests/recorder.rs renamed to quic/s2n-quic-tests/src/recorder.rs

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,13 @@
11
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
22
// SPDX-License-Identifier: Apache-2.0
33

4-
use super::*;
4+
use crate::*;
5+
use s2n_quic::provider::event::events::{self};
6+
7+
use std::{
8+
net::SocketAddr,
9+
sync::{Arc, Mutex},
10+
};
511

612
macro_rules! event_recorder {
713
($sub:ident, $event:ident, $method:ident) => {
@@ -113,8 +119,8 @@ event_recorder!(
113119
ConnectionClosed,
114120
ConnectionClosed,
115121
on_connection_closed,
116-
crate::connection::Error,
117-
|event: &events::ConnectionClosed, storage: &mut Vec<crate::connection::Error>| {
122+
s2n_quic::connection::Error,
123+
|event: &events::ConnectionClosed, storage: &mut Vec<s2n_quic::connection::Error>| {
118124
storage.push(event.error);
119125
}
120126
);

0 commit comments

Comments
 (0)