summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJordan Cook <jordan.cook@pioneer.com>2021-04-22 00:02:08 -0500
committerJordan Cook <jordan.cook@pioneer.com>2021-04-22 00:21:49 -0500
commit3ec85f0107caedbe3b3bd8080bd3dac81b7baa17 (patch)
treefb617be7c7760390b7239899e6522d865956342f
parentb1070a950e0365085b7edf8ef2e4a65c77630ac9 (diff)
downloadrequests-cache-3ec85f0107caedbe3b3bd8080bd3dac81b7baa17.tar.gz
Turn multi-threaded stress tests into test (sub)classes
This is mainly to take advantage of fail-fast connection tests; otherwise, these tests may just hang if backend dependenices are installed but backend services are not set up. See issue #221 for details.
-rw-r--r--tests/integration/test_backends.py55
-rw-r--r--tests/integration/test_dynamodb.py9
-rw-r--r--tests/integration/test_filesystem.py9
-rw-r--r--tests/integration/test_gridfs.py8
-rw-r--r--tests/integration/test_mongodb.py8
-rw-r--r--tests/integration/test_redis.py6
-rw-r--r--tests/integration/test_sqlite.py20
-rw-r--r--tests/integration/test_thread_safety.py35
8 files changed, 100 insertions, 50 deletions
diff --git a/tests/integration/test_backends.py b/tests/integration/test_backends.py
index 13f5424..9849a6b 100644
--- a/tests/integration/test_backends.py
+++ b/tests/integration/test_backends.py
@@ -1,8 +1,11 @@
import pytest
+from threading import Thread
+from time import time
from typing import Dict, Type
-from requests_cache.backends.base import BaseStorage
-from tests.conftest import CACHE_NAME
+from requests_cache.backends.base import BaseCache, BaseStorage
+from requests_cache.session import CachedSession
+from tests.conftest import CACHE_NAME, N_ITERATIONS, N_THREADS, httpbin
class BaseStorageTest:
@@ -109,7 +112,55 @@ class BaseStorageTest:
cache_2['key_2'] = 2
assert cache_1 == cache_2
+ def test_str(self):
+ """Not much to test for __str__ methods, just make sure they return keys in some format"""
+ cache = self.init_cache()
+ for i in range(10):
+ cache[f'key_{i}'] = f'value_{i}'
+ for i in range(10):
+ assert f'key_{i}' in str(cache)
+
class Picklable:
attr_1 = 'value_1'
attr_2 = 'value_2'
+
+
+class BaseCacheTest:
+ """Base class for testing cache backend classes"""
+
+ backend_class: Type[BaseCache] = None
+ init_kwargs: Dict = {}
+
+ def init_backend(self, clear=True, **kwargs):
+ kwargs['suppress_warnings'] = True
+ backend = self.backend_class(CACHE_NAME, **self.init_kwargs, **kwargs)
+ if clear:
+ backend.redirects.clear()
+ backend.responses.clear()
+ return backend
+
+ @pytest.mark.parametrize('iteration', range(N_ITERATIONS))
+ def test_caching_with_threads(self, iteration):
+ """Run a multi-threaded stress test for each backend"""
+ start = time()
+ session = CachedSession(backend=self.init_backend())
+ url = httpbin('anything')
+
+ def send_requests():
+ for i in range(N_ITERATIONS):
+ session.get(url, params={f'key_{i}': f'value_{i}'})
+
+ threads = [Thread(target=send_requests) for i in range(N_THREADS)]
+ for t in threads:
+ t.start()
+ for t in threads:
+ t.join()
+
+ elapsed = time() - start
+ average = (elapsed * 1000) / (N_ITERATIONS * N_THREADS)
+ print(f'{self.backend_class}: Ran {N_ITERATIONS} iterations with {N_THREADS} threads each in {elapsed} s')
+ print(f'Average time per request: {average} ms')
+
+ for i in range(N_ITERATIONS):
+ assert session.cache.has_url(f'{url}?key_{i}=value_{i}')
diff --git a/tests/integration/test_dynamodb.py b/tests/integration/test_dynamodb.py
index 12da135..951d9c8 100644
--- a/tests/integration/test_dynamodb.py
+++ b/tests/integration/test_dynamodb.py
@@ -1,9 +1,9 @@
import pytest
from unittest.mock import patch
-from requests_cache.backends import DynamoDbDict
+from requests_cache.backends import DynamoDbCache, DynamoDbDict
from tests.conftest import AWS_OPTIONS, fail_if_no_connection
-from tests.integration.test_backends import BaseStorageTest
+from tests.integration.test_backends import BaseCacheTest, BaseStorageTest
# Run this test module last, since the DynamoDB container takes the longest to initialize
pytestmark = pytest.mark.order(-1)
@@ -29,3 +29,8 @@ class TestDynamoDbDict(BaseStorageTest):
"""A spot check to make sure optional connection kwargs gets passed to connection"""
DynamoDbDict('test', region_name='us-east-2', invalid_kwarg='???')
mock_resource.assert_called_with('dynamodb', region_name='us-east-2')
+
+
+class TestDynamoDbCache(BaseCacheTest):
+ backend_class = DynamoDbCache
+ init_kwargs = AWS_OPTIONS
diff --git a/tests/integration/test_filesystem.py b/tests/integration/test_filesystem.py
index 2191daa..0a3caec 100644
--- a/tests/integration/test_filesystem.py
+++ b/tests/integration/test_filesystem.py
@@ -1,8 +1,8 @@
from os.path import isfile
from shutil import rmtree
-from requests_cache.backends import FileDict
-from tests.integration.test_backends import CACHE_NAME, BaseStorageTest
+from requests_cache.backends import FileCache, FileDict
+from tests.integration.test_backends import CACHE_NAME, BaseCacheTest, BaseStorageTest
class TestFileDict(BaseStorageTest):
@@ -26,3 +26,8 @@ class TestFileDict(BaseStorageTest):
assert len(list(cache.paths())) == self.num_instances
for path in cache.paths():
assert isfile(path)
+
+
+class TestFileCache(BaseCacheTest):
+ backend_class = FileCache
+ init_kwargs = {'use_temp': True}
diff --git a/tests/integration/test_gridfs.py b/tests/integration/test_gridfs.py
index 4879957..d463824 100644
--- a/tests/integration/test_gridfs.py
+++ b/tests/integration/test_gridfs.py
@@ -3,9 +3,9 @@ from unittest.mock import patch
from pymongo import MongoClient
-from requests_cache.backends import GridFSPickleDict, get_valid_kwargs
+from requests_cache.backends import GridFSCache, GridFSPickleDict, get_valid_kwargs
from tests.conftest import fail_if_no_connection
-from tests.integration.test_backends import BaseStorageTest
+from tests.integration.test_backends import BaseCacheTest, BaseStorageTest
@pytest.fixture(scope='module', autouse=True)
@@ -33,3 +33,7 @@ class TestGridFSPickleDict(BaseStorageTest):
"""A spot check to make sure optional connection kwargs gets passed to connection"""
GridFSPickleDict('test', host='http://0.0.0.0', port=1234, invalid_kwarg='???')
mock_client.assert_called_with(host='http://0.0.0.0', port=1234)
+
+
+class TestGridFSCache(BaseCacheTest):
+ backend_class = GridFSCache
diff --git a/tests/integration/test_mongodb.py b/tests/integration/test_mongodb.py
index 52c8935..a186ee7 100644
--- a/tests/integration/test_mongodb.py
+++ b/tests/integration/test_mongodb.py
@@ -3,9 +3,9 @@ from unittest.mock import patch
from pymongo import MongoClient
-from requests_cache.backends import MongoDict, MongoPickleDict, get_valid_kwargs
+from requests_cache.backends import MongoCache, MongoDict, MongoPickleDict, get_valid_kwargs
from tests.conftest import fail_if_no_connection
-from tests.integration.test_backends import BaseStorageTest
+from tests.integration.test_backends import BaseCacheTest, BaseStorageTest
@pytest.fixture(scope='module', autouse=True)
@@ -35,3 +35,7 @@ class TestMongoPickleDict(BaseStorageTest):
"""A spot check to make sure optional connection kwargs gets passed to connection"""
MongoDict('test', host='http://0.0.0.0', port=1234, invalid_kwarg='???')
mock_client.assert_called_with(host='http://0.0.0.0', port=1234)
+
+
+class TestMongoCache(BaseCacheTest):
+ backend_class = MongoCache
diff --git a/tests/integration/test_redis.py b/tests/integration/test_redis.py
index 1c00ff1..899d2b6 100644
--- a/tests/integration/test_redis.py
+++ b/tests/integration/test_redis.py
@@ -3,7 +3,7 @@ from unittest.mock import patch
from requests_cache.backends.redis import RedisCache, RedisDict
from tests.conftest import fail_if_no_connection
-from tests.integration.test_backends import BaseStorageTest
+from tests.integration.test_backends import BaseCacheTest, BaseStorageTest
@pytest.fixture(scope='module', autouse=True)
@@ -24,3 +24,7 @@ class TestRedisDict(BaseStorageTest):
"""A spot check to make sure optional connection kwargs gets passed to connection"""
RedisCache('test', username='user', password='pass', invalid_kwarg='???')
mock_redis.assert_called_with(username='user', password='pass')
+
+
+class TestRedisCache(BaseCacheTest):
+ backend_class = RedisCache
diff --git a/tests/integration/test_sqlite.py b/tests/integration/test_sqlite.py
index e93216d..63c67ec 100644
--- a/tests/integration/test_sqlite.py
+++ b/tests/integration/test_sqlite.py
@@ -2,8 +2,8 @@ import os
from threading import Thread
from unittest.mock import patch
-from requests_cache.backends.sqlite import DbDict, DbPickleDict
-from tests.integration.test_backends import CACHE_NAME, BaseStorageTest
+from requests_cache.backends.sqlite import DbCache, DbDict, DbPickleDict
+from tests.integration.test_backends import CACHE_NAME, BaseCacheTest, BaseStorageTest
class SQLiteTestCase(BaseStorageTest):
@@ -63,8 +63,8 @@ class SQLiteTestCase(BaseStorageTest):
thread.join()
# make sure connection is not closed by the thread
- cache[0] = 0
- assert str(cache) == "{0: 0}"
+ cache['key_1'] = 'value_1'
+ assert list(cache.keys()) == ['key_1']
@patch('requests_cache.backends.sqlite.sqlite3')
def test_connection_kwargs(self, mock_sqlite):
@@ -80,3 +80,15 @@ class TestDbDict(SQLiteTestCase):
class TestDbPickleDict(SQLiteTestCase):
storage_class = DbPickleDict
picklable = True
+
+
+class TestDbCache(BaseCacheTest):
+ backend_class = DbCache
+ init_kwargs = {'use_temp': True}
+
+ @classmethod
+ def teardown_class(cls):
+ try:
+ os.unlink(CACHE_NAME)
+ except Exception:
+ pass
diff --git a/tests/integration/test_thread_safety.py b/tests/integration/test_thread_safety.py
deleted file mode 100644
index bc99c72..0000000
--- a/tests/integration/test_thread_safety.py
+++ /dev/null
@@ -1,35 +0,0 @@
-import pytest
-from threading import Thread
-from time import time
-
-from requests_cache.backends import BACKEND_CLASSES
-from requests_cache.session import CachedSession
-from tests.conftest import AWS_OPTIONS, N_ITERATIONS, N_THREADS, httpbin
-
-
-@pytest.mark.parametrize('iteration', range(N_ITERATIONS))
-@pytest.mark.parametrize('backend', BACKEND_CLASSES.keys())
-def test_caching_with_threads(backend, iteration):
- """Run a multi-threaded stress test for each backend"""
- start = time()
- session = CachedSession(backend=backend, use_temp=True, **AWS_OPTIONS)
- session.cache.clear()
- url = httpbin('anything')
-
- def send_requests():
- for i in range(N_ITERATIONS):
- session.get(url, params={f'key_{i}': f'value_{i}'})
-
- threads = [Thread(target=send_requests) for i in range(N_THREADS)]
- for t in threads:
- t.start()
- for t in threads:
- t.join()
-
- elapsed = time() - start
- average = (elapsed * 1000) / (N_ITERATIONS * N_THREADS)
- print(f'{backend}: Ran {N_ITERATIONS} iterations with {N_THREADS} threads each in {elapsed} s')
- print(f'Average time per request: {average} ms')
-
- for i in range(N_ITERATIONS):
- assert session.cache.has_url(f'{url}?key_{i}=value_{i}')