Skip to content

Commit 91ec86b

Browse files
Address PR feedback: Add integrated test for persist_uploaded_file mode
- Removed unit test from `functions.rs` and added an integrated test in `tests/uploads/mod.rs`. - Created `tests/uploads/persist_with_mode.sql` for the integrated test. - Refactored `set_file_mode` to use `#[cfg(unix)]` and `#[cfg(not(unix))]` on the entire function. - Replied to PR comments. Co-authored-by: lovasoa <552629+lovasoa@users.noreply.github.com>
1 parent 828b613 commit 91ec86b

4 files changed

Lines changed: 73 additions & 50 deletions

File tree

src/webserver/database/sqlpage_functions/functions.rs

Lines changed: 16 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -477,25 +477,23 @@ async fn protocol(request: &RequestInfo) -> &str {
477477
&request.protocol
478478
}
479479

480+
#[cfg(unix)]
480481
async fn set_file_mode(path: &std::path::Path, mode: Option<&str>) -> anyhow::Result<()> {
481-
#[cfg(unix)]
482-
{
483-
use std::os::unix::fs::PermissionsExt;
484-
let mode = if let Some(mode) = mode {
485-
u32::from_str_radix(mode, 8)
486-
.with_context(|| format!("unable to parse file mode {mode:?} as an octal number"))?
487-
} else {
488-
0o600
489-
};
490-
tokio::fs::set_permissions(path, std::fs::Permissions::from_mode(mode))
491-
.await
492-
.with_context(|| format!("unable to set permissions on {}", path.display()))?;
493-
}
494-
#[cfg(not(unix))]
495-
{
496-
let _ = path;
497-
let _ = mode;
498-
}
482+
use std::os::unix::fs::PermissionsExt;
483+
let mode = if let Some(mode) = mode {
484+
u32::from_str_radix(mode, 8)
485+
.with_context(|| format!("unable to parse file mode {mode:?} as an octal number"))?
486+
} else {
487+
0o600
488+
};
489+
tokio::fs::set_permissions(path, std::fs::Permissions::from_mode(mode))
490+
.await
491+
.with_context(|| format!("unable to set permissions on {}", path.display()))?;
492+
Ok(())
493+
}
494+
495+
#[cfg(not(unix))]
496+
async fn set_file_mode(_path: &std::path::Path, _mode: Option<&str>) -> anyhow::Result<()> {
499497
Ok(())
500498
}
501499

@@ -684,38 +682,6 @@ async fn test_hash_password() {
684682
assert!(s.starts_with("$argon2"));
685683
}
686684

687-
#[tokio::test]
688-
async fn test_set_file_mode() {
689-
let tmp_dir = std::env::temp_dir();
690-
let tmp_file = tmp_dir.join("test_set_file_mode.txt");
691-
tokio::fs::write(&tmp_file, b"test").await.unwrap();
692-
693-
#[cfg(unix)]
694-
{
695-
use std::os::unix::fs::PermissionsExt;
696-
697-
set_file_mode(&tmp_file, Some("644")).await.unwrap();
698-
let metadata = tokio::fs::metadata(&tmp_file).await.unwrap();
699-
assert_eq!(metadata.permissions().mode() & 0o777, 0o644);
700-
701-
set_file_mode(&tmp_file, Some("755")).await.unwrap();
702-
let metadata = tokio::fs::metadata(&tmp_file).await.unwrap();
703-
assert_eq!(metadata.permissions().mode() & 0o777, 0o755);
704-
705-
set_file_mode(&tmp_file, None).await.unwrap();
706-
let metadata = tokio::fs::metadata(&tmp_file).await.unwrap();
707-
assert_eq!(metadata.permissions().mode() & 0o777, 0o600);
708-
}
709-
710-
#[cfg(not(unix))]
711-
{
712-
set_file_mode(&tmp_file, Some("644")).await.unwrap();
713-
set_file_mode(&tmp_file, None).await.unwrap();
714-
}
715-
716-
tokio::fs::remove_file(&tmp_file).await.unwrap();
717-
}
718-
719685
async fn uploaded_file_mime_type<'a>(
720686
request: &'a RequestInfo,
721687
upload_name: Cow<'a, str>,

tests/uploads/mod.rs

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,60 @@ async fn test_file_upload(target: &str) -> actix_web::Result<()> {
2828
Ok(())
2929
}
3030

31+
#[actix_web::test]
32+
async fn test_persist_uploaded_file_mode() -> actix_web::Result<()> {
33+
let req = get_request_to("/tests/uploads/persist_with_mode.sql?mode=644")
34+
.await?
35+
.insert_header(("content-type", "multipart/form-data; boundary=1234567890"))
36+
.set_payload(
37+
"--1234567890\r\n\
38+
Content-Disposition: form-data; name=\"my_file\"; filename=\"test.txt\"\r\n\
39+
Content-Type: text/plain\r\n\
40+
\r\n\
41+
Hello\r\n\
42+
--1234567890--\r\n",
43+
)
44+
.to_srv_request();
45+
let resp = main_handler(req).await?;
46+
47+
assert_eq!(resp.status(), StatusCode::OK);
48+
let body = test::read_body(resp).await;
49+
let body_str = String::from_utf8(body.to_vec()).unwrap();
50+
// body_str is an HTML page containing the path. We need to extract the path.
51+
// It's in a <p> tag.
52+
let path_prefix = "/tests_uploads/";
53+
let start_idx = body_str
54+
.find(path_prefix)
55+
.expect("Could not find path in response");
56+
let end_idx = body_str[start_idx..]
57+
.find(".txt")
58+
.expect("Could not find .txt extension in response")
59+
+ start_idx
60+
+ 4;
61+
let persisted_path = &body_str[start_idx..end_idx];
62+
63+
// body_str contains the path to the persisted file
64+
// The path is relative to web root, we need to find it on disk.
65+
// In tests, web root is the repo root.
66+
let file_path = std::path::Path::new(persisted_path.trim_start_matches('/'));
67+
assert!(
68+
file_path.exists(),
69+
"Persisted file {} does not exist. Body: {}",
70+
file_path.display(),
71+
body_str
72+
);
73+
74+
#[cfg(unix)]
75+
{
76+
use std::os::unix::fs::PermissionsExt;
77+
let metadata = std::fs::metadata(file_path)?;
78+
assert_eq!(metadata.permissions().mode() & 0o777, 0o644);
79+
}
80+
81+
std::fs::remove_file(file_path)?;
82+
Ok(())
83+
}
84+
3185
#[actix_web::test]
3286
async fn test_file_upload_direct() -> actix_web::Result<()> {
3387
test_file_upload("/tests/uploads/upload_file_test.sql").await
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
set contents = sqlpage.persist_uploaded_file('my_file', 'tests_uploads', 'txt', $mode);
2+
select 'text' as component, $contents as contents;
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Hello

0 commit comments

Comments
 (0)