mirror of
https://github.com/netbirdio/IronRDP.git
synced 2026-05-22 18:43:12 -07:00
test: organize integration tests into single crate
Put all integration tests in a single crate, and organized in modules. This is similar to what was done in `cargo` repository: https://github.com/rust-lang/cargo/pull/5022#issuecomment-364691154 ``` $ rustup show stable-x86_64-unknown-linux-gnu (default) rustc 1.69.0 (84c898d65 2023-04-16) ``` Run on a recent high-end laptop: 12th Gen Intel(R) Core(TM) i9-12900HK Original (multiple integration binaries): - `cargo clean && cargo test --no-run`: 62.893s - `cargo clean && cargo build --lib`: 54.959s - `cargo clean && cargo build --bins`: 55.933s - `cargo test --no-run` (after `cargo build`): 14.472s - `cargo test` (after `cargo test --no-run`): 1.786s - `du -hs target/`: 4.2G After (ironrdp-testsuite): - `cargo clean && cargo test --no-run`: 41.157s (crates with no tests are ignored) - `cargo clean && cargo build --lib`: 53.983s - `cargo clean && cargo build --bins`: 54.482s - `cargo test --no-run` (after `cargo build`): 12.915s - `cargo test` (after `cargo test --no-run`): 0.240s - `du -hs target/`: 3.4G Absolute diff: - `cargo clean && cargo test --no-run`: -21.736s - `cargo clean && cargo build --lib`: -0.976s - `cargo clean && cargo build --bins`: -1.451s - `cargo test --no-run` (after `cargo build`): -1.557s - `cargo test` (after `cargo test --no-run`): -1.546s - `du -hs target/`: -0.8G Relative diff (%): - `cargo clean && cargo test --no-run`: -34.5% - `cargo clean && cargo build --lib`: -1.77% - `cargo clean && cargo build --bins`: -2.59% - `cargo test --no-run` (after `cargo build`): -10.7% - `cargo test` (after `cargo test --no-run`): -86.5% - `du -hs target/`: -19.0%
This commit is contained in:
committed by
Benoît Cortier
parent
36a210aae9
commit
60bc72f873
+57
-18
@@ -12,50 +12,80 @@ This document describes the high-level architecture of IronRDP.
|
||||
|
||||
This section talks briefly about various important directories and data structures.
|
||||
|
||||
### Core Crates
|
||||
### Core Tier
|
||||
|
||||
Set of foundational libraries for which strict quality standards must be observed.
|
||||
Pay attention to the "**Architecture Invariant**" sections.
|
||||
|
||||
- `crates/ironrdp`: meta crate re-exporting important crates.
|
||||
- `crates/ironrdp-pdu`: PDU encoding and decoding (no I/O, trivial to fuzz). <!-- TODO: important types and traits (PduDecode, PduEncode…) -->
|
||||
- `crates/ironrdp-graphics`: image processing primitives (no I/O, trivial to fuzz).
|
||||
- `crates/ironrdp-connector`: state machines to drive an RDP connection sequence (no I/O, not _too_ hard to fuzz).
|
||||
- `crates/ironrdp-session`: state machines to drive an RDP session (no I/O, not _too_ hard to fuzz).
|
||||
- `crates/ironrdp-input`: utilities to manage and build input packets (no I/O).
|
||||
- `crates/ironrdp-pdu`: PDU encoding and decoding. (TODO: talk about important types and traits such as PduDecode, PduEncode…)
|
||||
- `crates/ironrdp-graphics`: image processing primitives.
|
||||
- `crates/ironrdp-connector`: state machines to drive an RDP connection sequence.
|
||||
- `crates/ironrdp-session`: state machines to drive an RDP session.
|
||||
- `crates/ironrdp-input`: utilities to manage and build input packets.
|
||||
- `crates/ironrdp-rdcleanpath`: RDCleanPath PDU structure used by IronRDP web client and Devolutions Gateway.
|
||||
|
||||
### Utility Crates
|
||||
**Architectural Invariant**: doing I/O is not allowed for these crates.
|
||||
|
||||
**Architectural Invariant**: all these crates must be fuzzed.
|
||||
|
||||
**Architectural Invariant**: no non-essential dependency is allowed.
|
||||
|
||||
**Architectural Invariant**: must be `#[no_std]`-compatible (eventually using the `alloc` crate). Usage of the standard
|
||||
library must be opt-in through a feature flag called `std` that is enabled by default. When the `alloc` crate is optional,
|
||||
a feature flag called `alloc` must exist to enable its use.
|
||||
|
||||
### Extra Tier
|
||||
|
||||
Higher level libraries and binaries built on top of the core tier.
|
||||
Guidelines and constraints are relaxed to some extent.
|
||||
|
||||
- `crates/ironrdp-async`: provides `Future`s wrapping the state machines conveniently.
|
||||
- `crates/ironrdp-tokio`: `Framed*` traits implementation above `tokio`’s traits.
|
||||
- `crates/ironrdp-futures`: `Framed*` traits implementation above `futures`’s traits.
|
||||
- `crates/ironrdp-tls`: TLS boilerplate common with most IronRDP clients.
|
||||
|
||||
### Client Crates
|
||||
|
||||
- `crates/ironrdp-client`: portable RDP client without GPU acceleration using softbuffer and winit for windowing.
|
||||
- `crates/ironrdp-web`: WebAssembly high-level bindings targeting web browsers.
|
||||
- `crates/ironrdp-glutin-renderer`: `glutin` primitives for OpenGL rendering.
|
||||
- `crates/ironrdp-client-glutin`: GPU-accelerated RDP client using glutin.
|
||||
- `crates/ironrdp-replay-client`: utility tool to replay RDP graphics pipeline for debugging purposes.
|
||||
- `web-client/iron-remote-gui`: core frontend UI used by `iron-svelte-client` as a Web Component.
|
||||
- `web-client/iron-svelte-client`: web-based frontend using `Svelte` and `Material` frameworks.
|
||||
|
||||
### Private Crates
|
||||
### Internal Tier
|
||||
|
||||
Crates that are only used inside the IronRDP project, not meant to be published.
|
||||
This is mostly test case generators, fuzzing oracles, build tools, and so on.
|
||||
|
||||
- `crates/ironrdp-pdu-generators`: `proptest` generators for `ironrdp-pdu` types.
|
||||
- `crates/ironrdp-session-generators`: `proptest` generators for `ironrdp-session` types.
|
||||
- `fuzz`: fuzz targets for core crates.
|
||||
- `crates/ironrdp-testsuite-core`: contains all integration tests for code living in the core tier, in a single binary,
|
||||
organized in modules. **Architectural Invariant**: no dependency from another tier is allowed.
|
||||
It must be the case that compiling and running the core test suite does not require building any library from
|
||||
the extra tier. This is to keep iteration time short.
|
||||
- `crates/ironrdp-testsuite-extra`: contains all integration tests for code living in the extra tier, in a single binary,
|
||||
organized in modules. (WIP: this crate does not exist yet.)
|
||||
- `crates/ironrdp-fuzzing`: provides test case generators and oracles for use with fuzzing.
|
||||
- `fuzz`: fuzz targets for code in core tier.
|
||||
- `xtask`: IronRDP’s free-form automation using Rust code.
|
||||
|
||||
**Architecture Invariant**: these crates are not, and will never be, an **API Boundary**.
|
||||
|
||||
### Community Tier
|
||||
|
||||
Crates provided and maintained by the community.
|
||||
Core maintainers will not invest a lot of time into these.
|
||||
One or several community maintainers are associated to each one
|
||||
|
||||
- `crates/ironrdp-glutin-renderer` (no maintainer): `glutin` primitives for OpenGL rendering.
|
||||
- `crates/ironrdp-client-glutin` (no maintainer): GPU-accelerated RDP client using glutin.
|
||||
- `crates/ironrdp-replay-client` (no maintainer): utility tool to replay RDP graphics pipeline for debugging purposes.
|
||||
|
||||
## Cross-Cutting Concerns
|
||||
|
||||
This section talks about the things which are everywhere and nowhere in particular.
|
||||
|
||||
### General
|
||||
|
||||
- Dependency injection when runtime information is necessary in core crates (no system call such as `gethostname`)
|
||||
- Keep non-portable code out of core crates
|
||||
- Dependency injection when runtime information is necessary in core tier crates (no system call such as `gethostname`)
|
||||
- Keep non-portable code out of core tier crates
|
||||
- Make crate `no_std`-compatible wherever possible
|
||||
- Facilitate fuzzing
|
||||
- In libraries, provide concrete error types either hand-crafted or using `thiserror` crate
|
||||
@@ -64,7 +94,7 @@ This section talks about the things which are everywhere and nowhere in particul
|
||||
|
||||
### Avoid I/O wherever possible
|
||||
|
||||
**Architecture Invariant**: core crates must never interact with the outside world. Only client and utility crates
|
||||
**Architecture Invariant**: core tier crates must never interact with the outside world. Only extra tier crates
|
||||
such as `ironrdp-client`, `ironrdp-web` or `ironrdp-async` are allowed to do I/O.
|
||||
|
||||
### Continuous integration
|
||||
@@ -77,6 +107,15 @@ be the case that a successful `cargo xtask ci` run implies a successful CI workf
|
||||
|
||||
### Testing
|
||||
|
||||
#### Test at the boundaries (test features, not code)
|
||||
|
||||
We should focus on testing the public API of libraries (keyword: **API boundary**).
|
||||
That’s why most (if not all) tests should go into the `ironrdp-testsuite-core` and `ironrdp-testsuite-extra` crates.
|
||||
|
||||
#### Do not depend on external resources
|
||||
|
||||
**Architecture Invariant**: tests do not depend on any kind of external resources, they are perfectly reproducible.
|
||||
|
||||
#### Fuzzing
|
||||
|
||||
See [`fuzz/README.md`](../fuzz/README.md).
|
||||
|
||||
Generated
+23
-20
@@ -1574,9 +1574,6 @@ dependencies = [
|
||||
"lazy_static",
|
||||
"num-derive 0.3.3",
|
||||
"num-traits",
|
||||
"proptest",
|
||||
"rdp-rs",
|
||||
"rstest",
|
||||
"thiserror",
|
||||
]
|
||||
|
||||
@@ -1584,11 +1581,8 @@ dependencies = [
|
||||
name = "ironrdp-input"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"bitvec",
|
||||
"ironrdp-pdu",
|
||||
"proptest",
|
||||
"rstest",
|
||||
"smallvec",
|
||||
]
|
||||
|
||||
@@ -1601,7 +1595,7 @@ dependencies = [
|
||||
"byteorder",
|
||||
"der-parser 8.2.0",
|
||||
"expect-test",
|
||||
"ironrdp-pdu-samples",
|
||||
"ironrdp-testsuite-core",
|
||||
"lazy_static",
|
||||
"md-5 0.10.5",
|
||||
"num-bigint 0.4.3",
|
||||
@@ -1622,24 +1616,11 @@ dependencies = [
|
||||
"proptest",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ironrdp-pdu-samples"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"array-concat",
|
||||
"ironrdp-pdu",
|
||||
"lazy_static",
|
||||
"paste",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ironrdp-rdcleanpath"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"der 0.7.5",
|
||||
"hex",
|
||||
"pretty_assertions",
|
||||
"rstest",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1663,6 +1644,28 @@ dependencies = [
|
||||
"proptest",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ironrdp-testsuite-core"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"arbitrary",
|
||||
"array-concat",
|
||||
"hex",
|
||||
"ironrdp-connector",
|
||||
"ironrdp-graphics",
|
||||
"ironrdp-input",
|
||||
"ironrdp-pdu",
|
||||
"ironrdp-rdcleanpath",
|
||||
"ironrdp-session",
|
||||
"lazy_static",
|
||||
"paste",
|
||||
"pretty_assertions",
|
||||
"proptest",
|
||||
"rdp-rs",
|
||||
"rstest",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ironrdp-tls"
|
||||
version = "0.1.0"
|
||||
|
||||
+1
-1
@@ -28,11 +28,11 @@ ironrdp-futures = { version = "0.1", path = "crates/ironrdp-futures" }
|
||||
ironrdp-graphics = { version = "0.1", path = "crates/ironrdp-graphics" }
|
||||
ironrdp-input = { version = "0.1", path = "crates/ironrdp-input" }
|
||||
ironrdp-pdu-generators = { path = "crates/ironrdp-pdu-generators" }
|
||||
ironrdp-pdu-samples = { path = "crates/ironrdp-pdu-samples" }
|
||||
ironrdp-pdu = { version = "0.1", path = "crates/ironrdp-pdu" }
|
||||
ironrdp-rdcleanpath = { version = "0.1", path = "crates/ironrdp-rdcleanpath" }
|
||||
ironrdp-session-generators = { path = "crates/ironrdp-session-generators" }
|
||||
ironrdp-session = { version = "0.1", path = "crates/ironrdp-session" }
|
||||
ironrdp-testsuite-core = { path = "crates/ironrdp-testsuite-core" }
|
||||
ironrdp-tls = { version = "0.1", path = "crates/ironrdp-tls" }
|
||||
ironrdp-tokio = { version = "0.1", path = "crates/ironrdp-tokio" }
|
||||
ironrdp = { version = "0.5", path = "crates/ironrdp" }
|
||||
|
||||
@@ -11,6 +11,10 @@ authors.workspace = true
|
||||
keywords.workspace = true
|
||||
categories.workspace = true
|
||||
|
||||
[lib]
|
||||
doctest = false
|
||||
test = false
|
||||
|
||||
[dependencies]
|
||||
bytes = "1"
|
||||
ironrdp-connector.workspace = true
|
||||
|
||||
@@ -12,6 +12,14 @@ keywords.workspace = true
|
||||
categories.workspace = true
|
||||
default-run = "ironrdp-client"
|
||||
|
||||
[lib]
|
||||
doctest = false
|
||||
test = false
|
||||
|
||||
[[bin]]
|
||||
name = "ironrdp-client"
|
||||
test = false
|
||||
|
||||
[features]
|
||||
default = ["rustls"]
|
||||
rustls = ["ironrdp-tls/rustls"]
|
||||
|
||||
@@ -11,6 +11,10 @@ authors.workspace = true
|
||||
keywords.workspace = true
|
||||
categories.workspace = true
|
||||
|
||||
[lib]
|
||||
doctest = false
|
||||
test = false
|
||||
|
||||
[features]
|
||||
arbitrary = ["dep:arbitrary"]
|
||||
|
||||
|
||||
@@ -52,32 +52,3 @@ fn sanitize_server_name(name: impl Into<String>) -> String {
|
||||
name
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use rstest::rstest;
|
||||
|
||||
use super::*;
|
||||
|
||||
#[rstest]
|
||||
#[case("somehostname:2345", "somehostname")]
|
||||
#[case("192.168.56.101:2345", "192.168.56.101")]
|
||||
#[case("[2001:db8::8a2e:370:7334]:7171", "2001:db8::8a2e:370:7334")]
|
||||
#[case("[2001:0db8:0000:0000:0000:8a2e:0370:7334]:433", "2001:db8::8a2e:370:7334")]
|
||||
#[case("[::1]:2222", "::1")]
|
||||
fn input_with_port(#[case] input: &str, #[case] expected: &str) {
|
||||
let result = sanitize_server_name(input);
|
||||
assert_eq!(result, expected);
|
||||
}
|
||||
|
||||
#[rstest]
|
||||
#[case("somehostname")]
|
||||
#[case("192.168.56.101")]
|
||||
#[case("2001:db8::8a2e:370:7334")]
|
||||
#[case("2001:0db8:0000:0000:0000:8a2e:0370:7334")]
|
||||
#[case("::1")]
|
||||
fn input_without_port(#[case] input: &str) {
|
||||
let result = sanitize_server_name(input);
|
||||
assert_eq!(result, input);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,6 +11,10 @@ authors.workspace = true
|
||||
keywords.workspace = true
|
||||
categories.workspace = true
|
||||
|
||||
[lib]
|
||||
doctest = false
|
||||
test = false
|
||||
|
||||
[dependencies]
|
||||
bytes = "1"
|
||||
futures-util = { version = "0.3.26", features = ["io"] }
|
||||
|
||||
@@ -4,6 +4,7 @@ use std::pin::Pin;
|
||||
use bytes::BytesMut;
|
||||
use futures_util::io::{AsyncRead, AsyncWrite};
|
||||
|
||||
#[rustfmt::skip] // do not re-order this pub use
|
||||
pub use ironrdp_async::*;
|
||||
|
||||
pub type FuturesFramed<S> = Framed<FuturesStream<S>>;
|
||||
|
||||
@@ -11,6 +11,10 @@ authors.workspace = true
|
||||
keywords.workspace = true
|
||||
categories.workspace = true
|
||||
|
||||
[lib]
|
||||
doctest = false
|
||||
# test = false
|
||||
|
||||
[dependencies]
|
||||
ironrdp-pdu.workspace = true
|
||||
num-traits = "0.2.15"
|
||||
@@ -25,6 +29,3 @@ lazy_static = "1.4.0"
|
||||
[dev-dependencies]
|
||||
bmp = "0.5"
|
||||
expect-test.workspace = true
|
||||
proptest = "1.1.0"
|
||||
rdp-rs = { git = "https://github.com/citronneur/rdp-rs", rev = "7ac880d7efb7f05efef3c84476f7c24f4053e0ea" }
|
||||
rstest = "0.17.0"
|
||||
|
||||
@@ -1,13 +1,10 @@
|
||||
use crate::{
|
||||
color_conversion::{Rgb, YCoCg},
|
||||
rdp6::rle::{decompress_8bpp_plane, RleError},
|
||||
};
|
||||
use ironrdp_pdu::{
|
||||
bitmap::rdp6::{BitmapStream as BitmapStreamPdu, ColorPlanes},
|
||||
decode, Error as PduError,
|
||||
};
|
||||
use ironrdp_pdu::bitmap::rdp6::{BitmapStream as BitmapStreamPdu, ColorPlanes};
|
||||
use ironrdp_pdu::{decode, Error as PduError};
|
||||
use thiserror::Error;
|
||||
|
||||
use crate::color_conversion::{Rgb, YCoCg};
|
||||
use crate::rdp6::rle::{decompress_8bpp_plane, RleError};
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
pub enum BitmapDecodeError {
|
||||
#[error("Failed to decode RDP6 bitmap stream PDU: {0}")]
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
use byteorder::ReadBytesExt;
|
||||
use std::io::{Read, Write};
|
||||
|
||||
use byteorder::ReadBytesExt;
|
||||
use thiserror::Error;
|
||||
|
||||
/// Maximum possible segment size is 47 (run_length = 2, raw_bytes_count = 15), which is treated as
|
||||
@@ -160,10 +161,10 @@ pub fn decompress_8bpp_plane(
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
use expect_test::expect;
|
||||
|
||||
use super::*;
|
||||
|
||||
/// Performs decompression of 8bpp color plane into vector. Vector will be resized to fit decompressed data.
|
||||
pub fn decompress(
|
||||
src: &[u8],
|
||||
|
||||
@@ -11,12 +11,11 @@ authors.workspace = true
|
||||
keywords.workspace = true
|
||||
categories.workspace = true
|
||||
|
||||
[lib]
|
||||
doctest = false
|
||||
test = false
|
||||
|
||||
[dependencies]
|
||||
ironrdp-pdu.workspace = true
|
||||
bitvec = "1.0.1"
|
||||
smallvec = "1.10.0"
|
||||
|
||||
[dev-dependencies]
|
||||
proptest.workspace = true
|
||||
rstest.workspace = true
|
||||
anyhow = "1"
|
||||
smallvec = "1.10.0"
|
||||
@@ -5,6 +5,10 @@ edition = "2021"
|
||||
description = "`proptest` generators for `ironrdp-pdu` types"
|
||||
publish = false
|
||||
|
||||
[lib]
|
||||
doctest = false
|
||||
test = false
|
||||
|
||||
[dependencies]
|
||||
ironrdp-pdu.workspace = true
|
||||
proptest.workspace = true
|
||||
|
||||
@@ -1,14 +1 @@
|
||||
pub fn add(left: usize, right: usize) -> usize {
|
||||
left + right
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn it_works() {
|
||||
let result = add(2, 2);
|
||||
assert_eq!(result, 4);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,11 +0,0 @@
|
||||
[package]
|
||||
name = "ironrdp-pdu-samples"
|
||||
version = "0.0.0"
|
||||
edition = "2021"
|
||||
publish = false
|
||||
|
||||
[dependencies]
|
||||
ironrdp-pdu.workspace = true
|
||||
array-concat = "0.5.2"
|
||||
lazy_static = "1.4.0"
|
||||
paste = "1"
|
||||
@@ -11,6 +11,10 @@ authors.workspace = true
|
||||
keywords.workspace = true
|
||||
categories.workspace = true
|
||||
|
||||
[lib]
|
||||
doctest = false
|
||||
# test = false
|
||||
|
||||
[features]
|
||||
default = []
|
||||
std = []
|
||||
@@ -34,5 +38,5 @@ x509-cert = { version = "0.2.1", default-features = false, features = ["std"] }
|
||||
|
||||
[dev-dependencies]
|
||||
expect-test.workspace = true
|
||||
ironrdp-pdu-samples.workspace = true
|
||||
ironrdp-testsuite-core.workspace = true # TODO: move more tests under ironrdp-testsuite-core itself
|
||||
lazy_static = "1.4.0"
|
||||
|
||||
@@ -136,9 +136,10 @@ impl<'a> PduEncode for BitmapStream<'a> {
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use expect_test::{expect, Expect};
|
||||
|
||||
use super::*;
|
||||
use crate::{decode, encode_buf, PduEncode};
|
||||
use expect_test::{expect, Expect};
|
||||
|
||||
fn assert_roundtrip(buffer: &[u8], expected: Expect) {
|
||||
let pdu = decode::<BitmapStream>(buffer).unwrap();
|
||||
|
||||
@@ -11,10 +11,9 @@ authors.workspace = true
|
||||
keywords.workspace = true
|
||||
categories.workspace = true
|
||||
|
||||
[dependencies]
|
||||
der = { version = "0.7.1", features = ["alloc", "derive"] }
|
||||
[lib]
|
||||
doctest = false
|
||||
test = false
|
||||
|
||||
[dev-dependencies]
|
||||
rstest = "0.17.0"
|
||||
hex = "0.4.3"
|
||||
pretty_assertions = "1.3.0"
|
||||
[dependencies]
|
||||
der = { version = "0.7.1", features = ["alloc", "derive"] }
|
||||
@@ -2,14 +2,15 @@ use core::fmt;
|
||||
|
||||
use der::asn1::OctetString;
|
||||
|
||||
// Re-export der crate for convenience
|
||||
#[rustfmt::skip] // do not re-order this pub use
|
||||
pub use der;
|
||||
|
||||
pub const BASE_VERSION: u64 = 3389;
|
||||
pub const VERSION_1: u64 = BASE_VERSION + 1;
|
||||
|
||||
pub const GENERAL_ERROR_CODE: u16 = 1;
|
||||
|
||||
// Re-export der crate for convenience
|
||||
pub use der;
|
||||
|
||||
#[derive(Clone, Debug, Eq, PartialEq, der::Sequence)]
|
||||
#[asn1(tag_mode = "EXPLICIT")]
|
||||
pub struct RDCleanPathErr {
|
||||
@@ -358,129 +359,3 @@ impl From<RDCleanPath> for RDCleanPathPdu {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use rstest::rstest;
|
||||
|
||||
use super::*;
|
||||
|
||||
fn request() -> RDCleanPathPdu {
|
||||
RDCleanPathPdu::new_request(
|
||||
vec![0xDE, 0xAD, 0xBE, 0xFF],
|
||||
"destination".to_owned(),
|
||||
"proxy auth".to_owned(),
|
||||
Some("PCB".to_owned()),
|
||||
)
|
||||
.unwrap()
|
||||
}
|
||||
|
||||
const REQUEST_DER: &[u8] = &[
|
||||
0x30, 0x32, 0xA0, 0x4, 0x2, 0x2, 0xD, 0x3E, 0xA2, 0xD, 0xC, 0xB, 0x64, 0x65, 0x73, 0x74, 0x69, 0x6E, 0x61,
|
||||
0x74, 0x69, 0x6F, 0x6E, 0xA3, 0xC, 0xC, 0xA, 0x70, 0x72, 0x6F, 0x78, 0x79, 0x20, 0x61, 0x75, 0x74, 0x68, 0xA5,
|
||||
0x5, 0xC, 0x3, 0x50, 0x43, 0x42, 0xA6, 0x6, 0x4, 0x4, 0xDE, 0xAD, 0xBE, 0xFF,
|
||||
];
|
||||
|
||||
fn response_success() -> RDCleanPathPdu {
|
||||
RDCleanPathPdu::new_response(
|
||||
"192.168.7.95".to_owned(),
|
||||
vec![0xDE, 0xAD, 0xBE, 0xFF],
|
||||
[
|
||||
vec![0xDE, 0xAD, 0xBE, 0xFF],
|
||||
vec![0xDE, 0xAD, 0xBE, 0xFF],
|
||||
vec![0xDE, 0xAD, 0xBE, 0xFF],
|
||||
],
|
||||
)
|
||||
.unwrap()
|
||||
}
|
||||
|
||||
const RESPONSE_SUCCESS_DER: &[u8] = &[
|
||||
0x30, 0x34, 0xA0, 0x4, 0x2, 0x2, 0xD, 0x3E, 0xA6, 0x6, 0x4, 0x4, 0xDE, 0xAD, 0xBE, 0xFF, 0xA7, 0x14, 0x30,
|
||||
0x12, 0x4, 0x4, 0xDE, 0xAD, 0xBE, 0xFF, 0x4, 0x4, 0xDE, 0xAD, 0xBE, 0xFF, 0x4, 0x4, 0xDE, 0xAD, 0xBE, 0xFF,
|
||||
0xA9, 0xE, 0xC, 0xC, 0x31, 0x39, 0x32, 0x2E, 0x31, 0x36, 0x38, 0x2E, 0x37, 0x2E, 0x39, 0x35,
|
||||
];
|
||||
|
||||
fn response_http_error() -> RDCleanPathPdu {
|
||||
RDCleanPathPdu::new_http_error(500)
|
||||
}
|
||||
|
||||
const RESPONSE_HTTP_ERROR_DER: &[u8] = &[
|
||||
0x30, 0x15, 0xA0, 0x4, 0x2, 0x2, 0xD, 0x3E, 0xA1, 0xD, 0x30, 0xB, 0xA0, 0x3, 0x2, 0x1, 0x1, 0xA1, 0x4, 0x2,
|
||||
0x2, 0x1, 0xF4,
|
||||
];
|
||||
|
||||
fn response_tls_error() -> RDCleanPathPdu {
|
||||
RDCleanPathPdu::new_tls_error(48)
|
||||
}
|
||||
|
||||
const RESPONSE_TLS_ERROR_DER: &[u8] = &[
|
||||
0x30, 0x14, 0xA0, 0x04, 0x02, 0x02, 0x0D, 0x3E, 0xA1, 0x0C, 0x30, 0x0A, 0xA0, 0x03, 0x02, 0x01, 0x01, 0xA3,
|
||||
0x03, 0x02, 0x01, 0x30,
|
||||
];
|
||||
|
||||
#[rstest]
|
||||
#[case(request())]
|
||||
#[case(response_success())]
|
||||
#[case(response_http_error())]
|
||||
#[case(response_tls_error())]
|
||||
fn smoke(#[case] message: RDCleanPathPdu) {
|
||||
let encoded = message.to_der().unwrap();
|
||||
let decoded = RDCleanPathPdu::from_der(&encoded).unwrap();
|
||||
assert_eq!(message, decoded);
|
||||
}
|
||||
|
||||
macro_rules! assert_serialization {
|
||||
($left:expr, $right:expr) => {{
|
||||
if $left != $right {
|
||||
let left = hex::encode(&$left);
|
||||
let right = hex::encode(&$right);
|
||||
let comparison = pretty_assertions::StrComparison::new(&left, &right);
|
||||
panic!(
|
||||
"assertion failed: `({} == {})`\n\n{comparison}",
|
||||
stringify!($left),
|
||||
stringify!($right),
|
||||
);
|
||||
}
|
||||
}};
|
||||
}
|
||||
|
||||
#[rstest]
|
||||
#[case(request(), REQUEST_DER)]
|
||||
#[case(response_success(), RESPONSE_SUCCESS_DER)]
|
||||
#[case(response_http_error(), RESPONSE_HTTP_ERROR_DER)]
|
||||
#[case(response_tls_error(), RESPONSE_TLS_ERROR_DER)]
|
||||
fn serialization(#[case] message: RDCleanPathPdu, #[case] expected_der: &[u8]) {
|
||||
let encoded = message.to_der().unwrap();
|
||||
assert_serialization!(encoded, expected_der);
|
||||
}
|
||||
|
||||
#[rstest]
|
||||
#[case(REQUEST_DER)]
|
||||
#[case(RESPONSE_SUCCESS_DER)]
|
||||
#[case(RESPONSE_HTTP_ERROR_DER)]
|
||||
#[case(RESPONSE_TLS_ERROR_DER)]
|
||||
fn detect(#[case] der: &[u8]) {
|
||||
let result = RDCleanPathPdu::detect(der);
|
||||
|
||||
let DetectionResult::Detected { version: detected_version, total_length: detected_length } = result else {
|
||||
panic!("unexpected result: {result:?}");
|
||||
};
|
||||
|
||||
assert_eq!(detected_version, VERSION_1);
|
||||
assert_eq!(detected_length, der.len());
|
||||
}
|
||||
|
||||
#[rstest]
|
||||
#[case(&[])]
|
||||
#[case(&[0x30])]
|
||||
#[case(&[0x30, 0x15])]
|
||||
#[case(&[0x30, 0x15, 0xA0])]
|
||||
#[case(&[0x30, 0x32, 0xA0, 0x4])]
|
||||
#[case(&[0x30, 0x32, 0xA0, 0x4, 0x2])]
|
||||
#[case(&[0x30, 0x32, 0xA0, 0x4, 0x2, 0x2])]
|
||||
#[case(&[0x30, 0x32, 0xA0, 0x4, 0x2, 0x2, 0xD])]
|
||||
fn detect_not_enough(#[case] payload: &[u8]) {
|
||||
let result = RDCleanPathPdu::detect(payload);
|
||||
assert_eq!(result, DetectionResult::NotEnoughBytes);
|
||||
}
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user