1+ """
2+ Test the `Bucket` class in `src/gardenlinux/s3/bucket.py` by using
3+ mock AWS interactions provided by the `moto` module.
4+
5+ The `@mock_aws` decorator `moto` provides ensures a fresh
6+ but fake AWS-like environment.
7+ """
8+
9+ import io
10+ import pytest
11+ import boto3
12+ from moto import mock_aws
13+ from pathlib import Path
14+
15+ from gardenlinux .s3 .bucket import Bucket
16+
17+
18+ BUCKET_NAME = "test-bucket"
19+ REGION = "us-east-1"
20+
21+
22+
23+ @mock_aws
24+ def test_objects_empty ():
25+ """
26+ List objects from empty bucket.
27+ """
28+ # Arrange
29+ s3 = boto3 .resource ("s3" , region_name = REGION )
30+ s3 .create_bucket (Bucket = BUCKET_NAME )
31+
32+ # Act
33+ bucket = Bucket (bucket_name = BUCKET_NAME , s3_resource_config = {"region_name" : REGION })
34+ objects = list (bucket .objects )
35+
36+ # Assert
37+ assert objects == []
38+
39+
40+ @mock_aws
41+ def test_upload_file_and_list (tmp_path ):
42+ """
43+ Create a fake file in a temporary directory, upload and try
44+ to list it
45+ """
46+ # Arrange
47+ s3 = boto3 .resource ("s3" , region_name = REGION )
48+ s3 .create_bucket (Bucket = BUCKET_NAME )
49+
50+ test_file = tmp_path / "example.txt"
51+ test_file .write_text ("hello moto" )
52+
53+ # Act
54+ bucket = Bucket (bucket_name = BUCKET_NAME , s3_resource_config = {"region_name" : REGION })
55+ bucket .upload_file (str (test_file ), "example.txt" )
56+
57+ all_keys = [obj .key for obj in bucket .objects ]
58+
59+ # Assert
60+ assert "example.txt" in all_keys
61+
62+
63+ @mock_aws
64+ def test_download_file (tmp_path ):
65+ """
66+ Try to download a file pre-existing in the bucket
67+ """
68+ # Arrange
69+ s3 = boto3 .resource ("s3" , region_name = REGION )
70+ s3 .create_bucket (Bucket = BUCKET_NAME )
71+ s3 .Object (BUCKET_NAME , "file.txt" ).put (Body = b"some data" )
72+
73+ # Act
74+ bucket = Bucket (bucket_name = BUCKET_NAME , s3_resource_config = {"region_name" : REGION })
75+
76+ target_path = tmp_path / "downloaded.txt"
77+ bucket .download_file ("file.txt" , str (target_path ))
78+
79+ # Assert
80+ assert target_path .read_text () == "some data"
81+
82+
83+ @mock_aws
84+ def test_upload_fileobj ():
85+ """
86+ Upload a file-like in-memory object to the bucket
87+ """
88+ # Arrange
89+ s3 = boto3 .resource ("s3" , region_name = REGION )
90+ s3 .create_bucket (Bucket = BUCKET_NAME )
91+
92+ # Act
93+ # Create in-memory binary stream (file content)
94+ data = io .BytesIO (b"Test Data" )
95+ bucket = Bucket (bucket_name = BUCKET_NAME , s3_resource_config = {"region_name" : REGION })
96+ bucket .upload_fileobj (data , "binary.obj" )
97+
98+ obj = s3 .Object (BUCKET_NAME , "binary.obj" ).get ()
99+
100+ # Assert
101+ assert obj ["Body" ].read () == b"Test Data"
102+
103+
104+ @mock_aws
105+ def test_download_fileobj ():
106+ """
107+ Download data into a in-memory object
108+ """
109+ # Arange
110+ s3 = boto3 .resource ("s3" , region_name = REGION )
111+ s3 .create_bucket (Bucket = BUCKET_NAME )
112+ # Put some object in the bucket
113+ s3 .Object (BUCKET_NAME , "somekey" ).put (Body = b"123abc" )
114+
115+ # Act
116+ bucket = Bucket (bucket_name = BUCKET_NAME , s3_resource_config = {"region_name" : REGION })
117+
118+ # Create empty in-memory bytestream to act as a writable file
119+ output = io .BytesIO ()
120+ bucket .download_fileobj ("somekey" , output )
121+
122+ # Reset binary cursor to prepare for read
123+ output .seek (0 )
124+
125+ # Assert
126+ assert output .read () == b"123abc"
127+
128+
129+ @mock_aws
130+ def test_getattr_delegates ():
131+ """
132+ Verify that attribute access is delegated to the underlying boto3 Bucket.
133+
134+ This checks that accessing e.g. `.name` on our custom Bucket works by forwarding
135+ the call to the real boto3 bucket.
136+ """
137+ # Arrange
138+ s3 = boto3 .resource ("s3" , region_name = REGION )
139+ s3 .create_bucket (Bucket = BUCKET_NAME )
140+
141+ # Act
142+ bucket = Bucket (bucket_name = BUCKET_NAME , s3_resource_config = {"region_name" : REGION })
143+
144+ # Assert
145+ # __getattr__ should delegate this to the underlying boto3 Bucket object
146+ assert bucket .name == BUCKET_NAME
0 commit comments