summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJordan Cook <jordan.cook@pioneer.com>2021-04-22 17:16:42 -0500
committerJordan Cook <jordan.cook@pioneer.com>2021-04-22 20:55:23 -0500
commit6e1679f7fb53a7edd2133f3a5ab2d8ca40ddccdb (patch)
tree32f3626643cc6b1e5102a6e627e8142d5dfd912a
parentf2bf9bbfd8d711e9dfc8ccce83f439d765d484cb (diff)
downloadrequests-cache-6e1679f7fb53a7edd2133f3a5ab2d8ca40ddccdb.tar.gz
Combine test_cache.py with BaseCacheTest to run these tests for all backends
-rw-r--r--.github/workflows/build.yml2
-rw-r--r--tests/conftest.py17
-rw-r--r--tests/integration/base_cache_test.py133
-rw-r--r--tests/integration/base_storage_test.py (renamed from tests/integration/test_backends.py)48
-rw-r--r--tests/integration/test_cache.py96
-rw-r--r--tests/integration/test_dynamodb.py3
-rw-r--r--tests/integration/test_filesystem.py3
-rw-r--r--tests/integration/test_gridfs.py3
-rw-r--r--tests/integration/test_mongodb.py3
-rw-r--r--tests/integration/test_redis.py3
-rw-r--r--tests/integration/test_sqlite.py3
11 files changed, 166 insertions, 148 deletions
diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index 36e2423..10f778d 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -72,7 +72,7 @@ jobs:
# Run longer stress tests if this is a release or merge to master
- name: Run stress tests
if: startsWith(github.ref, 'refs/tags/v') || endsWith(github.ref, '/master')
- run: STRESS_TEST_MULTIPLIER=5 pytest tests/integration/test_thread_safety.py
+ run: STRESS_TEST_MULTIPLIER=5 pytest tests/integration/ -k 'multithreaded'
# Run code analysis checks
analyze:
diff --git a/tests/conftest.py b/tests/conftest.py
index a918bc7..c01e066 100644
--- a/tests/conftest.py
+++ b/tests/conftest.py
@@ -29,6 +29,23 @@ STRESS_TEST_MULTIPLIER = int(os.getenv('STRESS_TEST_MULTIPLIER', '1'))
N_THREADS = 2 * STRESS_TEST_MULTIPLIER
N_ITERATIONS = 4 * STRESS_TEST_MULTIPLIER
+HTTPBIN_METHODS = ['GET', 'POST', 'PUT', 'PATCH', 'DELETE']
+HTTPBIN_FORMATS = [
+ 'brotli',
+ 'deflate',
+ 'deny',
+ 'encoding/utf8',
+ 'gzip',
+ 'html',
+ 'image/jpeg',
+ 'image/png',
+ 'image/svg',
+ 'image/webp',
+ 'json',
+ 'robots.txt',
+ 'xml',
+]
+
MOCKED_URL = 'http+mock://requests-cache.com/text'
MOCKED_URL_HTTPS = 'https+mock://requests-cache.com/text'
MOCKED_URL_JSON = 'http+mock://requests-cache.com/json'
diff --git a/tests/integration/base_cache_test.py b/tests/integration/base_cache_test.py
new file mode 100644
index 0000000..7745cc4
--- /dev/null
+++ b/tests/integration/base_cache_test.py
@@ -0,0 +1,133 @@
+"""Common tests to run for all backends (BaseCache subclasses)"""
+import json
+import pytest
+from threading import Thread
+from time import time
+from typing import Dict, Type
+
+from requests_cache import ALL_METHODS, CachedResponse, CachedSession
+from requests_cache.backends.base import BaseCache
+from tests.conftest import (
+ CACHE_NAME,
+ HTTPBIN_FORMATS,
+ HTTPBIN_METHODS,
+ N_ITERATIONS,
+ N_THREADS,
+ USE_PYTEST_HTTPBIN,
+ httpbin,
+)
+
+
+class BaseCacheTest:
+ """Base class for testing cache backend classes"""
+
+ backend_class: Type[BaseCache] = None
+ init_kwargs: Dict = {}
+
+ def init_session(self, clear=True, **kwargs) -> CachedSession:
+ kwargs.update({'allowable_methods': ALL_METHODS, 'suppress_warnings': True})
+ backend = self.backend_class(CACHE_NAME, **self.init_kwargs, **kwargs)
+ if clear:
+ backend.redirects.clear()
+ backend.responses.clear()
+
+ return CachedSession(backend=backend, **self.init_kwargs, **kwargs)
+
+ @pytest.mark.parametrize('method', HTTPBIN_METHODS)
+ @pytest.mark.parametrize('field', ['params', 'data', 'json'])
+ def test_all_methods(self, field, method):
+ """Test all relevant combinations of methods and data fields. Requests with different request
+ params, data, or json should be cached under different keys.
+ """
+ url = httpbin(method.lower())
+ session = self.init_session()
+ for params in [{'param_1': 1}, {'param_1': 2}, {'param_2': 2}]:
+ assert session.request(method, url, **{field: params}).from_cache is False
+ assert session.request(method, url, **{field: params}).from_cache is True
+
+ @pytest.mark.parametrize('response_format', HTTPBIN_FORMATS)
+ def test_all_response_formats(self, response_format):
+ """Test that all relevant response formats are cached correctly"""
+ session = self.init_session()
+ # Temporary workaround for this issue: https://github.com/kevin1024/pytest-httpbin/issues/60
+ if response_format == 'json' and USE_PYTEST_HTTPBIN:
+ session.allowable_codes = (200, 404)
+
+ r1 = session.get(httpbin(response_format))
+ r2 = session.get(httpbin(response_format))
+ assert r1.from_cache is False
+ assert r2.from_cache is True
+ assert r1.content == r2.content
+
+ @pytest.mark.parametrize('n_redirects', range(1, 5))
+ @pytest.mark.parametrize('endpoint', ['redirect', 'absolute-redirect', 'relative-redirect'])
+ def test_redirects(self, endpoint, n_redirects):
+ """Test all types of redirect endpoints with different numbers of consecutive redirects"""
+ session = self.init_session()
+ session.get(httpbin(f'redirect/{n_redirects}'))
+ r2 = session.get(httpbin('get'))
+
+ assert r2.from_cache is True
+ assert len(session.cache.redirects) == n_redirects
+
+ def test_cookies(self):
+ session = self.init_session()
+
+ def get_json(url):
+ return json.loads(session.get(url).text)
+
+ response_1 = get_json(httpbin('cookies/set/test1/test2'))
+ with session.cache_disabled():
+ assert get_json(httpbin('cookies')) == response_1
+ # From cache
+ response_2 = get_json(httpbin('cookies'))
+ assert response_2 == get_json(httpbin('cookies'))
+ # Not from cache
+ with session.cache_disabled():
+ response_3 = get_json(httpbin('cookies/set/test3/test4'))
+ assert response_3 == get_json(httpbin('cookies'))
+
+ def test_response_decode(self):
+ """Test that a gzip-compressed raw response can be manually uncompressed with decode_content"""
+ session = self.init_session()
+ response = session.get(httpbin('gzip'))
+ assert b'gzipped' in response.content
+
+ cached = CachedResponse(response)
+ assert b'gzipped' in cached.content
+ assert b'gzipped' in cached.raw.read(None, decode_content=True)
+
+ def test_response_decode_stream(self):
+ """Test that streamed gzip-compressed responses can be uncompressed with decode_content"""
+ session = self.init_session()
+ response_uncached = session.get(httpbin('gzip'), stream=True)
+ response_cached = session.get(httpbin('gzip'), stream=True)
+
+ for res in (response_uncached, response_cached):
+ assert b'gzipped' in res.content
+ assert b'gzipped' in res.raw.read(None, decode_content=True)
+
+ @pytest.mark.parametrize('iteration', range(N_ITERATIONS))
+ def test_multithreaded(self, iteration):
+ """Run a multi-threaded stress test for each backend"""
+ session = self.init_session()
+ start = time()
+ 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_backends.py b/tests/integration/base_storage_test.py
index 9849a6b..0679e9c 100644
--- a/tests/integration/test_backends.py
+++ b/tests/integration/base_storage_test.py
@@ -1,11 +1,9 @@
+"""Common tests to run for all backends (BaseStorage subclasses)"""
import pytest
-from threading import Thread
-from time import time
from typing import Dict, Type
-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
+from requests_cache.backends.base import BaseStorage
+from tests.conftest import CACHE_NAME
class BaseStorageTest:
@@ -124,43 +122,3 @@ class BaseStorageTest:
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_cache.py b/tests/integration/test_cache.py
deleted file mode 100644
index 4b2fb33..0000000
--- a/tests/integration/test_cache.py
+++ /dev/null
@@ -1,96 +0,0 @@
-"""CachedSession tests that hit a containerized httpbin service"""
-import json
-import pytest
-
-from requests_cache import CachedResponse
-from tests.conftest import USE_PYTEST_HTTPBIN, httpbin
-
-HTTPBIN_METHODS = ['GET', 'POST', 'PUT', 'PATCH', 'DELETE']
-HTTPBIN_FORMATS = [
- 'brotli',
- 'deflate',
- 'deny',
- 'encoding/utf8',
- 'gzip',
- 'html',
- 'image/jpeg',
- 'image/png',
- 'image/svg',
- 'image/webp',
- 'json',
- 'robots.txt',
- 'xml',
-]
-
-
-@pytest.mark.parametrize('method', HTTPBIN_METHODS)
-@pytest.mark.parametrize('field', ['params', 'data', 'json'])
-def test_all_methods(field, method, tempfile_session):
- """Test all relevant combinations of methods and data fields. Requests with different request
- params, data, or json should be cached under different keys.
- """
- url = httpbin(method.lower())
- for params in [{'param_1': 1}, {'param_1': 2}, {'param_2': 2}]:
- assert tempfile_session.request(method, url, **{field: params}).from_cache is False
- assert tempfile_session.request(method, url, **{field: params}).from_cache is True
-
-
-@pytest.mark.parametrize('response_format', HTTPBIN_FORMATS)
-def test_all_response_formats(response_format, tempfile_session):
- """Test that all relevant response formats are cached correctly"""
- # Temporary workaround for this issue: https://github.com/kevin1024/pytest-httpbin/issues/60
- if response_format == 'json' and USE_PYTEST_HTTPBIN:
- tempfile_session.allowable_codes = (200, 404)
-
- r1 = tempfile_session.get(httpbin(response_format))
- r2 = tempfile_session.get(httpbin(response_format))
- assert r1.from_cache is False
- assert r2.from_cache is True
- assert r1.content == r2.content
-
-
-@pytest.mark.parametrize('n_redirects', range(1, 5))
-@pytest.mark.parametrize('endpoint', ['redirect', 'absolute-redirect', 'relative-redirect'])
-def test_redirects(endpoint, n_redirects, mock_session):
- """Test all types of redirect endpoints with different numbers of consecutive redirects"""
- mock_session.get(httpbin(f'redirect/{n_redirects}'))
- r2 = mock_session.get(httpbin('get'))
-
- assert r2.from_cache is True
- assert len(mock_session.cache.redirects) == n_redirects
-
-
-def test_cookies(tempfile_session):
- def get_json(url):
- return json.loads(tempfile_session.get(url).text)
-
- response_1 = get_json(httpbin('cookies/set/test1/test2'))
- with tempfile_session.cache_disabled():
- assert get_json(httpbin('cookies')) == response_1
- # From cache
- response_2 = get_json(httpbin('cookies'))
- assert response_2 == get_json(httpbin('cookies'))
- # Not from cache
- with tempfile_session.cache_disabled():
- response_3 = get_json(httpbin('cookies/set/test3/test4'))
- assert response_3 == get_json(httpbin('cookies'))
-
-
-def test_response_decode(tempfile_session):
- """Test that a gzip-compressed raw response can be manually uncompressed with decode_content"""
- response = tempfile_session.get(httpbin('gzip'))
- assert b'gzipped' in response.content
-
- cached = CachedResponse(response)
- assert b'gzipped' in cached.content
- assert b'gzipped' in cached.raw.read(None, decode_content=True)
-
-
-def test_response_decode_stream(tempfile_session):
- """Test that streamed gzip-compressed responses can be uncompressed with decode_content"""
- response_uncached = tempfile_session.get(httpbin('gzip'), stream=True)
- response_cached = tempfile_session.get(httpbin('gzip'), stream=True)
-
- for res in (response_uncached, response_cached):
- assert b'gzipped' in res.content
- assert b'gzipped' in res.raw.read(None, decode_content=True)
diff --git a/tests/integration/test_dynamodb.py b/tests/integration/test_dynamodb.py
index 951d9c8..c6a175e 100644
--- a/tests/integration/test_dynamodb.py
+++ b/tests/integration/test_dynamodb.py
@@ -3,7 +3,8 @@ from unittest.mock import patch
from requests_cache.backends import DynamoDbCache, DynamoDbDict
from tests.conftest import AWS_OPTIONS, fail_if_no_connection
-from tests.integration.test_backends import BaseCacheTest, BaseStorageTest
+from tests.integration.base_cache_test import BaseCacheTest
+from tests.integration.base_storage_test import BaseStorageTest
# Run this test module last, since the DynamoDB container takes the longest to initialize
pytestmark = pytest.mark.order(-1)
diff --git a/tests/integration/test_filesystem.py b/tests/integration/test_filesystem.py
index 0a3caec..7c329a4 100644
--- a/tests/integration/test_filesystem.py
+++ b/tests/integration/test_filesystem.py
@@ -2,7 +2,8 @@ from os.path import isfile
from shutil import rmtree
from requests_cache.backends import FileCache, FileDict
-from tests.integration.test_backends import CACHE_NAME, BaseCacheTest, BaseStorageTest
+from tests.integration.base_cache_test import BaseCacheTest
+from tests.integration.base_storage_test import CACHE_NAME, BaseStorageTest
class TestFileDict(BaseStorageTest):
diff --git a/tests/integration/test_gridfs.py b/tests/integration/test_gridfs.py
index d463824..c628337 100644
--- a/tests/integration/test_gridfs.py
+++ b/tests/integration/test_gridfs.py
@@ -5,7 +5,8 @@ from pymongo import MongoClient
from requests_cache.backends import GridFSCache, GridFSPickleDict, get_valid_kwargs
from tests.conftest import fail_if_no_connection
-from tests.integration.test_backends import BaseCacheTest, BaseStorageTest
+from tests.integration.base_cache_test import BaseCacheTest
+from tests.integration.base_storage_test import BaseStorageTest
@pytest.fixture(scope='module', autouse=True)
diff --git a/tests/integration/test_mongodb.py b/tests/integration/test_mongodb.py
index a186ee7..8e9cafe 100644
--- a/tests/integration/test_mongodb.py
+++ b/tests/integration/test_mongodb.py
@@ -5,7 +5,8 @@ from pymongo import MongoClient
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 BaseCacheTest, BaseStorageTest
+from tests.integration.base_cache_test import BaseCacheTest
+from tests.integration.base_storage_test import BaseStorageTest
@pytest.fixture(scope='module', autouse=True)
diff --git a/tests/integration/test_redis.py b/tests/integration/test_redis.py
index 899d2b6..8154b29 100644
--- a/tests/integration/test_redis.py
+++ b/tests/integration/test_redis.py
@@ -3,7 +3,8 @@ 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 BaseCacheTest, BaseStorageTest
+from tests.integration.base_cache_test import BaseCacheTest
+from tests.integration.base_storage_test import BaseStorageTest
@pytest.fixture(scope='module', autouse=True)
diff --git a/tests/integration/test_sqlite.py b/tests/integration/test_sqlite.py
index 63c67ec..fd463ac 100644
--- a/tests/integration/test_sqlite.py
+++ b/tests/integration/test_sqlite.py
@@ -3,7 +3,8 @@ from threading import Thread
from unittest.mock import patch
from requests_cache.backends.sqlite import DbCache, DbDict, DbPickleDict
-from tests.integration.test_backends import CACHE_NAME, BaseCacheTest, BaseStorageTest
+from tests.integration.base_cache_test import BaseCacheTest
+from tests.integration.base_storage_test import CACHE_NAME, BaseStorageTest
class SQLiteTestCase(BaseStorageTest):