MemPrepMate / tests /unit /test_s3_config.py
Christian Kniep
update to v2
5d3ee93
"""
Unit tests for S3Config module.
Feature: 015-sqlite-s3-backup
"""
import os
import pytest
from unittest.mock import patch, MagicMock
from src.services.s3_config import (
S3Config,
S3CredentialsError,
S3BucketNotFoundError,
S3ConnectionError
)
class TestS3ConfigFromEnv:
"""Tests for S3Config.from_env() factory method."""
@patch.dict(os.environ, {
'S3_BACKUP_ENABLED': 'true',
'S3_BUCKET_NAME': 'test-bucket',
'S3_ACCESS_KEY': 'test-access-key',
'S3_SECRET_KEY': 'test-secret-key',
'S3_REGION': 'us-west-2'
})
def test_from_env_valid_config(self):
"""Test loading valid S3 configuration from environment."""
config = S3Config.from_env()
assert config.enabled is True
assert config.bucket == 'test-bucket'
assert config.access_key == 'test-access-key'
assert config.secret_key == 'test-secret-key'
assert config.region == 'us-west-2'
assert config.upload_timeout == 60
assert config.download_timeout == 30
assert config.debounce_seconds == 300
@patch.dict(os.environ, {}, clear=True)
def test_from_env_missing_config(self):
"""Test that missing S3_BACKUP_ENABLED defaults to disabled."""
config = S3Config.from_env()
assert config.enabled is False
@patch.dict(os.environ, {
'S3_BACKUP_ENABLED': 'true',
'S3_BUCKET_NAME': 'test-bucket',
# Missing S3_ACCESS_KEY and S3_SECRET_KEY
}, clear=True)
def test_from_env_partial_config(self):
"""Test that partial configuration disables the feature with warning."""
config = S3Config.from_env()
assert config.enabled is False
class TestS3ConfigValidateCredentials:
"""Tests for S3Config.validate_credentials() method."""
@patch('boto3.client')
def test_validate_credentials_success(self, mock_boto_client):
"""Test successful credential validation."""
# Setup mock
mock_s3 = MagicMock()
mock_boto_client.return_value = mock_s3
mock_s3.head_bucket.return_value = {}
# Create config
config = S3Config(
enabled=True,
bucket='test-bucket',
access_key='test-key',
secret_key='test-secret'
)
# Validate
result = config.validate_credentials()
assert result is True
mock_s3.head_bucket.assert_called_once_with(Bucket='test-bucket')
@patch('boto3.client')
def test_validate_credentials_bucket_not_found(self, mock_boto_client):
"""Test validation with non-existent bucket."""
# Setup mock
mock_s3 = MagicMock()
mock_boto_client.return_value = mock_s3
from botocore.exceptions import ClientError
mock_s3.head_bucket.side_effect = ClientError(
{'Error': {'Code': '404'}},
'HeadBucket'
)
# Create config
config = S3Config(
enabled=True,
bucket='nonexistent-bucket',
access_key='test-key',
secret_key='test-secret'
)
# Validate
result = config.validate_credentials()
assert result is False
@patch('boto3.client')
def test_validate_credentials_access_denied(self, mock_boto_client):
"""Test validation with invalid credentials."""
# Setup mock
mock_s3 = MagicMock()
mock_boto_client.return_value = mock_s3
from botocore.exceptions import ClientError
mock_s3.head_bucket.side_effect = ClientError(
{'Error': {'Code': '403'}},
'HeadBucket'
)
# Create config
config = S3Config(
enabled=True,
bucket='test-bucket',
access_key='invalid-key',
secret_key='invalid-secret'
)
# Validate
result = config.validate_credentials()
assert result is False