fix: Add cloud storage test dependencies and proper skipping (Kimi's issues #2 & #3)

Fixed cloud storage test failures and missing test dependencies:

Issue #2: Cloud Storage Test Failures (16 tests)
- Added availability checks for boto3, google-cloud-storage, azure-storage-blob
- Added @pytest.mark.skipif decorators to all 16 cloud storage tests
- Tests now skip gracefully when dependencies not installed
- Result: 4 passed, 16 skipped (instead of 16 failed)

Issue #3: Missing Test Dependencies
Added to [dependency-groups] dev:
- boto3>=1.26.0 (AWS S3 testing)
- google-cloud-storage>=2.10.0 (Google Cloud Storage testing)
- azure-storage-blob>=12.17.0 (Azure Blob Storage testing)
- psutil>=5.9.0 (process utilities)
- numpy>=1.24.0 (numerical operations)
- starlette>=0.31.0 (HTTP transport testing)
- httpx>=0.24.0 (HTTP client)

Test Results:
- Before: 16 failed (AttributeError on missing modules)
- After: 4 passed, 16 skipped (clean skip with reason)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
yusyus
2026-02-08 12:45:48 +03:00
parent 0d39b04f13
commit 0573ef24f9
2 changed files with 49 additions and 0 deletions

View File

@@ -294,10 +294,24 @@ check_untyped_defs = false
[dependency-groups]
dev = [
# Core testing
"pytest>=8.4.2",
"pytest-asyncio>=0.24.0",
"pytest-cov>=7.0.0",
"coverage>=7.11.0",
# Code quality
"ruff>=0.14.13",
"mypy>=1.19.1",
# Test dependencies (Kimi's finding #3)
"psutil>=5.9.0", # Process utilities for testing
"numpy>=1.24.0", # Numerical operations
"starlette>=0.31.0", # HTTP transport testing
"httpx>=0.24.0", # HTTP client for testing
# Cloud storage testing (Kimi's finding #2)
"boto3>=1.26.0", # AWS S3
"google-cloud-storage>=2.10.0", # Google Cloud Storage
"azure-storage-blob>=12.17.0", # Azure Blob Storage
]

View File

@@ -17,11 +17,31 @@ from skill_seekers.cli.storage import (
StorageObject,
)
# Check if cloud storage dependencies are available
try:
import boto3
BOTO3_AVAILABLE = True
except ImportError:
BOTO3_AVAILABLE = False
try:
from google.cloud import storage
GCS_AVAILABLE = True
except ImportError:
GCS_AVAILABLE = False
try:
from azure.storage.blob import BlobServiceClient
AZURE_AVAILABLE = True
except ImportError:
AZURE_AVAILABLE = False
# ========================================
# Factory Tests
# ========================================
@pytest.mark.skipif(not BOTO3_AVAILABLE, reason="boto3 not installed")
def test_get_storage_adaptor_s3():
"""Test S3 adaptor factory."""
with patch('skill_seekers.cli.storage.s3_storage.boto3'):
@@ -29,6 +49,7 @@ def test_get_storage_adaptor_s3():
assert isinstance(adaptor, S3StorageAdaptor)
@pytest.mark.skipif(not GCS_AVAILABLE, reason="google-cloud-storage not installed")
def test_get_storage_adaptor_gcs():
"""Test GCS adaptor factory."""
with patch('skill_seekers.cli.storage.gcs_storage.storage'):
@@ -36,6 +57,7 @@ def test_get_storage_adaptor_gcs():
assert isinstance(adaptor, GCSStorageAdaptor)
@pytest.mark.skipif(not AZURE_AVAILABLE, reason="azure-storage-blob not installed")
def test_get_storage_adaptor_azure():
"""Test Azure adaptor factory."""
with patch('skill_seekers.cli.storage.azure_storage.BlobServiceClient'):
@@ -57,6 +79,7 @@ def test_get_storage_adaptor_invalid_provider():
# S3 Storage Tests
# ========================================
@pytest.mark.skipif(not BOTO3_AVAILABLE, reason="boto3 not installed")
@patch('skill_seekers.cli.storage.s3_storage.boto3')
def test_s3_upload_file(mock_boto3):
"""Test S3 file upload."""
@@ -82,6 +105,7 @@ def test_s3_upload_file(mock_boto3):
Path(tmp_path).unlink()
@pytest.mark.skipif(not BOTO3_AVAILABLE, reason="boto3 not installed")
@patch('skill_seekers.cli.storage.s3_storage.boto3')
def test_s3_download_file(mock_boto3):
"""Test S3 file download."""
@@ -103,6 +127,7 @@ def test_s3_download_file(mock_boto3):
)
@pytest.mark.skipif(not BOTO3_AVAILABLE, reason="boto3 not installed")
@patch('skill_seekers.cli.storage.s3_storage.boto3')
def test_s3_list_files(mock_boto3):
"""Test S3 file listing."""
@@ -138,6 +163,7 @@ def test_s3_list_files(mock_boto3):
assert files[0].etag == 'abc123'
@pytest.mark.skipif(not BOTO3_AVAILABLE, reason="boto3 not installed")
@patch('skill_seekers.cli.storage.s3_storage.boto3')
def test_s3_file_exists(mock_boto3):
"""Test S3 file existence check."""
@@ -153,6 +179,7 @@ def test_s3_file_exists(mock_boto3):
assert adaptor.file_exists('test.txt') is True
@pytest.mark.skipif(not BOTO3_AVAILABLE, reason="boto3 not installed")
@patch('skill_seekers.cli.storage.s3_storage.boto3')
def test_s3_get_file_url(mock_boto3):
"""Test S3 presigned URL generation."""
@@ -175,6 +202,7 @@ def test_s3_get_file_url(mock_boto3):
# GCS Storage Tests
# ========================================
@pytest.mark.skipif(not GCS_AVAILABLE, reason="google-cloud-storage not installed")
@patch('skill_seekers.cli.storage.gcs_storage.storage')
def test_gcs_upload_file(mock_storage):
"""Test GCS file upload."""
@@ -204,6 +232,7 @@ def test_gcs_upload_file(mock_storage):
Path(tmp_path).unlink()
@pytest.mark.skipif(not GCS_AVAILABLE, reason="google-cloud-storage not installed")
@patch('skill_seekers.cli.storage.gcs_storage.storage')
def test_gcs_download_file(mock_storage):
"""Test GCS file download."""
@@ -227,6 +256,7 @@ def test_gcs_download_file(mock_storage):
mock_blob.download_to_filename.assert_called_once()
@pytest.mark.skipif(not GCS_AVAILABLE, reason="google-cloud-storage not installed")
@patch('skill_seekers.cli.storage.gcs_storage.storage')
def test_gcs_list_files(mock_storage):
"""Test GCS file listing."""
@@ -257,6 +287,7 @@ def test_gcs_list_files(mock_storage):
# Azure Storage Tests
# ========================================
@pytest.mark.skipif(not AZURE_AVAILABLE, reason="azure-storage-blob not installed")
@patch('skill_seekers.cli.storage.azure_storage.BlobServiceClient')
def test_azure_upload_file(mock_blob_service):
"""Test Azure file upload."""
@@ -287,6 +318,7 @@ def test_azure_upload_file(mock_blob_service):
Path(tmp_path).unlink()
@pytest.mark.skipif(not AZURE_AVAILABLE, reason="azure-storage-blob not installed")
@patch('skill_seekers.cli.storage.azure_storage.BlobServiceClient')
def test_azure_download_file(mock_blob_service):
"""Test Azure file download."""
@@ -315,6 +347,7 @@ def test_azure_download_file(mock_blob_service):
assert Path(local_path).read_bytes() == b'test content'
@pytest.mark.skipif(not AZURE_AVAILABLE, reason="azure-storage-blob not installed")
@patch('skill_seekers.cli.storage.azure_storage.BlobServiceClient')
def test_azure_list_files(mock_blob_service):
"""Test Azure file listing."""
@@ -372,6 +405,7 @@ def test_base_adaptor_abstract():
# Integration-style Tests
# ========================================
@pytest.mark.skipif(not BOTO3_AVAILABLE, reason="boto3 not installed")
@patch('skill_seekers.cli.storage.s3_storage.boto3')
def test_upload_directory(mock_boto3):
"""Test directory upload."""
@@ -396,6 +430,7 @@ def test_upload_directory(mock_boto3):
assert mock_client.upload_file.call_count == 3
@pytest.mark.skipif(not BOTO3_AVAILABLE, reason="boto3 not installed")
@patch('skill_seekers.cli.storage.s3_storage.boto3')
def test_download_directory(mock_boto3):
"""Test directory download."""