Skip to content

Commit

Permalink
Do not expose BodyPrintLimit as a Request field
Browse files Browse the repository at this point in the history
  • Loading branch information
LukeMathWalker committed Jan 18, 2024
1 parent e7e68f0 commit df95b99
Show file tree
Hide file tree
Showing 4 changed files with 70 additions and 53 deletions.
13 changes: 9 additions & 4 deletions src/mock_server/bare_server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,9 +38,8 @@ pub(super) struct MockServerState {
impl MockServerState {
pub(super) async fn handle_request(
&mut self,
mut request: Request,
request: Request,
) -> (hyper::Response<Full<Bytes>>, Option<tokio::time::Sleep>) {
request.body_print_limit = self.body_print_limit;
// If request recording is enabled, record the incoming request
// by adding it to the `received_requests` stack
if let Some(received_requests) = &mut self.received_requests {
Expand All @@ -64,7 +63,7 @@ impl BareMockServer {
RequestRecording::Disabled => None,
};
let state = Arc::new(RwLock::new(MockServerState {
mock_set: MountedMockSet::new(),
mock_set: MountedMockSet::new(body_print_limit),
received_requests,
body_print_limit,
}));
Expand Down Expand Up @@ -157,6 +156,11 @@ impl BareMockServer {
&self.server_address
}

/// Return the body print limit of this running instance of `BareMockServer`.
pub(crate) async fn body_print_limit(&self) -> BodyPrintLimit {
self.state.read().await.body_print_limit
}

/// Return a vector with all the requests received by the `BareMockServer` since it started.
/// If no request has been served, it returns an empty vector.
///
Expand Down Expand Up @@ -296,7 +300,8 @@ impl Drop for MockGuard {
received_requests.iter().enumerate().fold(
"Received requests:\n".to_string(),
|mut message, (index, request)| {
_ = write!(message, "- Request #{}\n\t{}", index + 1, request);
_ = write!(message, "- Request #{}\n\t", index + 1,);
_ = request.print_with_limit(&mut message, state.body_print_limit);
message
},
)
Expand Down
4 changes: 3 additions & 1 deletion src/mock_server/exposed_server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -329,6 +329,7 @@ impl MockServer {
/// their expectations on their number of invocations. Panics otherwise.
pub async fn verify(&self) {
debug!("Verify mock expectations.");
let body_print_limit = self.0.body_print_limit().await;
if let VerificationOutcome::Failure(failed_verifications) = self.0.verify().await {
let received_requests_message = if let Some(received_requests) =
self.0.received_requests().await
Expand All @@ -339,7 +340,8 @@ impl MockServer {
received_requests.iter().enumerate().fold(
"Received requests:\n".to_string(),
|mut message, (index, request)| {
_ = write!(message, "- Request #{}\n\t{}", index + 1, request);
_ = write!(message, "- Request #{}\n\t", index + 1,);
_ = request.print_with_limit(&mut message, body_print_limit);
message
},
)
Expand Down
22 changes: 16 additions & 6 deletions src/mock_set.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use crate::request::BodyPrintLimit;
use crate::{
mounted_mock::MountedMock,
verification::{VerificationOutcome, VerificationReport},
Expand Down Expand Up @@ -27,6 +28,7 @@ pub(crate) struct MountedMockSet {
/// We need `generation` to know if a [`MockId`] points to an [`MountedMock`] that has been
/// removed via [`MountedMockSet::reset`].
generation: u16,
body_print_limit: BodyPrintLimit,
}

/// A `MockId` is an opaque index that uniquely identifies an [`MountedMock`] inside an [`MountedMockSet`].
Expand All @@ -42,11 +44,12 @@ pub(crate) struct MockId {
}

impl MountedMockSet {
/// Create a new instance of `MockSet`.
pub(crate) fn new() -> MountedMockSet {
/// Create a new instance of `MountedMockSet`.
pub(crate) fn new(body_print_limit: BodyPrintLimit) -> MountedMockSet {
MountedMockSet {
mocks: vec![],
generation: 0,
body_print_limit,
}
}

Expand All @@ -70,7 +73,9 @@ impl MountedMockSet {
let delay = response_template.delay().map(sleep);
(response_template.generate_response(), delay)
} else {
debug!("Got unexpected request:\n{}", request);
let mut msg = "Got unexpected request:\n".to_string();
_ = request.print_with_limit(&mut msg, self.body_print_limit);
debug!("{}", msg);
(
hyper::Response::builder()
.status(hyper::StatusCode::NOT_FOUND)
Expand Down Expand Up @@ -177,11 +182,16 @@ pub(crate) enum MountedMockState {
mod tests {
use crate::matchers::path;
use crate::mock_set::{MountedMockSet, MountedMockState};
use crate::request::BodyPrintLimit;
use crate::{Mock, ResponseTemplate};

fn test_mock_set() -> MountedMockSet {
MountedMockSet::new(BodyPrintLimit::Unlimited)
}

#[test]
fn generation_is_incremented_for_every_reset() {
let mut set = MountedMockSet::new();
let mut set = test_mock_set();
assert_eq!(set.generation, 0);

for i in 1..10 {
Expand All @@ -194,7 +204,7 @@ mod tests {
#[should_panic]
fn accessing_a_mock_id_after_a_reset_triggers_a_panic() {
// Assert
let mut set = MountedMockSet::new();
let mut set = test_mock_set();
let mock = Mock::given(path("/")).respond_with(ResponseTemplate::new(200));
let (_, mock_id) = set.register(mock);

Expand All @@ -208,7 +218,7 @@ mod tests {
#[test]
fn deactivating_a_mock_does_not_invalidate_other_ids() {
// Assert
let mut set = MountedMockSet::new();
let mut set = test_mock_set();
let first_mock = Mock::given(path("/")).respond_with(ResponseTemplate::new(200));
let second_mock = Mock::given(path("/hello")).respond_with(ResponseTemplate::new(500));
let (_, first_mock_id) = set.register(first_mock);
Expand Down
84 changes: 42 additions & 42 deletions src/request.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,12 +41,42 @@ pub struct Request {
pub method: Method,
pub headers: HeaderMap,
pub body: Vec<u8>,
pub body_print_limit: BodyPrintLimit,
}

impl fmt::Display for Request {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
writeln!(f, "{} {}", self.method, self.url)?;
impl Request {
pub fn body_json<T: DeserializeOwned>(&self) -> Result<T, serde_json::Error> {
serde_json::from_slice(&self.body)
}

pub(crate) async fn from_hyper(request: hyper::Request<hyper::body::Incoming>) -> Request {
let (parts, body) = request.into_parts();
let url = match parts.uri.authority() {
Some(_) => parts.uri.to_string(),
None => format!("http://localhost{}", parts.uri),
}
.parse()
.unwrap();

let body = body
.collect()
.await
.expect("Failed to read request body.")
.to_bytes();

Self {
url,
method: parts.method,
headers: parts.headers,
body: body.to_vec(),
}
}

pub(crate) fn print_with_limit(
&self,
mut buffer: impl fmt::Write,
body_print_limit: BodyPrintLimit,
) -> fmt::Result {
writeln!(buffer, "{} {}", self.method, self.url)?;
for name in self.headers.keys() {
let values = self
.headers
Expand All @@ -55,31 +85,31 @@ impl fmt::Display for Request {
.map(|value| String::from_utf8_lossy(value.as_bytes()))
.collect::<Vec<_>>();
let values = values.join(",");
writeln!(f, "{}: {}", name, values)?;
writeln!(buffer, "{}: {}", name, values)?;
}

match self.body_print_limit {
match body_print_limit {
BodyPrintLimit::Limited(limit) if self.body.len() > limit => {
let mut written = false;
for end_byte in limit..(limit + 4).max(self.body.len()) {
if let Ok(truncated) = std::str::from_utf8(&self.body[..end_byte]) {
written = true;
writeln!(f, "{}", truncated)?;
writeln!(buffer, "{}", truncated)?;
if end_byte < self.body.len() {
writeln!(
f,
buffer,
"We truncated the body because it was too large: {} bytes (limit: {} bytes)",
self.body.len(),
limit
)?;
writeln!(f, "Increase this limit by setting `WIREMOCK_BODY_PRINT_LIMIT`, or calling `MockServerBuilder::body_print_limit` when building your MockServer instance")?;
writeln!(buffer, "Increase this limit by setting `WIREMOCK_BODY_PRINT_LIMIT`, or calling `MockServerBuilder::body_print_limit` when building your MockServer instance")?;
}
break;
}
}
if !written {
writeln!(
f,
buffer,
"Body is likely binary (invalid utf-8) size is {} bytes",
self.body.len()
)
Expand All @@ -89,10 +119,10 @@ impl fmt::Display for Request {
}
_ => {
if let Ok(body) = std::str::from_utf8(&self.body) {
writeln!(f, "{}", body)
writeln!(buffer, "{}", body)
} else {
writeln!(
f,
buffer,
"Body is likely binary (invalid utf-8) size is {} bytes",
self.body.len()
)
Expand All @@ -101,33 +131,3 @@ impl fmt::Display for Request {
}
}
}

impl Request {
pub fn body_json<T: DeserializeOwned>(&self) -> Result<T, serde_json::Error> {
serde_json::from_slice(&self.body)
}

pub(crate) async fn from_hyper(request: hyper::Request<hyper::body::Incoming>) -> Request {
let (parts, body) = request.into_parts();
let url = match parts.uri.authority() {
Some(_) => parts.uri.to_string(),
None => format!("http://localhost{}", parts.uri),
}
.parse()
.unwrap();

let body = body
.collect()
.await
.expect("Failed to read request body.")
.to_bytes();

Self {
url,
method: parts.method,
headers: parts.headers,
body: body.to_vec(),
body_print_limit: BodyPrintLimit::Limited(BODY_PRINT_LIMIT),
}
}
}

0 comments on commit df95b99

Please sign in to comment.