Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,9 @@ cython_debug/
# Built Visual Studio Code Extensions
*.vsix

# Claude Code settings
.claude/*

# Logs
logs
*.log
Expand Down
2,087 changes: 2,087 additions & 0 deletions poetry.lock

Large diffs are not rendered by default.

167 changes: 167 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,167 @@
[tool.poetry]
name = "aws-elasticache-examples"
version = "0.1.0"
description = "AWS ElastiCache examples and demos collection"
authors = ["AWS ElastiCache Team <aws-elasticache-examples@amazon.com>"]
readme = "README.md"
packages = [
{include = "compression-example"},
{include = "database-caching"},
{include = "dynamodb-elasticache-integration"},
{include = "session-store"},
{include = "lambda-feature-store"},
{include = "glide-samples"},
{include = "webinars"},
{include = "tools"},
{include = "blogs"},
]

[tool.poetry.dependencies]
python = "^3.11"
# Core dependencies used across examples
boto3 = "^1.34.29"
redis = "^5.0.1"
valkey-glide = "^1.0.0"
# Common utility libraries
numpy = "^1.24.0"
lz4 = "^4.0.0"
pymysql = "^1.1.1"
# Web framework dependencies
flask = "^2.3.0"
streamlit = "^1.28.0"
# Data processing
pandas = "^2.0.0"
# Environment management
python-dotenv = "^1.0.0"
# Data validation
pydantic = "^2.6.0"

[tool.poetry.group.dev.dependencies]
pytest = "^7.4.0"
pytest-cov = "^4.1.0"
pytest-mock = "^3.11.0"
pytest-asyncio = "^0.21.0"
black = "^23.0.0"
isort = "^5.12.0"
flake8 = "^6.0.0"
mypy = "^1.5.0"


[build-system]
requires = ["poetry-core"]
build-backend = "poetry.core.masonry.api"

[tool.pytest.ini_options]
testpaths = ["tests"]
python_files = ["test_*.py", "*_test.py"]
python_classes = ["Test*"]
python_functions = ["test_*"]
addopts = [
"--cov=.",
"--cov-report=html:htmlcov",
"--cov-report=xml:coverage.xml",
"--cov-report=term-missing",
"--cov-fail-under=80",
"--strict-markers",
"--strict-config",
"-ra",
]
markers = [
"unit: marks tests as unit tests",
"integration: marks tests as integration tests",
"slow: marks tests as slow running",
]
filterwarnings = [
"ignore::UserWarning",
"ignore::DeprecationWarning",
]

[tool.coverage.run]
source = [
"compression-example",
"database-caching",
"dynamodb-elasticache-integration",
"session-store",
"lambda-feature-store",
"glide-samples",
"webinars",
"tools",
"blogs",
]
omit = [
"tests/*",
"*/tests/*",
"*/test_*",
"*/__pycache__/*",
"*/venv/*",
"*/env/*",
".venv/*",
"setup.py",
]

[tool.coverage.report]
show_missing = true
skip_covered = false
exclude_lines = [
"pragma: no cover",
"def __repr__",
"if self.debug:",
"if settings.DEBUG",
"raise AssertionError",
"raise NotImplementedError",
"if 0:",
"if __name__ == .__main__.:",
"class .*\\bProtocol\\):",
"@(abc\\.)?abstractmethod",
]

[tool.coverage.html]
directory = "htmlcov"

[tool.coverage.xml]
output = "coverage.xml"

[tool.black]
line-length = 88
target-version = ['py311']
include = '\.pyi?$'
extend-exclude = '''
/(
# directories
\.eggs
| \.git
| \.hg
| \.mypy_cache
| \.tox
| \.venv
| _build
| buck-out
| build
| dist
)/
'''

[tool.isort]
profile = "black"
multi_line_output = 3
line_length = 88
known_first_party = ["compression_example", "database_caching", "dynamodb_elasticache_integration", "session_store", "lambda_feature_store", "glide_samples", "webinars", "tools", "blogs"]

[tool.mypy]
python_version = "3.11"
warn_return_any = true
warn_unused_configs = true
disallow_untyped_defs = true
disallow_incomplete_defs = true
check_untyped_defs = true
disallow_untyped_decorators = true
no_implicit_optional = true
warn_redundant_casts = true
warn_unused_ignores = true
warn_no_return = true
warn_unreachable = true
strict_equality = true

[[tool.mypy.overrides]]
module = ["redis.*", "valkey.*", "pymysql.*", "lz4.*"]
ignore_missing_imports = true
1 change: 1 addition & 0 deletions tests/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# Test package initialization
173 changes: 173 additions & 0 deletions tests/conftest.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,173 @@
"""Shared pytest fixtures for all tests."""
import os
import tempfile
import shutil
from pathlib import Path
from typing import Dict, Any, Generator
from unittest.mock import Mock, MagicMock

import pytest


@pytest.fixture
def temp_dir() -> Generator[Path, None, None]:
"""Provide a temporary directory for tests."""
temp_dir = tempfile.mkdtemp()
yield Path(temp_dir)
shutil.rmtree(temp_dir)


@pytest.fixture
def sample_data_dir(temp_dir: Path) -> Path:
"""Create a temporary directory with sample test data files."""
data_dir = temp_dir / "sample_data"
data_dir.mkdir()

# Create sample files
(data_dir / "test.txt").write_text("sample content")
(data_dir / "config.json").write_text('{"key": "value"}')

return data_dir


@pytest.fixture
def mock_env_vars() -> Generator[Dict[str, str], None, None]:
"""Provide mock environment variables and restore original ones after test."""
original_env = os.environ.copy()
test_env = {
"AWS_REGION": "us-east-1",
"AWS_ACCESS_KEY_ID": "test-key",
"AWS_SECRET_ACCESS_KEY": "test-secret",
"REDIS_HOST": "localhost",
"REDIS_PORT": "6379",
}
os.environ.update(test_env)
yield test_env
os.environ.clear()
os.environ.update(original_env)


@pytest.fixture
def mock_redis_client():
"""Mock Redis client for testing."""
mock_client = MagicMock()
mock_client.ping.return_value = True
mock_client.get.return_value = None
mock_client.set.return_value = True
mock_client.delete.return_value = 1
mock_client.exists.return_value = False
mock_client.keys.return_value = []
return mock_client


@pytest.fixture
def mock_boto3_client():
"""Mock boto3 client for AWS services."""
mock_client = MagicMock()
mock_client.describe_cache_clusters.return_value = {
'CacheClusters': [
{
'CacheClusterId': 'test-cluster',
'CacheClusterStatus': 'available',
'Engine': 'redis',
'CacheNodeType': 'cache.t3.micro'
}
]
}
return mock_client


@pytest.fixture
def sample_config() -> Dict[str, Any]:
"""Provide sample configuration data for tests."""
return {
"database": {
"host": "localhost",
"port": 5432,
"name": "testdb",
"user": "testuser",
"password": "testpass"
},
"cache": {
"host": "localhost",
"port": 6379,
"db": 0,
"timeout": 30
},
"app": {
"debug": True,
"log_level": "DEBUG"
}
}


@pytest.fixture
def mock_logger():
"""Mock logger for testing."""
return MagicMock()


@pytest.fixture(autouse=True)
def reset_modules():
"""Reset imported modules state between tests."""
yield
# Clean up any module-level state if needed


@pytest.fixture
def mock_aws_credentials():
"""Mock AWS credentials for testing."""
credentials = {
'aws_access_key_id': 'test-access-key',
'aws_secret_access_key': 'test-secret-key',
'region_name': 'us-east-1'
}
return credentials


@pytest.fixture
def mock_valkey_client():
"""Mock Valkey/Glide client for testing."""
mock_client = MagicMock()
mock_client.ping.return_value = b"PONG"
mock_client.get.return_value = None
mock_client.set.return_value = b"OK"
mock_client.delete.return_value = 1
mock_client.exists.return_value = 0
return mock_client


@pytest.fixture
def sample_cache_data() -> Dict[str, Any]:
"""Provide sample cache data for tests."""
return {
"user:123": {"name": "John Doe", "email": "john@example.com"},
"session:abc": {"user_id": 123, "expires": "2024-12-31T23:59:59"},
"counter:views": "1000",
"config:app": {"version": "1.0.0", "debug": False}
}


@pytest.fixture
def mock_database_connection():
"""Mock database connection for testing."""
mock_conn = MagicMock()
mock_cursor = MagicMock()
mock_conn.cursor.return_value = mock_cursor
mock_cursor.fetchone.return_value = None
mock_cursor.fetchall.return_value = []
mock_cursor.execute.return_value = None
return mock_conn


@pytest.fixture(scope="session")
def docker_compose_file():
"""Path to docker-compose file for integration tests."""
return Path(__file__).parent.parent / "docker-compose.test.yml"


# Markers for test categorization
pytestmark = [
pytest.mark.filterwarnings("ignore::DeprecationWarning"),
pytest.mark.filterwarnings("ignore::UserWarning"),
]
1 change: 1 addition & 0 deletions tests/integration/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# Integration tests package
Loading