diff --git a/requirements-dev.txt b/requirements-dev.txt index 19730fdd..fcb8eed3 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -28,6 +28,7 @@ pywin32; sys_platform == 'win32' rich shortuuid tabulate +tenacity tqdm typer wheel diff --git a/tests/conftest.py b/tests/conftest.py index 76c4bad5..bf680ece 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -10,6 +10,7 @@ from google.cloud import storage as google_storage from pytest_cases import fixture, fixture_union from shortuuid import uuid +from tenacity import retry, retry_if_exception_type, stop_after_attempt, wait_fixed from cloudpathlib import AzureBlobClient, AzureBlobPath, GSClient, GSPath, S3Client, S3Path from cloudpathlib.cloudpath import implementation_registry @@ -282,9 +283,24 @@ def custom_s3_rig(request, monkeypatch, assets_dir): # idempotent and our test server on heroku only has ephemeral storage # so we need to try to create each time try: - s3.meta.client.head_bucket(Bucket=drive) + # try a few times to spin up the bucket since the heroku worker needs some time to wake up + @retry( + stop=stop_after_attempt(5), + wait=wait_fixed(2), + retry=retry_if_exception_type(botocore.exceptions.ClientError), + reraise=True, + ) + def _spin_up_bucket(): + s3.meta.client.head_bucket(Bucket=drive) + + _spin_up_bucket() except botocore.exceptions.ClientError: - s3.create_bucket(Bucket=drive) + try: + s3.create_bucket(Bucket=drive) + except botocore.exceptions.ClientError as e: + # ok if bucket already exists + if e.response["Error"]["Code"] != "BucketAlreadyOwnedByYou": + raise bucket = s3.Bucket(drive) diff --git a/tests/test_caching.py b/tests/test_caching.py index 9384aac3..2d0d0a76 100644 --- a/tests/test_caching.py +++ b/tests/test_caching.py @@ -4,6 +4,7 @@ from pathlib import Path import pytest +from tenacity import retry, retry_if_exception_type, stop_after_attempt, wait_fixed from cloudpathlib.enums import FileCacheMode from cloudpathlib.exceptions import ( @@ -501,11 +502,19 @@ def test_manual_cache_clearing(rig: CloudProviderTestRig): del cp del client - gc.collect() # force gc before asserting - sleep(0.5) # give time to delete + # in CI there can be a lag before the cleanup actually happens + @retry( + retry=retry_if_exception_type(AssertionError), + wait=wait_fixed(1), + stop=stop_after_attempt(5), + ) + def _resilient_assert(): + gc.collect() # force gc before asserting + + assert not local_cache_path.exists() + assert not client_cache_folder.exists() - assert not local_cache_path.exists() - assert not client_cache_folder.exists() + _resilient_assert() def test_reuse_cache_after_manual_cache_clear(rig: CloudProviderTestRig):