s33r 0.4.1 → 0.4.2
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.
- data/examples/cli/simple.rb +17 -0
- data/examples/fores33r/app/controllers/browser_controller.rb +32 -8
- data/examples/fores33r/app/views/browser/_create_bucket.rhtml +6 -0
- data/examples/fores33r/app/views/browser/_upload.rhtml +5 -0
- data/examples/fores33r/app/views/browser/index.rhtml +1 -8
- data/examples/fores33r/app/views/browser/plain_bucket.rhtml +3 -0
- data/examples/fores33r/app/views/browser/s3_index.rhtml +9 -0
- data/examples/fores33r/app/views/browser/show_bucket.rhtml +6 -8
- data/examples/fores33r/app/views/layouts/application.rhtml +2 -0
- data/examples/fores33r/app/views/layouts/s3_layout.rhtml +14 -0
- data/examples/fores33r/config/environment.rb +1 -1
- data/examples/fores33r/config/routes.rb +2 -0
- data/examples/fores33r/public/stylesheets/core.css +2 -2
- data/html/classes/Net/HTTPResponse.html +3 -0
- data/html/classes/S33r.html +127 -116
- data/html/classes/S33r/BucketListing.html +119 -94
- data/html/classes/S33r/Client.html +602 -536
- data/html/classes/S33r/LoggingResource.html +3 -3
- data/html/classes/S33r/NamedBucket.html +235 -191
- data/html/classes/S33r/OrderlyXmlMarkup.html +7 -7
- data/html/classes/S33r/S33rException.html +1 -0
- data/html/classes/S33r/S33rException/TryingToPutEmptyResource.html +117 -0
- data/html/classes/S33r/S3ACL/ACLDoc.html +94 -94
- data/html/classes/S33r/S3ACL/AmazonCustomer.html +5 -5
- data/html/classes/S33r/S3ACL/CanonicalUser.html +12 -12
- data/html/classes/S33r/S3ACL/Grant.html +64 -64
- data/html/classes/S33r/S3ACL/Grantee.html +36 -36
- data/html/classes/S33r/S3ACL/Group.html +8 -8
- data/html/classes/S33r/S3Object.html +387 -79
- data/html/classes/XML.html +15 -15
- data/html/created.rid +1 -1
- data/html/files/CHANGELOG.html +7 -1
- data/html/files/MIT-LICENSE.html +1 -1
- data/html/files/README_txt.html +3 -7
- data/html/files/lib/s33r/bucket_listing_rb.html +1 -9
- data/html/files/lib/s33r/builder_rb.html +1 -1
- data/html/files/lib/s33r/client_rb.html +1 -1
- data/html/files/lib/s33r/core_rb.html +1 -2
- data/html/files/lib/s33r/libxml_extensions_rb.html +1 -7
- data/html/files/lib/s33r/libxml_loader_rb.html +109 -0
- data/html/files/lib/s33r/logging_rb.html +1 -2
- data/html/files/lib/s33r/mimetypes_rb.html +1 -1
- data/html/files/lib/s33r/named_bucket_rb.html +1 -1
- data/html/files/lib/s33r/s33r_exception_rb.html +1 -1
- data/html/files/lib/s33r/s33r_http_rb.html +1 -1
- data/html/files/lib/s33r/s3_acl_rb.html +1 -2
- data/html/files/lib/s33r/s3_obj_rb.html +108 -0
- data/html/files/lib/s33r/sync_rb.html +1 -1
- data/html/files/lib/s33r_rb.html +1 -1
- data/html/fr_class_index.html +1 -0
- data/html/fr_file_index.html +2 -0
- data/html/fr_method_index.html +80 -71
- data/lib/s33r/bucket_listing.rb +30 -55
- data/lib/s33r/client.rb +70 -28
- data/lib/s33r/core.rb +9 -4
- data/lib/s33r/libxml_extensions.rb +2 -0
- data/lib/s33r/libxml_loader.rb +6 -0
- data/lib/s33r/logging.rb +3 -3
- data/lib/s33r/named_bucket.rb +33 -15
- data/lib/s33r/s33r_exception.rb +4 -0
- data/lib/s33r/s33r_http.rb +1 -1
- data/lib/s33r/s3_acl.rb +3 -2
- data/lib/s33r/s3_obj.rb +186 -0
- data/test/cases/spec_bucket_listing.rb +9 -33
- data/test/cases/spec_s3_object.rb +35 -0
- data/test/files/suspect_bucket_listing.xml +19 -0
- metadata +94 -89
- data/examples/fores33r/log/development.log +0 -5960
- data/examples/fores33r/log/production.log +0 -0
- data/examples/fores33r/log/server.log +0 -0
- data/examples/fores33r/log/test.log +0 -0
- data/examples/fores33r/tmp/sessions/ruby_sess.2ea325f604aa5fb9 +0 -0
- data/examples/fores33r/tmp/sessions/ruby_sess.39d37e054d21d545 +0 -0
- data/examples/fores33r/tmp/sessions/ruby_sess.acf71fc73aa74983 +0 -0
- data/examples/fores33r/tmp/sessions/ruby_sess.c1697b7d6670f3cd +0 -0
data/lib/s33r/core.rb
CHANGED
@@ -3,8 +3,8 @@ require 'time'
|
|
3
3
|
require 'net/http'
|
4
4
|
require 'net/https'
|
5
5
|
require 'openssl'
|
6
|
-
require 'xml/libxml'
|
7
6
|
require 'parsedate'
|
7
|
+
require File.join(File.dirname(__FILE__), 'libxml_loader')
|
8
8
|
|
9
9
|
# Module to handle S3 operations which don't require an internet connection,
|
10
10
|
# i.e. data validation and request-building operations;
|
@@ -157,12 +157,17 @@ module S33r
|
|
157
157
|
headers
|
158
158
|
end
|
159
159
|
|
160
|
-
# Add metadata headers, correctly prefixing them first
|
160
|
+
# Add metadata headers, correctly prefixing them first,
|
161
|
+
# e.g. you might do metadata_headers({}, {'myname' => 'elliot', 'myage' => 36})
|
162
|
+
# to add two headers to the request:
|
163
|
+
#
|
164
|
+
# x-amz-meta-myname: elliot
|
165
|
+
# x-amz-meta-myage: 36
|
161
166
|
#
|
162
167
|
# Returns headers with the metadata headers appended.
|
163
168
|
def metadata_headers(headers, metadata={})
|
164
169
|
unless metadata.empty?
|
165
|
-
metadata.each { |key, value| headers[METADATA_PREFIX + key] = value }
|
170
|
+
metadata.each { |key, value| headers[METADATA_PREFIX + key] = value.to_s }
|
166
171
|
end
|
167
172
|
headers
|
168
173
|
end
|
@@ -285,7 +290,7 @@ module S33r
|
|
285
290
|
# Remove the namespace declaration from S3 XML response bodies (libxml
|
286
291
|
# isn't fond of it).
|
287
292
|
def S33r.remove_namespace(xml_in)
|
288
|
-
namespace = RESPONSE_NAMESPACE_URI.gsub('/', '\/')
|
293
|
+
namespace = S33r::RESPONSE_NAMESPACE_URI.gsub('/', '\/')
|
289
294
|
xml_in.gsub(/ xmlns="#{namespace}"/, '')
|
290
295
|
end
|
291
296
|
end
|
data/lib/s33r/logging.rb
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
require 'rubygems'
|
2
|
-
require 'xml/libxml'
|
3
2
|
require_gem 'builder'
|
3
|
+
require File.join(File.dirname(__FILE__), 'libxml_loader')
|
4
4
|
|
5
5
|
module S33r
|
6
6
|
# For manipulating logging directives on resources
|
7
7
|
# (see http://docs.amazonwebservices.com/AmazonS3/2006-03-01/LoggingHowTo.html).
|
8
8
|
#
|
9
|
-
#
|
10
|
-
#
|
9
|
+
# Creating a LoggingResource instance using new and no arguments will generate a "blank" instance;
|
10
|
+
# this can be put to the ?logging URL for a resource to remove logging from it.
|
11
11
|
class LoggingResource
|
12
12
|
attr_reader :log_target, :log_prefix
|
13
13
|
|
data/lib/s33r/named_bucket.rb
CHANGED
@@ -2,6 +2,8 @@
|
|
2
2
|
#-- specify a prefix and/or delimiter
|
3
3
|
|
4
4
|
require File.join(File.dirname(__FILE__), 'client')
|
5
|
+
require File.join(File.dirname(__FILE__), 's3_obj')
|
6
|
+
require File.join(File.dirname(__FILE__), 's33r_exception')
|
5
7
|
|
6
8
|
module S33r
|
7
9
|
# Wraps the S33r::Client class to make it more convenient for use with a single bucket.
|
@@ -33,10 +35,7 @@ module S33r
|
|
33
35
|
a :default_bucket option"
|
34
36
|
end
|
35
37
|
|
36
|
-
#
|
37
|
-
@listing = nil
|
38
|
-
|
39
|
-
# all content should be created as public-read
|
38
|
+
# all content inside the bucket should be created as public-read
|
40
39
|
@public_contents = (true == options[:public_contents])
|
41
40
|
@client_headers.merge!(canned_acl_header('public-read')) if @public_contents
|
42
41
|
|
@@ -58,14 +57,31 @@ module S33r
|
|
58
57
|
@strict
|
59
58
|
end
|
60
59
|
|
61
|
-
# Get a single object from a bucket as
|
62
|
-
|
63
|
-
|
60
|
+
# Get a single object from a bucket as an S3Object.
|
61
|
+
#
|
62
|
+
# To get a bare object (with no content):
|
63
|
+
#
|
64
|
+
# bucket['key']
|
65
|
+
#
|
66
|
+
# To get the object and load its content:
|
67
|
+
#
|
68
|
+
# bucket['key', :load]
|
69
|
+
def [](key, eager=false)
|
70
|
+
obj = listing.contents[key]
|
71
|
+
obj.named_bucket = self
|
72
|
+
obj.load if :load == eager
|
73
|
+
obj
|
74
|
+
end
|
75
|
+
|
76
|
+
# Get a raw response for a key inside the bucket.
|
77
|
+
def get_raw(key, headers={})
|
78
|
+
get_resource(@name, key, headers)
|
64
79
|
end
|
65
80
|
|
66
81
|
# Get a BucketListing instance for the content of this bucket.
|
82
|
+
# Uses the Client.list_bucket method to get the listing.
|
67
83
|
def listing
|
68
|
-
list_bucket(@name)
|
84
|
+
list_bucket(@name)[1]
|
69
85
|
end
|
70
86
|
|
71
87
|
# Does this bucket exist?
|
@@ -84,9 +100,12 @@ module S33r
|
|
84
100
|
listing.pretty
|
85
101
|
end
|
86
102
|
|
87
|
-
# List content of the bucket, and attach each item to this
|
88
|
-
|
89
|
-
|
103
|
+
# List content of the bucket, and attach each item to this NamedBucket
|
104
|
+
# instance as it is yielded (to enable easier manipulation directly from the S3Object).
|
105
|
+
# Note that the objects are incomplete, as the data associated with them has not been
|
106
|
+
# "got" from S3 yet.
|
107
|
+
def each_object
|
108
|
+
listing.contents.each_value { |obj| obj.named_bucket = self; yield obj }
|
90
109
|
end
|
91
110
|
|
92
111
|
# Does the given key exist in the bucket?
|
@@ -114,9 +133,8 @@ module S33r
|
|
114
133
|
# NB S3 doesn't discriminate between successfully deleting a key
|
115
134
|
# and trying to delete a non-existent key (both return a 204).
|
116
135
|
# If you want to test for existence first, use key_exists?.
|
117
|
-
def
|
118
|
-
|
119
|
-
listing
|
136
|
+
def delete(key, headers={})
|
137
|
+
delete_resource(@name, key, headers)
|
120
138
|
end
|
121
139
|
|
122
140
|
# Generate an authenticated URL (see http://docs.amazonwebservices.com/AmazonS3/2006-03-01/)
|
@@ -127,4 +145,4 @@ module S33r
|
|
127
145
|
super(@aws_access_key, @aws_secret_access_key, @name, resource_key, expires)
|
128
146
|
end
|
129
147
|
end
|
130
|
-
end
|
148
|
+
end
|
data/lib/s33r/s33r_exception.rb
CHANGED
@@ -41,6 +41,10 @@ module S33r
|
|
41
41
|
# (i.e. if LogDelivery permissions not set - see S33r::S3ACL::ACLDoc.add_log_target_grants)
|
42
42
|
class BucketNotLogTargetable < Exception
|
43
43
|
end
|
44
|
+
|
45
|
+
# Raised if you try to do a put with empty body
|
46
|
+
class TryingToPutEmptyResource < Exception
|
47
|
+
end
|
44
48
|
|
45
49
|
end
|
46
50
|
end
|
data/lib/s33r/s33r_http.rb
CHANGED
data/lib/s33r/s3_acl.rb
CHANGED
@@ -1,7 +1,8 @@
|
|
1
1
|
require 'rubygems'
|
2
|
-
require 'xml/libxml'
|
3
2
|
require_gem 'builder'
|
4
|
-
|
3
|
+
base = File.dirname(__FILE__)
|
4
|
+
require File.join(base, 'libxml_loader')
|
5
|
+
require File.join(base, 's33r_exception')
|
5
6
|
|
6
7
|
module S33r
|
7
8
|
# S3 ACL handling.
|
data/lib/s33r/s3_obj.rb
ADDED
@@ -0,0 +1,186 @@
|
|
1
|
+
require 'date'
|
2
|
+
|
3
|
+
# Representation of an object stored in a bucket.
|
4
|
+
module S33r
|
5
|
+
class S3Object
|
6
|
+
attr_accessor :key, :last_modified, :etag, :size, :owner, :storage_class, :value, :named_bucket,
|
7
|
+
:content_type, :mime_type
|
8
|
+
|
9
|
+
# Metadata set by x-amz-meta- style headers. Note that the bit after x-amz-meta-
|
10
|
+
# is stored for each key, rather than the full key.
|
11
|
+
attr_accessor :meta
|
12
|
+
|
13
|
+
def initialize(key, metadata={}, amz_meta={}, value=nil)
|
14
|
+
@key = key
|
15
|
+
@meta = amz_meta
|
16
|
+
@value = value
|
17
|
+
set_properties(metadata) unless metadata.empty?
|
18
|
+
end
|
19
|
+
|
20
|
+
# Set the properties of the object from some metadata name-value pairs.
|
21
|
+
#
|
22
|
+
# +metadata+ is a hash of properties and their values, used to set the
|
23
|
+
# corresponding properties on the object.
|
24
|
+
#
|
25
|
+
# +value+ is the data associated with the object on S3.
|
26
|
+
def set_properties(metadata)
|
27
|
+
# required properties
|
28
|
+
@etag = metadata[:etag].gsub("\"", "") if metadata[:etag]
|
29
|
+
@last_modified = DateTime.parse(metadata[:last_modified]) if metadata[:last_modified]
|
30
|
+
@size = metadata[:size].to_i if metadata[:size]
|
31
|
+
|
32
|
+
# only set if creating object from XML (not available otherwise)
|
33
|
+
@owner = metadata[:owner]
|
34
|
+
|
35
|
+
# only set if creating object from HTTP response
|
36
|
+
@content_type = metadata[:content_type]
|
37
|
+
end
|
38
|
+
|
39
|
+
# To create an object which reads the content in from a file;
|
40
|
+
# this is not very efficient - it's actually better to use NamedBucket.put_file,
|
41
|
+
# as this will stream out of a file to S3, rather than load the file in
|
42
|
+
# memory first.
|
43
|
+
def self.from_file(key, filename)
|
44
|
+
mime_type = guess_mime_type(filename)
|
45
|
+
content_type = mime_type.simplified
|
46
|
+
value = File.open(filename).read
|
47
|
+
self.new(key, { :content_type => content_type }, {}, value)
|
48
|
+
end
|
49
|
+
|
50
|
+
# Set properties of the object from an XML string.
|
51
|
+
#
|
52
|
+
# +xml_str+ should be a string representing a full XML document,
|
53
|
+
# containing a <Contents> element as its root element.
|
54
|
+
def self.from_xml_string(xml_str)
|
55
|
+
self.from_xml_node(XML.get_xml_doc(xml_str))
|
56
|
+
end
|
57
|
+
|
58
|
+
# Create a new instance from an XML document.
|
59
|
+
def self.from_xml_node(doc)
|
60
|
+
metadata = self.parse_xml_node(doc)
|
61
|
+
self.new(metadata[:key], metadata)
|
62
|
+
end
|
63
|
+
|
64
|
+
# Get properties of the object from an XML document, e.g. as returned in a bucket listing.
|
65
|
+
#
|
66
|
+
# +doc+: XML::Document instance to parse to get properties for this object.
|
67
|
+
#
|
68
|
+
# Returns the metadata relating to the object, as stored on S3.
|
69
|
+
#-- TODO: include amz-meta elements
|
70
|
+
def self.parse_xml_node(doc)
|
71
|
+
metadata = {}
|
72
|
+
metadata[:key] = doc.xget('Key')
|
73
|
+
metadata[:last_modified] = doc.xget('LastModified')
|
74
|
+
metadata[:etag] = doc.xget('ETag')
|
75
|
+
metadata[:size] = doc.xget('Size')
|
76
|
+
|
77
|
+
# Build representation of the owner.
|
78
|
+
user_xml_doc = doc.find('Owner').to_a.first
|
79
|
+
metadata[:owner] = S3ACL::CanonicalUser.from_xml(user_xml_doc)
|
80
|
+
|
81
|
+
metadata
|
82
|
+
end
|
83
|
+
|
84
|
+
# Create a new instance from a HTTP response.
|
85
|
+
# This is useful if you do a GET for a resource key and
|
86
|
+
# want to convert the response into an object; NB the response
|
87
|
+
# doesn't necessarily contain all the metadata you might want - you need to
|
88
|
+
# do a HEAD for that.
|
89
|
+
#
|
90
|
+
# +key+ is the key for the resource (not part of the response).
|
91
|
+
#
|
92
|
+
# Note that if the resp returns nil, a blank object is created.
|
93
|
+
def self.from_response(key, resp)
|
94
|
+
result = self.parse_response(resp)
|
95
|
+
if result
|
96
|
+
metadata, amz_meta, value = result
|
97
|
+
else
|
98
|
+
metadata = {}
|
99
|
+
amz_meta = {}
|
100
|
+
value = nil
|
101
|
+
end
|
102
|
+
self.new(key, metadata, amz_meta, value)
|
103
|
+
end
|
104
|
+
|
105
|
+
# Parse the response returned by GET on a resource key
|
106
|
+
# within a bucket.
|
107
|
+
#
|
108
|
+
# +resp+ is a Net::HTTPResponse instance.
|
109
|
+
#
|
110
|
+
# Returns an array [+metadata+, +response.body+]; or nil if the object
|
111
|
+
# doesn't exist.
|
112
|
+
def self.parse_response(resp)
|
113
|
+
resp_headers = resp.to_hash
|
114
|
+
|
115
|
+
# If there's no etag, there's no content in the resource.
|
116
|
+
if resp_headers['etag']
|
117
|
+
metadata = {}
|
118
|
+
metadata[:last_modified] = resp_headers['last-modified'][0]
|
119
|
+
metadata[:etag] = resp_headers['etag'][0]
|
120
|
+
metadata[:size] = resp_headers['content-length'][0]
|
121
|
+
metadata[:content_type] = resp_headers['content-type'][0]
|
122
|
+
|
123
|
+
# x-amz-meta- response headers.
|
124
|
+
interesting_header = Regexp.new(METADATA_PREFIX)
|
125
|
+
amz_meta = {}
|
126
|
+
resp.each_header do |key, value|
|
127
|
+
amz_meta[key.gsub(interesting_header, '')] = value if interesting_header =~ key
|
128
|
+
end
|
129
|
+
|
130
|
+
# The actual content of the S3 object.
|
131
|
+
value = resp.body
|
132
|
+
|
133
|
+
[metadata, amz_meta, value]
|
134
|
+
else
|
135
|
+
nil
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
# Load content into this object from S3; will perform
|
140
|
+
# an HTTP request to "refresh" the object (providing the object
|
141
|
+
# has an association with a bucket it can use for piggybacking).
|
142
|
+
#
|
143
|
+
# Returns false if value cannot be retrieved.
|
144
|
+
def load
|
145
|
+
if @named_bucket and @named_bucket.key_exists?(@key)
|
146
|
+
resp = @named_bucket.get_raw(@key)
|
147
|
+
if resp.ok?
|
148
|
+
@value = resp.body
|
149
|
+
@content_type = resp.to_hash['content-type']
|
150
|
+
return true
|
151
|
+
else
|
152
|
+
return false
|
153
|
+
end
|
154
|
+
else
|
155
|
+
return false
|
156
|
+
end
|
157
|
+
end
|
158
|
+
|
159
|
+
# Remove this object from its associated NamedBucket.
|
160
|
+
#
|
161
|
+
# Returns false if this object is not associated with a bucket;
|
162
|
+
# otherwise returns the response from S3.
|
163
|
+
def delete
|
164
|
+
if @named_bucket.nil?
|
165
|
+
return false
|
166
|
+
else
|
167
|
+
@named_bucket.delete_resource(@key)
|
168
|
+
end
|
169
|
+
end
|
170
|
+
|
171
|
+
# Save this object back into its bucket.
|
172
|
+
#
|
173
|
+
# Only works if the object has an associated NamedBucket;
|
174
|
+
# returns false if it doesn't.
|
175
|
+
def save
|
176
|
+
if @named_bucket.nil?
|
177
|
+
return false
|
178
|
+
else
|
179
|
+
headers = {}
|
180
|
+
headers["Content-Type"] = @content_type || ''
|
181
|
+
headers = metadata_headers(headers, meta)
|
182
|
+
@named_bucket.put_stream(@value, @key, headers)
|
183
|
+
end
|
184
|
+
end
|
185
|
+
end
|
186
|
+
end
|
@@ -12,6 +12,8 @@ context 'S33r bucket listing' do
|
|
12
12
|
@with_empty_bucket_listing_xml = File.open(xml_file3) { |f| f.read }
|
13
13
|
xml_file4 = File.join(base, '../files/bucket_listing_broken.xml')
|
14
14
|
@with_broken_bucket_listing_xml = File.open(xml_file4) { |f| f.read }
|
15
|
+
xml_file5 = File.join(base, '../files/suspect_bucket_listing.xml')
|
16
|
+
@with_suspect_bl_xml = File.open(xml_file5) { |f| f.read }
|
15
17
|
|
16
18
|
@bucket_listing = BucketListing.new(@with_bucket_listing_xml)
|
17
19
|
@bucket_properties = %w(name prefix marker max_keys is_truncated)
|
@@ -85,38 +87,12 @@ context 'S33r bucket listing' do
|
|
85
87
|
specify 'should provide easy access to <CommonPrefixes> elements as a hash' do
|
86
88
|
todo
|
87
89
|
end
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
end
|
96
|
-
|
97
|
-
specify 'can be initialised from XML fragment with correct data types' do
|
98
|
-
@s3obj.key.should.equal '/home/ell/dir1/four.txt'
|
99
|
-
d = @s3obj.last_modified
|
100
|
-
[d.year, d.month, d.day, d.hour, d.min, d.sec].should.equal [2006, 8, 19, 22, 53, 29]
|
101
|
-
@s3obj.etag.should.equal '24ce59274b89287b3960c184153ac24b'
|
102
|
-
@s3obj.size.should.equal 14
|
103
|
-
end
|
104
|
-
|
105
|
-
specify 'should treat the owner as an object in his/her own right' do
|
106
|
-
[@s3obj.owner.user_id, @s3obj.owner.display_name].should.equal \
|
107
|
-
['56efddfead5aa65da942f156fb2b294f44d78fd932d701331edc5fba19620fd4', 'elliotsmith3']
|
108
|
-
@s3obj.owner.should_be_instance_of S3ACL::CanonicalUser
|
109
|
-
end
|
110
|
-
|
111
|
-
specify 'can be associated with a NamedBucket' do
|
112
|
-
todo
|
113
|
-
end
|
114
|
-
|
115
|
-
specify 'can be saved by proxing through the NamedBucket it is associated with' do
|
116
|
-
todo
|
117
|
-
end
|
118
|
-
|
119
|
-
specify 'cannot be saved unless associated with a NamedBucket' do
|
120
|
-
todo
|
90
|
+
|
91
|
+
# attempting to fix ListBucketResult errors reported by Alex Payne
|
92
|
+
specify 'should handle suspect bucket listing' do
|
93
|
+
puts @with_suspect_bl_xml
|
94
|
+
bl = BucketListing.new(@with_suspect_bl_xml)
|
95
|
+
bl.contents.size.should_be 1
|
96
|
+
bl.contents.keys.should.include 'orly.jpg'
|
121
97
|
end
|
122
98
|
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
base = File.dirname(__FILE__)
|
2
|
+
require base + '/../test_setup'
|
3
|
+
|
4
|
+
context 'S3 object' do
|
5
|
+
setup do
|
6
|
+
@s3_object_xml = File.open(File.join(base, '../files/s3_object.xml')).read
|
7
|
+
@s3obj = S3Object.from_xml_string(@s3_object_xml)
|
8
|
+
end
|
9
|
+
|
10
|
+
specify 'can be initialised from XML fragment with correct data types' do
|
11
|
+
@s3obj.key.should.equal '/home/ell/dir1/four.txt'
|
12
|
+
d = @s3obj.last_modified
|
13
|
+
[d.year, d.month, d.day, d.hour, d.min, d.sec].should.equal [2006, 8, 19, 22, 53, 29]
|
14
|
+
@s3obj.etag.should.equal '24ce59274b89287b3960c184153ac24b'
|
15
|
+
@s3obj.size.should.equal 14
|
16
|
+
end
|
17
|
+
|
18
|
+
specify 'should treat the owner as an object in his/her own right' do
|
19
|
+
[@s3obj.owner.user_id, @s3obj.owner.display_name].should.equal \
|
20
|
+
['56efddfead5aa65da942f156fb2b294f44d78fd932d701331edc5fba19620fd4', 'elliotsmith3']
|
21
|
+
@s3obj.owner.should_be_instance_of S3ACL::CanonicalUser
|
22
|
+
end
|
23
|
+
|
24
|
+
specify 'can be associated with a NamedBucket' do
|
25
|
+
todo
|
26
|
+
end
|
27
|
+
|
28
|
+
specify 'can be saved by proxing through the NamedBucket it is associated with' do
|
29
|
+
todo
|
30
|
+
end
|
31
|
+
|
32
|
+
specify 'cannot be saved unless associated with a NamedBucket' do
|
33
|
+
todo
|
34
|
+
end
|
35
|
+
end
|