Skip to content

Commit

Permalink
feat: multipart testing utilities (#3288)
Browse files Browse the repository at this point in the history
  • Loading branch information
robjtede committed Feb 14, 2024
1 parent 3819767 commit 82f8ddc
Show file tree
Hide file tree
Showing 6 changed files with 287 additions and 24 deletions.
1 change: 1 addition & 0 deletions actix-multipart/CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

## Unreleased

- Add testing utilities under new module `test`.
- Minimum supported Rust version (MSRV) is now 1.72.

## 0.6.1
Expand Down
3 changes: 3 additions & 0 deletions actix-multipart/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ local-waker = "0.1"
log = "0.4"
memchr = "2.5"
mime = "0.3"
rand = "0.8"
serde = "1"
serde_json = "1"
serde_plain = "1"
Expand All @@ -46,7 +47,9 @@ actix-http = "3"
actix-multipart-rfc7578 = "0.10"
actix-rt = "2.2"
actix-test = "0.1"
actix-web = "4"
awc = "3"
futures-util = { version = "0.3.17", default-features = false, features = ["alloc"] }
multer = "3"
tokio = { version = "1.24.2", features = ["sync"] }
tokio-stream = "0.1"
51 changes: 34 additions & 17 deletions actix-multipart/src/form/json.rs
Original file line number Diff line number Diff line change
Expand Up @@ -131,14 +131,13 @@ impl Default for JsonConfig {

#[cfg(test)]
mod tests {
use std::{collections::HashMap, io::Cursor};
use std::collections::HashMap;

use actix_multipart_rfc7578::client::multipart;
use actix_web::{http::StatusCode, web, App, HttpResponse, Responder};
use bytes::Bytes;

use crate::form::{
json::{Json, JsonConfig},
tests::send_form,
MultipartForm,
};

Expand All @@ -155,6 +154,8 @@ mod tests {
HttpResponse::Ok().finish()
}

const TEST_JSON: &str = r#"{"key1": "value1", "key2": "value2"}"#;

#[actix_rt::test]
async fn test_json_without_content_type() {
let srv = actix_test::start(|| {
Expand All @@ -163,10 +164,16 @@ mod tests {
.app_data(JsonConfig::default().validate_content_type(false))
});

let mut form = multipart::Form::default();
form.add_text("json", "{\"key1\": \"value1\", \"key2\": \"value2\"}");
let response = send_form(&srv, form, "/").await;
assert_eq!(response.status(), StatusCode::OK);
let (body, headers) = crate::test::create_form_data_payload_and_headers(
"json",
None,
None,
Bytes::from_static(TEST_JSON.as_bytes()),
);
let mut req = srv.post("/");
*req.headers_mut() = headers;
let res = req.send_body(body).await.unwrap();
assert_eq!(res.status(), StatusCode::OK);
}

#[actix_rt::test]
Expand All @@ -178,17 +185,27 @@ mod tests {
});

// Deny because wrong content type
let bytes = Cursor::new("{\"key1\": \"value1\", \"key2\": \"value2\"}");
let mut form = multipart::Form::default();
form.add_reader_file_with_mime("json", bytes, "", mime::APPLICATION_OCTET_STREAM);
let response = send_form(&srv, form, "/").await;
assert_eq!(response.status(), StatusCode::BAD_REQUEST);
let (body, headers) = crate::test::create_form_data_payload_and_headers(
"json",
None,
Some(mime::APPLICATION_OCTET_STREAM),
Bytes::from_static(TEST_JSON.as_bytes()),
);
let mut req = srv.post("/");
*req.headers_mut() = headers;
let res = req.send_body(body).await.unwrap();
assert_eq!(res.status(), StatusCode::BAD_REQUEST);

// Allow because correct content type
let bytes = Cursor::new("{\"key1\": \"value1\", \"key2\": \"value2\"}");
let mut form = multipart::Form::default();
form.add_reader_file_with_mime("json", bytes, "", mime::APPLICATION_JSON);
let response = send_form(&srv, form, "/").await;
assert_eq!(response.status(), StatusCode::OK);
let (body, headers) = crate::test::create_form_data_payload_and_headers(
"json",
None,
Some(mime::APPLICATION_JSON),
Bytes::from_static(TEST_JSON.as_bytes()),
);
let mut req = srv.post("/");
*req.headers_mut() = headers;
let res = req.send_body(body).await.unwrap();
assert_eq!(res.status(), StatusCode::OK);
}
}
7 changes: 5 additions & 2 deletions actix-multipart/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,14 @@ extern crate self as actix_multipart;

mod error;
mod extractor;
mod server;

pub mod form;
mod server;
pub mod test;

pub use self::{
error::MultipartError,
server::{Field, Multipart},
test::{
create_form_data_payload_and_headers, create_form_data_payload_and_headers_with_boundary,
},
};
32 changes: 27 additions & 5 deletions actix-multipart/src/server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -863,13 +863,15 @@ mod tests {
test::TestRequest,
FromRequest,
};
use bytes::Bytes;
use bytes::{BufMut as _, Bytes};
use futures_util::{future::lazy, StreamExt as _};
use tokio::sync::mpsc;
use tokio_stream::wrappers::UnboundedReceiverStream;

use super::*;

const BOUNDARY: &str = "abbc761f78ff4d7cb7573b5a23f96ef0";

#[actix_rt::test]
async fn test_boundary() {
let headers = HeaderMap::new();
Expand Down Expand Up @@ -965,6 +967,26 @@ mod tests {
}

fn create_simple_request_with_header() -> (Bytes, HeaderMap) {
let (body, headers) = crate::test::create_form_data_payload_and_headers_with_boundary(
BOUNDARY,
"file",
Some("fn.txt".to_owned()),
Some(mime::TEXT_PLAIN_UTF_8),
Bytes::from_static(b"data"),
);

let mut buf = BytesMut::with_capacity(body.len() + 14);

// add junk before form to test pre-boundary data rejection
buf.put("testasdadsad\r\n".as_bytes());

buf.put(body);

(buf.freeze(), headers)
}

// TODO: use test utility when multi-file support is introduced
fn create_double_request_with_header() -> (Bytes, HeaderMap) {
let bytes = Bytes::from(
"testasdadsad\r\n\
--abbc761f78ff4d7cb7573b5a23f96ef0\r\n\
Expand All @@ -990,7 +1012,7 @@ mod tests {
#[actix_rt::test]
async fn test_multipart_no_end_crlf() {
let (sender, payload) = create_stream();
let (mut bytes, headers) = create_simple_request_with_header();
let (mut bytes, headers) = create_double_request_with_header();
let bytes_stripped = bytes.split_to(bytes.len()); // strip crlf

sender.send(Ok(bytes_stripped)).unwrap();
Expand All @@ -1017,7 +1039,7 @@ mod tests {
#[actix_rt::test]
async fn test_multipart() {
let (sender, payload) = create_stream();
let (bytes, headers) = create_simple_request_with_header();
let (bytes, headers) = create_double_request_with_header();

sender.send(Ok(bytes)).unwrap();

Expand Down Expand Up @@ -1080,7 +1102,7 @@ mod tests {

#[actix_rt::test]
async fn test_stream() {
let (bytes, headers) = create_simple_request_with_header();
let (bytes, headers) = create_double_request_with_header();
let payload = SlowStream::new(bytes);

let mut multipart = Multipart::new(&headers, payload);
Expand Down Expand Up @@ -1319,7 +1341,7 @@ mod tests {
#[actix_rt::test]
async fn test_drop_field_awaken_multipart() {
let (sender, payload) = create_stream();
let (bytes, headers) = create_simple_request_with_header();
let (bytes, headers) = create_double_request_with_header();
sender.send(Ok(bytes)).unwrap();
drop(sender); // eof

Expand Down

0 comments on commit 82f8ddc

Please sign in to comment.