@@ -2005,7 +2005,55 @@ def test_mv_file_raises_error_for_specific_generation(gcs):
20052005
20062006
20072007@pytest .mark .asyncio
2008- async def test_info_parallel (gcs ):
2008+ @pytest .mark .parametrize (
2009+ "object_behavior, dir_behavior, expected" ,
2010+ [
2011+ (
2012+ {"return" : {"name" : TEST_BUCKET + "/file" , "type" : "file" , "size" : 100 }},
2013+ {"exception" : FileNotFoundError },
2014+ {"return" : {"type" : "file" }},
2015+ ),
2016+ (
2017+ {"exception" : FileNotFoundError },
2018+ {"return" : {"name" : TEST_BUCKET + "/file" , "type" : "directory" , "size" : 0 }},
2019+ {"return" : {"type" : "directory" }},
2020+ ),
2021+ (
2022+ {
2023+ "return" : {
2024+ "name" : TEST_BUCKET + "/file/" ,
2025+ "type" : "directory" ,
2026+ "size" : 0 ,
2027+ }
2028+ },
2029+ {
2030+ "return" : {
2031+ "name" : TEST_BUCKET + "/file" ,
2032+ "type" : "directory" ,
2033+ "size" : 0 ,
2034+ "extra" : "info" ,
2035+ }
2036+ },
2037+ {"return" : {"type" : "directory" , "extra" : "info" }},
2038+ ),
2039+ (
2040+ {"exception" : Exception ("Generic error" )},
2041+ {"exception" : FileNotFoundError },
2042+ {"exception" : Exception , "match" : "Generic error" },
2043+ ),
2044+ (
2045+ {"exception" : FileNotFoundError },
2046+ {"exception" : Exception ("Directory error" )},
2047+ {"exception" : Exception , "match" : "Directory error" },
2048+ ),
2049+ (
2050+ {"exception" : FileNotFoundError },
2051+ {"exception" : FileNotFoundError },
2052+ {"exception" : FileNotFoundError },
2053+ ),
2054+ ],
2055+ )
2056+ async def test_info_parallel (gcs , object_behavior , dir_behavior , expected ):
20092057 path = TEST_BUCKET + "/file"
20102058
20112059 with (
@@ -2017,77 +2065,26 @@ async def test_info_parallel(gcs):
20172065 ) as mock_get_dir ,
20182066 ):
20192067
2020- # Case 1: File exists. _get_object succeeds, _get_directory_info fails.
2021- mock_get_object .return_value = {"name" : path , "type" : "file" , "size" : 100 }
2022- mock_get_dir .side_effect = FileNotFoundError
2068+ if "return" in object_behavior :
2069+ mock_get_object .return_value = object_behavior ["return" ]
2070+ elif "exception" in object_behavior :
2071+ mock_get_object .side_effect = object_behavior ["exception" ]
20232072
2024- res = await gcs . _info ( path )
2025- assert res [ "type" ] == "file"
2026- assert mock_get_object . call_count == 1
2027- assert mock_get_dir .call_count == 1
2073+ if "return" in dir_behavior :
2074+ mock_get_dir . return_value = dir_behavior [ "return" ]
2075+ elif "exception" in dir_behavior :
2076+ mock_get_dir .side_effect = dir_behavior [ "exception" ]
20282077
2029- # Case 2: Directory. _get_object fails, _get_directory_info succeeds.
2030- mock_get_object .reset_mock ()
2031- mock_get_dir .reset_mock ()
2032- mock_get_object .side_effect = FileNotFoundError
2033- mock_get_dir .side_effect = None
2034- mock_get_dir .return_value = {"name" : path , "type" : "directory" , "size" : 0 }
2035-
2036- res = await gcs ._info (path )
2037- assert res ["type" ] == "directory"
2038- assert mock_get_object .call_count == 1
2039- assert mock_get_dir .call_count == 1
2040-
2041- # Case 3: Directory marker. _get_object returns marker, _get_directory_info returns dir info.
2042- mock_get_object .reset_mock ()
2043- mock_get_dir .reset_mock ()
2044- mock_get_object .side_effect = None
2045- # A directory marker has size 0 and ends with /
2046- marker_path = path + "/"
2047- mock_get_object .return_value = {
2048- "name" : marker_path ,
2049- "type" : "directory" ,
2050- "size" : 0 ,
2051- }
2052- mock_get_dir .return_value = {
2053- "name" : path ,
2054- "type" : "directory" ,
2055- "size" : 0 ,
2056- "extra" : "info" ,
2057- }
2058-
2059- res = await gcs ._info (path )
2060- # Should prefer directory info over marker
2061- assert res ["extra" ] == "info"
2062- assert mock_get_object .call_count == 1
2063- assert mock_get_dir .call_count == 1
2064-
2065- # Case 4: _get_object raises generic exception. Should raise immediately.
2066- mock_get_object .reset_mock ()
2067- mock_get_dir .reset_mock ()
2068- mock_get_object .side_effect = Exception ("Generic error" )
2069- mock_get_dir .side_effect = FileNotFoundError
2070-
2071- with pytest .raises (Exception , match = "Generic error" ):
2072- await gcs ._info (path )
2073-
2074- # Case 5: _get_object fails with FileNotFoundError, _get_directory_info raises generic exception.
2075- mock_get_object .reset_mock ()
2076- mock_get_dir .reset_mock ()
2077- mock_get_object .side_effect = FileNotFoundError
2078- mock_get_dir .side_effect = Exception ("Directory error" )
2079-
2080- with pytest .raises (Exception , match = "Directory error" ):
2081- await gcs ._info (path )
2082-
2083- # Case 6: Both fail with FileNotFoundError. Should raise FileNotFoundError.
2084- mock_get_object .reset_mock ()
2085- mock_get_dir .reset_mock ()
2086- mock_get_object .side_effect = FileNotFoundError
2087- mock_get_dir .side_effect = FileNotFoundError
2078+ if "exception" in expected :
2079+ with pytest .raises (expected ["exception" ], match = expected .get ("match" )):
2080+ await gcs ._info (path )
2081+ else :
2082+ res = await gcs ._info (path )
2083+ for k , v in expected ["return" ].items ():
2084+ assert res [k ] == v
20882085
2089- with pytest . raises ( FileNotFoundError ):
2090- await gcs . _info ( path )
2086+ assert mock_get_object . call_count == 1
2087+ assert mock_get_dir . call_count == 1
20912088
20922089
20932090@pytest .mark .asyncio
0 commit comments