"""Unit tests for S3 connector.""" from unittest.mock import Mock, patch from botocore.exceptions import ClientError from adjustments_json_validation.connectors.s3 import ( S3Connector, get_s3_client, get_s3_connector, ) class TestS3ConnectorInit: """Tests for S3Connector initialization.""" def test_init_stores_s3_client(self): """Test S3Connector stores S3 client reference.""" mock_client = Mock() connector = S3Connector(mock_client) assert connector.s3_client is mock_client class TestS3ConnectorUploadObject: """Tests for S3Connector.upload_object method.""" def test_upload_object_returns_true_when_file_upload_success(self): """Test upload_object returns True when file is uploadede to s3 successfully.""" mock_client = Mock() mock_client.head_object.return_value = {'ContentLength': 1024} connector = S3Connector(mock_client) result = connector.upload_object( 'test-bucket', 'path/to/file.csv', 'file.csv', '123456' ) assert result is True mock_client.upload_file.assert_called_once_with( Filename='path/to/file.csv', Bucket='test-bucket', Key='file.csv', ExtraArgs={ 'ExpectedBucketOwner': '123456', }, ) def test_upload_object_returns_false_for_403(self): """Test upload_object returns False when s3 bucket don't have an access.""" mock_client = Mock() mock_client.upload_file.side_effect = ClientError( {'ResponseMetadata': {'HTTPStatusCode': 403}}, 'PutObject' ) connector = S3Connector(mock_client) result = connector.upload_object( 'test-bucket', 'path/to/file.csv', 'file.csv', '123456' ) assert result is False class TestGetS3Client: """Tests for get_s3_client function.""" @patch('adjustments_json_validation.connectors.s3.boto3.client') def test_get_s3_client_creates_client_with_default_config(self, mock_boto_client): """Test get_s3_client creates boto3 S3 client with default config.""" mock_client = Mock() mock_boto_client.return_value = mock_client result = get_s3_client() assert result is mock_client mock_boto_client.assert_called_once() call_args = mock_boto_client.call_args assert call_args[0][0] == 's3' # Verify config has signature_version config = call_args[1]['config'] assert config.signature_version == 's3v4' @patch('adjustments_json_validation.connectors.s3.boto3.client') def test_get_s3_client_accepts_custom_config(self, mock_boto_client): """Test get_s3_client accepts custom Config.""" from botocore.client import Config custom_config = Config(signature_version='s3', region_name='us-west-2') mock_client = Mock() mock_boto_client.return_value = mock_client result = get_s3_client(config=custom_config) assert result is mock_client mock_boto_client.assert_called_once_with('s3', config=custom_config) class TestGetS3Connector: """Tests for get_s3_connector function.""" def test_get_s3_connector_with_provided_client(self): """Test get_s3_connector uses provided S3 client.""" mock_client = Mock() connector = get_s3_connector(s3_client=mock_client) assert isinstance(connector, S3Connector) assert connector.s3_client is mock_client @patch('adjustments_json_validation.connectors.s3.get_s3_client') def test_get_s3_connector_creates_default_client(self, mock_get_client): """Test get_s3_connector creates default client when none provided.""" mock_client = Mock() mock_get_client.return_value = mock_client connector = get_s3_connector() assert isinstance(connector, S3Connector) assert connector.s3_client is mock_client mock_get_client.assert_called_once() @patch('adjustments_json_validation.connectors.s3.get_s3_client') def test_get_s3_connector_without_client_argument(self, mock_get_client): """Test get_s3_connector works when called without arguments.""" mock_client = Mock() mock_get_client.return_value = mock_client connector = get_s3_connector() assert connector.s3_client is mock_client