feat: re-export Method, Url, Request, Response and RequestBuilder from http, url and reqwest crates
- Closes kemitix/kxio#46 - Closes kemitix/kxio#47 - Closes kemitix/kxio#48
This commit is contained in:
parent
32ba3c00c7
commit
40a45f32da
6 changed files with 50 additions and 35 deletions
|
@ -21,7 +21,7 @@ derive_more = { version = "1.0", features = [
|
||||||
] }
|
] }
|
||||||
http = "1.1"
|
http = "1.1"
|
||||||
path-clean = "1.0"
|
path-clean = "1.0"
|
||||||
reqwest = "0.12"
|
reqwest = { version = "0.12", features = [ "json" ] }
|
||||||
url = "2.5"
|
url = "2.5"
|
||||||
tempfile = "3.10"
|
tempfile = "3.10"
|
||||||
|
|
||||||
|
|
|
@ -62,7 +62,8 @@ async fn download_and_save_to_file(
|
||||||
println!("fetching: {url}");
|
println!("fetching: {url}");
|
||||||
|
|
||||||
// Uses the network abstraction to create a perfectly normal `reqwest::ResponseBuilder`.
|
// Uses the network abstraction to create a perfectly normal `reqwest::ResponseBuilder`.
|
||||||
let request: reqwest::RequestBuilder = net.client().get(url);
|
// `kxio::net::RequestBuilder` is an alias.
|
||||||
|
let request: kxio::net::RequestBuilder = net.client().get(url);
|
||||||
|
|
||||||
// Rather than calling `.build().send()?` on the request, pass it to the `net`
|
// Rather than calling `.build().send()?` on the request, pass it to the `net`
|
||||||
// This allows the `net` to either make the network request as normal, or, if we are
|
// This allows the `net` to either make the network request as normal, or, if we are
|
||||||
|
@ -70,7 +71,8 @@ async fn download_and_save_to_file(
|
||||||
// NOTE: if the `.build().send()` is called on the `request` then that WILL result in
|
// NOTE: if the `.build().send()` is called on the `request` then that WILL result in
|
||||||
// a real network request being made, even under test conditions. Only ever use the
|
// a real network request being made, even under test conditions. Only ever use the
|
||||||
// `net.send(...)` function to keep your code testable.
|
// `net.send(...)` function to keep your code testable.
|
||||||
let response: reqwest::Response = net.send(request).await?;
|
// `kxio::net::Response` is an alias for `reqwest::Response`.
|
||||||
|
let response: kxio::net::Response = net.send(request).await?;
|
||||||
|
|
||||||
let body = response.text().await?;
|
let body = response.text().await?;
|
||||||
println!("fetched {} bytes", body.bytes().len());
|
println!("fetched {} bytes", body.bytes().len());
|
||||||
|
@ -102,6 +104,8 @@ fn delete_file(file_path: &Path, fs: &kxio::fs::FileSystem) -> kxio::Result<()>
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
|
use kxio::net::{Method, Url};
|
||||||
|
|
||||||
// This test demonstrates how to use the `kxio` to test your program.
|
// This test demonstrates how to use the `kxio` to test your program.
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn should_save_remote_body() {
|
async fn should_save_remote_body() {
|
||||||
|
@ -116,8 +120,8 @@ mod tests {
|
||||||
// declare what response should be made for a given request
|
// declare what response should be made for a given request
|
||||||
let response = mock_net.response().body("contents").expect("response body");
|
let response = mock_net.response().body("contents").expect("response body");
|
||||||
mock_net
|
mock_net
|
||||||
.on(http::Method::GET)
|
.on(Method::GET)
|
||||||
.url(url::Url::parse(url).expect("parse url"))
|
.url(Url::parse(url).expect("parse url"))
|
||||||
.respond(response);
|
.respond(response);
|
||||||
|
|
||||||
// Create a temporary directory that will be deleted with `fs` goes out of scope
|
// Create a temporary directory that will be deleted with `fs` goes out of scope
|
||||||
|
|
|
@ -21,7 +21,7 @@
|
||||||
//!
|
//!
|
||||||
//! Write your program to take a reference to [Net].
|
//! Write your program to take a reference to [Net].
|
||||||
//!
|
//!
|
||||||
//! Use the [Net::client] functionto create a [reqwest::RequestBuilder] which you should then pass to the [Net::send] method.
|
//! Use the [Net::client] functionto create a [RequestBuilder] which you should then pass to the [Net::send] method.
|
||||||
//! This is rather than building the request and calling its own `send` method, doing so would result in the network request being sent, even under-test.
|
//! This is rather than building the request and calling its own `send` method, doing so would result in the network request being sent, even under-test.
|
||||||
//!
|
//!
|
||||||
//! ```rust
|
//! ```rust
|
||||||
|
@ -62,12 +62,14 @@
|
||||||
//! let mock_net = net::mock();
|
//! let mock_net = net::mock();
|
||||||
//! ```
|
//! ```
|
||||||
//!
|
//!
|
||||||
//! Create a [reqwest::Client] using [MockNet::client()].
|
//! Create a [Client] using [MockNet::client()].
|
||||||
//!
|
//!
|
||||||
//! ```rust
|
//! ```rust
|
||||||
//! # let mock_net = kxio::net::mock();
|
//! # let mock_net = kxio::net::mock();
|
||||||
//! let client = mock_net.client();
|
//! let client = mock_net.client();
|
||||||
//! // this is the same as:
|
//! // this is the same as:
|
||||||
|
//! let client = kxio::net::Client::new();
|
||||||
|
//! // this is also the same as:
|
||||||
//! let client = reqwest::Client::new();
|
//! let client = reqwest::Client::new();
|
||||||
//! ```
|
//! ```
|
||||||
//!
|
//!
|
||||||
|
@ -77,16 +79,16 @@
|
||||||
//!
|
//!
|
||||||
//! ```rust
|
//! ```rust
|
||||||
//! use kxio::net;
|
//! use kxio::net;
|
||||||
//! use kxio::net::MatchOn;
|
//! use kxio::net::{Method, Url};
|
||||||
//!
|
//!
|
||||||
//! # #[tokio::main]
|
//! # #[tokio::main]
|
||||||
//! # async fn main() -> net::Result<()> {
|
//! # async fn main() -> net::Result<()> {
|
||||||
//! # let mock_net = net::mock();
|
//! # let mock_net = net::mock();
|
||||||
//! mock_net.on(http::Method::GET)
|
//! mock_net.on(Method::GET)
|
||||||
//! .url(url::Url::parse("https://example.com")?)
|
//! .url(Url::parse("https://example.com")?)
|
||||||
//! .respond(mock_net.response().status(200).body("")?);
|
//! .respond(mock_net.response().status(200).body("")?);
|
||||||
//! mock_net.on(http::Method::GET)
|
//! mock_net.on(Method::GET)
|
||||||
//! .url(url::Url::parse("https://example.com/foo")?)
|
//! .url(Url::parse("https://example.com/foo")?)
|
||||||
//! .respond(mock_net.response().status(500).body("Mocked response")?);
|
//! .respond(mock_net.response().status(500).body("Mocked response")?);
|
||||||
//! # mock_net.reset();
|
//! # mock_net.reset();
|
||||||
//! # Ok(())
|
//! # Ok(())
|
||||||
|
@ -151,6 +153,13 @@ pub use result::{Error, Result};
|
||||||
|
|
||||||
pub use system::{MatchOn, MockNet, Net};
|
pub use system::{MatchOn, MockNet, Net};
|
||||||
|
|
||||||
|
pub use http::Method;
|
||||||
|
pub use reqwest::Client;
|
||||||
|
pub use reqwest::Request;
|
||||||
|
pub use reqwest::RequestBuilder;
|
||||||
|
pub use reqwest::Response;
|
||||||
|
pub use url::Url;
|
||||||
|
|
||||||
/// Creates a new `Net`.
|
/// Creates a new `Net`.
|
||||||
pub const fn new() -> Net {
|
pub const fn new() -> Net {
|
||||||
Net::new()
|
Net::new()
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
//
|
//
|
||||||
use derive_more::derive::From;
|
use derive_more::derive::From;
|
||||||
|
|
||||||
|
use crate::net::Request;
|
||||||
|
|
||||||
/// The Errors that may occur within [kxio::net][crate::net].
|
/// The Errors that may occur within [kxio::net][crate::net].
|
||||||
#[derive(Debug, From, derive_more::Display)]
|
#[derive(Debug, From, derive_more::Display)]
|
||||||
pub enum Error {
|
pub enum Error {
|
||||||
|
@ -20,7 +22,7 @@ pub enum Error {
|
||||||
|
|
||||||
/// There was network request that doesn't match any that were expected
|
/// There was network request that doesn't match any that were expected
|
||||||
#[display("Unexpected request: {0}", 0.to_string())]
|
#[display("Unexpected request: {0}", 0.to_string())]
|
||||||
UnexpectedMockRequest(reqwest::Request),
|
UnexpectedMockRequest(Request),
|
||||||
|
|
||||||
/// There was an error accessing the list of expected requests.
|
/// There was an error accessing the list of expected requests.
|
||||||
RwLockLocked,
|
RwLockLocked,
|
||||||
|
|
|
@ -3,6 +3,8 @@ use std::cell::RefCell;
|
||||||
|
|
||||||
use reqwest::{Body, Client};
|
use reqwest::{Body, Client};
|
||||||
|
|
||||||
|
use crate::net::{Method, Request, RequestBuilder, Response, Url};
|
||||||
|
|
||||||
use super::{Error, Result};
|
use super::{Error, Result};
|
||||||
|
|
||||||
/// A list of planned requests and responses
|
/// A list of planned requests and responses
|
||||||
|
@ -29,10 +31,10 @@ pub enum MatchOn {
|
||||||
/// Contains a list of the criteria that a request must meet before being considered a match.
|
/// Contains a list of the criteria that a request must meet before being considered a match.
|
||||||
struct Plan {
|
struct Plan {
|
||||||
match_request: Vec<MatchRequest>,
|
match_request: Vec<MatchRequest>,
|
||||||
response: reqwest::Response,
|
response: Response,
|
||||||
}
|
}
|
||||||
impl Plan {
|
impl Plan {
|
||||||
fn matches(&self, request: &reqwest::Request) -> bool {
|
fn matches(&self, request: &Request) -> bool {
|
||||||
self.match_request.iter().all(|criteria| match criteria {
|
self.match_request.iter().all(|criteria| match criteria {
|
||||||
MatchRequest::Method(method) => request.method() == method,
|
MatchRequest::Method(method) => request.method() == method,
|
||||||
MatchRequest::Url(uri) => request.url() == uri,
|
MatchRequest::Url(uri) => request.url() == uri,
|
||||||
|
@ -72,7 +74,7 @@ impl Net {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl Net {
|
impl Net {
|
||||||
/// Helper to create a default [reqwest::Client].
|
/// Helper to create a default [Client].
|
||||||
///
|
///
|
||||||
/// # Example
|
/// # Example
|
||||||
///
|
///
|
||||||
|
@ -82,7 +84,7 @@ impl Net {
|
||||||
/// let client = net.client();
|
/// let client = net.client();
|
||||||
/// let request = client.get("https://hyper.rs");
|
/// let request = client.get("https://hyper.rs");
|
||||||
/// ```
|
/// ```
|
||||||
pub fn client(&self) -> reqwest::Client {
|
pub fn client(&self) -> Client {
|
||||||
Default::default()
|
Default::default()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -105,10 +107,7 @@ impl Net {
|
||||||
/// # Ok(())
|
/// # Ok(())
|
||||||
/// # }
|
/// # }
|
||||||
/// ```
|
/// ```
|
||||||
pub async fn send(
|
pub async fn send(&self, request: impl Into<RequestBuilder>) -> Result<Response> {
|
||||||
&self,
|
|
||||||
request: impl Into<reqwest::RequestBuilder>,
|
|
||||||
) -> Result<reqwest::Response> {
|
|
||||||
let Some(plans) = &self.plans else {
|
let Some(plans) = &self.plans else {
|
||||||
return request.into().send().await.map_err(Error::from);
|
return request.into().send().await.map_err(Error::from);
|
||||||
};
|
};
|
||||||
|
@ -148,13 +147,14 @@ impl TryFrom<Net> for MockNet {
|
||||||
/// # Example
|
/// # Example
|
||||||
///
|
///
|
||||||
/// ```rust
|
/// ```rust
|
||||||
|
/// use kxio::net::{Method, Url};
|
||||||
/// # use kxio::net::Result;
|
/// # use kxio::net::Result;
|
||||||
/// # fn run() -> Result<()> {
|
/// # fn run() -> Result<()> {
|
||||||
/// let mock_net = kxio::net::mock();
|
/// let mock_net = kxio::net::mock();
|
||||||
/// let client = mock_net.client();
|
/// let client = mock_net.client();
|
||||||
/// // define an expected requet, and the response that should be returned
|
/// // define an expected requet, and the response that should be returned
|
||||||
/// mock_net.on(http::Method::GET)
|
/// mock_net.on(Method::GET)
|
||||||
/// .url(url::Url::parse("https://hyper.rs")?)
|
/// .url(Url::parse("https://hyper.rs")?)
|
||||||
/// .respond(mock_net.response().status(200).body("Ok")?);
|
/// .respond(mock_net.response().status(200).body("Ok")?);
|
||||||
/// let net: kxio::net::Net = mock_net.into();
|
/// let net: kxio::net::Net = mock_net.into();
|
||||||
/// // use 'net' in your program, by passing it as a reference
|
/// // use 'net' in your program, by passing it as a reference
|
||||||
|
@ -170,7 +170,7 @@ pub struct MockNet {
|
||||||
plans: RefCell<Plans>,
|
plans: RefCell<Plans>,
|
||||||
}
|
}
|
||||||
impl MockNet {
|
impl MockNet {
|
||||||
/// Helper to create a default [reqwest::Client].
|
/// Helper to create a default [Client].
|
||||||
///
|
///
|
||||||
/// # Example
|
/// # Example
|
||||||
///
|
///
|
||||||
|
@ -188,17 +188,18 @@ impl MockNet {
|
||||||
/// # Example
|
/// # Example
|
||||||
///
|
///
|
||||||
/// ```rust
|
/// ```rust
|
||||||
|
/// use kxio::net::{Method, Url};
|
||||||
/// # use kxio::net::Result;
|
/// # use kxio::net::Result;
|
||||||
/// # fn run() -> Result<()> {
|
/// # fn run() -> Result<()> {
|
||||||
/// let mock_net = kxio::net::mock();
|
/// let mock_net = kxio::net::mock();
|
||||||
/// let client = mock_net.client();
|
/// let client = mock_net.client();
|
||||||
/// mock_net.on(http::Method::GET)
|
/// mock_net.on(Method::GET)
|
||||||
/// .url(url::Url::parse("https://hyper.rs")?)
|
/// .url(Url::parse("https://hyper.rs")?)
|
||||||
/// .respond(mock_net.response().status(200).body("Ok")?);
|
/// .respond(mock_net.response().status(200).body("Ok")?);
|
||||||
/// # Ok(())
|
/// # Ok(())
|
||||||
/// # }
|
/// # }
|
||||||
/// ```
|
/// ```
|
||||||
pub fn on(&self, method: impl Into<http::Method>) -> WhenRequest {
|
pub fn on(&self, method: impl Into<Method>) -> WhenRequest {
|
||||||
WhenRequest::new(self, method)
|
WhenRequest::new(self, method)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -256,8 +257,8 @@ impl Drop for Net {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub enum MatchRequest {
|
pub enum MatchRequest {
|
||||||
Method(http::Method),
|
Method(Method),
|
||||||
Url(reqwest::Url),
|
Url(Url),
|
||||||
Header { name: String, value: String },
|
Header { name: String, value: String },
|
||||||
Body(String),
|
Body(String),
|
||||||
}
|
}
|
||||||
|
@ -268,7 +269,7 @@ pub struct WhenRequest<'net> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'net> WhenRequest<'net> {
|
impl<'net> WhenRequest<'net> {
|
||||||
pub fn url(mut self, url: impl Into<reqwest::Url>) -> Self {
|
pub fn url(mut self, url: impl Into<Url>) -> Self {
|
||||||
self.match_on.push(MatchRequest::Url(url.into()));
|
self.match_on.push(MatchRequest::Url(url.into()));
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
@ -293,7 +294,7 @@ impl<'net> WhenRequest<'net> {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
fn new(net: &'net MockNet, method: impl Into<http::Method>) -> Self {
|
fn new(net: &'net MockNet, method: impl Into<Method>) -> Self {
|
||||||
Self {
|
Self {
|
||||||
net,
|
net,
|
||||||
match_on: vec![MatchRequest::Method(method.into())],
|
match_on: vec![MatchRequest::Method(method.into())],
|
||||||
|
|
|
@ -1,8 +1,7 @@
|
||||||
use assert2::let_assert;
|
|
||||||
use http::Method;
|
|
||||||
//
|
//
|
||||||
use kxio::net::{Error, MockNet, Net};
|
use kxio::net::{Error, Method, MockNet, Net, Url};
|
||||||
use reqwest::Url;
|
|
||||||
|
use assert2::let_assert;
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn test_get_url() {
|
async fn test_get_url() {
|
||||||
|
|
Loading…
Reference in a new issue