feat(net): add basic_auth helper to MockNet
All checks were successful
Test / build (map[name:stable]) (push) Successful in 6m52s
Test / build (map[name:nightly]) (push) Successful in 5m49s
Release Please / Release-plz (push) Successful in 1m36s

chore(deps): add base64@0.22
This commit is contained in:
Paul Campbell 2024-12-01 20:58:05 +00:00
parent 3b8b260b65
commit 17dc1dbe30
3 changed files with 84 additions and 0 deletions

View file

@ -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",

View file

@ -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 {

View file

@ -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