use actix_web::{http::StatusCode, test}; use serde_json::json; use sqlpage::webserver::http::main_handler; use crate::common::get_request_to; #[actix_web::test] async fn test_request_body() -> actix_web::Result<()> { let req = get_request_to("/tests/requests/request_body_test.sql") .await? .insert_header(("content-type", "text/plain")) .set_payload("Hello, world!") .to_srv_request(); let resp = main_handler(req).await?; assert_eq!(resp.status(), StatusCode::OK); let body = test::read_body(resp).await; let body_str = String::from_utf8(body.to_vec()).unwrap(); assert!( body_str.contains("Hello, world!"), "{body_str}\nexpected to contain: Hello, world!" ); // Test with form data - should return NULL let req = get_request_to("/tests/requests/request_body_test.sql") .await? .insert_header(("content-type", "application/x-www-form-urlencoded")) .set_payload("key=value") .to_srv_request(); let resp = main_handler(req).await?; assert_eq!(resp.status(), StatusCode::OK); let body = test::read_body(resp).await; let body_str = String::from_utf8(body.to_vec()).unwrap(); assert!( body_str.contains("NULL"), "{body_str}\nexpected NULL for form data" ); Ok(()) } #[actix_web::test] async fn test_request_body_base64() -> actix_web::Result<()> { let binary_data = (0u8..=255u8).collect::>(); let expected_base64 = base64::Engine::encode(&base64::engine::general_purpose::STANDARD, &binary_data); let req = get_request_to("/tests/requests/request_body_base64_test.sql") .await? .insert_header(("content-type", "application/octet-stream")) .set_payload(binary_data) .to_srv_request(); let resp = main_handler(req).await?; assert_eq!(resp.status(), StatusCode::OK); let body = test::read_body(resp).await; let body_str = String::from_utf8(body.to_vec()).unwrap(); assert!( body_str.contains(&expected_base64), "{body_str}\nexpected to contain base64: {expected_base64}" ); // Test with form data - should return NULL let req = get_request_to("/tests/requests/request_body_base64_test.sql") .await? .insert_header(("content-type", "application/x-www-form-urlencoded")) .set_payload("key=value") .to_srv_request(); let resp = main_handler(req).await?; assert_eq!(resp.status(), StatusCode::OK); let body = test::read_body(resp).await; let body_str = String::from_utf8(body.to_vec()).unwrap(); assert!( body_str.contains("NULL"), "{body_str}\nexpected NULL for form data" ); Ok(()) } #[actix_web::test] async fn test_download_data_url() -> actix_web::Result<()> { let req = get_request_to("/tests/requests/request_download_test.sql") .await? .to_srv_request(); let resp = main_handler(req).await?; assert_eq!(resp.status(), StatusCode::OK); let ct = resp.headers().get("content-type").unwrap(); assert_eq!(ct, "text/plain"); let content_disposition = resp.headers().get("content-disposition").unwrap(); assert_eq!( content_disposition, "attachment; filename=\"my text file.txt\"" ); let body = test::read_body(resp).await; assert_eq!(&body, &b"Hello download!"[..]); Ok(()) } #[actix_web::test] async fn test_large_form_field_roundtrip() -> actix_web::Result<()> { let long_string = "a".repeat(123454); let req = get_request_to("/tests/components/display_form_field.sql") .await? .insert_header(("content-type", "application/x-www-form-urlencoded")) .set_payload(["x=", &long_string].concat()) // total size is 123454 + 2 = 123456 bytes .to_srv_request(); let resp = main_handler(req).await?; assert_eq!(resp.status(), StatusCode::OK); let body = test::read_body(resp).await; let body_str = String::from_utf8(body.to_vec()).unwrap(); assert!( !body_str.contains("error"), "{body_str}\nshouldn't have errors" ); assert!( body_str.contains(&long_string), "{body_str}\nexpected to contain long string submitted" ); Ok(()) } #[actix_web::test] async fn test_variables_function() -> actix_web::Result<()> { let url = "/tests/requests/variables.sql?common=get_value&get_only=get_val"; let req_body = "common=post_value&post_only=post_val"; let req = get_request_to(url) .await? .insert_header(("content-type", "application/x-www-form-urlencoded")) .insert_header(("accept", "application/json")) .set_payload(req_body) .to_srv_request(); let resp = main_handler(req).await?; assert_eq!(resp.status(), StatusCode::OK); let body_json: serde_json::Value = test::read_body_json(resp).await; let expected = [ [ ( "all_vars", json!({"get_only": "get_val", "common": "get_value", "post_only": "post_val", "common": "post_value"}), ), ( "get_vars", json!({"get_only": "get_val", "common": "get_value"}), ), ( "post_vars", json!({"post_only": "post_val", "common": "post_value"}), ), ("set_vars", json!({})), ], [ ( "all_vars", json!({"get_only": "get_val", "common": "set_common_value", "post_only": "post_val", "my_set_var": "set_value"}), ), ( "get_vars", json!({"get_only": "get_val", "common": "get_value"}), ), ( "post_vars", json!({"post_only": "post_val", "common": "post_value"}), ), ( "set_vars", json!({"common": "set_common_value", "my_set_var": "set_value"}), ), ], ]; let actual_array = body_json.as_array().expect("response is nota json array"); for (i, expected_step) in expected.into_iter().enumerate() { let actual = &actual_array[i]; for (key, expected_value) in expected_step { let actual_decoded: serde_json::Value = serde_json::from_str(actual[key].as_str().unwrap()).unwrap(); assert_eq!( actual_decoded, expected_value, "step {i}: {key} mismatch: {actual_decoded:#} != {expected_value:#}" ) } } Ok(()) } #[actix_web::test] async fn test_invalid_utf8_multipart_text_field_returns_bad_request() -> actix_web::Result<()> { let req = get_request_to("/tests/requests/variables.sql") .await? .insert_header(("content-type", "multipart/form-data; boundary=1234567890")) .set_payload( b"--1234567890\r\n\ Content-Disposition: form-data; name=\"x\"\r\n\ Content-Type: text/plain\r\n\ \r\n\ \xff\r\n\ --1234567890--\r\n" .as_slice(), ) .to_srv_request(); let status = match main_handler(req).await { Ok(resp) => resp.status(), Err(err) => err.as_response_error().status_code(), }; assert_eq!( status, StatusCode::BAD_REQUEST, "assertion error, expected 400 bad request on invalid utf8 payload, got {}", status ); Ok(()) } #[actix_web::test] async fn test_missing_multipart_content_disposition_returns_bad_request() -> actix_web::Result<()> { let req = get_request_to("/tests/requests/variables.sql") .await? .insert_header(("content-type", "multipart/form-data; boundary=1234567890")) .set_payload( b"--1234567890\r\n\ Content-Type: text/plain\r\n\ \r\n\ hello\r\n\ --1234567890--\r\n" .as_slice(), ) .to_srv_request(); let status = match main_handler(req).await { Ok(resp) => resp.status(), Err(err) => err.as_response_error().status_code(), }; assert_eq!( status, StatusCode::BAD_REQUEST, "expected 400 bad request on malformed multipart payload, got {}", status ); Ok(()) } mod webhook_hmac;