This is an automated email from the ASF dual-hosted git repository.

xuanwo pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/opendal.git


The following commit(s) were added to refs/heads/main by this push:
     new d56962971 feat: Return hinted error for S3 wildcard if-none-match 
(#5506)
d56962971 is described below

commit d569629719980cf4c3e2ecb08823e0678f2f1300
Author: Marko Grujic <[email protected]>
AuthorDate: Sat Jan 4 04:47:11 2025 +0100

    feat: Return hinted error for S3 wildcard if-none-match (#5506)
---
 core/src/layers/correctness_check.rs | 57 +++++++++++++++++++++++++++++-------
 1 file changed, 46 insertions(+), 11 deletions(-)

diff --git a/core/src/layers/correctness_check.rs 
b/core/src/layers/correctness_check.rs
index b3a08f897..61d0669a3 100644
--- a/core/src/layers/correctness_check.rs
+++ b/core/src/layers/correctness_check.rs
@@ -122,12 +122,16 @@ impl<A: Access> LayeredAccess for CorrectnessAccessor<A> {
                 "if_not_exists",
             ));
         }
-        if args.if_none_match().is_some() && 
!capability.write_with_if_none_match {
-            return Err(new_unsupported_error(
-                self.info.as_ref(),
-                Operation::Write,
-                "if_none_match",
-            ));
+        if let Some(if_none_match) = args.if_none_match() {
+            if !capability.write_with_if_none_match {
+                let mut err =
+                    new_unsupported_error(self.info.as_ref(), 
Operation::Write, "if_none_match");
+                if if_none_match == "*" && capability.write_with_if_not_exists 
{
+                    err = err.with_context("hint", "use if_not_exists 
instead");
+                }
+
+                return Err(err);
+            }
         }
 
         self.inner.write(path, args).await
@@ -304,7 +308,7 @@ mod tests {
         }
 
         async fn write(&self, _: &str, _: OpWrite) -> Result<(RpWrite, 
Self::Writer)> {
-            Ok((RpWrite::new(), Box::new(())))
+            Ok((RpWrite::new(), Box::new(MockWriter)))
         }
 
         async fn list(&self, _: &str, _: OpList) -> Result<(RpList, 
Self::Lister)> {
@@ -316,6 +320,22 @@ mod tests {
         }
     }
 
+    struct MockWriter;
+
+    impl oio::Write for MockWriter {
+        async fn write(&mut self, _: Buffer) -> Result<()> {
+            Ok(())
+        }
+
+        async fn close(&mut self) -> Result<()> {
+            Ok(())
+        }
+
+        async fn abort(&mut self) -> Result<()> {
+            Ok(())
+        }
+    }
+
     struct MockDeleter;
 
     impl oio::Delete for MockDeleter {
@@ -376,6 +396,7 @@ mod tests {
     async fn test_write_with() {
         let op = new_test_operator(Capability {
             write: true,
+            write_with_if_not_exists: true,
             ..Default::default()
         });
         let res = op.write_with("path", "".as_bytes()).append(true).await;
@@ -384,17 +405,31 @@ mod tests {
 
         let res = op
             .write_with("path", "".as_bytes())
-            .if_not_exists(true)
+            .if_none_match("etag")
             .await;
         assert!(res.is_err());
-        assert_eq!(res.unwrap_err().kind(), ErrorKind::Unsupported);
+        assert_eq!(
+            res.unwrap_err().to_string(),
+            "Unsupported (permanent) at write => service memory doesn't 
support operation write with args if_none_match"
+        );
 
+        // Now try a wildcard if-none-match
         let res = op
             .write_with("path", "".as_bytes())
-            .if_none_match("etag")
+            .if_none_match("*")
             .await;
         assert!(res.is_err());
-        assert_eq!(res.unwrap_err().kind(), ErrorKind::Unsupported);
+        assert_eq!(
+            res.unwrap_err().to_string(),
+            "Unsupported (permanent) at write, context: { hint: use 
if_not_exists instead } => \
+            service memory doesn't support operation write with args 
if_none_match"
+        );
+
+        let res = op
+            .write_with("path", "".as_bytes())
+            .if_not_exists(true)
+            .await;
+        assert!(res.is_ok());
 
         let op = new_test_operator(Capability {
             write: true,

Reply via email to