1
0
Fork 0
mirror of https://github.com/fog/fog.git synced 2022-11-09 13:51:43 -05:00

Merge pull request #1962 from burns/delete_multiple_objects

[rackspace|storage] add #delete_multiple_objects
This commit is contained in:
Kyle Rames 2013-07-18 06:39:16 -07:00
commit 4aac22de79
3 changed files with 149 additions and 18 deletions

View file

@ -0,0 +1,75 @@
module Fog
module Storage
class Rackspace
class Real
# Deletes multiple objects or containers with a single request.
#
# To delete objects from a single container, +container+ may be provided
# and +object_names+ should be an Array of object names within the container.
#
# To delete objects from multiple containers or delete containers,
# +container+ should be +nil+ and all +object_names+ should be prefixed with a container name.
#
# Containers must be empty when deleted. +object_names+ are processed in the order given,
# so objects within a container should be listed first to empty the container.
#
# Up to 10,000 objects may be deleted in a single request.
# The server will respond with +200 OK+ for all requests.
# +response.body+ must be inspected for actual results.
#
# @example Delete objects from a container
# object_names = ['object', 'another/object']
# conn.delete_multiple_objects('my_container', object_names)
#
# @example Delete objects from multiple containers
# object_names = ['container_a/object', 'container_b/object']
# conn.delete_multiple_objects(nil, object_names)
#
# @example Delete a container and all it's objects
# object_names = ['my_container/object_a', 'my_container/object_b', 'my_container']
# conn.delete_multiple_objects(nil, object_names)
#
# @param container [String,nil] Name of container.
# @param object_names [Array<String>] Object names to be deleted.
# @param options [Hash] Additional request headers.
#
# @return [Excon::Response]
# * body [Hash] - Results of the operation.
# * "Number Not Found" [Integer] - Number of missing objects or containers.
# * "Response Status" [String] - Response code for the subrequest of the last failed operation.
# * "Errors" [Array<object_name, response_status>]
# * object_name [String] - Object that generated an error when the delete was attempted.
# * response_status [String] - Response status from the subrequest for object_name.
# * "Number Deleted" [Integer] - Number of objects or containers deleted.
# * "Response Body" [String] - Response body for "Response Status".
#
# @raise [Fog::Storage::Rackspace::NotFound] HTTP 404
# @raise [Fog::Storage::Rackspace::BadRequest] HTTP 400
# @raise [Fog::Storage::Rackspace::InternalServerError] HTTP 500
# @raise [Fog::Storage::Rackspace::ServiceError]
# @raise [Excon::Errors::Unauthorized] HTTP 401
#
# @see http://docs.rackspace.com/files/api/v1/cf-devguide/content/Bulk_Delete-d1e2338.html
def delete_multiple_objects(container, object_names, options = {})
body = object_names.map do |name|
object_name = container ? "#{ container }/#{ name }" : name
URI.encode(object_name)
end.join("\n")
response = request({
:expects => 200,
:method => 'DELETE',
:headers => options.merge('Content-Type' => 'text/plain',
'Accept' => 'application/json'),
:body => body,
:query => { 'bulk-delete' => true }
}, false)
response.body = Fog::JSON.decode(response.body)
response
end
end
end
end
end

View file

@ -26,6 +26,7 @@ module Fog
request :delete_container
request :delete_object
request :delete_static_large_object
request :delete_multiple_objects
request :get_container
request :get_containers
request :get_object

View file

@ -17,18 +17,18 @@ Shindo.tests('Fog::Storage[:rackspace] | object requests', ["rackspace"]) do
Fog::Storage[:rackspace].put_object('fogobjecttests', 'fog_object', lorem_file)
end
tests("#get_object('fogobjectests', 'fog_object')").returns(lorem_file.read) do
tests("#get_object('fogobjectests', 'fog_object')").succeeds do
pending if Fog.mocking?
Fog::Storage[:rackspace].get_object('fogobjecttests', 'fog_object').body
Fog::Storage[:rackspace].get_object('fogobjecttests', 'fog_object').body == lorem_file.read
end
tests("#get_object('fogobjecttests', 'fog_object', &block)").returns(lorem_file.read) do
tests("#get_object('fogobjecttests', 'fog_object', &block)").succeeds do
pending if Fog.mocking?
data = ''
Fog::Storage[:rackspace].get_object('fogobjecttests', 'fog_object') do |chunk, remaining_bytes, total_bytes|
data << chunk
end
data
data == lorem_file.read
end
tests("#head_object('fogobjectests', 'fog_object')").succeeds do
@ -70,40 +70,59 @@ Shindo.tests('Fog::Storage[:rackspace] | object requests', ["rackspace"]) do
storage = Fog::Storage::Rackspace.new(:rackspace_temp_url_key => "super_secret")
storage.extend RackspaceStorageHelpers
storage.override_path('/fake_version/fake_tenant')
object_url = storage.get_object_https_url('fogobjecttests', 'fog-object', expires_at)
object_url = storage.get_object_https_url('fogobjecttests', 'fog-object', expires_at)
object_url =~ /https:\/\/.*clouddrive.com\/[^\/]+\/[^\/]+\/fogobjecttests\/fog%2Dobject\?temp_url_sig=a24dd5fc955a57adce7d1b5bc4ec2c7660ab8396&temp_url_expires=1344149532/
end
tests("put_object with block") do
tests("#put_object('fogobjecttests', 'fog_object', &block)") do
pending if Fog.mocking?
pending if Fog.mocking?
tests("#put_object('fogobjecttests', 'fog_object', &block)").succeeds do
begin
file = lorem_file
buffer_size = file.size / 2 # chop it up into two buffers
buffer_size = file.stat.size / 2 # chop it up into two buffers
Fog::Storage[:rackspace].put_object('fogobjecttests', 'fog_block_object', nil) do
if file.pos < file.size
file.sysread(buffer_size)
else
""
end
file.read(buffer_size).to_s
end
ensure
file.close
end
end
tests("object successfully uploaded?").returns(lorem_file.read) do
pending if Fog.mocking?
Fog::Storage[:rackspace].get_object('fogobjecttests', 'fog_block_object').body
tests('#get_object').succeeds do
Fog::Storage[:rackspace].get_object('fogobjecttests', 'fog_block_object').body == lorem_file.read
end
tests("delete file").succeeds do
pending if Fog.mocking?
tests('#delete_object').succeeds do
Fog::Storage[:rackspace].delete_object('fogobjecttests', 'fog_block_object')
end
end
tests('#delete_multiple_objects') do
pending if Fog.mocking?
Fog::Storage[:rackspace].put_object('fogobjecttests', 'fog_object', lorem_file)
Fog::Storage[:rackspace].put_object('fogobjecttests', 'fog_object2', lorem_file)
Fog::Storage[:rackspace].directories.create(:key => 'fogobjecttests2')
Fog::Storage[:rackspace].put_object('fogobjecttests2', 'fog_object', lorem_file)
expected = {
"Number Not Found" => 0,
"Response Status" => "200 OK",
"Errors" => [],
"Number Deleted" => 2,
"Response Body" => ""
}
returns(expected, 'deletes multiple objects') do
Fog::Storage[:rackspace].delete_multiple_objects('fogobjecttests', ['fog_object', 'fog_object2']).body
end
returns(expected, 'deletes object and container') do
Fog::Storage[:rackspace].delete_multiple_objects(nil, ['fogobjecttests2/fog_object', 'fogobjecttests2']).body
end
end
end
tests('failure') do
@ -138,6 +157,42 @@ Shindo.tests('Fog::Storage[:rackspace] | object requests', ["rackspace"]) do
Fog::Storage[:rackspace].delete_object('fognoncontainer', 'fog_non_object')
end
tests('#delete_multiple_objects') do
pending if Fog.mocking?
expected = {
"Number Not Found" => 2,
"Response Status" => "200 OK",
"Errors" => [],
"Number Deleted" => 0,
"Response Body" => ""
}
returns(expected, 'reports missing objects') do
Fog::Storage[:rackspace].delete_multiple_objects('fogobjecttests', ['fog_non_object', 'fog_non_object2']).body
end
returns(expected, 'reports missing container') do
Fog::Storage[:rackspace].delete_multiple_objects('fognoncontainer', ['fog_non_object', 'fog_non_object2']).body
end
tests('deleting non-empty container') do
Fog::Storage[:rackspace].put_object('fogobjecttests', 'fog_object', lorem_file)
expected = {
"Number Not Found" => 0,
"Response Status" => "400 Bad Request",
"Errors" => [['fogobjecttests', '409 Conflict']],
"Number Deleted" => 1,
"Response Body" => ""
}
body = Fog::Storage[:rackspace].delete_multiple_objects(nil, ['fogobjecttests', 'fogobjecttests/fog_object']).body
expected['Errors'][0][0] = body['Errors'][0][0] rescue nil
returns(expected, 'deletes object but not container') { body }
end
end
end
unless Fog.mocking?