fakes3test10 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.gitignore +18 -0
- data/CONTRIBUTING.md +50 -0
- data/DEPLOY_README.md +18 -0
- data/Dockerfile +13 -0
- data/Gemfile +4 -0
- data/ISSUE_TEMPLATE.md +9 -0
- data/Makefile +7 -0
- data/PULL_REQUEST_TEMPLATE.md +9 -0
- data/README.md +42 -0
- data/Rakefile +18 -0
- data/bin/fakes3 +6 -0
- data/fakes3.gemspec +35 -0
- data/lib/fakes3.rb +3 -0
- data/lib/fakes3/bucket.rb +65 -0
- data/lib/fakes3/bucket_query.rb +11 -0
- data/lib/fakes3/cli.rb +71 -0
- data/lib/fakes3/errors.rb +46 -0
- data/lib/fakes3/file_store.rb +320 -0
- data/lib/fakes3/rate_limitable_file.rb +21 -0
- data/lib/fakes3/s3_object.rb +19 -0
- data/lib/fakes3/server.rb +585 -0
- data/lib/fakes3/sorted_object_list.rb +137 -0
- data/lib/fakes3/unsupported_operation.rb +4 -0
- data/lib/fakes3/util.rb +8 -0
- data/lib/fakes3/version.rb +3 -0
- data/lib/fakes3/xml_adapter.rb +222 -0
- data/lib/fakes3/xml_parser.rb +16 -0
- data/static/button.svg +4 -0
- data/static/logo.png +0 -0
- data/test/aws_sdk_commands_test.rb +98 -0
- data/test/aws_sdk_v2_commands_test.rb +65 -0
- data/test/boto_test.rb +25 -0
- data/test/botocmd.py +87 -0
- data/test/cli_test.rb +18 -0
- data/test/local_s3_cfg +34 -0
- data/test/minitest_helper.rb +46 -0
- data/test/post_test.rb +58 -0
- data/test/right_aws_commands_test.rb +219 -0
- data/test/s3_commands_test.rb +208 -0
- data/test/s3cmd_test.rb +52 -0
- data/test/test_helper.rb +6 -0
- metadata +270 -0
@@ -0,0 +1,137 @@
|
|
1
|
+
require 'set'
|
2
|
+
module FakeS3
|
3
|
+
class S3MatchSet
|
4
|
+
attr_accessor :matches,:is_truncated,:common_prefixes
|
5
|
+
def initialize
|
6
|
+
@matches = []
|
7
|
+
@is_truncated = false
|
8
|
+
@common_prefixes = []
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
# This class has some of the semantics necessary for how buckets can return
|
13
|
+
# their items
|
14
|
+
#
|
15
|
+
# It is currently implemented naively as a sorted set + hash If you are going
|
16
|
+
# to try to put massive lists inside buckets and ls them, you will be sorely
|
17
|
+
# disappointed about this performance.
|
18
|
+
class SortedObjectList
|
19
|
+
|
20
|
+
def initialize
|
21
|
+
@sorted_set = SortedSet.new
|
22
|
+
@object_map = {}
|
23
|
+
@mutex = Mutex.new
|
24
|
+
end
|
25
|
+
|
26
|
+
def count
|
27
|
+
@sorted_set.count
|
28
|
+
end
|
29
|
+
|
30
|
+
def find(object_name)
|
31
|
+
@object_map[object_name]
|
32
|
+
end
|
33
|
+
|
34
|
+
# Add an S3 object into the sorted list
|
35
|
+
def add(s3_object)
|
36
|
+
return if !s3_object
|
37
|
+
|
38
|
+
@object_map[s3_object.name] = s3_object
|
39
|
+
@sorted_set << s3_object
|
40
|
+
end
|
41
|
+
|
42
|
+
def remove(s3_object)
|
43
|
+
return if !s3_object
|
44
|
+
|
45
|
+
@object_map.delete(s3_object.name)
|
46
|
+
@sorted_set.delete(s3_object)
|
47
|
+
end
|
48
|
+
|
49
|
+
# Return back a set of matches based on the passed in options
|
50
|
+
#
|
51
|
+
# options:
|
52
|
+
#
|
53
|
+
# :marker : a string to start the lexographical search (it is not included
|
54
|
+
# in the result)
|
55
|
+
# :max_keys : a maximum number of results
|
56
|
+
# :prefix : a string to filter the results by
|
57
|
+
# :delimiter : not supported yet
|
58
|
+
def list(options)
|
59
|
+
marker = options[:marker]
|
60
|
+
prefix = options[:prefix]
|
61
|
+
max_keys = options[:max_keys] || 1000
|
62
|
+
delimiter = options[:delimiter]
|
63
|
+
|
64
|
+
ms = S3MatchSet.new
|
65
|
+
|
66
|
+
marker_found = true
|
67
|
+
pseudo = nil
|
68
|
+
if marker
|
69
|
+
marker_found = false
|
70
|
+
if !@object_map[marker]
|
71
|
+
pseudo = S3Object.new
|
72
|
+
pseudo.name = marker
|
73
|
+
@sorted_set << pseudo
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
if delimiter
|
78
|
+
if prefix
|
79
|
+
base_prefix = prefix
|
80
|
+
else
|
81
|
+
base_prefix = ""
|
82
|
+
end
|
83
|
+
prefix_offset = base_prefix.length
|
84
|
+
end
|
85
|
+
|
86
|
+
count = 0
|
87
|
+
last_chunk = nil
|
88
|
+
@sorted_set.each do |s3_object|
|
89
|
+
if marker_found && (!prefix or s3_object.name.index(prefix) == 0)
|
90
|
+
if delimiter
|
91
|
+
name = s3_object.name
|
92
|
+
remainder = name.slice(prefix_offset, name.length)
|
93
|
+
chunks = remainder.split(delimiter, 2)
|
94
|
+
if chunks.length > 1
|
95
|
+
if (last_chunk != chunks[0])
|
96
|
+
# "All of the keys rolled up in a common prefix count as
|
97
|
+
# a single return when calculating the number of
|
98
|
+
# returns. See MaxKeys."
|
99
|
+
# (http://awsdocs.s3.amazonaws.com/S3/latest/s3-api.pdf)
|
100
|
+
count += 1
|
101
|
+
if count <= max_keys
|
102
|
+
ms.common_prefixes << base_prefix + chunks[0] + delimiter
|
103
|
+
last_chunk = chunks[0]
|
104
|
+
else
|
105
|
+
is_truncated = true
|
106
|
+
break
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
# Continue to the next key, since this one has a
|
111
|
+
# delimiter.
|
112
|
+
next
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
count += 1
|
117
|
+
if count <= max_keys
|
118
|
+
ms.matches << s3_object
|
119
|
+
else
|
120
|
+
is_truncated = true
|
121
|
+
break
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
if marker and marker == s3_object.name
|
126
|
+
marker_found = true
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
if pseudo
|
131
|
+
@sorted_set.delete(pseudo)
|
132
|
+
end
|
133
|
+
|
134
|
+
return ms
|
135
|
+
end
|
136
|
+
end
|
137
|
+
end
|
data/lib/fakes3/util.rb
ADDED
@@ -0,0 +1,222 @@
|
|
1
|
+
require 'builder'
|
2
|
+
require 'time'
|
3
|
+
|
4
|
+
module FakeS3
|
5
|
+
class XmlAdapter
|
6
|
+
def self.buckets(bucket_objects)
|
7
|
+
output = ""
|
8
|
+
xml = Builder::XmlMarkup.new(:target => output)
|
9
|
+
xml.instruct! :xml, :version=>"1.0", :encoding=>"UTF-8"
|
10
|
+
xml.ListAllMyBucketsResult(:xmlns => "http://s3.amazonaws.com/doc/2006-03-01/") { |lam|
|
11
|
+
lam.Owner { |owner|
|
12
|
+
owner.ID("123")
|
13
|
+
owner.DisplayName("FakeS3")
|
14
|
+
}
|
15
|
+
lam.Buckets { |buckets|
|
16
|
+
bucket_objects.each do |bucket|
|
17
|
+
buckets.Bucket do |b|
|
18
|
+
b.Name(bucket.name)
|
19
|
+
b.CreationDate(bucket.creation_date.strftime("%Y-%m-%dT%H:%M:%S.000Z"))
|
20
|
+
end
|
21
|
+
end
|
22
|
+
}
|
23
|
+
}
|
24
|
+
output
|
25
|
+
end
|
26
|
+
|
27
|
+
def self.error(error)
|
28
|
+
output = ""
|
29
|
+
xml = Builder::XmlMarkup.new(:target => output)
|
30
|
+
xml.instruct! :xml, :version=>"1.0", :encoding=>"UTF-8"
|
31
|
+
xml.Error { |err|
|
32
|
+
err.Code(error.code)
|
33
|
+
err.Message(error.message)
|
34
|
+
err.Resource(error.resource)
|
35
|
+
err.RequestId(1)
|
36
|
+
}
|
37
|
+
output
|
38
|
+
end
|
39
|
+
|
40
|
+
# <?xml version="1.0" encoding="UTF-8"?>
|
41
|
+
#<Error>
|
42
|
+
# <Code>NoSuchKey</Code>
|
43
|
+
# <Message>The resource you requested does not exist</Message>
|
44
|
+
# <Resource>/mybucket/myfoto.jpg</Resource>
|
45
|
+
# <RequestId>4442587FB7D0A2F9</RequestId>
|
46
|
+
#</Error>
|
47
|
+
#
|
48
|
+
def self.error_no_such_bucket(name)
|
49
|
+
output = ""
|
50
|
+
xml = Builder::XmlMarkup.new(:target => output)
|
51
|
+
xml.instruct! :xml, :version=>"1.0", :encoding=>"UTF-8"
|
52
|
+
xml.Error { |err|
|
53
|
+
err.Code("NoSuchBucket")
|
54
|
+
err.Message("The resource you requested does not exist")
|
55
|
+
err.Resource(name)
|
56
|
+
err.RequestId(1)
|
57
|
+
}
|
58
|
+
output
|
59
|
+
end
|
60
|
+
|
61
|
+
def self.error_bucket_not_empty(name)
|
62
|
+
output = ""
|
63
|
+
xml = Builder::XmlMarkup.new(:target => output)
|
64
|
+
xml.instruct! :xml, :version=>"1.0", :encoding=>"UTF-8"
|
65
|
+
xml.Error { |err|
|
66
|
+
err.Code("BucketNotEmpty")
|
67
|
+
err.Message("The bucket you tried to delete is not empty.")
|
68
|
+
err.Resource(name)
|
69
|
+
err.RequestId(1)
|
70
|
+
}
|
71
|
+
output
|
72
|
+
end
|
73
|
+
|
74
|
+
def self.error_no_such_key(name)
|
75
|
+
output = ""
|
76
|
+
xml = Builder::XmlMarkup.new(:target => output)
|
77
|
+
xml.instruct! :xml, :version=>"1.0", :encoding=>"UTF-8"
|
78
|
+
xml.Error { |err|
|
79
|
+
err.Code("NoSuchKey")
|
80
|
+
err.Message("The specified key does not exist")
|
81
|
+
err.Key(name)
|
82
|
+
err.RequestId(1)
|
83
|
+
err.HostId(2)
|
84
|
+
}
|
85
|
+
output
|
86
|
+
end
|
87
|
+
|
88
|
+
def self.bucket(bucket)
|
89
|
+
output = ""
|
90
|
+
xml = Builder::XmlMarkup.new(:target => output)
|
91
|
+
xml.instruct! :xml, :version=>"1.0", :encoding=>"UTF-8"
|
92
|
+
xml.ListBucketResult(:xmlns => "http://s3.amazonaws.com/doc/2006-03-01/") { |lbr|
|
93
|
+
lbr.Name(bucket.name)
|
94
|
+
lbr.Prefix
|
95
|
+
lbr.Marker
|
96
|
+
lbr.MaxKeys("1000")
|
97
|
+
lbr.IsTruncated("false")
|
98
|
+
}
|
99
|
+
output
|
100
|
+
end
|
101
|
+
|
102
|
+
# A bucket query gives back the bucket along with contents
|
103
|
+
# <Contents>
|
104
|
+
#<Key>Nelson</Key>
|
105
|
+
# <LastModified>2006-01-01T12:00:00.000Z</LastModified>
|
106
|
+
# <ETag>"828ef3fdfa96f00ad9f27c383fc9ac7f"</ETag>
|
107
|
+
# <Size>5</Size>
|
108
|
+
# <StorageClass>STANDARD</StorageClass>
|
109
|
+
# <Owner>
|
110
|
+
# <ID>bcaf161ca5fb16fd081034f</ID>
|
111
|
+
# <DisplayName>webfile</DisplayName>
|
112
|
+
# </Owner>
|
113
|
+
# </Contents>
|
114
|
+
|
115
|
+
def self.append_objects_to_list_bucket_result(lbr,objects)
|
116
|
+
return if objects.nil? or objects.size == 0
|
117
|
+
|
118
|
+
if objects.index(nil)
|
119
|
+
require 'ruby-debug'
|
120
|
+
Debugger.start
|
121
|
+
debugger
|
122
|
+
end
|
123
|
+
|
124
|
+
objects.each do |s3_object|
|
125
|
+
lbr.Contents { |contents|
|
126
|
+
contents.Key(s3_object.name)
|
127
|
+
contents.LastModified(s3_object.modified_date)
|
128
|
+
contents.ETag("\"#{s3_object.md5}\"")
|
129
|
+
contents.Size(s3_object.size)
|
130
|
+
contents.StorageClass("STANDARD")
|
131
|
+
|
132
|
+
contents.Owner { |owner|
|
133
|
+
owner.ID("abc")
|
134
|
+
owner.DisplayName("You")
|
135
|
+
}
|
136
|
+
}
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
def self.append_common_prefixes_to_list_bucket_result(lbr, prefixes)
|
141
|
+
return if prefixes.nil? or prefixes.size == 0
|
142
|
+
|
143
|
+
prefixes.each do |common_prefix|
|
144
|
+
lbr.CommonPrefixes { |contents| contents.Prefix(common_prefix) }
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
148
|
+
def self.bucket_query(bucket_query)
|
149
|
+
output = ""
|
150
|
+
bucket = bucket_query.bucket
|
151
|
+
xml = Builder::XmlMarkup.new(:target => output)
|
152
|
+
xml.instruct! :xml, :version=>"1.0", :encoding=>"UTF-8"
|
153
|
+
xml.ListBucketResult(:xmlns => "http://s3.amazonaws.com/doc/2006-03-01/") { |lbr|
|
154
|
+
lbr.Name(bucket.name)
|
155
|
+
lbr.Prefix(bucket_query.prefix)
|
156
|
+
lbr.Marker(bucket_query.marker)
|
157
|
+
lbr.MaxKeys(bucket_query.max_keys)
|
158
|
+
lbr.IsTruncated(bucket_query.is_truncated?)
|
159
|
+
append_objects_to_list_bucket_result(lbr,bucket_query.matches)
|
160
|
+
append_common_prefixes_to_list_bucket_result(lbr, bucket_query.common_prefixes)
|
161
|
+
}
|
162
|
+
output
|
163
|
+
end
|
164
|
+
|
165
|
+
# ACL xml
|
166
|
+
def self.acl(object = nil)
|
167
|
+
output = ""
|
168
|
+
xml = Builder::XmlMarkup.new(:target => output)
|
169
|
+
xml.instruct! :xml, :version=>"1.0", :encoding=>"UTF-8"
|
170
|
+
xml.AccessControlPolicy(:xmlns => "http://s3.amazonaws.com/doc/2006-03-01/") { |acp|
|
171
|
+
acp.Owner do |owner|
|
172
|
+
owner.ID("abc")
|
173
|
+
owner.DisplayName("You")
|
174
|
+
end
|
175
|
+
acp.AccessControlList do |acl|
|
176
|
+
acl.Grant do |grant|
|
177
|
+
grant.Grantee("xmlns:xsi" => "http://www.w3.org/2001/XMLSchema-instance", "xsi:type" => "CanonicalUser") do |grantee|
|
178
|
+
grantee.ID("abc")
|
179
|
+
grantee.DisplayName("You")
|
180
|
+
end
|
181
|
+
grant.Permission("FULL_CONTROL")
|
182
|
+
end
|
183
|
+
end
|
184
|
+
}
|
185
|
+
output
|
186
|
+
end
|
187
|
+
|
188
|
+
# <CopyObjectResult>
|
189
|
+
# <LastModified>2009-10-28T22:32:00</LastModified>
|
190
|
+
# <ETag>"9b2cf535f27731c974343645a3985328"</ETag>
|
191
|
+
# </CopyObjectResult>
|
192
|
+
def self.copy_object_result(object)
|
193
|
+
output = ""
|
194
|
+
xml = Builder::XmlMarkup.new(:target => output)
|
195
|
+
xml.instruct! :xml, :version=>"1.0", :encoding=>"UTF-8"
|
196
|
+
xml.CopyObjectResult { |result|
|
197
|
+
result.LastModified(object.modified_date)
|
198
|
+
result.ETag("\"#{object.md5}\"")
|
199
|
+
}
|
200
|
+
output
|
201
|
+
end
|
202
|
+
|
203
|
+
# <CompleteMultipartUploadResult>
|
204
|
+
# <Location>http://Example-Bucket.s3.amazonaws.com/Example-Object</Location>
|
205
|
+
# <Bucket>Example-Bucket</Bucket>
|
206
|
+
# <Key>Example-Object</Key>
|
207
|
+
# <ETag>"3858f62230ac3c915f300c664312c11f-9"</ETag>
|
208
|
+
# </CompleteMultipartUploadResult>
|
209
|
+
def self.complete_multipart_result(object)
|
210
|
+
output = ""
|
211
|
+
xml = Builder::XmlMarkup.new(:target => output)
|
212
|
+
xml.instruct! :xml, :version=>"1.0", :encoding=>"UTF-8"
|
213
|
+
xml.CompleteMultipartUploadResult { |result|
|
214
|
+
result.Location("TODO: implement")
|
215
|
+
result.Bucket("TODO: implement")
|
216
|
+
result.Key(object.name)
|
217
|
+
result.ETag("\"#{object.md5}\"")
|
218
|
+
}
|
219
|
+
output
|
220
|
+
end
|
221
|
+
end
|
222
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
require 'xmlsimple'
|
2
|
+
|
3
|
+
module FakeS3
|
4
|
+
class XmlParser
|
5
|
+
def self.delete_objects(request)
|
6
|
+
keys = []
|
7
|
+
|
8
|
+
objects = XmlSimple.xml_in(request.body, {'NoAttr' => true})['Object']
|
9
|
+
objects.each do |key|
|
10
|
+
keys << key['Key'][0]
|
11
|
+
end
|
12
|
+
|
13
|
+
keys
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
data/static/button.svg
ADDED
@@ -0,0 +1,4 @@
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
2
|
+
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
3
|
+
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="110px" height="20px" viewBox="0 0 110 20" enable-background="new 0 0 110 20" xml:space="preserve"> <image id="image0" width="110" height="20" x="0" y="0" xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAG4AAAAUCAMAAABbPPhuAAAABGdBTUEAALGPC/xhBQAAACBjSFJN AAB6JQAAgIMAAPn/AACA6QAAdTAAAOpgAAA6mAAAF2+SX8VGAAABL1BMVEUAUJX///8AUJUAUJUA UJUAUJUAUJUAUJUAUJUAUJUAUJUAUJUAUJUAUJUAUJUAUJUAUJUAUJUAUJUAUJUAUJUAUJUAUJUA UJUAUJUAUJUAUJUAUJUAUJUAUJU5e7Rmns59r9uAs917sNx6r9yDtN5lnc0vdK9EhLtzq9o/i8wp fsYhecQdd8Mke8U9iss6fLU4e7RyqtougccfeMNQjcx0otRjmNAhesQzhMliodVKib8+i8zT4PDI 2OyTtdyvx+ShvuD///8qf8dOlNCAstwlfMU7fbZ/st0gecQ5g8e7z+iErNibw+QyhMnq8Pj19/vf 6PTG3fAwg8jm8PhNlND5+/12rNs0hcluqNh3rdtNisDn8fl5rtvH3fBnns4xdbCcw+VhoNU5fLVo oM99sNsds+t8AAAAHXRSTlMAAAZux/NbG8+ZCNAobZoK+dNcn/VgLF+dB2/L9Kp1EagAAAABYktH RAH/Ai3eAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH4AsECgU1BHGi1AAAAmZJREFUSMe9 lgtT1DAQxytwgoLC+X4BeiegGEUkCXqXtgkomlabqvh+P77/Z3A3SXst5Wa4cY6duUmbbPaX/HeT XhAEE5NTrcXx2ckTFQuC6Zml5Zu3Ot3x2O2V1VOnK7iJmbU7d9fvkTHZ/Qedjdm5Ae7Mw81HW0ef Thkfjbf9+EmvVQoaTC33HU2ghdGQWZGIbSuVGHF/Wzu7K6tn5z1u4em661bO4sMnFRgmo6NRKvas 39lrO0GDxecvChzDqMpFjCTjUiJH0gZOy1BIDS+JbcBXigTfQxFTHBZJ6oK+tEWx/QoEPedwHVLB pSpzkYWSVClKuDK13WGrc5RBkAgbo8HXwENOKL5nfli6oK/flIKen0dct8TlAibyEkdC+MUqaeAS lVMdc21UCj4J+GYMZOESMsEYumiOS7VB3+57QbsoaBXnc1fiUlhxrngDlykrFQwzwGTWF8VhsGWQ OleSsVxFPui7965CP3zsXbhYxYGYFEKVOIjLIFoDZz1tnq2VOCJB1IQY1y0L3KcC97mBw6XhgoEk MWDmc1DD2fCY1gzKQ5MBjpLUKI45wG4X9MuuF/PrXvtSrVQgdxmkIIWn3K4Oc08LnFsy4sAhiQ3m TEgByS5w0sSwP8qUiXHYBv3mS2X/+w9XKoODgHUmIC2h5eG2hApJE0ci0MtERAvoCXWJSzOnoR12 J+GnPwi/eq3L9WNeMc7cGYt9wskwD830gW4nBq/ddL4q65dY02CXIflvs2fuSnGJTS4Nv6L5iNfx YXbgir46u7bZH+cHqLvRnqt9Xn//+Xtsn1f483Dt+o3j+vPwD8d6fpTeP3ACAAAAJXRFWHRkYXRl OmNyZWF0ZQAyMDE2LTExLTA0VDEwOjA1OjUzLTA3OjAwJ5wXuQAAACV0RVh0ZGF0ZTptb2RpZnkA MjAxNi0xMS0wNFQxMDowNTo1My0wNzowMFbBrwUAAAAASUVORK5CYII="/>
|
4
|
+
</svg>
|
data/static/logo.png
ADDED
Binary file
|
@@ -0,0 +1,98 @@
|
|
1
|
+
require 'test/test_helper'
|
2
|
+
require 'aws-sdk-v1'
|
3
|
+
require 'rest-client'
|
4
|
+
|
5
|
+
class AwsSdkCommandsTest < Test::Unit::TestCase
|
6
|
+
def setup
|
7
|
+
@s3 = AWS::S3.new(:access_key_id => '123',
|
8
|
+
:secret_access_key => 'abc',
|
9
|
+
:s3_endpoint => 'localhost',
|
10
|
+
:s3_port => 10453,
|
11
|
+
:use_ssl => false)
|
12
|
+
end
|
13
|
+
|
14
|
+
def test_copy_to
|
15
|
+
bucket = @s3.buckets["test_copy_to"]
|
16
|
+
object = bucket.objects["key1"]
|
17
|
+
object.write("asdf")
|
18
|
+
|
19
|
+
assert object.exists?
|
20
|
+
object.copy_to("key2")
|
21
|
+
|
22
|
+
assert_equal 2, bucket.objects.count
|
23
|
+
end
|
24
|
+
|
25
|
+
def test_multipart_upload
|
26
|
+
bucket = @s3.buckets["test_multipart_upload"]
|
27
|
+
object = bucket.objects["key1"]
|
28
|
+
object.write("thisisaverybigfile", :multipart_threshold => 5)
|
29
|
+
assert object.exists?
|
30
|
+
assert_equal "thisisaverybigfile", object.read
|
31
|
+
end
|
32
|
+
|
33
|
+
def test_metadata
|
34
|
+
file_path = './test_root/test_metadata/metaobject'
|
35
|
+
FileUtils.rm_rf file_path
|
36
|
+
|
37
|
+
bucket = @s3.buckets["test_metadata"]
|
38
|
+
object = bucket.objects["metaobject"]
|
39
|
+
object.write(
|
40
|
+
'data',
|
41
|
+
# this is sent as header x-amz-storage-class
|
42
|
+
:storage_class => 'REDUCED_REDUNDANCY',
|
43
|
+
# this is sent as header x-amz-meta-custom1
|
44
|
+
:metadata => {
|
45
|
+
"custom1" => "foobar"
|
46
|
+
}
|
47
|
+
)
|
48
|
+
assert object.exists?
|
49
|
+
metadata_file = YAML.load(IO.read("#{file_path}/.fakes3_metadataFFF/metadata"))
|
50
|
+
|
51
|
+
assert metadata_file.has_key?(:custom_metadata), 'Metadata file does not contain a :custom_metadata key'
|
52
|
+
assert metadata_file[:custom_metadata].has_key?('custom1'), ':custom_metadata does not contain field "custom1"'
|
53
|
+
assert_equal 'foobar', metadata_file[:custom_metadata]['custom1'], '"custom1" does not equal expected value "foobar"'
|
54
|
+
|
55
|
+
assert metadata_file.has_key?(:amazon_metadata), 'Metadata file does not contain an :amazon_metadata key'
|
56
|
+
assert metadata_file[:amazon_metadata].has_key?('storage-class'), ':amazon_metadata does not contain field "storage-class"'
|
57
|
+
assert_equal 'REDUCED_REDUNDANCY', metadata_file[:amazon_metadata]['storage-class'], '"storage-class" does not equal expected value "REDUCED_REDUNDANCY"'
|
58
|
+
end
|
59
|
+
|
60
|
+
def test_content_disposition
|
61
|
+
bucket = @s3.buckets["test_bucket"]
|
62
|
+
bucket.objects.create("test_object", "asdf", :content_disposition => "application/test")
|
63
|
+
assert_equal "application/test", content_disposition("test_bucket", "test_object")
|
64
|
+
end
|
65
|
+
|
66
|
+
def test_content_disposition_copy
|
67
|
+
bucket = @s3.buckets["test_bucket"]
|
68
|
+
object = bucket.objects.create("test_object", "asdf", :content_disposition => "application/test")
|
69
|
+
object.copy_to("test_copy_object")
|
70
|
+
assert_equal "application/test", content_disposition("test_bucket", "test_copy_object")
|
71
|
+
end
|
72
|
+
|
73
|
+
def test_content_disposition_request_parameter
|
74
|
+
bucket = @s3.buckets["test_bucket"]
|
75
|
+
object = bucket.objects.create("test_object", "asdf")
|
76
|
+
url = object.url_for(:read, :response_content_disposition => "application/test", :signature_version => :v4)
|
77
|
+
assert_equal "application/test", response_header(url, :content_disposition)
|
78
|
+
end
|
79
|
+
|
80
|
+
def test_content_type_request_parameter
|
81
|
+
bucket = @s3.buckets["test_bucket"]
|
82
|
+
object = bucket.objects.create("test_object", "asdf")
|
83
|
+
url = object.url_for(:read, :response_content_type => "application/test", :signature_version => :v4)
|
84
|
+
assert_equal "application/test", response_header(url, :content_type)
|
85
|
+
end
|
86
|
+
|
87
|
+
# Unfortunately v1 of the AWS SDK doesn't support reading the content_disposition of an object
|
88
|
+
def content_disposition(bucket_name, key)
|
89
|
+
url = "http://localhost:#{@s3.client.port}/#{bucket_name}/#{key}"
|
90
|
+
response_header(url, :content_disposition)
|
91
|
+
end
|
92
|
+
|
93
|
+
def response_header(url, header_name)
|
94
|
+
RestClient.head(url.to_s) do |response|
|
95
|
+
response.headers[header_name]
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|