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.
@@ -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
@@ -0,0 +1,4 @@
1
+ module FakeS3
2
+ class UnsupportedOperation < RuntimeError
3
+ end
4
+ end
@@ -0,0 +1,8 @@
1
+ module FakeS3
2
+ module Util
3
+ def Util.strip_before_and_after(string, strip_this)
4
+ regex_friendly_strip_this = Regexp.escape(strip_this)
5
+ string.gsub(/\A[#{regex_friendly_strip_this}]+|[#{regex_friendly_strip_this}]+\z/, '')
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,3 @@
1
+ module FakeS3
2
+ VERSION = "1.2.0"
3
+ end
@@ -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>&quot;828ef3fdfa96f00ad9f27c383fc9ac7f&quot;</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
@@ -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>
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