cloudfiles 1.4.10 → 1.4.11
Sign up to get free protection for your applications and to get access to all the features.
- 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
|