24 self._storage: Dict[pathlib.Path, S3Object] = {}
27 def _generate_etag(data):
28 return hashlib.md5(data).hexdigest()
34 user_defined_meta: Mapping[str, str] = {},
35 last_modified: Optional[Union[dt.datetime, str]] =
None,
37 key_path = pathlib.Path(key)
38 if last_modified
is None:
40 last_modified = dt.datetime.now().replace(tzinfo=tz.tzlocal()).isoformat()
41 elif isinstance(last_modified, dt.datetime):
42 last_modified = last_modified.isoformat()
47 'Last-Modified': last_modified,
48 'Size': str(sys.getsizeof(data)),
51 meta.update(user_defined_meta)
53 self._storage[key_path] =
S3Object(data, meta)
56 def get_object(self, key: str) -> Optional[S3Object]:
57 key_path = pathlib.Path(key)
58 return self._storage.get(key_path)
60 def get_objects(self, parent_dir='') -> Dict[str, S3Object]:
61 all_objects = {str(key_path): value
for key_path, value
in self._storage.items()}
66 return {key: value
for key, value
in all_objects.items()
if key.startswith(str(pathlib.Path(parent_dir)))}
68 def delete_object(self, key) -> Optional[S3Object]:
69 key = pathlib.Path(key)
70 if key
not in self._storage:
72 return self._storage.pop(key)
76 def __init__(self, mockserver, s3_mock_storage, mock_base_url):
81 def _get_bucket_name(self, request):
82 return request.headers[
'Host'].split(
'.')[0]
84 def _extract_key(self, request):
85 return request.path[len(self.
_base_url) + 1 :]
87 def _generate_get_objects_result(
89 s3_objects_dict: Dict[str, S3Object],
91 marker: Optional[str],
93 empty_result = {
'result_objects': [],
'is_truncated':
False}
94 keys = list(s3_objects_dict.keys())
100 if marker > keys[-1]:
102 for i, key
in enumerate(keys):
107 result_objects = [s3_objects_dict[key]
for key
in keys[from_index : from_index + max_keys]]
108 is_truncated = from_index + max_keys >= len(keys)
109 return {
'result_objects': result_objects,
'is_truncated': is_truncated}
111 def _generate_get_objects_xml(
113 s3_objects: List[S3Object],
116 max_keys: Optional[int],
117 marker: Optional[str],
121 for s3_object
in s3_objects:
124 <ETag>{s3_object.meta['ETag']}</ETag>
125 <Key>{s3_object.meta['Key']}</Key>
126 <LastModified>{s3_object.meta['Last-Modified']}</LastModified>
127 <Size>{s3_object.meta['Size']}</Size>
128 <StorageClass>STANDARD</StorageClass>
132 <?xml version="1.0" encoding="UTF-8"?>
134 <Name>{bucket_name}</Name>
135 <Prefix>{prefix}</Prefix>
136 <Marker>{marker or ''}</Marker>
137 <MaxKeys>{max_keys or ''}</MaxKeys>
138 <IsTruncated>{is_truncated}</IsTruncated>
143 def get_object(self, request):
148 s3_object = bucket_storage.get_object(key)
150 return self.
_mockserver.make_response(
'Object not found', 404)
154 headers=s3_object.meta,
157 def put_object(self, request):
162 data = request.get_data()
164 user_defined_meta = {}
165 for meta_key, meta_value
in request.headers.items():
167 if meta_key.startswith(
'x-amz-meta-'):
168 user_defined_meta[meta_key] = meta_value
170 meta = bucket_storage.put_object(key, data, user_defined_meta)
171 return self.
_mockserver.make_response(
'OK', 200, headers=meta)
173 def copy_object(self, request):
176 source_bucket_name, source_key = request.headers.get(
180 src_bucket_storage = self.
_storage[source_bucket_name]
181 dst_bucket_storage = self.
_storage[dest_bucket_name]
183 src_obj = src_bucket_storage.get_object(source_key)
184 src_data = src_obj.data
185 src_meta = src_obj.meta
186 meta = dst_bucket_storage.put_object(key, src_data, src_meta)
187 return self.
_mockserver.make_response(
'OK', 200, headers=meta)
189 def get_objects(self, request):
190 prefix = request.query[
'prefix']
192 max_keys = int(request.query.get(
'max-keys', 1000))
193 marker = request.query.get(
'marker')
196 bucket_storage = self.
_storage[bucket_name]
198 s3_objects_dict = bucket_storage.get_objects(parent_dir=prefix)
200 s3_objects_dict=s3_objects_dict,
205 s3_objects=result[
'result_objects'],
206 bucket_name=bucket_name,
210 is_truncated=result[
'is_truncated'],
212 return self.
_mockserver.make_response(result_xml, 200)
214 def delete_object(self, request):
219 bucket_storage.delete_object(key)
223 def get_object_head(self, request):
228 s3_object = bucket_storage.get_object(key)
230 return self.
_mockserver.make_response(
'Object not found', 404)
234 headers=s3_object.meta,