d718c5a372
CI / windows_test (push) Waiting to run
CI / compile_and_lint (push) Failing after 0s
CI / docker_build (linux/amd64, -linux-amd64-duckdb, duckdb) (push) Failing after 0s
CI / docker_build (linux/arm64, -linux-arm64, minimal) (push) Failing after 2s
CI / docker_build (linux/arm64, -linux-arm64-duckdb, duckdb) (push) Failing after 1s
CI / docker_build (linux/amd64, minimal) (push) Failing after 1s
CI / test (, sqlite, sqlite::memory:) (push) Has been skipped
CI / test (mssql, mssql, mssql://root:Password123!@127.0.0.1/sqlpage) (push) Has been skipped
CI / test (mysql, mysql, mysql://root:Password123!@127.0.0.1/sqlpage) (push) Has been skipped
CI / test (oracle, oracle, Driver=Oracle 21 ODBC driver;Dbq=//127.0.0.1:1521/FREEPDB1;Uid=root;Pwd=Password123!) (push) Has been skipped
CI / test (postgres, odbc, Driver=PostgreSQL Unicode;Server=127.0.0.1;Port=5432;Database=sqlpage;UID=root;PWD=Password123!, true) (push) Has been skipped
CI / test (postgres, postgres, postgres://root:Password123!@127.0.0.1/sqlpage) (push) Has been skipped
CI / playwright (push) Has been skipped
CI / docker_build (linux/arm/v7, -linux-arm-v7, minimal) (push) Failing after 0s
CI / hurl_examples (push) Failing after 8s
deploy website / deploy_official_site (push) Failing after 1s
CI / docker_push (duckdb) (push) Waiting to run
CI / docker_push (minimal) (push) Waiting to run
CI / hurl (${{ matrix.example }}) (push) Has been skipped
223 lines
7.6 KiB
Rust
223 lines
7.6 KiB
Rust
use actix_web::{http::StatusCode, test};
|
|
use sqlpage::webserver::http::main_handler;
|
|
|
|
use crate::common::get_request_to;
|
|
|
|
async fn test_file_upload(target: &str) -> actix_web::Result<()> {
|
|
let req = get_request_to(target)
|
|
.await?
|
|
.insert_header(("content-type", "multipart/form-data; boundary=1234567890"))
|
|
.set_payload(
|
|
"--1234567890\r\n\
|
|
Content-Disposition: form-data; name=\"my_file\"; filename=\"testfile.txt\"\r\n\
|
|
Content-Type: text/plain\r\n\
|
|
\r\n\
|
|
Hello, world!\r\n\
|
|
--1234567890--\r\n",
|
|
)
|
|
.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!"
|
|
);
|
|
Ok(())
|
|
}
|
|
|
|
#[actix_web::test]
|
|
async fn test_persist_uploaded_file_mode() -> actix_web::Result<()> {
|
|
let app_data = crate::common::make_app_data().await;
|
|
let req = actix_web::test::TestRequest::get()
|
|
.uri("/tests/uploads/persist_with_mode.sql?mode=644")
|
|
.app_data(app_data.clone())
|
|
.app_data(sqlpage::webserver::http::payload_config(&app_data))
|
|
.app_data(sqlpage::webserver::http::form_config(&app_data))
|
|
.insert_header((actix_web::http::header::ACCEPT, "application/json"))
|
|
.insert_header(("content-type", "multipart/form-data; boundary=1234567890"))
|
|
.set_payload(
|
|
"--1234567890\r\n\
|
|
Content-Disposition: form-data; name=\"my_file\"; filename=\"test.txt\"\r\n\
|
|
Content-Type: text/plain\r\n\
|
|
\r\n\
|
|
Hello\r\n\
|
|
--1234567890--\r\n",
|
|
)
|
|
.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 persisted_path = body_json[0]["contents"]
|
|
.as_str()
|
|
.expect("Path not found in JSON response");
|
|
|
|
// The path is relative to web root, we need to find it on disk.
|
|
// In tests, web root is the repo root.
|
|
// We normalize the path separators to be platform-specific for the file system check.
|
|
let normalized_path = persisted_path
|
|
.replace('\\', "/")
|
|
.trim_start_matches('/')
|
|
.replace('/', std::path::MAIN_SEPARATOR_STR);
|
|
let file_path = std::path::Path::new(&normalized_path);
|
|
assert!(
|
|
file_path.exists(),
|
|
"Persisted file {} does not exist. Persisted path: {}, JSON: {}",
|
|
file_path.display(),
|
|
persisted_path,
|
|
body_json
|
|
);
|
|
let contents = std::fs::read_to_string(file_path)?;
|
|
assert_eq!(contents, "Hello");
|
|
|
|
#[cfg(unix)]
|
|
{
|
|
use std::os::unix::fs::PermissionsExt;
|
|
let metadata = std::fs::metadata(file_path)?;
|
|
assert_eq!(metadata.permissions().mode() & 0o777, 0o644);
|
|
}
|
|
|
|
std::fs::remove_file(file_path)?;
|
|
Ok(())
|
|
}
|
|
|
|
#[actix_web::test]
|
|
async fn test_file_upload_direct() -> actix_web::Result<()> {
|
|
test_file_upload("/tests/uploads/upload_file_test.sql").await
|
|
}
|
|
|
|
#[actix_web::test]
|
|
async fn test_file_upload_through_runsql() -> actix_web::Result<()> {
|
|
test_file_upload("/tests/uploads/upload_file_runsql_test.sql").await
|
|
}
|
|
|
|
#[actix_web::test]
|
|
async fn test_blank_file_upload_field() -> actix_web::Result<()> {
|
|
let req = get_request_to("/tests/uploads/upload_file_test.sql")
|
|
.await?
|
|
.insert_header(("content-type", "multipart/form-data; boundary=1234567890"))
|
|
.set_payload(
|
|
"--1234567890\r\n\
|
|
Content-Disposition: form-data; name=\"my_file\"; filename=\"\"\r\n\
|
|
Content-Type: application/octet-stream\r\n\
|
|
\r\n\
|
|
\r\n\
|
|
--1234567890--\r\n",
|
|
)
|
|
.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("No file uploaded"),
|
|
"{body_str}\nexpected to contain: No file uploaded"
|
|
);
|
|
Ok(())
|
|
}
|
|
|
|
#[actix_web::test]
|
|
async fn test_file_upload_too_large() -> actix_web::Result<()> {
|
|
let req = get_request_to("/tests/uploads/upload_file_test.sql")
|
|
.await?
|
|
.insert_header(("content-type", "multipart/form-data; boundary=1234567890"))
|
|
.set_payload(
|
|
"--1234567890\r\n\
|
|
Content-Disposition: form-data; name=\"my_file\"; filename=\"testfile.txt\"\r\n\
|
|
Content-Type: text/plain\r\n\
|
|
\r\n\
|
|
"
|
|
.to_string()
|
|
+ "a".repeat(123457).as_str()
|
|
+ "\r\n\
|
|
--1234567890--\r\n",
|
|
)
|
|
.to_srv_request();
|
|
let err_str = main_handler(req)
|
|
.await
|
|
.expect_err("Expected an error response")
|
|
.to_string();
|
|
let msg = "max file size";
|
|
assert!(
|
|
err_str.to_ascii_lowercase().contains(msg),
|
|
"{err_str}\nexpected to contain: {msg}"
|
|
);
|
|
Ok(())
|
|
}
|
|
|
|
#[actix_web::test]
|
|
async fn test_upload_file_data_url() -> actix_web::Result<()> {
|
|
let req = get_request_to("/tests/uploads/upload_file_data_url_test.sql")
|
|
.await?
|
|
.insert_header(("content-type", "multipart/form-data; boundary=1234567890"))
|
|
.set_payload(
|
|
"--1234567890\r\n\
|
|
Content-Disposition: form-data; name=\"my_file\"; filename=\"testfile.txt\"\r\n\
|
|
Content-Type: image/svg+xml\r\n\
|
|
\r\n\
|
|
<svg></svg>\r\n\
|
|
--1234567890--\r\n",
|
|
)
|
|
.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_eq!(body_str, "data:image/svg+xml;base64,PHN2Zz48L3N2Zz4=");
|
|
Ok(())
|
|
}
|
|
|
|
#[actix_web::test]
|
|
async fn test_uploaded_file_name() -> actix_web::Result<()> {
|
|
let req = get_request_to("/tests/uploads/uploaded_file_name_test.sql")
|
|
.await?
|
|
.insert_header(("content-type", "multipart/form-data; boundary=1234567890"))
|
|
.set_payload(
|
|
"--1234567890\r\n\
|
|
Content-Disposition: form-data; name=\"my_file\"; filename=\"testfile.txt\"\r\n\
|
|
Content-Type: text/plain\r\n\
|
|
\r\n\
|
|
Some plain text.\r\n\
|
|
--1234567890--\r\n",
|
|
)
|
|
.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_eq!(body_str, "testfile.txt");
|
|
Ok(())
|
|
}
|
|
|
|
#[actix_web::test]
|
|
async fn test_csv_upload() -> actix_web::Result<()> {
|
|
let req = get_request_to("/tests/uploads/upload_csv_test.sql")
|
|
.await?
|
|
.insert_header(("content-type", "multipart/form-data; boundary=1234567890"))
|
|
.set_payload(
|
|
"--1234567890\r\n\
|
|
Content-Disposition: form-data; name=\"people_file\"; filename=\"people.csv\"\r\n\
|
|
Content-Type: text/csv\r\n\
|
|
\r\n\
|
|
name,age\r\n\
|
|
Ophir,29\r\n\
|
|
Max,99\r\n\
|
|
--1234567890--\r\n",
|
|
)
|
|
.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("Ophir is 29 years old"),
|
|
"{body_str}\nexpected to contain: Ophir is 29 years old"
|
|
);
|
|
Ok(())
|
|
}
|