ipulse-shared-core-ftredge 27.3.0__tar.gz → 27.4.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {ipulse_shared_core_ftredge-27.3.0/src/ipulse_shared_core_ftredge.egg-info → ipulse_shared_core_ftredge-27.4.1}/PKG-INFO +1 -1
- {ipulse_shared_core_ftredge-27.3.0 → ipulse_shared_core_ftredge-27.4.1}/setup.py +1 -1
- {ipulse_shared_core_ftredge-27.3.0 → ipulse_shared_core_ftredge-27.4.1}/src/ipulse_shared_core_ftredge/models/base_api_response.py +4 -0
- {ipulse_shared_core_ftredge-27.3.0 → ipulse_shared_core_ftredge-27.4.1}/src/ipulse_shared_core_ftredge/services/base/cache_aware_firestore_service.py +65 -4
- {ipulse_shared_core_ftredge-27.3.0 → ipulse_shared_core_ftredge-27.4.1}/src/ipulse_shared_core_ftredge/services/charging_processors.py +2 -2
- {ipulse_shared_core_ftredge-27.3.0 → ipulse_shared_core_ftredge-27.4.1/src/ipulse_shared_core_ftredge.egg-info}/PKG-INFO +1 -1
- {ipulse_shared_core_ftredge-27.3.0 → ipulse_shared_core_ftredge-27.4.1}/src/ipulse_shared_core_ftredge.egg-info/SOURCES.txt +1 -3
- ipulse_shared_core_ftredge-27.3.0/src/ipulse_shared_core_ftredge/utils/authz_credit_extraction.py +0 -0
- ipulse_shared_core_ftredge-27.3.0/tests/test_shared_cache.py +0 -147
- {ipulse_shared_core_ftredge-27.3.0 → ipulse_shared_core_ftredge-27.4.1}/LICENCE +0 -0
- {ipulse_shared_core_ftredge-27.3.0 → ipulse_shared_core_ftredge-27.4.1}/README.md +0 -0
- {ipulse_shared_core_ftredge-27.3.0 → ipulse_shared_core_ftredge-27.4.1}/pyproject.toml +0 -0
- {ipulse_shared_core_ftredge-27.3.0 → ipulse_shared_core_ftredge-27.4.1}/setup.cfg +0 -0
- {ipulse_shared_core_ftredge-27.3.0 → ipulse_shared_core_ftredge-27.4.1}/src/ipulse_shared_core_ftredge/__init__.py +0 -0
- {ipulse_shared_core_ftredge-27.3.0 → ipulse_shared_core_ftredge-27.4.1}/src/ipulse_shared_core_ftredge/cache/__init__.py +0 -0
- {ipulse_shared_core_ftredge-27.3.0 → ipulse_shared_core_ftredge-27.4.1}/src/ipulse_shared_core_ftredge/cache/shared_cache.py +0 -0
- {ipulse_shared_core_ftredge-27.3.0 → ipulse_shared_core_ftredge-27.4.1}/src/ipulse_shared_core_ftredge/dependencies/__init__.py +0 -0
- {ipulse_shared_core_ftredge-27.3.0 → ipulse_shared_core_ftredge-27.4.1}/src/ipulse_shared_core_ftredge/dependencies/auth_firebase_token_validation.py +0 -0
- {ipulse_shared_core_ftredge-27.3.0 → ipulse_shared_core_ftredge-27.4.1}/src/ipulse_shared_core_ftredge/dependencies/auth_protected_router.py +0 -0
- {ipulse_shared_core_ftredge-27.3.0 → ipulse_shared_core_ftredge-27.4.1}/src/ipulse_shared_core_ftredge/dependencies/authz_credit_extraction.py +0 -0
- {ipulse_shared_core_ftredge-27.3.0 → ipulse_shared_core_ftredge-27.4.1}/src/ipulse_shared_core_ftredge/dependencies/authz_for_apis.py +0 -0
- {ipulse_shared_core_ftredge-27.3.0 → ipulse_shared_core_ftredge-27.4.1}/src/ipulse_shared_core_ftredge/dependencies/firestore_client.py +0 -0
- {ipulse_shared_core_ftredge-27.3.0 → ipulse_shared_core_ftredge-27.4.1}/src/ipulse_shared_core_ftredge/exceptions/__init__.py +0 -0
- {ipulse_shared_core_ftredge-27.3.0 → ipulse_shared_core_ftredge-27.4.1}/src/ipulse_shared_core_ftredge/exceptions/base_exceptions.py +0 -0
- {ipulse_shared_core_ftredge-27.3.0 → ipulse_shared_core_ftredge-27.4.1}/src/ipulse_shared_core_ftredge/exceptions/user_exceptions.py +0 -0
- {ipulse_shared_core_ftredge-27.3.0 → ipulse_shared_core_ftredge-27.4.1}/src/ipulse_shared_core_ftredge/models/__init__.py +0 -0
- {ipulse_shared_core_ftredge-27.3.0 → ipulse_shared_core_ftredge-27.4.1}/src/ipulse_shared_core_ftredge/models/base_data_model.py +0 -0
- {ipulse_shared_core_ftredge-27.3.0 → ipulse_shared_core_ftredge-27.4.1}/src/ipulse_shared_core_ftredge/models/catalog/__init__.py +0 -0
- {ipulse_shared_core_ftredge-27.3.0 → ipulse_shared_core_ftredge-27.4.1}/src/ipulse_shared_core_ftredge/models/catalog/subscriptionplan.py +0 -0
- {ipulse_shared_core_ftredge-27.3.0 → ipulse_shared_core_ftredge-27.4.1}/src/ipulse_shared_core_ftredge/models/catalog/usertype.py +0 -0
- {ipulse_shared_core_ftredge-27.3.0 → ipulse_shared_core_ftredge-27.4.1}/src/ipulse_shared_core_ftredge/models/credit_api_response.py +0 -0
- {ipulse_shared_core_ftredge-27.3.0 → ipulse_shared_core_ftredge-27.4.1}/src/ipulse_shared_core_ftredge/models/custom_json_response.py +0 -0
- {ipulse_shared_core_ftredge-27.3.0 → ipulse_shared_core_ftredge-27.4.1}/src/ipulse_shared_core_ftredge/models/time_series_packaged_dataset_model.py +0 -0
- {ipulse_shared_core_ftredge-27.3.0 → ipulse_shared_core_ftredge-27.4.1}/src/ipulse_shared_core_ftredge/models/user/__init__.py +0 -0
- {ipulse_shared_core_ftredge-27.3.0 → ipulse_shared_core_ftredge-27.4.1}/src/ipulse_shared_core_ftredge/models/user/user_permissions.py +0 -0
- {ipulse_shared_core_ftredge-27.3.0 → ipulse_shared_core_ftredge-27.4.1}/src/ipulse_shared_core_ftredge/models/user/user_subscription.py +0 -0
- {ipulse_shared_core_ftredge-27.3.0 → ipulse_shared_core_ftredge-27.4.1}/src/ipulse_shared_core_ftredge/models/user/userauth.py +0 -0
- {ipulse_shared_core_ftredge-27.3.0 → ipulse_shared_core_ftredge-27.4.1}/src/ipulse_shared_core_ftredge/models/user/userprofile.py +0 -0
- {ipulse_shared_core_ftredge-27.3.0 → ipulse_shared_core_ftredge-27.4.1}/src/ipulse_shared_core_ftredge/models/user/userstatus.py +0 -0
- {ipulse_shared_core_ftredge-27.3.0 → ipulse_shared_core_ftredge-27.4.1}/src/ipulse_shared_core_ftredge/monitoring/__init__.py +0 -0
- {ipulse_shared_core_ftredge-27.3.0 → ipulse_shared_core_ftredge-27.4.1}/src/ipulse_shared_core_ftredge/monitoring/tracemon.py +0 -0
- {ipulse_shared_core_ftredge-27.3.0 → ipulse_shared_core_ftredge-27.4.1}/src/ipulse_shared_core_ftredge/services/__init__.py +0 -0
- {ipulse_shared_core_ftredge-27.3.0 → ipulse_shared_core_ftredge-27.4.1}/src/ipulse_shared_core_ftredge/services/base/__init__.py +0 -0
- {ipulse_shared_core_ftredge-27.3.0 → ipulse_shared_core_ftredge-27.4.1}/src/ipulse_shared_core_ftredge/services/base/base_firestore_service.py +0 -0
- {ipulse_shared_core_ftredge-27.3.0 → ipulse_shared_core_ftredge-27.4.1}/src/ipulse_shared_core_ftredge/services/base/multi_collection_cache_aware_firestore_service.py +0 -0
- {ipulse_shared_core_ftredge-27.3.0 → ipulse_shared_core_ftredge-27.4.1}/src/ipulse_shared_core_ftredge/services/catalog/__init__.py +0 -0
- {ipulse_shared_core_ftredge-27.3.0 → ipulse_shared_core_ftredge-27.4.1}/src/ipulse_shared_core_ftredge/services/catalog/catalog_subscriptionplan_service.py +0 -0
- {ipulse_shared_core_ftredge-27.3.0 → ipulse_shared_core_ftredge-27.4.1}/src/ipulse_shared_core_ftredge/services/catalog/catalog_usertype_service.py +0 -0
- {ipulse_shared_core_ftredge-27.3.0 → ipulse_shared_core_ftredge-27.4.1}/src/ipulse_shared_core_ftredge/services/user/__init__.py +0 -0
- {ipulse_shared_core_ftredge-27.3.0 → ipulse_shared_core_ftredge-27.4.1}/src/ipulse_shared_core_ftredge/services/user/user_charging_operations.py +0 -0
- {ipulse_shared_core_ftredge-27.3.0 → ipulse_shared_core_ftredge-27.4.1}/src/ipulse_shared_core_ftredge/services/user/user_core_service.py +0 -0
- {ipulse_shared_core_ftredge-27.3.0 → ipulse_shared_core_ftredge-27.4.1}/src/ipulse_shared_core_ftredge/services/user/user_multistep_operations.py +0 -0
- {ipulse_shared_core_ftredge-27.3.0 → ipulse_shared_core_ftredge-27.4.1}/src/ipulse_shared_core_ftredge/services/user/user_permissions_operations.py +0 -0
- {ipulse_shared_core_ftredge-27.3.0 → ipulse_shared_core_ftredge-27.4.1}/src/ipulse_shared_core_ftredge/services/user/user_subscription_operations.py +0 -0
- {ipulse_shared_core_ftredge-27.3.0 → ipulse_shared_core_ftredge-27.4.1}/src/ipulse_shared_core_ftredge/services/user/userauth_operations.py +0 -0
- {ipulse_shared_core_ftredge-27.3.0 → ipulse_shared_core_ftredge-27.4.1}/src/ipulse_shared_core_ftredge/services/user/userprofile_operations.py +0 -0
- {ipulse_shared_core_ftredge-27.3.0 → ipulse_shared_core_ftredge-27.4.1}/src/ipulse_shared_core_ftredge/services/user/userstatus_operations.py +0 -0
- {ipulse_shared_core_ftredge-27.3.0 → ipulse_shared_core_ftredge-27.4.1}/src/ipulse_shared_core_ftredge/services/user_charging_service.py +0 -0
- {ipulse_shared_core_ftredge-27.3.0 → ipulse_shared_core_ftredge-27.4.1}/src/ipulse_shared_core_ftredge/utils/__init__.py +0 -0
- {ipulse_shared_core_ftredge-27.3.0 → ipulse_shared_core_ftredge-27.4.1}/src/ipulse_shared_core_ftredge/utils/custom_json_encoder.py +0 -0
- {ipulse_shared_core_ftredge-27.3.0 → ipulse_shared_core_ftredge-27.4.1}/src/ipulse_shared_core_ftredge/utils/json_encoder.py +0 -0
- {ipulse_shared_core_ftredge-27.3.0 → ipulse_shared_core_ftredge-27.4.1}/src/ipulse_shared_core_ftredge.egg-info/dependency_links.txt +0 -0
- {ipulse_shared_core_ftredge-27.3.0 → ipulse_shared_core_ftredge-27.4.1}/src/ipulse_shared_core_ftredge.egg-info/requires.txt +0 -0
- {ipulse_shared_core_ftredge-27.3.0 → ipulse_shared_core_ftredge-27.4.1}/src/ipulse_shared_core_ftredge.egg-info/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: ipulse_shared_core_ftredge
|
|
3
|
-
Version: 27.
|
|
3
|
+
Version: 27.4.1
|
|
4
4
|
Summary: Shared Core models and Logger util for the Pulse platform project. Using AI for financial advisory and investment management.
|
|
5
5
|
Home-page: https://github.com/TheFutureEdge/ipulse_shared_core
|
|
6
6
|
Author: Russlan Ramdowar
|
|
@@ -3,7 +3,7 @@ from setuptools import setup, find_packages
|
|
|
3
3
|
|
|
4
4
|
setup(
|
|
5
5
|
name='ipulse_shared_core_ftredge',
|
|
6
|
-
version='27.
|
|
6
|
+
version='27.4.1',
|
|
7
7
|
package_dir={'': 'src'}, # Specify the source directory
|
|
8
8
|
packages=find_packages(where='src'), # Look for packages in 'src'
|
|
9
9
|
install_requires=[
|
|
@@ -16,6 +16,10 @@ class BaseAPIResponse(BaseModel, Generic[T]):
|
|
|
16
16
|
message: Optional[str] = None
|
|
17
17
|
error: Optional[str] = None
|
|
18
18
|
|
|
19
|
+
# Optional fields for specific use cases
|
|
20
|
+
cache_hit: Optional[bool] = None # Whether data came from cache
|
|
21
|
+
charged: Optional[bool] = None # Whether credits were charged for this request
|
|
22
|
+
|
|
19
23
|
metadata: Dict[str, Any] = {
|
|
20
24
|
"timestamp": dt.datetime.now(dt.timezone.utc).isoformat()
|
|
21
25
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"""Cache-aware Firestore service base class."""
|
|
2
2
|
import time
|
|
3
|
-
from typing import TypeVar, Generic, Dict, Any, List, Optional, Union, Type
|
|
3
|
+
from typing import TypeVar, Generic, Dict, Any, List, Optional, Union, Type, Tuple
|
|
4
4
|
from google.cloud import firestore
|
|
5
5
|
from . import BaseFirestoreService
|
|
6
6
|
from ...exceptions import ResourceNotFoundError, ServiceError
|
|
@@ -58,7 +58,9 @@ class CacheAwareFirestoreService(BaseFirestoreService[T], Generic[T]):
|
|
|
58
58
|
cache_check_time = (time.time() - start_time) * 1000
|
|
59
59
|
|
|
60
60
|
if cached_doc is not None:
|
|
61
|
-
|
|
61
|
+
# SharedCache.get() already logs cache hit, only log timing if significant
|
|
62
|
+
if cache_check_time > 5.0: # Only log if cache check took >5ms
|
|
63
|
+
self.logger.debug(f"Cache HIT for document {doc_id} in {cache_check_time:.2f}ms")
|
|
62
64
|
if convert_to_model and self.model_class:
|
|
63
65
|
return self._convert_to_model(cached_doc, doc_id)
|
|
64
66
|
else:
|
|
@@ -68,7 +70,66 @@ class CacheAwareFirestoreService(BaseFirestoreService[T], Generic[T]):
|
|
|
68
70
|
self.logger.debug(f"Cache MISS for document {doc_id} - checking Firestore")
|
|
69
71
|
|
|
70
72
|
# Fetch from Firestore using parent method
|
|
71
|
-
|
|
73
|
+
result = await super().get_document(doc_id, convert_to_model)
|
|
74
|
+
|
|
75
|
+
# Cache the result if we have a cache and got valid data
|
|
76
|
+
if self.document_cache and result is not None:
|
|
77
|
+
if convert_to_model and isinstance(result, BaseDataModel):
|
|
78
|
+
# Cache the model's dict representation
|
|
79
|
+
self._cache_document_data(doc_id, result.model_dump())
|
|
80
|
+
elif isinstance(result, dict):
|
|
81
|
+
# Cache the dict directly
|
|
82
|
+
self._cache_document_data(doc_id, result)
|
|
83
|
+
|
|
84
|
+
return result
|
|
85
|
+
|
|
86
|
+
async def get_document_with_cache_info(self, doc_id: str, convert_to_model: bool = True) -> Tuple[Union[T, Dict[str, Any], None], bool]:
|
|
87
|
+
"""
|
|
88
|
+
Get a document with cache hit information.
|
|
89
|
+
|
|
90
|
+
Args:
|
|
91
|
+
doc_id: Document ID to fetch
|
|
92
|
+
convert_to_model: Whether to convert to Pydantic model
|
|
93
|
+
|
|
94
|
+
Returns:
|
|
95
|
+
Tuple of (document, cache_hit) where cache_hit indicates if from cache
|
|
96
|
+
|
|
97
|
+
Raises:
|
|
98
|
+
ResourceNotFoundError: If document doesn't exist
|
|
99
|
+
"""
|
|
100
|
+
cache_hit = False
|
|
101
|
+
|
|
102
|
+
# Check cache first
|
|
103
|
+
if self.document_cache:
|
|
104
|
+
cached_doc = self.document_cache.get(doc_id)
|
|
105
|
+
if cached_doc is not None:
|
|
106
|
+
cache_hit = True
|
|
107
|
+
# Note: SharedCache.get() already logs cache hit at DEBUG level
|
|
108
|
+
if convert_to_model and self.model_class:
|
|
109
|
+
return self._convert_to_model(cached_doc, doc_id), cache_hit
|
|
110
|
+
else:
|
|
111
|
+
cached_doc['id'] = doc_id
|
|
112
|
+
return cached_doc, cache_hit
|
|
113
|
+
|
|
114
|
+
# Cache miss - fetch from Firestore
|
|
115
|
+
self.logger.debug(f"Cache MISS for document {doc_id} - checking Firestore")
|
|
116
|
+
|
|
117
|
+
try:
|
|
118
|
+
result = await super().get_document(doc_id, convert_to_model)
|
|
119
|
+
|
|
120
|
+
# Cache the result if we have a cache and got valid data
|
|
121
|
+
if self.document_cache and result is not None:
|
|
122
|
+
if convert_to_model and isinstance(result, BaseDataModel):
|
|
123
|
+
# Cache the model's dict representation
|
|
124
|
+
self._cache_document_data(doc_id, result.model_dump())
|
|
125
|
+
elif isinstance(result, dict):
|
|
126
|
+
# Cache the dict directly
|
|
127
|
+
self._cache_document_data(doc_id, result)
|
|
128
|
+
|
|
129
|
+
return result, cache_hit
|
|
130
|
+
|
|
131
|
+
except ResourceNotFoundError:
|
|
132
|
+
return None, cache_hit
|
|
72
133
|
|
|
73
134
|
async def get_all_documents(self, cache_key: Optional[str] = None, as_models: bool = True) -> Union[List[T], List[Dict[str, Any]]]:
|
|
74
135
|
"""
|
|
@@ -151,7 +212,7 @@ class CacheAwareFirestoreService(BaseFirestoreService[T], Generic[T]):
|
|
|
151
212
|
"""Helper to cache document data if document_cache is available."""
|
|
152
213
|
if self.document_cache:
|
|
153
214
|
self.document_cache.set(doc_id, data)
|
|
154
|
-
|
|
215
|
+
# Note: SharedCache.set() already logs at DEBUG level
|
|
155
216
|
|
|
156
217
|
async def create_document(self, doc_id: str, data: Union[T, Dict[str, Any]], creator_uid: str, merge: bool = False) -> Dict[str, Any]:
|
|
157
218
|
"""Create document and invalidate cache."""
|
|
@@ -56,7 +56,7 @@ class ChargingProcessor:
|
|
|
56
56
|
updated_user_credits = pre_fetched_credits
|
|
57
57
|
elif self.user_charging_service: # Attempt to get current credits if not pre-fetched
|
|
58
58
|
try:
|
|
59
|
-
_, current_user_credits_from_verify = await self.user_charging_service.verify_enough_credits(user_uid, 0, None)
|
|
59
|
+
_, current_user_credits_from_verify = await self.user_charging_service.verify_enough_credits(user_uid=user_uid, required_credits_for_resource=0, pre_fetched_user_credits=None)
|
|
60
60
|
updated_user_credits = current_user_credits_from_verify
|
|
61
61
|
except Exception: # pylint: disable=broad-except
|
|
62
62
|
self.logger.warning(f"Could not fetch current credits for user {user_uid} for free item.")
|
|
@@ -77,7 +77,7 @@ class ChargingProcessor:
|
|
|
77
77
|
updated_user_credits = pre_fetched_credits
|
|
78
78
|
elif self.user_charging_service:
|
|
79
79
|
try:
|
|
80
|
-
_, current_user_credits_from_verify = await self.user_charging_service.verify_enough_credits(user_uid, 0, None)
|
|
80
|
+
_, current_user_credits_from_verify = await self.user_charging_service.verify_enough_credits(user_uid=user_uid, required_credits_for_resource=0, pre_fetched_user_credits=None)
|
|
81
81
|
updated_user_credits = current_user_credits_from_verify
|
|
82
82
|
except Exception: # pylint: disable=broad-except
|
|
83
83
|
self.logger.warning(f"Could not fetch current credits for user {user_uid} during debug bypass.")
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: ipulse_shared_core_ftredge
|
|
3
|
-
Version: 27.
|
|
3
|
+
Version: 27.4.1
|
|
4
4
|
Summary: Shared Core models and Logger util for the Pulse platform project. Using AI for financial advisory and investment management.
|
|
5
5
|
Home-page: https://github.com/TheFutureEdge/ipulse_shared_core
|
|
6
6
|
Author: Russlan Ramdowar
|
|
@@ -56,7 +56,5 @@ src/ipulse_shared_core_ftredge/services/user/userauth_operations.py
|
|
|
56
56
|
src/ipulse_shared_core_ftredge/services/user/userprofile_operations.py
|
|
57
57
|
src/ipulse_shared_core_ftredge/services/user/userstatus_operations.py
|
|
58
58
|
src/ipulse_shared_core_ftredge/utils/__init__.py
|
|
59
|
-
src/ipulse_shared_core_ftredge/utils/authz_credit_extraction.py
|
|
60
59
|
src/ipulse_shared_core_ftredge/utils/custom_json_encoder.py
|
|
61
|
-
src/ipulse_shared_core_ftredge/utils/json_encoder.py
|
|
62
|
-
tests/test_shared_cache.py
|
|
60
|
+
src/ipulse_shared_core_ftredge/utils/json_encoder.py
|
ipulse_shared_core_ftredge-27.3.0/src/ipulse_shared_core_ftredge/utils/authz_credit_extraction.py
DELETED
|
File without changes
|
|
@@ -1,147 +0,0 @@
|
|
|
1
|
-
"""Tests for the SharedCache implementation."""
|
|
2
|
-
|
|
3
|
-
import time
|
|
4
|
-
import unittest
|
|
5
|
-
import logging
|
|
6
|
-
from ipulse_shared_core_ftredge.cache.shared_cache import SharedCache
|
|
7
|
-
|
|
8
|
-
# Configure logging for tests
|
|
9
|
-
logging.basicConfig(level=logging.INFO)
|
|
10
|
-
logger = logging.getLogger(__name__)
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
class TestSharedCache(unittest.TestCase):
|
|
14
|
-
"""Test cases for SharedCache."""
|
|
15
|
-
|
|
16
|
-
def setUp(self):
|
|
17
|
-
"""Set up test fixtures."""
|
|
18
|
-
self.cache = SharedCache[str](
|
|
19
|
-
name="TestCache",
|
|
20
|
-
ttl=0.5, # Short TTL for faster testing
|
|
21
|
-
enabled=True,
|
|
22
|
-
logger=logger
|
|
23
|
-
)
|
|
24
|
-
|
|
25
|
-
def test_cache_set_get(self):
|
|
26
|
-
"""Test basic cache set and get operations."""
|
|
27
|
-
# Set a value
|
|
28
|
-
self.cache.set("test_key", "test_value")
|
|
29
|
-
|
|
30
|
-
# Get the value
|
|
31
|
-
cached_value = self.cache.get("test_key")
|
|
32
|
-
|
|
33
|
-
# Verify value was cached
|
|
34
|
-
self.assertEqual(cached_value, "test_value")
|
|
35
|
-
|
|
36
|
-
def test_cache_ttl_expiration(self):
|
|
37
|
-
"""Test cache TTL expiration."""
|
|
38
|
-
# Set a value
|
|
39
|
-
self.cache.set("expiring_key", "expiring_value")
|
|
40
|
-
|
|
41
|
-
# Verify it's initially cached
|
|
42
|
-
self.assertEqual(self.cache.get("expiring_key"), "expiring_value")
|
|
43
|
-
|
|
44
|
-
# Wait for TTL to expire
|
|
45
|
-
time.sleep(0.6) # Slightly longer than TTL (0.5s)
|
|
46
|
-
|
|
47
|
-
# Verify value is no longer cached
|
|
48
|
-
self.assertIsNone(self.cache.get("expiring_key"))
|
|
49
|
-
|
|
50
|
-
def test_cache_invalidate(self):
|
|
51
|
-
"""Test cache invalidation."""
|
|
52
|
-
# Set multiple values
|
|
53
|
-
self.cache.set("key1", "value1")
|
|
54
|
-
self.cache.set("key2", "value2")
|
|
55
|
-
|
|
56
|
-
# Invalidate specific key
|
|
57
|
-
self.cache.invalidate("key1")
|
|
58
|
-
|
|
59
|
-
# Verify key1 is gone but key2 remains
|
|
60
|
-
self.assertIsNone(self.cache.get("key1"))
|
|
61
|
-
self.assertEqual(self.cache.get("key2"), "value2")
|
|
62
|
-
|
|
63
|
-
def test_cache_invalidate_all(self):
|
|
64
|
-
"""Test invalidating all cache entries."""
|
|
65
|
-
# Set multiple values
|
|
66
|
-
self.cache.set("key1", "value1")
|
|
67
|
-
self.cache.set("key2", "value2")
|
|
68
|
-
|
|
69
|
-
# Invalidate all
|
|
70
|
-
self.cache.invalidate_all()
|
|
71
|
-
|
|
72
|
-
# Verify both keys are gone
|
|
73
|
-
self.assertIsNone(self.cache.get("key1"))
|
|
74
|
-
self.assertIsNone(self.cache.get("key2"))
|
|
75
|
-
|
|
76
|
-
def test_cache_get_or_set(self):
|
|
77
|
-
"""Test get_or_set functionality."""
|
|
78
|
-
# Define a counter to verify how many times the loader is called
|
|
79
|
-
counter = [0]
|
|
80
|
-
|
|
81
|
-
def data_loader():
|
|
82
|
-
counter[0] += 1
|
|
83
|
-
return f"loaded_value_{counter[0]}"
|
|
84
|
-
|
|
85
|
-
# First call should use data_loader
|
|
86
|
-
value1, was_cached1 = self.cache.get_or_set("loader_key", data_loader)
|
|
87
|
-
|
|
88
|
-
# Second call should use cached value
|
|
89
|
-
value2, was_cached2 = self.cache.get_or_set("loader_key", data_loader)
|
|
90
|
-
|
|
91
|
-
# Verify results
|
|
92
|
-
self.assertEqual(value1, "loaded_value_1")
|
|
93
|
-
self.assertEqual(value2, "loaded_value_1") # Same value from cache
|
|
94
|
-
self.assertFalse(was_cached1) # First call was not cached
|
|
95
|
-
self.assertTrue(was_cached2) # Second call was cached
|
|
96
|
-
self.assertEqual(counter[0], 1) # Loader called exactly once
|
|
97
|
-
|
|
98
|
-
def test_cache_disabled(self):
|
|
99
|
-
"""Test cache behavior when disabled."""
|
|
100
|
-
# Create disabled cache
|
|
101
|
-
disabled_cache = SharedCache[str](
|
|
102
|
-
name="DisabledCache",
|
|
103
|
-
ttl=1.0,
|
|
104
|
-
enabled=False,
|
|
105
|
-
logger=logger
|
|
106
|
-
)
|
|
107
|
-
|
|
108
|
-
# Set a value
|
|
109
|
-
disabled_cache.set("disabled_key", "disabled_value")
|
|
110
|
-
|
|
111
|
-
# Attempt to get - should return None since cache is disabled
|
|
112
|
-
cached_value = disabled_cache.get("disabled_key")
|
|
113
|
-
self.assertIsNone(cached_value)
|
|
114
|
-
|
|
115
|
-
def test_cache_generic_typing(self):
|
|
116
|
-
"""Test cache with different data types."""
|
|
117
|
-
# Integer cache
|
|
118
|
-
int_cache = SharedCache[int](name="IntCache", ttl=1.0, enabled=True)
|
|
119
|
-
int_cache.set("int_key", 123)
|
|
120
|
-
self.assertEqual(int_cache.get("int_key"), 123)
|
|
121
|
-
|
|
122
|
-
# Dictionary cache
|
|
123
|
-
dict_cache = SharedCache[dict](name="DictCache", ttl=1.0, enabled=True)
|
|
124
|
-
dict_cache.set("dict_key", {"a": 1, "b": 2})
|
|
125
|
-
self.assertEqual(dict_cache.get("dict_key"), {"a": 1, "b": 2})
|
|
126
|
-
|
|
127
|
-
def test_cache_stats(self):
|
|
128
|
-
"""Test cache statistics."""
|
|
129
|
-
# Add some data
|
|
130
|
-
self.cache.set("stats_key1", "stats_value1")
|
|
131
|
-
self.cache.set("stats_key2", "stats_value2")
|
|
132
|
-
|
|
133
|
-
# Get stats
|
|
134
|
-
stats = self.cache.get_stats()
|
|
135
|
-
|
|
136
|
-
# Verify stats
|
|
137
|
-
self.assertEqual(stats["name"], "TestCache")
|
|
138
|
-
self.assertEqual(stats["enabled"], True)
|
|
139
|
-
self.assertEqual(stats["ttl_seconds"], 0.5)
|
|
140
|
-
self.assertEqual(stats["item_count"], 2)
|
|
141
|
-
self.assertIn("stats_key1", stats["first_20_keys"])
|
|
142
|
-
self.assertIn("stats_key2", stats["first_20_keys"])
|
|
143
|
-
self.assertEqual(stats["total_keys"], 2)
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
if __name__ == "__main__":
|
|
147
|
-
unittest.main()
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|