feat(net): add basic_auth helper to MockNet
chore(deps): add base64@0.22
This commit is contained in:
parent
3b8b260b65
commit
17dc1dbe30
3 changed files with 84 additions and 0 deletions
|
@ -14,6 +14,7 @@ unexpected_cfgs = { level = "warn", check-cfg = ['cfg(tarpaulin_include)'] }
|
|||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
base64 = "0.22"
|
||||
bytes = "1.8"
|
||||
derive_more = { version = "1.0", features = [
|
||||
"constructor",
|
||||
|
|
|
@ -440,6 +440,17 @@ impl<'net> ReqBuilder<'net> {
|
|||
self.header(http::header::USER_AGENT.to_string(), user_agent)
|
||||
}
|
||||
|
||||
/// Enable HTTP basic authentication.
|
||||
#[must_use]
|
||||
pub fn basic_auth(
|
||||
self,
|
||||
username: impl Into<String>,
|
||||
password: Option<impl Into<String>>,
|
||||
) -> Self {
|
||||
let value = basic_auth_header_value(username, password);
|
||||
self.header(http::header::AUTHORIZATION.to_string(), value)
|
||||
}
|
||||
|
||||
/// Add query parameter
|
||||
#[must_use]
|
||||
pub fn query(mut self, key: impl Into<String>, value: impl Into<String>) -> Self {
|
||||
|
@ -448,6 +459,30 @@ impl<'net> ReqBuilder<'net> {
|
|||
}
|
||||
}
|
||||
|
||||
fn basic_auth_header_value(
|
||||
username: impl Into<String>,
|
||||
password: Option<impl Into<String>>,
|
||||
) -> String {
|
||||
let username = username.into();
|
||||
let password = password.map(|p| p.into());
|
||||
let value = {
|
||||
use base64::prelude::BASE64_STANDARD;
|
||||
use base64::write::EncoderWriter;
|
||||
use std::io::Write;
|
||||
|
||||
let mut buf = b"Basic ".to_vec();
|
||||
{
|
||||
let mut encoder = EncoderWriter::new(&mut buf, &BASE64_STANDARD);
|
||||
let _ = write!(encoder, "{username}:");
|
||||
if let Some(password) = password {
|
||||
let _ = write!(encoder, "{password}");
|
||||
}
|
||||
}
|
||||
String::from_utf8(buf).expect("should always be valid utf8")
|
||||
};
|
||||
value
|
||||
}
|
||||
|
||||
/// A struct for defining the expected requests and their responses that should be made
|
||||
/// during a test.
|
||||
///
|
||||
|
@ -762,6 +797,17 @@ impl<'net> WhenRequest<'net, WhenBuildRequest> {
|
|||
self
|
||||
}
|
||||
|
||||
/// Specifies basic authentication the mock will match against.
|
||||
#[must_use]
|
||||
pub fn basic_auth(
|
||||
self,
|
||||
username: impl Into<String>,
|
||||
password: Option<impl Into<String>>,
|
||||
) -> Self {
|
||||
let value = basic_auth_header_value(username, password);
|
||||
self.header(http::header::AUTHORIZATION.to_string(), value)
|
||||
}
|
||||
|
||||
/// Specifies user agent the mock will match against.
|
||||
#[must_use]
|
||||
pub fn user_agent(self, agent: impl Into<String>) -> Self {
|
||||
|
|
37
tests/net.rs
37
tests/net.rs
|
@ -532,6 +532,43 @@ async fn test_get_with_duplicate_query_keys() {
|
|||
);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_get_with_basic_auth() {
|
||||
//given
|
||||
let mock_net = kxio::net::mock();
|
||||
let url = "https://www.example.com/path";
|
||||
|
||||
mock_net
|
||||
.on()
|
||||
.get(url)
|
||||
.basic_auth("bob", Some("secret"))
|
||||
.respond(StatusCode::OK)
|
||||
.mock()
|
||||
.expect("mock");
|
||||
mock_net
|
||||
.on()
|
||||
.get(url)
|
||||
.basic_auth("bob", None::<String>)
|
||||
.respond(StatusCode::FORBIDDEN)
|
||||
.mock()
|
||||
.expect("mock");
|
||||
let net = Net::from(mock_net);
|
||||
|
||||
//when
|
||||
let invalid = net.get(url).basic_auth("bob", None::<String>).send().await;
|
||||
let valid = net
|
||||
.get(url)
|
||||
.basic_auth("bob", Some("secret"))
|
||||
.send()
|
||||
.await
|
||||
.expect("valid response");
|
||||
|
||||
//then
|
||||
let_assert!(Err(Error::ResponseError { response }) = invalid);
|
||||
assert_eq!(response.status(), StatusCode::FORBIDDEN);
|
||||
assert_eq!(valid.status(), StatusCode::OK);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_get_with_user_agent() {
|
||||
//given
|
||||
|
|
Loading…
Add table
Reference in a new issue