1818import fsspec .core
1919from dateutil .tz import tzutc
2020
21+ import botocore
2122import s3fs .core
2223from s3fs .core import S3FileSystem
2324from s3fs .utils import ignoring , SSEParams
@@ -2888,7 +2889,14 @@ def test_exist_after_delete(s3):
28882889 assert not s3 .exists (test_dir )
28892890
28902891
2891- @pytest .mark .xfail (reason = "moto doesn't support conditional MPU" )
2892+ # condition: True if running on botocore < 1.36.0
2893+ # The below tests for exclusive writes will fail on older versions of botocore.
2894+ old_botocore = version .parse (botocore .__version__ ) < version .parse ("1.36.0" )
2895+
2896+
2897+ @pytest .mark .xfail (
2898+ reason = "moto doesn't support IfNoneMatch for MPU when object created via MPU"
2899+ )
28922900def test_pipe_exclusive_big (s3 ):
28932901 chunksize = 5 * 2 ** 20 # minimum allowed
28942902 data = b"x" * chunksize * 3
@@ -2899,17 +2907,82 @@ def test_pipe_exclusive_big(s3):
28992907 assert not s3 .list_multipart_uploads (test_bucket_name )
29002908
29012909
2902- @pytest .mark .xfail (reason = "moto doesn't support conditional MPU" )
2903- def test_put_exclusive_big (s3 , tempdir ):
2910+ @pytest .mark .xfail (
2911+ old_botocore , reason = "botocore<1.33.0 lacks IfNoneMatch support" , strict = True
2912+ )
2913+ def test_pipe_exclusive_big_after_small (s3 ):
2914+ """Test conditional MPU after creating object via put_object
2915+
2916+ This test is required because moto's implementation of IfNoneMatch for MPU
2917+ only works when the object is initially created via put_object and not via
2918+ MPU.
2919+ """
29042920 chunksize = 5 * 2 ** 20 # minimum allowed
2905- data = b"x" * chunksize * 3
2906- fn = f"{ tempdir } /afile"
2907- with open (fn , "wb" ) as f :
2908- f .write (fn )
2909- s3 .put (fn , f"{ test_bucket_name } /afile" , data , mode = "overwrite" , chunksize = chunksize )
2910- s3 .put (fn , f"{ test_bucket_name } /afile" , data , mode = "overwrite" , chunksize = chunksize )
2921+
2922+ # First, create object via put_object (small upload)
2923+ s3 .pipe (f"{ test_bucket_name } /afile" , b"small" , mode = "overwrite" )
2924+
2925+ # Now try multipart upload with mode="create" (should fail)
29112926 with pytest .raises (FileExistsError ):
2912- s3 .put (
2913- fn , f"{ test_bucket_name } /afile" , data , mode = "create" , chunksize = chunksize
2927+ s3 .pipe (
2928+ f"{ test_bucket_name } /afile" ,
2929+ b"c" * chunksize * 3 ,
2930+ mode = "create" ,
2931+ chunksize = chunksize ,
29142932 )
2933+
2934+ assert not s3 .list_multipart_uploads (test_bucket_name )
2935+
2936+
2937+ @pytest .mark .xfail (
2938+ reason = "moto doesn't support IfNoneMatch for MPU when object created via MPU"
2939+ )
2940+ def test_put_exclusive_big (s3 , tmpdir ):
2941+ chunksize = 5 * 2 ** 20 # minimum allowed
2942+ fn = f"{ tmpdir } /afile"
2943+ with open (fn , "wb" ) as f :
2944+ f .write (b"x" * chunksize * 3 )
2945+ s3 .put (fn , f"{ test_bucket_name } /afile" , mode = "overwrite" , chunksize = chunksize )
2946+ s3 .put (fn , f"{ test_bucket_name } /afile" , mode = "overwrite" , chunksize = chunksize )
2947+ with pytest .raises (FileExistsError ):
2948+ s3 .put (fn , f"{ test_bucket_name } /afile" , mode = "create" , chunksize = chunksize )
2949+ assert not s3 .list_multipart_uploads (test_bucket_name )
2950+
2951+
2952+ @pytest .mark .xfail (
2953+ old_botocore , reason = "botocore<1.33.0 lacks IfNoneMatch support" , strict = True
2954+ )
2955+ def test_put_exclusive_big_after_small (s3 , tmpdir ):
2956+ """Test conditional MPU after creating object via put_object.
2957+
2958+ This test is required because moto's implementation of IfNoneMatch for MPU
2959+ only works when the object is initially created via put_object and not via
2960+ MPU.
2961+ """
2962+ chunksize = 5 * 2 ** 20 # minimum allowed
2963+ fn = str (tmpdir .join ("afile" ))
2964+ with open (fn , "wb" ) as f :
2965+ f .write (b"x" * chunksize * 3 )
2966+
2967+ # First, create object via put_object (small upload)
2968+ s3 .pipe (f"{ test_bucket_name } /afile" , b"small" , mode = "overwrite" )
2969+
2970+ # Now try multipart upload with mode="create" (should fail)
2971+ with pytest .raises (FileExistsError ):
2972+ s3 .put (fn , f"{ test_bucket_name } /afile" , mode = "create" , chunksize = chunksize )
2973+
2974+ assert not s3 .list_multipart_uploads (test_bucket_name )
2975+
2976+
2977+ @pytest .mark .xfail (
2978+ old_botocore , reason = "botocore<1.33.0 lacks IfNoneMatch support" , strict = True
2979+ )
2980+ def test_put_exclusive_small (s3 , tmpdir ):
2981+ fn = f"{ tmpdir } /afile"
2982+ with open (fn , "wb" ) as f :
2983+ f .write (b"x" )
2984+ s3 .put (fn , f"{ test_bucket_name } /afile" , mode = "overwrite" )
2985+ s3 .put (fn , f"{ test_bucket_name } /afile" , mode = "overwrite" )
2986+ with pytest .raises (FileExistsError ):
2987+ s3 .put (fn , f"{ test_bucket_name } /afile" , mode = "create" )
29152988 assert not s3 .list_multipart_uploads (test_bucket_name )
0 commit comments