-
Notifications
You must be signed in to change notification settings - Fork 933
Add context to get_toml_path() error #5207
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
Instead of an error like: ``` Permission denied (os error 13) ``` Gives error like: ``` Failed to get metadata for config file "/root/.rustfmt.toml": Permission denied (os error 13) ```
I avoided changing the signature of Alternative approaches would be using a custom error enum (like thiserror) or I leave it to the maintainers to decide what is preferred. |
Thanks for submitting this PR! The changes look good to me. I'm wondering if there's a way that we could write a test for the new error message. Any thoughts? |
I considered writing a test, but I couldn't think of a way to test this in a portable way without overhauling more of the code. We could just hope that a directory like We could also make the |
I think portability is something we should strive for, but in this case I think it might be more practical to have platform specific implementations for these tests. Even if we only had a unix test (gated by Maybe we could create a temporary directory or file and then give ownership to root using something like nix::unistd::chown and then try to call rustfmt with |
This wouldn't work. You can't set the owner to root if you are not root. If you could, then a user could accidentally change the owner of a directory to root but not be able to recover. Example with shell commands:
We essentially need a directory owned by root (or another user) that we don't have permissions to list. It would be fragile to assume Of course, there's no guarantee that the root user's home directory are such that we cannot list the contents. Instead of Due to these problems, I don't think it's worth writing a test. I could try to code some heuristics to exit the test early if the prerequisites are not there, but that seems fragile. If I don't test for the prerequisites correctly, the test could fail unexpectedly. It could seem like the requirements are met, but they are not and the |
This is what a test could look like. I personally think adding this test is not worth the complexity/maintainability. diff --git a/src/config/mod.rs b/src/config/mod.rs
index 5041e1e3..dea534ad 100644
--- a/src/config/mod.rs
+++ b/src/config/mod.rs
@@ -25,6 +25,8 @@ pub(crate) mod file_lines;
pub(crate) mod license;
pub(crate) mod lists;
+const FAIL_METADATA_FOR_CONFIG_FILE: &str = "Failed to get metadata for config file";
+
// This macro defines configuration options used in rustfmt. Each option
// is defined as follows:
//
@@ -364,7 +366,7 @@ fn get_toml_path(dir: &Path) -> Result<Option<PathBuf>, Error> {
// find the project file yet, and continue searching.
Err(e) => {
if e.kind() != ErrorKind::NotFound {
- let ctx = format!("Failed to get metadata for config file {:?}", &config_file);
+ let ctx = format!("{} {:?}", FAIL_METADATA_FOR_CONFIG_FILE, &config_file);
let err = anyhow::Error::new(e).context(ctx);
return Err(Error::new(ErrorKind::Other, err));
}
@@ -663,6 +665,41 @@ make_backup = false
assert_eq!(config.unstable_features(), true);
}
+ #[cfg(target_os = "linux")]
+ #[test]
+ fn test_fail_access_config_dir() {
+ fn is_unlistable_directory<P: AsRef<Path>>(path: &P) -> bool {
+ let metadata = match fs::metadata(path) {
+ Err(err) => return err.kind() == ErrorKind::PermissionDenied,
+ Ok(metadata) => metadata,
+ };
+ if !metadata.is_dir() {
+ return false;
+ }
+ let mut child_path = path.as_ref().to_path_buf();
+ child_path.push("a");
+
+ // listing a child path should give us a permission error
+ match fs::metadata(child_path) {
+ Ok(_) => false,
+ Err(err) => err.kind() == ErrorKind::PermissionDenied,
+ }
+ }
+
+ let possible_root_dirs = ["/root", "/home/root", "/var/home/root"];
+ let root_dir = possible_root_dirs
+ .into_iter()
+ .find(is_unlistable_directory)
+ .expect("Unable to find root-owned, non-listable dir on this system; fix test");
+ let root_dir: PathBuf = root_dir
+ .parse()
+ .expect("Failed to convert dir path to PathBuf");
+
+ let err = get_toml_path(&root_dir).expect_err("Listing root-owned directory should fail");
+ let err_str = format!("{:#}", err);
+ assert!(err_str.contains(FAIL_METADATA_FOR_CONFIG_FILE))
+ }
+
#[cfg(test)]
mod deprecated_option_merge_imports {
use super::*;
|
@tmfink I really appreciate your detailed explanation on all this. I don't do too much work on Linux day to day so that was very informative. I also appreciate you taking the time to come up with a test, even though as you mention it might not be reliable when run on all machines. I think given your explanation and the complexity of setting up the test It's probably okay if we move forward on this without the test in place. @calebcartwright I'd also really like your opinion on this as well. |
Haven't had a chance to look at this yet (promise to do so soon) but wanted to add that I don't view a test as necessary for being able to move ahead. Wouldn't hate having a test for things like error messages one day, but feel like it'd be more appropriate to test that specific piece via unit tests with appropriate mocks/stubs on the actual fs touch points. However, we're not really setup for that level of unit testing and I don't think the gymnastics that would be required to generate the message via more of an integration or functional style test are worth it |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Much better, thank you!
Handles #5188
Before Change
After Change