cloudfiles 1.4.10 → 1.4.11
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/CHANGELOG +11 -0
- data/CONTRIBUTORS +28 -0
- data/COPYING +1 -1
- data/README.rdoc +9 -2
- data/VERSION +1 -1
- data/cloudfiles.gemspec +6 -5
- data/lib/cloudfiles.rb +20 -7
- data/lib/cloudfiles/authentication.rb +33 -28
- data/lib/cloudfiles/connection.rb +91 -85
- data/lib/cloudfiles/container.rb +149 -125
- data/lib/cloudfiles/exception.rb +64 -0
- data/lib/cloudfiles/storage_object.rb +140 -80
- data/test/cloudfiles_authentication_test.rb +7 -7
- data/test/cloudfiles_connection_test.rb +14 -13
- data/test/cloudfiles_container_test.rb +15 -14
- data/test/cloudfiles_storage_object_test.rb +10 -9
- metadata +9 -7
- data/Manifest +0 -16
@@ -1,83 +1,97 @@
|
|
1
1
|
module CloudFiles
|
2
2
|
class StorageObject
|
3
3
|
# See COPYING for license information.
|
4
|
-
# Copyright (c)
|
5
|
-
|
4
|
+
# Copyright (c) 2011, Rackspace US, Inc.
|
5
|
+
|
6
6
|
# Name of the object corresponding to the instantiated object
|
7
7
|
attr_reader :name
|
8
|
-
|
9
|
-
# Size of the object (in bytes)
|
10
|
-
attr_reader :bytes
|
11
8
|
|
12
9
|
# The parent CloudFiles::Container object
|
13
10
|
attr_reader :container
|
14
11
|
|
15
|
-
# Date of the object's last modification
|
16
|
-
attr_reader :last_modified
|
17
|
-
|
18
|
-
# ETag of the object data
|
19
|
-
attr_reader :etag
|
20
|
-
|
21
|
-
# Content type of the object data
|
22
|
-
attr_reader :content_type
|
23
|
-
|
24
12
|
# Builds a new CloudFiles::StorageObject in the current container. If force_exist is set, the object must exist or a
|
25
|
-
#
|
13
|
+
# CloudFiles::Exception::NoSuchObject Exception will be raised. If not, an "empty" CloudFiles::StorageObject will be returned, ready for data
|
26
14
|
# via CloudFiles::StorageObject.write
|
27
|
-
def initialize(container,objectname,force_exists=false,make_path=false)
|
15
|
+
def initialize(container, objectname, force_exists = false, make_path = false)
|
28
16
|
if objectname.match(/\?/)
|
29
|
-
raise
|
17
|
+
raise CloudFiles::Exception::Syntax, "Object #{objectname} contains an invalid character in the name (? not allowed)"
|
30
18
|
end
|
31
19
|
@container = container
|
32
20
|
@containername = container.name
|
33
21
|
@name = objectname
|
34
22
|
@make_path = make_path
|
35
23
|
@storagehost = self.container.connection.storagehost
|
36
|
-
@storagepath = self.container.connection.storagepath+"/#{
|
24
|
+
@storagepath = self.container.connection.storagepath + "/#{CloudFiles.escape @containername}/#{CloudFiles.escape @name}"
|
37
25
|
@storageport = self.container.connection.storageport
|
38
26
|
@storagescheme = self.container.connection.storagescheme
|
39
|
-
if
|
40
|
-
|
41
|
-
else
|
42
|
-
raise NoSuchObjectException, "Object #{@name} does not exist" if force_exists
|
27
|
+
if force_exists
|
28
|
+
raise CloudFiles::Exception::NoSuchObject, "Object #{@name} does not exist" unless container.object_exists?(objectname)
|
43
29
|
end
|
44
30
|
end
|
45
|
-
|
46
|
-
#
|
47
|
-
|
48
|
-
|
49
|
-
response = self.container.connection.cfreq("HEAD",@storagehost,@storagepath,@storageport,@storagescheme)
|
50
|
-
raise NoSuchObjectException, "Object #{@name} does not exist" unless (response.code =~ /^20/)
|
51
|
-
@bytes = response["content-length"]
|
52
|
-
@last_modified = Time.parse(response["last-modified"])
|
53
|
-
@etag = response["etag"]
|
54
|
-
@content_type = response["content-type"]
|
55
|
-
resphash = {}
|
56
|
-
response.to_hash.select { |k,v| k.match(/^x-object-meta/) }.each { |x| resphash[x[0]] = x[1].to_s }
|
57
|
-
@metadata = resphash
|
31
|
+
|
32
|
+
# Refreshes the object metadata
|
33
|
+
def refresh
|
34
|
+
@object_metadata = nil
|
58
35
|
true
|
59
36
|
end
|
60
|
-
alias :
|
37
|
+
alias :populate :refresh
|
38
|
+
|
39
|
+
# Retrieves Metadata for the object
|
40
|
+
def object_metadata
|
41
|
+
@object_metadata ||= (
|
42
|
+
response = self.container.connection.cfreq("HEAD", @storagehost, @storagepath, @storageport, @storagescheme)
|
43
|
+
raise CloudFiles::Exception::NoSuchObject, "Object #{@name} does not exist" unless (response.code =~ /^20/)
|
44
|
+
resphash = {}
|
45
|
+
response.to_hash.select { |k,v| k.match(/^x-object-meta/) }.each { |x| resphash[x[0]] = x[1].to_s }
|
46
|
+
{
|
47
|
+
:bytes => response["content-length"],
|
48
|
+
:last_modified => Time.parse(response["last-modified"]),
|
49
|
+
:etag => response["etag"],
|
50
|
+
:content_type => response["content-type"],
|
51
|
+
:metadata => resphash
|
52
|
+
}
|
53
|
+
)
|
54
|
+
end
|
55
|
+
|
56
|
+
# Size of the object (in bytes)
|
57
|
+
def bytes
|
58
|
+
self.object_metadata[:bytes]
|
59
|
+
end
|
60
|
+
|
61
|
+
# Date of the object's last modification
|
62
|
+
def last_modified
|
63
|
+
self.object_metadata[:last_modified]
|
64
|
+
end
|
65
|
+
|
66
|
+
# ETag of the object data
|
67
|
+
def etag
|
68
|
+
self.object_metadata[:etag]
|
69
|
+
end
|
70
|
+
|
71
|
+
# Content type of the object data
|
72
|
+
def content_type
|
73
|
+
self.object_metadata[:content_type]
|
74
|
+
end
|
61
75
|
|
62
76
|
# Retrieves the data from an object and stores the data in memory. The data is returned as a string.
|
63
77
|
# Throws a NoSuchObjectException if the object doesn't exist.
|
64
78
|
#
|
65
79
|
# If the optional size and range arguments are provided, the call will return the number of bytes provided by
|
66
80
|
# size, starting from the offset provided in offset.
|
67
|
-
#
|
81
|
+
#
|
68
82
|
# object.data
|
69
83
|
# => "This is the text stored in the file"
|
70
|
-
def data(size
|
84
|
+
def data(size = -1, offset = 0, headers = {})
|
71
85
|
if size.to_i > 0
|
72
86
|
range = sprintf("bytes=%d-%d", offset.to_i, (offset.to_i + size.to_i) - 1)
|
73
87
|
headers['Range'] = range
|
74
88
|
end
|
75
|
-
response = self.container.connection.cfreq("GET"
|
76
|
-
raise
|
89
|
+
response = self.container.connection.cfreq("GET", @storagehost, @storagepath, @storageport, @storagescheme, headers)
|
90
|
+
raise CloudFiles::Exception::NoSuchObject, "Object #{@name} does not exist" unless (response.code =~ /^20/)
|
77
91
|
response.body
|
78
92
|
end
|
79
93
|
|
80
|
-
# Retrieves the data from an object and returns a stream that must be passed to a block. Throws a
|
94
|
+
# Retrieves the data from an object and returns a stream that must be passed to a block. Throws a
|
81
95
|
# NoSuchObjectException if the object doesn't exist.
|
82
96
|
#
|
83
97
|
# If the optional size and range arguments are provided, the call will return the number of bytes provided by
|
@@ -87,16 +101,16 @@ module CloudFiles
|
|
87
101
|
# object.data_stream do |chunk|
|
88
102
|
# data += chunk
|
89
103
|
# end
|
90
|
-
#
|
104
|
+
#
|
91
105
|
# data
|
92
106
|
# => "This is the text stored in the file"
|
93
|
-
def data_stream(size
|
107
|
+
def data_stream(size = -1, offset = 0, headers = {}, &block)
|
94
108
|
if size.to_i > 0
|
95
109
|
range = sprintf("bytes=%d-%d", offset.to_i, (offset.to_i + size.to_i) - 1)
|
96
110
|
headers['Range'] = range
|
97
111
|
end
|
98
|
-
self.container.connection.cfreq("GET"
|
99
|
-
raise
|
112
|
+
self.container.connection.cfreq("GET", @storagehost, @storagepath, @storageport, @storagescheme, headers, nil) do |response|
|
113
|
+
raise CloudFiles::Exception::NoSuchObject, "Object #{@name} does not exist" unless (response.code == "200")
|
100
114
|
response.read_body(&block)
|
101
115
|
end
|
102
116
|
end
|
@@ -108,32 +122,32 @@ module CloudFiles
|
|
108
122
|
# => {"ruby"=>"cool", "foo"=>"bar"}
|
109
123
|
def metadata
|
110
124
|
metahash = {}
|
111
|
-
|
125
|
+
self.object_metadata[:metadata].each{ |key, value| metahash[key.gsub(/x-object-meta-/, '').gsub(/\+\-/, ' ')] = URI.decode(value).gsub(/\+\-/, ' ') }
|
112
126
|
metahash
|
113
127
|
end
|
114
|
-
|
128
|
+
|
115
129
|
# Sets the metadata for an object. By passing a hash as an argument, you can set the metadata for an object.
|
116
130
|
# However, setting metadata will overwrite any existing metadata for the object.
|
117
|
-
#
|
131
|
+
#
|
118
132
|
# Throws NoSuchObjectException if the object doesn't exist. Throws InvalidResponseException if the request
|
119
133
|
# fails.
|
120
134
|
def set_metadata(metadatahash)
|
121
135
|
headers = {}
|
122
|
-
metadatahash.each{|key, value| headers['X-Object-Meta-' + key.to_s.capitalize] = value.to_s}
|
123
|
-
response = self.container.connection.cfreq("POST"
|
124
|
-
raise
|
125
|
-
raise
|
136
|
+
metadatahash.each{ |key, value| headers['X-Object-Meta-' + key.to_s.capitalize] = value.to_s }
|
137
|
+
response = self.container.connection.cfreq("POST", @storagehost, @storagepath, @storageport, @storagescheme, headers)
|
138
|
+
raise CloudFiles::Exception::NoSuchObject, "Object #{@name} does not exist" if (response.code == "404")
|
139
|
+
raise CloudFiles::Exception::InvalidResponse, "Invalid response code #{response.code}" unless (response.code == "202")
|
126
140
|
true
|
127
141
|
end
|
128
|
-
|
142
|
+
|
129
143
|
# Takes supplied data and writes it to the object, saving it. You can supply an optional hash of headers, including
|
130
144
|
# Content-Type and ETag, that will be applied to the object.
|
131
145
|
#
|
132
|
-
# If you would rather stream the data in chunks, instead of reading it all into memory at once, you can pass an
|
146
|
+
# If you would rather stream the data in chunks, instead of reading it all into memory at once, you can pass an
|
133
147
|
# IO object for the data, such as: object.write(open('/path/to/file.mp3'))
|
134
148
|
#
|
135
149
|
# You can compute your own MD5 sum and send it in the "ETag" header. If you provide yours, it will be compared to
|
136
|
-
# the MD5 sum on the server side. If they do not match, the server will return a 422 status code and a
|
150
|
+
# the MD5 sum on the server side. If they do not match, the server will return a 422 status code and a CloudFiles::Exception::MisMatchedChecksum Exception
|
137
151
|
# will be raised. If you do not provide an MD5 sum as the ETag, one will be computed on the server side.
|
138
152
|
#
|
139
153
|
# Updates the container cache and returns true on success, raises exceptions if stuff breaks.
|
@@ -153,9 +167,9 @@ module CloudFiles
|
|
153
167
|
# with no data (or, if you need to pass headers)
|
154
168
|
#
|
155
169
|
# object.write(nil,{'header' => 'value})
|
156
|
-
|
157
|
-
def write(data=nil,headers={})
|
158
|
-
raise
|
170
|
+
|
171
|
+
def write(data = nil, headers = {})
|
172
|
+
raise CloudFiles::Exception::Syntax, "No data or header updates supplied" if ((data.nil? && $stdin.tty?) and headers.empty?)
|
159
173
|
if headers['Content-Type'].nil?
|
160
174
|
type = MIME::Types.type_for(self.name).first.to_s
|
161
175
|
if type.empty?
|
@@ -166,18 +180,20 @@ module CloudFiles
|
|
166
180
|
end
|
167
181
|
# If we're taking data from standard input, send that IO object to cfreq
|
168
182
|
data = $stdin if (data.nil? && $stdin.tty? == false)
|
169
|
-
response = self.container.connection.cfreq("PUT"
|
183
|
+
response = self.container.connection.cfreq("PUT", @storagehost, "#{@storagepath}", @storageport, @storagescheme, headers, data)
|
170
184
|
code = response.code
|
171
|
-
raise
|
172
|
-
raise
|
173
|
-
raise
|
185
|
+
raise CloudFiles::Exception::InvalidResponse, "Invalid content-length header sent" if (code == "412")
|
186
|
+
raise CloudFiles::Exception::MisMatchedChecksum, "Mismatched etag" if (code == "422")
|
187
|
+
raise CloudFiles::Exception::InvalidResponse, "Invalid response code #{code}" unless (code =~ /^20./)
|
174
188
|
make_path(File.dirname(self.name)) if @make_path == true
|
175
|
-
self.
|
189
|
+
self.refresh
|
176
190
|
true
|
177
191
|
end
|
178
|
-
|
192
|
+
|
179
193
|
# A convenience method to stream data into an object from a local file (or anything that can be loaded by Ruby's open method)
|
180
194
|
#
|
195
|
+
# You can provide an optional hash of headers, in case you want to do something like set the Content-Type manually.
|
196
|
+
#
|
181
197
|
# Throws an Errno::ENOENT if the file cannot be read.
|
182
198
|
#
|
183
199
|
# object.data
|
@@ -186,21 +202,23 @@ module CloudFiles
|
|
186
202
|
# object.load_from_filename("/tmp/file.txt")
|
187
203
|
# => true
|
188
204
|
#
|
205
|
+
# object.load_from_filename("/home/rackspace/myfile.tmp", 'Content-Type' => 'text/plain')
|
206
|
+
#
|
189
207
|
# object.data
|
190
208
|
# => "This data was in the file /tmp/file.txt"
|
191
209
|
#
|
192
210
|
# object.load_from_filename("/tmp/nonexistent.txt")
|
193
211
|
# => Errno::ENOENT: No such file or directory - /tmp/nonexistent.txt
|
194
|
-
def load_from_filename(filename)
|
212
|
+
def load_from_filename(filename, headers = {})
|
195
213
|
f = open(filename)
|
196
|
-
self.write(f)
|
214
|
+
self.write(f, headers)
|
197
215
|
f.close
|
198
216
|
true
|
199
217
|
end
|
200
218
|
|
201
219
|
# A convenience method to stream data from an object into a local file
|
202
220
|
#
|
203
|
-
# Throws an Errno::ENOENT if the file cannot be opened for writing due to a path error,
|
221
|
+
# Throws an Errno::ENOENT if the file cannot be opened for writing due to a path error,
|
204
222
|
# and Errno::EACCES if the file cannot be opened for writing due to permissions.
|
205
223
|
#
|
206
224
|
# object.data
|
@@ -222,7 +240,7 @@ module CloudFiles
|
|
222
240
|
end
|
223
241
|
true
|
224
242
|
end
|
225
|
-
|
243
|
+
|
226
244
|
# If the parent container is public (CDN-enabled), returns the CDN URL to this object. Otherwise, return nil
|
227
245
|
#
|
228
246
|
# public_object.public_url
|
@@ -231,26 +249,68 @@ module CloudFiles
|
|
231
249
|
# private_object.public_url
|
232
250
|
# => nil
|
233
251
|
def public_url
|
234
|
-
self.container.public? ? self.container.cdn_url + "/#{
|
252
|
+
self.container.public? ? self.container.cdn_url + "/#{CloudFiles.escape @name}" : nil
|
235
253
|
end
|
236
254
|
|
255
|
+
# Copy this object to a new location (optionally in a new container)
|
256
|
+
#
|
257
|
+
# You must supply either a name for the new object or a container name, or both. If a :name is supplied without a :container,
|
258
|
+
# the object is copied within the current container. If the :container is specified with no :name, then the object is copied
|
259
|
+
# to the new container with its current name.
|
260
|
+
#
|
261
|
+
# object.copy(:name => "images/funny/lolcat.jpg", :container => "pictures")
|
262
|
+
#
|
263
|
+
# You may also supply a hash of headers in the :headers option. From there, you can set things like Content-Type, or other
|
264
|
+
# headers as available in the API document.
|
265
|
+
#
|
266
|
+
# object.copy(:name => 'newfile.tmp', :headers => {'Content-Type' => 'text/plain'})
|
267
|
+
#
|
268
|
+
# Returns the new CloudFiles::StorageObject for the copied item.
|
269
|
+
def copy(options = {})
|
270
|
+
raise CloudFiles::Exception::Syntax, "You must either provide the :container or the :name for this operation" unless (options[:container] || options[:name])
|
271
|
+
new_container = options[:container] || self.container.name
|
272
|
+
new_name = options[:name] || self.name
|
273
|
+
new_headers = options[:headers] || {}
|
274
|
+
raise CloudFiles::Exception::Syntax, "The :headers option must be a hash" unless new_headers.is_a?(Hash)
|
275
|
+
new_name.sub!(/^\//,'')
|
276
|
+
headers = {'X-Copy-From' => "#{self.container.name}/#{self.name}", 'Content-Type' => self.content_type.sub(/;.+/, '')}.merge(new_headers)
|
277
|
+
# , 'Content-Type' => self.content_type
|
278
|
+
new_path = self.container.connection.storagepath + "/#{CloudFiles.escape new_container}/#{CloudFiles.escape new_name}"
|
279
|
+
response = self.container.connection.cfreq("PUT", @storagehost, new_path, @storageport, @storagescheme, headers)
|
280
|
+
code = response.code
|
281
|
+
raise CloudFiles::Exception::InvalidResponse, "Invalid response code #{response.code}" unless (response.code =~ /^20/)
|
282
|
+
return CloudFiles::Container.new(self.container.connection, new_container).object(new_name)
|
283
|
+
end
|
284
|
+
|
285
|
+
# Takes the same options as the copy method, only it does a copy followed by a delete on the original object.
|
286
|
+
#
|
287
|
+
# Returns the new CloudFiles::StorageObject for the moved item. You should not attempt to use the old object after doing
|
288
|
+
# a move.
|
289
|
+
def move(options = {})
|
290
|
+
new_object = self.copy(options)
|
291
|
+
self.container.delete_object(self.name)
|
292
|
+
self.freeze
|
293
|
+
return new_object
|
294
|
+
end
|
295
|
+
|
296
|
+
|
237
297
|
def to_s # :nodoc:
|
238
298
|
@name
|
239
299
|
end
|
240
|
-
|
300
|
+
|
241
301
|
private
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
302
|
+
|
303
|
+
def make_path(path) # :nodoc:
|
304
|
+
if path == "." || path == "/"
|
305
|
+
return
|
306
|
+
else
|
307
|
+
unless self.container.object_exists?(path)
|
308
|
+
o = self.container.create_object(path)
|
309
|
+
o.write(nil, {'Content-Type' => 'application/directory'})
|
310
|
+
end
|
311
|
+
make_path(File.dirname(path))
|
250
312
|
end
|
251
|
-
make_path(File.dirname(path))
|
252
313
|
end
|
253
|
-
end
|
254
314
|
|
255
315
|
end
|
256
316
|
|
@@ -10,7 +10,7 @@ class CloudfilesAuthenticationTest < Test::Unit::TestCase
|
|
10
10
|
server = mock(:use_ssl= => true, :verify_mode= => true, :start => true, :finish => true)
|
11
11
|
server.stubs(:get).returns(response)
|
12
12
|
CloudFiles::Authentication.any_instance.stubs(:get_server).returns(server)
|
13
|
-
@connection = stub(:authuser => 'dummy_user', :authkey => 'dummy_key', :cdnmgmthost= => true, :cdnmgmtpath= => true, :cdnmgmtport= => true, :cdnmgmtscheme= => true, :storagehost= => true, :storagepath= => true, :storageport= => true, :storagescheme= => true, :authtoken= => true, :authok= => true, :snet? => false, :
|
13
|
+
@connection = stub(:authuser => 'dummy_user', :authkey => 'dummy_key', :cdnmgmthost= => true, :cdnmgmtpath= => true, :cdnmgmtport= => true, :cdnmgmtscheme= => true, :storagehost= => true, :storagepath= => true, :storageport= => true, :storagescheme= => true, :authtoken= => true, :authok= => true, :snet? => false, :auth_url => 'https://auth.api.rackspacecloud.com/v1.0')
|
14
14
|
result = CloudFiles::Authentication.new(@connection)
|
15
15
|
assert_equal result.class, CloudFiles::Authentication
|
16
16
|
end
|
@@ -21,7 +21,7 @@ class CloudfilesAuthenticationTest < Test::Unit::TestCase
|
|
21
21
|
server = mock(:use_ssl= => true, :verify_mode= => true, :start => true, :finish => true)
|
22
22
|
server.stubs(:get).returns(response)
|
23
23
|
CloudFiles::Authentication.any_instance.stubs(:get_server).returns(server)
|
24
|
-
@connection = stub(:authuser => 'dummy_user', :authkey => 'dummy_key', :cdnmgmthost= => true, :cdnmgmtpath= => true, :cdnmgmtport= => true, :cdnmgmtscheme= => true, :storagehost= => true, :storagepath= => true, :storageport= => true, :storagescheme= => true, :authtoken= => true, :authok= => true, :snet? => true, :
|
24
|
+
@connection = stub(:authuser => 'dummy_user', :authkey => 'dummy_key', :cdnmgmthost= => true, :cdnmgmtpath= => true, :cdnmgmtport= => true, :cdnmgmtscheme= => true, :storagehost= => true, :storagepath= => true, :storageport= => true, :storagescheme= => true, :authtoken= => true, :authok= => true, :snet? => true, :auth_url => 'https://auth.api.rackspacecloud.com/v1.0')
|
25
25
|
result = CloudFiles::Authentication.new(@connection)
|
26
26
|
assert_equal result.class, CloudFiles::Authentication
|
27
27
|
end
|
@@ -32,16 +32,16 @@ class CloudfilesAuthenticationTest < Test::Unit::TestCase
|
|
32
32
|
server = mock(:use_ssl= => true, :verify_mode= => true, :start => true)
|
33
33
|
server.stubs(:get).returns(response)
|
34
34
|
CloudFiles::Authentication.any_instance.stubs(:get_server).returns(server)
|
35
|
-
@connection = stub(:authuser => 'bad_user', :authkey => 'bad_key', :authok= => true, :authtoken= => true, :
|
36
|
-
assert_raises(
|
35
|
+
@connection = stub(:authuser => 'bad_user', :authkey => 'bad_key', :authok= => true, :authtoken= => true, :auth_url => 'https://auth.api.rackspacecloud.com/v1.0')
|
36
|
+
assert_raises(CloudFiles::Exception::Authentication) do
|
37
37
|
result = CloudFiles::Authentication.new(@connection)
|
38
38
|
end
|
39
39
|
end
|
40
40
|
|
41
41
|
def test_bad_hostname
|
42
|
-
Net::HTTP.stubs(:new).raises(
|
43
|
-
@connection = stub(:authuser => 'bad_user', :authkey => 'bad_key', :authok= => true, :authtoken= => true, :
|
44
|
-
assert_raises(
|
42
|
+
Net::HTTP.stubs(:new).raises(CloudFiles::Exception::Connection)
|
43
|
+
@connection = stub(:proxy_host => nil, :proxy_port => nil, :authuser => 'bad_user', :authkey => 'bad_key', :authok= => true, :authtoken= => true, :auth_url => 'https://auth.api.rackspacecloud.com/v1.0')
|
44
|
+
assert_raises(CloudFiles::Exception::Connection) do
|
45
45
|
result = CloudFiles::Authentication.new(@connection)
|
46
46
|
end
|
47
47
|
end
|
@@ -83,8 +83,8 @@ class CloudfilesConnectionTest < Test::Unit::TestCase
|
|
83
83
|
end
|
84
84
|
|
85
85
|
def test_net_http_raises_connection_exception
|
86
|
-
Net::HTTP.expects(:new).raises(
|
87
|
-
assert_raises(
|
86
|
+
Net::HTTP.expects(:new).raises(CloudFiles::Exception::Connection)
|
87
|
+
assert_raises(CloudFiles::Exception::Connection) do
|
88
88
|
response = @connection.cfreq("GET", "test.server.example", "/dummypath", "80", "http")
|
89
89
|
end
|
90
90
|
end
|
@@ -118,8 +118,9 @@ class CloudfilesConnectionTest < Test::Unit::TestCase
|
|
118
118
|
server = stub(:use_ssl= => true, :verify_mode= => true, :start => true)
|
119
119
|
server.stubs(:finish).returns(true)
|
120
120
|
server.stubs(:request).raises(EOFError)
|
121
|
+
CloudFiles::Connection.any_instance.stubs(:get_info).returns({:bytes => @bytes, :count => @count})
|
121
122
|
Net::HTTP.stubs(:new).returns(server)
|
122
|
-
assert_raises(
|
123
|
+
assert_raises(CloudFiles::Exception::Connection) do
|
123
124
|
response = @connection.cfreq("GET", "test.server.example", "/dummypath", "80", "http")
|
124
125
|
end
|
125
126
|
end
|
@@ -133,7 +134,7 @@ class CloudfilesConnectionTest < Test::Unit::TestCase
|
|
133
134
|
|
134
135
|
def test_get_info_fails
|
135
136
|
build_net_http_object(:response => {'x-account-bytes-used' => '9999', 'x-account-container-count' => '5'}, :code => '999')
|
136
|
-
assert_raises(
|
137
|
+
assert_raises(CloudFiles::Exception::InvalidResponse) do
|
137
138
|
@connection.get_info
|
138
139
|
end
|
139
140
|
end
|
@@ -154,7 +155,7 @@ class CloudfilesConnectionTest < Test::Unit::TestCase
|
|
154
155
|
|
155
156
|
def test_public_containers_exception
|
156
157
|
build_net_http_object(:code => '999')
|
157
|
-
assert_raises(
|
158
|
+
assert_raises(CloudFiles::Exception::InvalidResponse) do
|
158
159
|
public_containers = @connection.public_containers
|
159
160
|
end
|
160
161
|
end
|
@@ -167,14 +168,14 @@ class CloudfilesConnectionTest < Test::Unit::TestCase
|
|
167
168
|
|
168
169
|
def test_delete_nonempty_container
|
169
170
|
build_net_http_object(:code => '409')
|
170
|
-
assert_raises(
|
171
|
+
assert_raises(CloudFiles::Exception::NonEmptyContainer) do
|
171
172
|
response = @connection.delete_container("not_empty")
|
172
173
|
end
|
173
174
|
end
|
174
175
|
|
175
176
|
def test_delete_unknown_container
|
176
177
|
build_net_http_object(:code => '999')
|
177
|
-
assert_raises(
|
178
|
+
assert_raises(CloudFiles::Exception::NoSuchContainer) do
|
178
179
|
response = @connection.delete_container("not_empty")
|
179
180
|
end
|
180
181
|
end
|
@@ -188,7 +189,7 @@ class CloudfilesConnectionTest < Test::Unit::TestCase
|
|
188
189
|
|
189
190
|
def test_create_container_with_invalid_name
|
190
191
|
CloudFiles::Container.stubs(:new)
|
191
|
-
assert_raise(
|
192
|
+
assert_raise(CloudFiles::Exception::Syntax) do
|
192
193
|
container = @connection.create_container('a'*300)
|
193
194
|
end
|
194
195
|
end
|
@@ -196,7 +197,7 @@ class CloudfilesConnectionTest < Test::Unit::TestCase
|
|
196
197
|
def test_create_container_name_filter
|
197
198
|
CloudFiles::Container.any_instance.stubs(:populate)
|
198
199
|
build_net_http_object(:code => '201')
|
199
|
-
assert_raises(
|
200
|
+
assert_raises(CloudFiles::Exception::Syntax) do
|
200
201
|
container = @connection.create_container('this/has/bad?characters')
|
201
202
|
end
|
202
203
|
end
|
@@ -219,9 +220,9 @@ class CloudfilesConnectionTest < Test::Unit::TestCase
|
|
219
220
|
end
|
220
221
|
|
221
222
|
def test_fetch_nonexistent_container
|
222
|
-
CloudFiles::Container.any_instance.stubs(:
|
223
|
+
CloudFiles::Container.any_instance.stubs(:metadata).raises(CloudFiles::Exception::NoSuchContainer)
|
223
224
|
build_net_http_object
|
224
|
-
assert_raise(
|
225
|
+
assert_raise(CloudFiles::Exception::NoSuchContainer) do
|
225
226
|
container = @connection.container('bad_container')
|
226
227
|
end
|
227
228
|
end
|
@@ -258,7 +259,7 @@ class CloudfilesConnectionTest < Test::Unit::TestCase
|
|
258
259
|
|
259
260
|
def test_containers_bad_result
|
260
261
|
build_net_http_object(:code => '999')
|
261
|
-
assert_raises(
|
262
|
+
assert_raises(CloudFiles::Exception::InvalidResponse) do
|
262
263
|
containers = @connection.containers
|
263
264
|
end
|
264
265
|
end
|
@@ -280,7 +281,7 @@ class CloudfilesConnectionTest < Test::Unit::TestCase
|
|
280
281
|
|
281
282
|
def test_containers_detail_bad_response
|
282
283
|
build_net_http_object(:code => '999')
|
283
|
-
assert_raises(
|
284
|
+
assert_raises(CloudFiles::Exception::InvalidResponse) do
|
284
285
|
details = @connection.containers_detail
|
285
286
|
end
|
286
287
|
end
|