"""Provides S3 utility functions to facilitate tests.""" from typing import Any import boto3 from mypy_boto3_s3 import S3Client from mypy_boto3_s3.type_defs import PutObjectOutputTypeDef from tests.testutils.api_client.api_client import APIClient class S3Helper: """Provides S3 utility functions to facilitate tests.""" @staticmethod def _s3_client(creds: dict[str, str]) -> S3Client: """Initialize s3 client via boto3.""" return boto3.client( "s3", aws_access_key_id=creds["aws_access_key_id"], aws_secret_access_key=creds["aws_secret_access_key"], aws_session_token=creds["token"], ) @staticmethod def _upload_to_s3( upload_token: dict[str, Any], data: dict[str, Any], file_path: str, content_type: str, file_ext: str, ) -> PutObjectOutputTypeDef: """Upload to s3.""" client = S3Helper._s3_client(upload_token["credentials"]) return client.put_object( Bucket=upload_token["bucket"], Key="{}.{}".format(upload_token["filename"], file_ext), Body=open(file_path, "rb").read(), Metadata=data, ContentType=content_type, ) @staticmethod def s3_metadata( product_dict: dict[str, Any], file_ext: str, tuid: int | None, exclude_meta_key: str | None = None, is_correction: str = "0", ) -> dict[str, str]: """Create a dictionary of s3 metadata.""" s3_meta_dict = { "asset_type": file_ext, "product_id": str(product_dict["product_id"]), "upc": product_dict["upc"], "track_unique_id": "0" if tuid is None else str(tuid), "original_filename": "{}_file.{}".format(file_ext, file_ext), "is_correction": is_correction, } if exclude_meta_key: del s3_meta_dict[exclude_meta_key] return s3_meta_dict @staticmethod def upload_to_s3_check_response( asset_file: str, s3_meta_dict: dict[str, Any], file_ext: str, content_type: str, upload_token: dict[str, Any], ) -> None: """Upload a file to s3 and check response.""" s3_response = S3Helper._upload_to_s3( upload_token, s3_meta_dict, asset_file, content_type, file_ext ) s3_response_metadata = s3_response["ResponseMetadata"] assert s3_response_metadata["HTTPStatusCode"] == 200, ( "Result of S3 Upload was {}, expected 200.".format( s3_response_metadata["HTTPStatusCode"] ) ) # etag indicates asset was processed successfully assert s3_response_metadata["HTTPHeaders"]["etag"].replace('"', ""), ( "etag was empty" ) @staticmethod def get_upload_token( workstation_api_client: APIClient, asset_type: str ) -> dict[str, Any]: """Get upload token from s3 and check response.""" upload_token_response = workstation_api_client.upload_token(asset_type) assert upload_token_response.status_code == 200, ( "Result of GET was {}, expected 200.".format( upload_token_response.status_code ) ) result: dict[str, Any] = upload_token_response.json() return result @staticmethod def post_upload_token( workstation_api_client: APIClient, asset_type: str ) -> dict[str, Any]: """Get upload token from s3 and check response.""" upload_token_response = workstation_api_client.post_upload_token(asset_type) assert upload_token_response.status_code == 200, ( "Result of GET was {}, expected 200.".format( upload_token_response.status_code ) ) result: dict[str, Any] = upload_token_response.json() return result