diff --git a/lib/fog/bin/rackspace.rb b/lib/fog/bin/rackspace.rb index 73a34d783..193c18b80 100644 --- a/lib/fog/bin/rackspace.rb +++ b/lib/fog/bin/rackspace.rb @@ -23,6 +23,8 @@ class Rackspace < Fog::Bin Fog::Rackspace::Databases when :monitoring Fog::Rackspace::Monitoring + when :queues + Fog::Rackspace::Queues else raise ArgumentError, "Unrecognized service: #{key}" end @@ -56,6 +58,8 @@ class Rackspace < Fog::Bin Fog::Rackspace::BlockStorage.new when :monitoring Fog::Rackspace::Monitoring.new + when :queues + Fog::Rackspace::Queues.new else raise ArgumentError, "Unrecognized service: #{key.inspect}" end diff --git a/lib/fog/rackspace.rb b/lib/fog/rackspace.rb index cf52432f1..dde1cb227 100644 --- a/lib/fog/rackspace.rb +++ b/lib/fog/rackspace.rb @@ -62,7 +62,7 @@ module Fog class InternalServerError < ServiceError; end class Conflict < ServiceError; end class ServiceUnavailable < ServiceError; end - + class MethodNotAllowed < ServiceError; end class BadRequest < ServiceError #TODO - Need to find a better way to print out these validation errors when they are thrown attr_reader :validation_errors @@ -91,6 +91,7 @@ module Fog service(:identity, 'rackspace/identity', 'Identity') service(:databases, 'rackspace/databases', 'Databases') service(:monitoring, 'rackspace/monitoring', 'Monitoring') + service(:queues, 'rackspace/queues', 'Queues') def self.authenticate(options, connection_options = {}) rackspace_auth_url = options[:rackspace_auth_url] diff --git a/lib/fog/rackspace/models/queues/claim.rb b/lib/fog/rackspace/models/queues/claim.rb new file mode 100644 index 000000000..af6521833 --- /dev/null +++ b/lib/fog/rackspace/models/queues/claim.rb @@ -0,0 +1,92 @@ +require 'fog/core/model' + +module Fog + module Rackspace + class Queues + class Claim < Fog::Model + + identity :identity + + attribute :grace + attribute :ttl + attribute :limit + attribute :messages + + def save + if identity.nil? + create + else + update + end + end + + def destroy + requires :identity, :queue + service.delete_claim(queue.name, identity) + + #Since Claims aren't a server side collection, we should remove + # the claim from the collection. + collection.delete(self) + + true + end + + def messages=(messages) + #HACK - Models require a collection, but I don't really want to expose + # the messages collection to users here. + message_collection = Fog::Rackspace::Queues::Messages.new({ + :service => service, + :queue => queue, + :client_id => service.client_id, + :echo => true + }) + attributes[:messages] = messages.collect do |message| + if message.instance_of? Fog::Rackspace::Queues::Message + message + else + Fog::Rackspace::Queues::Message.new( + message.merge({ + :service => service, + :collection => message_collection + }.merge(message)) + ) + end + end + end + + private + + def queue + collection.queue + end + + def create + requires :queue, :ttl, :grace, :collection + + options = {} + options[:limit] = limit unless limit.nil? + + response = service.create_claim(queue.identity, ttl, grace, options) + + if [200, 201].include? response.status + self.identity = response.headers['Location'].split('/').last + self.messages = response.body + + #Since Claims aren't a server side collection, we need to + # add the claim to the collection + collection << self + true + else + false + end + end + + def update + requires :identity, :queue, :ttl + service.update_claim(queue.identity, identity, ttl) + true + end + end + end + end +end diff --git a/lib/fog/rackspace/models/queues/claims.rb b/lib/fog/rackspace/models/queues/claims.rb new file mode 100644 index 000000000..2948cca5d --- /dev/null +++ b/lib/fog/rackspace/models/queues/claims.rb @@ -0,0 +1,40 @@ +require 'fog/core/collection' +require 'fog/rackspace/models/queues/claim' + +module Fog + module Rackspace + class Queues + class Claims < Fog::Collection + + model Fog::Rackspace::Queues::Claim + + attr_accessor :queue + + def all + self + end + + def create(attributes = {}) + object = new(attributes) + if object.save + object + else + false + end + end + + def get(claim_id) + requires :queue + data = service.get_claim(queue.identity, claim_id).body + new(data) + rescue Fog::Rackspace::Queues::NotFound + nil + # HACK - This has been escalated to the Rackspace Queues team, as this + # behavior is not normal HTTP behavior. + rescue Fog::Rackspace::Queues::ServiceError + nil + end + end + end + end +end diff --git a/lib/fog/rackspace/models/queues/message.rb b/lib/fog/rackspace/models/queues/message.rb new file mode 100644 index 000000000..0d9415ebe --- /dev/null +++ b/lib/fog/rackspace/models/queues/message.rb @@ -0,0 +1,51 @@ +require 'fog/core/model' + +module Fog + module Rackspace + class Queues + class Message < Fog::Model + + attribute :age + attribute :ttl + attribute :body + attribute :href + attribute :claim_id + + def identity + if href + href.split('/').last + else + nil + end + end + + def save + requires :queue, :client_id, :body, :ttl + raise "Message has already been created and may not be updated." unless identity.nil? + data = service.create_message(client_id, queue.name, body, ttl).body + self.href = data['resources'][0] + true + end + + def destroy + requires :identity, :queue + options = {} + options[:claim_id] = claim_id unless claim_id.nil? + + service.delete_message(queue.name, identity, options) + true + end + + private + + def queue + collection.queue + end + + def client_id + collection.client_id + end + end + end + end +end diff --git a/lib/fog/rackspace/models/queues/messages.rb b/lib/fog/rackspace/models/queues/messages.rb new file mode 100644 index 000000000..600792a46 --- /dev/null +++ b/lib/fog/rackspace/models/queues/messages.rb @@ -0,0 +1,54 @@ +require 'fog/core/collection' +require 'fog/rackspace/models/queues/message' + +module Fog + module Rackspace + class Queues + class Messages < Fog::Collection + + model Fog::Rackspace::Queues::Message + + attr_accessor :client_id + attr_accessor :queue + attr_accessor :echo + attr_accessor :limit + attr_accessor :marker + attr_accessor :include_claimed + + def all + requires :client_id, :queue + response = service.list_messages(client_id, queue.name, options) + if response.status == 204 + data = [] + else + data = response.body['messages'] + end + load(data) + end + + def get(message_id) + requires :client_id, :queue + data = service.get_message(client_id, queue.name, message_id).body + new(data) + rescue Fog::Rackspace::Queues::NotFound + nil + # HACK - This has been escalated to the Rackspace Queues team, as this + # behavior is not normal HTTP behavior. + rescue Fog::Rackspace::Queues::ServiceError + nil + end + + private + + def options + data = {} + data[:echo] = echo.to_s unless echo.nil? + data[:limit] = limit.to_s unless limit.nil? + data[:marker] = marker.to_s unless marker.nil? + data[:include_claimed] = include_claimed.to_s unless include_claimed.nil? + data + end + end + end + end +end diff --git a/lib/fog/rackspace/models/queues/queue.rb b/lib/fog/rackspace/models/queues/queue.rb new file mode 100644 index 000000000..6c81ac7bd --- /dev/null +++ b/lib/fog/rackspace/models/queues/queue.rb @@ -0,0 +1,73 @@ +require 'fog/core/model' + +module Fog + module Rackspace + class Queues + class Queue < Fog::Model + + identity :name + + def messages + @messages ||= begin + Fog::Rackspace::Queues::Messages.new({ + :service => service, + :queue => self, + :client_id => service.client_id, + :echo => true + }) + end + end + + def stats + service.get_queue_stats(name).body['messages'] + end + + def claims + @claims ||= begin + Fog::Rackspace::Queues::Claims.new({ + :service => service, + :queue => self + }) + end + end + + #Helper method to enqueue a single message + def enqueue(body, ttl, options = {}) + messages.create(options.merge(options.merge({:body => body, :ttl => ttl}))) + end + + #Helper method to claim (dequeue) a single message, including destroying it + def dequeue(ttl, grace, options = {}) + claim = claims.create( + options.merge( + { + :limit => 1, + :ttl => ttl, + :grace => grace + })) + + if claim + message = claim.messages.first + yield message + message.destroy + true + else + false + end + end + + def save + requires :name + data = service.create_queue(name) + true + end + + def destroy + requires :name + service.delete_queue(name) + true + end + end + end + end +end diff --git a/lib/fog/rackspace/models/queues/queues.rb b/lib/fog/rackspace/models/queues/queues.rb new file mode 100644 index 000000000..32aa6fea8 --- /dev/null +++ b/lib/fog/rackspace/models/queues/queues.rb @@ -0,0 +1,32 @@ +require 'fog/core/collection' +require 'fog/rackspace/models/queues/queue' + +module Fog + module Rackspace + class Queues + class Queues < Fog::Collection + + model Fog::Rackspace::Queues::Queue + + def all + response = service.list_queues + if service.list_queues.status == 204 + data = [] + else + data = service.list_queues.body['queues'] + end + load(data) + end + + def get(queue_name) + #204 no content is returned on success. That's why no data is passed + # from the GET to the constructor. + service.get_queue(queue_name) + new({:name => queue_name}) + rescue Fog::Rackspace::Queues::NotFound + nil + end + end + end + end +end diff --git a/lib/fog/rackspace/queues.rb b/lib/fog/rackspace/queues.rb new file mode 100644 index 000000000..d7e7a2d43 --- /dev/null +++ b/lib/fog/rackspace/queues.rb @@ -0,0 +1,130 @@ +require File.expand_path(File.join(File.dirname(__FILE__), '..', 'rackspace')) + +module Fog + module Rackspace + class Queues < Fog::Service + include Fog::Rackspace::Errors + + class ServiceError < Fog::Rackspace::Errors::ServiceError; end + class InternalServerError < Fog::Rackspace::Errors::InternalServerError; end + class BadRequest < Fog::Rackspace::Errors::BadRequest; end + class MethodNotAllowed < Fog::Rackspace::Errors::BadRequest; end + + requires :rackspace_api_key, :rackspace_username, :rackspace_queues_client_id + recognizes :rackspace_auth_url + recognizes :rackspace_auth_token + recognizes :rackspace_endpoint + recognizes :rackspace_region + recognizes :rackspace_queues_url + + + model_path 'fog/rackspace/models/queues' + model :queue + collection :queues + model :message + collection :messages + model :claim + collection :claims + + request_path 'fog/rackspace/requests/queues' + request :list_queues + request :get_queue + request :create_queue + request :delete_queue + request :get_queue_stats + + request :list_messages + request :get_message + request :create_message + request :delete_message + request :create_claim + request :get_claim + request :update_claim + request :delete_claim + + class Mock < Fog::Rackspace::Service + def request(params) + Fog::Mock.not_implemented + end + end + + class Real < Fog::Rackspace::Service + + def service_name + :cloudQueues + end + + def region + @rackspace_region + end + + def initialize(options = {}) + @rackspace_api_key = options[:rackspace_api_key] + @rackspace_username = options[:rackspace_username] + @rackspace_queues_client_id = options[:rackspace_queues_client_id] + @rackspace_auth_url = options[:rackspace_auth_url] + @rackspace_must_reauthenticate = false + @connection_options = options[:connection_options] || {} + @rackspace_endpoint = Fog::Rackspace.normalize_url(options[:rackspace_queues_url] || options[:rackspace_endpoint]) + + unless v2_authentication? + raise Fog::Errors::NotImplemented.new("V2 authentication required for Queues") + end + + authenticate + + deprecation_warnings(options) + + @persistent = options[:persistent] || false + @connection = Fog::Connection.new(endpoint_uri.to_s, @persistent, @connection_options) + end + + def request(params, parse_json = true, &block) + super(params, parse_json, &block) + rescue Excon::Errors::NotFound => error + raise NotFound.slurp(error, region) + rescue Excon::Errors::BadRequest => error + raise BadRequest.slurp error + rescue Excon::Errors::InternalServerError => error + raise InternalServerError.slurp error + rescue Excon::Errors::MethodNotAllowed => error + raise MethodNotAllowed.slurp error + rescue Excon::Errors::HTTPStatusError => error + raise ServiceError.slurp error + end + + def endpoint_uri(service_endpoint_url=nil) + @uri = super(@rackspace_endpoint || service_endpoint_url, :rackspace_queues_url) + end + + def authenticate(options={}) + super({ + :rackspace_api_key => @rackspace_api_key, + :rackspace_username => @rackspace_username, + :rackspace_auth_url => @rackspace_auth_url, + :connection_options => @connection_options + }) + end + + def client_id + @rackspace_queues_client_id + end + + def client_id=(client_id) + @rackspace_queues_client_id = client_id + end + + private + + def deprecation_warnings(options) + Fog::Logger.deprecation("The :rackspace_endpoint option is deprecated. Please use :rackspace_queues_url for custom endpoints") if options[:rackspace_endpoint] + + # if [DFW_ENDPOINT, ORD_ENDPOINT, LON_ENDPOINT].include?(@rackspace_endpoint) && v2_authentication? + # regions = @identity_service.service_catalog.display_service_regions(service_name) + # Fog::Logger.deprecation("Please specify region using :rackspace_region rather than :rackspace_endpoint. Valid region for :rackspace_region are #{regions}.") + # end + end + end + end + end +end diff --git a/lib/fog/rackspace/requests/queues/create_claim.rb b/lib/fog/rackspace/requests/queues/create_claim.rb new file mode 100644 index 000000000..b66e5d9be --- /dev/null +++ b/lib/fog/rackspace/requests/queues/create_claim.rb @@ -0,0 +1,24 @@ +module Fog + module Rackspace + class Queues + class Real + def create_claim(queue_name, ttl, grace, options = {}) + body = { + :ttl => ttl, + :grace => grace + } + + query = {} + query[:limit] = options[:limit] if options.has_key? :limit + request( + :body => Fog::JSON.encode(body), + :expects => [200, 201, 204], + :method => 'POST', + :path => "queues/#{queue_name}/claims", + :query => query + ) + end + end + end + end +end diff --git a/lib/fog/rackspace/requests/queues/create_message.rb b/lib/fog/rackspace/requests/queues/create_message.rb new file mode 100644 index 000000000..d6f9d2022 --- /dev/null +++ b/lib/fog/rackspace/requests/queues/create_message.rb @@ -0,0 +1,21 @@ +module Fog + module Rackspace + class Queues + class Real + def create_message(client_id, queue_name, body, ttl) + data = [{ + :ttl => ttl, + :body => body + }] + request( + :body => Fog::JSON.encode(data), + :expects => 201, + :method => 'POST', + :path => "queues/#{queue_name}/messages", + :headers => { 'Client-ID' => client_id } + ) + end + end + end + end +end diff --git a/lib/fog/rackspace/requests/queues/create_queue.rb b/lib/fog/rackspace/requests/queues/create_queue.rb new file mode 100644 index 000000000..6abc90114 --- /dev/null +++ b/lib/fog/rackspace/requests/queues/create_queue.rb @@ -0,0 +1,16 @@ +module Fog + module Rackspace + class Queues + class Real + def create_queue(queue_name) + request( + :body => Fog::JSON.encode({}), + :expects => 201, + :method => 'PUT', + :path => "queues/#{queue_name}" + ) + end + end + end + end +end diff --git a/lib/fog/rackspace/requests/queues/delete_claim.rb b/lib/fog/rackspace/requests/queues/delete_claim.rb new file mode 100644 index 000000000..374efeb35 --- /dev/null +++ b/lib/fog/rackspace/requests/queues/delete_claim.rb @@ -0,0 +1,15 @@ +module Fog + module Rackspace + class Queues + class Real + def delete_claim(queue_name, claim_id) + request( + :expects => 204, + :method => 'DELETE', + :path => "queues/#{queue_name}/claims/#{claim_id}" + ) + end + end + end + end +end diff --git a/lib/fog/rackspace/requests/queues/delete_message.rb b/lib/fog/rackspace/requests/queues/delete_message.rb new file mode 100644 index 000000000..9331df783 --- /dev/null +++ b/lib/fog/rackspace/requests/queues/delete_message.rb @@ -0,0 +1,18 @@ +module Fog + module Rackspace + class Queues + class Real + def delete_message(queue_name, message_id, options = {}) + query = {} + query[:claim_id] = options[:claim_id] if options.has_key? :claim_id + request( + :expects => 204, + :method => 'DELETE', + :path => "queues/#{queue_name}/messages/#{message_id}", + :query => query + ) + end + end + end + end +end diff --git a/lib/fog/rackspace/requests/queues/delete_queue.rb b/lib/fog/rackspace/requests/queues/delete_queue.rb new file mode 100644 index 000000000..85a52955d --- /dev/null +++ b/lib/fog/rackspace/requests/queues/delete_queue.rb @@ -0,0 +1,15 @@ +module Fog + module Rackspace + class Queues + class Real + def delete_queue(queue_name) + request( + :expects => 204, + :method => 'DELETE', + :path => "queues/#{queue_name}" + ) + end + end + end + end +end diff --git a/lib/fog/rackspace/requests/queues/get_claim.rb b/lib/fog/rackspace/requests/queues/get_claim.rb new file mode 100644 index 000000000..3220eab5e --- /dev/null +++ b/lib/fog/rackspace/requests/queues/get_claim.rb @@ -0,0 +1,15 @@ +module Fog + module Rackspace + class Queues + class Real + def get_claim(queue_name, claim_id) + request( + :expects => 200, + :method => 'GET', + :path => "queues/#{queue_name}/claims/#{claim_id}" + ) + end + end + end + end +end diff --git a/lib/fog/rackspace/requests/queues/get_message.rb b/lib/fog/rackspace/requests/queues/get_message.rb new file mode 100644 index 000000000..71654bd1c --- /dev/null +++ b/lib/fog/rackspace/requests/queues/get_message.rb @@ -0,0 +1,16 @@ +module Fog + module Rackspace + class Queues + class Real + def get_message(client_id, queue_name, message_id) + request( + :expects => 200, + :method => 'GET', + :path => "queues/#{queue_name}/messages/#{message_id}", + :headers => { 'Client-ID' => client_id } + ) + end + end + end + end +end diff --git a/lib/fog/rackspace/requests/queues/get_queue.rb b/lib/fog/rackspace/requests/queues/get_queue.rb new file mode 100644 index 000000000..78ee5b234 --- /dev/null +++ b/lib/fog/rackspace/requests/queues/get_queue.rb @@ -0,0 +1,15 @@ +module Fog + module Rackspace + class Queues + class Real + def get_queue(queue_name) + request( + :expects => [200, 204], + :method => 'GET', + :path => "queues/#{queue_name}" + ) + end + end + end + end +end diff --git a/lib/fog/rackspace/requests/queues/get_queue_stats.rb b/lib/fog/rackspace/requests/queues/get_queue_stats.rb new file mode 100644 index 000000000..3a7490ea5 --- /dev/null +++ b/lib/fog/rackspace/requests/queues/get_queue_stats.rb @@ -0,0 +1,15 @@ +module Fog + module Rackspace + class Queues + class Real + def get_queue_stats(queue_name) + request( + :expects => 200, + :method => 'GET', + :path => "queues/#{queue_name}/stats" + ) + end + end + end + end +end diff --git a/lib/fog/rackspace/requests/queues/list_messages.rb b/lib/fog/rackspace/requests/queues/list_messages.rb new file mode 100644 index 000000000..127fb0815 --- /dev/null +++ b/lib/fog/rackspace/requests/queues/list_messages.rb @@ -0,0 +1,17 @@ +module Fog + module Rackspace + class Queues + class Real + def list_messages(client_id, queue_name, options = {}) + request( + :expects => [200, 204], + :method => 'GET', + :path => "queues/#{queue_name}/messages", + :headers => { 'Client-ID' => client_id }, + :query => options + ) + end + end + end + end +end diff --git a/lib/fog/rackspace/requests/queues/list_queues.rb b/lib/fog/rackspace/requests/queues/list_queues.rb new file mode 100644 index 000000000..f39f54bdb --- /dev/null +++ b/lib/fog/rackspace/requests/queues/list_queues.rb @@ -0,0 +1,15 @@ +module Fog + module Rackspace + class Queues + class Real + def list_queues + request( + :expects => [200, 204], + :method => 'GET', + :path => 'queues' + ) + end + end + end + end +end diff --git a/lib/fog/rackspace/requests/queues/update_claim.rb b/lib/fog/rackspace/requests/queues/update_claim.rb new file mode 100644 index 000000000..2e9c4af34 --- /dev/null +++ b/lib/fog/rackspace/requests/queues/update_claim.rb @@ -0,0 +1,19 @@ +module Fog + module Rackspace + class Queues + class Real + def update_claim(queue_name, claim_id, ttl) + body = { + :ttl => ttl + } + request( + :body => Fog::JSON.encode(body), + :expects => 204, + :method => 'PATCH', + :path => "queues/#{queue_name}/claims/#{claim_id}" + ) + end + end + end + end +end diff --git a/tests/rackspace/models/queues/claim_tests.rb b/tests/rackspace/models/queues/claim_tests.rb new file mode 100644 index 000000000..f3669e31d --- /dev/null +++ b/tests/rackspace/models/queues/claim_tests.rb @@ -0,0 +1,43 @@ +Shindo.tests('Fog::Rackspace::Queues | claim', ['rackspace']) do + + pending if Fog.mocking? + + service = Fog::Rackspace::Queues.new + queue = service.queues.create({ + :name => "fog_queue_#{Time.now.to_i.to_s}", + }) + queue.messages.create({ + :ttl => VALID_TTL, + :body => { :random => :body } + }) + + params = { + :ttl => VALID_TTL, + :grace => VALID_GRACE + } + + begin + model_tests(queue.claims, params, false) do + tests('#messages') do + returns(1) { @instance.messages.length } + returns('body') { @instance.messages.first.body['random'] } + end + + tests('#update').succeeds do + @instance.ttl = VALID_TTL + 5 + @instance.save + end + end + + queue.messages.create({ + :ttl => VALID_TTL, + :body => { :random => :body } + }) + tests('destroying claimed messages').succeeds do + claim = queue.claims.create(params) + claim.messages.first.destroy + end + ensure + queue.destroy + end +end diff --git a/tests/rackspace/models/queues/claims_tests.rb b/tests/rackspace/models/queues/claims_tests.rb new file mode 100644 index 000000000..47ba9d5de --- /dev/null +++ b/tests/rackspace/models/queues/claims_tests.rb @@ -0,0 +1,55 @@ +Shindo.tests('Fog::Rackspace::Queues | claims', ['rackspace']) do + + pending if Fog.mocking? + + service = Fog::Rackspace::Queues.new + queue = service.queues.create({ + :name => "fog_queue_#{Time.now.to_i.to_s}", + }) + queue.messages.create({ + :ttl => VALID_TTL, + :body => { :random => :body } + }) + params = { + :ttl => VALID_TTL, + :grace => VALID_GRACE + } + + begin + collection_tests(queue.claims, params, false) + + tests('creating claims when there are no messages') do + + before do + #clear all message from queue + queue.messages.all.each do |message| + message.destroy + end + end + + tests("#create(#{params.inspect}) => with no messages does not show up in claim list") do + returns(false) { queue.claims.create(params) } + returns(true) { queue.claims.empty? } + end + end + + tests('create claims when there are messages') do + + before do + queue.messages.create({ + :ttl => VALID_TTL, + :body => { :random => :body } + }) + end + + tests("#create(#{params.inspect}) => with messages does show up in claim list") do + returns(true) do + queue.claims.create(params).instance_of? Fog::Rackspace::Queues::Claim + end + returns(false) { queue.claims.empty? } + end + end + ensure + queue.destroy + end +end diff --git a/tests/rackspace/models/queues/message_tests.rb b/tests/rackspace/models/queues/message_tests.rb new file mode 100644 index 000000000..347aae4ff --- /dev/null +++ b/tests/rackspace/models/queues/message_tests.rb @@ -0,0 +1,33 @@ +Shindo.tests('Fog::Rackspace::Queues | message', ['rackspace']) do + + pending if Fog.mocking? + + service = Fog::Rackspace::Queues.new + queue = service.queues.create({ + :name => "fog_instance_#{Time.now.to_i.to_s}", + }) + options = { + :ttl => VALID_TTL, + :body => { :key => 'value' } + } + begin + model_tests(queue.messages, options, false) do + tests('#href').returns(true) do + !@instance.href.nil? + end + tests('#identity').returns(true) do + !@instance.identity.nil? + end + tests('#save => Fails to update').raises(StandardError) do + @instance.save + end + end + + message = queue.messages.create(options.merge({:claim_id => '10'})) + tests('#destroy => fails if claim is not valid').raises(Fog::Rackspace::Queues::ServiceError) do + message.destroy + end + ensure + queue.destroy + end +end diff --git a/tests/rackspace/models/queues/messages_tests.rb b/tests/rackspace/models/queues/messages_tests.rb new file mode 100644 index 000000000..ab5bb8796 --- /dev/null +++ b/tests/rackspace/models/queues/messages_tests.rb @@ -0,0 +1,18 @@ +Shindo.tests('Fog::Rackspace::Queues | messages', ['rackspace']) do + + pending if Fog.mocking? + + service = Fog::Rackspace::Queues.new + queue = service.queues.create({ + :name => "fog_queue_#{Time.now.to_i.to_s}", + }) + + options = { + :ttl => 300, + :body => "blah" + } + + collection_tests(queue.messages, options, false) + + queue.destroy +end diff --git a/tests/rackspace/models/queues/queue_tests.rb b/tests/rackspace/models/queues/queue_tests.rb new file mode 100644 index 000000000..b51b72be1 --- /dev/null +++ b/tests/rackspace/models/queues/queue_tests.rb @@ -0,0 +1,30 @@ +Shindo.tests('Fog::Rackspace::Queues | queue', ['rackspace']) do + + pending if Fog.mocking? + + service = Fog::Rackspace::Queues.new + options = { + :name => "fog_instance_#{Time.now.to_i.to_s}", + } + model_tests(service.queues, options, false) do + + tests('#stats').formats(QUEUE_STATS_FORMAT['messages']) do + @instance.stats + end + + tests('#enqueue("msg", 60)') do + @instance.enqueue("msg", 60) + end + + tests('#dequeue(60, 60)').returns(true) do + @instance.dequeue(60, 60) do |message| + returns("msg") { message.body } + end + end + + tests('#dequeue(60, 60) => with not messages').returns(false) do + @instance.dequeue(60, 60) do |message| + end + end + end +end diff --git a/tests/rackspace/models/queues/queues_tests.rb b/tests/rackspace/models/queues/queues_tests.rb new file mode 100644 index 000000000..15970aade --- /dev/null +++ b/tests/rackspace/models/queues/queues_tests.rb @@ -0,0 +1,10 @@ +Shindo.tests('Fog::Rackspace::Queues | queues', ['rackspace']) do + + pending if Fog.mocking? + + service = Fog::Rackspace::Queues.new + options = { + :name => "fog_instance_#{Time.now.to_i.to_s}", + } + collection_tests(service.queues, options, false) +end diff --git a/tests/rackspace/queues_tests.rb b/tests/rackspace/queues_tests.rb new file mode 100644 index 000000000..ea07ef506 --- /dev/null +++ b/tests/rackspace/queues_tests.rb @@ -0,0 +1,105 @@ +Shindo.tests('Fog::Rackspace::Queues', ['rackspace']) do + + pending if Fog.mocking? + + + def assert_method(url, method) + @service.instance_variable_set "@rackspace_auth_url", url + returns(method) { @service.send :authentication_method } + end + + tests('#authentication_method') do + @service = Fog::Rackspace::Queues.new + + assert_method nil, :authenticate_v2 + + assert_method 'https://identity.api.rackspacecloud.com', :authenticate_v1 + assert_method 'https://identity.api.rackspacecloud.com/v1', :authenticate_v1 + assert_method 'https://identity.api.rackspacecloud.com/v1.1', :authenticate_v1 + assert_method 'https://identity.api.rackspacecloud.com/v2.0', :authenticate_v2 + + assert_method 'https://lon.identity.api.rackspacecloud.com', :authenticate_v1 + assert_method 'https://lon.identity.api.rackspacecloud.com/v1', :authenticate_v1 + assert_method 'https://lon.identity.api.rackspacecloud.com/v1.1', :authenticate_v1 + assert_method 'https://lon.identity.api.rackspacecloud.com/v2.0', :authenticate_v2 + end + + tests('authentication v1') do + pending if Fog.mocking? + + raises(Fog::Errors::NotImplemented) do + @service = Fog::Rackspace::Queues.new :rackspace_auth_url => 'https://identity.api.rackspacecloud.com/v1.0' + end + end + + tests('authentication v2') do + pending if Fog.mocking? + + tests('variables populated').succeeds do + @service = Fog::Rackspace::Queues.new :rackspace_auth_url => 'https://identity.api.rackspacecloud.com/v2.0', :connection_options => { :ssl_verify_peer => true } + returns(true, "auth token populated") { !@service.send(:auth_token).nil? } + returns(false, "path populated") { @service.instance_variable_get("@uri").nil? } + + identity_service = @service.instance_variable_get("@identity_service") + returns(false, "identity service was used") { identity_service.nil? } + returns(true, "connection_options are passed") { identity_service.instance_variable_get("@connection_options").has_key?(:ssl_verify_peer) } + @service.queues + end + tests('dfw region').succeeds do + @service = Fog::Rackspace::Queues.new :rackspace_auth_url => 'https://identity.api.rackspacecloud.com/v2.0', :rackspace_region => :dfw + returns(true, "auth token populated") { !@service.send(:auth_token).nil? } + returns(true) { (@service.instance_variable_get("@uri").host =~ /dfw/) != nil } + @service.queues + end + tests('ord region').succeeds do + @service = Fog::Rackspace::Queues.new :rackspace_auth_url => 'https://identity.api.rackspacecloud.com/v2.0', :rackspace_region => :ord + returns(true, "auth token populated") { !@service.send(:auth_token).nil? } + returns(true) { (@service.instance_variable_get("@uri").host =~ /ord/) != nil } + @service.queues + end + tests('custom endpoint') do + @service = Fog::Rackspace::Queues.new :rackspace_auth_url => 'https://identity.api.rackspacecloud.com/v2.0', + :rackspace_queues_url => 'https://my-custom-endpoint.com' + returns(true, "auth token populated") { !@service.send(:auth_token).nil? } + returns(true, "uses custom endpoint") { (@service.instance_variable_get("@uri").host =~ /my-custom-endpoint\.com/) != nil } + end + end + + tests('default auth') do + pending if Fog.mocking? + + tests('no params').succeeds do + @service = Fog::Rackspace::Queues.new + returns(true, "auth token populated") { !@service.send(:auth_token).nil? } + returns(true) { (@service.instance_variable_get("@uri").host =~ /dfw/) != nil } + @service.queues + end + tests('specify region').succeeds do + @service = Fog::Rackspace::Queues.new :rackspace_region => :ord + returns(true, "auth token populated") { !@service.send(:auth_token).nil? } + returns(true) { (@service.instance_variable_get("@uri").host =~ /ord/ ) != nil } + @service.queues + end + tests('custom endpoint') do + @service = Fog::Rackspace::Queues.new :rackspace_queues_url => 'https://my-custom-endpoint.com' + returns(true, "auth token populated") { !@service.send(:auth_token).nil? } + returns(true, "uses custom endpoint") { (@service.instance_variable_get("@uri").host =~ /my-custom-endpoint\.com/) != nil } + end + end + + tests('reauthentication') do + pending if Fog.mocking? + + @service = Fog::Rackspace::Queues.new + returns(true, "auth token populated") { !@service.send(:auth_token).nil? } + @service.instance_variable_set("@auth_token", "bad_token") + returns(200) { @service.list_queues.status } + end + + @service = Fog::Rackspace::Queues.new + + tests('#queues').succeeds do + data = @service.queues + returns(true) { data.is_a? Array } + end +end diff --git a/tests/rackspace/requests/queues/claim_tests.rb b/tests/rackspace/requests/queues/claim_tests.rb new file mode 100644 index 000000000..3e5f9c25b --- /dev/null +++ b/tests/rackspace/requests/queues/claim_tests.rb @@ -0,0 +1,63 @@ + Shindo.tests('Fog::Rackspace::Queues | claim_tests', ['rackspace']) do + + pending if Fog.mocking? + + service = Fog::Rackspace::Queues.new + + queue_name = 'fog' + Time.now.to_i.to_s + client_id = 'fog-client-' + Time.now.to_i.to_s + claim_id = nil + + service.create_queue(queue_name) + + tests('success') do + + tests("#create_claim(#{queue_name}, #{VALID_TTL}, #{VALID_GRACE}) => No Messages").returns(204) do + service.create_claim(queue_name, VALID_TTL, VALID_GRACE).status + end + + tests('with messages in the queue') do + + before do + service.create_message(client_id, queue_name, { :message => "message-body"}, 300) + end + + #TODO - Fix it so simple text bodies pass validation + tests("#create_claim(#{queue_name}, #{VALID_TTL}, #{VALID_GRACE})").formats(CREATE_CLAIM_FORMAT) do + response = service.create_claim(queue_name, VALID_TTL, VALID_GRACE) + claim_id = response.headers['Location'].split('/').last + response.body + end + + tests("#get_claim(#{queue_name}, #{claim_id})").formats(CLAIM_FORMAT) do + service.get_claim(queue_name, claim_id).body + end + + tests("#update_claim(#{queue_name}, #{claim_id}, 500)").succeeds do + service.update_claim(queue_name, claim_id, 500) + end + + tests("#delete_claim(#{queue_name}, #{claim_id})").succeeds do + service.delete_claim(queue_name, claim_id) + end + + tests("#create_claim(#{queue_name}, #{VALID_TTL}, #{VALID_GRACE}, { :limit => 1})") do + response = service.create_claim(queue_name, VALID_TTL, VALID_GRACE, { :limit => 1}) + + formats(CREATE_CLAIM_FORMAT) { response.body } + returns(1) { response.body.length } + end + end + end + + tests('failure') do + #TODO - Escalate to queueing team + tests("#get_claim('queue_name', 'nonexistentclaim') => Does not exist").raises(Fog::Rackspace::Queues::ServiceError) do + service.get_claim(queue_name, 'nonexistentclaim') + end + + end + + service.delete_queue(queue_name) + +end diff --git a/tests/rackspace/requests/queues/helper.rb b/tests/rackspace/requests/queues/helper.rb new file mode 100644 index 000000000..e92cde4d0 --- /dev/null +++ b/tests/rackspace/requests/queues/helper.rb @@ -0,0 +1,55 @@ +VALID_TTL = 300 +VALID_GRACE = 300 + +LINKS_FORMAT = [{ + 'href' => String, + 'rel' => String +}] + +METADATA_FORMAT = { +} + +QUEUE_FORMAT = { + 'metadata' => METADATA_FORMAT +} + +LIST_QUEUES_FORMAT = { + 'queues' => [ + QUEUE_FORMAT.merge({ + 'name' => String, + 'href' => String, + }) + ], + 'links' => LINKS_FORMAT +} + +MESSAGE_FORMAT = { + 'href' => String, + 'ttl' => Integer, + 'age' => Integer, + 'body' => Hash +} + +LIST_MESSAGES_FORMAT = { + 'messages' => [MESSAGE_FORMAT], + 'links' => LINKS_FORMAT +} + +CREATE_CLAIM_FORMAT = [ + MESSAGE_FORMAT +] + +CLAIM_FORMAT = { + 'ttl' => Integer, + 'age' => Integer, + 'messages' => [ + MESSAGE_FORMAT + ] +} + +QUEUE_STATS_FORMAT = { + 'messages' => { + 'free' => Integer, + 'claimed' => Integer + } +} diff --git a/tests/rackspace/requests/queues/messages_tests.rb b/tests/rackspace/requests/queues/messages_tests.rb new file mode 100644 index 000000000..e2892af2b --- /dev/null +++ b/tests/rackspace/requests/queues/messages_tests.rb @@ -0,0 +1,60 @@ +Shindo.tests('Fog::Rackspace::Queues | messages_tests', ['rackspace']) do + + pending if Fog.mocking? + + service = Fog::Rackspace::Queues.new + + queue_name = 'fog' + Time.now.to_i.to_s + client_id = 'fog-client-' + Time.now.to_i.to_s + message_id = nil + + service.create_queue(queue_name) + + begin + + tests('success') do + + + tests("#list_message(#{client_id}, #{queue_name}, {:echo => true}) => No Content").returns(204) do + service.list_messages(client_id, queue_name, {:echo => true}).status + end + + tests("#create_message(#{client_id}, #{queue_name}, '{ :blah => 'blah' }', 300)").succeeds do + response = service.create_message(client_id, queue_name, { :blah => 'blah' }, 300) + message_id = response.body['resources'][0].split('/').last + end + + tests("#list_message(#{client_id}, #{queue_name}, {:echo => true}) => With Content").formats(LIST_MESSAGES_FORMAT) do + service.list_messages(client_id, queue_name, {:echo => true}).body + end + + tests("#get_message(#{client_id}, #{queue_name}, #{message_id})").formats(MESSAGE_FORMAT) do + service.get_message(client_id, queue_name, message_id).body + end + + #TODO - Report bad error code to queueing team + tests("#delete_message(#{queue_name}, #{message_id}, { :claim_id => '10' })").raises(Fog::Rackspace::Queues::ServiceError) do + service.delete_message(queue_name, message_id, { :claim_id => '10' }) + end + + tests("#delete_message(#{queue_name}, #{message_id})").succeeds do + service.delete_message(queue_name, message_id) + end + end + + tests('failure') do + tests("#create_message('') => Invalid Create Critera").raises(Fog::Rackspace::Queues::BadRequest) do + service.create_message(client_id, queue_name, '', 0) + end + + #TODO - Report bad error code to queueing team + tests("#get_message('queue_name', 'nonexistentmessage') => Does not exist").raises(Fog::Rackspace::Queues::ServiceError) do + service.get_message(client_id, queue_name, 'nonexistentmessage') + end + + end + ensure + service.delete_queue(queue_name) + end + +end diff --git a/tests/rackspace/requests/queues/queues_tests.rb b/tests/rackspace/requests/queues/queues_tests.rb new file mode 100644 index 000000000..688016002 --- /dev/null +++ b/tests/rackspace/requests/queues/queues_tests.rb @@ -0,0 +1,42 @@ +Shindo.tests('Fog::Rackspace::Queues | queue_tests', ['rackspace']) do + + pending if Fog.mocking? + + service = Fog::Rackspace::Queues.new + + tests('success') do + + queue_name = 'fog' + Time.now.to_i.to_s + + tests("#list_queues").formats(LIST_QUEUES_FORMAT) do + service.list_queues.body + end + + tests("#create_queue(#{queue_name})").succeeds do + service.create_queue(queue_name) + end + + tests("#get_queue(#{queue_name})").formats(QUEUE_FORMAT) do + service.get_queue(queue_name).body + end + + tests("#get_queue_stats(#{queue_name})").formats(QUEUE_STATS_FORMAT) do + service.get_queue_stats(queue_name).body + end + + tests("#delete_queue(#{queue_name})").succeeds do + service.delete_queue(queue_name) + end + end + + tests('failure') do + tests("#create_queue('') => Invalid Create Critera").raises(Fog::Rackspace::Queues::MethodNotAllowed) do + service.create_queue('') + end + + tests("#get_queue('nonexistentqueue') => Does not exist").raises(Fog::Rackspace::Queues::NotFound) do + service.get_queue('nonexistentqueue') + end + + end +end