fix(volume): preserve existing speed test directories - #3082
fix(volume): preserve existing speed test directories#3082OldFriendWenjianjian wants to merge 3 commits into
Conversation
WalkthroughSpeed tests now use UUID-named files, exclusive creation, and ownership tracking. Cleanup removes only files created by the test and preserves existing directories and concurrent contents. Writable-directory checks no longer create directories. ChangesSpeed-test cleanup safety
Estimated code review effort: 4 (Complex) | ~45 minutes Sequence Diagram(s)sequenceDiagram
participant SpeedTest
participant TestLocation
participant FileSystem
SpeedTest->>TestLocation: run test
TestLocation->>FileSystem: create unique file exclusively
FileSystem-->>TestLocation: write result
TestLocation->>FileSystem: remove owned file
FileSystem-->>SpeedTest: cleanup result
Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 2
🧹 Nitpick comments (2)
core/src/volume/speed.rs (2)
124-124: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winUse structured fields in the cleanup warnings.
Both
warn!calls embed the error in the message string instead of using named fields. Structured fields let log tooling filter on the failing path or error kind without parsing free text.♻️ Proposed fix for structured logging
- warn!("Failed to remove test file: {}", e); + warn!(error = %e, path = %self.test_file.display(), "Failed to remove test file");- warn!("Failed to remove test directory: {}", e); + warn!(error = %e, path = %dir.display(), "Failed to remove test directory");As per coding guidelines, "Include relevant context fields in structured logging, e.g.,
debug!(job_id = %self.id, "message")."Also applies to: 135-135
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@core/src/volume/speed.rs` at line 124, Update both cleanup warning calls around the test-file removal and cleanup paths to use structured logging fields for the error instead of interpolating it into the message; preserve the existing warning context and include the error as a named field such as error = %e.Source: Coding guidelines
69-73: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick winPreserve the primary test result if cleanup ever becomes fallible.
cleanup()always returnsOk(()): every failure branch (Line 124, Line 135) only callswarn!and continues. Given that,test_location.cleanup().await?;at Line 72 can never actually fail today, so the?is currently a no-op.This is fragile.
cleanup()'s signature promisesVolumeResult<()>, so a future change that makes it genuinely propagate aremove_file/remove_direrror is a natural evolution. If that happens, the current ordering discards the trueperform_speed_testoutcome (for example aVolumeError::Timeout) in favor of a cleanup error, becausetest_location.cleanup().await?;runs beforelet result = result?;.Restructure so a cleanup failure never shadows the primary result.
♻️ Proposed fix to prioritize the primary result
let mut test_location = TestLocation::new(&volume.mount_point, &volume.mount_type).await?; let result = perform_speed_test(&mut test_location, &config).await; - - test_location.cleanup().await?; - let result = result?; + if let Err(cleanup_err) = test_location.cleanup().await { + warn!("Failed to clean up speed test resources: {}", cleanup_err); + } + let result = result?;Also applies to: 110-141
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@core/src/volume/speed.rs` around lines 69 - 73, Update the test flow around perform_speed_test and TestLocation::cleanup so the primary test result is resolved before propagating any cleanup error: preserve and return the perform_speed_test error while still always attempting cleanup, and only propagate cleanup failure when the test itself succeeded. Apply the same ordering to the cleanup-related flow in the referenced TestLocation implementation.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@core/src/volume/speed.rs`:
- Around line 277-294: Update the cleanup in the successful branch of the
permission probe around permission_file and remove_file: inspect the removal
result and log the failure with sufficient context instead of discarding it,
while preserving the existing writable result behavior.
- Around line 459-481: Update test_concurrent_locations_use_different_files and
the shared-directory cleanup flow so concurrent cleanup cannot leave the
temporary directory behind. Serialize cleanup for locations sharing a directory,
or retry remove_dir after sibling file removal, and make the test explicitly
assert that the shared directory is removed successfully instead of relying only
on warn!.
---
Nitpick comments:
In `@core/src/volume/speed.rs`:
- Line 124: Update both cleanup warning calls around the test-file removal and
cleanup paths to use structured logging fields for the error instead of
interpolating it into the message; preserve the existing warning context and
include the error as a named field such as error = %e.
- Around line 69-73: Update the test flow around perform_speed_test and
TestLocation::cleanup so the primary test result is resolved before propagating
any cleanup error: preserve and return the perform_speed_test error while still
always attempting cleanup, and only propagate cleanup failure when the test
itself succeeded. Apply the same ordering to the cleanup-related flow in the
referenced TestLocation implementation.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro Plus
Run ID: 86ff38c8-5b84-499f-9143-66871f357de7
📒 Files selected for processing (1)
core/src/volume/speed.rs
|
Follow-up commit 75b6fc8 also addresses the two review-summary nitpicks:
Validation after the update:
|
There was a problem hiding this comment.
🧹 Nitpick comments (1)
core/src/volume/speed.rs (1)
86-128: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winExtract a shared remove-and-log helper.
cleanup()(lines 111-125) and the permission-probe removal (lines 275-287) implement the same pattern: remove a file, treatOkandNotFoundas success, andwarn!on any other error. Extract one helper to avoid divergence between the two call sites as this code evolves.♻️ Proposed refactor
+async fn remove_file_best_effort(path: &std::path::Path, context: &str) -> bool { + match tokio::fs::remove_file(path).await { + Ok(()) => true, + Err(e) if e.kind() == std::io::ErrorKind::NotFound => true, + Err(e) => { + warn!(error = %e, path = %path.display(), "Failed to remove {}", context); + false + } + } +} + /// Clean up the test file async fn cleanup(&mut self) { // Never remove a file unless this speed test successfully created it. if self.test_file_created { - match tokio::fs::remove_file(&self.test_file).await { - Ok(()) => { - self.test_file_created = false; - } - Err(e) if e.kind() == std::io::ErrorKind::NotFound => { - self.test_file_created = false; - } - Err(e) => { - warn!( - error = %e, - path = %self.test_file.display(), - "Failed to remove speed test file" - ); - } - } + if remove_file_best_effort(&self.test_file, "speed test file").await { + self.test_file_created = false; + } } }Ok(mut file) => { - let write_result = file.write_all(b"test").await; + let write_ok = file.write_all(b"test").await.is_ok(); drop(file); - let cleanup_succeeded = match tokio::fs::remove_file(&permission_file).await - { - Ok(()) => true, - Err(error) if error.kind() == std::io::ErrorKind::NotFound => true, - Err(error) => { - warn!( - error = %error, - path = %permission_file.display(), - "Failed to remove speed test permission probe" - ); - false - } - }; - write_result.is_ok() && cleanup_succeeded + write_ok + && remove_file_best_effort(&permission_file, "speed test permission probe") + .await }Also applies to: 262-296
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@core/src/volume/speed.rs` around lines 86 - 128, Extract the shared remove-and-log behavior from TestLocation::cleanup and the permission-probe removal around the permission test flow into one helper. Have the helper remove the provided path, treat successful removal and NotFound as success, and warn with the error and path for other failures; update both call sites to use it while preserving test_file_created state handling in cleanup.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Nitpick comments:
In `@core/src/volume/speed.rs`:
- Around line 86-128: Extract the shared remove-and-log behavior from
TestLocation::cleanup and the permission-probe removal around the permission
test flow into one helper. Have the helper remove the provided path, treat
successful removal and NotFound as success, and warn with the error and path for
other failures; update both call sites to use it while preserving
test_file_created state handling in cleanup.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro Plus
Run ID: d41172ff-f14e-44e7-b677-465ad702ed05
📒 Files selected for processing (1)
core/src/volume/speed.rs
|
Addressed the follow-up maintainability suggestion in f286bbf by sharing the remove/NotFound/warn behavior between final test-file cleanup and permission-probe cleanup. The probe path deliberately calls the helper before combining its result with the write result, so a failed probe write cannot short-circuit cleanup and leave the created probe file behind. Validation remains green:
|
Summary
Testing
RUSTFLAGS="--cap-lints warn" cargo test -p sd-core volume::speed::tests --lib(9 passed)RUSTFLAGS="--cap-lints warn" cargo check -p sd-core --libtmp, file collision, and concurrent-test coverageThe lint cap is needed on the current main branch because
sd-task-systemforbids a new Rust 1.99 future-deprecation warning forAtomicUsize::fetch_update.Fixes #3056