Skip to content

Commit 7f6e0b6

Browse files
committed
Extract bucket preparation logic into a reusable helper function in conftest.py
1 parent 94733b8 commit 7f6e0b6

2 files changed

Lines changed: 47 additions & 44 deletions

File tree

gcsfs/tests/conftest.py

Lines changed: 41 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -222,30 +222,14 @@ def gcs(gcs_factory, buckets_to_delete, populate_bucket):
222222
# Create the bucket if it doesn't exist, otherwise clean it.
223223
if not gcs.exists(TEST_BUCKET):
224224
gcs.mkdir(TEST_BUCKET)
225+
# By adding the bucket name to this set, we are marking it for
226+
# deletion at the end of the test session. This ensures that if
227+
# the test suite creates the bucket, it will also be responsible
228+
# for deleting it. If the bucket already existed, we assume it's
229+
# managed externally and should not be deleted by the tests.
225230
buckets_to_delete.add(TEST_BUCKET)
226-
existing_files = {}
227-
else:
228-
existing_files = (
229-
gcs.find(TEST_BUCKET, detail=True) if populate_bucket else {}
230-
)
231-
base_files = {TEST_BUCKET + "/" + k for k in allfiles.keys()}
232-
if populate_bucket:
233-
_cleanup_gcs(
234-
gcs, bucket=TEST_BUCKET, bucket_populated=True, excludes=base_files
235-
)
236-
else:
237-
_cleanup_gcs(gcs, bucket=TEST_BUCKET, bucket_populated=False)
238231

239-
if populate_bucket:
240-
files_to_pipe = {}
241-
for k, v in allfiles.items():
242-
remote_path = f"{TEST_BUCKET}/{k}"
243-
if remote_path not in existing_files or existing_files[remote_path][
244-
"size"
245-
] != len(v):
246-
files_to_pipe[remote_path] = v
247-
if files_to_pipe:
248-
gcs.pipe(files_to_pipe)
232+
_prepare_bucket(gcs, TEST_BUCKET, populate_bucket)
249233

250234
gcs.invalidate_cache()
251235
yield gcs
@@ -277,7 +261,13 @@ def factory(**kwargs):
277261
yield factory
278262

279263
for fs in created_instances:
280-
_cleanup_gcs(fs, bucket_populated=populate_bucket)
264+
base_files = {TEST_ZONAL_BUCKET + "/" + k for k in allfiles.keys()}
265+
_cleanup_gcs(
266+
fs,
267+
bucket=TEST_ZONAL_BUCKET,
268+
bucket_populated=populate_bucket,
269+
excludes=base_files,
270+
)
281271

282272

283273
@pytest.fixture
@@ -288,7 +278,13 @@ def extended_gcsfs(gcs_factory, buckets_to_delete, populate_bucket):
288278
try:
289279
yield extended_gcsfs
290280
finally:
291-
_cleanup_gcs(extended_gcsfs, bucket_populated=populate_bucket)
281+
base_files = {TEST_ZONAL_BUCKET + "/" + k for k in allfiles.keys()}
282+
_cleanup_gcs(
283+
extended_gcsfs,
284+
bucket=TEST_ZONAL_BUCKET,
285+
bucket_populated=populate_bucket,
286+
excludes=base_files,
287+
)
292288

293289

294290
def _cleanup_gcs(gcs, bucket=TEST_BUCKET, bucket_populated=True, excludes=None):
@@ -311,6 +307,26 @@ def _cleanup_gcs(gcs, bucket=TEST_BUCKET, bucket_populated=True, excludes=None):
311307
logging.warning(f"Failed to clean up GCS bucket {bucket}: {e}")
312308

313309

310+
def _prepare_bucket(gcs, bucket, populate_bucket):
311+
"""Clean bucket (excluding base files) and populate with missing/modified base files."""
312+
if populate_bucket:
313+
base_files = {bucket + "/" + k for k in allfiles.keys()}
314+
_cleanup_gcs(gcs, bucket=bucket, bucket_populated=True, excludes=base_files)
315+
316+
existing_files = gcs.find(bucket, detail=True) if populate_bucket else {}
317+
files_to_pipe = {}
318+
for k, v in allfiles.items():
319+
remote_path = f"{bucket}/{k}"
320+
if remote_path not in existing_files or existing_files[remote_path][
321+
"size"
322+
] != len(v):
323+
files_to_pipe[remote_path] = v
324+
if files_to_pipe:
325+
gcs.pipe(files_to_pipe, finalize_on_close=True)
326+
else:
327+
_cleanup_gcs(gcs, bucket=bucket, bucket_populated=False)
328+
329+
314330
@pytest.fixture(scope="session", autouse=True)
315331
def final_cleanup(gcs_factory, buckets_to_delete):
316332
"""
@@ -434,20 +450,7 @@ def _create_extended_gcsfs(gcs_factory, buckets_to_delete, populate_bucket, **kw
434450
extended_gcsfs.mkdir(TEST_BUCKET)
435451
buckets_to_delete.add(TEST_BUCKET)
436452
try:
437-
if populate_bucket:
438-
# To avoid hitting object mutation limits, only pipe files if they
439-
# don't exist or if their size has changed.
440-
existing_files = extended_gcsfs.find(TEST_ZONAL_BUCKET, detail=True)
441-
files_to_pipe = {}
442-
for k, v in allfiles.items():
443-
remote_path = f"{TEST_ZONAL_BUCKET}/{k}"
444-
if remote_path not in existing_files or existing_files[remote_path][
445-
"size"
446-
] != len(v):
447-
files_to_pipe[remote_path] = v
448-
449-
if files_to_pipe:
450-
extended_gcsfs.pipe(files_to_pipe, finalize_on_close=True)
453+
_prepare_bucket(extended_gcsfs, TEST_ZONAL_BUCKET, populate_bucket)
451454
except Exception as e:
452455
logging.warning(f"Failed to populate Zonal bucket: {e}")
453456

gcsfs/tests/test_extended_hns_gcsfs.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -259,9 +259,8 @@ def test_hns_empty_folder_rename_success(self, gcs_hns, gcs_hns_mocks):
259259
path1 = f"{TEST_HNS_BUCKET}/empty_old_dir"
260260
path2 = f"{TEST_HNS_BUCKET}/empty_new_dir"
261261

262-
gcsfs.mkdir(path1)
263-
264262
with gcs_hns_mocks(BucketType.HIERARCHICAL, gcsfs) as mocks:
263+
gcsfs.mkdir(path1)
265264
# Configure mocks for the sequence of calls
266265
mocks["info"].side_effect = [
267266
{"type": "directory", "name": path1}, # _mv check
@@ -274,7 +273,8 @@ def test_hns_empty_folder_rename_success(self, gcs_hns, gcs_hns_mocks):
274273
assert not gcsfs.exists(path1)
275274
assert gcsfs.exists(path2)
276275

277-
mocks["async_lookup_bucket_type"].assert_called_once_with(TEST_HNS_BUCKET)
276+
assert mocks["async_lookup_bucket_type"].call_count == 2
277+
mocks["async_lookup_bucket_type"].assert_called_with(TEST_HNS_BUCKET)
278278
expected_info_calls = [
279279
mock.call(path1), # from _mv
280280
mock.call(path1), # from exists(path1)
@@ -1568,9 +1568,8 @@ def test_hns_rmdir_success(self, gcs_hns, gcs_hns_mocks):
15681568
dir_name = "empty_dir"
15691569
dir_path = f"{TEST_HNS_BUCKET}/{dir_name}"
15701570

1571-
gcsfs.mkdir(f"{dir_path}/placeholder", create_parents=True)
1572-
15731571
with gcs_hns_mocks(BucketType.HIERARCHICAL, gcsfs) as mocks:
1572+
gcsfs.mkdir(f"{dir_path}/placeholder", create_parents=True)
15741573
# Configure mocks
15751574
# 1. exists(dir_path) before rmdir should succeed.
15761575
# 2. exists(dir_path) after rmdir should fail.
@@ -1583,7 +1582,8 @@ def test_hns_rmdir_success(self, gcs_hns, gcs_hns_mocks):
15831582
gcsfs.rmdir(dir_path)
15841583

15851584
assert not gcsfs.exists(dir_path)
1586-
mocks["async_lookup_bucket_type"].assert_called_once_with(TEST_HNS_BUCKET)
1585+
assert mocks["async_lookup_bucket_type"].call_count == 2
1586+
mocks["async_lookup_bucket_type"].assert_called_with(TEST_HNS_BUCKET)
15871587
expected_request = self._get_delete_folder_request(dir_path)
15881588
mocks["control_client"].delete_folder.assert_called_once_with(
15891589
request=expected_request, retry=mock.ANY, timeout=mock.ANY

0 commit comments

Comments
 (0)