From 983dca419bb61475f6c8e95a09efec28bd34630c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rog=C3=A9rio=20Ara=C3=BAjo?= Date: Mon, 9 Feb 2026 22:35:45 -0300 Subject: [PATCH 01/15] docs: added badges --- README.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/README.md b/README.md index 2a1c91b..844af17 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,10 @@ # EasyHttpMock +[![crates.io](https://img.shields.io/crates/v/easyhttpmock?style=flat-square)](https://crates.io/crates/easyhttpmock) +[![Build Status](https://github.com/ararog/easyhttpmock/actions/workflows/rust.yml/badge.svg?event=push)](https://github.com/ararog/easyhttpmock/actions/workflows/rust.yml) +[![Documentation](https://docs.rs/easyhttpmock/badge.svg)](https://docs.rs/easyhttpmock/latest/easyhttpmock) +[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT) + **The effortless HTTP mock server for seamless API testing** **EasyHttpMock** is a powerful yet simple HTTP mock server designed specifically for testing HTTP clients. Built on top of [VeTiS](https://github.com/ararog/vetis), it provides a clean, intuitive API for creating realistic mock endpoints that simulate real-world API behavior, making your testing workflow faster and more reliable. From ae70fcee68eb784fafa71a99d5caf8d9cb4cb728 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rog=C3=A9rio=20Ara=C3=BAjo?= Date: Tue, 10 Feb 2026 09:07:09 -0300 Subject: [PATCH 02/15] docs: updated badges --- README.md | 6 ++---- docs/index.md | 5 +---- 2 files changed, 3 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 844af17..96c3d2c 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,7 @@ # EasyHttpMock -[![crates.io](https://img.shields.io/crates/v/easyhttpmock?style=flat-square)](https://crates.io/crates/easyhttpmock) -[![Build Status](https://github.com/ararog/easyhttpmock/actions/workflows/rust.yml/badge.svg?event=push)](https://github.com/ararog/easyhttpmock/actions/workflows/rust.yml) -[![Documentation](https://docs.rs/easyhttpmock/badge.svg)](https://docs.rs/easyhttpmock/latest/easyhttpmock) -[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT) +[![Crates.io downloads](https://img.shields.io/crates/d/easyhttpmock)](https://crates.io/crates/easyhttpmock) [![crates.io](https://img.shields.io/crates/v/easyhttpmock?style=flat-square)](https://crates.io/crates/easyhttpmock) [![Build Status](https://github.com/ararog/easyhttpmock/actions/workflows/rust.yml/badge.svg?event=push)](https://github.com/ararog/easyhttpmock/actions/workflows/rust.yml) ![Crates.io MSRV](https://img.shields.io/crates/msrv/easyhttpmock) [![Documentation](https://docs.rs/easyhttpmock/badge.svg)](https://docs.rs/easyhttpmock/latest/easyhttpmock) [![MIT licensed](https://img.shields.io/badge/license-MIT-blue.svg)](https://github.com/ararog/easyhttpmock/blob/main/LICENSE.md) [![codecov](https://codecov.io/gh/ararog/easyhttpmock/graph/badge.svg?token=T0HSBAPVSI)](https://codecov.io/gh/ararog/easyhttpmock) + **The effortless HTTP mock server for seamless API testing** diff --git a/docs/index.md b/docs/index.md index c25cc73..6288854 100644 --- a/docs/index.md +++ b/docs/index.md @@ -9,10 +9,7 @@ permalink: /

EasyHttpMock

-[![crates.io](https://img.shields.io/crates/v/easyhttpmock?style=flat-square)](https://crates.io/crates/easyhttpmock) -[![Build Status](https://github.com/ararog/easyhttpmock/actions/workflows/rust.yml/badge.svg?event=push)](https://github.com/ararog/easyhttpmock/actions/workflows/rust.yml) -[![Documentation](https://docs.rs/easyhttpmock/badge.svg)](https://docs.rs/easyhttpmock/latest/easyhttpmock) -[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT) +[![Crates.io downloads](https://img.shields.io/crates/d/easyhttpmock)](https://crates.io/crates/easyhttpmock) [![crates.io](https://img.shields.io/crates/v/easyhttpmock?style=flat-square)](https://crates.io/crates/easyhttpmock) [![Build Status](https://github.com/ararog/easyhttpmock/actions/workflows/rust.yml/badge.svg?event=push)](https://github.com/ararog/easyhttpmock/actions/workflows/rust.yml) ![Crates.io MSRV](https://img.shields.io/crates/msrv/easyhttpmock) [![Documentation](https://docs.rs/easyhttpmock/badge.svg)](https://docs.rs/easyhttpmock/latest/easyhttpmock) [![MIT licensed](https://img.shields.io/badge/license-MIT-blue.svg)](https://github.com/ararog/easyhttpmock/blob/main/LICENSE.md) [![codecov](https://codecov.io/gh/ararog/easyhttpmock/graph/badge.svg?token=T0HSBAPVSI)](https://codecov.io/gh/ararog/easyhttpmock) **EasyHttpMock** is a powerful yet simple HTTP mock server designed specifically for testing HTTP clients. Built on top of [VeTiS](https://github.com/ararog/vetis), it provides a clean, intuitive API for creating realistic mock endpoints that simulate real-world API behavior, making your testing workflow faster and more reliable. From 46c1765b8fe361493576a175406df523cb65101c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rog=C3=A9rio=20Ara=C3=BAjo?= Date: Wed, 11 Feb 2026 14:21:54 -0300 Subject: [PATCH 03/15] feat: make possible set another mock server hostname --- Cargo.lock | 2 +- Cargo.toml | 2 +- src/server/adapters/vetis_adapter.rs | 168 ++++++++++++++++++++++++++- src/server/mod.rs | 45 +++++++ 4 files changed, 211 insertions(+), 6 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index fee3a16..074aae4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -610,7 +610,7 @@ checksum = "92773504d58c093f6de2459af4af33faa518c13451eb8f2b5698ed3d36e7c813" [[package]] name = "easyhttpmock" -version = "0.1.3-beta.1" +version = "0.1.3-beta.2" dependencies = [ "bytes", "http", diff --git a/Cargo.toml b/Cargo.toml index e4183fc..20fa9ac 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "easyhttpmock" -version = "0.1.3-beta.1" +version = "0.1.3-beta.2" edition = "2021" authors = ["Rogerio Araújo "] repository = "https://github.com/ararog/easyhttpmock" diff --git a/src/server/adapters/vetis_adapter.rs b/src/server/adapters/vetis_adapter.rs index d317ad9..09b3001 100644 --- a/src/server/adapters/vetis_adapter.rs +++ b/src/server/adapters/vetis_adapter.rs @@ -17,7 +17,9 @@ use crate::{ EasyHttpMock, }; +/// Builder for VetisAdapterConfig pub struct VetisAdapterConfigBuilder { + hostname: Option, interface: String, port: u16, cert: Option>, @@ -26,33 +28,85 @@ pub struct VetisAdapterConfigBuilder { } impl VetisAdapterConfigBuilder { + /// Sets the hostname for the server. + /// + /// # Arguments + /// * `hostname` - The hostname to set. + /// + /// # Returns + /// A new `VetisAdapterConfigBuilder` instance with the hostname set. + pub fn hostname(mut self, hostname: Option) -> Self { + self.hostname = hostname; + self + } + + /// Sets the interface for the server. + /// + /// # Arguments + /// * `interface` - The interface to set. + /// + /// # Returns + /// A new `VetisAdapterConfigBuilder` instance with the interface set. pub fn interface(mut self, interface: &str) -> Self { self.interface = interface.to_string(); self } + /// Sets the port for the server. + /// + /// # Arguments + /// * `port` - The port to set. + /// + /// # Returns + /// A new `VetisAdapterConfigBuilder` instance with the port set. pub fn port(mut self, port: u16) -> Self { self.port = port; self } + /// Sets the certificate for the server. + /// + /// # Arguments + /// * `cert` - The certificate to set. + /// + /// # Returns + /// A new `VetisAdapterConfigBuilder` instance with the certificate set. pub fn cert(mut self, cert: Option>) -> Self { self.cert = cert; self } + /// Sets the key for the server. + /// + /// # Arguments + /// * `key` - The key to set. + /// + /// # Returns + /// A new `VetisAdapterConfigBuilder` instance with the key set. pub fn key(mut self, key: Option>) -> Self { self.key = key; self } + /// Sets the CA certificate for the server. + /// + /// # Arguments + /// * `ca` - The CA certificate to set. + /// + /// # Returns + /// A new `VetisAdapterConfigBuilder` instance with the CA certificate set. pub fn ca(mut self, ca: Option>) -> Self { self.ca = ca; self } + /// Builds the VetisAdapterConfig from the builder. + /// + /// # Returns + /// A new `VetisAdapterConfig` instance. pub fn build(self) -> VetisAdapterConfig { VetisAdapterConfig { + hostname: self.hostname, interface: self.interface, port: self.port, cert: self.cert, @@ -62,8 +116,10 @@ impl VetisAdapterConfigBuilder { } } +/// Configuration for the Vetis adapter. #[derive(Clone)] pub struct VetisAdapterConfig { + hostname: Option, interface: String, port: u16, cert: Option>, @@ -72,14 +128,40 @@ pub struct VetisAdapterConfig { } impl Default for VetisAdapterConfig { + /// Creates a default configuration for the Vetis adapter. + /// + /// This function sets up a basic server configuration with: + /// - Interface: "0.0.0.0" + /// - Port: 80 + /// - No TLS certificates (HTTP only) + /// + /// # Returns + /// A default `VetisAdapterConfig` instance. fn default() -> Self { - Self { interface: "0.0.0.0".into(), port: 80, cert: None, key: None, ca: None } + Self { + hostname: None, + interface: "0.0.0.0".into(), + port: 80, + cert: None, + key: None, + ca: None, + } } } impl VetisAdapterConfig { + /// Creates a new builder for the Vetis adapter configuration. + /// + /// This function sets up a basic server configuration with: + /// - Interface: "0.0.0.0" + /// - Port: 80 + /// - No TLS certificates (HTTP only) + /// + /// # Returns + /// A new `VetisAdapterConfigBuilder` instance. pub fn builder() -> VetisAdapterConfigBuilder { VetisAdapterConfigBuilder { + hostname: None, interface: "0.0.0.0".into(), port: 80, cert: None, @@ -88,22 +170,50 @@ impl VetisAdapterConfig { } } + /// Returns the hostname of the server. + /// + /// # Returns + /// The hostname of the server. + pub fn hostname(&self) -> &Option { + &self.hostname + } + + /// Returns the interface of the server. + /// + /// # Returns + /// The interface of the server. pub fn interface(&self) -> &str { &self.interface } + /// Returns the port of the server. + /// + /// # Returns + /// The port of the server. pub fn port(&self) -> u16 { self.port } + /// Returns the certificate of the server. + /// + /// # Returns + /// The certificate of the server. pub fn cert(&self) -> &Option> { &self.cert } + /// Returns the key of the server. + /// + /// # Returns + /// The key of the server. pub fn key(&self) -> &Option> { &self.key } + /// Returns the CA certificate of the server. + /// + /// # Returns + /// The CA certificate of the server. pub fn ca(&self) -> &Option> { &self.ca } @@ -134,6 +244,15 @@ impl PortGenerator for VetisAdapterConfigBuilder { } impl Default for EasyHttpMockConfig { + /// Creates a default configuration for the Vetis adapter. + /// + /// This function sets up a basic server configuration with: + /// - Interface: "0.0.0.0" + /// - Port: 80 + /// - No TLS certificates (HTTP only) + /// + /// # Returns + /// A default `EasyHttpMockConfig` configured for the Vetis adapter. fn default() -> Self { let server_config = VetisAdapterConfig::builder() .interface("0.0.0.0") @@ -158,6 +277,13 @@ impl Default for EasyHttpMock { impl ServerAdapter for VetisAdapter { type Config = VetisAdapterConfig; + /// Creates a new VetisAdapter instance. + /// + /// # Arguments + /// * `config` - The configuration for the adapter. + /// + /// # Returns + /// A new `VetisAdapter` instance. fn new(config: Self::Config) -> Result { let vetis_config = config .clone() @@ -168,22 +294,50 @@ impl ServerAdapter for VetisAdapter { Ok(Self { server, config }) } + /// Returns the hostname of the server. + /// + /// # Returns + /// The hostname of the server. + fn hostname(&self) -> String { + self.config + .hostname() + .clone() + .unwrap_or_else(|| "localhost".to_string()) + } + + /// Returns the base URL of the server. + /// + /// # Returns + /// The base URL of the server. fn base_url(&self) -> String { + let hostname = self.hostname(); + if self .config .cert .is_some() { - format!("https://localhost:{}", self.config.port()) + format!("https://{}:{}", hostname, self.config.port()) } else { - format!("http://localhost:{}", self.config.port()) + format!("http://{}:{}", hostname, self.config.port()) } } + /// Returns the configuration of the server. + /// + /// # Returns + /// The configuration of the server. fn config(&self) -> &Self::Config { &self.config } + /// Starts the server with the given handler. + /// + /// # Arguments + /// * `handler` - The handler to use for the server. + /// + /// # Returns + /// A result indicating whether the server started successfully. async fn start(&mut self, handler: H) -> Result<(), EasyHttpMockError> where H: Fn(Request) -> Fut + Send + Sync + 'static, @@ -195,8 +349,10 @@ impl ServerAdapter for VetisAdapter { .build() .unwrap(); + let hostname = self.hostname(); + let host_config = VirtualHostConfig::builder() - .hostname("localhost") + .hostname(&hostname) .port(self.config.port()); let host_config = if let Some(((cert, key), ca)) = self @@ -241,6 +397,10 @@ impl ServerAdapter for VetisAdapter { .map_err(|e| EasyHttpMockError::Server(ServerError::Start(e.to_string()))) } + /// Stops the server. + /// + /// # Returns + /// A result indicating whether the server stopped successfully. async fn stop(&mut self) -> Result<(), EasyHttpMockError> { self.server .stop() diff --git a/src/server/mod.rs b/src/server/mod.rs index 3250ba9..52fa762 100644 --- a/src/server/mod.rs +++ b/src/server/mod.rs @@ -6,22 +6,67 @@ use crate::errors::EasyHttpMockError; pub mod adapters; +/// Server adapter trait to allow different http server implementations pub trait ServerAdapter { type Config: Clone; + /// Create a new server adapter + /// + /// # Arguments + /// + /// * `config` - The configuration for the server adapter + /// + /// # Returns + /// + /// * `Result` - The server adapter or an error fn new(config: Self::Config) -> Result where Self: Sized; + /// Get the hostname of the server + /// + /// # Returns + /// + /// * `String` - The hostname of the server + fn hostname(&self) -> String; + + /// Get the base URL of the server + /// + /// # Returns + /// + /// * `String` - The base URL of the server + /// fn base_url(&self) -> String; + /// Get the configuration of the server + /// + /// # Returns + /// + /// * `&Self::Config` - The configuration of the server + /// fn config(&self) -> &Self::Config; + /// Start the server + /// + /// # Arguments + /// + /// * `handler` - The handler function to handle incoming requests + /// + /// # Returns + /// + /// * `Result<(), EasyHttpMockError>` - The result of the operation + /// fn start(&mut self, handler: H) -> impl Future> where H: Fn(Request) -> Fut + Send + Sync + 'static, Fut: Future> + Send + Sync + 'static; + /// Stop the server + /// + /// # Returns + /// + /// * `Result<(), EasyHttpMockError>` - The result of the operation + /// fn stop(&mut self) -> impl Future>; } From a864a00c1df0c43d3b2ff3a2de251a5be33815a5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rog=C3=A9rio=20Ara=C3=BAjo?= Date: Wed, 11 Feb 2026 19:08:21 -0300 Subject: [PATCH 04/15] feat: improved vetis customization --- Cargo.lock | 2 +- Cargo.toml | 2 +- src/errors.rs | 2 ++ src/server/adapters/vetis_adapter.rs | 28 +++++++++++++++++++++++++--- src/tests/config.rs | 12 ++++++++++++ src/tests/mod.rs | 17 +++++++++++++++++ src/tests/server.rs | 13 +++++++++++-- 7 files changed, 69 insertions(+), 7 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 074aae4..85a1fb2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -610,7 +610,7 @@ checksum = "92773504d58c093f6de2459af4af33faa518c13451eb8f2b5698ed3d36e7c813" [[package]] name = "easyhttpmock" -version = "0.1.3-beta.2" +version = "0.1.3-beta.6" dependencies = [ "bytes", "http", diff --git a/Cargo.toml b/Cargo.toml index 20fa9ac..7f66e4d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "easyhttpmock" -version = "0.1.3-beta.2" +version = "0.1.3-beta.6" edition = "2021" authors = ["Rogerio Araújo "] repository = "https://github.com/ararog/easyhttpmock" diff --git a/src/errors.rs b/src/errors.rs index 662d4f6..e6380b5 100644 --- a/src/errors.rs +++ b/src/errors.rs @@ -8,6 +8,8 @@ pub enum EasyHttpMockError { #[derive(Debug, Clone, Error, PartialEq)] pub enum ServerError { + #[error("Server config error: {0}")] + Config(String), #[error("Server start error: {0}")] Start(String), #[error("Server stop error: {0}")] diff --git a/src/server/adapters/vetis_adapter.rs b/src/server/adapters/vetis_adapter.rs index 09b3001..3bb3c8d 100644 --- a/src/server/adapters/vetis_adapter.rs +++ b/src/server/adapters/vetis_adapter.rs @@ -1,7 +1,7 @@ use std::future::Future; use vetis::{ - config::{ListenerConfig, SecurityConfig, ServerConfig, VirtualHostConfig}, + config::{ListenerConfig, Protocol, SecurityConfig, ServerConfig, VirtualHostConfig}, errors::VetisError, server::{ path::HandlerPath, @@ -21,6 +21,7 @@ use crate::{ pub struct VetisAdapterConfigBuilder { hostname: Option, interface: String, + protocol: Protocol, port: u16, cert: Option>, key: Option>, @@ -52,6 +53,18 @@ impl VetisAdapterConfigBuilder { self } + /// Sets the protocol for the server. + /// + /// # Arguments + /// * `protocol` - The protocol to set. + /// + /// # Returns + /// A new `VetisAdapterConfigBuilder` instance with the protocol set. + pub fn protocol(mut self, protocol: Protocol) -> Self { + self.protocol = protocol; + self + } + /// Sets the port for the server. /// /// # Arguments @@ -108,6 +121,7 @@ impl VetisAdapterConfigBuilder { VetisAdapterConfig { hostname: self.hostname, interface: self.interface, + protocol: self.protocol, port: self.port, cert: self.cert, key: self.key, @@ -121,6 +135,7 @@ impl VetisAdapterConfigBuilder { pub struct VetisAdapterConfig { hostname: Option, interface: String, + protocol: Protocol, port: u16, cert: Option>, key: Option>, @@ -141,6 +156,7 @@ impl Default for VetisAdapterConfig { Self { hostname: None, interface: "0.0.0.0".into(), + protocol: Protocol::Http1, port: 80, cert: None, key: None, @@ -163,6 +179,7 @@ impl VetisAdapterConfig { VetisAdapterConfigBuilder { hostname: None, interface: "0.0.0.0".into(), + protocol: Protocol::Http1, port: 80, cert: None, key: None, @@ -223,11 +240,14 @@ impl From for ServerConfig { fn from(config: VetisAdapterConfig) -> Self { let listener_config = ListenerConfig::builder() .interface(&config.interface) + .protocol(config.protocol) .port(config.port) - .build(); + .build() + .expect("Failed to build listener config"); ServerConfig::builder() .add_listener(listener_config) .build() + .expect("Failed to build server config") } } @@ -353,6 +373,7 @@ impl ServerAdapter for VetisAdapter { let host_config = VirtualHostConfig::builder() .hostname(&hostname) + .root_directory("src/tests") .port(self.config.port()); let host_config = if let Some(((cert, key), ca)) = self @@ -374,7 +395,8 @@ impl ServerAdapter for VetisAdapter { .cert_from_bytes(cert.clone()) .key_from_bytes(key.clone()) .ca_cert_from_bytes(ca.clone()) - .build(), + .build() + .map_err(|e| EasyHttpMockError::Server(ServerError::Config(e.to_string())))?, ) } else { host_config diff --git a/src/tests/config.rs b/src/tests/config.rs index 76021c7..313cc6b 100644 --- a/src/tests/config.rs +++ b/src/tests/config.rs @@ -3,6 +3,7 @@ mod easy_http_mock_config_tests { use crate::{ config::EasyHttpMockConfig, server::adapters::vetis_adapter::{VetisAdapter, VetisAdapterConfig}, + tests::default_protocol, }; #[test] @@ -97,6 +98,7 @@ mod easy_http_mock_config_tests { fn test_easy_http_mock_config_builder_with_server_config() { let server_config = VetisAdapterConfig::builder() .interface("127.0.0.1") + .protocol(default_protocol()) .port(3000) .build(); @@ -126,6 +128,7 @@ mod easy_http_mock_config_tests { let base_url = "https://test.mock".to_string(); let server_config = VetisAdapterConfig::builder() .interface("0.0.0.0") + .protocol(default_protocol()) .port(8443) .build(); @@ -153,6 +156,7 @@ mod easy_http_mock_config_tests { fn test_easy_http_mock_config_builder_chaining() { let server_config = VetisAdapterConfig::builder() .interface("192.168.1.100") + .protocol(default_protocol()) .port(9090) .build(); @@ -207,12 +211,14 @@ mod integration_tests { use crate::{ config::EasyHttpMockConfig, server::adapters::vetis_adapter::{VetisAdapter, VetisAdapterConfig}, + tests::default_protocol, }; #[test] fn test_config_with_vetis_server_adapter_integration() { let server_config = VetisAdapterConfig::builder() .interface("0.0.0.0") + .protocol(default_protocol()) .port(443) .build(); @@ -236,6 +242,7 @@ mod integration_tests { .server_config( VetisAdapterConfig::builder() .interface("0.0.0.0") + .protocol(default_protocol()) .port(8080) .build(), ) @@ -246,6 +253,7 @@ mod integration_tests { .server_config( VetisAdapterConfig::builder() .interface("0.0.0.0") + .protocol(default_protocol()) .port(9090) .build(), ) @@ -268,6 +276,7 @@ mod integration_tests { .base_url(Some("https://immutable.mock".to_string())) .server_config( VetisAdapterConfig::builder() + .protocol(default_protocol()) .port(3000) .build(), ) @@ -285,6 +294,7 @@ mod integration_tests { .base_url(Some("https://new.mock".to_string())) .server_config( VetisAdapterConfig::builder() + .protocol(default_protocol()) .port(3000) .build(), ) @@ -303,11 +313,13 @@ mod integration_tests { fn test_config_with_different_server_configs() { let http_config = VetisAdapterConfig::builder() .interface("0.0.0.0") + .protocol(default_protocol()) .port(80) .build(); let https_config = VetisAdapterConfig::builder() .interface("0.0.0.0") + .protocol(default_protocol()) .port(443) .build(); diff --git a/src/tests/mod.rs b/src/tests/mod.rs index 21be1b5..b1f8920 100644 --- a/src/tests/mod.rs +++ b/src/tests/mod.rs @@ -1,2 +1,19 @@ +use vetis::config::Protocol; + mod config; mod server; + +pub(crate) const fn default_protocol() -> Protocol { + #[cfg(feature = "http1")] + { + Protocol::Http1 + } + #[cfg(feature = "http2")] + { + Protocol::Http2 + } + #[cfg(feature = "http3")] + { + Protocol::Http3 + } +} diff --git a/src/tests/server.rs b/src/tests/server.rs index 0f4d5bc..f3ee220 100644 --- a/src/tests/server.rs +++ b/src/tests/server.rs @@ -3,11 +3,10 @@ mod easy_http_mock_server_tests { use crate::{ config::EasyHttpMockConfig, server::adapters::vetis_adapter::{VetisAdapter, VetisAdapterConfig}, + tests::default_protocol, EasyHttpMock, }; - use bytes::Bytes; use http::StatusCode; - use http_body_util::{Either, Full}; use std::time::Duration; use vetis::{Request, Response}; @@ -27,6 +26,7 @@ mod easy_http_mock_server_tests { .server_config( VetisAdapterConfig::builder() .interface("127.0.0.1") + .protocol(default_protocol()) .port(3000) .build(), ) @@ -47,6 +47,7 @@ mod easy_http_mock_server_tests { .server_config( VetisAdapterConfig::builder() .interface("127.0.0.1") + .protocol(default_protocol()) .port(4000) .build(), ) @@ -90,6 +91,7 @@ mod easy_http_mock_server_tests { .server_config( VetisAdapterConfig::builder() .interface("127.0.0.1") + .protocol(default_protocol()) .port(8181) .build(), ) @@ -110,6 +112,7 @@ mod easy_http_mock_server_tests { .server_config( VetisAdapterConfig::builder() .interface("127.0.0.1") + .protocol(default_protocol()) .port(9999) .build(), ) @@ -155,6 +158,7 @@ mod easy_http_mock_server_tests { .server_config( VetisAdapterConfig::builder() .interface("127.0.0.1") + .protocol(default_protocol()) .port(7777) // Use random available port .build(), ) @@ -209,6 +213,7 @@ mod integration_tests { use crate::{ config::EasyHttpMockConfig, server::adapters::vetis_adapter::{VetisAdapter, VetisAdapterConfig}, + tests::default_protocol, EasyHttpMock, }; use http::StatusCode; @@ -221,6 +226,7 @@ mod integration_tests { .server_config( VetisAdapterConfig::builder() .interface("127.0.0.1") + .protocol(default_protocol()) .port(8081) .build(), ) @@ -230,6 +236,7 @@ mod integration_tests { .server_config( VetisAdapterConfig::builder() .interface("127.0.0.1") + .protocol(default_protocol()) .port(8082) .build(), ) @@ -288,6 +295,7 @@ mod integration_tests { .server_config( VetisAdapterConfig::builder() .interface("127.0.0.1") + .protocol(default_protocol()) .port(8888) // Use random available port .build(), ) @@ -328,6 +336,7 @@ mod integration_tests { .server_config( VetisAdapterConfig::builder() .interface("127.0.0.1") + .protocol(default_protocol()) .port(5555) // Use random available port .build(), ) From 751565268fe2bc7bf9fbee2026b4323a3dbc28b6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rog=C3=A9rio=20Ara=C3=BAjo?= Date: Wed, 11 Feb 2026 22:40:58 -0300 Subject: [PATCH 05/15] docs: updated code examples --- README.md | 51 ++++++++++++++++++++++++++------------------------- docs/index.md | 42 ++++++++++++++++++++---------------------- docs/llms.txt | 42 ++++++++++++++++++++---------------------- 3 files changed, 66 insertions(+), 69 deletions(-) diff --git a/README.md b/README.md index 96c3d2c..5e2f938 100644 --- a/README.md +++ b/README.md @@ -29,25 +29,25 @@ easyhttpmock = { version = "0.1.1", features = ["tokio-rt", "http2", "tokio-rust Here's how simple it is to create a mock HTTP server for testing: ```rust -use bytes::Bytes; use http::StatusCode; -use http_body_util::Full; -use hyper::Response; use easyhttpmock::{ - config::EasyHttpMockConfig, - server::{adapters::vetis_adapter::VetisServerAdapter, PortGenerator}, EasyHttpMock, -}; - -use deboa::{cert::ContentEncoding, request::DeboaRequest, Client}; - -use vetis::{ + config::EasyHttpMockConfig, server::{ - config::{SecurityConfig, ServerConfig}, + PortGenerator, + adapters::vetis_adapter::{VetisAdapter, VetisAdapterConfig}, }, }; +use deboa::{ + Client, + cert::{Certificate, ContentEncoding}, + request::DeboaRequest, +}; + +use vetis::Response; + pub const CA_CERT: &[u8] = include_bytes!("../certs/ca.der"); pub const CA_CERT_PEM: &[u8] = include_bytes!("../certs/ca.crt"); @@ -56,25 +56,25 @@ pub const SERVER_KEY: &[u8] = include_bytes!("../certs/server.key.der"); #[tokio::main] async fn main() -> Result<(), Box> { - let tls_config = SecurityConfig::builder() - .cert(SERVER_CERT.to_vec()) - .key(SERVER_KEY.to_vec()) - .build(); - - let vetis_config = ServerConfig::builder() - .security(tls_config) + let vetis_adapter_config = VetisAdapterConfig::builder() + .interface("0.0.0.0") .with_random_port() + .cert(Some(SERVER_CERT.to_vec())) + .key(Some(SERVER_KEY.to_vec())) + .ca(Some(CA_CERT.to_vec())) .build(); - let config = EasyHttpMockConfig::::builder() - .server_config(vetis_config) + let config = EasyHttpMockConfig::::builder() + .server_config(vetis_adapter_config) .build(); - let mut server = EasyHttpMock::new(config); + let mut server = EasyHttpMock::new(config)?; #[allow(unused_must_use)] let result = server .start(|_| async move { - Ok(Response::new(Full::new(Bytes::from("Hello World")))) + Ok(Response::builder() + .status(StatusCode::OK) + .text("Hello World")) }) .await; @@ -83,10 +83,11 @@ async fn main() -> Result<(), Box> { }); let client = Client::builder() - .certificate(deboa::cert::Certificate::from_slice(CA_CERT, ContentEncoding::DER)) + .certificate(Certificate::from_slice(CA_CERT, ContentEncoding::DER)) .build(); - let request = DeboaRequest::get(server.url("/anything"))?.build()?; + let url = server.url("/anything"); + let request = DeboaRequest::get(url)?.build()?; let response = client .execute(request) @@ -99,7 +100,7 @@ async fn main() -> Result<(), Box> { server .stop() .await?; - + Ok(()) } ``` diff --git a/docs/index.md b/docs/index.md index 6288854..c94c998 100644 --- a/docs/index.md +++ b/docs/index.md @@ -34,25 +34,25 @@ easyhttpmock = { version = "0.0.9" } Basic usage: ```rust -use bytes::Bytes; use http::StatusCode; -use http_body_util::Full; -use hyper::Response; use easyhttpmock::{ - config::EasyHttpMockConfig, - server::{adapters::vetis_adapter::VetisServerAdapter, PortGenerator}, EasyHttpMock, -}; - -use deboa::{cert::ContentEncoding, request::DeboaRequest, Client}; - -use vetis::{ + config::EasyHttpMockConfig, server::{ - config::{SecurityConfig, ServerConfig}, + PortGenerator, + adapters::vetis_adapter::{VetisAdapter, VetisAdapterConfig}, }, }; +use deboa::{ + Client, + cert::{Certificate, ContentEncoding}, + request::DeboaRequest, +}; + +use vetis::Response; + pub const CA_CERT: &[u8] = include_bytes!("../certs/ca.der"); pub const CA_CERT_PEM: &[u8] = include_bytes!("../certs/ca.crt"); @@ -61,22 +61,19 @@ pub const SERVER_KEY: &[u8] = include_bytes!("../certs/server.key.der"); #[tokio::main] async fn main() -> Result<(), Box> { - let tls_config = SecurityConfig::builder() - .cert(SERVER_CERT.to_vec()) - .key(SERVER_KEY.to_vec()) - .build(); - - let vetis_config = ServerConfig::builder() - .security(tls_config) + let vetis_adapter_config = VetisAdapterConfig::builder() + .interface("0.0.0.0") .with_random_port() + .cert(Some(SERVER_CERT.to_vec())) + .key(Some(SERVER_KEY.to_vec())) + .ca(Some(CA_CERT.to_vec())) .build(); - let config = EasyHttpMockConfig::::builder() - .server_config(vetis_config) + let config = EasyHttpMockConfig::::builder() + .server_config(vetis_adapter_config) .build(); - let mut server = EasyHttpMock::new(config); - #[allow(unused_must_use)] + let mut server = EasyHttpMock::new(config)?; let result = server .start(|_| async move { Ok(Response::new(Full::new(Bytes::from("Hello World")))) @@ -106,6 +103,7 @@ async fn main() -> Result<(), Box> { .await?; Ok(()) +} ``` ## Examples diff --git a/docs/llms.txt b/docs/llms.txt index 66d74e4..fd2afc9 100644 --- a/docs/llms.txt +++ b/docs/llms.txt @@ -12,25 +12,25 @@ easyhttpmock = { version = "0.0.1", features = ["http1", "tokio-rt", "tokio-rust ## 💡 Usage Example ```rust -use bytes::Bytes; use http::StatusCode; -use http_body_util::Full; -use hyper::Response; use easyhttpmock::{ - config::EasyHttpMockConfig, - server::{adapters::vetis_adapter::VetisServerAdapter, PortGenerator}, EasyHttpMock, -}; - -use deboa::{cert::ContentEncoding, request::DeboaRequest, Client}; - -use vetis::{ + config::EasyHttpMockConfig, server::{ - config::{SecurityConfig, ServerConfig}, + PortGenerator, + adapters::vetis_adapter::{VetisAdapter, VetisAdapterConfig}, }, }; +use deboa::{ + Client, + cert::{Certificate, ContentEncoding}, + request::DeboaRequest, +}; + +use vetis::Response; + pub const CA_CERT: &[u8] = include_bytes!("../certs/ca.der"); pub const CA_CERT_PEM: &[u8] = include_bytes!("../certs/ca.crt"); @@ -39,22 +39,19 @@ pub const SERVER_KEY: &[u8] = include_bytes!("../certs/server.key.der"); #[tokio::main] async fn main() -> Result<(), Box> { - let tls_config = SecurityConfig::builder() - .cert(SERVER_CERT.to_vec()) - .key(SERVER_KEY.to_vec()) - .build(); - - let vetis_config = ServerConfig::builder() - .security(tls_config) + let vetis_adapter_config = VetisAdapterConfig::builder() + .interface("0.0.0.0") .with_random_port() + .cert(Some(SERVER_CERT.to_vec())) + .key(Some(SERVER_KEY.to_vec())) + .ca(Some(CA_CERT.to_vec())) .build(); - let config = EasyHttpMockConfig::::builder() - .server_config(vetis_config) + let config = EasyHttpMockConfig::::builder() + .server_config(vetis_adapter_config) .build(); - let mut server = EasyHttpMock::new(config); - #[allow(unused_must_use)] + let mut server = EasyHttpMock::new(config)?; let result = server .start(|_| async move { Ok(Response::new(Full::new(Bytes::from("Hello World")))) @@ -84,6 +81,7 @@ async fn main() -> Result<(), Box> { .await?; Ok(()) +} ``` ## Features From fc2b88981a8fa229ef409d96658dd8b0b6559f45 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rog=C3=A9rio=20Ara=C3=BAjo?= Date: Tue, 24 Feb 2026 18:21:46 -0300 Subject: [PATCH 06/15] doc: updated VetisAdapter api doc --- src/server/adapters/vetis_adapter.rs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/server/adapters/vetis_adapter.rs b/src/server/adapters/vetis_adapter.rs index 3bb3c8d..3447456 100644 --- a/src/server/adapters/vetis_adapter.rs +++ b/src/server/adapters/vetis_adapter.rs @@ -354,10 +354,16 @@ impl ServerAdapter for VetisAdapter { /// Starts the server with the given handler. /// /// # Arguments + /// /// * `handler` - The handler to use for the server. /// /// # Returns - /// A result indicating whether the server started successfully. + /// + /// A result indicating whether the server started successfully or a `EasyHttpMockError` if it failed. + /// + /// TODO: Make handler a EasyHttpMockHandler and convert from EasyMockRequest + /// and Response to Vetis Request and Response. Maybe have From implementation + /// for EasyMockRequest and Response. async fn start(&mut self, handler: H) -> Result<(), EasyHttpMockError> where H: Fn(Request) -> Fut + Send + Sync + 'static, From 8af8378c5d400de194e48c6365246268af1f14a6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rog=C3=A9rio=20Ara=C3=BAjo?= Date: Tue, 24 Feb 2026 18:28:00 -0300 Subject: [PATCH 07/15] refactor: updated code to reflect latest vetis api changes --- src/lib.rs | 7 ++++--- src/server/adapters/vetis_adapter.rs | 11 +++++++---- src/server/mod.rs | 5 ++++- src/tests/mod.rs | 2 +- src/tests/server.rs | 4 ++-- 5 files changed, 18 insertions(+), 11 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 331e078..0ca4bb0 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -2,10 +2,11 @@ use std::future::Future; use crate::{config::EasyHttpMockConfig, errors::EasyHttpMockError, server::ServerAdapter}; -use bytes::Bytes; use http::StatusCode; -use http_body_util::{Either, Full}; -use vetis::{errors::VetisError, Request, Response}; +use vetis::{ + errors::VetisError, + server::http::{Request, Response}, +}; pub mod config; pub mod errors; diff --git a/src/server/adapters/vetis_adapter.rs b/src/server/adapters/vetis_adapter.rs index 3447456..b186498 100644 --- a/src/server/adapters/vetis_adapter.rs +++ b/src/server/adapters/vetis_adapter.rs @@ -1,13 +1,16 @@ use std::future::Future; use vetis::{ - config::{ListenerConfig, Protocol, SecurityConfig, ServerConfig, VirtualHostConfig}, + config::server::{ + virtual_host::{SecurityConfig, VirtualHostConfig}, + ListenerConfig, Protocol, ServerConfig, + }, errors::VetisError, server::{ - path::HandlerPath, - virtual_host::{handler_fn, VirtualHost}, + http::{Request, Response}, + virtual_host::{handler_fn, path::HandlerPath, VirtualHost}, }, - Request, Response, Vetis, + Vetis, }; use crate::{ diff --git a/src/server/mod.rs b/src/server/mod.rs index 52fa762..236302d 100644 --- a/src/server/mod.rs +++ b/src/server/mod.rs @@ -1,6 +1,9 @@ use std::future::Future; -use vetis::{errors::VetisError, Request, Response}; +use vetis::{ + errors::VetisError, + server::http::{Request, Response}, +}; use crate::errors::EasyHttpMockError; diff --git a/src/tests/mod.rs b/src/tests/mod.rs index b1f8920..acedeae 100644 --- a/src/tests/mod.rs +++ b/src/tests/mod.rs @@ -1,4 +1,4 @@ -use vetis::config::Protocol; +use vetis::config::server::Protocol; mod config; mod server; diff --git a/src/tests/server.rs b/src/tests/server.rs index f3ee220..b315f6b 100644 --- a/src/tests/server.rs +++ b/src/tests/server.rs @@ -8,7 +8,7 @@ mod easy_http_mock_server_tests { }; use http::StatusCode; use std::time::Duration; - use vetis::{Request, Response}; + use vetis::server::http::{Request, Response}; #[tokio::test] async fn test_easy_http_mock_default() { @@ -218,7 +218,7 @@ mod integration_tests { }; use http::StatusCode; use std::time::Duration; - use vetis::{Request, Response}; + use vetis::server::http::{Request, Response}; #[tokio::test] async fn test_multiple_server_instances() -> Result<(), Box> { From 70c24d679e77bc13ac513cbef5cd5976673a0c1b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rog=C3=A9rio=20Ara=C3=BAjo?= Date: Sat, 28 Feb 2026 19:31:21 -0300 Subject: [PATCH 08/15] chore: updated vetis to beta-5 --- Cargo.lock | 2 +- Cargo.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 85a1fb2..305ad8c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -610,7 +610,7 @@ checksum = "92773504d58c093f6de2459af4af33faa518c13451eb8f2b5698ed3d36e7c813" [[package]] name = "easyhttpmock" -version = "0.1.3-beta.6" +version = "0.1.3-beta.7" dependencies = [ "bytes", "http", diff --git a/Cargo.toml b/Cargo.toml index 7f66e4d..a8eb38e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "easyhttpmock" -version = "0.1.3-beta.6" +version = "0.1.3-beta.7" edition = "2021" authors = ["Rogerio Araújo "] repository = "https://github.com/ararog/easyhttpmock" From a2c072d38bb6d852e90caf2cf03b074369756293 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rog=C3=A9rio=20Ara=C3=BAjo?= Date: Thu, 12 Mar 2026 17:38:15 -0300 Subject: [PATCH 09/15] docs: updated llms.txt, make cargo docs generate docs for all features --- .commitlintrc.yaml | 7 +++++++ .samoyed/commit-msg | 3 +++ Cargo.toml | 3 +++ docs/llms.txt | 14 +++++++------- 4 files changed, 20 insertions(+), 7 deletions(-) create mode 100644 .commitlintrc.yaml create mode 100755 .samoyed/commit-msg diff --git a/.commitlintrc.yaml b/.commitlintrc.yaml new file mode 100644 index 0000000..2316995 --- /dev/null +++ b/.commitlintrc.yaml @@ -0,0 +1,7 @@ +rules: + description-empty: # Description shouldn't be empty + level: warning + subject-empty: # Subject line should exist + level: error + type-empty: # Type must not be empty + level: error \ No newline at end of file diff --git a/.samoyed/commit-msg b/.samoyed/commit-msg new file mode 100755 index 0000000..f041635 --- /dev/null +++ b/.samoyed/commit-msg @@ -0,0 +1,3 @@ +#!/usr/bin/env sh + +commitlint --edit $1 \ No newline at end of file diff --git a/Cargo.toml b/Cargo.toml index a8eb38e..63257a0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,6 +12,9 @@ keywords = ["http", "mock", "testing"] publish = true rust-version = "1.75.0" +[package.metadata.docs.rs] +all-features = true + [features] default = ["tokio-rt", "http2", "tokio-rust-tls"] diff --git a/docs/llms.txt b/docs/llms.txt index fd2afc9..81181de 100644 --- a/docs/llms.txt +++ b/docs/llms.txt @@ -9,7 +9,7 @@ easyhttpmock = { version = "0.0.1", features = ["http1", "tokio-rt", "tokio-rust-tls"] } ``` -## 💡 Usage Example +## Usage Example ```rust use http::StatusCode; @@ -86,12 +86,12 @@ async fn main() -> Result<(), Box> { ## Features -- **🎯 Testing-Focused**: Purpose-built for HTTP client testing scenarios -- **⚡ Lightning Fast**: Powered by VeTiS for optimal performance -- **🔧 Flexible Runtime**: Choose between Tokio or Smol async runtimes -- **🌐 Full Protocol Support**: HTTP/1, HTTP/2, and HTTP/3 compatibility -- **🛡️ Secure Testing**: Built-in TLS support for HTTPS endpoint testing -- **📦 Minimal Dependencies**: Lightweight footprint for your test suite +- ** Testing-Focused**: Purpose-built for HTTP client testing scenarios +- ** Lightning Fast**: Powered by VeTiS for optimal performance +- ** Flexible Runtime**: Choose between Tokio or Smol async runtimes +- ** Full Protocol Support**: HTTP/1, HTTP/2, and HTTP/3 compatibility +- ** Secure Testing**: Built-in TLS support for HTTPS endpoint testing +- ** Minimal Dependencies**: Lightweight footprint for your test suite ## Blog Posts From 5bd03b8884876d53dda5ffe12480220b36f4c346 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rog=C3=A9rio=20Ara=C3=BAjo?= Date: Wed, 18 Mar 2026 20:03:28 -0300 Subject: [PATCH 10/15] chore: disable compio --- Cargo.lock | 14 +++++++------- Cargo.toml | 2 ++ samoyed.toml | 3 --- 3 files changed, 9 insertions(+), 10 deletions(-) delete mode 100644 samoyed.toml diff --git a/Cargo.lock b/Cargo.lock index 305ad8c..6f77e84 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1120,7 +1120,7 @@ dependencies = [ "hyper", "libc", "pin-project-lite", - "socket2 0.6.2", + "socket2 0.6.3", "tokio", "tower-service", "tracing", @@ -1743,7 +1743,7 @@ dependencies = [ "rustc-hash", "rustls", "smol", - "socket2 0.6.2", + "socket2 0.6.3", "thiserror 2.0.18", "tokio", "tracing", @@ -1783,7 +1783,7 @@ dependencies = [ "cfg_aliases", "libc", "once_cell", - "socket2 0.6.2", + "socket2 0.6.3", "tracing", "windows-sys 0.60.2", ] @@ -2312,12 +2312,12 @@ dependencies = [ [[package]] name = "socket2" -version = "0.6.2" +version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86f4aa3ad99f2088c990dfa82d367e19cb29268ed67c574d10d0a4bfe71f07e0" +checksum = "3a766e1110788c36f4fa1c2b71b387a7815aa65f88ce0229841826633d93723e" dependencies = [ "libc", - "windows-sys 0.60.2", + "windows-sys 0.61.2", ] [[package]] @@ -2575,7 +2575,7 @@ dependencies = [ "parking_lot", "pin-project-lite", "signal-hook-registry", - "socket2 0.6.2", + "socket2 0.6.3", "tokio-macros", "windows-sys 0.61.2", ] diff --git a/Cargo.toml b/Cargo.toml index 63257a0..7263e4d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -20,9 +20,11 @@ default = ["tokio-rt", "http2", "tokio-rust-tls"] tokio-rt = ["vetis/tokio-rt", "vetis/__deboa_tokio"] smol-rt = ["vetis/smol-rt", "vetis/__deboa_smol"] +#compio-rt = ["vetis/compio-rt"] tokio-rust-tls = ["vetis/tokio-rust-tls"] smol-rust-tls = ["vetis/smol-rust-tls"] +#compio-rust-tls = ["vetis/compio-rust-tls"] http1 = ["vetis/http1"] http2 = ["vetis/http2"] diff --git a/samoyed.toml b/samoyed.toml deleted file mode 100644 index e889539..0000000 --- a/samoyed.toml +++ /dev/null @@ -1,3 +0,0 @@ -[hooks] -pre-push = "cargo test --release" -pre-commit = "cargo fmt --check && cargo clippy -- -D warnings" From 6ef92525a6982fb21204cdd09e500a9069616073 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rog=C3=A9rio=20Ara=C3=BAjo?= Date: Sun, 12 Apr 2026 19:54:20 -0300 Subject: [PATCH 11/15] refactor: allow easyhttpmock support more than one server implementation --- .samoyed/pre-commit | 2 +- Cargo.lock | 1559 +++++++++++------ Cargo.toml | 59 +- LICENSE-APACHE.md | 201 +++ LICENSE => LICENSE-MIT.md | 3 +- easyhttpmock-vetis-smol/Cargo.toml | 22 + easyhttpmock-vetis-smol/src/lib.rs | 2 + .../src}/vetis_adapter.rs | 137 +- easyhttpmock-vetis-tokio/Cargo.toml | 22 + .../src/lib.rs | 0 easyhttpmock-vetis-tokio/src/vetis_adapter.rs | 460 +++++ easyhttpmock/Cargo.toml | 27 + {src => easyhttpmock/src}/config.rs | 0 {src => easyhttpmock/src}/errors.rs | 2 + easyhttpmock/src/expect.rs | 199 +++ easyhttpmock/src/lib.rs | 120 ++ .../mod.rs => easyhttpmock/src/server.rs | 28 +- easyhttpmock/src/tests/config.rs | 1 + easyhttpmock/src/tests/mod.rs | 2 + easyhttpmock/src/tests/server.rs | 1 + src/lib.rs | 75 - src/tests/config.rs | 352 ---- src/tests/mod.rs | 19 - src/tests/server.rs | 393 ----- 24 files changed, 2241 insertions(+), 1445 deletions(-) create mode 100644 LICENSE-APACHE.md rename LICENSE => LICENSE-MIT.md (93%) create mode 100644 easyhttpmock-vetis-smol/Cargo.toml create mode 100644 easyhttpmock-vetis-smol/src/lib.rs rename {src/server/adapters => easyhttpmock-vetis-smol/src}/vetis_adapter.rs (78%) create mode 100644 easyhttpmock-vetis-tokio/Cargo.toml rename src/server/adapters/mod.rs => easyhttpmock-vetis-tokio/src/lib.rs (100%) create mode 100644 easyhttpmock-vetis-tokio/src/vetis_adapter.rs create mode 100644 easyhttpmock/Cargo.toml rename {src => easyhttpmock/src}/config.rs (100%) rename {src => easyhttpmock/src}/errors.rs (90%) create mode 100644 easyhttpmock/src/expect.rs create mode 100644 easyhttpmock/src/lib.rs rename src/server/mod.rs => easyhttpmock/src/server.rs (74%) create mode 100644 easyhttpmock/src/tests/config.rs create mode 100644 easyhttpmock/src/tests/mod.rs create mode 100644 easyhttpmock/src/tests/server.rs delete mode 100644 src/lib.rs delete mode 100644 src/tests/config.rs delete mode 100644 src/tests/mod.rs delete mode 100644 src/tests/server.rs diff --git a/.samoyed/pre-commit b/.samoyed/pre-commit index b2abe8f..add6453 100644 --- a/.samoyed/pre-commit +++ b/.samoyed/pre-commit @@ -4,4 +4,4 @@ # exit 0 cargo fmt --check -cargo test \ No newline at end of file +# cargo test \ No newline at end of file diff --git a/Cargo.lock b/Cargo.lock index 6f77e84..78cc3ba 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -13,9 +13,9 @@ dependencies = [ [[package]] name = "anstream" -version = "0.6.21" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43d5b281e737544384e969a5ccad3f1cdd24b48086a0fc1b2a5262a26b8f4f4a" +checksum = "824a212faf96e9acacdbd09febd34438f8f711fb84e09a8916013cd7815ca28d" dependencies = [ "anstyle", "anstyle-parse", @@ -34,9 +34,9 @@ checksum = "940b3a0ca603d1eade50a4846a2afffd5ef57a9feac2c0e2ec2e14f9ead76000" [[package]] name = "anstyle-parse" -version = "0.2.7" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e7644824f0aa2c7b9384579234ef10eb7efb6a0deb83f9630a49594dd9c15c2" +checksum = "52ce7f38b242319f7cabaa6813055467063ecdc9d355bbb4ce0c68908cd8130e" dependencies = [ "utf8parse", ] @@ -67,6 +67,18 @@ version = "1.0.102" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f202df86484c868dbad7eaa557ef785d5c66295e41b460ef922eca0723b842c" +[[package]] +name = "argon2" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c3610892ee6e0cbce8ae2700349fcf8f98adb0dbfbee85aec3c9179d29cc072" +dependencies = [ + "base64ct", + "blake2", + "cpufeatures 0.2.17", + "password-hash", +] + [[package]] name = "async-channel" version = "1.9.0" @@ -150,15 +162,28 @@ dependencies = [ [[package]] name = "async-lock" -version = "3.4.2" +version = "3.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "290f7f2596bd5b78a9fec8088ccd89180d7f9f55b94b0576823bbbdc72ee8311" +checksum = "5fd03604047cee9b6ce9de9f70c6cd540a0520c813cbd49bae61f33ab80ed1dc" dependencies = [ "event-listener 5.4.1", "event-listener-strategy", "pin-project-lite", ] +[[package]] +name = "async-native-tls" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9343dc5acf07e79ff82d0c37899f079db3534d99f189a1837c8e549c99405bec" +dependencies = [ + "futures-util", + "native-tls", + "thiserror 1.0.69", + "tokio", + "url", +] + [[package]] name = "async-net" version = "2.0.0" @@ -279,9 +304,9 @@ checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" [[package]] name = "aws-lc-rs" -version = "1.16.1" +version = "1.16.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94bffc006df10ac2a68c83692d734a465f8ee6c5b384d8545a636f81d858f4bf" +checksum = "a054912289d18629dc78375ba2c3726a3afe3ff71b4edba9dedfca0e3446d1fc" dependencies = [ "aws-lc-sys", "zeroize", @@ -289,9 +314,9 @@ dependencies = [ [[package]] name = "aws-lc-sys" -version = "0.38.0" +version = "0.39.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4321e568ed89bb5a7d291a7f37997c2c0df89809d7b6d12062c81ddb54aa782e" +checksum = "83a25cf98105baa966497416dbd42565ce3a8cf8dbfd59803ec9ad46f3126399" dependencies = [ "cc", "cmake", @@ -311,12 +336,66 @@ version = "0.22.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" +[[package]] +name = "base64ct" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" + +[[package]] +name = "bcrypt" +version = "0.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "523ab528ce3a7ada6597f8ccf5bd8d85ebe26d5edf311cad4d1d3cfb2d357ac6" +dependencies = [ + "base64", + "blowfish", + "getrandom 0.4.2", + "subtle", +] + +[[package]] +name = "bindgen" +version = "0.72.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "993776b509cfb49c750f11b8f07a46fa23e0a1386ffc01fb1e7d343efc387895" +dependencies = [ + "bitflags", + "cexpr", + "clang-sys", + "itertools", + "proc-macro2", + "quote", + "regex", + "rustc-hash", + "shlex", + "syn 2.0.117", +] + [[package]] name = "bitflags" version = "2.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "843867be96c8daad0d758b57df9392b6d8d271134fce549de6ce169ff98a92af" +[[package]] +name = "blake2" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46502ad458c9a52b69d4d4d32775c788b7a1b85e8bc9d482d92250fc0e3f8efe" +dependencies = [ + "digest", +] + +[[package]] +name = "block-buffer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +dependencies = [ + "generic-array", +] + [[package]] name = "blocking" version = "1.6.2" @@ -330,12 +409,28 @@ dependencies = [ "piper", ] +[[package]] +name = "blowfish" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e412e2cd0f2b2d93e02543ceae7917b3c70331573df19ee046bcbc35e45e87d7" +dependencies = [ + "byteorder", + "cipher", +] + [[package]] name = "bumpalo" version = "3.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5d20789868f4b01b2f2caec9f5c4e0213b41e3e5702a50157d699ae31ced2fcb" +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + [[package]] name = "bytes" version = "1.11.1" @@ -344,9 +439,9 @@ checksum = "1e748733b7cbc798e1434b6ac524f0c1ff2ab456fe201501e6497c8417a4fc33" [[package]] name = "cc" -version = "1.2.57" +version = "1.2.59" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a0dd1ca384932ff3641c8718a02769f1698e7563dc6974ffd03346116310423" +checksum = "b7a4d3ec6524d28a329fc53654bbadc9bdd7b0431f5d65f1a56ffb28a1ee5283" dependencies = [ "find-msvc-tools", "jobserver", @@ -355,10 +450,13 @@ dependencies = [ ] [[package]] -name = "cesu8" -version = "1.1.0" +name = "cexpr" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d43a04d8753f35258c91f8ec639f792891f748a1edbd759cf1dcea3382ad83c" +checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766" +dependencies = [ + "nom", +] [[package]] name = "cfg-if" @@ -379,15 +477,36 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6f8d983286843e49675a4b7a2d174efe136dc93a18d69130dd18198a6c167601" dependencies = [ "cfg-if", - "cpufeatures", + "cpufeatures 0.3.0", "rand_core 0.10.0", ] +[[package]] +name = "cipher" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad" +dependencies = [ + "crypto-common", + "inout", +] + +[[package]] +name = "clang-sys" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b023947811758c97c59bf9d1c188fd619ad4718dcaa767947df1cadb14f39f4" +dependencies = [ + "glob", + "libc", + "libloading", +] + [[package]] name = "clap" -version = "4.6.0" +version = "4.5.61" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b193af5b67834b676abd72466a96c1024e6a6ad978a1f484bd90b85c94041351" +checksum = "52fa72306bb30daf11bc97773431628e5b4916e97aaa74b7d3f625d4d495da02" dependencies = [ "clap_builder", "clap_derive", @@ -395,9 +514,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.6.0" +version = "4.5.61" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "714a53001bf66416adb0e2ef5ac857140e7dc3a0c48fb28b2f10762fc4b5069f" +checksum = "2071365c5c56eae7d77414029dde2f4f4ba151cf68d5a3261c9a40de428ace93" dependencies = [ "anstyle", "clap_lex", @@ -405,9 +524,9 @@ dependencies = [ [[package]] name = "clap_derive" -version = "4.6.0" +version = "4.5.61" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1110bd8a634a1ab8cb04345d8d878267d57c3cf1b38d91b71af6686408bbca6a" +checksum = "dec5be1eea072311774b7b84ded287adbd9f293f9d23456817605c6042f4f5e0" dependencies = [ "heck", "proc-macro2", @@ -417,15 +536,15 @@ dependencies = [ [[package]] name = "clap_lex" -version = "1.1.0" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8d4a3bb8b1e0c1050499d1815f5ab16d04f0959b233085fb31653fbfc9d98f9" +checksum = "0e78417baa3b3114dc0e95e7357389a249c4da97c3c2b540700079db6171bfd7" [[package]] name = "cmake" -version = "0.1.57" +version = "0.1.58" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75443c44cd6b379beb8c5b45d85d0773baf31cce901fe7bb252f4eff3008ef7d" +checksum = "c0f78a02292a74a88ac736019ab962ece0bc380e3f977bf72e376c5d78ff0678" dependencies = [ "cc", ] @@ -436,16 +555,6 @@ version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1d07550c9036bf2ae0c684c4297d503f838287c83c53686d05370d0e139ae570" -[[package]] -name = "combine" -version = "4.6.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba5a308b75df32fe02788e748662718f03fde005016435c444eea572398219fd" -dependencies = [ - "bytes", - "memchr", -] - [[package]] name = "concurrent-queue" version = "2.5.0" @@ -471,6 +580,16 @@ dependencies = [ "version_check", ] +[[package]] +name = "core-foundation" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" +dependencies = [ + "core-foundation-sys", + "libc", +] + [[package]] name = "core-foundation" version = "0.10.1" @@ -487,6 +606,15 @@ version = "0.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" +[[package]] +name = "cpufeatures" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280" +dependencies = [ + "libc", +] + [[package]] name = "cpufeatures" version = "0.3.0" @@ -496,6 +624,24 @@ dependencies = [ "libc", ] +[[package]] +name = "crossbeam-channel" +version = "0.5.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82b8f8f868b36967f9606790d1903570de9ceaf870a7bf9fbbd3016d636a2cb2" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.9.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" +dependencies = [ + "crossbeam-utils", +] + [[package]] name = "crossbeam-utils" version = "0.8.21" @@ -504,9 +650,9 @@ checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" [[package]] name = "crossfire" -version = "3.1.6" +version = "3.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "45c93b03ce6b0c57c0c37a1a347fc51e4a7d4eca4ea97e06a456093df88376e8" +checksum = "e0042e53977a94d5d10de04ce7eb6016aa212c08e83ea202f7a9f102ff104303" dependencies = [ "crossbeam-utils", "futures-core", @@ -514,6 +660,16 @@ dependencies = [ "smallvec", ] +[[package]] +name = "crypto-common" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78c8292055d1c1df0cce5d180393dc8cce0abec0a7102adb6c7b1eef6016d60a" +dependencies = [ + "generic-array", + "typenum", +] + [[package]] name = "data-encoding" version = "2.10.0" @@ -522,19 +678,14 @@ checksum = "d7a1e2f27636f116493b8b860f5546edb47c8d8f8ea73e1d2a20be88e28d1fea" [[package]] name = "deboa" -version = "0.1.0-beta.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6350e6d582813b061aff007ffeca894a421f4ccd58c03d289062a7a4f86f868" +version = "0.1.0-beta.16" dependencies = [ - "async-executor", - "async-std-resolver", "async-trait", "base64", "bytes", "cfg-if", "cookie", "futures", - "futures-rustls", "h3", "h3-quinn", "http", @@ -545,13 +696,45 @@ dependencies = [ "hyper-util", "indexmap", "log", + "minimime", + "mockall", + "rand 0.9.2", + "regex", + "serde", + "thiserror 2.0.18", + "time 0.2.27", + "url", + "urlencoding", +] + +[[package]] +name = "deboa-smol" +version = "0.1.0-beta.1" +dependencies = [ + "async-native-tls", + "async-std-resolver", + "async-trait", + "base64", + "bytes", + "cfg-if", + "cookie", + "deboa", + "futures", + "futures-rustls", + "http", + "http-body", + "http-body-util", + "hyper", + "hyper-body-utils", + "hyper-util", + "indexmap", + "log", "macro_rules_attribute", "minimime", "mockall", "quinn", "rand 0.9.2", "regex", - "rt-gate", "rustls", "rustls-native-certs", "rustls-pki-types", @@ -561,6 +744,44 @@ dependencies = [ "smol-macros", "thiserror 2.0.18", "time 0.2.27", + "trust-dns-resolver", + "url", + "urlencoding", + "webpki-roots", +] + +[[package]] +name = "deboa-tokio" +version = "0.1.0-beta.1" +dependencies = [ + "async-std-resolver", + "async-trait", + "base64", + "bytes", + "cfg-if", + "cookie", + "deboa", + "futures", + "futures-rustls", + "http", + "http-body", + "http-body-util", + "hyper", + "hyper-body-utils", + "hyper-util", + "indexmap", + "log", + "minimime", + "mockall", + "quinn", + "rand 0.9.2", + "regex", + "rustls", + "rustls-native-certs", + "rustls-pki-types", + "serde", + "thiserror 2.0.18", + "time 0.2.27", "tokio", "tokio-rustls", "tokio-util", @@ -572,13 +793,24 @@ dependencies = [ [[package]] name = "deranged" -version = "0.5.8" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7cd812cc2bc1d69d4764bd80df88b4317eaef9e773c75226407d9bc0876b211c" +checksum = "9c9e6a11ca8224451684bc0d7d5a7adbf8f2fd6887261a1cfc3c0432f9d4068e" dependencies = [ "powerfmt", ] +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer", + "crypto-common", + "subtle", +] + [[package]] name = "discard" version = "1.0.4" @@ -619,10 +851,34 @@ dependencies = [ "hyper-util", "rand 0.10.0", "thiserror 2.0.18", - "tokio", - "vetis", ] +[[package]] +name = "easyhttpmock-vetis-smol" +version = "0.1.0-beta.1" +dependencies = [ + "easyhttpmock", + "http", + "rand 0.9.2", + "vetis-smol", +] + +[[package]] +name = "easyhttpmock-vetis-tokio" +version = "0.1.0-beta.1" +dependencies = [ + "easyhttpmock", + "http", + "rand 0.9.2", + "vetis-tokio", +] + +[[package]] +name = "either" +version = "1.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" + [[package]] name = "endian-type" version = "0.2.0" @@ -643,9 +899,9 @@ dependencies = [ [[package]] name = "env_filter" -version = "1.0.0" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a1c3cc8e57274ec99de65301228b537f1e4eedc1b8e0f9411c6caac8ae7308f" +checksum = "32e90c2accc4b07a8456ea0debdc2e7587bdd890680d71173a15d4ae604f6eef" dependencies = [ "log", "regex", @@ -653,9 +909,9 @@ dependencies = [ [[package]] name = "env_logger" -version = "0.11.9" +version = "0.11.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2daee4ea451f429a58296525ddf28b45a3b64f1acf6587e2067437bb11e218d" +checksum = "0621c04f2196ac3f488dd583365b9c09be011a4ab8b9f37248ffcc8f6198b56a" dependencies = [ "anstream", "anstyle", @@ -707,23 +963,11 @@ dependencies = [ "pin-project-lite", ] -[[package]] -name = "fastbloom" -version = "0.14.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e7f34442dbe69c60fe8eaf58a8cafff81a1f278816d8ab4db255b3bef4ac3c4" -dependencies = [ - "getrandom 0.3.4", - "libm", - "rand 0.9.2", - "siphasher", -] - [[package]] name = "fastrand" -version = "2.3.0" +version = "2.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" +checksum = "9f1f227452a390804cdb637b74a86990f2a7d7ba4b7d5693aac9b4dd6defd8d6" [[package]] name = "find-msvc-tools" @@ -743,6 +987,21 @@ version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" +[[package]] +name = "foreign-types" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" +dependencies = [ + "foreign-types-shared", +] + +[[package]] +name = "foreign-types-shared" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" + [[package]] name = "form_urlencoded" version = "1.2.2" @@ -754,9 +1013,12 @@ dependencies = [ [[package]] name = "fragile" -version = "2.0.1" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28dd6caf6059519a65843af8fe2a3ae298b14b80179855aeb4adc2c1934ee619" +checksum = "8878864ba14bb86e818a412bfd6f18f9eabd4ec0f008a28e8f7eb61db532fcf9" +dependencies = [ + "futures-core", +] [[package]] name = "fs_extra" @@ -876,6 +1138,16 @@ dependencies = [ "slab", ] +[[package]] +name = "generic-array" +version = "0.14.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +dependencies = [ + "typenum", + "version_check", +] + [[package]] name = "getrandom" version = "0.2.17" @@ -898,25 +1170,31 @@ dependencies = [ "cfg-if", "js-sys", "libc", - "r-efi", + "r-efi 5.3.0", "wasip2", "wasm-bindgen", ] [[package]] name = "getrandom" -version = "0.4.1" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "139ef39800118c7683f2fd3c98c1b23c09ae076556b435f8e9064ae108aaeeec" +checksum = "0de51e6874e94e7bf76d726fc5d13ba782deca734ff60d5bb2fb2607c7406555" dependencies = [ "cfg-if", "libc", - "r-efi", + "r-efi 6.0.0", "rand_core 0.10.0", "wasip2", "wasip3", ] +[[package]] +name = "glob" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0cc23270f6e1808e30a928bdc84dea0b9b4136a8bc82338574f23baf47bbd280" + [[package]] name = "gloo-timers" version = "0.3.0" @@ -1005,18 +1283,18 @@ checksum = "fc0fef456e4baa96da950455cd02c081ca953b141298e41db3fc7e36b1da849c" [[package]] name = "hotpath" -version = "0.14.0" +version = "0.14.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2fde50be006a0fe95cc2fd6d25d884aa6932218e4055d7df2fa0d95c386acf8d" +checksum = "f7d9982fcb4356a5260502f0e646411ec1feb2962cc98c230777104a8d1c5ed3" dependencies = [ "hotpath-macros", ] [[package]] name = "hotpath-macros" -version = "0.14.0" +version = "0.14.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd884cee056e269e41e1127549458e1c4e309f31897ebbc1416982a74d40a5b5" +checksum = "4398eddb78466298f1ddcc739abbbd8a942e541d1972c7590bd83de364e626e0" [[package]] name = "http" @@ -1065,9 +1343,9 @@ checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" [[package]] name = "hyper" -version = "1.8.1" +version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2ab2d4f250c3d7b1c9fcdff1cece94ea4e2dfbec68614f7b87cb205f24ca9d11" +checksum = "6299f016b246a94207e63da54dbe807655bf9e00044f73ded42c3ac5305fbcca" dependencies = [ "atomic-waker", "bytes", @@ -1080,7 +1358,6 @@ dependencies = [ "httpdate", "itoa", "pin-project-lite", - "pin-utils", "smallvec", "tokio", "want", @@ -1094,14 +1371,9 @@ checksum = "d4eff608807e6c410941de3e22c17044fecec132e20dc21f33247cc31509f14f" dependencies = [ "bytes", "futures", - "h3", - "h3-quinn", "hotpath", "http-body-util", "hyper", - "macro_rules_attribute", - "smol", - "smol-macros", "tokio", "tokio-util", ] @@ -1128,22 +1400,21 @@ dependencies = [ [[package]] name = "icu_collections" -version = "2.1.1" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c6b649701667bbe825c3b7e6388cb521c23d88644678e83c0c4d0a621a34b43" +checksum = "db2fa452206ebee18c4b5c2274dbf1de17008e874b4dc4f0aea9d01ca79e4526" dependencies = [ "displaydoc", - "potential_utf", "yoke", "zerofrom", "zerovec", ] [[package]] -name = "icu_locale_core" -version = "2.1.1" +name = "icu_locid" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "edba7861004dd3714265b4db54a3c390e880ab658fec5f7db895fae2046b5bb6" +checksum = "13acbb8371917fc971be86fc8057c41a64b521c184808a698c02acc242dbf637" dependencies = [ "displaydoc", "litemap", @@ -1152,61 +1423,99 @@ dependencies = [ "zerovec", ] +[[package]] +name = "icu_locid_transform" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "01d11ac35de8e40fdeda00d9e1e9d92525f3f9d887cdd7aa81d727596788b54e" +dependencies = [ + "displaydoc", + "icu_locid", + "icu_locid_transform_data", + "icu_provider", + "tinystr", + "zerovec", +] + +[[package]] +name = "icu_locid_transform_data" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7515e6d781098bf9f7205ab3fc7e9709d34554ae0b21ddbcb5febfa4bc7df11d" + [[package]] name = "icu_normalizer" -version = "2.1.1" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f6c8828b67bf8908d82127b2054ea1b4427ff0230ee9141c54251934ab1b599" +checksum = "19ce3e0da2ec68599d193c93d088142efd7f9c5d6fc9b803774855747dc6a84f" dependencies = [ + "displaydoc", "icu_collections", "icu_normalizer_data", "icu_properties", "icu_provider", "smallvec", + "utf16_iter", + "utf8_iter", + "write16", "zerovec", ] [[package]] name = "icu_normalizer_data" -version = "2.1.1" +version = "1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7aedcccd01fc5fe81e6b489c15b247b8b0690feb23304303a9e560f37efc560a" +checksum = "c5e8338228bdc8ab83303f16b797e177953730f601a96c25d10cb3ab0daa0cb7" [[package]] name = "icu_properties" -version = "2.1.2" +version = "1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "020bfc02fe870ec3a66d93e677ccca0562506e5872c650f893269e08615d74ec" +checksum = "93d6020766cfc6302c15dbbc9c8778c37e62c14427cb7f6e601d849e092aeef5" dependencies = [ + "displaydoc", "icu_collections", - "icu_locale_core", + "icu_locid_transform", "icu_properties_data", "icu_provider", - "zerotrie", + "tinystr", "zerovec", ] [[package]] name = "icu_properties_data" -version = "2.1.2" +version = "1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "616c294cf8d725c6afcd8f55abc17c56464ef6211f9ed59cccffe534129c77af" +checksum = "85fb8799753b75aee8d2a21d7c14d9f38921b54b3dbda10f5a3c7a7b82dba5e2" [[package]] name = "icu_provider" -version = "2.1.1" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85962cf0ce02e1e0a629cc34e7ca3e373ce20dda4c4d7294bbd0bf1fdb59e614" +checksum = "6ed421c8a8ef78d3e2dbc98a973be2f3770cb42b606e3ab18d6237c4dfde68d9" dependencies = [ "displaydoc", - "icu_locale_core", + "icu_locid", + "icu_provider_macros", + "stable_deref_trait", + "tinystr", "writeable", "yoke", "zerofrom", - "zerotrie", "zerovec", ] +[[package]] +name = "icu_provider_macros" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ec89e9337638ecdc08744df490b221a7399bf8d164eb52a665454e60e075ad6" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + [[package]] name = "id-arena" version = "2.3.0" @@ -1236,9 +1545,9 @@ dependencies = [ [[package]] name = "idna_adapter" -version = "1.2.1" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3acae9609540aa318d1bc588455225fb2085b9ed0c4f6bd0d9d5bcd86f1a0344" +checksum = "daca1df1c957320b2cf139ac61e7bd64fed304c5040df000a745aa1de3b4ef71" dependencies = [ "icu_normalizer", "icu_properties", @@ -1246,9 +1555,9 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.13.0" +version = "2.11.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7714e70437a7dc3ac8eb7e6f8df75fd8eb422675fc7678aff7364301092b1017" +checksum = "4b0f83760fb341a774ed326568e19f5a863af4a952def8c39f9ab92fd95b88e5" dependencies = [ "equivalent", "hashbrown 0.16.1", @@ -1257,15 +1566,21 @@ dependencies = [ ] [[package]] -name = "ipconfig" -version = "0.3.2" +name = "indoc" +version = "2.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b58db92f96b720de98181bbbe63c831e87005ab460c1bf306eb2622b4707997f" +checksum = "79cf5c93f93228cf8efb3ba362535fb11199ac548a09ce117c9b1adc3030d706" dependencies = [ - "socket2 0.5.10", - "widestring", - "windows-sys 0.48.0", - "winreg", + "rustversion", +] + +[[package]] +name = "inout" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "879f10e63c20629ecabbb64a8010319738c66a5cd0c29b02d63d272b03751d01" +dependencies = [ + "generic-array", ] [[package]] @@ -1280,11 +1595,20 @@ version = "1.70.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a6cb138bb79a146c1bd460005623e142ef0181e3d0219cb493e02f7d08a35695" +[[package]] +name = "itertools" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186" +dependencies = [ + "either", +] + [[package]] name = "itoa" -version = "1.0.17" +version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92ecc6618181def0457392ccd0ee51198e065e016d1d527a7ac1b6dc7c1f09d2" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" [[package]] name = "jiff" @@ -1310,28 +1634,6 @@ dependencies = [ "syn 2.0.117", ] -[[package]] -name = "jni" -version = "0.21.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a87aa2bb7d2af34197c04845522473242e1aa17c12f4935d5856491a7fb8c97" -dependencies = [ - "cesu8", - "cfg-if", - "combine", - "jni-sys", - "log", - "thiserror 1.0.69", - "walkdir", - "windows-sys 0.45.0", -] - -[[package]] -name = "jni-sys" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130" - [[package]] name = "jobserver" version = "0.1.34" @@ -1344,10 +1646,12 @@ dependencies = [ [[package]] name = "js-sys" -version = "0.3.85" +version = "0.3.94" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c942ebf8e95485ca0d52d97da7c5a2c387d0e7f0ba4c35e93bfcaee045955b3" +checksum = "2e04e2ef80ce82e13552136fabeef8a5ed1f985a96805761cbb9a2c34e7664d9" dependencies = [ + "cfg-if", + "futures-util", "once_cell", "wasm-bindgen", ] @@ -1361,6 +1665,12 @@ dependencies = [ "log", ] +[[package]] +name = "lazy_static" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" + [[package]] name = "leb128fmt" version = "0.1.0" @@ -1369,15 +1679,19 @@ checksum = "09edd9e8b54e49e587e4f6295a7d29c3ea94d469cb40ab8ca70b288248a81db2" [[package]] name = "libc" -version = "0.2.183" +version = "0.2.184" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5b646652bf6661599e1da8901b3b9522896f01e736bad5f723fe7a3a27f899d" +checksum = "48f5d2a454e16a5ea0f4ced81bd44e4cfc7bd3a507b61887c99fd3538b28e4af" [[package]] -name = "libm" -version = "0.2.16" +name = "libloading" +version = "0.8.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6d2cec3eae94f9f509c767b45932f1ada8350c4bdb85af2fcab4a3c14807981" +checksum = "d7c4b02199fee7c5d21a5ae7d8cfa79a6ef5bb2fc834d6e9058e89c825efdc55" +dependencies = [ + "cfg-if", + "windows-link", +] [[package]] name = "libmimalloc-sys" @@ -1403,9 +1717,9 @@ checksum = "32a66949e030da00e8c7d4434b251670a91556f4144941d37452769c25d58a53" [[package]] name = "litemap" -version = "0.8.1" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6373607a59f0be73a39b6fe456b8192fcc3585f602af20751600e974dd455e77" +checksum = "4ee93343901ab17bd981295f2cf0026d4ad018c7c31ba84549a4ddbb47a45104" [[package]] name = "lock_api" @@ -1456,12 +1770,44 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "670fdfda89751bc4a84ac13eaa63e205cf0fd22b4c9a5fbfa085b63c1f1d3a30" +[[package]] +name = "magnus" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b36a5b126bbe97eb0d02d07acfeb327036c6319fd816139a49824a83b7f9012" +dependencies = [ + "magnus-macros", + "rb-sys", + "rb-sys-env", + "seq-macro", +] + +[[package]] +name = "magnus-macros" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47607461fd8e1513cb4f2076c197d8092d921a1ea75bd08af97398f593751892" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + [[package]] name = "memchr" version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79" +[[package]] +name = "memoffset" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "488016bfae457b036d996092f6cb448677611ce4449e970ceaf42695203f218a" +dependencies = [ + "autocfg", +] + [[package]] name = "mimalloc" version = "0.1.48" @@ -1471,6 +1817,18 @@ dependencies = [ "libmimalloc-sys", ] +[[package]] +name = "mime" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" + +[[package]] +name = "minimal-lexical" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" + [[package]] name = "minimime" version = "1.0.0" @@ -1479,9 +1837,9 @@ checksum = "9bcaa89828ea1e6ab547d9d61ae49f1f9336459b593f285ecc402af9152e16b2" [[package]] name = "mio" -version = "1.1.1" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a69bcab0ad47271a0234d9422b131806bf3968021e5dc9328caf2d4cd58557fc" +checksum = "50b7e5b27aa02a74bac8c3f23f448f8d87ff11f92d3aac1a6ed369ee08cc56c1" dependencies = [ "libc", "wasi", @@ -1514,6 +1872,43 @@ dependencies = [ "syn 2.0.117", ] +[[package]] +name = "moka" +version = "0.12.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "957228ad12042ee839f93c8f257b62b4c0ab5eaae1d4fa60de53b27c9d7c5046" +dependencies = [ + "async-lock", + "crossbeam-channel", + "crossbeam-epoch", + "crossbeam-utils", + "equivalent", + "event-listener 5.4.1", + "futures-util", + "parking_lot", + "portable-atomic", + "smallvec", + "tagptr", + "uuid", +] + +[[package]] +name = "native-tls" +version = "0.2.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0dab59f8e050d5df8e4dd87d9206fb6f65a483e20ac9fda365ade4fab353196c" +dependencies = [ + "libc", + "log", + "openssl", + "openssl-probe 0.1.6", + "openssl-sys", + "schannel", + "security-framework 2.11.1", + "security-framework-sys", + "tempfile", +] + [[package]] name = "nibble_vec" version = "0.1.0" @@ -1523,11 +1918,97 @@ dependencies = [ "smallvec", ] +[[package]] +name = "nom" +version = "7.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" +dependencies = [ + "memchr", + "minimal-lexical", +] + +[[package]] +name = "num" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8536030f9fea7127f841b45bb6243b27255787fb4eb83958aa1ef9d2fdc0c36" +dependencies = [ + "num-bigint", + "num-complex", + "num-integer", + "num-iter", + "num-rational", + "num-traits", +] + +[[package]] +name = "num-bigint" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "090c7f9998ee0ff65aa5b723e4009f7b217707f1fb5ea551329cc4d6231fb304" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-complex" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6b19411a9719e753aff12e5187b74d60d3dc449ec3f4dc21e3989c3f554bc95" +dependencies = [ + "autocfg", + "num-traits", +] + [[package]] name = "num-conv" -version = "0.2.0" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" + +[[package]] +name = "num-integer" +version = "0.1.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" +dependencies = [ + "num-traits", +] + +[[package]] +name = "num-iter" +version = "0.1.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1429034a0490724d0075ebb2bc9e875d6503c3cf69e235a8941aa757d83ef5bf" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-rational" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf97ec579c3c42f953ef76dbf8d55ac91fb219dde70e49aa4a6b7d74e9919050" +checksum = "5c000134b5dbf44adc5cb772486d335293351644b801551abe8f75c84cfa4aef" +dependencies = [ + "autocfg", + "num-bigint", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", +] [[package]] name = "once_cell" @@ -1541,12 +2022,56 @@ version = "1.70.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe" +[[package]] +name = "openssl" +version = "0.10.77" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfe4646e360ec77dff7dde40ed3d6c5fee52d156ef4a62f53973d38294dad87f" +dependencies = [ + "bitflags", + "cfg-if", + "foreign-types", + "libc", + "once_cell", + "openssl-macros", + "openssl-sys", +] + +[[package]] +name = "openssl-macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "openssl-probe" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d05e27ee213611ffe7d6348b942e8f942b37114c00cc03cec254295a4a17852e" + [[package]] name = "openssl-probe" version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7c87def4c32ab89d880effc9e097653c8da5d6ef28e6b539d313baaacfbafcbe" +[[package]] +name = "openssl-sys" +version = "0.9.113" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad2f2c0eba47118757e4c6d2bff2838f3e0523380021356e7875e858372ce644" +dependencies = [ + "cc", + "libc", + "pkg-config", + "vcpkg", +] + [[package]] name = "parking" version = "2.2.1" @@ -1576,6 +2101,28 @@ dependencies = [ "windows-link", ] +[[package]] +name = "parse_duration" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7037e5e93e0172a5a96874380bf73bc6ecef022e26fa25f2be26864d6b3ba95d" +dependencies = [ + "lazy_static", + "num", + "regex", +] + +[[package]] +name = "password-hash" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "346f04948ba92c43e8469c1ee6736c7563d71012b17d40745260fe106aac2166" +dependencies = [ + "base64ct", + "rand_core 0.6.4", + "subtle", +] + [[package]] name = "paste" version = "1.0.15" @@ -1623,6 +2170,12 @@ dependencies = [ "futures-io", ] +[[package]] +name = "pkg-config" +version = "0.3.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19f132c84eca552bf34cab8ec81f1c1dcc229b811638f9d283dceabe58c5569e" + [[package]] name = "polling" version = "3.11.0" @@ -1652,15 +2205,6 @@ dependencies = [ "portable-atomic", ] -[[package]] -name = "potential_utf" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b73949432f5e2a09657003c25bca5e19a0e9c84f8058ca374f49e0ebe605af77" -dependencies = [ - "zerovec", -] - [[package]] name = "powerfmt" version = "0.2.0" @@ -1727,13 +2271,73 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "pyo3" +version = "0.27.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab53c047fcd1a1d2a8820fe84f05d6be69e9526be40cb03b73f86b6b03e6d87d" +dependencies = [ + "indoc", + "libc", + "memoffset", + "once_cell", + "portable-atomic", + "pyo3-build-config", + "pyo3-ffi", + "pyo3-macros", + "unindent", +] + +[[package]] +name = "pyo3-build-config" +version = "0.27.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b455933107de8642b4487ed26d912c2d899dec6114884214a0b3bb3be9261ea6" +dependencies = [ + "target-lexicon", +] + +[[package]] +name = "pyo3-ffi" +version = "0.27.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c85c9cbfaddf651b1221594209aed57e9e5cff63c4d11d1feead529b872a089" +dependencies = [ + "libc", + "pyo3-build-config", +] + +[[package]] +name = "pyo3-macros" +version = "0.27.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0a5b10c9bf9888125d917fb4d2ca2d25c8df94c7ab5a52e13313a07e050a3b02" +dependencies = [ + "proc-macro2", + "pyo3-macros-backend", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "pyo3-macros-backend" +version = "0.27.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03b51720d314836e53327f5871d4c0cfb4fb37cc2c4a11cc71907a86342c40f9" +dependencies = [ + "heck", + "proc-macro2", + "pyo3-build-config", + "quote", + "syn 2.0.117", +] + [[package]] name = "quinn" version = "0.11.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b9e20a958963c291dc322d98411f541009df2ced7b5a4f2bd52337638cfccf20" dependencies = [ - "async-io", "bytes", "cfg_aliases", "futures-io", @@ -1742,7 +2346,6 @@ dependencies = [ "quinn-udp", "rustc-hash", "rustls", - "smol", "socket2 0.6.3", "thiserror 2.0.18", "tokio", @@ -1758,7 +2361,6 @@ checksum = "434b42fec591c96ef50e21e886936e66d3cc3f737104fdb9b737c40ffb94c098" dependencies = [ "aws-lc-rs", "bytes", - "fastbloom", "getrandom 0.3.4", "lru-slab", "rand 0.9.2", @@ -1766,7 +2368,6 @@ dependencies = [ "rustc-hash", "rustls", "rustls-pki-types", - "rustls-platform-verifier", "slab", "thiserror 2.0.18", "tinyvec", @@ -1803,6 +2404,12 @@ version = "5.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" +[[package]] +name = "r-efi" +version = "6.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8dcc9c7d52a811697d2151c701e0d08956f92b0e24136cf4cf27b57a6a0d9bf" + [[package]] name = "radix_trie" version = "0.3.0" @@ -1841,7 +2448,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bc266eb313df6c5c09c1c7b1fbe2510961e5bcd3add930c1e31f7ed9da0feff8" dependencies = [ "chacha20", - "getrandom 0.4.1", + "getrandom 0.4.2", "rand_core 0.10.0", ] @@ -1889,6 +2496,36 @@ version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0c8d0fd677905edcbeedbf2edb6494d676f0e98d54d5cf9bda0b061cb8fb8aba" +[[package]] +name = "rb-sys" +version = "0.9.126" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "284799e73e899fe946fd77c7211b83bff61a1356e039ade7a2516a779e3212d0" +dependencies = [ + "rb-sys-build", +] + +[[package]] +name = "rb-sys-build" +version = "0.9.126" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "855fc1ad8943d12c89ef12f9147f1cc531f5bf19fb744112fdd317bb6ee7b5c5" +dependencies = [ + "bindgen", + "lazy_static", + "proc-macro2", + "quote", + "regex", + "shell-words", + "syn 2.0.117", +] + +[[package]] +name = "rb-sys-env" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cca7ad6a7e21e72151d56fe2495a259b5670e204c3adac41ee7ef676ea08117a" + [[package]] name = "redox_syscall" version = "0.5.18" @@ -1927,12 +2564,6 @@ version = "0.8.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dc897dd8d9e8bd1ed8cdad82b5966c3e0ecae09fb1907d58efaa013543185d0a" -[[package]] -name = "resolv-conf" -version = "0.7.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e061d1b48cb8d38042de4ae0a7a6401009d6143dc80d2e2d6f31f0bdd6470c7" - [[package]] name = "ring" version = "0.17.14" @@ -1947,16 +2578,6 @@ dependencies = [ "windows-sys 0.52.0", ] -[[package]] -name = "rt-gate" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d78077a3e29aa7f843d854b0133957d485ecaff3b47c657c156a2808ced16dc" -dependencies = [ - "smol", - "tokio", -] - [[package]] name = "rustc-hash" version = "2.1.1" @@ -1992,9 +2613,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "758025cb5fccfd3bc2fd74708fd4682be41d99e5dff73c377c0646c6012c73a4" dependencies = [ "aws-lc-rs", - "log", "once_cell", - "ring", "rustls-pki-types", "rustls-webpki", "subtle", @@ -2007,10 +2626,10 @@ version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "612460d5f7bea540c490b2b6395d8e34a953e52b491accd6c86c8164c5932a63" dependencies = [ - "openssl-probe", + "openssl-probe 0.2.1", "rustls-pki-types", "schannel", - "security-framework", + "security-framework 3.6.0", ] [[package]] @@ -2023,38 +2642,11 @@ dependencies = [ "zeroize", ] -[[package]] -name = "rustls-platform-verifier" -version = "0.6.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d99feebc72bae7ab76ba994bb5e121b8d83d910ca40b36e0921f53becc41784" -dependencies = [ - "core-foundation", - "core-foundation-sys", - "jni", - "log", - "once_cell", - "rustls", - "rustls-native-certs", - "rustls-platform-verifier-android", - "rustls-webpki", - "security-framework", - "security-framework-sys", - "webpki-root-certs", - "windows-sys 0.61.2", -] - -[[package]] -name = "rustls-platform-verifier-android" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f87165f0995f63a9fbeea62b64d10b4d9d8e78ec6d7d51fb2125fda7bb36788f" - [[package]] name = "rustls-webpki" -version = "0.103.9" +version = "0.103.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7df23109aa6c1567d1c575b9952556388da57401e4ace1d15f79eedad0d8f53" +checksum = "df33b2b81ac578cabaf06b89b0631153a3f416b0a886e8a7a1707fb51abbd1ef" dependencies = [ "aws-lc-rs", "ring", @@ -2074,15 +2666,6 @@ version = "1.0.23" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9774ba4a74de5f7b1c1451ed6cd5285a32eddb5cccb8cc655a4e50009e06477f" -[[package]] -name = "same-file" -version = "1.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" -dependencies = [ - "winapi-util", -] - [[package]] name = "schannel" version = "0.1.29" @@ -2100,12 +2683,25 @@ checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" [[package]] name = "security-framework" -version = "3.7.0" +version = "2.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7f4bc775c73d9a02cde8bf7b2ec4c9d12743edf609006c7facc23998404cd1d" +checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02" dependencies = [ "bitflags", - "core-foundation", + "core-foundation 0.9.4", + "core-foundation-sys", + "libc", + "security-framework-sys", +] + +[[package]] +name = "security-framework" +version = "3.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d17b898a6d6948c3a8ee4372c17cb384f90d2e6e912ef00895b14fd7ab54ec38" +dependencies = [ + "bitflags", + "core-foundation 0.10.1", "core-foundation-sys", "libc", "security-framework-sys", @@ -2132,9 +2728,9 @@ dependencies = [ [[package]] name = "semver" -version = "1.0.27" +version = "1.0.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d767eb0aabc880b29956c35734170f26ed551a859dbd361d140cdbeca61ab1e2" +checksum = "8a7852d02fc848982e0c167ef163aaff9cd91dc640ba85e263cb1ce46fae51cd" [[package]] name = "semver-parser" @@ -2142,6 +2738,12 @@ version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" +[[package]] +name = "seq-macro" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bc711410fbe7399f390ca1c3b60ad0f53f80e95c5eb935e52268a0e2cd49acc" + [[package]] name = "serde" version = "1.0.228" @@ -2213,6 +2815,12 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bbfa15b3dddfee50a0fff136974b3e1bde555604ba463834a7eb7deb6417705d" +[[package]] +name = "shell-words" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc6fe69c597f9c37bfeeeeeb33da3530379845f10be461a66d16d03eca2ded77" + [[package]] name = "shlex" version = "1.3.0" @@ -2221,9 +2829,9 @@ checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" [[package]] name = "signal-hook" -version = "0.4.3" +version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b57709da74f9ff9f4a27dce9526eec25ca8407c45a7887243b031a58935fb8e" +checksum = "b2a0c28ca5908dbdbcd52e6fdaa00358ab88637f8ab33e1f188dd510eb44b53d" dependencies = [ "libc", "signal-hook-registry", @@ -2239,12 +2847,6 @@ dependencies = [ "libc", ] -[[package]] -name = "siphasher" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2aa850e253778c88a04c3d7323b043aeda9d3e30d5971937c1855769763678e" - [[package]] name = "slab" version = "0.4.12" @@ -2280,8 +2882,6 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7428a49d323867702cd12b97b08a6b0104f39ec13b49117911f101271321bc1a" dependencies = [ - "async-executor", - "async-io", "futures-io", "hyper", "pin-project-lite", @@ -2423,6 +3023,31 @@ dependencies = [ "syn 2.0.117", ] +[[package]] +name = "tagptr" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b2093cf4c8eb1e67749a6762251bc9cd836b6fc171623bd0a9d324d37af2417" + +[[package]] +name = "target-lexicon" +version = "0.13.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "adb6935a6f5c20170eeceb1a3835a49e12e19d792f6dd344ccc76a985ca5a6ca" + +[[package]] +name = "tempfile" +version = "3.27.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32497e9a4c7b38532efcdebeef879707aa9f794296a4f0244f6f69e9bc8574bd" +dependencies = [ + "fastrand", + "getrandom 0.3.4", + "once_cell", + "rustix", + "windows-sys 0.61.2", +] + [[package]] name = "termtree" version = "0.5.1" @@ -2486,24 +3111,24 @@ dependencies = [ [[package]] name = "time" -version = "0.3.47" +version = "0.3.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "743bd48c283afc0388f9b8827b976905fb217ad9e647fae3a379a9283c4def2c" +checksum = "8a7619e19bc266e0f9c5e6686659d394bc57973859340060a69221e57dbc0c40" dependencies = [ "deranged", "itoa", "num-conv", "powerfmt", - "serde_core", + "serde", "time-core", - "time-macros 0.2.27", + "time-macros 0.2.22", ] [[package]] name = "time-core" -version = "0.1.8" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7694e1cfe791f8d31026952abf09c69ca6f6fa4e1a1229e18988f06a04a12dca" +checksum = "c9e9a38711f559d9e3ce1cdb06dd7c5b8ea546bc90052da6d06bb76da74bb07c" [[package]] name = "time-macros" @@ -2517,9 +3142,9 @@ dependencies = [ [[package]] name = "time-macros" -version = "0.2.27" +version = "0.2.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e70e4c5a0e0a8a4823ad65dfe1a6930e4f4d756dcd9dd7939022b5e8c501215" +checksum = "3526739392ec93fd8b359c8e98514cb3e8e021beb4e5f597b00a0221f8ed8a49" dependencies = [ "num-conv", "time-core", @@ -2540,9 +3165,9 @@ dependencies = [ [[package]] name = "tinystr" -version = "0.8.2" +version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42d3e9c45c09de15d06dd8acf5f4e0e399e85927b7f00711024eb7ae10fa4869" +checksum = "9117f5d4db391c1cf6927e7bea3db74b9a1c1add8f7eda9ffd5364f40f57b82f" dependencies = [ "displaydoc", "zerovec", @@ -2565,14 +3190,13 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.50.0" +version = "1.51.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "27ad5e34374e03cfffefc301becb44e9dc3c17584f414349ebe29ed26661822d" +checksum = "f66bf9585cda4b724d3e78ab34b73fb2bbaba9011b9bfdf69dc836382ea13b8c" dependencies = [ "bytes", "libc", "mio", - "parking_lot", "pin-project-lite", "signal-hook-registry", "socket2 0.6.3", @@ -2582,9 +3206,9 @@ dependencies = [ [[package]] name = "tokio-macros" -version = "2.6.1" +version = "2.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c55a2eff8b69ce66c84f85e1da1c233edc36ceb85a2058d11b0d6a3c7e7569c" +checksum = "385a6cb71ab9ab790c5fe8d67f1645e6c450a7ce006a33de03daa956cf70a496" dependencies = [ "proc-macro2", "quote", @@ -2626,7 +3250,6 @@ version = "0.1.44" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "63e71662fa4b2a2c3a26f570f037eb95bb1f85397f3cd8076caed2f026a6d100" dependencies = [ - "log", "pin-project-lite", "tracing-attributes", "tracing-core", @@ -2685,12 +3308,10 @@ checksum = "10a3e6c3aff1718b3c73e395d1f35202ba2ffa847c6a62eea0db8fb4cfe30be6" dependencies = [ "cfg-if", "futures-util", - "ipconfig", "lru-cache", "once_cell", "parking_lot", "rand 0.8.5", - "resolv-conf", "smallvec", "thiserror 1.0.69", "tokio", @@ -2704,6 +3325,12 @@ version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" +[[package]] +name = "typenum" +version = "1.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "562d481066bde0658276a35467c4af00bdc6ee726305698a55b86e61d7ad82bb" + [[package]] name = "unicode-bidi" version = "0.3.18" @@ -2731,6 +3358,12 @@ version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" +[[package]] +name = "unindent" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7264e107f553ccae879d21fbea1d6724ac785e8c3bfc762137959b5802826ef3" + [[package]] name = "unsafe-libyaml" version = "0.2.11" @@ -2761,6 +3394,12 @@ version = "2.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "daf8dba3b7eb870caf1ddeed7bc9d2a049f3cfdfae7cb521b087cc33ae4c49da" +[[package]] +name = "utf16_iter" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8232dd3cdaed5356e0f716d285e4b40b932ac434100fe9b7e0e8e935b9e6246" + [[package]] name = "utf8_iter" version = "1.0.4" @@ -2773,12 +3412,29 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" +[[package]] +name = "uuid" +version = "1.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee48d38b119b0cd71fe4141b30f5ba9c7c5d9f4e7a3a8b4a674e4b6ef789976f" +dependencies = [ + "getrandom 0.3.4", + "js-sys", + "wasm-bindgen", +] + [[package]] name = "value-bag" version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7ba6f5989077681266825251a52748b8c1d8a4ad098cc37e440103d0ea717fc0" +[[package]] +name = "vcpkg" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" + [[package]] name = "version_check" version = "0.9.5" @@ -2788,25 +3444,79 @@ checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" [[package]] name = "vetis" version = "0.1.4-beta.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50124f6d436fd2047a885a7d75811c4eec05e1d9429d00137a68ecddc049cd0d" dependencies = [ + "argon2", + "async-lock", + "base64", + "bcrypt", + "bytes", + "cfg-if", + "clap", + "env_logger", + "futures-util", + "http", + "http-body-util", + "hyper-body-utils", + "log", + "mimalloc", + "mime", + "minimime", + "moka", + "parse_duration", + "radix_trie", + "rand 0.9.2", + "regex", + "serde", + "serde_yaml_ng", + "socket2 0.6.3", + "thiserror 2.0.18", + "time 0.3.41", + "url", +] + +[[package]] +name = "vetis-fcgi" +version = "0.1.0" +dependencies = [ + "http", + "hyper-body-utils", + "log", + "tokio", + "vetis", +] + +[[package]] +name = "vetis-rack" +version = "0.1.0" +dependencies = [ + "http", + "hyper-body-utils", + "log", + "magnus", + "mimalloc", + "tokio", + "vetis", +] + +[[package]] +name = "vetis-smol" +version = "0.1.0-beta.1" +dependencies = [ + "async-native-tls", "async-signal", - "blocking", "bytes", "cfg-if", "clap", - "crossfire", "deboa", + "deboa-smol", "env_logger", "futures-lite", "futures-rustls", "futures-util", - "h3", - "h3-quinn", "http", "http-body-util", "hyper", + "hyper-body-utils", "hyper-util", "log", "macro_rules_attribute", @@ -2815,7 +3525,6 @@ dependencies = [ "quinn", "radix_trie", "rand 0.9.2", - "rt-gate", "rustls", "serde", "serde_yaml_ng", @@ -2823,22 +3532,70 @@ dependencies = [ "smol", "smol-hyper", "smol-macros", + "socket2 0.6.3", + "thiserror 2.0.18", + "time 0.3.41", + "url", + "vetis", + "vetis-fcgi", + "vetis-rack", + "vetis-wsgi", +] + +[[package]] +name = "vetis-tokio" +version = "0.1.0-beta.1" +dependencies = [ + "async-lock", + "bytes", + "cfg-if", + "clap", + "deboa", + "deboa-tokio", + "env_logger", + "futures-rustls", + "futures-util", + "http", + "http-body-util", + "hyper", + "hyper-body-utils", + "hyper-util", + "log", + "mimalloc", + "minimime", + "moka", + "peekable", + "quinn", + "radix_trie", + "rand 0.9.2", + "regex", + "rustls", + "serde", + "serde_yaml_ng", + "socket2 0.6.3", "thiserror 2.0.18", - "time 0.3.47", + "time 0.3.41", "tokio", "tokio-rustls", "tokio-util", "url", + "vetis", + "vetis-fcgi", + "vetis-rack", + "vetis-wsgi", ] [[package]] -name = "walkdir" -version = "2.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" +name = "vetis-wsgi" +version = "0.1.0" dependencies = [ - "same-file", - "winapi-util", + "crossfire", + "http", + "hyper-body-utils", + "log", + "pyo3", + "tokio", + "vetis", ] [[package]] @@ -2876,9 +3633,9 @@ dependencies = [ [[package]] name = "wasm-bindgen" -version = "0.2.108" +version = "0.2.117" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64024a30ec1e37399cf85a7ffefebdb72205ca1c972291c51512360d90bd8566" +checksum = "0551fc1bb415591e3372d0bc4780db7e587d84e2a7e79da121051c5c4b89d0b0" dependencies = [ "cfg-if", "once_cell", @@ -2889,23 +3646,19 @@ dependencies = [ [[package]] name = "wasm-bindgen-futures" -version = "0.4.58" +version = "0.4.67" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70a6e77fd0ae8029c9ea0063f87c46fde723e7d887703d74ad2616d792e51e6f" +checksum = "03623de6905b7206edd0a75f69f747f134b7f0a2323392d664448bf2d3c5d87e" dependencies = [ - "cfg-if", - "futures-util", "js-sys", - "once_cell", "wasm-bindgen", - "web-sys", ] [[package]] name = "wasm-bindgen-macro" -version = "0.2.108" +version = "0.2.117" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "008b239d9c740232e71bd39e8ef6429d27097518b6b30bdf9086833bd5b6d608" +checksum = "7fbdf9a35adf44786aecd5ff89b4563a90325f9da0923236f6104e603c7e86be" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -2913,9 +3666,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.108" +version = "0.2.117" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5256bae2d58f54820e6490f9839c49780dff84c65aeab9e772f15d5f0e913a55" +checksum = "dca9693ef2bab6d4e6707234500350d8dad079eb508dca05530c85dc3a529ff2" dependencies = [ "bumpalo", "proc-macro2", @@ -2926,9 +3679,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-shared" -version = "0.2.108" +version = "0.2.117" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f01b580c9ac74c8d8f0c0e4afb04eeef2acf145458e52c03845ee9cd23e3d12" +checksum = "39129a682a6d2d841b6c429d0c51e5cb0ed1a03829d8b3d1e69a011e62cb3d3b" dependencies = [ "unicode-ident", ] @@ -2964,17 +3717,7 @@ dependencies = [ "bitflags", "hashbrown 0.15.5", "indexmap", - "semver 1.0.27", -] - -[[package]] -name = "web-sys" -version = "0.3.85" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "312e32e551d92129218ea9a2452120f4aabc03529ef03e4d0d82fb2780608598" -dependencies = [ - "js-sys", - "wasm-bindgen", + "semver 1.0.28", ] [[package]] @@ -2987,15 +3730,6 @@ dependencies = [ "wasm-bindgen", ] -[[package]] -name = "webpki-root-certs" -version = "1.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "804f18a4ac2676ffb4e8b5b5fa9ae38af06df08162314f96a68d2a363e21a8ca" -dependencies = [ - "rustls-pki-types", -] - [[package]] name = "webpki-roots" version = "1.0.6" @@ -3005,12 +3739,6 @@ dependencies = [ "rustls-pki-types", ] -[[package]] -name = "widestring" -version = "1.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72069c3113ab32ab29e5584db3c6ec55d416895e60715417b5b883a357c3e471" - [[package]] name = "winapi" version = "0.3.9" @@ -3027,15 +3755,6 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" -[[package]] -name = "winapi-util" -version = "0.1.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22" -dependencies = [ - "windows-sys 0.61.2", -] - [[package]] name = "winapi-x86_64-pc-windows-gnu" version = "0.4.0" @@ -3048,24 +3767,6 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" -[[package]] -name = "windows-sys" -version = "0.45.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0" -dependencies = [ - "windows-targets 0.42.2", -] - -[[package]] -name = "windows-sys" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" -dependencies = [ - "windows-targets 0.48.5", -] - [[package]] name = "windows-sys" version = "0.52.0" @@ -3093,36 +3794,6 @@ dependencies = [ "windows-link", ] -[[package]] -name = "windows-targets" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071" -dependencies = [ - "windows_aarch64_gnullvm 0.42.2", - "windows_aarch64_msvc 0.42.2", - "windows_i686_gnu 0.42.2", - "windows_i686_msvc 0.42.2", - "windows_x86_64_gnu 0.42.2", - "windows_x86_64_gnullvm 0.42.2", - "windows_x86_64_msvc 0.42.2", -] - -[[package]] -name = "windows-targets" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" -dependencies = [ - "windows_aarch64_gnullvm 0.48.5", - "windows_aarch64_msvc 0.48.5", - "windows_i686_gnu 0.48.5", - "windows_i686_msvc 0.48.5", - "windows_x86_64_gnu 0.48.5", - "windows_x86_64_gnullvm 0.48.5", - "windows_x86_64_msvc 0.48.5", -] - [[package]] name = "windows-targets" version = "0.52.6" @@ -3156,18 +3827,6 @@ dependencies = [ "windows_x86_64_msvc 0.53.1", ] -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8" - -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" - [[package]] name = "windows_aarch64_gnullvm" version = "0.52.6" @@ -3180,18 +3839,6 @@ version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a9d8416fa8b42f5c947f8482c43e7d89e73a173cead56d044f6a56104a6d1b53" -[[package]] -name = "windows_aarch64_msvc" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" - [[package]] name = "windows_aarch64_msvc" version = "0.52.6" @@ -3204,18 +3851,6 @@ version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b9d782e804c2f632e395708e99a94275910eb9100b2114651e04744e9b125006" -[[package]] -name = "windows_i686_gnu" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f" - -[[package]] -name = "windows_i686_gnu" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" - [[package]] name = "windows_i686_gnu" version = "0.52.6" @@ -3240,18 +3875,6 @@ version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fa7359d10048f68ab8b09fa71c3daccfb0e9b559aed648a8f95469c27057180c" -[[package]] -name = "windows_i686_msvc" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060" - -[[package]] -name = "windows_i686_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" - [[package]] name = "windows_i686_msvc" version = "0.52.6" @@ -3264,18 +3887,6 @@ version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e7ac75179f18232fe9c285163565a57ef8d3c89254a30685b57d83a38d326c2" -[[package]] -name = "windows_x86_64_gnu" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" - [[package]] name = "windows_x86_64_gnu" version = "0.52.6" @@ -3288,18 +3899,6 @@ version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c3842cdd74a865a8066ab39c8a7a473c0778a3f29370b5fd6b4b9aa7df4a499" -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" - [[package]] name = "windows_x86_64_gnullvm" version = "0.52.6" @@ -3312,18 +3911,6 @@ version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0ffa179e2d07eee8ad8f57493436566c7cc30ac536a3379fdf008f47f6bb7ae1" -[[package]] -name = "windows_x86_64_msvc" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" - [[package]] name = "windows_x86_64_msvc" version = "0.52.6" @@ -3336,16 +3923,6 @@ version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d6bbff5f0aada427a1e5a6da5f1f98158182f26556f345ac9e04d36d0ebed650" -[[package]] -name = "winreg" -version = "0.50.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "524e57b2c537c0f9b1e69f1965311ec12182b4122e45035b1508cd24d2adadb1" -dependencies = [ - "cfg-if", - "windows-sys 0.48.0", -] - [[package]] name = "wit-bindgen" version = "0.51.0" @@ -3426,7 +4003,7 @@ dependencies = [ "id-arena", "indexmap", "log", - "semver 1.0.27", + "semver 1.0.28", "serde", "serde_derive", "serde_json", @@ -3434,18 +4011,25 @@ dependencies = [ "wasmparser", ] +[[package]] +name = "write16" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1890f4022759daae28ed4fe62859b1236caebfc61ede2f63ed4e695f3f6d936" + [[package]] name = "writeable" -version = "0.6.2" +version = "0.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9edde0db4769d2dc68579893f2306b26c6ecfbe0ef499b013d731b7b9247e0b9" +checksum = "1e9df38ee2d2c3c5948ea468a8406ff0db0b29ae1ffde1bcf20ef305bcc95c51" [[package]] name = "yoke" -version = "0.8.1" +version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72d6e5c6afb84d73944e5cedb052c4680d5657337201555f9f2a16b7406d4954" +checksum = "120e6aef9aa629e3d4f52dc8cc43a015c7724194c97dfaf45180d2daf2b77f40" dependencies = [ + "serde", "stable_deref_trait", "yoke-derive", "zerofrom", @@ -3453,9 +4037,9 @@ dependencies = [ [[package]] name = "yoke-derive" -version = "0.8.1" +version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b659052874eb698efe5b9e8cf382204678a0086ebf46982b79d6ca3182927e5d" +checksum = "2380878cad4ac9aac1e2435f3eb4020e8374b5f13c296cb75b4620ff8e229154" dependencies = [ "proc-macro2", "quote", @@ -3465,18 +4049,18 @@ dependencies = [ [[package]] name = "zerocopy" -version = "0.8.42" +version = "0.8.48" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2578b716f8a7a858b7f02d5bd870c14bf4ddbbcf3a4c05414ba6503640505e3" +checksum = "eed437bf9d6692032087e337407a86f04cd8d6a16a37199ed57949d415bd68e9" dependencies = [ "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.8.42" +version = "0.8.48" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e6cc098ea4d3bd6246687de65af3f920c430e236bee1e3bf2e441463f08a02f" +checksum = "70e3cd084b1788766f53af483dd21f93881ff30d7320490ec3ef7526d203bad4" dependencies = [ "proc-macro2", "quote", @@ -3485,18 +4069,18 @@ dependencies = [ [[package]] name = "zerofrom" -version = "0.1.6" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50cc42e0333e05660c3587f3bf9d0478688e15d870fab3346451ce7f8c9fbea5" +checksum = "69faa1f2a1ea75661980b013019ed6687ed0e83d069bc1114e2cc74c6c04c4df" dependencies = [ "zerofrom-derive", ] [[package]] name = "zerofrom-derive" -version = "0.1.6" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502" +checksum = "11532158c46691caf0f2593ea8358fed6bbf68a0315e80aae9bd41fbade684a1" dependencies = [ "proc-macro2", "quote", @@ -3510,22 +4094,11 @@ version = "1.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b97154e67e32c85465826e8bcc1c59429aaaf107c1e4a9e53c8d8ccd5eff88d0" -[[package]] -name = "zerotrie" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a59c17a5562d507e4b54960e8569ebee33bee890c70aa3fe7b97e85a9fd7851" -dependencies = [ - "displaydoc", - "yoke", - "zerofrom", -] - [[package]] name = "zerovec" -version = "0.11.5" +version = "0.10.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c28719294829477f525be0186d13efa9a3c602f7ec202ca9e353d310fb9a002" +checksum = "aa2b893d79df23bfb12d5461018d408ea19dfafe76c2c7ef6d4eba614f8ff079" dependencies = [ "yoke", "zerofrom", @@ -3534,9 +4107,9 @@ dependencies = [ [[package]] name = "zerovec-derive" -version = "0.11.2" +version = "0.10.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eadce39539ca5cb3985590102671f2567e659fca9666581ad3411d59207951f3" +checksum = "6eafa6dfb17584ea3e2bd6e76e0cc15ad7af12b09abdd1ca55961bed9b1063c6" dependencies = [ "proc-macro2", "quote", diff --git a/Cargo.toml b/Cargo.toml index 7263e4d..5681183 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,42 +1,21 @@ -[package] -name = "easyhttpmock" -version = "0.1.3-beta.7" -edition = "2021" -authors = ["Rogerio Araújo "] -repository = "https://github.com/ararog/easyhttpmock" -homepage = "https://github.com/ararog/easyhttpmock" -description = "EasyHttpMock is a simple HTTP mock server for testing HTTP clients." -readme = "README.md" -license = "MIT" -keywords = ["http", "mock", "testing"] -publish = true -rust-version = "1.75.0" +[workspace] +# Use the latest resolver available +resolver = "3" +# Include both parts of the library in the workspace +members = [ + "easyhttpmock", + "easyhttpmock-vetis-smol", + "easyhttpmock-vetis-tokio", +] -[package.metadata.docs.rs] -all-features = true +[profile.release] +strip = true +opt-level = "z" +lto = true +codegen-units = 1 +panic = "abort" -[features] -default = ["tokio-rt", "http2", "tokio-rust-tls"] - -tokio-rt = ["vetis/tokio-rt", "vetis/__deboa_tokio"] -smol-rt = ["vetis/smol-rt", "vetis/__deboa_smol"] -#compio-rt = ["vetis/compio-rt"] - -tokio-rust-tls = ["vetis/tokio-rust-tls"] -smol-rust-tls = ["vetis/smol-rust-tls"] -#compio-rust-tls = ["vetis/compio-rust-tls"] - -http1 = ["vetis/http1"] -http2 = ["vetis/http2"] -http3 = ["vetis/http3"] - -[dependencies] -bytes = "1.11.0" -http = "1.4.0" -http-body-util = "0.1.3" -hyper = { version = "1.8.1", features = ["full"] } -hyper-util = "0.1.9" -rand = "0.10.0" -thiserror = "2.0.17" -tokio = { version = "1.50", features = ["full"] } -vetis = { version = "0.1.4-beta.5", optional = true, default-features = false } +# The profile that 'dist' will build with +[profile.dist] +inherits = "release" +lto = "thin" diff --git a/LICENSE-APACHE.md b/LICENSE-APACHE.md new file mode 100644 index 0000000..c6c6f01 --- /dev/null +++ b/LICENSE-APACHE.md @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright 2020 quininer kel + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. \ No newline at end of file diff --git a/LICENSE b/LICENSE-MIT.md similarity index 93% rename from LICENSE rename to LICENSE-MIT.md index f8e760d..01c3389 100644 --- a/LICENSE +++ b/LICENSE-MIT.md @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2026 ararog +Copyright (c) 2025 Rogerio Pereira Araújo Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal @@ -19,3 +19,4 @@ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + diff --git a/easyhttpmock-vetis-smol/Cargo.toml b/easyhttpmock-vetis-smol/Cargo.toml new file mode 100644 index 0000000..0c44896 --- /dev/null +++ b/easyhttpmock-vetis-smol/Cargo.toml @@ -0,0 +1,22 @@ +[package] +name = "easyhttpmock-vetis-smol" +version = "0.1.0-beta.1" +edition = "2021" +authors = ["Rogerio Araújo "] +repository = "https://github.com/ararog/easyhttpmock" +homepage = "https://github.com/ararog/easyhttpmock" +description = "EasyHttpMock adapter for Vetis HTTP server using smol runtime." +readme = "README.md" +license = "MIT OR Apache-2.0" +keywords = ["http", "mock", "testing"] +publish = true +rust-version = "1.75.0" + +[package.metadata.docs.rs] +all-features = true + +[dependencies] +easyhttpmock = { path = "../easyhttpmock" } +http = "1.4.0" +rand = "0.9.2" +vetis-smol = { path = "../../vetis/vetis-smol" } diff --git a/easyhttpmock-vetis-smol/src/lib.rs b/easyhttpmock-vetis-smol/src/lib.rs new file mode 100644 index 0000000..cd7eeb3 --- /dev/null +++ b/easyhttpmock-vetis-smol/src/lib.rs @@ -0,0 +1,2 @@ +pub mod vetis_adapter; +pub use easyhttpmock::*; diff --git a/src/server/adapters/vetis_adapter.rs b/easyhttpmock-vetis-smol/src/vetis_adapter.rs similarity index 78% rename from src/server/adapters/vetis_adapter.rs rename to easyhttpmock-vetis-smol/src/vetis_adapter.rs index b186498..bd08375 100644 --- a/src/server/adapters/vetis_adapter.rs +++ b/easyhttpmock-vetis-smol/src/vetis_adapter.rs @@ -1,23 +1,20 @@ -use std::future::Future; +use std::{future::Future, sync::Arc}; -use vetis::{ - config::server::{ - virtual_host::{SecurityConfig, VirtualHostConfig}, - ListenerConfig, Protocol, ServerConfig, - }, +use vetis_smol::{ errors::VetisError, - server::{ - http::{Request, Response}, - virtual_host::{handler_fn, path::HandlerPath, VirtualHost}, - }, - Vetis, + http::Response, + listener::ListenerConfig, + server::virtual_host::{handler_fn, path::HandlerPath, VirtualHost}, + virtual_host::{SecurityConfig, VirtualHostConfig}, + Protocol, ServerConfig, Vetis, }; -use crate::{ - config::EasyHttpMockConfig, +use easyhttpmock::{ errors::{EasyHttpMockError, ServerError}, + expect::{Then, When}, + mock_fn, server::{PortGenerator, ServerAdapter}, - EasyHttpMock, + BoxedHandlerClosure, }; /// Builder for VetisAdapterConfig @@ -257,6 +254,7 @@ impl From for ServerConfig { pub struct VetisAdapter { server: Vetis, config: VetisAdapterConfig, + mocker: Option>, } impl PortGenerator for VetisAdapterConfigBuilder { @@ -266,37 +264,6 @@ impl PortGenerator for VetisAdapterConfigBuilder { } } -impl Default for EasyHttpMockConfig { - /// Creates a default configuration for the Vetis adapter. - /// - /// This function sets up a basic server configuration with: - /// - Interface: "0.0.0.0" - /// - Port: 80 - /// - No TLS certificates (HTTP only) - /// - /// # Returns - /// A default `EasyHttpMockConfig` configured for the Vetis adapter. - fn default() -> Self { - let server_config = VetisAdapterConfig::builder() - .interface("0.0.0.0") - .cert(None) - .key(None) - .ca(None) - .port(80) - .build(); - EasyHttpMockConfig::::builder() - .server_config(server_config.clone()) - .base_url(format!("http://localhost:{}", 80).into()) - .build() - } -} - -impl Default for EasyHttpMock { - fn default() -> Self { - EasyHttpMock::new(EasyHttpMockConfig::default()).unwrap() - } -} - impl ServerAdapter for VetisAdapter { type Config = VetisAdapterConfig; @@ -314,7 +281,7 @@ impl ServerAdapter for VetisAdapter { let server = Vetis::new(vetis_config); - Ok(Self { server, config }) + Ok(Self { server, config, mocker: None }) } /// Returns the hostname of the server. @@ -354,6 +321,24 @@ impl ServerAdapter for VetisAdapter { &self.config } + /// Sets the mocker to handle incoming requests. + /// + /// # Arguments + /// + /// * `mocker` - The mocker to handle incoming requests. + /// + /// # Returns + /// + /// * `Result<(), EasyHttpMockError>` - The result of the operation. + /// + fn mocker(&mut self, mocker: F) + where + F: Fn(When) -> Fut + Send + Sync + 'static, + Fut: Future> + Send + Sync + 'static, + { + self.mocker = Some(mock_fn(mocker).into()); + } + /// Starts the server with the given handler. /// /// # Arguments @@ -364,25 +349,55 @@ impl ServerAdapter for VetisAdapter { /// /// A result indicating whether the server started successfully or a `EasyHttpMockError` if it failed. /// - /// TODO: Make handler a EasyHttpMockHandler and convert from EasyMockRequest - /// and Response to Vetis Request and Response. Maybe have From implementation - /// for EasyMockRequest and Response. - async fn start(&mut self, handler: H) -> Result<(), EasyHttpMockError> - where - H: Fn(Request) -> Fut + Send + Sync + 'static, - Fut: Future> + Send + Sync + 'static, - { + async fn start(&mut self) -> Result<(), EasyHttpMockError> { + let mocker = match self.mocker.as_ref() { + Some(mocker) => mocker, + None => return Err(EasyHttpMockError::MockNotFound), + }; + + let mocker_clone = mocker.clone(); let path = HandlerPath::builder() .uri("/") - .handler(handler_fn(handler)) - .build() - .unwrap(); + .handler(handler_fn(move |request| { + // Since handler function is defined here, we need to clone the mocker + // to move it into the async block + let value = mocker_clone.clone(); + async move { + let (parts, _body) = request.into_parts(); + let when = When::builder() + .path( + parts + .uri + .path() + .to_string(), + ) + .method( + parts + .method + .to_string(), + ) + .headers(parts.headers) + .body(String::new()); + + let then = value(when).await; + + if let Err(e) = then { + return Err(VetisError::Handler(e.to_string())); + } + + let then = then.unwrap(); + Ok(Response::builder() + .status(then.status_code()) + .text(&then.body())) + } + })) + .build(); let hostname = self.hostname(); let host_config = VirtualHostConfig::builder() .hostname(&hostname) - .root_directory("src/tests") + .root_directory(".") .port(self.config.port()); let host_config = if let Some(((cert, key), ca)) = self @@ -416,7 +431,11 @@ impl ServerAdapter for VetisAdapter { .map_err(|e| EasyHttpMockError::Server(ServerError::Creation(e.to_string())))?; let mut host = VirtualHost::new(host_config); - host.add_path(path); + if let Err(e) = path { + return Err(EasyHttpMockError::Server(ServerError::Creation(e.to_string()))); + } + + host.add_path(path.unwrap()); self.server .add_virtual_host(host) diff --git a/easyhttpmock-vetis-tokio/Cargo.toml b/easyhttpmock-vetis-tokio/Cargo.toml new file mode 100644 index 0000000..111e578 --- /dev/null +++ b/easyhttpmock-vetis-tokio/Cargo.toml @@ -0,0 +1,22 @@ +[package] +name = "easyhttpmock-vetis-tokio" +version = "0.1.0-beta.1" +edition = "2021" +authors = ["Rogerio Araújo "] +repository = "https://github.com/ararog/easyhttpmock" +homepage = "https://github.com/ararog/easyhttpmock" +description = "EasyHttpMock adapter for Vetis HTTP server using tokio runtime." +readme = "README.md" +license = "MIT OR Apache-2.0" +keywords = ["http", "mock", "testing"] +publish = true +rust-version = "1.75.0" + +[package.metadata.docs.rs] +all-features = true + +[dependencies] +easyhttpmock = { path = "../easyhttpmock" } +http = "1.4.0" +rand = "0.9.2" +vetis-tokio = { path = "../../vetis/vetis-tokio" } diff --git a/src/server/adapters/mod.rs b/easyhttpmock-vetis-tokio/src/lib.rs similarity index 100% rename from src/server/adapters/mod.rs rename to easyhttpmock-vetis-tokio/src/lib.rs diff --git a/easyhttpmock-vetis-tokio/src/vetis_adapter.rs b/easyhttpmock-vetis-tokio/src/vetis_adapter.rs new file mode 100644 index 0000000..d301aed --- /dev/null +++ b/easyhttpmock-vetis-tokio/src/vetis_adapter.rs @@ -0,0 +1,460 @@ +use std::{future::Future, sync::Arc}; + +use vetis_tokio::{ + errors::VetisError, + http::Response, + listener::ListenerConfig, + server::virtual_host::{handler_fn, path::HandlerPath, VirtualHost}, + virtual_host::{SecurityConfig, VirtualHostConfig}, + Protocol, ServerConfig, Vetis, +}; + +use easyhttpmock::{ + errors::{EasyHttpMockError, ServerError}, + expect::{Then, When}, + mock_fn, + server::{PortGenerator, ServerAdapter}, + BoxedHandlerClosure, +}; + +/// Builder for VetisAdapterConfig +pub struct VetisAdapterConfigBuilder { + hostname: Option, + interface: String, + protocol: Protocol, + port: u16, + cert: Option>, + key: Option>, + ca: Option>, +} + +impl VetisAdapterConfigBuilder { + /// Sets the hostname for the server. + /// + /// # Arguments + /// * `hostname` - The hostname to set. + /// + /// # Returns + /// A new `VetisAdapterConfigBuilder` instance with the hostname set. + pub fn hostname(mut self, hostname: Option) -> Self { + self.hostname = hostname; + self + } + + /// Sets the interface for the server. + /// + /// # Arguments + /// * `interface` - The interface to set. + /// + /// # Returns + /// A new `VetisAdapterConfigBuilder` instance with the interface set. + pub fn interface(mut self, interface: &str) -> Self { + self.interface = interface.to_string(); + self + } + + /// Sets the protocol for the server. + /// + /// # Arguments + /// * `protocol` - The protocol to set. + /// + /// # Returns + /// A new `VetisAdapterConfigBuilder` instance with the protocol set. + pub fn protocol(mut self, protocol: Protocol) -> Self { + self.protocol = protocol; + self + } + + /// Sets the port for the server. + /// + /// # Arguments + /// * `port` - The port to set. + /// + /// # Returns + /// A new `VetisAdapterConfigBuilder` instance with the port set. + pub fn port(mut self, port: u16) -> Self { + self.port = port; + self + } + + /// Sets the certificate for the server. + /// + /// # Arguments + /// * `cert` - The certificate to set. + /// + /// # Returns + /// A new `VetisAdapterConfigBuilder` instance with the certificate set. + pub fn cert(mut self, cert: Option>) -> Self { + self.cert = cert; + self + } + + /// Sets the key for the server. + /// + /// # Arguments + /// * `key` - The key to set. + /// + /// # Returns + /// A new `VetisAdapterConfigBuilder` instance with the key set. + pub fn key(mut self, key: Option>) -> Self { + self.key = key; + self + } + + /// Sets the CA certificate for the server. + /// + /// # Arguments + /// * `ca` - The CA certificate to set. + /// + /// # Returns + /// A new `VetisAdapterConfigBuilder` instance with the CA certificate set. + pub fn ca(mut self, ca: Option>) -> Self { + self.ca = ca; + self + } + + /// Builds the VetisAdapterConfig from the builder. + /// + /// # Returns + /// A new `VetisAdapterConfig` instance. + pub fn build(self) -> VetisAdapterConfig { + VetisAdapterConfig { + hostname: self.hostname, + interface: self.interface, + protocol: self.protocol, + port: self.port, + cert: self.cert, + key: self.key, + ca: self.ca, + } + } +} + +/// Configuration for the Vetis adapter. +#[derive(Clone)] +pub struct VetisAdapterConfig { + hostname: Option, + interface: String, + protocol: Protocol, + port: u16, + cert: Option>, + key: Option>, + ca: Option>, +} + +impl Default for VetisAdapterConfig { + /// Creates a default configuration for the Vetis adapter. + /// + /// This function sets up a basic server configuration with: + /// - Interface: "0.0.0.0" + /// - Port: 80 + /// - No TLS certificates (HTTP only) + /// + /// # Returns + /// A default `VetisAdapterConfig` instance. + fn default() -> Self { + Self { + hostname: None, + interface: "0.0.0.0".into(), + protocol: Protocol::Http1, + port: 80, + cert: None, + key: None, + ca: None, + } + } +} + +impl VetisAdapterConfig { + /// Creates a new builder for the Vetis adapter configuration. + /// + /// This function sets up a basic server configuration with: + /// - Interface: "0.0.0.0" + /// - Port: 80 + /// - No TLS certificates (HTTP only) + /// + /// # Returns + /// A new `VetisAdapterConfigBuilder` instance. + pub fn builder() -> VetisAdapterConfigBuilder { + VetisAdapterConfigBuilder { + hostname: None, + interface: "0.0.0.0".into(), + protocol: Protocol::Http1, + port: 80, + cert: None, + key: None, + ca: None, + } + } + + /// Returns the hostname of the server. + /// + /// # Returns + /// The hostname of the server. + pub fn hostname(&self) -> &Option { + &self.hostname + } + + /// Returns the interface of the server. + /// + /// # Returns + /// The interface of the server. + pub fn interface(&self) -> &str { + &self.interface + } + + /// Returns the port of the server. + /// + /// # Returns + /// The port of the server. + pub fn port(&self) -> u16 { + self.port + } + + /// Returns the certificate of the server. + /// + /// # Returns + /// The certificate of the server. + pub fn cert(&self) -> &Option> { + &self.cert + } + + /// Returns the key of the server. + /// + /// # Returns + /// The key of the server. + pub fn key(&self) -> &Option> { + &self.key + } + + /// Returns the CA certificate of the server. + /// + /// # Returns + /// The CA certificate of the server. + pub fn ca(&self) -> &Option> { + &self.ca + } +} + +impl From for ServerConfig { + fn from(config: VetisAdapterConfig) -> Self { + let listener_config = ListenerConfig::builder() + .interface(&config.interface) + .protocol(config.protocol) + .port(config.port) + .build() + .expect("Failed to build listener config"); + ServerConfig::builder() + .add_listener(listener_config) + .build() + .expect("Failed to build server config") + } +} + +pub struct VetisAdapter { + server: Vetis, + config: VetisAdapterConfig, + mocker: Option>, +} + +impl PortGenerator for VetisAdapterConfigBuilder { + fn with_random_port(self) -> Self { + let port = rand::random_range(9000..65535); + self.port(port) + } +} + +impl ServerAdapter for VetisAdapter { + type Config = VetisAdapterConfig; + + /// Creates a new VetisAdapter instance. + /// + /// # Arguments + /// * `config` - The configuration for the adapter. + /// + /// # Returns + /// A new `VetisAdapter` instance. + fn new(config: Self::Config) -> Result { + let vetis_config = config + .clone() + .into(); + + let server = Vetis::new(vetis_config); + + Ok(Self { server, config, mocker: None }) + } + + /// Returns the hostname of the server. + /// + /// # Returns + /// The hostname of the server. + fn hostname(&self) -> String { + self.config + .hostname() + .clone() + .unwrap_or_else(|| "localhost".to_string()) + } + + /// Returns the base URL of the server. + /// + /// # Returns + /// The base URL of the server. + fn base_url(&self) -> String { + let hostname = self.hostname(); + + if self + .config + .cert + .is_some() + { + format!("https://{}:{}", hostname, self.config.port()) + } else { + format!("http://{}:{}", hostname, self.config.port()) + } + } + + /// Returns the configuration of the server. + /// + /// # Returns + /// The configuration of the server. + fn config(&self) -> &Self::Config { + &self.config + } + + /// Sets the mocker to handle incoming requests. + /// + /// # Arguments + /// + /// * `mocker` - The mocker to handle incoming requests. + /// + /// # Returns + /// + /// * `Result<(), EasyHttpMockError>` - The result of the operation. + /// + fn mocker(&mut self, mocker: F) + where + F: Fn(When) -> Fut + Send + Sync + 'static, + Fut: Future> + Send + Sync + 'static, + { + self.mocker = Some(mock_fn(mocker).into()); + } + + /// Starts the server with the given handler. + /// + /// # Arguments + /// + /// * `handler` - The handler to use for the server. + /// + /// # Returns + /// + /// A result indicating whether the server started successfully or a `EasyHttpMockError` if it failed. + /// + async fn start(&mut self) -> Result<(), EasyHttpMockError> { + let mocker = match self.mocker.as_ref() { + Some(mocker) => mocker, + None => return Err(EasyHttpMockError::MockNotFound), + }; + + let mocker_clone = mocker.clone(); + let path = HandlerPath::builder() + .uri("/") + .handler(handler_fn(move |request| { + // Since handler function is defined here, we need to clone the mocker + // to move it into the async block + let value = mocker_clone.clone(); + async move { + let (parts, _body) = request.into_parts(); + let when = When::builder() + .path( + parts + .uri + .path() + .to_string(), + ) + .method( + parts + .method + .to_string(), + ) + .headers(parts.headers) + .body(String::new()); + + let then = value(when).await; + + if let Err(e) = then { + return Err(VetisError::Handler(e.to_string())); + } + + let then = then.unwrap(); + Ok(Response::builder() + .status(then.status_code()) + .text(&then.body())) + } + })) + .build(); + + let hostname = self.hostname(); + + let host_config = VirtualHostConfig::builder() + .hostname(&hostname) + .root_directory(".") + .port(self.config.port()); + + let host_config = if let Some(((cert, key), ca)) = self + .config + .cert + .as_ref() + .zip( + self.config + .key + .as_ref(), + ) + .zip( + self.config + .ca + .as_ref(), + ) { + host_config.security( + SecurityConfig::builder() + .cert_from_bytes(cert.clone()) + .key_from_bytes(key.clone()) + .ca_cert_from_bytes(ca.clone()) + .build() + .map_err(|e| EasyHttpMockError::Server(ServerError::Config(e.to_string())))?, + ) + } else { + host_config + }; + + let host_config = host_config + .build() + .map_err(|e| EasyHttpMockError::Server(ServerError::Creation(e.to_string())))?; + + let mut host = VirtualHost::new(host_config); + if let Err(e) = path { + return Err(EasyHttpMockError::Server(ServerError::Creation(e.to_string()))); + } + + host.add_path(path.unwrap()); + + self.server + .add_virtual_host(host) + .await; + + self.server + .start() + .await + .map_err(|e| EasyHttpMockError::Server(ServerError::Start(e.to_string()))) + } + + /// Stops the server. + /// + /// # Returns + /// A result indicating whether the server stopped successfully. + async fn stop(&mut self) -> Result<(), EasyHttpMockError> { + self.server + .stop() + .await + .map_err(|e| EasyHttpMockError::Server(ServerError::Stop(e.to_string()))) + } +} diff --git a/easyhttpmock/Cargo.toml b/easyhttpmock/Cargo.toml new file mode 100644 index 0000000..5ed5607 --- /dev/null +++ b/easyhttpmock/Cargo.toml @@ -0,0 +1,27 @@ +[package] +name = "easyhttpmock" +version = "0.1.3-beta.7" +edition = "2021" +authors = ["Rogerio Araújo "] +repository = "https://github.com/ararog/easyhttpmock" +homepage = "https://github.com/ararog/easyhttpmock" +description = "EasyHttpMock is a simple HTTP mock server for testing HTTP clients." +readme = "README.md" +license = "MIT OR Apache-2.0" +keywords = ["http", "mock", "testing"] +publish = true +rust-version = "1.75.0" + +[package.metadata.docs.rs] +all-features = true + +[features] + +[dependencies] +bytes = "1.11.0" +http = "1.4.0" +http-body-util = "0.1.3" +hyper = { version = "1.8.1", features = ["full"] } +hyper-util = "0.1.9" +rand = "0.10.0" +thiserror = "2.0.17" diff --git a/src/config.rs b/easyhttpmock/src/config.rs similarity index 100% rename from src/config.rs rename to easyhttpmock/src/config.rs diff --git a/src/errors.rs b/easyhttpmock/src/errors.rs similarity index 90% rename from src/errors.rs rename to easyhttpmock/src/errors.rs index e6380b5..0f1e514 100644 --- a/src/errors.rs +++ b/easyhttpmock/src/errors.rs @@ -4,6 +4,8 @@ use thiserror::Error; pub enum EasyHttpMockError { #[error("Server error: {0}")] Server(#[from] ServerError), + #[error("Mock not found")] + MockNotFound, } #[derive(Debug, Clone, Error, PartialEq)] diff --git a/easyhttpmock/src/expect.rs b/easyhttpmock/src/expect.rs new file mode 100644 index 0000000..9694713 --- /dev/null +++ b/easyhttpmock/src/expect.rs @@ -0,0 +1,199 @@ +use std::collections::HashMap; + +use http::{HeaderMap, StatusCode}; + +pub struct WhenBuilder { + path: String, + method: String, + headers: HeaderMap, + query_params: HashMap, + body: String, +} + +impl WhenBuilder { + pub fn path(mut self, path: String) -> Self { + self.path = path; + self + } + + pub fn method(mut self, method: String) -> Self { + self.method = method; + self + } + + pub fn headers(mut self, headers: HeaderMap) -> Self { + self.headers = headers; + self + } + + pub fn query_params(mut self, query_params: HashMap) -> Self { + self.query_params = query_params; + self + } + + pub fn body(mut self, body: String) -> When { + self.body = body; + When { + path: self.path, + method: self.method, + headers: self.headers, + query_params: self.query_params, + body: self.body, + errors: Vec::new(), + } + } +} + +pub struct When { + path: String, + method: String, + headers: HeaderMap, + query_params: HashMap, + body: String, + errors: Vec, +} + +impl When { + pub fn builder() -> WhenBuilder { + WhenBuilder { + path: String::new(), + method: String::new(), + headers: HeaderMap::new(), + query_params: HashMap::new(), + body: String::new(), + } + } + + pub fn path(mut self, path: String) -> Self { + if !path.eq(&self.path) { + self.errors + .push(format!("No matching path, expected {}", self.path)); + } + self + } + + pub fn method(mut self, method: String) -> Self { + if !method.eq(&self.method) { + self.errors + .push(format!("No matching method, expected {}", self.method)); + } + self + } + + pub fn query_param(mut self, key: String, value: String) -> Self { + if !self + .query_params + .contains_key(&key) + { + self.errors + .push(format!("No matching query param, expected {}", key)); + } else { + let existing_value = self + .query_params + .get(&key) + .unwrap(); + if !value.eq(existing_value) { + self.errors + .push(format!("No matching query param value, expected {}", key)); + } + } + self + } + + pub fn body(mut self, body: String) -> Self { + if !body.eq(&self.body) { + self.errors + .push(format!("No matching body, expected {}", self.body)); + } + self + } + + pub fn header(mut self, key: String, value: String) -> Self { + if !self + .headers + .contains_key(&key) + { + self.errors + .push(format!("No matching header, expected {}", key)); + } else { + let existing_value = self + .headers + .get(&key) + .unwrap(); + if !value.eq(existing_value) { + self.errors + .push(format!("No matching header value, expected {}", key)); + } + } + self + } + + pub fn headers(mut self, headers: HeaderMap) -> Self { + self.headers = headers; + self + } + + pub fn then(self) -> ThenBuilder { + ThenBuilder { + status_code: StatusCode::OK, + header: (String::new(), String::new()), + body: String::new(), + errors: Vec::new(), + } + } +} + +pub struct ThenBuilder { + status_code: StatusCode, + header: (String, String), + body: String, + errors: Vec, +} + +impl ThenBuilder { + pub fn with_status(mut self, status: StatusCode) -> Self { + self.status_code = status; + self + } + + pub fn with_header(mut self, key: String, value: String) -> Self { + self.header = (key, value); + self + } + + pub fn with_body(mut self, body: String) -> Then { + self.body = body; + + Then { + status_code: self.status_code, + header: self.header, + body: self.body, + errors: self.errors, + } + } +} + +pub struct Then { + status_code: StatusCode, + header: (String, String), + body: String, + errors: Vec, +} + +impl Then { + pub fn status_code(&self) -> StatusCode { + self.status_code + } + + pub fn header(&self) -> (String, String) { + self.header.clone() + } + + pub fn body(&self) -> String { + self.body.clone() + } + + pub fn errors(&self) -> Vec { + self.errors.clone() + } +} diff --git a/easyhttpmock/src/lib.rs b/easyhttpmock/src/lib.rs new file mode 100644 index 0000000..af8fb36 --- /dev/null +++ b/easyhttpmock/src/lib.rs @@ -0,0 +1,120 @@ +use std::{future::Future, pin::Pin}; + +use crate::{ + config::EasyHttpMockConfig, + errors::EasyHttpMockError, + expect::{Then, When}, + server::ServerAdapter, +}; + +pub mod config; +pub mod errors; +pub mod expect; +pub mod server; + +mod tests; + +pub struct EasyHttpMock +where + S: ServerAdapter, +{ + config: EasyHttpMockConfig, + server: S, +} + +impl EasyHttpMock { + pub fn new(config: EasyHttpMockConfig) -> Result, EasyHttpMockError> { + let server = S::new( + config + .server_config + .clone(), + )?; + + Ok(EasyHttpMock { config, server }) + } + + pub fn url(&self, path: &str) -> String { + if let Some(base_url) = &self.config.base_url { + format!("{}{}", base_url, path) + } else { + format!( + "{}{}", + self.server + .base_url(), + path + ) + } + } + + pub fn base_url(&self) -> String { + self.server + .base_url() + } + + pub async fn mock(&mut self, mocker: F) -> Result<(), EasyHttpMockError> + where + F: Fn(When) -> Fut + Send + Sync + 'static, + Fut: Future> + Send + Sync + 'static, + { + self.server + .mocker(mocker); + + self.server + .start() + .await + } + + pub async fn assert(&mut self) -> Result<(), EasyHttpMockError> { + self.server + .stop() + .await + } +} + +/// Type alias for boxed handler closures. +/// +/// This represents an async function that takes a `Request` and returns +/// a `Response` or an error. Handlers are the core of request processing +/// in VeTiS virtual hosts. +/// +/// # Examples +/// +/// ```rust,ignore +/// use easyhttpmock::{errors::EasyHttpMockError, expect::{When, Then}, BoxedHandlerClosure}; +/// +/// let handler: BoxedHandlerClosure = Box::new(|when: When| { +/// Box::pin(async move { +/// // Process request... +/// Ok(Then::builder() +/// .status(http::StatusCode::OK) +/// .body(http_body_util::Full::new(bytes::Bytes::from("OK")))) +/// }) +/// }); +/// ``` +pub type BoxedHandlerClosure = Box< + dyn Fn(When) -> Pin> + Send + Sync>> + + Send + + Sync, +>; + +/// Creates a handler closure from a function. +/// +/// This utility function converts any compatible async function into a +/// `BoxedHandlerClosure` that can be used with virtual hosts. +/// +/// # Arguments +/// +/// * `f` - An async function that takes a `Then` and returns a `Result` +/// +/// # Examples +/// +/// ```rust,ignore +/// +/// ``` +pub fn mock_fn(f: F) -> BoxedHandlerClosure +where + F: Fn(When) -> Fut + Send + Sync + 'static, + Fut: Future> + Send + Sync + 'static, +{ + Box::new(move |req| Box::pin(f(req))) +} diff --git a/src/server/mod.rs b/easyhttpmock/src/server.rs similarity index 74% rename from src/server/mod.rs rename to easyhttpmock/src/server.rs index 236302d..078b010 100644 --- a/src/server/mod.rs +++ b/easyhttpmock/src/server.rs @@ -1,14 +1,10 @@ use std::future::Future; -use vetis::{ - errors::VetisError, - server::http::{Request, Response}, +use crate::{ + errors::EasyHttpMockError, + expect::{Then, When}, }; -use crate::errors::EasyHttpMockError; - -pub mod adapters; - /// Server adapter trait to allow different http server implementations pub trait ServerAdapter { type Config: Clone; @@ -49,20 +45,28 @@ pub trait ServerAdapter { /// fn config(&self) -> &Self::Config; - /// Start the server + /// Set the mocker to handle incoming requests /// /// # Arguments /// - /// * `handler` - The handler function to handle incoming requests + /// * `mocker` - The mocker to handle incoming requests /// /// # Returns /// /// * `Result<(), EasyHttpMockError>` - The result of the operation /// - fn start(&mut self, handler: H) -> impl Future> + fn mocker(&mut self, mocker: F) where - H: Fn(Request) -> Fut + Send + Sync + 'static, - Fut: Future> + Send + Sync + 'static; + F: Fn(When) -> Fut + Send + Sync + 'static, + Fut: Future> + Send + Sync + 'static; + + /// Start the server + /// + /// # Returns + /// + /// * `Result<(), EasyHttpMockError>` - The result of the operation + /// + fn start(&mut self) -> impl Future>; /// Stop the server /// diff --git a/easyhttpmock/src/tests/config.rs b/easyhttpmock/src/tests/config.rs new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/easyhttpmock/src/tests/config.rs @@ -0,0 +1 @@ + diff --git a/easyhttpmock/src/tests/mod.rs b/easyhttpmock/src/tests/mod.rs new file mode 100644 index 0000000..21be1b5 --- /dev/null +++ b/easyhttpmock/src/tests/mod.rs @@ -0,0 +1,2 @@ +mod config; +mod server; diff --git a/easyhttpmock/src/tests/server.rs b/easyhttpmock/src/tests/server.rs new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/easyhttpmock/src/tests/server.rs @@ -0,0 +1 @@ + diff --git a/src/lib.rs b/src/lib.rs deleted file mode 100644 index 0ca4bb0..0000000 --- a/src/lib.rs +++ /dev/null @@ -1,75 +0,0 @@ -use std::future::Future; - -use crate::{config::EasyHttpMockConfig, errors::EasyHttpMockError, server::ServerAdapter}; - -use http::StatusCode; -use vetis::{ - errors::VetisError, - server::http::{Request, Response}, -}; - -pub mod config; -pub mod errors; -pub mod server; - -mod tests; - -pub struct EasyHttpMock -where - S: ServerAdapter, -{ - config: EasyHttpMockConfig, - server: S, -} - -impl EasyHttpMock { - pub fn new(config: EasyHttpMockConfig) -> Result, EasyHttpMockError> { - let server = S::new( - config - .server_config - .clone(), - )?; - - Ok(EasyHttpMock { config, server }) - } - - pub fn url(&self, path: &str) -> String { - if let Some(base_url) = &self.config.base_url { - format!("{}{}", base_url, path) - } else { - format!( - "{}{}", - self.server - .base_url(), - path - ) - } - } - - pub fn base_url(&self) -> String { - self.server - .base_url() - } - - pub async fn start(&mut self, handler: H) -> Result<(), EasyHttpMockError> - where - H: Fn(Request) -> Fut + Send + Sync + 'static, - Fut: Future> + Send + Sync + 'static, - { - self.server - .start(handler) - .await - } - - pub async fn stop(&mut self) -> Result<(), EasyHttpMockError> { - self.server - .stop() - .await - } -} - -pub fn mock_response(status: StatusCode, body: &str) -> Response { - Response::builder() - .status(status) - .text(body) -} diff --git a/src/tests/config.rs b/src/tests/config.rs deleted file mode 100644 index 313cc6b..0000000 --- a/src/tests/config.rs +++ /dev/null @@ -1,352 +0,0 @@ -#[cfg(test)] -mod easy_http_mock_config_tests { - use crate::{ - config::EasyHttpMockConfig, - server::adapters::vetis_adapter::{VetisAdapter, VetisAdapterConfig}, - tests::default_protocol, - }; - - #[test] - fn test_easy_http_mock_config_default() { - let config = EasyHttpMockConfig::::default(); - - assert!(config - .base_url() - .is_some()); - assert_eq!( - config - .base_url() - .as_ref() - .unwrap(), - "http://localhost:80" - ); - assert_eq!( - config - .server_config() - .port(), - 80 - ); - assert_eq!( - config - .server_config() - .interface(), - "0.0.0.0" - ); - } - - #[test] - fn test_easy_http_mock_config_builder_default() { - let config = EasyHttpMockConfig::::builder().build(); - - assert!(config - .base_url() - .is_none()); - assert_eq!( - config - .server_config() - .port(), - 80 - ); - assert_eq!( - config - .server_config() - .interface(), - "0.0.0.0" - ); - } - - #[test] - fn test_easy_http_mock_config_builder_with_base_url() { - let base_url = "https://api.example.com".to_string(); - let config = EasyHttpMockConfig::::builder() - .base_url(Some(base_url.clone())) - .build(); - - assert_eq!(config.base_url(), &Some(base_url)); - assert_eq!( - config - .server_config() - .port(), - 80 - ); - assert_eq!( - config - .server_config() - .interface(), - "0.0.0.0" - ); - } - - #[test] - fn test_easy_http_mock_config_builder_with_none_base_url() { - let config = EasyHttpMockConfig::::builder() - .base_url(None) - .build(); - - assert!(config - .base_url() - .is_none()); - assert_eq!( - config - .server_config() - .port(), - 80 - ); - } - - #[test] - fn test_easy_http_mock_config_builder_with_server_config() { - let server_config = VetisAdapterConfig::builder() - .interface("127.0.0.1") - .protocol(default_protocol()) - .port(3000) - .build(); - - let config = EasyHttpMockConfig::::builder() - .server_config(server_config.clone()) - .build(); - - assert!(config - .base_url() - .is_none()); - assert_eq!( - config - .server_config() - .port(), - 3000 - ); - assert_eq!( - config - .server_config() - .interface(), - "127.0.0.1" - ); - } - - #[test] - fn test_easy_http_mock_config_builder_complete() { - let base_url = "https://test.mock".to_string(); - let server_config = VetisAdapterConfig::builder() - .interface("0.0.0.0") - .protocol(default_protocol()) - .port(8443) - .build(); - - let config = EasyHttpMockConfig::::builder() - .base_url(Some(base_url.clone())) - .server_config(server_config.clone()) - .build(); - - assert_eq!(config.base_url(), &Some(base_url)); - assert_eq!( - config - .server_config() - .port(), - 8443 - ); - assert_eq!( - config - .server_config() - .interface(), - "0.0.0.0" - ); - } - - #[test] - fn test_easy_http_mock_config_builder_chaining() { - let server_config = VetisAdapterConfig::builder() - .interface("192.168.1.100") - .protocol(default_protocol()) - .port(9090) - .build(); - - let config = EasyHttpMockConfig::::builder() - .base_url(Some("https://chained.mock".to_string())) - .server_config(server_config) - .build(); - - assert_eq!( - config - .base_url() - .as_ref() - .unwrap(), - "https://chained.mock" - ); - assert_eq!( - config - .server_config() - .port(), - 9090 - ); - assert_eq!( - config - .server_config() - .interface(), - "192.168.1.100" - ); - } - - #[test] - fn test_easy_http_mock_config_empty_base_url() { - let config = EasyHttpMockConfig::::builder() - .base_url(Some("".to_string())) - .build(); - - assert_eq!(config.base_url(), &Some("".to_string())); - } - - #[test] - fn test_easy_http_mock_config_long_base_url() { - let long_url = "https://very.long.domain.name.with.many.subdomains.for.testing.purposes.example.com:8443/api/v1".to_string(); - let config = EasyHttpMockConfig::::builder() - .base_url(Some(long_url.clone())) - .build(); - - assert_eq!(config.base_url(), &Some(long_url)); - } -} - -#[cfg(test)] -mod integration_tests { - use crate::{ - config::EasyHttpMockConfig, - server::adapters::vetis_adapter::{VetisAdapter, VetisAdapterConfig}, - tests::default_protocol, - }; - - #[test] - fn test_config_with_vetis_server_adapter_integration() { - let server_config = VetisAdapterConfig::builder() - .interface("0.0.0.0") - .protocol(default_protocol()) - .port(443) - .build(); - - let mock_config = EasyHttpMockConfig::::builder() - .base_url(Some("https://secure.mock".to_string())) - .server_config(server_config) - .build(); - - assert_eq!( - mock_config - .server_config() - .port(), - 443 - ); - } - - #[test] - fn test_multiple_config_instances() { - let config1 = EasyHttpMockConfig::::builder() - .base_url(Some("https://config1.mock".to_string())) - .server_config( - VetisAdapterConfig::builder() - .interface("0.0.0.0") - .protocol(default_protocol()) - .port(8080) - .build(), - ) - .build(); - - let config2 = EasyHttpMockConfig::::builder() - .base_url(Some("https://config2.mock".to_string())) - .server_config( - VetisAdapterConfig::builder() - .interface("0.0.0.0") - .protocol(default_protocol()) - .port(9090) - .build(), - ) - .build(); - - assert_ne!(config1.base_url(), config2.base_url()); - assert_ne!( - config1 - .server_config() - .port(), - config2 - .server_config() - .port() - ); - } - - #[test] - fn test_config_immutability() { - let config = EasyHttpMockConfig::::builder() - .base_url(Some("https://immutable.mock".to_string())) - .server_config( - VetisAdapterConfig::builder() - .protocol(default_protocol()) - .port(3000) - .build(), - ) - .build(); - - assert_eq!(config.base_url(), &Some("https://immutable.mock".to_string())); - assert_eq!( - config - .server_config() - .port(), - 3000 - ); - - let _new_config = EasyHttpMockConfig::::builder() - .base_url(Some("https://new.mock".to_string())) - .server_config( - VetisAdapterConfig::builder() - .protocol(default_protocol()) - .port(3000) - .build(), - ) - .build(); - - assert_eq!(config.base_url(), &Some("https://immutable.mock".to_string())); - assert_eq!( - config - .server_config() - .port(), - 3000 - ); - } - - #[test] - fn test_config_with_different_server_configs() { - let http_config = VetisAdapterConfig::builder() - .interface("0.0.0.0") - .protocol(default_protocol()) - .port(80) - .build(); - - let https_config = VetisAdapterConfig::builder() - .interface("0.0.0.0") - .protocol(default_protocol()) - .port(443) - .build(); - - let http_mock = EasyHttpMockConfig::::builder() - .base_url(Some("http://http.mock".to_string())) - .server_config(http_config) - .build(); - - let https_mock = EasyHttpMockConfig::::builder() - .base_url(Some("https://https.mock".to_string())) - .server_config(https_config) - .build(); - - assert_eq!(http_mock.base_url(), &Some("http://http.mock".to_string())); - assert_eq!( - http_mock - .server_config() - .port(), - 80 - ); - - assert_eq!(https_mock.base_url(), &Some("https://https.mock".to_string())); - assert_eq!( - https_mock - .server_config() - .port(), - 443 - ); - } -} diff --git a/src/tests/mod.rs b/src/tests/mod.rs deleted file mode 100644 index acedeae..0000000 --- a/src/tests/mod.rs +++ /dev/null @@ -1,19 +0,0 @@ -use vetis::config::server::Protocol; - -mod config; -mod server; - -pub(crate) const fn default_protocol() -> Protocol { - #[cfg(feature = "http1")] - { - Protocol::Http1 - } - #[cfg(feature = "http2")] - { - Protocol::Http2 - } - #[cfg(feature = "http3")] - { - Protocol::Http3 - } -} diff --git a/src/tests/server.rs b/src/tests/server.rs deleted file mode 100644 index b315f6b..0000000 --- a/src/tests/server.rs +++ /dev/null @@ -1,393 +0,0 @@ -#[cfg(test)] -mod easy_http_mock_server_tests { - use crate::{ - config::EasyHttpMockConfig, - server::adapters::vetis_adapter::{VetisAdapter, VetisAdapterConfig}, - tests::default_protocol, - EasyHttpMock, - }; - use http::StatusCode; - use std::time::Duration; - use vetis::server::http::{Request, Response}; - - #[tokio::test] - async fn test_easy_http_mock_default() { - let mock = EasyHttpMock::::default(); - - assert_eq!(mock.base_url(), "http://localhost:80"); - assert_eq!(mock.url("/test"), "http://localhost:80/test"); - assert_eq!(mock.url(""), "http://localhost:80"); - } - - #[tokio::test] - async fn test_easy_http_mock_with_custom_config() -> Result<(), Box> { - let config = EasyHttpMockConfig::::builder() - .base_url(Some("https://custom.mock".to_string())) - .server_config( - VetisAdapterConfig::builder() - .interface("127.0.0.1") - .protocol(default_protocol()) - .port(3000) - .build(), - ) - .build(); - - let mock = EasyHttpMock::new(config)?; - - assert_eq!(mock.base_url(), "http://localhost:3000"); - assert_eq!(mock.url("/api"), "https://custom.mock/api"); - assert_eq!(mock.url(""), "https://custom.mock"); - - Ok(()) - } - - #[tokio::test] - async fn test_server_lifecycle() -> Result<(), Box> { - let config = EasyHttpMockConfig::::builder() - .server_config( - VetisAdapterConfig::builder() - .interface("127.0.0.1") - .protocol(default_protocol()) - .port(4000) - .build(), - ) - .build(); - - let mut mock = EasyHttpMock::new(config)?; - - let handler = |_req: Request| async move { - let response: Response = Response::builder() - .status(StatusCode::OK) - .text("Hello, World!"); - Ok(response) - }; - - let result = mock - .start(handler) - .await; - if let Err(e) = &result { - println!("Server start error: {:?}", e); - } - assert!(result.is_ok()); - - tokio::time::sleep(Duration::from_millis(100)).await; - - let result = mock.stop().await; - assert!(result.is_ok()); - - Ok(()) - } - - #[tokio::test] - async fn test_url_generation() -> Result<(), Box> { - let mock = EasyHttpMock::::default(); - assert_eq!(mock.url("/api/users"), "http://localhost:80/api/users"); - assert_eq!(mock.url("/"), "http://localhost:80/"); - assert_eq!(mock.url(""), "http://localhost:80"); - assert_eq!(mock.url("test"), "http://localhost:80test"); - - let config = EasyHttpMockConfig::::builder() - .base_url(Some("https://api.example.com".to_string())) - .server_config( - VetisAdapterConfig::builder() - .interface("127.0.0.1") - .protocol(default_protocol()) - .port(8181) - .build(), - ) - .build(); - - let mock = EasyHttpMock::new(config)?; - assert_eq!(mock.url("/v1/users"), "https://api.example.com/v1/users"); - assert_eq!(mock.url("/"), "https://api.example.com/"); - assert_eq!(mock.url(""), "https://api.example.com"); - assert_eq!(mock.url("health"), "https://api.example.comhealth"); - - Ok(()) - } - - #[tokio::test] - async fn test_server_with_different_responses() -> Result<(), Box> { - let config = EasyHttpMockConfig::::builder() - .server_config( - VetisAdapterConfig::builder() - .interface("127.0.0.1") - .protocol(default_protocol()) - .port(9999) - .build(), - ) - .build(); - - let mut mock = EasyHttpMock::new(config)?; - - let handler = |req: Request| async move { - let path = req.uri().path(); - let (status, body) = match path { - "/health" => (StatusCode::OK, "OK"), - "/not-found" => (StatusCode::NOT_FOUND, "Not Found"), - _ => (StatusCode::OK, "Default Response"), - }; - - let response: Response = Response::builder() - .status(status) - .text(body); - Ok(response) - }; - - mock.start(handler) - .await - .unwrap(); - - tokio::time::sleep(Duration::from_millis(100)).await; - - assert!(mock - .base_url() - .contains("localhost:")); - assert!(!mock - .base_url() - .contains("localhost:80")); - - mock.stop().await?; - - Ok(()) - } - - #[tokio::test] - async fn test_server_with_json_response() -> Result<(), Box> { - let config = EasyHttpMockConfig::::builder() - .server_config( - VetisAdapterConfig::builder() - .interface("127.0.0.1") - .protocol(default_protocol()) - .port(7777) // Use random available port - .build(), - ) - .build(); - - let mut mock = EasyHttpMock::new(config)?; - - let handler = |_req: Request| async move { - let json_body = r#"{ - "id": 1, - "name": "Test User", - "email": "test@example.com", - "active": true - }"#; - - let response: Response = Response::builder() - .status(StatusCode::OK) - .header( - "Content-Type", - "application/json" - .parse() - .unwrap(), - ) - .text(json_body); - Ok(response) - }; - - mock.start(handler) - .await - .unwrap(); - - tokio::time::sleep(Duration::from_millis(100)).await; - tokio::time::sleep(Duration::from_millis(100)).await; - - assert!(mock - .base_url() - .contains("localhost:7777")); - assert!(!mock - .base_url() - .is_empty()); - - mock.stop() - .await - .unwrap(); - - Ok(()) - } -} - -#[cfg(test)] -mod integration_tests { - use crate::{ - config::EasyHttpMockConfig, - server::adapters::vetis_adapter::{VetisAdapter, VetisAdapterConfig}, - tests::default_protocol, - EasyHttpMock, - }; - use http::StatusCode; - use std::time::Duration; - use vetis::server::http::{Request, Response}; - - #[tokio::test] - async fn test_multiple_server_instances() -> Result<(), Box> { - let config1 = EasyHttpMockConfig::::builder() - .server_config( - VetisAdapterConfig::builder() - .interface("127.0.0.1") - .protocol(default_protocol()) - .port(8081) - .build(), - ) - .build(); - - let config2 = EasyHttpMockConfig::::builder() - .server_config( - VetisAdapterConfig::builder() - .interface("127.0.0.1") - .protocol(default_protocol()) - .port(8082) - .build(), - ) - .build(); - - let mut mock1 = EasyHttpMock::new(config1)?; - let mut mock2 = EasyHttpMock::new(config2)?; - - let handler1 = |_req: Request| async move { - let response: Response = Response::builder() - .status(StatusCode::OK) - .text("Server 1 response"); - Ok(response) - }; - - let handler2 = |_req: Request| async move { - let response: Response = Response::builder() - .status(StatusCode::OK) - .text("Server 2 response"); - Ok(response) - }; - - mock1 - .start(handler1) - .await - .unwrap(); - mock2 - .start(handler2) - .await - .unwrap(); - - tokio::time::sleep(Duration::from_millis(100)).await; - - let base_url1 = mock1.base_url(); - let base_url2 = mock2.base_url(); - - assert!(base_url1.contains("localhost")); - assert!(base_url2.contains("localhost")); - - mock1 - .stop() - .await - .unwrap(); - mock2 - .stop() - .await - .unwrap(); - - Ok(()) - } - - #[tokio::test] - async fn test_server_with_random_port() -> Result<(), Box> { - // Create a mock server with random port - let config = EasyHttpMockConfig::::builder() - .server_config( - VetisAdapterConfig::builder() - .interface("127.0.0.1") - .protocol(default_protocol()) - .port(8888) // Use random available port - .build(), - ) - .build(); - - let mut mock = EasyHttpMock::new(config)?; - - let handler = |_req: Request| async move { - let response: Response = Response::builder() - .status(StatusCode::OK) - .text("Random port test"); - Ok(response) - }; - - mock.start(handler) - .await - .unwrap(); - - tokio::time::sleep(Duration::from_millis(100)).await; - tokio::time::sleep(Duration::from_millis(100)).await; - - let base_url = mock.base_url(); - - assert!(base_url.contains("localhost:8888")); - assert!(!base_url.contains("localhost:80")); - - mock.stop() - .await - .unwrap(); - - Ok(()) - } - - #[tokio::test] - async fn test_server_restart() -> Result<(), Box> { - // Use a random available port to avoid permission issues - let config = EasyHttpMockConfig::::builder() - .server_config( - VetisAdapterConfig::builder() - .interface("127.0.0.1") - .protocol(default_protocol()) - .port(5555) // Use random available port - .build(), - ) - .build(); - - let mut mock = EasyHttpMock::new(config)?; - - let handler = |_req: Request| async move { - let response: Response = Response::builder() - .status(StatusCode::OK) - .text("Restart test"); - Ok(response) - }; - - mock.start(handler) - .await - .unwrap(); - tokio::time::sleep(Duration::from_millis(100)).await; - - // Stop the server - mock.stop() - .await - .unwrap(); - tokio::time::sleep(Duration::from_millis(50)).await; - - // Start the server again with a new handler - let handler2 = |_req: Request| async move { - let response: Response = Response::builder() - .status(StatusCode::OK) - .text("Restarted"); - Ok(response) - }; - - mock.start(handler2) - .await - .unwrap(); - tokio::time::sleep(Duration::from_millis(100)).await; - - // Verify server is running again - assert!(mock - .base_url() - .contains("localhost:5555")); - assert!(!mock - .base_url() - .is_empty()); - - // Stop the server - mock.stop() - .await - .unwrap(); - - Ok(()) - } -} From 8126cbae2534c61b2a2f0d8ad578c19e953d0184 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rog=C3=A9rio=20Ara=C3=BAjo?= Date: Mon, 13 Apr 2026 16:24:00 -0300 Subject: [PATCH 12/15] refactor: fix adapter to use new vetis api structure --- Cargo.lock | 30 +++++++------------ easyhttpmock-vetis-smol/Cargo.toml | 7 +++++ easyhttpmock-vetis-smol/src/lib.rs | 1 + easyhttpmock-vetis-smol/src/vetis_adapter.rs | 10 +++---- easyhttpmock-vetis-tokio/Cargo.toml | 7 +++++ easyhttpmock-vetis-tokio/src/lib.rs | 2 ++ easyhttpmock-vetis-tokio/src/vetis_adapter.rs | 10 +++---- 7 files changed, 35 insertions(+), 32 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 78cc3ba..8d08bca 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -180,7 +180,6 @@ dependencies = [ "futures-util", "native-tls", "thiserror 1.0.69", - "tokio", "url", ] @@ -1281,21 +1280,6 @@ version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fc0fef456e4baa96da950455cd02c081ca953b141298e41db3fc7e36b1da849c" -[[package]] -name = "hotpath" -version = "0.14.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7d9982fcb4356a5260502f0e646411ec1feb2962cc98c230777104a8d1c5ed3" -dependencies = [ - "hotpath-macros", -] - -[[package]] -name = "hotpath-macros" -version = "0.14.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4398eddb78466298f1ddcc739abbbd8a942e541d1972c7590bd83de364e626e0" - [[package]] name = "http" version = "1.4.0" @@ -1365,15 +1349,17 @@ dependencies = [ [[package]] name = "hyper-body-utils" -version = "0.1.6-beta.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4eff608807e6c410941de3e22c17044fecec132e20dc21f33247cc31509f14f" +version = "0.1.6-beta.7" dependencies = [ "bytes", "futures", - "hotpath", + "h3", + "h3-quinn", "http-body-util", "hyper", + "macro_rules_attribute", + "smol", + "smol-macros", "tokio", "tokio-util", ] @@ -3513,6 +3499,8 @@ dependencies = [ "futures-lite", "futures-rustls", "futures-util", + "h3", + "h3-quinn", "http", "http-body-util", "hyper", @@ -3555,6 +3543,8 @@ dependencies = [ "env_logger", "futures-rustls", "futures-util", + "h3", + "h3-quinn", "http", "http-body-util", "hyper", diff --git a/easyhttpmock-vetis-smol/Cargo.toml b/easyhttpmock-vetis-smol/Cargo.toml index 0c44896..5063bca 100644 --- a/easyhttpmock-vetis-smol/Cargo.toml +++ b/easyhttpmock-vetis-smol/Cargo.toml @@ -15,6 +15,13 @@ rust-version = "1.75.0" [package.metadata.docs.rs] all-features = true +[features] +http1 = ["vetis-smol/http1"] +http2 = ["vetis-smol/http2"] +http3 = ["vetis-smol/http3"] + +rust-tls = ["vetis-smol/rust-tls"] + [dependencies] easyhttpmock = { path = "../easyhttpmock" } http = "1.4.0" diff --git a/easyhttpmock-vetis-smol/src/lib.rs b/easyhttpmock-vetis-smol/src/lib.rs index cd7eeb3..3d8f88d 100644 --- a/easyhttpmock-vetis-smol/src/lib.rs +++ b/easyhttpmock-vetis-smol/src/lib.rs @@ -1,2 +1,3 @@ pub mod vetis_adapter; pub use easyhttpmock::*; +pub use vetis_smol::Protocol; diff --git a/easyhttpmock-vetis-smol/src/vetis_adapter.rs b/easyhttpmock-vetis-smol/src/vetis_adapter.rs index bd08375..27736eb 100644 --- a/easyhttpmock-vetis-smol/src/vetis_adapter.rs +++ b/easyhttpmock-vetis-smol/src/vetis_adapter.rs @@ -3,9 +3,7 @@ use std::{future::Future, sync::Arc}; use vetis_smol::{ errors::VetisError, http::Response, - listener::ListenerConfig, - server::virtual_host::{handler_fn, path::HandlerPath, VirtualHost}, - virtual_host::{SecurityConfig, VirtualHostConfig}, + virtual_host::{handler_fn, path::HandlerPath, VirtualHost}, Protocol, ServerConfig, Vetis, }; @@ -238,7 +236,7 @@ impl VetisAdapterConfig { impl From for ServerConfig { fn from(config: VetisAdapterConfig) -> Self { - let listener_config = ListenerConfig::builder() + let listener_config = vetis_smol::ListenerConfig::builder() .interface(&config.interface) .protocol(config.protocol) .port(config.port) @@ -395,7 +393,7 @@ impl ServerAdapter for VetisAdapter { let hostname = self.hostname(); - let host_config = VirtualHostConfig::builder() + let host_config = vetis_smol::VirtualHostConfig::builder() .hostname(&hostname) .root_directory(".") .port(self.config.port()); @@ -415,7 +413,7 @@ impl ServerAdapter for VetisAdapter { .as_ref(), ) { host_config.security( - SecurityConfig::builder() + vetis_smol::SecurityConfig::builder() .cert_from_bytes(cert.clone()) .key_from_bytes(key.clone()) .ca_cert_from_bytes(ca.clone()) diff --git a/easyhttpmock-vetis-tokio/Cargo.toml b/easyhttpmock-vetis-tokio/Cargo.toml index 111e578..8ce16b7 100644 --- a/easyhttpmock-vetis-tokio/Cargo.toml +++ b/easyhttpmock-vetis-tokio/Cargo.toml @@ -15,6 +15,13 @@ rust-version = "1.75.0" [package.metadata.docs.rs] all-features = true +[features] +http1 = ["vetis-tokio/http1"] +http2 = ["vetis-tokio/http2"] +http3 = ["vetis-tokio/http3"] + +rust-tls = ["vetis-tokio/rust-tls"] + [dependencies] easyhttpmock = { path = "../easyhttpmock" } http = "1.4.0" diff --git a/easyhttpmock-vetis-tokio/src/lib.rs b/easyhttpmock-vetis-tokio/src/lib.rs index 5308612..60f9dd0 100644 --- a/easyhttpmock-vetis-tokio/src/lib.rs +++ b/easyhttpmock-vetis-tokio/src/lib.rs @@ -1 +1,3 @@ pub mod vetis_adapter; +pub use easyhttpmock::*; +pub use vetis_tokio::Protocol; diff --git a/easyhttpmock-vetis-tokio/src/vetis_adapter.rs b/easyhttpmock-vetis-tokio/src/vetis_adapter.rs index d301aed..4eef359 100644 --- a/easyhttpmock-vetis-tokio/src/vetis_adapter.rs +++ b/easyhttpmock-vetis-tokio/src/vetis_adapter.rs @@ -3,9 +3,7 @@ use std::{future::Future, sync::Arc}; use vetis_tokio::{ errors::VetisError, http::Response, - listener::ListenerConfig, - server::virtual_host::{handler_fn, path::HandlerPath, VirtualHost}, - virtual_host::{SecurityConfig, VirtualHostConfig}, + virtual_host::{handler_fn, path::HandlerPath, VirtualHost}, Protocol, ServerConfig, Vetis, }; @@ -238,7 +236,7 @@ impl VetisAdapterConfig { impl From for ServerConfig { fn from(config: VetisAdapterConfig) -> Self { - let listener_config = ListenerConfig::builder() + let listener_config = vetis_tokio::ListenerConfig::builder() .interface(&config.interface) .protocol(config.protocol) .port(config.port) @@ -395,7 +393,7 @@ impl ServerAdapter for VetisAdapter { let hostname = self.hostname(); - let host_config = VirtualHostConfig::builder() + let host_config = vetis_tokio::VirtualHostConfig::builder() .hostname(&hostname) .root_directory(".") .port(self.config.port()); @@ -415,7 +413,7 @@ impl ServerAdapter for VetisAdapter { .as_ref(), ) { host_config.security( - SecurityConfig::builder() + vetis_tokio::SecurityConfig::builder() .cert_from_bytes(cert.clone()) .key_from_bytes(key.clone()) .ca_cert_from_bytes(ca.clone()) From ffe28795eea34764b3a312cf122afb78b72cc8fe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rog=C3=A9rio=20Ara=C3=BAjo?= Date: Sun, 19 Apr 2026 21:43:13 -0300 Subject: [PATCH 13/15] style: code format updates --- .samoyed/pre-commit | 6 +- Cargo.lock | 618 ++---------------- certs/README.md | 92 +++ certs/ca.crt | 29 + certs/ca.der | Bin 0 -> 1285 bytes certs/ca.key | 52 ++ certs/client.cnf | 20 + certs/client.crt | 32 + certs/client.der | Bin 0 -> 1408 bytes certs/client.key | 52 ++ certs/client.key.der | Bin 0 -> 2374 bytes certs/client.p12 | Bin 0 -> 4408 bytes certs/ip6-server.der | Bin 0 -> 1320 bytes certs/ip6-server.key.der | Bin 0 -> 2375 bytes certs/server.cnf | 16 + certs/server.crt | 30 + certs/server.der | Bin 0 -> 1300 bytes certs/server.key | 52 ++ certs/server.key.der | Bin 0 -> 2375 bytes easyhttpmock-vetis-smol/Cargo.toml | 12 +- easyhttpmock-vetis-smol/src/lib.rs | 2 + easyhttpmock-vetis-smol/src/tests/mod.rs | 63 ++ easyhttpmock-vetis-smol/src/vetis_adapter.rs | 81 ++- easyhttpmock-vetis-tokio/Cargo.toml | 12 +- easyhttpmock-vetis-tokio/src/lib.rs | 2 + easyhttpmock-vetis-tokio/src/tests/mod.rs | 60 ++ easyhttpmock-vetis-tokio/src/vetis_adapter.rs | 81 ++- easyhttpmock/Cargo.toml | 1 + easyhttpmock/src/config.rs | 49 ++ easyhttpmock/src/errors.rs | 30 +- easyhttpmock/src/expect.rs | 199 ------ easyhttpmock/src/lib.rs | 114 ++-- easyhttpmock/src/mock.rs | 369 +++++++++++ easyhttpmock/src/server.rs | 10 +- easyhttpmock/src/tests/config.rs | 30 + easyhttpmock/src/tests/mock.rs | 34 + easyhttpmock/src/tests/mod.rs | 1 + easyhttpmock/src/tests/server.rs | 80 +++ 38 files changed, 1287 insertions(+), 942 deletions(-) create mode 100644 certs/README.md create mode 100644 certs/ca.crt create mode 100644 certs/ca.der create mode 100644 certs/ca.key create mode 100644 certs/client.cnf create mode 100644 certs/client.crt create mode 100644 certs/client.der create mode 100644 certs/client.key create mode 100644 certs/client.key.der create mode 100644 certs/client.p12 create mode 100644 certs/ip6-server.der create mode 100644 certs/ip6-server.key.der create mode 100644 certs/server.cnf create mode 100644 certs/server.crt create mode 100644 certs/server.der create mode 100644 certs/server.key create mode 100644 certs/server.key.der create mode 100644 easyhttpmock-vetis-smol/src/tests/mod.rs create mode 100644 easyhttpmock-vetis-tokio/src/tests/mod.rs delete mode 100644 easyhttpmock/src/expect.rs create mode 100644 easyhttpmock/src/mock.rs create mode 100644 easyhttpmock/src/tests/mock.rs diff --git a/.samoyed/pre-commit b/.samoyed/pre-commit index add6453..5d88598 100644 --- a/.samoyed/pre-commit +++ b/.samoyed/pre-commit @@ -4,4 +4,8 @@ # exit 0 cargo fmt --check -# cargo test \ No newline at end of file +cd easyhttpmock + +cargo test + +cd .. \ No newline at end of file diff --git a/Cargo.lock b/Cargo.lock index 8d08bca..8e83255 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -67,18 +67,6 @@ version = "1.0.102" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f202df86484c868dbad7eaa557ef785d5c66295e41b460ef922eca0723b842c" -[[package]] -name = "argon2" -version = "0.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c3610892ee6e0cbce8ae2700349fcf8f98adb0dbfbee85aec3c9179d29cc072" -dependencies = [ - "base64ct", - "blake2", - "cpufeatures 0.2.17", - "password-hash", -] - [[package]] name = "async-channel" version = "1.9.0" @@ -335,66 +323,12 @@ version = "0.22.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" -[[package]] -name = "base64ct" -version = "1.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" - -[[package]] -name = "bcrypt" -version = "0.19.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "523ab528ce3a7ada6597f8ccf5bd8d85ebe26d5edf311cad4d1d3cfb2d357ac6" -dependencies = [ - "base64", - "blowfish", - "getrandom 0.4.2", - "subtle", -] - -[[package]] -name = "bindgen" -version = "0.72.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "993776b509cfb49c750f11b8f07a46fa23e0a1386ffc01fb1e7d343efc387895" -dependencies = [ - "bitflags", - "cexpr", - "clang-sys", - "itertools", - "proc-macro2", - "quote", - "regex", - "rustc-hash", - "shlex", - "syn 2.0.117", -] - [[package]] name = "bitflags" version = "2.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "843867be96c8daad0d758b57df9392b6d8d271134fce549de6ce169ff98a92af" -[[package]] -name = "blake2" -version = "0.10.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46502ad458c9a52b69d4d4d32775c788b7a1b85e8bc9d482d92250fc0e3f8efe" -dependencies = [ - "digest", -] - -[[package]] -name = "block-buffer" -version = "0.10.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" -dependencies = [ - "generic-array", -] - [[package]] name = "blocking" version = "1.6.2" @@ -408,28 +342,12 @@ dependencies = [ "piper", ] -[[package]] -name = "blowfish" -version = "0.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e412e2cd0f2b2d93e02543ceae7917b3c70331573df19ee046bcbc35e45e87d7" -dependencies = [ - "byteorder", - "cipher", -] - [[package]] name = "bumpalo" version = "3.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5d20789868f4b01b2f2caec9f5c4e0213b41e3e5702a50157d699ae31ced2fcb" -[[package]] -name = "byteorder" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" - [[package]] name = "bytes" version = "1.11.1" @@ -448,15 +366,6 @@ dependencies = [ "shlex", ] -[[package]] -name = "cexpr" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766" -dependencies = [ - "nom", -] - [[package]] name = "cfg-if" version = "1.0.4" @@ -476,31 +385,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6f8d983286843e49675a4b7a2d174efe136dc93a18d69130dd18198a6c167601" dependencies = [ "cfg-if", - "cpufeatures 0.3.0", + "cpufeatures", "rand_core 0.10.0", ] -[[package]] -name = "cipher" -version = "0.4.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad" -dependencies = [ - "crypto-common", - "inout", -] - -[[package]] -name = "clang-sys" -version = "1.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b023947811758c97c59bf9d1c188fd619ad4718dcaa767947df1cadb14f39f4" -dependencies = [ - "glob", - "libc", - "libloading", -] - [[package]] name = "clap" version = "4.5.61" @@ -605,15 +493,6 @@ version = "0.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" -[[package]] -name = "cpufeatures" -version = "0.2.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280" -dependencies = [ - "libc", -] - [[package]] name = "cpufeatures" version = "0.3.0" @@ -647,28 +526,6 @@ version = "0.8.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" -[[package]] -name = "crossfire" -version = "3.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0042e53977a94d5d10de04ce7eb6016aa212c08e83ea202f7a9f102ff104303" -dependencies = [ - "crossbeam-utils", - "futures-core", - "parking_lot", - "smallvec", -] - -[[package]] -name = "crypto-common" -version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78c8292055d1c1df0cce5d180393dc8cce0abec0a7102adb6c7b1eef6016d60a" -dependencies = [ - "generic-array", - "typenum", -] - [[package]] name = "data-encoding" version = "2.10.0" @@ -706,49 +563,6 @@ dependencies = [ "urlencoding", ] -[[package]] -name = "deboa-smol" -version = "0.1.0-beta.1" -dependencies = [ - "async-native-tls", - "async-std-resolver", - "async-trait", - "base64", - "bytes", - "cfg-if", - "cookie", - "deboa", - "futures", - "futures-rustls", - "http", - "http-body", - "http-body-util", - "hyper", - "hyper-body-utils", - "hyper-util", - "indexmap", - "log", - "macro_rules_attribute", - "minimime", - "mockall", - "quinn", - "rand 0.9.2", - "regex", - "rustls", - "rustls-native-certs", - "rustls-pki-types", - "serde", - "smol", - "smol-hyper", - "smol-macros", - "thiserror 2.0.18", - "time 0.2.27", - "trust-dns-resolver", - "url", - "urlencoding", - "webpki-roots", -] - [[package]] name = "deboa-tokio" version = "0.1.0-beta.1" @@ -799,17 +613,6 @@ dependencies = [ "powerfmt", ] -[[package]] -name = "digest" -version = "0.10.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" -dependencies = [ - "block-buffer", - "crypto-common", - "subtle", -] - [[package]] name = "discard" version = "1.0.4" @@ -844,6 +647,7 @@ name = "easyhttpmock" version = "0.1.3-beta.7" dependencies = [ "bytes", + "googletest", "http", "http-body-util", "hyper", @@ -857,8 +661,12 @@ name = "easyhttpmock-vetis-smol" version = "0.1.0-beta.1" dependencies = [ "easyhttpmock", + "googletest", "http", + "macro_rules_attribute", "rand 0.9.2", + "smol", + "smol-macros", "vetis-smol", ] @@ -866,18 +674,16 @@ dependencies = [ name = "easyhttpmock-vetis-tokio" version = "0.1.0-beta.1" dependencies = [ + "deboa", + "deboa-tokio", "easyhttpmock", + "googletest", "http", "rand 0.9.2", + "tokio", "vetis-tokio", ] -[[package]] -name = "either" -version = "1.15.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" - [[package]] name = "endian-type" version = "0.2.0" @@ -1137,16 +943,6 @@ dependencies = [ "slab", ] -[[package]] -name = "generic-array" -version = "0.14.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" -dependencies = [ - "typenum", - "version_check", -] - [[package]] name = "getrandom" version = "0.2.17" @@ -1188,12 +984,6 @@ dependencies = [ "wasip3", ] -[[package]] -name = "glob" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0cc23270f6e1808e30a928bdc84dea0b9b4136a8bc82338574f23baf47bbd280" - [[package]] name = "gloo-timers" version = "0.3.0" @@ -1206,6 +996,29 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "googletest" +version = "0.14.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06597b7d02ee58b9a37f522785ac15b9e18c6b178747c4439a6c03fbb35ea753" +dependencies = [ + "googletest_macro", + "num-traits", + "regex", + "rustversion", +] + +[[package]] +name = "googletest_macro" +version = "0.14.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c31d9f07c9c19b855faebf71637be3b43f8e13a518aece5d61a3beee7710b4ef" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + [[package]] name = "h2" version = "0.4.13" @@ -1551,24 +1364,6 @@ dependencies = [ "serde_core", ] -[[package]] -name = "indoc" -version = "2.0.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79cf5c93f93228cf8efb3ba362535fb11199ac548a09ce117c9b1adc3030d706" -dependencies = [ - "rustversion", -] - -[[package]] -name = "inout" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "879f10e63c20629ecabbb64a8010319738c66a5cd0c29b02d63d272b03751d01" -dependencies = [ - "generic-array", -] - [[package]] name = "ipnet" version = "2.12.0" @@ -1581,15 +1376,6 @@ version = "1.70.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a6cb138bb79a146c1bd460005623e142ef0181e3d0219cb493e02f7d08a35695" -[[package]] -name = "itertools" -version = "0.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186" -dependencies = [ - "either", -] - [[package]] name = "itoa" version = "1.0.18" @@ -1651,12 +1437,6 @@ dependencies = [ "log", ] -[[package]] -name = "lazy_static" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" - [[package]] name = "leb128fmt" version = "0.1.0" @@ -1669,16 +1449,6 @@ version = "0.2.184" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "48f5d2a454e16a5ea0f4ced81bd44e4cfc7bd3a507b61887c99fd3538b28e4af" -[[package]] -name = "libloading" -version = "0.8.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7c4b02199fee7c5d21a5ae7d8cfa79a6ef5bb2fc834d6e9058e89c825efdc55" -dependencies = [ - "cfg-if", - "windows-link", -] - [[package]] name = "libmimalloc-sys" version = "0.1.44" @@ -1756,44 +1526,12 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "670fdfda89751bc4a84ac13eaa63e205cf0fd22b4c9a5fbfa085b63c1f1d3a30" -[[package]] -name = "magnus" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b36a5b126bbe97eb0d02d07acfeb327036c6319fd816139a49824a83b7f9012" -dependencies = [ - "magnus-macros", - "rb-sys", - "rb-sys-env", - "seq-macro", -] - -[[package]] -name = "magnus-macros" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "47607461fd8e1513cb4f2076c197d8092d921a1ea75bd08af97398f593751892" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.117", -] - [[package]] name = "memchr" version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79" -[[package]] -name = "memoffset" -version = "0.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "488016bfae457b036d996092f6cb448677611ce4449e970ceaf42695203f218a" -dependencies = [ - "autocfg", -] - [[package]] name = "mimalloc" version = "0.1.48" @@ -1803,18 +1541,6 @@ dependencies = [ "libmimalloc-sys", ] -[[package]] -name = "mime" -version = "0.3.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" - -[[package]] -name = "minimal-lexical" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" - [[package]] name = "minimime" version = "1.0.0" @@ -1904,89 +1630,12 @@ dependencies = [ "smallvec", ] -[[package]] -name = "nom" -version = "7.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" -dependencies = [ - "memchr", - "minimal-lexical", -] - -[[package]] -name = "num" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8536030f9fea7127f841b45bb6243b27255787fb4eb83958aa1ef9d2fdc0c36" -dependencies = [ - "num-bigint", - "num-complex", - "num-integer", - "num-iter", - "num-rational", - "num-traits", -] - -[[package]] -name = "num-bigint" -version = "0.2.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "090c7f9998ee0ff65aa5b723e4009f7b217707f1fb5ea551329cc4d6231fb304" -dependencies = [ - "autocfg", - "num-integer", - "num-traits", -] - -[[package]] -name = "num-complex" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6b19411a9719e753aff12e5187b74d60d3dc449ec3f4dc21e3989c3f554bc95" -dependencies = [ - "autocfg", - "num-traits", -] - [[package]] name = "num-conv" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" -[[package]] -name = "num-integer" -version = "0.1.46" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" -dependencies = [ - "num-traits", -] - -[[package]] -name = "num-iter" -version = "0.1.45" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1429034a0490724d0075ebb2bc9e875d6503c3cf69e235a8941aa757d83ef5bf" -dependencies = [ - "autocfg", - "num-integer", - "num-traits", -] - -[[package]] -name = "num-rational" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c000134b5dbf44adc5cb772486d335293351644b801551abe8f75c84cfa4aef" -dependencies = [ - "autocfg", - "num-bigint", - "num-integer", - "num-traits", -] - [[package]] name = "num-traits" version = "0.2.19" @@ -2087,28 +1736,6 @@ dependencies = [ "windows-link", ] -[[package]] -name = "parse_duration" -version = "2.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7037e5e93e0172a5a96874380bf73bc6ecef022e26fa25f2be26864d6b3ba95d" -dependencies = [ - "lazy_static", - "num", - "regex", -] - -[[package]] -name = "password-hash" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "346f04948ba92c43e8469c1ee6736c7563d71012b17d40745260fe106aac2166" -dependencies = [ - "base64ct", - "rand_core 0.6.4", - "subtle", -] - [[package]] name = "paste" version = "1.0.15" @@ -2257,73 +1884,13 @@ dependencies = [ "unicode-ident", ] -[[package]] -name = "pyo3" -version = "0.27.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab53c047fcd1a1d2a8820fe84f05d6be69e9526be40cb03b73f86b6b03e6d87d" -dependencies = [ - "indoc", - "libc", - "memoffset", - "once_cell", - "portable-atomic", - "pyo3-build-config", - "pyo3-ffi", - "pyo3-macros", - "unindent", -] - -[[package]] -name = "pyo3-build-config" -version = "0.27.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b455933107de8642b4487ed26d912c2d899dec6114884214a0b3bb3be9261ea6" -dependencies = [ - "target-lexicon", -] - -[[package]] -name = "pyo3-ffi" -version = "0.27.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c85c9cbfaddf651b1221594209aed57e9e5cff63c4d11d1feead529b872a089" -dependencies = [ - "libc", - "pyo3-build-config", -] - -[[package]] -name = "pyo3-macros" -version = "0.27.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a5b10c9bf9888125d917fb4d2ca2d25c8df94c7ab5a52e13313a07e050a3b02" -dependencies = [ - "proc-macro2", - "pyo3-macros-backend", - "quote", - "syn 2.0.117", -] - -[[package]] -name = "pyo3-macros-backend" -version = "0.27.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03b51720d314836e53327f5871d4c0cfb4fb37cc2c4a11cc71907a86342c40f9" -dependencies = [ - "heck", - "proc-macro2", - "pyo3-build-config", - "quote", - "syn 2.0.117", -] - [[package]] name = "quinn" version = "0.11.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b9e20a958963c291dc322d98411f541009df2ced7b5a4f2bd52337638cfccf20" dependencies = [ + "async-io", "bytes", "cfg_aliases", "futures-io", @@ -2332,6 +1899,7 @@ dependencies = [ "quinn-udp", "rustc-hash", "rustls", + "smol", "socket2 0.6.3", "thiserror 2.0.18", "tokio", @@ -2482,36 +2050,6 @@ version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0c8d0fd677905edcbeedbf2edb6494d676f0e98d54d5cf9bda0b061cb8fb8aba" -[[package]] -name = "rb-sys" -version = "0.9.126" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "284799e73e899fe946fd77c7211b83bff61a1356e039ade7a2516a779e3212d0" -dependencies = [ - "rb-sys-build", -] - -[[package]] -name = "rb-sys-build" -version = "0.9.126" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "855fc1ad8943d12c89ef12f9147f1cc531f5bf19fb744112fdd317bb6ee7b5c5" -dependencies = [ - "bindgen", - "lazy_static", - "proc-macro2", - "quote", - "regex", - "shell-words", - "syn 2.0.117", -] - -[[package]] -name = "rb-sys-env" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cca7ad6a7e21e72151d56fe2495a259b5670e204c3adac41ee7ef676ea08117a" - [[package]] name = "redox_syscall" version = "0.5.18" @@ -2724,12 +2262,6 @@ version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" -[[package]] -name = "seq-macro" -version = "0.3.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bc711410fbe7399f390ca1c3b60ad0f53f80e95c5eb935e52268a0e2cd49acc" - [[package]] name = "serde" version = "1.0.228" @@ -2801,12 +2333,6 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bbfa15b3dddfee50a0fff136974b3e1bde555604ba463834a7eb7deb6417705d" -[[package]] -name = "shell-words" -version = "1.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc6fe69c597f9c37bfeeeeeb33da3530379845f10be461a66d16d03eca2ded77" - [[package]] name = "shlex" version = "1.3.0" @@ -3015,12 +2541,6 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7b2093cf4c8eb1e67749a6762251bc9cd836b6fc171623bd0a9d324d37af2417" -[[package]] -name = "target-lexicon" -version = "0.13.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "adb6935a6f5c20170eeceb1a3835a49e12e19d792f6dd344ccc76a985ca5a6ca" - [[package]] name = "tempfile" version = "3.27.0" @@ -3311,12 +2831,6 @@ version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" -[[package]] -name = "typenum" -version = "1.19.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "562d481066bde0658276a35467c4af00bdc6ee726305698a55b86e61d7ad82bb" - [[package]] name = "unicode-bidi" version = "0.3.18" @@ -3344,12 +2858,6 @@ version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" -[[package]] -name = "unindent" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7264e107f553ccae879d21fbea1d6724ac785e8c3bfc762137959b5802826ef3" - [[package]] name = "unsafe-libyaml" version = "0.2.11" @@ -3431,10 +2939,7 @@ checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" name = "vetis" version = "0.1.4-beta.5" dependencies = [ - "argon2", "async-lock", - "base64", - "bcrypt", "bytes", "cfg-if", "clap", @@ -3445,13 +2950,8 @@ dependencies = [ "hyper-body-utils", "log", "mimalloc", - "mime", - "minimime", - "moka", - "parse_duration", "radix_trie", "rand 0.9.2", - "regex", "serde", "serde_yaml_ng", "socket2 0.6.3", @@ -3460,30 +2960,6 @@ dependencies = [ "url", ] -[[package]] -name = "vetis-fcgi" -version = "0.1.0" -dependencies = [ - "http", - "hyper-body-utils", - "log", - "tokio", - "vetis", -] - -[[package]] -name = "vetis-rack" -version = "0.1.0" -dependencies = [ - "http", - "hyper-body-utils", - "log", - "magnus", - "mimalloc", - "tokio", - "vetis", -] - [[package]] name = "vetis-smol" version = "0.1.0-beta.1" @@ -3494,7 +2970,6 @@ dependencies = [ "cfg-if", "clap", "deboa", - "deboa-smol", "env_logger", "futures-lite", "futures-rustls", @@ -3525,9 +3000,6 @@ dependencies = [ "time 0.3.41", "url", "vetis", - "vetis-fcgi", - "vetis-rack", - "vetis-wsgi", ] [[package]] @@ -3570,22 +3042,6 @@ dependencies = [ "tokio-util", "url", "vetis", - "vetis-fcgi", - "vetis-rack", - "vetis-wsgi", -] - -[[package]] -name = "vetis-wsgi" -version = "0.1.0" -dependencies = [ - "crossfire", - "http", - "hyper-body-utils", - "log", - "pyo3", - "tokio", - "vetis", ] [[package]] @@ -3722,9 +3178,9 @@ dependencies = [ [[package]] name = "webpki-roots" -version = "1.0.6" +version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22cfaf3c063993ff62e73cb4311efde4db1efb31ab78a3e5c457939ad5cc0bed" +checksum = "52f5ee44c96cf55f1b349600768e3ece3a8f26010c05265ab73f945bb1a2eb9d" dependencies = [ "rustls-pki-types", ] diff --git a/certs/README.md b/certs/README.md new file mode 100644 index 0000000..c9c3b43 --- /dev/null +++ b/certs/README.md @@ -0,0 +1,92 @@ +# Generating self-signed certificates + +## CA Certificate + +```bash +openssl req -x509 -noenc -subj '/CN=My CA' -newkey rsa:4096 -keyout ca.key -out ca.crt -days 3650 +``` + +### Export as DER: + +```bash +openssl x509 -in ca.crt -out ca.der -outform DER +``` + +## Server + +### Private Key + +```bash +openssl genrsa -out server.key 4096 +``` + +### Certificate Request + +```bash +openssl req -new -key server.key -out server.csr -subj '/CN=localhost' +``` + +### Export as DER: + +```bash +openssl x509 -inform pem -in server.key -outform der -out server.der.key +``` + +### Create server.cnf + +```bash +# server.cnf +[ req ] +prompt = no +distinguished_name = req_distinguished_name +req_extensions = req_ext + +[ req_distinguished_name ] +CN = localhost + +[ req_ext ] +subjectAltName = @alt_names + +[ alt_names ] +DNS.1 = localhost +IP.1 = 127.0.0.1 +# Add more DNS names or IPs as needed, e.g., DNS.2 = myapp.internal +``` + +### Sign the Certificate Request + +```bash +openssl x509 -req -in server.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out server.crt -days 3650 -extfile server.cnf -extensions req_ext +``` + +### Export as DER: + +```bash +openssl x509 -in server.crt -outform der -out server.der +``` + +## Client + +### Private Key and certificate request + +```bash +openssl req -new -newkey rsa:4096 -nodes -keyout client.key -out client.csr -config client.cnf -sha256 +``` + +### Sign the Certificate Request + +```bash +openssl x509 -req -in client.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out client.crt -days 3650 -sha256 -extfile client.cnf +``` + +### Export as PKCS#8 DER + +```bash +openssl pkcs8 -topk8 -inform PEM -outform DER -in client.key -out client.der.key -nocrypt +``` + +### Export as PKCS#12 (client.key and client.crt are PEM encoded) + +```bash +openssl pkcs12 -export -out client.p12 -inkey client.key -in client.crt -name "Client Certificate" +``` diff --git a/certs/ca.crt b/certs/ca.crt new file mode 100644 index 0000000..0d855a2 --- /dev/null +++ b/certs/ca.crt @@ -0,0 +1,29 @@ +-----BEGIN CERTIFICATE----- +MIIFATCCAumgAwIBAgIUGP1tov72wLh6qoyNxUKGX2VPeZEwDQYJKoZIhvcNAQEL +BQAwEDEOMAwGA1UEAwwFTXkgQ0EwHhcNMjYwMTE0MDAxNDMyWhcNMzYwMTEyMDAx +NDMyWjAQMQ4wDAYDVQQDDAVNeSBDQTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCC +AgoCggIBAOQALuFzLrzssBoyvILUX9IYzIGIPbDza5pY5XQ9OyuOQonuDALz+0Zp +ta72zB13RG5CNmol6Nfkjh/wAY4leJuM9lgreLs7j31Il+rt4MwHcfHDfW+Wti88 +a18BjBKHAq1b3Dt+PHXj5do/BAOX/3xv6U4uZ7JHpvMdkuGbYXbZkQvyLmDp+vF6 +ZP0n/kM2owRtJWYwDaNi2qHn+TDRteA1Q3m5bzcbF6iJtvRsXXEKqDU1Ei6mlDtp +eKK7OvAKktcwNM3f78DIyVRFfeZLRbiqnRM+C9qH/YNx4/DLX3iUEQL1oYPKD/Kg +MumNXaizRImCUX2JYKzWUMSS1g0j1RknMLJMW+i49bWKVG8hm6k13DOvGuHRjzRs +MxNL+B5QKNd2bS20GHCsAWV8+EMwEFPKORX4RGn4bMML34MpMC683d3EFXdI9UP5 +6p+0uvw/LvSiXHmqfwqhPelgpkKz+0IVF+31TE+n37OimO+dq4boNRP4BXjo+AQs +Pcy/dmLlfJ9ghAXSpJGzXHAT9JeQzWlOZDMOFXKIygs9HHrARxJjaz1kjlGdXJ32 +h6Fwn+FkCKEeEaYu7FPVc+u/EZfaedgnPcg/06YlWbRgdxYeT7bEizF31+FW7D02 +Cc0yMvfUzzWdtli3mAWHq4vQwx0h2tdSfafhSUtGcvU5F0zuPLhvAgMBAAGjUzBR +MB0GA1UdDgQWBBSgG1KEEwWG42vTne9aa2N+N7w2TTAfBgNVHSMEGDAWgBSgG1KE +EwWG42vTne9aa2N+N7w2TTAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUA +A4ICAQBrZT+nVQwVKHa0XU8f9bikHtNWA1qHglwssqu85gW6qIvQBCuCZ6553g6b +bD8Dazv4Bjs73f/FV+GutL7AStpwtpz2MJE1JqkKZ3uiLCEo7XqHNBNfMyLGVxWH +GBgVhsxo9aH3gl69odgHVyYe+fFKPuyd1flhzwkT3c/Pq4l+j/fYie7AwXMFUlJY +Bl/FNaqPtjrKwkhGCqLDNmraM97q2i7Wy0sw1TWgtbIhtT0vWeSjGS+LFbl2pgzr +bIkLjD5j3SQBEh2JEmXli5jJw5EG3WBS3ogCBVTacSiIihnNyl1f9X6TiR4N8R9Q +Cp9Wg45niLlgzIi0K8kQO0FDYnl+iWRf8HtxPO+vD/uqfVpTi2aY6juWLjJm06MF +sIEsmuiO/oCO0baynKp/iIko317xHu1OZ8r6kX8pOY8uSHD473Tgd3rJe9kBPfBS +Fh8zy3dyrfxnC59DPxIexgLG3SPeRfseZUNUrBlu4o6OIApqByBBD0FJKNWKERt1 ++dtGbPBL3HC76Gdvo2jU3xu65Fp7hQCvcMi9YUX5j+2tV6mQLZyvodjJjwRtcoT1 +jZxspFtfWf6cgK+tLjl4QFHzr4w/uqyViMOLyUvaBimoyz+NMlJWbmMxfq7BVegu +8ioBqZTRQo12GQRNZ+ZGJP1aF4e9MsY97e33L7OqeL/xarK8YA== +-----END CERTIFICATE----- diff --git a/certs/ca.der b/certs/ca.der new file mode 100644 index 0000000000000000000000000000000000000000..25fc9962834e5734990d4b78489da89689ed1fb6 GIT binary patch literal 1285 zcmXqLVr4XFVtToNnTe5!Nkrmr?xKI+4(zB})zf>_sVzR$zjC4hFB_*;n@8JsUPeZ4 zRt5tBLp}o@Hs(+kW*%1GN(E;}137VCBQpa-LlXl7Lla}8C~;n65Z4IG#iFB$NeS6l zMpg#qCMJFcpi8)znwS_Fo-pV=EY{oeW`mT`o~A4Dmn6oNV++XrXZ3qKyN z&7ZbS-zGbru}7$#X>If!>pGj#$4_tBvoKHpUz7jRPcMCw`?AlnlOE1aEW0_8`;%V6 z%U>U>QvRy{b2eMdlB=3#z`Ho<*23pM4K8kdVCr1CGv8cVd`0KBFFCP=Tq{gXh4hw9 zvCgbmwA<XLZ`U2G<_gG+B%f=pi*HlO1E zw7}?PZ|sWAE}cz*wVerTt_2*Kbd6W}s-(KXCZFgRJHBr13dvWTz0&lK@p`F;7yC_e zjD@{_$OULzFU!^4B2lo0F}3E0vw=YHDNE5GE}1`a4s+jc)-=%DbNB8M(Q=Qk&Ocwx z-?HnEz228aF_o+8xfa^KOjzc$`L~m(_}i~O{>$%gUNqzV+|_L_Ooe~2R=oJZqGNkz ze_7Jgn)wMWte2Kd+#FLN{AK!tvzdM=#(bhh9jCZ$WvULi3ngdUrt}5QjhXwcePO}; zhbbHjkq@;*qU*kH8T2s z<-Fy9OIm&2H&+M8l@Hm%^tCft6E!OQ zOTMeZC?wk{l=`%L#>vAI+3qF;-Rodt4Y^gQ(a|M&_Ec>A*Sg7_a=ahq1GwggHTR`= z>`XY*u|@l&fVHD@Qe|CdO8kfFLYw#N`G2pfjSB8goAJtenx0YG<;AQU8g*v9==;~u zcX8XMIjibBIyLUceUy9amwxKk#ClE3em#$ZAMZ;ZlvkaszR76&AxKQ#_;h*E+CS;s z^PTO5Qj7Ttx>d zJ-G_yv4}-U$T>5XXPph}h{;;B&-Oh1`FY>xeV*?hpD)NnTnCvj-x3%A1ps;X)uT=9 zY@z=F=Dq72t~p6^X0QgtASE&ypS)OOyp= zM3E#~f)Z;Pay8UDIF={}VnrDWElG*BqDRpq=pn)1w=lGLq+diNBf>8nWC90&ycddq zz?gtEWG|Nlm;e+~n-nkc&K3uB*6>g8t=ohQb*26w&sQW|-8bZ;EaAtAi)M*>ifIjF z$-Gy81cVR#9>FJQ4?UpF%S{GKx1j@q`s?Sq5cgY;H>d`*tCzmr2rDF<$LTMh`8%B5 zg!f>%V_RxYln7PGB$nptNly3zcYrWq6(hvnSn^Eo&o>cPSHBB{Up!)fg4{7aiJyan z(L?S%~bHw-Z%dBFBxNT!>#-fUS*t8F~&6x>v*k zM+6zy8Q%ah_w(nTGTE3skTHl-OPN&YTvq7NgdDpY-{&I0sA2UXzH1{SPK!UrKLTM* z%WrQiTx=^QpRu2=$g6gSCCm3TFT=`B3(F|G-S+IxTC4nDdGq{Opy zkJhFyzNLnFr{ZYSg@YU?wT@IhbtcQVAV0f|Q@-QN&Iwx!b_^=5@?snD($8vjTPV4k zn^oo}*jnM{2BxRceyT1y&yJJD>6y#2mlO*Zs+@oRWu>oTog9VCpt#R>&URQgXtfT# zNcHjL=#2*P!DY^z&rzIQyb;TJt0!<_HTnIvO=meD6-qfL8!iSPNziRPXKL+MRelD5 zK_Sp`1{m?5ka#&b075{iJ+<)CQ0Oik4g(M+pn{0iM2rR{k>XlNC;}k{13aZt^&s?Pn8pE0bFAs{WDuQgl|C?THH(rG_6k>gf-wmNL@? z>R7^bwIt+? zrv4<*VC)w}$*?6|y6I_VcvrM4L{ ziH*I89eQ;4;k)61c z+eVI?*>xBeQ;p54uhX&_PC85lG@6=JKk#Ok+-6i|$8$xFY9N zkV|4o^zw5;gG00 zmJ$-$N9`Is1WUy!n$0gg@8@921Grqx*;U%igVB@&+!^Ah#R`V>fT`}k DT;X6s literal 0 HcmV?d00001 diff --git a/certs/client.key b/certs/client.key new file mode 100644 index 0000000..0754130 --- /dev/null +++ b/certs/client.key @@ -0,0 +1,52 @@ +-----BEGIN PRIVATE KEY----- +MIIJQgIBADANBgkqhkiG9w0BAQEFAASCCSwwggkoAgEAAoICAQCygX0JyUoYAsev +4j/iRsL7dSgZz2xfuzsYtvwGqZD7091bPH8yF4y424Thu8xqctLFc+IfLNalTeoT +3msPwgxqbM+36cgFpL89uCRqxCihwfZxmh9UGDPuS/NylbodXoZdEb6vP6D7ID47 +hiryQJty6+DSH91EePsRgO1fjc+XOfutrclrBFsnNAsAmDdAHekAcWlvnnd+l2Rt +DEpIH6zWp/mhDV173aqcEcA3dVWBLhn2WOkd6wpzsWcHj+wKVpU3y4v9UV7iMja5 +C/ibRBSkXKnNHzP4kvLgQoMTGJD1n4FCkX8gV3TcN6tZfevrA/TcYDVf19RdpnkC +J/COfHX8Aj7g2dnLohJ4ljB11Aslid4Wx+4WxioAOJ19zlfwDSURMwBk9Ng7m75m +DWZzBUZjl8S5muzCnz5LT+Omlq1WA4QUy73uA6M6mqJN/8pPlceyRJeF4U/9DSzU +4/YsR+VEO39OaV6/uu9koTWWRXpj45rUm1MlxosyKIKGZJmXkqKbo/1klZNx9G5S +bKGsYJU24Y1OK8pCGV1BPKeUfkpEGOnS4+MMZSRXLbA9Pghpj+4SXBea66xWGknx +zqb1PnYGjk1d6sfmxka4K7/Ws4tiX5sy2mziMO6b6WIvGBN9NoZW+ctr6/KE0PpI +x6PiC3BNUBJyBwTYfi65UDpGWqyjSwIDAQABAoICAAJGk1UCG2817dzIqh7U3xx8 +kF/P3KZVyTmV752YINCNEWfd3BND6JfcuJN2JPOAdj5tLUdPd4cQ+Lh7H+tKAoWC +0J0cHmAwCv4a8F/qE0iIo/8rw1V7n4HctwRRc1d3gogCN2edjIxXC2QP4FFJUJIE +/s8+97+tOSoudhg/QxO++f3rVsOGATF9QNynlCC9oOBQEdOJ9iUHghC/1NyZhscP +yidq97OiDlBCC6zJUqc8crlIxeQLQI1cCB+5Dn3NP8a/0g+PL4H7uOXgCLHWCttT +kRib2rpDCVShlHE0YXi4KVozZ6b+Zm9+SDFyYQUUflUm5tdLdZoiCq3j23W9kXV5 +DGWwtcR2H740oWtg0uJ5PMob3YAMXfIdrwfIKjLzwxTiCqkdSK8EmHacpeb+j6R4 +m30dJqiaaq5pMVg7Qi3ds/OJ7tstLw7jsOgPNYTkhFhTEri5r95Cl/MOyjzIzmep +FvGmatCJFld56M8Lfir608QXMOkJwzoBOnPESMA5Z3UXY4eMaLlol6qAhHYFAlGh +/+fgrOz2QsCpNi3genasht3PvPpFWVyArI6Tz5+xaIAsJRRvkRdu4v4VBFN6PtaW +bBVjCHeoW3ArHhCIYCN9nlqD9eJT0pE1O18yQ2v6nmb5XSIzIV56kxE5HlbnU88+ +I4ZomwzsPqsXPO1UAIRJAoIBAQDm0esN71qEbRxEXpL8BkgN7oVg4H24v8l54fcM +9EhjoMn+5dgBSHrz0Y1YA5px210Ek11PtIq9s1Bu8ySffS5e0STLq7HJJy9Zk6jt +gyGewm2khnhbKO1etUOY4SBMgpsqvaX/KH8sPFOCqQMhNmhCQ9bVQ4yzpXSy15Kf +pAgy9V4qO+4J1mDLM7vCj8XPpMHmyvOeILZQhNx/Z+xKA9hNKokI2zDOijPQ/AuX +v6Go5tdD5qAcWijIuk3Ls2AgCRiwDwc4HFChfdDTFfclFRNpJ0qeyDw56RqYudeo +MnqA0+1nhnuNwTufwe+D+II/HOVBPYiXIRToJGFUDFxsWftjAoIBAQDF+pk62MVo +9WJVTiFGjNEwyVCNA4NWpalM29zLgaWHft8kT4K0MqqpnbsbQsiAOdaL2ffALqRT +IaFLVhqF2KN3aEEUU3cy5+Agy1ACUi3M+HKcYCqpDcyXRPbyIoF5aZCOCx8JF8eO +4+szmoe2WtGAU34reuwOX5tPOjKCdtwUjWAldTAXhzIn08LiJy8xZBSr2TfnpuZF +Bq80y4DIeFFyuYQxgEWA9cxVLcJP+FlH8hB1uGKiux7FZ4LqxhVTpJewYj8RszAq +RUutKNTZyOzVtx8i2vJZaMU+tWK7hj2uEr9vnNtznqNyAqMM9Q60DfwRDDQBmNbz +xZtE8damNmD5AoIBABOLIJjcdFCUIHmVfGKEcaNkV7y9JUf4TSnZvR5GrL5qxc+k +TGbHaUmtq4cRPwl25mhVxefSxJCNVzkdszMh2URD9xabogEDJVozS3FY0gbsNXZh +wF0PmRGUzXVrUl3IDTVQO3bgSexH61Y70z0Dq045Cj6iao5navsdj5eevub5qZBv +5JbGpQlvhu1RWRFcxOIyuu/fmzA0H6tV9EbMDotyF4o9bOOABiUiwiSGIDz51q40 +H8hmxd9BDwc5V+E+g+2cSCMzGoyh54WH7ZYhM7SKlCHfmGHa39qgmabvJzozN321 +gE6fVtoPBKWq6/RGEQ82E5OgRHHnaqpAJa8y6zsCggEAEa2a2SJaHlErAqsDVaVl +WJHhW3Yg2C/auj43rQRan4q4qilfZm/PxW2MM5b3CFwhyEMiWErR6YprOKrrm2AI +2LS6evIpBqal4MfG0S49YLwen9AGfyn4Rtmlo2FpZkoC2mwrzUgOTbgUXHtD+wiJ +BIhwD7neMjpfR+fOcs/iPwOQvkeEj9VGqT/DeyY8lJB3OBEhaNICZc9+/ZveWAhG +XZQrNbBahHVuVXzMiQ+ICWCYD6rzQ8yppr7jdctSRDHCScG8F/yEJIIji8bFmtzS +KRM8+IPMeCde1Yak1lHaWBzccz7yaZSUy61omdOYCIPnKi6Ixku7hfDzOGjP3e+l +IQKCAQEAl6NCBTpxYPd0NpoD8NsAckgnERzwdVsSHCgncD7Da1jhwOwkl2naoab3 +NnRLYgqgqDNx/P8ttzVtVK1XrVedP3/sEQyQK/Yj28ATx+JYn4EqELbprgzTSDcL +8gxJhfxCEKs73Xmpu4jRtdzH+vXmAG/M5rQ/kcORwoaFgAS6lhCrDAZrG9C2Q7Do +ctjBjnxfSjCW7X2EQsRfxzFjImCAMAAHnrCNRueljg888+ZltQj4mjSM7EzyGhrG +r1EOj+as3DLEmBG8xqxdNruknDNHsJKJx93xHaEXlIy30FkhVoM72fl3gDCg1Kf4 +VxKTyw6mBwq6/LXr+QQs/+IT2Sjg4A== +-----END PRIVATE KEY----- diff --git a/certs/client.key.der b/certs/client.key.der new file mode 100644 index 0000000000000000000000000000000000000000..17f1d1729aac707a315e03ced4cf9585d7b21298 GIT binary patch literal 2374 zcmV-M3Ay$#f(b$b0RS)!1_>&LNQUwEHHuzC;|Zh0)heo0J4F73CT(r z0>`i7KjKEh`*kQ8&um}2I~cb72C0zy)7@JBt47zdg7lYQ!j^!S->QA5<7K?o0D>mAV~XhFuZ9uRoysAU->WD)K;^ za_ivIAKgTF`w@WcUyaX~Is2`x$!i2#Co~HHm^VNj=>TzQZ=QF4mt<`WN=P59)~ETQ z4PATPs+063j}&R6gaB@r_KWc1iOo4#fZW^)BbW0%Can(V@#K1)yIrk1T% z1B4XIz3u~}I+~(Q|H@C5$FfA1h2c;A4J_2-_AE!`L_2>@Xc{5BMz|}#*0YOZUz;-8Y~nEPo9SXN z7!!RqhF1B@YwPla(E3Qnqv8v2O;8eY2L#xDF1b)TMp~?+O9BG{009Dm0ssO=lT`v6 zZ#C`Q$f_RH-yD39U(ej8RmnM(@12++(2Wsi-P{vH=$G8MlXfKYfObA@Ek{pxhYLmog5xuFbe(}@L%c^NQk5VE5lWLpMl)B1W|KWcY=rlH)oxUj8_X}58zQr zP?7}x&p!9RtvM<#b{IcH6TbQV>sG^t0Wp0*+^3Wvy`bPw5z~qGB?p2Kztr5BhQ|-e zCu;Yzq7G0(3#`dfr#y1GNX6s}K#g1oAGr>F%|FJ!(hrX>f%~}S;0UqS3fohW7@OL< zLkU!&lyNj+c(^HAGiRp$W^aB-F>+xA6n<4E=GRMgnj#9V@uq6fi56FR=+6s&D*DsJ z7cl7w!#V*vbHqr%IcIejV~31rxoDTFfP{7h0#Tv==isdD_Cmm^HZ9^`d(Jnd8fgh>K|0RaH!(d!NGT7+#J zL|&5o21pI=g<#-)xWCDH;r9&mNMoSM{^i&KNP6?pjaUPkaob%4lU+}=ioLT?Zu2Cc zeJ)3A)dl*q=tA~DD7UgLzv+pOoE##y`}#se=Iyxf~f-`HfTaa z*40Cdv!!&h*OH&42r~6vDm(58)?mvsyTXsf&!oZT%JZHeworuJe`oAU1K3R}i3r;; z&Wbb8{0o=Ap{VB9L*}3yS}4f6P0O=jAPE?-4+l6LP@#R$(-rq66%%PEN}k9(Iq4dh zx!0&NdVtgIXNG%?!8@P9?}PY)KOE&jJ&2bf6zC*jR192fS^HxGf&l>l#rl~#*u`k| zVpUEdMvT!g$xw|0gI1-fOxxVcfu)Cj-y~0hv@)uxox2-C$bdQ4i`nob~%wp!7E zQ+_LY><(X>PdYM!cH9(=U?p`h7l$$@)578>FEL~ktJyc_rshQkuQbbm$aqn5xr8x* zMS%6pRV~6#_*qBt5Oug>qPrf&XM*a+6;q^_uwp+EvoI<}ORXr>*~skGw;v+f@>yub zKDA=IhCQwlzi*t|bDpDe0;3G|4zvyY5ezf|nAY>fn?&)}rZ!;t0)hbm6N@02+;mWs zAbFL1VuW#{WLLbsB}e#8DcQXqMy$SS#m}TnX2)qst*eI-KM8i`XjR4M(!`LBS2-QC zGa=bTL-!V&q5%UXS~E*=SkeaUHFjaZT@RTNl+AT(QeDUmHBdWt;7RO9>sC9{Jp-#w zISM|aYK~`W`yG#$p1$V!sgQ5vmd2$CZ-(trSrJ^s;xfAL-Ga8Jc=Y@yumLW5=ij*PWm|@!A z+Mt=H?-0tu4>l8%phR)!YN|jbuQKa90)hbm5v`ipB3d3% zD*~$nRi$NEk>Oi*AlNV3x;{6p1X`bpxT+~%W^d2MZHzOP_Xu1e$U`DnO3~?xYdEUw zn_vjow7PooDF&vc;K#<%E+;cwiX_S=9t!SCkm8=dZNH+`e3`vFjLJ+Gv-Fd0Ih|#s&$NKf= z0B_9Zv_Fx2>6;bjO*&{-i?gFD&zcYrXU)Tj7Y5|hggrUweT{I%=(1T6pJ6WJ)>;8rzqZ~y=R literal 0 HcmV?d00001 diff --git a/certs/client.p12 b/certs/client.p12 new file mode 100644 index 0000000000000000000000000000000000000000..e68cd18a7a7bbce62c7d1c84993a9981a13f6243 GIT binary patch literal 4408 zcmai&WmFXG)`kZdVwj<%89+*;8M{&udZ759o8akEsMunkR>#3CM{%B-Hc| z$^eZ~!$py?lmMO$O_a40-Y{rJfT$*hb-@K9yi}u6T-5HJ0*NlDJvzA;W1f`2jmlw3 z;@1e2nw?ekA@!|DH!H3trFq0ssK?LdzB_2RbsRJtl1O{$1}>*B5c2JPJzt3{gw&l% z^irTEJm(9}lmEWMl~>s2pwO3g7u8SG!w1xH$suxgz`cGmrT!`66EE`SxZe}NK(ATa zW~BEz_52HJdm)o0|A1quicIOJ(Y&I9zNHyi55q2GnKe`rns;InbctQn9G_?UrPZ&x z2U?!$Oe+${uVQ|fqE>evLR@dmzG)1O3qh4z$=PLbeQ5NLgapYjr#@BEG4$;IoFU!| zZv?%EE%tw++)2c>6J z&(p-}bUUkOyDK}IDi%Bxm^c!VY287kheVNcO!qKZ%NVQqA`mnj_5p!H`5m;G+(C34ze1oKw*3j`y~_V!To-7S3o@Z;j= zYczi0)M{CKY_Z^=bDF6=K*%D^b2SBvW>rlO1|(4;Q1)|4S;KT3 zQb|75P#DfP>+QU(RSXj67$B#$5iUzfhbZQThHcwre_sT5e@Ky+F9;RMfjTnf!}mh% zhg`cDoS89K{%$-wjFjHW(5KQ=W9~kS69=TP{py4!#amL4vW~aL!5?mg;KbH~Gi&Ha z*kpz2@bk~!!+6QM)>=88Os_Yxf+X^(L>ZAw2pxjy=riIkKBbpRmf*Lo7gY^dZbz^O z-%=diwB*B7va5jmoYg7<>(kp;+L_Aeb8tx(^4g$IKswot#2z(XKU%^+CR3W~5t-={ z`jhf8af5zzc%CCLa@dKM?FIX@?g|6yk6wx1`i^Ucv8l8`#p80uJ{7WR|L0=grn0w0 z(T%><@359Aqs$|(!;e|9A{5)jt}IApbXQ(>+dBEEMgdjqHbIC^2R1ehyl3Iyze6#og^c*%rrYvzU@DGQ48Gh-8^8mnf55|M%3#(so#1zve&fonkUIul z$|G_7LWFKoaG!m}vCRWu4HF<5 zq*wD)+j&%UCYZsUmPZ+{L651jNGHcydDSN*!KalBzwbGrf&Gy31Ae|R}d>*PDZ45X2JGOJCGU?`nF3}A-ZaI>T z!6o49e5XaD?ngFSCQ&a+!~}_Yc+-L;7QBqf&U*(*)`L)&HxSE|Oh;pJ47p3OchtOk z+DOLY%GbROPpYe%C#f5IrvghvVr-lG8F|TPs(#d#xAe^{pJ5-Wg8eq)rEWAvl*;SMl730NSPEkU5MOp)UZ_`2JSQ*ohB#_ z7x6%wIm49WGv;t|gWn{G$=o*Rq6X_k2g@0$M5E&O+%pzE&sf#_K<(xwy@&QzFWb1; zK{T^iy_-&_I;?~#obH*=04U%%W#AP@jg%~+TCh5u#%=fve^e5$G=>&oRcrFDag0J{ zTUss|_DNO!;qlY`rh5u=5iD8UfqM7Gd@0{UGvaM&(Cm9Jh+mn*>pL``WF)>49Bcz6 z9D3%JlaM$#B^*rjF!Ed%EO96gpps>e)tF?hoWkWoe|}d4eZaBb5UhzDsrU)Yhzv)@ zv2(tdG)53zx;_vr5F~fu!u(jH?oABqgqFD^{!-E7?2i5PkyR+ua@Dd_!GAM33SQ02 zrf8Haz0sC7rtc`DMfNaY#JVxzK4!2Z^5pv>Je9$$ROAnKOd{6E<6i5M7>n=nw2Z(I zIL7o@ji~8NB;$rh+0ygv;@M&+ zTEXz|?-S@uuaIu?8k|*n67hz9$U@J)U{2=9RnaEQa;RThQ_xway`;}K)&~u?i(W}D zD8d;j{3Gnw7(s!s#oA4 z;{-fmTxRR*AHz4s;!ED9MCckTcm+Gp46k;o3G!VHvya?qA;z-#Z>Uvz>ECuc%}z>tai0wKE&KtYN-e%ZK!WK=Tb~wqD@JB zUUa7gNhlu0IQmNr{lKqlX9O(lK+o`MV|9(fO1GHgW?LSfxgk(4x*qSx7QgnGVUhuy z!`E)CY8@O>lhu=h5}k(|J?m*cOPZ_#otjeFTb!#6Bga&nkqNKUju#m31 zz=4E#+^f#md{`2dFQs9|kiE0~$k>34c;nqB{X>yy4n%~TaLbXc6M8g?e84rWIYRkG z6j~r#9g}HTqute%aG~~M`tX!T9!@WaDyFLEJ0n;gDf*zb{iesJRk?~qJ7b>P^lP_t zs>E{Ms{?9f(Ja`D)4Go^lV1vKbBdyVV2j9cugl~se)y%qh;X}=nr&@0x^5|hI-LTZSZ82;_Mkai zjO=sv)m*o4+?{NK6~gePp%zQSjm=+h9nwXstSD*P*q!%LlkT-~?tBY6>`EUS!3zAm z*As$3)7HpbjXLfYzA*gzM{SOV0=6}M!b&tBqZ{4}n@B%iA#_PEjzND{FnT@e^9+uU zNg9=tUp;a+TuRy=E0q}&N}n0`Fl|2U-V&)MRlGiNkFwtBN&J<|M))V5lJC^i2d8T? zXy}@eVwHgnb1Wpe1XYT!J<3biz?&s-!fd}bj|D!mcHL!Pu%`yQj&`9V(om1R0~Jad z+J#^KZg%+nrMjIxAvQHefGm8a)Z&&a%Ww=+U5q~*Z@JaTN^-`cFK9kKBpxSFP+=h2 z|AsRE6+)$_31zo9F5ezmB;ZryQW3O!O{^%vlS9GSc~oW`S63eZA_59_q6L{K(&6@?CLBoQ1ZkjGYj#stjidWA((7 z49zgcdj@w}A3LVQS-{QXi3tYy$H$4k8%A_0C{IRw5aP4o~Lza4AZm1E_hG#5Ys0aujA7B0iU2IOE1dOl8;4J($EJjJ#q^< z+z}K^F{?0ZqC72M5fNehY)mwE+E bQ-vPiE&aZ6b`B)U3??OP}K# literal 0 HcmV?d00001 diff --git a/certs/ip6-server.der b/certs/ip6-server.der new file mode 100644 index 0000000000000000000000000000000000000000..4e00a573c2c0e298190bc802ea7214a4af8a7afb GIT binary patch literal 1320 zcmY+?YdF&j90%}iwqcoEHka0NPvr97LVB=>BSmEq!dyFBG1)=M$TW9J9g!M^vm>^D zq3AHt!BU^#RxjeSj^aP$C0^!eE$lui~jCf4RBY z@XOzlr4g{;22v-0M#>wfxuktXL!p}x5I~8b2q++Bj=^OV5QpNl9UXve>S&@BKm@D- z0$>5`@>NIg+K5*FM?iz124McXK%Zh*nbIRegXt$DqhkOzO!vq4Py|GV4ciP^@1tOB z7!;DdrTw#=-(%Eu_|(;_lT<3n@q@mO$(g8d9#N6m04(*~kj@w9s2d9oVl5rXMfyiP z%z82ztIC2f#+TOZhGSm`XP=)$oR$@>72bKQ%Op78>&9!zE{~n4y&y!h>0_ zU6W9T8^G)sj|XbZ+1XEm6S@Ynoo52PxrQtp;zHV7lktFry``*q^69^tW`D1Wsqy1c#9U>ICa2iL#awT(rs_`VoPd&KmPqxtD>erav?hma|F_pv)31}y%JP&2UthQZ0U?Pn5IG;hp`){HY(T-%l z;+c+vXJ&;f%31v7(S`jd@8W{QkmlCWkNr+T6Shryo&6W%v!hKa3R}Cm^2aTEkjPGC z;1K^qmH;&_`qf@2L<0t&1aFk2`KZ1nPKFOMXYh}_qW6hKa6ivR-7=RK7aP@G770>X zu}DpWJVfxrAPP({Q?hwbl-fXP51Q0{4f4j8Zd z!7Ib{03G(vhSHTFKNl3hZ|o|<)!-O$C@io!-u@-**%OqFlu@mCU(*24+8FD>H2}3F zObPC2iYg*)I9zgb#y31Pad)HDp&v!AgI^a3g^)RDLcv0BVjUyDwl}A>^gewy)_WiM zR<^{l?F|PPgEiltG_C60vltKMSlVNK`S!SxMEK446z+8Sgmcv0%!$~!Aw%?h8djYZ zW>knjw0m~q&qqd|eB7DVzLBijh%s4m z2kZd1c+Yk^e=7Hq(Qvzxb=*uBn)CXBZ{k)C)EE(ZLVtfon1%j8z;DIh%=39hwX|ko zvV)CAUwyR^r6vdBH z0avF~oio0J38`{$1^SNnYiK{7RLj#8v^e^VRPXIqaoFVQY0Vb|b9|*{2rn~9ws1dj zK{%c;U^M-vuJfZ`T#tRs*@!Tzt(j8|uq>b9>O=vX3*1JnZ!HDY(5Ysl@8I|5w7xjW z_gwjfMXQe#%jrFe9Wd}n2g#|2bFqq$Ju#QtF08zqSs>9$UFW}{FIP7y7)52}F!GPz z4*t-0CB8b(OF1R08QEy_I)q&1W*er1>GG`7$`l~vJbd>~6o`TyRgq z2di>1I}7WxDyTcn!RN~M10l;L-8wisgx<(}o4zO+Dyq3Q!zP@|@m!4-1>m*qZ0Wh2 Wf@=jUXX#%ql}(|t75#$!8~z0{a7R%9 literal 0 HcmV?d00001 diff --git a/certs/ip6-server.key.der b/certs/ip6-server.key.der new file mode 100644 index 0000000000000000000000000000000000000000..e2ba3437894703daa2105abe85d9716172e38745 GIT binary patch literal 2375 zcmV-N3Apw!f(b(c0RS)!1_>&LNQUwEii%!DFOii0)heo0E`;U@;zI` z3YY}#lauUbW>5;EK_O5o%@SQ= zG${4GUf0t;^Q!>$uD7e9nTMug!|dCUy{rK4)aK~B`bMM8a37RnsRB6umeXD1x~q(I zQ?(X)@$vAvWFjR8(RE%|qbGkG1%Zb1y(-_+g8Cu7U4QZg)^f`zWJ7$V6{XFZeO(I9W`l= zxOzZvsuH;Vdf8CBI0|&GGS1VhJ-M!Z0eS*99+*ii!go`Bh%y~q3tgONPmIv1E$XXv z@xuHOimLnN^+#x}8(_@4IEF1p)&B009Dm0st@~yBt*+ zbgJPT{8bWT3$cJ62Z8`a%9=yO4_7NPQbx6zV35B`?a8-%Z29g*nLJ)*sdw7-&vfbg z*pTQRT4F!*NQ0KL8sZ-$7;j9uy}v5X=P=yIE3Xf->1NFr?(P6p*BU(6lx&`v@dBY2 zC3xRM!pha776Vw)%@#PbhNFF$9AV8oi2t4&dGh+)rcCfXG6kMX_;aziOgtQ=s_Mlm z&H}!ASw>6-6=VWgFRb>$v7mGw_VqT=+h;gdOHjHTtQ2~kRtT_t3E`c7 zws;KTt(c)uX|?x^iuG%yV|OCsxD+ zL_ald%r2+B8cmX^k>VbBq&V+=AGcQF5S@!mJJF1>Om_!+j|-a2oczfh;JrQTQITWD zYcGdP$&n+*!t+eZjz5@tgIx#5@QR{_+fa*hWLH*(n!*^Bh`tzks}WQ+))E|%J~+Fy zqP7y$kp+P6RdKhf|4^j4!gsYQ%+1FtZpIy%$Mec6n#{t3N0$dr)4AF_GuO^gZWDqa z^HjMCMNDM3Lp z%XpdcKru6Z0HQS5RH+!0TC?{=qLMW4K<>)x^*v<97H3~8(?AO8UmPv!Y%Sn};Vx=D z;WGQKHY&yov2|&|2<4*>>Z|{Ob|YufqG_f!#8{>T*nn_|eEm`ZXyX*FlLcN(&f&l>lwf&%KFD&g# z+0PX#C=SLSv`x<(i27471*$JUxViO}2lLI>gW%fJs`;Wb@F&C$m?Zj!&1-WzC^j0JC^Qc|9?xGEG0I5xZMEkXV}4o zh&`0uM>hr^_2J|98qa>@6X2N6z(3TKD}oc2ZDtzY5|$zt7TV(`v!Z`(yee$A66-PF z%i=zpRj?jci2uuEkhew?fk(I~f`Fys3l7iDkpKBL^!U04AuNVLyC^7xa!D;P2Jvn9 z732jN&45O+zAICoj>g7(OQSK;E7<&(a|Pe68$QB$&;I&FcQcxA0)hbn0I6t^Sx-VM zL^z8-1s*Rw+vITw{o(_RLwl&#yinHCHA%OXox@)L`HNOBGb2V2)i9D2)!m~8EfVDNsjULX?Sqw zz*zz=l3p&D;~vJc6LPxP-eY<&k_KI5_(VmDs1rp=8ymnF{t+*!!WVa92kj^u7<9}U zPSBS;ZxEP^_ZLk6PDP(H^cR7FH-Y`x$5I2JTs8op2qa#Fb~F`p*8+k800}^^+cq-J zjli)go?90MGp}IsAtu~1M)|tS*#a9sF@snq;GPn# z7x=byfd3nT^Dnvs3ND;g+OcuP4cuA09V>K6U%5ux5@AQXI7z=)pWYy1G7RVukIX2b z9;>dE*7`f`@5&5@4wfojg)$9=H(kcz1NVYagrH+Yl5N*~JUB@}t3wXU^Tbh8-JS5C zM1_?nA-1KFrCF`VrGZ8eCIz^oz)ONg?8_@5otpWmt@)aJy1Wewc4QHfoykGBE^X`Z zZ(xm!M9Yot3NvK*hj2FH_=eB%M1nps`Efg^H=*A8{62d0Hhb*038CI0He985 zh-%{!l;w0Fc`kixsKyG;t@s$Po_m80D_!`foi|}P#Q5%;#-lfgGT^OC zyS;AutTdi*;e#Of-?9);m%r3?(HE?alm#ed!1Css2^TAj1gS>s48TJm7P0?P+%wlF z3saHbfj1EjP$NwJCo|;-UT^wp@vA=Q2ssF@0qqw2#+W5gtmq3Nh9mzFLNR97fx8^h41%lxosEtQ+5PBKY=8geb%7tUdMy9| literal 0 HcmV?d00001 diff --git a/certs/server.cnf b/certs/server.cnf new file mode 100644 index 0000000..5afd139 --- /dev/null +++ b/certs/server.cnf @@ -0,0 +1,16 @@ +# server.cnf +[ req ] +prompt = no +distinguished_name = req_distinguished_name +req_extensions = req_ext + +[ req_distinguished_name ] +CN = localhost + +[ req_ext ] +subjectAltName = @alt_names + +[ alt_names ] +DNS.1 = localhost +IP.1 = 127.0.0.1 +# Add more DNS names or IPs as needed, e.g., DNS.2 = myapp.internal diff --git a/certs/server.crt b/certs/server.crt new file mode 100644 index 0000000..40b0916 --- /dev/null +++ b/certs/server.crt @@ -0,0 +1,30 @@ +-----BEGIN CERTIFICATE----- +MIIFEDCCAvigAwIBAgIUXNy9jnSXC73JGQ5ZPh1r0BK5+Y0wDQYJKoZIhvcNAQEL +BQAwEDEOMAwGA1UEAwwFTXkgQ0EwHhcNMjYwMTE0MDAxNjQwWhcNMzYwMTEyMDAx +NjQwWjAUMRIwEAYDVQQDDAlsb2NhbGhvc3QwggIiMA0GCSqGSIb3DQEBAQUAA4IC +DwAwggIKAoICAQCXwudcfKePoE97PtA+wgDxzgDfk9KJhKhEDWJgW9GbSjbpudQ0 +j3P+7KKmOR7KkoW7fmiKcfXVVeMXDgz93vI+ViIXoQTO8YStWt/nuvClUqPbX1DR +583k5dS8E8jpamWfM2GNjgj/zIpI6T1MrtLOlQDk0jjiKUYLH26LY8zF422aNwri +wFS9bkTh0A8VHJ1A9LtX42TLjau9rccwUtltR3GyXRWewjfb2AgBWwP1Vmm39Z+k +gGWxDPecTQscw/5zBK+WbACRBU7IQyXj37d7o9ySqynEzga+xCvFezT6VsO2oASI +4K5uY8dKGpYibAs3R7u2vcHaNlyU53dDIwQSp83SqtrFzBLKtuDREdtGpwgBj9Av +4nlqmtwGBgmPgar03FUUxzUTVUyhbKOC06VjzD3g3DK0SBmVCqzHvi997ZJXXMIl +TT5pUVTM1VUMVtJGVydrgVpRA9CG6bVZ7Z1YZkzK2Iwf0agKAguWKgivXsavs4KV +BLmUvBIk29sRGchzoxT5Ms/nKs7jRMlG+PdY5BIWvTxg9koTDLfGLJ6T+3HTnIHR +K6xU4ac8v8ESNWz1bLbg2mhiFR1z1iFNhPgjPpw324+IxQ+D6MNav4gLqy7rlcaN +jTENV0817ncgbIwNd/ceXcVHCB/blzAa5MAko0r/HGQl3pe2r5+/OsxvCwIDAQAB +o14wXDAaBgNVHREEEzARgglsb2NhbGhvc3SHBH8AAAEwHQYDVR0OBBYEFPSbh5Ha +mGiURrS+lZQPyw2BdCq1MB8GA1UdIwQYMBaAFKAbUoQTBYbja9Od71prY343vDZN +MA0GCSqGSIb3DQEBCwUAA4ICAQA6fZhuxUKs2DGNAY59OmvRQ+wwpewGxLdLHI8H +IDqgGM2HCo/TMBB9YxaGZi+de3QYiEzdCbvvomzrISVaNcM6xuD28Y5ds4aAktAY +jHLn3QNXv4SLjSOdWGsVql0QpCIoyqKAjwavjFo/ESKKJ4br5MPRCbAI9XhUz5I9 +8qRNm1boxLbSbzXme4rMNxn/HbQyBGlXdN7ACXHIWhu0t9LM9SqipHKFNKoFXX1Q +cBfI3N+4bPcbYrgQAb04nylGHarXH7rmA8+0FQV62zxWzjg6V6cIdlPy2DATYlXV +5iAMtDpTmuQA2tmXQd5XBqsdsvHYUCNmcxb1tEB/cn8iveiufL8uFKwx/ftzvMBZ +pWLxpoUZIHhv9oZTfaoJP8S/uRGZsTUusC5PSNE9ZVr9PwGCmudaKTH6PU4ft1zN +LVpkEjOjzPrvPwmnn+hiDUeS+YaUkZLCXWPpuYj5i0Ilfwq3Oq7jWePydGvFLMPr +92b/93V3LhrvPKpl1NzGfZwMmNxp9DkPkhTNYfJHJ89P+2UT1xtYFSxB73IRy4Xj +1ZjuOEVPZLLD2rDRtw0t1lQIh+gvPiu43JwYjzXwOND3lADfiVtkM+IE0BlH/2fo +aA/PcfCUsFZii+fIZFu3WPZi50pqgSLdCGD/VBTZitbD6KceZFDgVfLyL1hLA1Hq +OiW0EQ== +-----END CERTIFICATE----- diff --git a/certs/server.der b/certs/server.der new file mode 100644 index 0000000000000000000000000000000000000000..a3dc2938873137a43ab249c006008d21b1ad24ce GIT binary patch literal 1300 zcmV+v1?&1Sf&~yTf&%!U0|Eg80u)@_y^eI33%$u14p}}OYtRz8`He6Q1_>&LNQUY-n$DbTEPfA}|dG2`Yw2hW8Bt0RaU71A+n%05F0A z3Ic)x0RWf6=UjZJkDyO`KF~hG0P)TM-;>gbgs4OfVqja*n@Tq6xzsd|bN=k2ra2zU zl7+i|Xo_+5)m7sc4h;R?@;+7~7oh~s@r12f-{-pUrBb8YUr^EK&E)0Oyc5XjYGt1@ zVU3Om|ICU=={-!Y($19t`c}iXpah8Eu5M$;N*b0TYzsF>ySBZ-+BRI2=XXOR z1QMss(yH3U%o57B;L#D=MyCh?kI*mTd1{*61_lX_fvWV}RTRfH6ID#1Y@>qHrDM!J z;M_8_NEww1tjE4DeeIH0T*4(yK50=@%+*y4R?9twyomgf}%Git_ z(WnXn3zjMfuU^Klvx1cbxs<#TB-`5&8OU>^6!|jG=PJ(QM9D_@_gLf-7QH-R_DT~B zx5g}W+e_a0rvM+hI=moOUSz$Bwe{~Tl`-j}wopT9cHZwmqg z0RRD`UNBrR8U_PZ9T5Z*FcE?YY;R*>Y-n$DbcY0g0003n9R>qc9S#H*1Qhg}hmqQt zXp}~@zLk^@%MF2aDzz{l1_M8&ZT51%~5m)1B{HYh!*lyf#fR4F(A+ zhDe6@4FLfQ1potr0s#OzeVA^=Laf*^jRB5*I&0BG>@cP52E?~Z9FGSeI-nTMhYF9= zFc5uX7KUaooqKc`h)mrHyYHfG>memtHN!f_;P&y3U9*OOlF%58a_8LxSHFadjU$~{ zYZa|iy*QsKMjfix zAG+oP&$JZB3& zJ!M+`KLLW8=UOQ-`aMn`w_MFFT4WM4qs;p6KMALw=wb~=lKF;|k&?n)W9hkw`HMm& ze+sucuH#wb@^ov(EW_*fX8-qfcP<+5JgQ~X+{S&J44B+$^f?cb6wP7sM<>ru`(+c? z8(0-ALGN-A%Z20BnC>`5Ph_&g+OW~L4K3DG2#4q|J}bD~oEVQa@Ho)-lmOp}TVylh z1kf2r|7YlE56^M%l(1G}i|5E>Ten#DV&_U~fg;@qVE&LNQUwEii%!DFOii0)heo0GGn&TzsdG zpig@~&_2Qd@y-C>lhTQVs6-87U|Z3fN;c`a)HIKC{_LWrIUdTAg}Z)eigESTRpS>9 z4E^5nK2{3L|&<_d!yWvt0~0J z2EN2A#d|dRR>QWS1c>0SZezzv8kQn#3pYo*w!OjHHe8hFcS9ot5~t15s@lcO63VvV z(GlB5rw9R$&@bY7YMR^z1__UWs`T7d6vs6aRZO95qk_|=W6V9^+%mLC8I=mG$G$Ip z?UGkq!X-^UX;Dj6bcW z^`M!{($=;l^~)U`EJA4N;xi%`=zC}ulsLFXBoACquVSR_$h=_=freM)NwF@EMOlm+ zA(n^M&%krif>O^ti! z5f=s0$mV_C%7t>piy<97V$CEylrSO3o@sqAJ2d7YbIC)L5COFWx{9FTlJi@c!M#~P z$S+%B^PNU-TodH>gk9KUjOY$df))DMHa3@U-gq4_;R%i# zK~9?4_iX%D7=~_uWw5LB#63*RzJB8dy|NjvqzGABiGqp)H!%W&0RaHbq)t+I)%kM< zxd{q~0&;q4S|y;ZU(H;U)iS~iiT6HLHNYvbmpy|cx!@wij#K~iN(GbK@H&G|Ldm%V z6aXn2+Hcb42poO|*#xS0)Y%d_+nCL$2W_pRhXr`bwCez#-&Csu5aMRAzLVvm=q(P8 zW;shI5e+lC)ocY>o z-F1-jB6F^-ikizTE*jHKH^@!C=W9n|^(jD4!wF3ns4wlo(D8ZPclZV0)^;S#`=Q3l zVWxN8eSQ?8P_w=d(kQB`-*nTOCM^ovlyzJB%cl9a7 zyi7Q@*CYYo@FLu2sY8~%J#acT#;NZLdyC!$P{8Kse71oUmq94#nzH6X1QmjL);{OL zK!vl0543iFktl%P9a#0i6z*k%2J~tQ_$yh>WaVPl=d!{d!!a4eHWNun(=D=#=b^jj z;qHLVLj+rWV{ebu0i#^qCBfusw8^ffQq^|aF{-sbAU#vlpbM)foA1B64c=av&w z*dw8&cRKevW)I1Y>!Mhfpo5sl`=ZM{Q@0ncaE;*pWul_1*r(^o0)hbn0FX)9D#R+j z{Fa*jT?C#I^%3fByl&~~jx1m6U3{+5Y)c)B*R-%{*t!^z%hO(pQSEkuvs`}?k54*H zkR$A5uyV%{??|{PMZ}b$QF{YD%q$Fv3d8$yS%ZWbvd4&N+vS~(D(~CK|AfRd!OW~% z@cOxbIs-zhrW=W_|nRgOh?vp4xZ-OzDJ9hBYo6>pnx5QzvZp{+5Jy4_c zEA7Ko+J3%`tm4;x1yI_ExB6B|l|y~qC>f_KYLtwm+7jPS!Q)(563IT~C_4t9p7UtC z`d`Lmr*~sS02Ij4M5o=> z?4%r)n6~bPE=SVt0Fi{44%M}V5$StGix{wYiis)Dy?_er1cB#oLbuX7w#1M@JbEvU zd$)0ZAfJ`6`?J!D>g2noy{!+`Cnp-Xm*82Hm7XRBOU`$~7m#<+^njjWzAl3PU_b5B7V(?2fN!2>Rl0| z<_O&+aF84pf4J}9Ms0U@cJ3F$#FZ`-`&jJ+Y(E@@20RXB9F8GZ( zD+DDITWbt-l2JyLnP~`L%lv*m;N=lg;{pD34`qjMLvS0~(7NU}jhiU3^0YP=U>Ab- z50j?U`L2#y;0Y$bU^fWZgA(~1evIvI9#|tdc^NlBGn%S34Y-Z)<&KP$;oKvU;O}K| z(e%bZ8D=|FOe$aqd_!?F&GMiG zzU0ShZGP8w=7kGx~Hlx`nFA#Zy!A(YL~6ASKG)-#~xrn;)V$ngsv= literal 0 HcmV?d00001 diff --git a/easyhttpmock-vetis-smol/Cargo.toml b/easyhttpmock-vetis-smol/Cargo.toml index 5063bca..acab3f1 100644 --- a/easyhttpmock-vetis-smol/Cargo.toml +++ b/easyhttpmock-vetis-smol/Cargo.toml @@ -24,6 +24,16 @@ rust-tls = ["vetis-smol/rust-tls"] [dependencies] easyhttpmock = { path = "../easyhttpmock" } +googletest = "0.14.2" http = "1.4.0" +macro_rules_attribute = "0.2.2" rand = "0.9.2" -vetis-smol = { path = "../../vetis/vetis-smol" } +smol-macros = "0.1.1" +vetis-smol = { path = "../../vetis/vetis-smol", features = [ + "http2", + "rust-tls", +], default-features = false } + +[dev-dependencies] +smol = { version = "2.0.2", default-features = false } +smol-macros = { version = "0.1.1", default-features = false } diff --git a/easyhttpmock-vetis-smol/src/lib.rs b/easyhttpmock-vetis-smol/src/lib.rs index 3d8f88d..a579552 100644 --- a/easyhttpmock-vetis-smol/src/lib.rs +++ b/easyhttpmock-vetis-smol/src/lib.rs @@ -1,3 +1,5 @@ pub mod vetis_adapter; pub use easyhttpmock::*; pub use vetis_smol::Protocol; +#[cfg(test)] +mod tests; diff --git a/easyhttpmock-vetis-smol/src/tests/mod.rs b/easyhttpmock-vetis-smol/src/tests/mod.rs new file mode 100644 index 0000000..99f2395 --- /dev/null +++ b/easyhttpmock-vetis-smol/src/tests/mod.rs @@ -0,0 +1,63 @@ +use std::error::Error; + +use easyhttpmock::{ + config::EasyHttpMockConfig, + mock::{MethodExt, Mock, StatusCodeExt}, + server::PortGenerator, + EasyHttpMock, +}; +use http::{Method, StatusCode}; + +use crate::vetis_adapter::{VetisAdapter, VetisAdapterConfig}; +use vetis_smol::Protocol; + +use macro_rules_attribute::apply; +use smol_macros::test; + +const CA_CERT: &[u8] = include_bytes!("../../../certs/ca.der"); + +const SERVER_CERT: &[u8] = include_bytes!("../../../certs/server.der"); +const SERVER_KEY: &[u8] = include_bytes!("../../../certs/server.key.der"); + +#[apply(test!)] +async fn test_mock_request() -> Result<(), Box> { + let server_cert = SERVER_CERT; + let server_key = SERVER_KEY; + + let vetis_adapter_config = VetisAdapterConfig::builder() + .hostname(Some("localhost".to_string())) + .interface("0.0.0.0") + .protocol(Protocol::Http2) + .with_random_port() + .cert(Some(server_cert.to_vec())) + .key(Some(server_key.to_vec())) + .ca(Some(CA_CERT.to_vec())) + .build(); + + let config = EasyHttpMockConfig::::builder() + .server_config(vetis_adapter_config) + .build(); + + let server = EasyHttpMock::new(config); + let mut server = match server { + Ok(server) => server, + Err(err) => { + panic!("Failed to create mock server: {}", err); + } + }; + + let mock = Mock::of( + Method::GET + .has() + .path("/test") + .will_return( + StatusCode::OK + .respond() + .with_body(b"teste"), + ), + ); + + server.register_mock(mock); + + Ok(()) +} diff --git a/easyhttpmock-vetis-smol/src/vetis_adapter.rs b/easyhttpmock-vetis-smol/src/vetis_adapter.rs index 27736eb..f1bc138 100644 --- a/easyhttpmock-vetis-smol/src/vetis_adapter.rs +++ b/easyhttpmock-vetis-smol/src/vetis_adapter.rs @@ -1,18 +1,15 @@ -use std::{future::Future, sync::Arc}; +use std::sync::{Arc, RwLock}; use vetis_smol::{ - errors::VetisError, http::Response, virtual_host::{handler_fn, path::HandlerPath, VirtualHost}, Protocol, ServerConfig, Vetis, }; use easyhttpmock::{ - errors::{EasyHttpMockError, ServerError}, - expect::{Then, When}, - mock_fn, + errors::{EasyHttpMockError, MockError, ServerError}, + mock::{ActualRequest, Mock}, server::{PortGenerator, ServerAdapter}, - BoxedHandlerClosure, }; /// Builder for VetisAdapterConfig @@ -252,7 +249,7 @@ impl From for ServerConfig { pub struct VetisAdapter { server: Vetis, config: VetisAdapterConfig, - mocker: Option>, + mock: Option>>, } impl PortGenerator for VetisAdapterConfigBuilder { @@ -279,7 +276,7 @@ impl ServerAdapter for VetisAdapter { let server = Vetis::new(vetis_config); - Ok(Self { server, config, mocker: None }) + Ok(Self { server, config, mock: None }) } /// Returns the hostname of the server. @@ -319,22 +316,18 @@ impl ServerAdapter for VetisAdapter { &self.config } - /// Sets the mocker to handle incoming requests. + /// Sets the mock to handle incoming requests. /// /// # Arguments /// - /// * `mocker` - The mocker to handle incoming requests. + /// * `mock` - The mock to handle incoming requests. /// /// # Returns /// /// * `Result<(), EasyHttpMockError>` - The result of the operation. /// - fn mocker(&mut self, mocker: F) - where - F: Fn(When) -> Fut + Send + Sync + 'static, - Fut: Future> + Send + Sync + 'static, - { - self.mocker = Some(mock_fn(mocker).into()); + fn register_mock(&mut self, mock: Mock) { + self.mock = Some(Arc::new(RwLock::new(mock))); } /// Starts the server with the given handler. @@ -348,45 +341,45 @@ impl ServerAdapter for VetisAdapter { /// A result indicating whether the server started successfully or a `EasyHttpMockError` if it failed. /// async fn start(&mut self) -> Result<(), EasyHttpMockError> { - let mocker = match self.mocker.as_ref() { + let mock = match self.mock.as_ref() { Some(mocker) => mocker, - None => return Err(EasyHttpMockError::MockNotFound), + None => return Err(MockError::Notfound.into()), }; - let mocker_clone = mocker.clone(); + let mock_clone = mock.clone(); let path = HandlerPath::builder() .uri("/") .handler(handler_fn(move |request| { // Since handler function is defined here, we need to clone the mocker // to move it into the async block - let value = mocker_clone.clone(); + let mock = mock_clone.clone(); async move { let (parts, _body) = request.into_parts(); - let when = When::builder() - .path( - parts - .uri - .path() - .to_string(), - ) - .method( - parts - .method - .to_string(), - ) - .headers(parts.headers) - .body(String::new()); - - let then = value(when).await; - - if let Err(e) = then { - return Err(VetisError::Handler(e.to_string())); - } - - let then = then.unwrap(); + + let mut mock_write_guard = mock + .write() + .unwrap(); + + mock_write_guard.match_with( + ActualRequest::builder() + .path(parts.uri.path()) + .method(parts.method) + .headers(parts.headers) + .build(), + ); + + mock_write_guard.report_call(); + + drop(mock_write_guard); + + let mock_read_guard = mock.read().unwrap(); + let respond = mock_read_guard + .request() + .respond(); + Ok(Response::builder() - .status(then.status_code()) - .text(&then.body())) + .status(respond.status_code()) + .bytes(&respond.body())) } })) .build(); diff --git a/easyhttpmock-vetis-tokio/Cargo.toml b/easyhttpmock-vetis-tokio/Cargo.toml index 8ce16b7..a55be40 100644 --- a/easyhttpmock-vetis-tokio/Cargo.toml +++ b/easyhttpmock-vetis-tokio/Cargo.toml @@ -24,6 +24,16 @@ rust-tls = ["vetis-tokio/rust-tls"] [dependencies] easyhttpmock = { path = "../easyhttpmock" } +googletest = "0.14.2" http = "1.4.0" rand = "0.9.2" -vetis-tokio = { path = "../../vetis/vetis-tokio" } +tokio = "1.50.0" +vetis-tokio = { path = "../../vetis/vetis-tokio", features = [ + "http2", + "rust-tls", +], default-features = false } + +[dev-dependencies] +deboa = { path = "../../deboa/deboa" } +deboa-tokio = { path = "../../deboa/deboa-tokio" } +tokio = { version = "1.50.0", default-features = false, features = ["macros"] } diff --git a/easyhttpmock-vetis-tokio/src/lib.rs b/easyhttpmock-vetis-tokio/src/lib.rs index 60f9dd0..f61b9a7 100644 --- a/easyhttpmock-vetis-tokio/src/lib.rs +++ b/easyhttpmock-vetis-tokio/src/lib.rs @@ -1,3 +1,5 @@ pub mod vetis_adapter; pub use easyhttpmock::*; pub use vetis_tokio::Protocol; +#[cfg(test)] +mod tests; diff --git a/easyhttpmock-vetis-tokio/src/tests/mod.rs b/easyhttpmock-vetis-tokio/src/tests/mod.rs new file mode 100644 index 0000000..c41aff2 --- /dev/null +++ b/easyhttpmock-vetis-tokio/src/tests/mod.rs @@ -0,0 +1,60 @@ +use std::error::Error; + +use easyhttpmock::{ + config::EasyHttpMockConfig, + mock::{MethodExt, Mock, StatusCodeExt}, + server::PortGenerator, + EasyHttpMock, +}; +use http::{Method, StatusCode}; + +use crate::vetis_adapter::{VetisAdapter, VetisAdapterConfig}; +use vetis_tokio::Protocol; + +const CA_CERT: &[u8] = include_bytes!("../../../certs/ca.der"); + +const SERVER_CERT: &[u8] = include_bytes!("../../../certs/server.der"); +const SERVER_KEY: &[u8] = include_bytes!("../../../certs/server.key.der"); + +#[tokio::test] +async fn test_mock_request() -> Result<(), Box> { + let server_cert = SERVER_CERT; + let server_key = SERVER_KEY; + + let vetis_adapter_config = VetisAdapterConfig::builder() + .hostname(Some("localhost".to_string())) + .interface("0.0.0.0") + .protocol(Protocol::Http2) + .with_random_port() + .cert(Some(server_cert.to_vec())) + .key(Some(server_key.to_vec())) + .ca(Some(CA_CERT.to_vec())) + .build(); + + let config = EasyHttpMockConfig::::builder() + .server_config(vetis_adapter_config) + .build(); + + let server = EasyHttpMock::new(config); + let mut server = match server { + Ok(server) => server, + Err(err) => { + panic!("Failed to create mock server: {}", err); + } + }; + + let mock = Mock::of( + Method::GET + .has() + .path("/test") + .will_return( + StatusCode::OK + .respond() + .with_body(b"teste"), + ), + ); + + server.register_mock(mock); + + Ok(()) +} diff --git a/easyhttpmock-vetis-tokio/src/vetis_adapter.rs b/easyhttpmock-vetis-tokio/src/vetis_adapter.rs index 4eef359..60b4f8d 100644 --- a/easyhttpmock-vetis-tokio/src/vetis_adapter.rs +++ b/easyhttpmock-vetis-tokio/src/vetis_adapter.rs @@ -1,18 +1,15 @@ -use std::{future::Future, sync::Arc}; +use std::sync::{Arc, RwLock}; use vetis_tokio::{ - errors::VetisError, http::Response, virtual_host::{handler_fn, path::HandlerPath, VirtualHost}, Protocol, ServerConfig, Vetis, }; use easyhttpmock::{ - errors::{EasyHttpMockError, ServerError}, - expect::{Then, When}, - mock_fn, + errors::{EasyHttpMockError, MockError, ServerError}, + mock::{ActualRequest, Mock}, server::{PortGenerator, ServerAdapter}, - BoxedHandlerClosure, }; /// Builder for VetisAdapterConfig @@ -252,7 +249,7 @@ impl From for ServerConfig { pub struct VetisAdapter { server: Vetis, config: VetisAdapterConfig, - mocker: Option>, + mock: Option>>, } impl PortGenerator for VetisAdapterConfigBuilder { @@ -279,7 +276,7 @@ impl ServerAdapter for VetisAdapter { let server = Vetis::new(vetis_config); - Ok(Self { server, config, mocker: None }) + Ok(Self { server, config, mock: None }) } /// Returns the hostname of the server. @@ -319,22 +316,18 @@ impl ServerAdapter for VetisAdapter { &self.config } - /// Sets the mocker to handle incoming requests. + /// Sets the mock to handle incoming requests. /// /// # Arguments /// - /// * `mocker` - The mocker to handle incoming requests. + /// * `mock` - The mock to handle incoming requests. /// /// # Returns /// /// * `Result<(), EasyHttpMockError>` - The result of the operation. /// - fn mocker(&mut self, mocker: F) - where - F: Fn(When) -> Fut + Send + Sync + 'static, - Fut: Future> + Send + Sync + 'static, - { - self.mocker = Some(mock_fn(mocker).into()); + fn register_mock(&mut self, mock: Mock) { + self.mock = Some(Arc::new(RwLock::new(mock))); } /// Starts the server with the given handler. @@ -348,45 +341,45 @@ impl ServerAdapter for VetisAdapter { /// A result indicating whether the server started successfully or a `EasyHttpMockError` if it failed. /// async fn start(&mut self) -> Result<(), EasyHttpMockError> { - let mocker = match self.mocker.as_ref() { + let mock = match self.mock.as_ref() { Some(mocker) => mocker, - None => return Err(EasyHttpMockError::MockNotFound), + None => return Err(MockError::Notfound.into()), }; - let mocker_clone = mocker.clone(); + let mock_clone = mock.clone(); let path = HandlerPath::builder() .uri("/") .handler(handler_fn(move |request| { // Since handler function is defined here, we need to clone the mocker // to move it into the async block - let value = mocker_clone.clone(); + let mock = mock_clone.clone(); async move { let (parts, _body) = request.into_parts(); - let when = When::builder() - .path( - parts - .uri - .path() - .to_string(), - ) - .method( - parts - .method - .to_string(), - ) - .headers(parts.headers) - .body(String::new()); - - let then = value(when).await; - - if let Err(e) = then { - return Err(VetisError::Handler(e.to_string())); - } - - let then = then.unwrap(); + + let mut mock_write_guard = mock + .write() + .unwrap(); + + mock_write_guard.match_with( + ActualRequest::builder() + .path(parts.uri.path()) + .method(parts.method) + .headers(parts.headers) + .build(), + ); + + mock_write_guard.report_call(); + + drop(mock_write_guard); + + let mock_read_guard = mock.read().unwrap(); + let respond = mock_read_guard + .request() + .respond(); + Ok(Response::builder() - .status(then.status_code()) - .text(&then.body())) + .status(respond.status_code()) + .bytes(&respond.body())) } })) .build(); diff --git a/easyhttpmock/Cargo.toml b/easyhttpmock/Cargo.toml index 5ed5607..345466f 100644 --- a/easyhttpmock/Cargo.toml +++ b/easyhttpmock/Cargo.toml @@ -19,6 +19,7 @@ all-features = true [dependencies] bytes = "1.11.0" +googletest = "0.14.2" http = "1.4.0" http-body-util = "0.1.3" hyper = { version = "1.8.1", features = ["full"] } diff --git a/easyhttpmock/src/config.rs b/easyhttpmock/src/config.rs index df4b8a7..c25aabc 100644 --- a/easyhttpmock/src/config.rs +++ b/easyhttpmock/src/config.rs @@ -1,10 +1,13 @@ use crate::server::ServerAdapter; +/// A easyhttpmock configuration builder for server adapter pub struct EasyHttpMockConfigBuilder where S: ServerAdapter, { + /// The base URL for the mock server base_url: Option, + /// The server configuration pub(crate) server_config: S::Config, } @@ -12,16 +15,42 @@ impl EasyHttpMockConfigBuilder where S: ServerAdapter, { + /// Sets the base URL for the mock server + /// + /// # Arguments + /// + /// * `base_url` - The base URL for the mock server + /// + /// # Returns + /// + /// * `Self` - The current instance + /// pub fn base_url(mut self, base_url: Option) -> Self { self.base_url = base_url; self } + /// Sets the server configuration + /// + /// # Arguments + /// + /// * `server_config` - The server configuration + /// + /// # Returns + /// + /// * `Self` - The current instance + /// pub fn server_config(mut self, server_config: S::Config) -> Self { self.server_config = server_config; self } + /// Builds the configuration + /// + /// # Returns + /// + /// * `EasyHttpMockConfig` - The built configuration + /// pub fn build(self) -> EasyHttpMockConfig { EasyHttpMockConfig { base_url: self.base_url, server_config: self.server_config } } @@ -32,7 +61,9 @@ pub struct EasyHttpMockConfig where S: ServerAdapter, { + /// The base URL for the mock server pub(crate) base_url: Option, + /// The server configuration pub(crate) server_config: S::Config, } @@ -51,14 +82,32 @@ where S: ServerAdapter, S::Config: Clone + Default, { + /// Returns a new builder for the configuration + /// + /// # Returns + /// + /// * `EasyHttpMockConfigBuilder` - A new builder for the configuration + /// pub fn builder() -> EasyHttpMockConfigBuilder { EasyHttpMockConfigBuilder { base_url: None, server_config: S::Config::default() } } + /// Returns the base URL for the mock server + /// + /// # Returns + /// + /// * `&Option` - The base URL for the mock server + /// pub fn base_url(&self) -> &Option { &self.base_url } + /// Returns the server configuration + /// + /// # Returns + /// + /// * `&S::Config` - The server configuration + /// pub fn server_config(&self) -> &S::Config { &self.server_config } diff --git a/easyhttpmock/src/errors.rs b/easyhttpmock/src/errors.rs index 0f1e514..18a2627 100644 --- a/easyhttpmock/src/errors.rs +++ b/easyhttpmock/src/errors.rs @@ -4,8 +4,8 @@ use thiserror::Error; pub enum EasyHttpMockError { #[error("Server error: {0}")] Server(#[from] ServerError), - #[error("Mock not found")] - MockNotFound, + #[error("Mock error: {0}")] + Mock(#[from] MockError), } #[derive(Debug, Clone, Error, PartialEq)] @@ -19,3 +19,29 @@ pub enum ServerError { #[error("Server creation error: {0}")] Creation(String), } + +#[derive(Debug, Clone, Error, PartialEq)] +pub enum MockError { + #[error("Mock not found")] + Notfound, + #[error("Mock already exists")] + AlreadyExists, + #[error("Request error: {0}")] + Request(#[from] RequestError), +} + +#[derive(Debug, Clone, Error, PartialEq)] +pub enum RequestError { + #[error("Request failed: {0}")] + Failed(String), + #[error("Invalid path, expected {0}")] + InvalidPath(String), + #[error("Invalid method, expected {0}")] + InvalidMethod(String), + #[error("Invalid query param, expected {0}")] + InvalidQuery(String), + #[error("Invalid body, expected {0}")] + InvalidBody(String), + #[error("Invalid header, expected {0}")] + InvalidHeader(String), +} diff --git a/easyhttpmock/src/expect.rs b/easyhttpmock/src/expect.rs deleted file mode 100644 index 9694713..0000000 --- a/easyhttpmock/src/expect.rs +++ /dev/null @@ -1,199 +0,0 @@ -use std::collections::HashMap; - -use http::{HeaderMap, StatusCode}; - -pub struct WhenBuilder { - path: String, - method: String, - headers: HeaderMap, - query_params: HashMap, - body: String, -} - -impl WhenBuilder { - pub fn path(mut self, path: String) -> Self { - self.path = path; - self - } - - pub fn method(mut self, method: String) -> Self { - self.method = method; - self - } - - pub fn headers(mut self, headers: HeaderMap) -> Self { - self.headers = headers; - self - } - - pub fn query_params(mut self, query_params: HashMap) -> Self { - self.query_params = query_params; - self - } - - pub fn body(mut self, body: String) -> When { - self.body = body; - When { - path: self.path, - method: self.method, - headers: self.headers, - query_params: self.query_params, - body: self.body, - errors: Vec::new(), - } - } -} - -pub struct When { - path: String, - method: String, - headers: HeaderMap, - query_params: HashMap, - body: String, - errors: Vec, -} - -impl When { - pub fn builder() -> WhenBuilder { - WhenBuilder { - path: String::new(), - method: String::new(), - headers: HeaderMap::new(), - query_params: HashMap::new(), - body: String::new(), - } - } - - pub fn path(mut self, path: String) -> Self { - if !path.eq(&self.path) { - self.errors - .push(format!("No matching path, expected {}", self.path)); - } - self - } - - pub fn method(mut self, method: String) -> Self { - if !method.eq(&self.method) { - self.errors - .push(format!("No matching method, expected {}", self.method)); - } - self - } - - pub fn query_param(mut self, key: String, value: String) -> Self { - if !self - .query_params - .contains_key(&key) - { - self.errors - .push(format!("No matching query param, expected {}", key)); - } else { - let existing_value = self - .query_params - .get(&key) - .unwrap(); - if !value.eq(existing_value) { - self.errors - .push(format!("No matching query param value, expected {}", key)); - } - } - self - } - - pub fn body(mut self, body: String) -> Self { - if !body.eq(&self.body) { - self.errors - .push(format!("No matching body, expected {}", self.body)); - } - self - } - - pub fn header(mut self, key: String, value: String) -> Self { - if !self - .headers - .contains_key(&key) - { - self.errors - .push(format!("No matching header, expected {}", key)); - } else { - let existing_value = self - .headers - .get(&key) - .unwrap(); - if !value.eq(existing_value) { - self.errors - .push(format!("No matching header value, expected {}", key)); - } - } - self - } - - pub fn headers(mut self, headers: HeaderMap) -> Self { - self.headers = headers; - self - } - - pub fn then(self) -> ThenBuilder { - ThenBuilder { - status_code: StatusCode::OK, - header: (String::new(), String::new()), - body: String::new(), - errors: Vec::new(), - } - } -} - -pub struct ThenBuilder { - status_code: StatusCode, - header: (String, String), - body: String, - errors: Vec, -} - -impl ThenBuilder { - pub fn with_status(mut self, status: StatusCode) -> Self { - self.status_code = status; - self - } - - pub fn with_header(mut self, key: String, value: String) -> Self { - self.header = (key, value); - self - } - - pub fn with_body(mut self, body: String) -> Then { - self.body = body; - - Then { - status_code: self.status_code, - header: self.header, - body: self.body, - errors: self.errors, - } - } -} - -pub struct Then { - status_code: StatusCode, - header: (String, String), - body: String, - errors: Vec, -} - -impl Then { - pub fn status_code(&self) -> StatusCode { - self.status_code - } - - pub fn header(&self) -> (String, String) { - self.header.clone() - } - - pub fn body(&self) -> String { - self.body.clone() - } - - pub fn errors(&self) -> Vec { - self.errors.clone() - } -} diff --git a/easyhttpmock/src/lib.rs b/easyhttpmock/src/lib.rs index af8fb36..7e4c11d 100644 --- a/easyhttpmock/src/lib.rs +++ b/easyhttpmock/src/lib.rs @@ -1,28 +1,37 @@ -use std::{future::Future, pin::Pin}; - use crate::{ - config::EasyHttpMockConfig, - errors::EasyHttpMockError, - expect::{Then, When}, - server::ServerAdapter, + config::EasyHttpMockConfig, errors::EasyHttpMockError, mock::Mock, server::ServerAdapter, }; pub mod config; pub mod errors; -pub mod expect; +pub mod mock; pub mod server; +#[cfg(test)] mod tests; +/// Create a mock using a specific server implementation pub struct EasyHttpMock where S: ServerAdapter, { + /// Configuration for the mock server config: EasyHttpMockConfig, + /// The actual server implementation server: S, } impl EasyHttpMock { + /// Creates a new mock with the given configuration + /// + /// # Arguments + /// + /// * `config` - The configuration for the mock server + /// + /// # Returns + /// + /// * `Result, EasyHttpMockError>` - A result indicating whether the mock was created successfully + /// pub fn new(config: EasyHttpMockConfig) -> Result, EasyHttpMockError> { let server = S::new( config @@ -33,6 +42,15 @@ impl EasyHttpMock { Ok(EasyHttpMock { config, server }) } + /// Returns the full URL for a given path + /// + /// # Arguments + /// + /// * `path` - The path to append to the base URL + /// + /// # Returns + /// + /// * `String` - The full URL for the given path pub fn url(&self, path: &str) -> String { if let Some(base_url) = &self.config.base_url { format!("{}{}", base_url, path) @@ -46,19 +64,41 @@ impl EasyHttpMock { } } + /// Returns the base URL for the mock server + /// + /// # Returns + /// + /// * `String` - The base URL for the mock server + /// pub fn base_url(&self) -> String { self.server .base_url() } - pub async fn mock(&mut self, mocker: F) -> Result<(), EasyHttpMockError> - where - F: Fn(When) -> Fut + Send + Sync + 'static, - Fut: Future> + Send + Sync + 'static, - { + /// Starts the mock server with the given mocker function + /// + /// # Arguments + /// + /// * `mocker` - A function that returns a `Mock` or an error + /// + /// # Returns + /// + /// * `Result<(), EasyHttpMockError>` - A result indicating whether the mock server started successfully + /// + /// # Examples + /// + /// ```rust,ignore + /// let mut mock = EasyHttpMock::new(EasyHttpMockConfig::builder().build()); + /// mock.mock(|| async { + /// Ok(Mock::of(Request::get("/test").build()).respond().with_status(200).build()) + /// }).await?; + /// ``` + pub fn register_mock(&mut self, mock: Mock) { self.server - .mocker(mocker); + .register_mock(mock); + } + pub async fn start(&mut self) -> Result<(), EasyHttpMockError> { self.server .start() .await @@ -70,51 +110,3 @@ impl EasyHttpMock { .await } } - -/// Type alias for boxed handler closures. -/// -/// This represents an async function that takes a `Request` and returns -/// a `Response` or an error. Handlers are the core of request processing -/// in VeTiS virtual hosts. -/// -/// # Examples -/// -/// ```rust,ignore -/// use easyhttpmock::{errors::EasyHttpMockError, expect::{When, Then}, BoxedHandlerClosure}; -/// -/// let handler: BoxedHandlerClosure = Box::new(|when: When| { -/// Box::pin(async move { -/// // Process request... -/// Ok(Then::builder() -/// .status(http::StatusCode::OK) -/// .body(http_body_util::Full::new(bytes::Bytes::from("OK")))) -/// }) -/// }); -/// ``` -pub type BoxedHandlerClosure = Box< - dyn Fn(When) -> Pin> + Send + Sync>> - + Send - + Sync, ->; - -/// Creates a handler closure from a function. -/// -/// This utility function converts any compatible async function into a -/// `BoxedHandlerClosure` that can be used with virtual hosts. -/// -/// # Arguments -/// -/// * `f` - An async function that takes a `Then` and returns a `Result` -/// -/// # Examples -/// -/// ```rust,ignore -/// -/// ``` -pub fn mock_fn(f: F) -> BoxedHandlerClosure -where - F: Fn(When) -> Fut + Send + Sync + 'static, - Fut: Future> + Send + Sync + 'static, -{ - Box::new(move |req| Box::pin(f(req))) -} diff --git a/easyhttpmock/src/mock.rs b/easyhttpmock/src/mock.rs new file mode 100644 index 0000000..2ec4602 --- /dev/null +++ b/easyhttpmock/src/mock.rs @@ -0,0 +1,369 @@ +use std::collections::HashMap; + +use bytes::Bytes; +use http::{HeaderMap, Method, StatusCode}; + +pub struct Mock { + request: Request, + count: u32, + match_request: Option, +} + +impl Mock { + #[inline] + pub fn of(request: Request) -> Self { + Self { request, count: 0, match_request: None } + } + + #[inline] + pub fn report_call(&mut self) { + self.count += 1; + } + + #[inline] + pub fn request(&self) -> &Request { + &self.request + } + + #[inline] + pub fn match_with(&mut self, request: ActualRequest) { + self.match_request = Some(request); + } +} + +pub trait StatusCodeExt { + fn respond(self) -> RespondBuilder; +} + +impl StatusCodeExt for StatusCode { + fn respond(self) -> RespondBuilder { + RespondBuilder { status_code: self, headers: HashMap::new() } + } +} + +/// Extension trait for HTTP methods to create requests. +/// Allows creating requests using method names as strings or Method enum values. +/// +/// # Examples +/// ``` compile_fail +/// use http::Method; +/// use deboa::request::MethodExt; +/// +/// // Using Method enum +/// let request = Method::GET.has(); +/// +/// // Using string +/// let request = "GET".has(); +/// ``` +pub trait MethodExt { + fn has(self) -> RequestBuilder; +} + +impl MethodExt for Method { + #[inline] + fn has(self) -> RequestBuilder { + match self { + Method::GET => Request::builder(self), + Method::POST => Request::builder(self), + Method::PUT => Request::builder(self), + Method::DELETE => Request::builder(self), + Method::PATCH => Request::builder(self), + Method::HEAD => Request::builder(self), + Method::OPTIONS => Request::builder(self), + _ => panic!("Method not supported"), + } + } +} + +impl MethodExt for &str { + #[inline] + fn has(self) -> RequestBuilder { + match self { + "GET" | "get" => Request::builder(Method::GET), + "POST" | "post" => Request::builder(Method::POST), + "PUT" | "put" => Request::builder(Method::PUT), + "DELETE" | "delete" => Request::builder(Method::DELETE), + "PATCH" | "patch" => Request::builder(Method::PATCH), + "HEAD" | "head" => Request::builder(Method::HEAD), + "OPTIONS" | "options" => Request::builder(Method::OPTIONS), + _ => panic!("Method not supported"), + } + } +} + +pub struct ActualRequestBuilder { + path: String, + method: Method, + headers: HeaderMap, + query_params: HashMap, + body: String, +} + +impl ActualRequestBuilder { + #[inline] + pub fn path(mut self, path: &str) -> Self { + self.path = path.to_string(); + self + } + + #[inline] + pub fn method(mut self, method: Method) -> Self { + self.method = method; + self + } + + #[inline] + pub fn headers(mut self, headers: HeaderMap) -> Self { + self.headers = headers; + self + } + + #[inline] + pub fn query_params(mut self, query_params: HashMap) -> Self { + self.query_params = query_params; + self + } + + #[inline] + pub fn body(mut self, body: &str) -> Self { + self.body = body.to_string(); + self + } + + #[inline] + pub fn build(self) -> ActualRequest { + ActualRequest { + path: self.path, + method: self.method, + headers: self.headers, + query_params: self.query_params, + body: self.body, + } + } +} + +pub struct ActualRequest { + path: String, + method: Method, + headers: HeaderMap, + query_params: HashMap, + body: String, +} + +impl ActualRequest { + #[inline] + pub fn builder() -> ActualRequestBuilder { + ActualRequestBuilder { + path: String::new(), + method: Method::GET, + headers: HeaderMap::new(), + query_params: HashMap::new(), + body: String::new(), + } + } + + #[inline] + pub fn path(&self) -> &str { + &self.path + } + + #[inline] + pub fn method(&self) -> &Method { + &self.method + } + + #[inline] + pub fn headers(&self) -> &HeaderMap { + &self.headers + } + + #[inline] + pub fn query_params(&self) -> &HashMap { + &self.query_params + } + + #[inline] + pub fn body(&self) -> &str { + &self.body + } +} + +pub struct RequestBuilder { + path: String, + method: Method, + headers: HeaderMap, + query_params: HashMap, + body: Bytes, +} + +impl RequestBuilder { + #[inline] + pub fn path(mut self, path: &str) -> Self { + self.path = path.to_string(); + self + } + + #[inline] + pub fn method(mut self, method: Method) -> Self { + self.method = method; + self + } + + #[inline] + pub fn headers(mut self, headers: HeaderMap) -> Self { + self.headers = headers; + self + } + + #[inline] + pub fn query_params(mut self, query_params: HashMap) -> Self { + self.query_params = query_params; + self + } + + #[inline] + pub fn body(mut self, body: &[u8]) -> Self { + self.body = Bytes::from(body.to_vec()); + self + } + + #[inline] + pub fn will_return(self, respond: Respond) -> Request { + Request { + path: self.path, + method: self.method, + headers: self.headers, + query_params: self.query_params, + body: self.body, + respond, + } + } +} + +pub struct Request { + path: String, + method: Method, + headers: HeaderMap, + query_params: HashMap, + body: Bytes, + respond: Respond, +} + +impl Request { + #[inline] + pub fn builder(method: Method) -> RequestBuilder { + RequestBuilder { + path: String::new(), + method, + headers: HeaderMap::new(), + query_params: HashMap::new(), + body: Bytes::new(), + } + } + + #[inline] + pub fn path(&self) -> &str { + &self.path + } + + #[inline] + pub fn method(&self) -> &Method { + &self.method + } + + #[inline] + pub fn query_params(&self) -> &HashMap { + &self.query_params + } + + #[inline] + pub fn body(&self) -> &Bytes { + &self.body + } + + #[inline] + pub fn headers(&self) -> &HeaderMap { + &self.headers + } + + #[inline] + pub fn respond(&self) -> &Respond { + &self.respond + } +} + +pub struct RespondBuilder { + status_code: StatusCode, + headers: HashMap, +} + +impl RespondBuilder { + #[inline] + pub fn with_status(mut self, status: StatusCode) -> Self { + self.status_code = status; + self + } + + #[inline] + pub fn with_header(mut self, key: &str, value: &str) -> Self { + self.headers + .insert(key.to_string(), value.to_string()); + self + } + + #[inline] + pub fn with_headers(mut self, entries: &[(&str, &str)]) -> Self { + for (key, value) in entries { + self.headers + .insert(key.to_string(), value.to_string()); + } + self + } + + #[inline] + pub fn empty(self) -> Respond { + self.no_body() + } + + #[inline] + pub fn no_body(self) -> Respond { + Respond { status_code: self.status_code, headers: self.headers, body: Bytes::new() } + } + + #[inline] + pub fn with_body(self, body: &[u8]) -> Respond { + Respond { + status_code: self.status_code, + headers: self.headers, + body: Bytes::from(body.to_vec()), + } + } +} + +pub struct Respond { + status_code: StatusCode, + headers: HashMap, + body: Bytes, +} + +impl Respond { + #[inline] + pub fn builder() -> RespondBuilder { + RespondBuilder { status_code: StatusCode::OK, headers: HashMap::new() } + } + + #[inline] + pub fn status_code(&self) -> StatusCode { + self.status_code + } + + #[inline] + pub fn headers(&self) -> HashMap { + self.headers.clone() + } + + #[inline] + pub fn body(&self) -> Bytes { + self.body.clone() + } +} diff --git a/easyhttpmock/src/server.rs b/easyhttpmock/src/server.rs index 078b010..39c0a16 100644 --- a/easyhttpmock/src/server.rs +++ b/easyhttpmock/src/server.rs @@ -1,9 +1,6 @@ use std::future::Future; -use crate::{ - errors::EasyHttpMockError, - expect::{Then, When}, -}; +use crate::{errors::EasyHttpMockError, mock::Mock}; /// Server adapter trait to allow different http server implementations pub trait ServerAdapter { @@ -55,10 +52,7 @@ pub trait ServerAdapter { /// /// * `Result<(), EasyHttpMockError>` - The result of the operation /// - fn mocker(&mut self, mocker: F) - where - F: Fn(When) -> Fut + Send + Sync + 'static, - Fut: Future> + Send + Sync + 'static; + fn register_mock(&mut self, mock: Mock); /// Start the server /// diff --git a/easyhttpmock/src/tests/config.rs b/easyhttpmock/src/tests/config.rs index 8b13789..665d74e 100644 --- a/easyhttpmock/src/tests/config.rs +++ b/easyhttpmock/src/tests/config.rs @@ -1 +1,31 @@ +use crate::{ + config::EasyHttpMockConfig, + tests::server::{TestServer, TestServerConfig}, +}; +#[test] +fn test_config() { + let config = EasyHttpMockConfig::::builder() + .base_url(Some("http://127.0.0.1:8080".to_string())) + .server_config(TestServerConfig::default()) + .build(); + + assert_eq!( + config + .server_config() + .port(), + 8080 + ); + assert_eq!( + config + .server_config() + .interface(), + "127.0.0.1" + ); + + assert_eq!( + config.base_url(), + &Some("http://127.0.0.1:8080".to_string()), + "base url should be http://127.0.0.1:8080" + ); +} diff --git a/easyhttpmock/src/tests/mock.rs b/easyhttpmock/src/tests/mock.rs new file mode 100644 index 0000000..7885970 --- /dev/null +++ b/easyhttpmock/src/tests/mock.rs @@ -0,0 +1,34 @@ +use std::error::Error; + +use googletest::{expect_that, gtest, prelude::eq}; +use http::{Method, StatusCode}; + +use crate::mock::{MethodExt, Mock, StatusCodeExt}; + +#[gtest] +fn test_mock_request() -> Result<(), Box> { + let mock = Mock::of( + Method::GET + .has() + .path("/test") + .will_return( + StatusCode::OK + .respond() + .with_body(b"teste"), + ), + ); + + expect_that!( + mock.request() + .method(), + eq(Method::GET) + ); + + expect_that!( + mock.request() + .path(), + eq("/test") + ); + + Ok(()) +} diff --git a/easyhttpmock/src/tests/mod.rs b/easyhttpmock/src/tests/mod.rs index 21be1b5..cd5c040 100644 --- a/easyhttpmock/src/tests/mod.rs +++ b/easyhttpmock/src/tests/mod.rs @@ -1,2 +1,3 @@ mod config; +mod mock; mod server; diff --git a/easyhttpmock/src/tests/server.rs b/easyhttpmock/src/tests/server.rs index 8b13789..72007de 100644 --- a/easyhttpmock/src/tests/server.rs +++ b/easyhttpmock/src/tests/server.rs @@ -1 +1,81 @@ +use std::error::Error; +use crate::{errors::EasyHttpMockError, mock::Mock, server::ServerAdapter, EasyHttpMock}; + +#[derive(Debug, Clone)] +pub struct TestServerConfig { + port: u32, + interface: String, +} + +impl Default for TestServerConfig { + fn default() -> Self { + Self { port: 8080, interface: "127.0.0.1".to_string() } + } +} + +impl TestServerConfig { + pub fn port(&self) -> u32 { + self.port + } + + pub fn interface(&self) -> &str { + &self.interface + } +} + +pub struct TestServer { + config: TestServerConfig, + mock: Option, +} + +impl ServerAdapter for TestServer { + type Config = TestServerConfig; + + fn new(config: Self::Config) -> Result { + Ok(Self { config, mock: None }) + } + + fn hostname(&self) -> String { + "localhost".to_string() + } + + fn base_url(&self) -> String { + format!("http://{}:{}", self.hostname(), self.config.port) + } + + fn config(&self) -> &Self::Config { + &self.config + } + + fn register_mock(&mut self, mock: Mock) { + self.mock = Some(mock); + } + + async fn start(&mut self) -> Result<(), EasyHttpMockError> { + todo!() + } + + async fn stop(&mut self) -> Result<(), EasyHttpMockError> { + todo!() + } +} + +#[test] +fn test_server() -> Result<(), Box> { + let mock_server = EasyHttpMock::::new(crate::config::EasyHttpMockConfig { + server_config: TestServerConfig { port: 8080, interface: "127.0.0.1".to_string() }, + base_url: Some("http://127.0.0.1:8080".to_string()), + })?; + + assert_eq!( + mock_server + .config + .server_config + .port, + 8080, + "server port should be 8080" + ); + + Ok(()) +} From ae76f1543a9bd50615e30d67adf1167dcbc9685a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rog=C3=A9rio=20Ara=C3=BAjo?= Date: Mon, 20 Apr 2026 13:08:18 -0300 Subject: [PATCH 14/15] docs: improved documetation --- Cargo.lock | 165 ++---------------- easyhttpmock-vetis-smol/README.md | 0 easyhttpmock-vetis-smol/src/lib.rs | 3 + easyhttpmock-vetis-smol/src/vetis_adapter.rs | 1 + easyhttpmock-vetis-tokio/README.md | 0 easyhttpmock-vetis-tokio/src/lib.rs | 3 + easyhttpmock-vetis-tokio/src/vetis_adapter.rs | 1 + easyhttpmock/README.md | 0 easyhttpmock/src/config.rs | 1 + easyhttpmock/src/errors.rs | 19 ++ easyhttpmock/src/lib.rs | 16 ++ easyhttpmock/src/mock.rs | 53 ++++++ easyhttpmock/src/server.rs | 4 + 13 files changed, 116 insertions(+), 150 deletions(-) create mode 100644 easyhttpmock-vetis-smol/README.md create mode 100644 easyhttpmock-vetis-tokio/README.md create mode 100644 easyhttpmock/README.md diff --git a/Cargo.lock b/Cargo.lock index 8e83255..4293459 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -67,17 +67,6 @@ version = "1.0.102" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f202df86484c868dbad7eaa557ef785d5c66295e41b460ef922eca0723b842c" -[[package]] -name = "async-channel" -version = "1.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81953c529336010edd6d8e358f886d9581267795c61b19475b71314bffa46d35" -dependencies = [ - "concurrent-queue", - "event-listener 2.5.3", - "futures-core", -] - [[package]] name = "async-channel" version = "2.5.0" @@ -115,21 +104,6 @@ dependencies = [ "futures-lite", ] -[[package]] -name = "async-global-executor" -version = "2.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05b1b633a2115cd122d73b955eadd9916c18c8f510ec9cd1686404c60ad1c29c" -dependencies = [ - "async-channel 2.5.0", - "async-executor", - "async-io", - "async-lock", - "blocking", - "futures-lite", - "once_cell", -] - [[package]] name = "async-io" version = "2.6.0" @@ -154,7 +128,7 @@ version = "3.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5fd03604047cee9b6ce9de9f70c6cd540a0520c813cbd49bae61f33ab80ed1dc" dependencies = [ - "event-listener 5.4.1", + "event-listener", "event-listener-strategy", "pin-project-lite", ] @@ -188,14 +162,14 @@ version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fc50921ec0055cdd8a16de48773bfeec5c972598674347252c0399676be7da75" dependencies = [ - "async-channel 2.5.0", + "async-channel", "async-io", "async-lock", "async-signal", "async-task", "blocking", "cfg-if", - "event-listener 5.4.1", + "event-listener", "futures-lite", "rustix", ] @@ -218,48 +192,6 @@ dependencies = [ "windows-sys 0.61.2", ] -[[package]] -name = "async-std" -version = "1.13.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c8e079a4ab67ae52b7403632e4618815d6db36d2a010cfe41b02c1b1578f93b" -dependencies = [ - "async-channel 1.9.0", - "async-global-executor", - "async-io", - "async-lock", - "async-process", - "crossbeam-utils", - "futures-channel", - "futures-core", - "futures-io", - "futures-lite", - "gloo-timers", - "kv-log-macro", - "log", - "memchr", - "once_cell", - "pin-project-lite", - "pin-utils", - "slab", - "wasm-bindgen-futures", -] - -[[package]] -name = "async-std-resolver" -version = "0.23.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0928198152da571a19145031360f34fc7569ef2dc387681565f330c811a5ba9b" -dependencies = [ - "async-std", - "async-trait", - "futures-io", - "futures-util", - "pin-utils", - "socket2 0.5.10", - "trust-dns-resolver", -] - [[package]] name = "async-task" version = "4.7.1" @@ -335,7 +267,7 @@ version = "1.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e83f8d02be6967315521be875afa792a316e28d57b5a2d401897e2a7921b7f21" dependencies = [ - "async-channel 2.5.0", + "async-channel", "async-task", "futures-io", "futures-lite", @@ -567,11 +499,9 @@ dependencies = [ name = "deboa-tokio" version = "0.1.0-beta.1" dependencies = [ - "async-std-resolver", "async-trait", "base64", "bytes", - "cfg-if", "cookie", "deboa", "futures", @@ -741,12 +671,6 @@ dependencies = [ "windows-sys 0.61.2", ] -[[package]] -name = "event-listener" -version = "2.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0" - [[package]] name = "event-listener" version = "5.4.1" @@ -764,7 +688,7 @@ version = "0.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8be9f3dfaaffdae2972880079a491a1a8bb7cbed0b8dd7a347f668b4150a3b93" dependencies = [ - "event-listener 5.4.1", + "event-listener", "pin-project-lite", ] @@ -984,18 +908,6 @@ dependencies = [ "wasip3", ] -[[package]] -name = "gloo-timers" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbb143cf96099802033e0d4f4963b19fd2e0b728bcf076cd9cf7f6634f092994" -dependencies = [ - "futures-channel", - "futures-core", - "js-sys", - "wasm-bindgen", -] - [[package]] name = "googletest" version = "0.14.2" @@ -1191,7 +1103,7 @@ dependencies = [ "hyper", "libc", "pin-project-lite", - "socket2 0.6.3", + "socket2", "tokio", "tower-service", "tracing", @@ -1422,21 +1334,10 @@ version = "0.3.94" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2e04e2ef80ce82e13552136fabeef8a5ed1f985a96805761cbb9a2c34e7664d9" dependencies = [ - "cfg-if", - "futures-util", "once_cell", "wasm-bindgen", ] -[[package]] -name = "kv-log-macro" -version = "1.0.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0de8b303297635ad57c9f5059fd9cee7a47f8e8daa09df0fcd07dd39fb22977f" -dependencies = [ - "log", -] - [[package]] name = "leb128fmt" version = "0.1.0" @@ -1491,9 +1392,6 @@ name = "log" version = "0.4.29" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897" -dependencies = [ - "value-bag", -] [[package]] name = "lru-cache" @@ -1595,7 +1493,7 @@ dependencies = [ "crossbeam-epoch", "crossbeam-utils", "equivalent", - "event-listener 5.4.1", + "event-listener", "futures-util", "parking_lot", "portable-atomic", @@ -1766,12 +1664,6 @@ version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd" -[[package]] -name = "pin-utils" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" - [[package]] name = "piper" version = "0.2.5" @@ -1900,7 +1792,7 @@ dependencies = [ "rustc-hash", "rustls", "smol", - "socket2 0.6.3", + "socket2", "thiserror 2.0.18", "tokio", "tracing", @@ -1938,7 +1830,7 @@ dependencies = [ "cfg_aliases", "libc", "once_cell", - "socket2 0.6.3", + "socket2", "tracing", "windows-sys 0.60.2", ] @@ -2377,7 +2269,7 @@ version = "2.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a33bd3e260892199c3ccfc487c88b2da2265080acb316cd920da72fdfd7c599f" dependencies = [ - "async-channel 2.5.0", + "async-channel", "async-executor", "async-fs", "async-io", @@ -2408,20 +2300,10 @@ dependencies = [ "async-executor", "async-io", "async-lock", - "event-listener 5.4.1", + "event-listener", "futures-lite", ] -[[package]] -name = "socket2" -version = "0.5.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e22376abed350d73dd1cd119b57ffccad95b4e585a7cda43e286245ce23c0678" -dependencies = [ - "libc", - "windows-sys 0.52.0", -] - [[package]] name = "socket2" version = "0.6.3" @@ -2705,7 +2587,7 @@ dependencies = [ "mio", "pin-project-lite", "signal-hook-registry", - "socket2 0.6.3", + "socket2", "tokio-macros", "windows-sys 0.61.2", ] @@ -2917,12 +2799,6 @@ dependencies = [ "wasm-bindgen", ] -[[package]] -name = "value-bag" -version = "1.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ba6f5989077681266825251a52748b8c1d8a4ad098cc37e440103d0ea717fc0" - [[package]] name = "vcpkg" version = "0.2.15" @@ -2954,7 +2830,7 @@ dependencies = [ "rand 0.9.2", "serde", "serde_yaml_ng", - "socket2 0.6.3", + "socket2", "thiserror 2.0.18", "time 0.3.41", "url", @@ -2995,7 +2871,7 @@ dependencies = [ "smol", "smol-hyper", "smol-macros", - "socket2 0.6.3", + "socket2", "thiserror 2.0.18", "time 0.3.41", "url", @@ -3011,7 +2887,6 @@ dependencies = [ "cfg-if", "clap", "deboa", - "deboa-tokio", "env_logger", "futures-rustls", "futures-util", @@ -3034,7 +2909,7 @@ dependencies = [ "rustls", "serde", "serde_yaml_ng", - "socket2 0.6.3", + "socket2", "thiserror 2.0.18", "time 0.3.41", "tokio", @@ -3090,16 +2965,6 @@ dependencies = [ "wasm-bindgen-shared", ] -[[package]] -name = "wasm-bindgen-futures" -version = "0.4.67" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03623de6905b7206edd0a75f69f747f134b7f0a2323392d664448bf2d3c5d87e" -dependencies = [ - "js-sys", - "wasm-bindgen", -] - [[package]] name = "wasm-bindgen-macro" version = "0.2.117" diff --git a/easyhttpmock-vetis-smol/README.md b/easyhttpmock-vetis-smol/README.md new file mode 100644 index 0000000..e69de29 diff --git a/easyhttpmock-vetis-smol/src/lib.rs b/easyhttpmock-vetis-smol/src/lib.rs index a579552..cbff270 100644 --- a/easyhttpmock-vetis-smol/src/lib.rs +++ b/easyhttpmock-vetis-smol/src/lib.rs @@ -1,3 +1,6 @@ +#![doc = include_str!("../README.md")] +#![deny(missing_docs)] +/// Vetis smol adapter module pub mod vetis_adapter; pub use easyhttpmock::*; pub use vetis_smol::Protocol; diff --git a/easyhttpmock-vetis-smol/src/vetis_adapter.rs b/easyhttpmock-vetis-smol/src/vetis_adapter.rs index f1bc138..0bfb6c7 100644 --- a/easyhttpmock-vetis-smol/src/vetis_adapter.rs +++ b/easyhttpmock-vetis-smol/src/vetis_adapter.rs @@ -246,6 +246,7 @@ impl From for ServerConfig { } } +/// Vetis adapter implementation pub struct VetisAdapter { server: Vetis, config: VetisAdapterConfig, diff --git a/easyhttpmock-vetis-tokio/README.md b/easyhttpmock-vetis-tokio/README.md new file mode 100644 index 0000000..e69de29 diff --git a/easyhttpmock-vetis-tokio/src/lib.rs b/easyhttpmock-vetis-tokio/src/lib.rs index f61b9a7..1a51e1c 100644 --- a/easyhttpmock-vetis-tokio/src/lib.rs +++ b/easyhttpmock-vetis-tokio/src/lib.rs @@ -1,3 +1,6 @@ +#![doc = include_str!("../README.md")] +#![deny(missing_docs)] +/// Vetis tokio adapter module pub mod vetis_adapter; pub use easyhttpmock::*; pub use vetis_tokio::Protocol; diff --git a/easyhttpmock-vetis-tokio/src/vetis_adapter.rs b/easyhttpmock-vetis-tokio/src/vetis_adapter.rs index 60b4f8d..bb2f8fb 100644 --- a/easyhttpmock-vetis-tokio/src/vetis_adapter.rs +++ b/easyhttpmock-vetis-tokio/src/vetis_adapter.rs @@ -246,6 +246,7 @@ impl From for ServerConfig { } } +/// Vetis adapter implementation pub struct VetisAdapter { server: Vetis, config: VetisAdapterConfig, diff --git a/easyhttpmock/README.md b/easyhttpmock/README.md new file mode 100644 index 0000000..e69de29 diff --git a/easyhttpmock/src/config.rs b/easyhttpmock/src/config.rs index c25aabc..2bfcd0b 100644 --- a/easyhttpmock/src/config.rs +++ b/easyhttpmock/src/config.rs @@ -56,6 +56,7 @@ where } } +/// EasyHttpMock server adapter configuration #[derive(Clone)] pub struct EasyHttpMockConfig where diff --git a/easyhttpmock/src/errors.rs b/easyhttpmock/src/errors.rs index 18a2627..ea21cb8 100644 --- a/easyhttpmock/src/errors.rs +++ b/easyhttpmock/src/errors.rs @@ -1,47 +1,66 @@ use thiserror::Error; +/// EasyHttpMock error types #[derive(Debug, Error)] pub enum EasyHttpMockError { + /// Server error #[error("Server error: {0}")] Server(#[from] ServerError), + /// Mock error #[error("Mock error: {0}")] Mock(#[from] MockError), } +/// Server related errors #[derive(Debug, Clone, Error, PartialEq)] pub enum ServerError { + /// Server config error #[error("Server config error: {0}")] Config(String), + /// Server start error #[error("Server start error: {0}")] Start(String), + /// Server stop error #[error("Server stop error: {0}")] Stop(String), + /// Server creation error #[error("Server creation error: {0}")] Creation(String), } +/// Mock related errors #[derive(Debug, Clone, Error, PartialEq)] pub enum MockError { + /// Mock not found #[error("Mock not found")] Notfound, #[error("Mock already exists")] + /// Mock already exists AlreadyExists, + /// Request error #[error("Request error: {0}")] Request(#[from] RequestError), } +/// Request related errors #[derive(Debug, Clone, Error, PartialEq)] pub enum RequestError { + /// Request failed #[error("Request failed: {0}")] Failed(String), + /// Invalid path #[error("Invalid path, expected {0}")] InvalidPath(String), + /// Invalid method #[error("Invalid method, expected {0}")] InvalidMethod(String), + /// Invalid query param #[error("Invalid query param, expected {0}")] InvalidQuery(String), + /// Invalid body #[error("Invalid body, expected {0}")] InvalidBody(String), + /// Invalid header #[error("Invalid header, expected {0}")] InvalidHeader(String), } diff --git a/easyhttpmock/src/lib.rs b/easyhttpmock/src/lib.rs index 7e4c11d..be0bd4f 100644 --- a/easyhttpmock/src/lib.rs +++ b/easyhttpmock/src/lib.rs @@ -1,10 +1,16 @@ +#![doc = include_str!("../README.md")] +#![deny(missing_docs)] use crate::{ config::EasyHttpMockConfig, errors::EasyHttpMockError, mock::Mock, server::ServerAdapter, }; +/// Configuration module pub mod config; +/// Error module pub mod errors; +/// Mock module pub mod mock; +/// Server module pub mod server; #[cfg(test)] @@ -98,12 +104,22 @@ impl EasyHttpMock { .register_mock(mock); } + /// Start server + /// + /// # Returns + /// + /// * `Result<(), EasyHttpMockError>` - A result indicating whether the server started successfully pub async fn start(&mut self) -> Result<(), EasyHttpMockError> { self.server .start() .await } + /// Assert that the server has stopped + /// + /// # Returns + /// + /// * `Result<(), EasyHttpMockError>` - A result indicating whether the server stopped successfully pub async fn assert(&mut self) -> Result<(), EasyHttpMockError> { self.server .stop() diff --git a/easyhttpmock/src/mock.rs b/easyhttpmock/src/mock.rs index 2ec4602..c987fd7 100644 --- a/easyhttpmock/src/mock.rs +++ b/easyhttpmock/src/mock.rs @@ -3,6 +3,7 @@ use std::collections::HashMap; use bytes::Bytes; use http::{HeaderMap, Method, StatusCode}; +/// Mock struct pub struct Mock { request: Request, count: u32, @@ -11,31 +12,38 @@ pub struct Mock { impl Mock { #[inline] + /// Create a new mock pub fn of(request: Request) -> Self { Self { request, count: 0, match_request: None } } #[inline] + /// Report a call to this mock pub fn report_call(&mut self) { self.count += 1; } #[inline] + /// Get the request that matched this mock pub fn request(&self) -> &Request { &self.request } #[inline] + /// Match this mock with an actual request pub fn match_with(&mut self, request: ActualRequest) { self.match_request = Some(request); } } +/// Extension trait for StatusCode to create responses pub trait StatusCodeExt { + /// Create a response builder with this status code fn respond(self) -> RespondBuilder; } impl StatusCodeExt for StatusCode { + /// Create a response builder with this status code fn respond(self) -> RespondBuilder { RespondBuilder { status_code: self, headers: HashMap::new() } } @@ -56,11 +64,13 @@ impl StatusCodeExt for StatusCode { /// let request = "GET".has(); /// ``` pub trait MethodExt { + /// Create a request builder with this method fn has(self) -> RequestBuilder; } impl MethodExt for Method { #[inline] + /// Create a request builder with this method fn has(self) -> RequestBuilder { match self { Method::GET => Request::builder(self), @@ -77,6 +87,7 @@ impl MethodExt for Method { impl MethodExt for &str { #[inline] + /// Create a request builder with this method fn has(self) -> RequestBuilder { match self { "GET" | "get" => Request::builder(Method::GET), @@ -91,6 +102,7 @@ impl MethodExt for &str { } } +/// Builder for creating actual HTTP requests to be matched against mocks pub struct ActualRequestBuilder { path: String, method: Method, @@ -101,36 +113,42 @@ pub struct ActualRequestBuilder { impl ActualRequestBuilder { #[inline] + /// Set the path for this request pub fn path(mut self, path: &str) -> Self { self.path = path.to_string(); self } #[inline] + /// Set the method for this request pub fn method(mut self, method: Method) -> Self { self.method = method; self } #[inline] + /// Set the headers for this request pub fn headers(mut self, headers: HeaderMap) -> Self { self.headers = headers; self } #[inline] + /// Set the query parameters for this request pub fn query_params(mut self, query_params: HashMap) -> Self { self.query_params = query_params; self } #[inline] + /// Set the body for this request pub fn body(mut self, body: &str) -> Self { self.body = body.to_string(); self } #[inline] + /// Build the actual request pub fn build(self) -> ActualRequest { ActualRequest { path: self.path, @@ -142,6 +160,7 @@ impl ActualRequestBuilder { } } +/// Represents an actual HTTP request that will be matched against mocks pub struct ActualRequest { path: String, method: Method, @@ -152,6 +171,7 @@ pub struct ActualRequest { impl ActualRequest { #[inline] + /// Create a new actual request builder pub fn builder() -> ActualRequestBuilder { ActualRequestBuilder { path: String::new(), @@ -163,31 +183,37 @@ impl ActualRequest { } #[inline] + /// Get the path pub fn path(&self) -> &str { &self.path } #[inline] + /// Get the method pub fn method(&self) -> &Method { &self.method } #[inline] + /// Get the headers pub fn headers(&self) -> &HeaderMap { &self.headers } #[inline] + /// Get the query params pub fn query_params(&self) -> &HashMap { &self.query_params } #[inline] + /// Get the body pub fn body(&self) -> &str { &self.body } } +/// Builder for creating mock requests pub struct RequestBuilder { path: String, method: Method, @@ -198,36 +224,42 @@ pub struct RequestBuilder { impl RequestBuilder { #[inline] + /// Set the path for this request pub fn path(mut self, path: &str) -> Self { self.path = path.to_string(); self } #[inline] + /// Set the method for this request pub fn method(mut self, method: Method) -> Self { self.method = method; self } #[inline] + /// Set the headers for this request pub fn headers(mut self, headers: HeaderMap) -> Self { self.headers = headers; self } #[inline] + /// Set the query parameters for this request pub fn query_params(mut self, query_params: HashMap) -> Self { self.query_params = query_params; self } #[inline] + /// Set the body for this request pub fn body(mut self, body: &[u8]) -> Self { self.body = Bytes::from(body.to_vec()); self } #[inline] + /// Set the response for this request pub fn will_return(self, respond: Respond) -> Request { Request { path: self.path, @@ -240,6 +272,7 @@ impl RequestBuilder { } } +/// Represents a mock HTTP request pub struct Request { path: String, method: Method, @@ -251,6 +284,7 @@ pub struct Request { impl Request { #[inline] + /// Create a new request builder pub fn builder(method: Method) -> RequestBuilder { RequestBuilder { path: String::new(), @@ -262,36 +296,43 @@ impl Request { } #[inline] + /// Get the path pub fn path(&self) -> &str { &self.path } #[inline] + /// Get the method pub fn method(&self) -> &Method { &self.method } #[inline] + /// Get the query params pub fn query_params(&self) -> &HashMap { &self.query_params } #[inline] + /// Get the body pub fn body(&self) -> &Bytes { &self.body } #[inline] + /// Get the headers pub fn headers(&self) -> &HeaderMap { &self.headers } #[inline] + /// Get the respond pub fn respond(&self) -> &Respond { &self.respond } } +/// Builder for what represents a response for a request pub struct RespondBuilder { status_code: StatusCode, headers: HashMap, @@ -299,12 +340,14 @@ pub struct RespondBuilder { impl RespondBuilder { #[inline] + /// Set the status code for this response pub fn with_status(mut self, status: StatusCode) -> Self { self.status_code = status; self } #[inline] + /// Set a header for this response pub fn with_header(mut self, key: &str, value: &str) -> Self { self.headers .insert(key.to_string(), value.to_string()); @@ -312,6 +355,7 @@ impl RespondBuilder { } #[inline] + /// Set multiple headers for this response pub fn with_headers(mut self, entries: &[(&str, &str)]) -> Self { for (key, value) in entries { self.headers @@ -321,16 +365,19 @@ impl RespondBuilder { } #[inline] + /// Create an empty response pub fn empty(self) -> Respond { self.no_body() } #[inline] + /// Create a response with no body pub fn no_body(self) -> Respond { Respond { status_code: self.status_code, headers: self.headers, body: Bytes::new() } } #[inline] + /// Create a response with a body pub fn with_body(self, body: &[u8]) -> Respond { Respond { status_code: self.status_code, @@ -340,6 +387,7 @@ impl RespondBuilder { } } +/// Represents how to respond for a request pub struct Respond { status_code: StatusCode, headers: HashMap, @@ -347,22 +395,27 @@ pub struct Respond { } impl Respond { + /// Initialize respond builder #[inline] + /// Initialize respond builder pub fn builder() -> RespondBuilder { RespondBuilder { status_code: StatusCode::OK, headers: HashMap::new() } } #[inline] + /// Get the status code pub fn status_code(&self) -> StatusCode { self.status_code } #[inline] + /// Get the headers pub fn headers(&self) -> HashMap { self.headers.clone() } #[inline] + /// Get the body pub fn body(&self) -> Bytes { self.body.clone() } diff --git a/easyhttpmock/src/server.rs b/easyhttpmock/src/server.rs index 39c0a16..781e357 100644 --- a/easyhttpmock/src/server.rs +++ b/easyhttpmock/src/server.rs @@ -4,6 +4,7 @@ use crate::{errors::EasyHttpMockError, mock::Mock}; /// Server adapter trait to allow different http server implementations pub trait ServerAdapter { + /// The configuration for the server adapter type Config: Clone; /// Create a new server adapter @@ -71,14 +72,17 @@ pub trait ServerAdapter { fn stop(&mut self) -> impl Future>; } +/// Port generator trait to allow different port generation strategies pub trait PortGenerator where S: ServerAdapter, S::Config: Clone, { + /// Generate a random port fn random_port() -> u16 { rand::random_range(9000..65535) } + /// Set the server to use a random port fn with_random_port(self) -> Self; } From eec2cf9f277364de31d5d8a899a5ae6439fae29d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rog=C3=A9rio=20Ara=C3=BAjo?= Date: Mon, 20 Apr 2026 19:44:22 -0300 Subject: [PATCH 15/15] refactor: moved handler_fn to vetis crate, use it via re-export --- Cargo.lock | 3 +-- easyhttpmock-vetis-smol/src/lib.rs | 2 +- easyhttpmock-vetis-smol/src/vetis_adapter.rs | 3 ++- easyhttpmock-vetis-tokio/src/vetis_adapter.rs | 3 ++- 4 files changed, 6 insertions(+), 5 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 4293459..fe04dfd 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2840,10 +2840,10 @@ dependencies = [ name = "vetis-smol" version = "0.1.0-beta.1" dependencies = [ + "async-lock", "async-native-tls", "async-signal", "bytes", - "cfg-if", "clap", "deboa", "env_logger", @@ -2884,7 +2884,6 @@ version = "0.1.0-beta.1" dependencies = [ "async-lock", "bytes", - "cfg-if", "clap", "deboa", "env_logger", diff --git a/easyhttpmock-vetis-smol/src/lib.rs b/easyhttpmock-vetis-smol/src/lib.rs index cbff270..87181e8 100644 --- a/easyhttpmock-vetis-smol/src/lib.rs +++ b/easyhttpmock-vetis-smol/src/lib.rs @@ -3,6 +3,6 @@ /// Vetis smol adapter module pub mod vetis_adapter; pub use easyhttpmock::*; -pub use vetis_smol::Protocol; +pub use vetis_smol::{handler_fn, Protocol}; #[cfg(test)] mod tests; diff --git a/easyhttpmock-vetis-smol/src/vetis_adapter.rs b/easyhttpmock-vetis-smol/src/vetis_adapter.rs index 0bfb6c7..69d6dba 100644 --- a/easyhttpmock-vetis-smol/src/vetis_adapter.rs +++ b/easyhttpmock-vetis-smol/src/vetis_adapter.rs @@ -1,8 +1,9 @@ use std::sync::{Arc, RwLock}; use vetis_smol::{ + handler_fn, http::Response, - virtual_host::{handler_fn, path::HandlerPath, VirtualHost}, + virtual_host::{path::HandlerPath, VirtualHost}, Protocol, ServerConfig, Vetis, }; diff --git a/easyhttpmock-vetis-tokio/src/vetis_adapter.rs b/easyhttpmock-vetis-tokio/src/vetis_adapter.rs index bb2f8fb..170ce45 100644 --- a/easyhttpmock-vetis-tokio/src/vetis_adapter.rs +++ b/easyhttpmock-vetis-tokio/src/vetis_adapter.rs @@ -1,8 +1,9 @@ use std::sync::{Arc, RwLock}; use vetis_tokio::{ + handler_fn, http::Response, - virtual_host::{handler_fn, path::HandlerPath, VirtualHost}, + virtual_host::{path::HandlerPath, VirtualHost}, Protocol, ServerConfig, Vetis, };