1
+ import os
2
+ import pytest
3
+ import boto3
4
+ from moto import mock_aws
5
+ from app .utils import upload_to_s3 , get_from_s3 , delete_from_s3
6
+
7
+ @pytest .fixture (scope = "function" )
8
+ def aws_credentials ():
9
+ """Mocked AWS Credentials for moto."""
10
+ os .environ ["AWS_ACCESS_KEY_ID" ] = "testing"
11
+ os .environ ["AWS_SECRET_ACCESS_KEY" ] = "testing"
12
+ os .environ ["AWS_SECURITY_TOKEN" ] = "testing"
13
+ os .environ ["AWS_SESSION_TOKEN" ] = "testing"
14
+ os .environ ["AWS_DEFAULT_REGION" ] = "us-east-1"
15
+ os .environ ["S3_BUCKET_NAME" ] = "test-bucket"
16
+
17
+ @pytest .fixture (scope = "function" )
18
+ def mocked_aws (aws_credentials ):
19
+ """
20
+ Mock all AWS interactions
21
+ Requires self creation of boto3 clients
22
+ """
23
+ with mock_aws ():
24
+ yield
25
+
26
+ @pytest .fixture
27
+ def mock_image_png ():
28
+ """Fixture for a 1x1 black pixel PNG."""
29
+ return b'\x89 PNG\r \n \x1a \n \x00 \x00 \x00 \r IHDR\x00 \x00 \x00 \x01 \x00 \x00 \x00 \x01 \x08 \x06 \x00 \x00 \x00 \x1f \x15 \xc4 \x89 \x00 \x00 \x00 \x0c IDATx\x9c c`\x00 \x01 \x00 \x00 \x05 \x00 \x01 \xa2 \x99 V\xdd \x00 \x00 \x00 \x00 IEND\xae B`\x82 '
30
+
31
+ @pytest .fixture
32
+ def mock_png_s3_keys ():
33
+ return "questions/qid1/0.png"
34
+
35
+ @pytest .fixture
36
+ def mock_image_jpeg ():
37
+ """Fixture for a 1x1 black pixel JPEG."""
38
+ jpeg_data = b'' .join ([
39
+ b'\xff \xd8 ' , # SOI
40
+ b'\xff \xe0 \x00 \x10 ' , # APP0 segment (JFIF)
41
+ b'JFIF\x00 \x01 \x01 \x00 \x00 \x01 \x00 \x01 \x00 \x00 ' ,
42
+ b'\xff \xdb \x00 C' , b'\x00 ' * 67 , # DQT
43
+ b'\xff \xc0 \x00 \x11 ' , # SOF0 (baseline DCT)
44
+ b'\x08 \x00 \x01 \x00 \x01 \x01 \x01 \x11 \x00 ' ,
45
+ b'\xff \xc4 \x00 \x14 ' , b'\x00 ' * 20 , # DHT
46
+ b'\xff \xda \x00 \x0c ' , # SOS
47
+ b'\x01 \x01 \x00 \x00 ?\x00 ' ,
48
+ b'\x00 \x00 ' , # dummy compressed data
49
+ b'\xff \xd9 ' # EOI
50
+ ])
51
+ return jpeg_data
52
+
53
+ @pytest .fixture
54
+ def mock_jpeg_s3_keys ():
55
+ return "questions/qid2/0.jpeg"
56
+
57
+ @mock_aws
58
+ def test_upload_to_s3_empty_list ():
59
+ """Tests that upload_to_s3 handles an empty list without error."""
60
+ try :
61
+ upload_to_s3 ([])
62
+ except Exception as e :
63
+ pytest .fail (f"upload_to_s3 raised an exception with an empty list: { e } " )
64
+
65
+ @mock_aws
66
+ def test_get_from_s3_empty_list ():
67
+ """Tests that get_from_s3 handles an empty list correctly."""
68
+ result = get_from_s3 ([])
69
+ assert result == []
70
+
71
+ @mock_aws
72
+ def test_delete_from_s3_empty_list ():
73
+ """Tests that delete_from_s3 handles an empty list without error."""
74
+ try :
75
+ delete_from_s3 ([])
76
+ except Exception as e :
77
+ pytest .fail (f"delete_from_s3 raised an exception with an empty list: { e } " )
78
+
79
+ @mock_aws
80
+ def test_s3_upload_get_delete_integration (mocked_aws , mock_image_png , mock_png_s3_keys , mock_image_jpeg , mock_jpeg_s3_keys ):
81
+ """
82
+ Tests the full upload -> get -> delete cycle with image bytes using fixtures.
83
+ """
84
+ s3_client = boto3 .client ("s3" )
85
+ s3_client .create_bucket (Bucket = os .getenv ("S3_BUCKET_NAME" ))
86
+
87
+ # 1. Upload
88
+ files_to_upload = [
89
+ (mock_image_png , mock_png_s3_keys ),
90
+ (mock_image_jpeg , mock_jpeg_s3_keys )
91
+ ]
92
+ upload_to_s3 (files_to_upload )
93
+
94
+ # 2. Get and Verify
95
+ retrieved_data = get_from_s3 ([mock_png_s3_keys , mock_jpeg_s3_keys ])
96
+ assert len (retrieved_data ) == 2
97
+ assert retrieved_data [0 ] == mock_image_png
98
+ assert retrieved_data [1 ] == mock_image_jpeg
99
+
100
+ # 3. Delete
101
+ delete_from_s3 ([mock_png_s3_keys , mock_jpeg_s3_keys ])
102
+
103
+ # 4. Verify Deletion
104
+ # Check that getting the objects now raises an error
105
+ with pytest .raises (s3_client .exceptions .NoSuchKey ):
106
+ s3_client .get_object (Bucket = os .getenv ("S3_BUCKET_NAME" ), Key = mock_png_s3_keys )
107
+ with pytest .raises (s3_client .exceptions .NoSuchKey ):
108
+ s3_client .get_object (Bucket = os .getenv ("S3_BUCKET_NAME" ), Key = mock_jpeg_s3_keys )
0 commit comments