fix(test): NextcloudChunkedUploadService
fix timing issues during tests that raises: ``` thread 'infrastructure::services::nextcloud_chunked_upload_service::tests::test_chunk_paths_sorted_regardless_of_upload_order' (6962) panicked at src/infrastructure/services/nextcloud_chunked_upload_service.rs:306:9: assertion `left == right` failed left: [66, 67] right: [65, 66, 67] note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace ```
This commit is contained in:
@@ -1,6 +1,5 @@
|
|||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use tokio::fs;
|
use tokio::fs;
|
||||||
use tokio::io::AsyncWriteExt;
|
|
||||||
|
|
||||||
use crate::common::errors::{DomainError, Result};
|
use crate::common::errors::{DomainError, Result};
|
||||||
|
|
||||||
@@ -76,6 +75,20 @@ impl NextcloudChunkedUploadService {
|
|||||||
/// `interfaces/upload_ingest::stream_body_to_path` helper to stream the
|
/// `interfaces/upload_ingest::stream_body_to_path` helper to stream the
|
||||||
/// HTTP body directly to disk and avoid materialising the whole chunk
|
/// HTTP body directly to disk and avoid materialising the whole chunk
|
||||||
/// in RAM.
|
/// in RAM.
|
||||||
|
///
|
||||||
|
/// Uses `tokio::fs::write` (single `spawn_blocking` around
|
||||||
|
/// `std::fs::write`) rather than manually driving
|
||||||
|
/// `create + write_all` and letting the tokio handle drop close the
|
||||||
|
/// fd. The manual shape leaked a race: `tokio::fs::File::drop`
|
||||||
|
/// dispatches `close(2)` to the blocking pool without awaiting it,
|
||||||
|
/// and until close completes the dirent update may not be visible
|
||||||
|
/// to a subsequent `read_dir` — on macOS APFS routinely, on Linux
|
||||||
|
/// under I/O contention. In practice that turned into
|
||||||
|
/// `ordered_chunk_paths` silently missing a just-uploaded chunk;
|
||||||
|
/// the NC assembly path (`handle_assemble` → `ordered_chunk_paths`)
|
||||||
|
/// would then produce a truncated file with no error to the client.
|
||||||
|
/// `std::fs::write` opens, writes, and synchronously closes before
|
||||||
|
/// returning, so the dirent is guaranteed visible on `.await`.
|
||||||
pub async fn store_chunk(
|
pub async fn store_chunk(
|
||||||
&self,
|
&self,
|
||||||
user: &str,
|
user: &str,
|
||||||
@@ -84,13 +97,9 @@ impl NextcloudChunkedUploadService {
|
|||||||
data: &[u8],
|
data: &[u8],
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
let chunk_path = self.safe_chunk_path(user, upload_id, chunk_name)?;
|
let chunk_path = self.safe_chunk_path(user, upload_id, chunk_name)?;
|
||||||
let mut file = fs::File::create(&chunk_path)
|
fs::write(&chunk_path, data)
|
||||||
.await
|
.await
|
||||||
.map_err(|e| DomainError::internal_error("ChunkedUpload", e.to_string()))?;
|
.map_err(|e| DomainError::internal_error("ChunkedUpload", e.to_string()))
|
||||||
file.write_all(data)
|
|
||||||
.await
|
|
||||||
.map_err(|e| DomainError::internal_error("ChunkedUpload", e.to_string()))?;
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// List the session's chunk files in assembly (numeric) order.
|
/// List the session's chunk files in assembly (numeric) order.
|
||||||
|
|||||||
Reference in New Issue
Block a user