diff --git a/.autotest b/.autotest index d23e2e4..fad759b 100644 --- a/.autotest +++ b/.autotest @@ -1,6 +1,6 @@ Autotest.add_hook :initialize do |at| at.clear_mappings - + at.add_mapping(%r{^test/.*_test\.rb$}) {|f, _| [f] } at.add_mapping(%r{^lib/amazon/(.*)\.rb$}) {|_, m| ["test/#{m[1]}_test.rb"] } at.add_mapping(%r{^test/(test_helper)\.rb$}) { at.files_matching %r{^test/.*_test\.rb$} } diff --git a/README.rdoc b/README.rdoc index 7b47798..0df22f1 100644 --- a/README.rdoc +++ b/README.rdoc @@ -1,25 +1,25 @@ == amazon-associate -Generic Amazon E-commerce REST API using Hpricot with configurable -default options and method call options. Uses Response and +Generic Amazon E-commerce REST API using Hpricot with configurable +default options and method call options. Uses Response and Element wrapper classes for easy access to REST XML output. It supports ECS 4.0. -It is generic, so you can easily extend AmazonAssociate::Request to support +It is generic, so you can easily extend AmazonAssociate::Request to support other not implemented REST operations; and it is also generic because it just wraps around Hpricot element object, instead of providing one-to-one object/attributes to XML elements map. -If in the future, there is a change in REST XML output structure, -no changes will be required on amazon-ecs library, +If in the future, there is a change in REST XML output structure, +no changes will be required on amazon-ecs library, instead you just need to change the element path. -NOTE: You must now specify a secret key to support request signing as +NOTE: You must now specify a secret key to support request signing as required by Amazon. Version: 0.6.1 == WANTS * instance based refactoring (singletons are not ideal here) - + == INSTALLATION $ gem install dpickett-amazon_associate @@ -27,7 +27,7 @@ Version: 0.6.1 == EXAMPLE require 'amazon_associate' - + # set the default options; options will be camelized and converted to REST request parameters. AmazonAssociate::Request.configure do |options| options[:aWS_access_key_id] = [your developer token] @@ -54,32 +54,32 @@ Version: 0.6.1 # or return AmazonAssociate::Element instance atts = item.search_and_convert('itemattributes') atts.get('title') - + # return first author or a string array of authors atts.get('author') # 'Author 1' atts.get_array('author') # ['Author 1', 'Author 2', ...] - + # return an hash of children text values with the element names as the keys item.get_hash('smallimage') # {:url => ..., :width => ..., :height => ...} - + # note that '/' returns Hpricot::Elements array object, nil if not found reviews = item/'editorialreview' - + # traverse through Hpricot elements reviews.each do |review| # Getting hash value out of Hpricot element AmazonAssociate::Element.get_hash(review) # [:source => ..., :content ==> ...] - + # Or to get unescaped HTML values AmazonAssociate::Element.get_unescaped(review, 'source') AmazonAssociate::Element.get_unescaped(review, 'content') - + # Or this way el = AmazonAssociate::Element.new(review) el.get_unescaped('source') el.get_unescaped('content') end - + # returns AmazonAssociate::Element instead of string item.search_and_convert('itemattributes'). end @@ -93,20 +93,20 @@ http://www.awszone.com/scratchpads/aws/ecs.us/index.aws == CACHING Filesystem caching is now available. - - AmazonAssociate::Request.configure do |options| + + AmazonAssociate::Request.configure do |options| options[:aWS_access_key_id] = [your developer token] options[:scret_key] = [your secret key] options[:caching_strategy] = :filesystem options[:caching_options] = { - :disk_quota => 200, - :cache_path => , + :disk_quota => 200, + :cache_path => , :sweep_frequency => 4 } end - + The above command will cache up to 200MB of requests. It will purge the cache every 4 hours or when the disk quota has been exceeded. - + Every request will be stored in the cache path. On every request, AmazonAssociate::Request will check for the presence of the cached file before querying Amazon directly. == LINKS diff --git a/VERSION.yml b/VERSION.yml index 0018d80..be1caa9 100644 --- a/VERSION.yml +++ b/VERSION.yml @@ -1,4 +1,4 @@ ---- +--- :patch: 0 :major: 0 :minor: 7 diff --git a/lib/amazon_associate/cache_factory.rb b/lib/amazon_associate/cache_factory.rb index 39dfc4a..7a091c6 100644 --- a/lib/amazon_associate/cache_factory.rb +++ b/lib/amazon_associate/cache_factory.rb @@ -3,24 +3,24 @@ class CacheFactory def self.cache(request, response, strategy) strategy_class_hash[strategy].cache(request, response) end - + def self.initialize_options(options) #check for a valid caching strategy unless self.strategy_class_hash.keys.include?(options[:caching_strategy]) - raise AmazonAssociate::ConfigurationError, "Invalid caching strategy" + raise AmazonAssociate::ConfigurationError, "Invalid caching strategy" end strategy_class_hash[options[:caching_strategy]].initialize_options(options) end - + def self.get(request, strategy) strategy_class_hash[strategy].get(request) end - + def self.sweep(strategy) strategy_class_hash[strategy].sweep end - + private def self.strategy_class_hash { diff --git a/lib/amazon_associate/caching_strategy/base.rb b/lib/amazon_associate/caching_strategy/base.rb index e243271..5b2c9a1 100644 --- a/lib/amazon_associate/caching_strategy/base.rb +++ b/lib/amazon_associate/caching_strategy/base.rb @@ -5,15 +5,15 @@ class Base def self.cache(request, response) raise "This method must be overwritten by a caching strategy" end - + def self.initialize_options(options) raise "This method must be overwritten by a caching strategy" end - + def self.get(request) raise "This method must be overwritten by a caching strategy" end - + def self.sweep raise "This method must be overwritten by a caching strategy" end diff --git a/lib/amazon_associate/caching_strategy/filesystem.rb b/lib/amazon_associate/caching_strategy/filesystem.rb index 051d07b..aa8ff30 100644 --- a/lib/amazon_associate/caching_strategy/filesystem.rb +++ b/lib/amazon_associate/caching_strategy/filesystem.rb @@ -6,10 +6,10 @@ module CachingStrategy class Filesystem < AmazonAssociate::CachingStrategy::Base #disk quota in megabytes DEFAULT_DISK_QUOTA = 200 - + #frequency of sweeping in hours DEFAULT_SWEEP_FREQUENCY = 2 - + class << self attr_accessor :cache_path attr_accessor :disk_quota @@ -19,14 +19,14 @@ def cache(request, response) path = self.cache_path cached_filename = Digest::SHA1.hexdigest(request) cached_folder = cached_filename[0..2] - + FileUtils.mkdir_p(File.join(path, cached_folder, cached_folder)) - + cached_file = File.open(File.join(path, cached_folder, cached_filename), "w") cached_file.puts response.doc.to_s cached_file.close end - + def get(request) path = self.cache_path cached_filename = Digest::SHA1.hexdigest(request) @@ -37,8 +37,8 @@ def get(request) nil end end - - def initialize_options(options) + + def initialize_options(options) #check for required options if options[:caching_options].nil? || options[:caching_options][:cache_path].nil? raise AmazonAssociate::ConfigurationError, "You must specify caching options for filesystem caching: :cache_path is required" @@ -46,54 +46,54 @@ def initialize_options(options) #default disk quota to 200MB Filesystem.disk_quota = options[:caching_options][:disk_quota] || DEFAULT_DISK_QUOTA - + Filesystem.sweep_frequency = options[:caching_options][:sweep_frequency] || DEFAULT_SWEEP_FREQUENCY - + Filesystem.cache_path = options[:caching_options][:cache_path] - + if Filesystem.cache_path.nil? || !File.directory?(Filesystem.cache_path) raise AmazonAssociate::ConfigurationError, "You must specify a cache path for filesystem caching" end return options end - + def sweep perform_sweep if must_sweep? end - + private def perform_sweep FileUtils.rm_rf(Dir.glob("#{Filesystem.cache_path}/*")) - + timestamp_sweep_performance end - + def timestamp_sweep_performance #remove the timestamp FileUtils.rm_rf(timestamp_filename) - + #create a new one its place timestamp = File.open(timestamp_filename, "w") timestamp.puts(Time.now) timestamp.close end - + def must_sweep? sweep_time_expired? || disk_quota_exceeded? end - + def sweep_time_expired? FileTest.exists?(timestamp_filename) && Time.parse(File.read(timestamp_filename).chomp) < Time.now - (sweep_frequency * 3600) end - + def disk_quota_exceeded? cache_size > Filesystem.disk_quota end - + def timestamp_filename File.join(Filesystem.cache_path, ".amz_timestamp") end - + def cache_size size = 0 Find.find(Filesystem.cache_path) do|f| diff --git a/lib/amazon_associate/element.rb b/lib/amazon_associate/element.rb index 0d3b854..36a4d4f 100644 --- a/lib/amazon_associate/element.rb +++ b/lib/amazon_associate/element.rb @@ -6,7 +6,7 @@ def initialize(element) @element = element end - # Returns Hpricot::Elments object + # Returns Hpricot::Elments object def elem @element end @@ -56,7 +56,7 @@ def self.get(element, path="") result end - # Similar to #get_unescaped, except an element object must be passed-in. + # Similar to #get_unescaped, except an element object must be passed-in. def self.get_unescaped(element, path="") result = get(element, path) CGI::unescapeHTML(result) if result @@ -65,7 +65,7 @@ def self.get_unescaped(element, path="") # Similar to #get_array, except an element object must be passed-in. def self.get_array(element, path="") return unless element - + result = element/path if (result.is_a? Hpricot::Elements) || (result.is_a? Array) parsed_result = [] @@ -88,7 +88,7 @@ def self.get_hash(element, path="") result = result.children result.each do |item| hash[item.name.to_sym] = item.inner_html - end + end hash end end diff --git a/lib/amazon_associate/request.rb b/lib/amazon_associate/request.rb index 2efb3c2..62b2533 100644 --- a/lib/amazon_associate/request.rb +++ b/lib/amazon_associate/request.rb @@ -32,7 +32,7 @@ #++ module AmazonAssociate class Request - + SERVICE_URLS = {:us => "http://webservices.amazon.com", :uk => "http://webservices.amazon.co.uk", :ca => "http://webservices.amazon.ca", @@ -40,7 +40,7 @@ class Request :jp => "http://webservices.amazon.co.jp", :fr => "http://webservices.amazon.fr" } - + # The sort types available to each product search index. SORT_TYPES = { "Apparel" => %w[relevancerank salesrank pricerank inverseprice -launch-date sale-flag], @@ -75,32 +75,32 @@ class Request "VHS" => %w[relevancerank salesrank price -price titlerank -video-release-date], "Video" => %w[relevancerank salesrank price -price titlerank -video-release-date], "VideoGames" => %w[pmrank salesrank price -price titlerank], - "Wireless" => %w[daterank pricerank invers-pricerank reviewrank salesrank titlerank -titlerank], + "Wireless" => %w[daterank pricerank invers-pricerank reviewrank salesrank titlerank -titlerank], "WirelessAccessories" => %w[psrank salesrank titlerank -titlerank] } - + # Returns an Array of valid sort types for _search_index_, or +nil+ if _search_index_ is invalid. def self.sort_types(search_index) SORT_TYPES.has_key?(search_index) ? SORT_TYPES[search_index] : nil end - + # Performs BrowseNodeLookup request, defaults to TopSellers ResponseGroup def self.browse_node_lookup(browse_node_id, opts = {}) opts = self.options.merge(opts) if self.options opts[:operation] = "BrowseNodeLookup" opts[:browse_node_id] = browse_node_id - + self.send_request(opts) end - + # Cart operations build the Item tags from the ASIN # Item.ASIN.Quantity defaults to 1, unless otherwise specified in _opts_ - + # Creates remote shopping cart containing _asin_ def self.cart_create(items, opts = {}) opts = self.options.merge(opts) if self.options opts[:operation] = "CartCreate" - + if items.is_a?(String) asin = items opts["Item.#{asin}.Quantity"] = opts[:quantity] || 1 @@ -111,15 +111,15 @@ def self.cart_create(items, opts = {}) opts["Item.#{item[:asin]}.Quantity"] = item[:quantity] || 1 end end - + self.send_request(opts) end - + # Adds items to remote shopping cart def self.cart_add(items, cart_id, hmac, opts = {}) opts = self.options.merge(opts) if self.options opts[:operation] = "CartAdd" - + if items.is_a?(String) asin = items opts["Item.#{asin}.Quantity"] = opts[:quantity] || 1 @@ -130,23 +130,23 @@ def self.cart_add(items, cart_id, hmac, opts = {}) opts["Item.#{item[:asin]}.Quantity"] = item[:quantity] || 1 end end - + opts[:cart_id] = cart_id opts[:hMAC] = hmac - + self.send_request(opts) end - + # Retrieve a remote shopping cart def self.cart_get(cart_id, hmac, opts = {}) opts = self.options.merge(opts) if self.options opts[:operation] = "CartGet" opts[:cart_id] = cart_id opts[:hMAC] = hmac - + self.send_request(opts) end - + # modifies _cart_item_id_ in remote shopping cart # _quantity_ defaults to 0 to remove the given _cart_item_id_ # specify _quantity_ to update cart contents @@ -157,17 +157,17 @@ def self.cart_modify(cart_item_id, cart_id, hmac, quantity=0, opts = {}) opts["Item.1.Quantity"] = quantity opts[:cart_id] = cart_id opts[:hMAC] = hmac - + self.send_request(opts) end - + # clears contents of remote shopping cart def self.cart_clear(cart_id, hmac, opts = {}) opts = self.options.merge(opts) if self.options opts[:operation] = "CartClear" opts[:cart_id] = cart_id opts[:hMAC] = hmac - + self.send_request(opts) end @@options = {} @@ -177,44 +177,44 @@ def self.cart_clear(cart_id, hmac, opts = {}) def self.options @@options end - + # Set default search options def self.options=(opts) @@options = opts end - + # Get debug flag. def self.debug @@debug end - + # Set debug flag to true or false. def self.debug=(dbg) @@debug = dbg end - + def self.configure(&proc) raise ArgumentError, "Block is required." unless block_given? - + yield @@options if !@@options[:caching_strategy].nil? @@options.merge!(CacheFactory.initialize_options(@@options)) end end - + # Search amazon items with search terms. Default search index option is "Books". # For other search type other than keywords, please specify :type => [search type param name]. def self.item_search(terms, opts = {}) opts[:operation] = "ItemSearch" opts[:search_index] = opts[:search_index] || "Books" - + type = opts.delete(:type) - if type + if type opts[type.to_sym] = terms - else + else opts[:keywords] = terms end - + self.send_request(opts) end @@ -222,10 +222,10 @@ def self.item_search(terms, opts = {}) def self.item_lookup(item_id, opts = {}) opts[:operation] = "ItemLookup" opts[:item_id] = item_id - + self.send_request(opts) - end - + end + # Generic send request to ECS REST service. You have to specify the :operation parameter. def self.send_request(opts) opts = self.options.merge(opts) if self.options @@ -234,11 +234,11 @@ def self.send_request(opts) if caching_enabled? AmazonAssociate::CacheFactory.sweep(self.options[:caching_strategy]) - - res = AmazonAssociate::CacheFactory.get(unsigned_url, self.options[:caching_strategy]) + + res = AmazonAssociate::CacheFactory.get(unsigned_url, self.options[:caching_strategy]) response = Response.new(res, unsigned_url) unless res.nil? end - + if !caching_enabled? || response.nil? request_url = prepare_signed_url(opts) log "Request URL: #{request_url}" @@ -252,13 +252,13 @@ def self.send_request(opts) response.unsigned_url = unsigned_url if caching_enabled? - cache_response(unsigned_url, response, self.options[:caching_strategy]) + cache_response(unsigned_url, response, self.options[:caching_strategy]) end end - + response end - + attr_accessor :request_url, :unsigned_url protected @@ -272,7 +272,7 @@ def self.log(s) puts s end end - + private def self.get_service_url(opts) country = opts.delete(:country) @@ -281,11 +281,11 @@ def self.get_service_url(opts) raise AmazonAssociate::RequestError, "Invalid country \"#{country}\"" unless url url - end + end def self.prepare_unsigned_url(opts) url = get_service_url(opts) + "/onca/xml" - + qs = "" opts.each {|k,v| next unless v @@ -299,7 +299,7 @@ def self.prepare_unsigned_url(opts) def self.prepare_signed_url(opts) url = get_service_url(opts) + "/onca/xml" - + unencoded_key_value_strings = [] encoded_key_value_strings = [] opts[:timestamp] = Time.now.utc.strftime("%Y-%m-%dT%H:%M:%S") + ".000Z" @@ -311,11 +311,11 @@ def self.prepare_signed_url(opts) encoded_value = CGI.escape(p[1].to_s) - + encoded_key_value_strings << camelize(p[0].to_s ) + "=" + encoded_value end - string_to_sign = + string_to_sign = "GET #{get_service_url(opts).gsub("http://", "")} /onca/xml @@ -338,15 +338,15 @@ def self.sign_string(string_to_sign) #Base64 encoding adds a linefeed to the end of the string so chop the last character! CGI.escape(Base64.encode64(sha1).chomp) end - + def self.camelize(s) s.to_s.gsub(/\/(.?)/) { "::" + $1.upcase }.gsub(/(^|_)(.)/) { $2.upcase } end - + def self.caching_enabled? !self.options[:caching_strategy].nil? end - + def self.cache_response(request, response, options) AmazonAssociate::CacheFactory.cache(request, response, options) end diff --git a/lib/amazon_associate/response.rb b/lib/amazon_associate/response.rb index 67de565..5fd4b29 100644 --- a/lib/amazon_associate/response.rb +++ b/lib/amazon_associate/response.rb @@ -1,7 +1,7 @@ module AmazonAssociate # Response object returned after a REST call to Amazon service. class Response - + attr_accessor :request_url, :unsigned_url # XML input is in string format def initialize(xml, request_url) @@ -10,7 +10,7 @@ def initialize(xml, request_url) @item_page = nil @total_results = nil @total_pages = nil - + self.request_url = request_url end diff --git a/test/amazon_associate/browse_node_lookup_test.rb b/test/amazon_associate/browse_node_lookup_test.rb index ab16722..c689d60 100644 --- a/test/amazon_associate/browse_node_lookup_test.rb +++ b/test/amazon_associate/browse_node_lookup_test.rb @@ -1,7 +1,7 @@ require File.dirname(__FILE__) + "/../test_helper" class AmazonAssociate::BrowseNodeLookupTest < Test::Unit::TestCase - + ## Test browse_node_lookup def test_browse_node_lookup resp = AmazonAssociate::Request.browse_node_lookup("5", :response_group => "TopSellers") @@ -10,19 +10,19 @@ def test_browse_node_lookup browse_node_tags.each { |node| assert_equal("5", node.inner_text) } assert_equal "TopSellers", resp.doc.get_elements_by_tag_name("responsegroup").inner_text end - + def test_browse_node_lookup_with_browse_node_info_response resp = AmazonAssociate::Request.browse_node_lookup("5", :response_group => "BrowseNodeInfo") assert resp.is_valid_request? assert_equal "BrowseNodeInfo", resp.doc.get_elements_by_tag_name("responsegroup").inner_text end - + def test_browse_node_lookup_with_new_releases_response resp = AmazonAssociate::Request.browse_node_lookup("5", :response_group => "NewReleases") assert resp.is_valid_request? assert_equal "NewReleases", resp.doc.get_elements_by_tag_name("responsegroup").inner_text end - + def test_browse_node_lookup_with_invalid_request resp = AmazonAssociate::Request.browse_node_lookup(nil) assert resp.has_error? @@ -31,7 +31,7 @@ def test_browse_node_lookup_with_invalid_request def test_browse_node_lookup_with_no_result resp = AmazonAssociate::Request.browse_node_lookup("abc") - + assert resp.is_valid_request? assert_match(/abc is not a valid value for BrowseNodeId/, resp.error) end diff --git a/test/amazon_associate/cache_test.rb b/test/amazon_associate/cache_test.rb index 4c7c10b..11a0ee5 100644 --- a/test/amazon_associate/cache_test.rb +++ b/test/amazon_associate/cache_test.rb @@ -7,12 +7,12 @@ class AmazonAssociate::CacheTest < Test::Unit::TestCase get_cache_directory get_valid_caching_options end - + teardown do destroy_cache_directory destroy_caching_options end - + should "optionally allow for a caching strategy in configuration" do assert_nothing_raised do AmazonAssociate::Request.configure do |options| @@ -20,7 +20,7 @@ class AmazonAssociate::CacheTest < Test::Unit::TestCase end end end - + should "raise an exception if a caching strategy is specified that is not found" do assert_raises(AmazonAssociate::ConfigurationError) do AmazonAssociate::Request.configure do |options| @@ -28,6 +28,6 @@ class AmazonAssociate::CacheTest < Test::Unit::TestCase end end end - + end end diff --git a/test/amazon_associate/caching_strategy/filesystem_test.rb b/test/amazon_associate/caching_strategy/filesystem_test.rb index 9f9d01d..a2e44d2 100644 --- a/test/amazon_associate/caching_strategy/filesystem_test.rb +++ b/test/amazon_associate/caching_strategy/filesystem_test.rb @@ -9,7 +9,7 @@ class AmazonAssociate::CachingStrategy::FilesystemTest < Test::Unit::TestCase options[:caching_options] = nil end end - + should "require a caching options hash with a cache_path key" do assert_raises(AmazonAssociate::ConfigurationError) do AmazonAssociate::Request.configure do |options| @@ -18,7 +18,7 @@ class AmazonAssociate::CachingStrategy::FilesystemTest < Test::Unit::TestCase end end end - + should "raise an exception when a cache_path is specified that doesn't exist" do assert_raises(AmazonAssociate::ConfigurationError) do AmazonAssociate::Request.configure do |options| @@ -36,63 +36,63 @@ class AmazonAssociate::CachingStrategy::FilesystemTest < Test::Unit::TestCase end end end - + should "set default values for disk_quota and sweep_frequency" do AmazonAssociate::Request.configure do |options| options[:caching_strategy] = :filesystem options[:caching_options] = {:cache_path => "."} end - + assert_equal AmazonAssociate::CachingStrategy::Filesystem.disk_quota, AmazonAssociate::CachingStrategy::Filesystem.disk_quota assert_equal AmazonAssociate::CachingStrategy::Filesystem.sweep_frequency, AmazonAssociate::CachingStrategy::Filesystem.sweep_frequency end - + should "override the default value for disk quota if I specify one" do quota = 400 AmazonAssociate::Request.configure do |options| options[:caching_strategy] = :filesystem options[:caching_options] = {:cache_path => ".", :disk_quota => quota} end - + assert_equal quota, AmazonAssociate::CachingStrategy::Filesystem.disk_quota end - + should "override the default value for cache_frequency if I specify one" do frequency = 4 AmazonAssociate::Request.configure do |options| options[:caching_strategy] = :filesystem options[:caching_options] = {:cache_path => ".", :sweep_frequency => frequency} end - + assert_equal frequency, AmazonAssociate::CachingStrategy::Filesystem.sweep_frequency end end - + context "caching a request" do - + setup do get_cache_directory get_valid_caching_options @resp = AmazonAssociate::Request.item_lookup("0974514055") @filename = Digest::SHA1.hexdigest(@resp.unsigned_url) end - + teardown do destroy_cache_directory destroy_caching_options end - + should "create a folder in the cache path with the first three letters of the digested filename" do filename = Digest::SHA1.hexdigest(@resp.request_url) - FileTest.exists?(File.join(@@cache_path, @filename[0..2])) + FileTest.exists?(File.join(@@cache_path, @filename[0..2])) end - + should "create a file in the cache path with a digested version of the url " do - + filename = Digest::SHA1.hexdigest(@resp.request_url) assert FileTest.exists?(File.join(@@cache_path, @filename[0..2], @filename)) end - + should "create a file in the cache path with the response inside it" do assert FileTest.exists?(File.join(@@cache_path + @filename[0..2], @filename)) assert_equal @resp.doc.to_s, File.read(File.join(@@cache_path + @filename[0..2], @filename)).chomp @@ -104,86 +104,86 @@ class AmazonAssociate::CachingStrategy::FilesystemTest < Test::Unit::TestCase end end end - + context "getting a cached request" do setup do get_cache_directory get_valid_caching_options do_request end - + teardown do destroy_cache_directory destroy_caching_options end - + should "not do an http request the second time the lookup is performed due a cached copy" do Net::HTTP.expects(:get_response).never do_request end - + end - + context "sweeping cached requests" do setup do get_cache_directory get_valid_caching_options do_request end - + teardown do destroy_cache_directory destroy_caching_options end - + should "not perform the sweep if the timestamp is within the range of the sweep frequency and quota is not exceeded" do AmazonAssociate::CachingStrategy::Filesystem.expects(:sweep_time_expired?).returns(false) AmazonAssociate::CachingStrategy::Filesystem.expects(:disk_quota_exceeded?).returns(false) - + AmazonAssociate::CachingStrategy::Filesystem.expects(:perform_sweep).never - + do_request end - + should "perform a sweep if the quota is exceeded" do AmazonAssociate::CachingStrategy::Filesystem.stubs(:sweep_time_expired?).returns(false) AmazonAssociate::CachingStrategy::Filesystem.expects(:disk_quota_exceeded?).once.returns(true) - + AmazonAssociate::CachingStrategy::Filesystem.expects(:perform_sweep).once - + do_request end - + should "perform a sweep if the sweep time is expired" do AmazonAssociate::CachingStrategy::Filesystem.expects(:sweep_time_expired?).once.returns(true) AmazonAssociate::CachingStrategy::Filesystem.stubs(:disk_quota_exceeded?).returns(false) AmazonAssociate::CachingStrategy::Filesystem.expects(:perform_sweep).once - + do_request end - + should "create a timestamp file after performing a sweep" do AmazonAssociate::CachingStrategy::Filesystem.expects(:sweep_time_expired?).once.returns(true) - + do_request assert FileTest.exists?(File.join(@@cache_path, ".amz_timestamp")) end - + should "purge the cache when performing a sweep" do - (0..9).each do |n| + (0..9).each do |n| test = File.open(File.join(@@cache_path, "test_file_#{n}"), "w") test.puts Time.now test.close end - + AmazonAssociate::CachingStrategy::Filesystem.expects(:sweep_time_expired?).once.returns(true) do_request - + (0..9).each do |n| assert !FileTest.exists?(File.join(@@cache_path, "test_file_#{n}")) end end - + end protected diff --git a/test/amazon_associate/cart_test.rb b/test/amazon_associate/cart_test.rb index 35a7c63..aa72536 100644 --- a/test/amazon_associate/cart_test.rb +++ b/test/amazon_associate/cart_test.rb @@ -1,7 +1,7 @@ require File.dirname(__FILE__) + "/../test_helper" class AmazonAssociate::CartTest < Test::Unit::TestCase - + # create a cart to store cart_id and hmac for add, get, modify, and clear tests def setup sleep(2) @@ -17,14 +17,14 @@ def setup assert_not_nil @cart_id assert_not_nil @hmac end - + # Test cart_get def test_cart_get resp = AmazonAssociate::Request.cart_get(@cart_id, @hmac) assert resp.is_valid_request? assert_not_nil resp.doc.get_elements_by_tag_name("purchaseurl").inner_text end - + # Test cart_modify def test_cart_modify resp = AmazonAssociate::Request.cart_get(@cart_id, @hmac) @@ -36,13 +36,13 @@ def test_cart_modify assert_equal "2", item.get("quantity") assert_not_nil resp.doc.get_elements_by_tag_name("purchaseurl").inner_text end - + # Test cart_clear def test_cart_clear resp = AmazonAssociate::Request.cart_clear(@cart_id, @hmac) assert resp.is_valid_request? end - + ## Test cart_create with a specified quantity ## note this will create a separate cart def test_cart_create_with_quantity @@ -55,36 +55,36 @@ def test_cart_create_with_quantity assert_not_nil resp.doc.get_elements_by_tag_name("cartid").inner_text assert_not_nil resp.doc.get_elements_by_tag_name("hmac").inner_text end - + # Test cart_create with an array of hashes representing multiple items def test_cart_create_with_multiple_items items = [ { :asin => "0974514055", :quantity => 2 }, { :asin => "0672328844", :quantity => 3 } ] resp = AmazonAssociate::Request.cart_create(items) assert resp.is_valid_request? first_item, second_item = resp.items.reverse[0], resp.items.reverse[1] - + assert_equal items[0][:asin], first_item.get("asin") assert_equal items[0][:quantity].to_s, first_item.get("quantity") - + assert_equal items[1][:asin], second_item.get("asin") assert_equal items[1][:quantity].to_s, second_item.get("quantity") - + assert_not_nil resp.doc.get_elements_by_tag_name("cartid").inner_text assert_not_nil resp.doc.get_elements_by_tag_name("hmac").inner_text end - + # Test cart_create with offer_listing_id instead of asin def test_cart_create_with_offer_listing_id items = [ { :offer_listing_id => "MCK%2FnCXIges8tpX%2B222nOYEqeZ4AzbrFyiHuP6pFf45N3vZHTm8hFTytRF%2FLRONNkVmt182%2BmeX72n%2BbtUcGEtpLN92Oy9Y7", :quantity => 2 } ] resp = AmazonAssociate::Request.cart_create(items) assert resp.is_valid_request? first_item = resp.items.first - + assert_equal items[0][:offer_listing_id], first_item.get("offerlistingid") assert_equal items[0][:quantity].to_s, first_item.get("quantity") - + assert_not_nil resp.doc.get_elements_by_tag_name("cartid").inner_text assert_not_nil resp.doc.get_elements_by_tag_name("hmac").inner_text end - + end diff --git a/test/amazon_associate/request_test.rb b/test/amazon_associate/request_test.rb index 095874f..fab9e6b 100644 --- a/test/amazon_associate/request_test.rb +++ b/test/amazon_associate/request_test.rb @@ -7,7 +7,7 @@ def setup options[:response_group] = "Large" end end - + ## Test item_search def test_item_search resp = AmazonAssociate::Request.item_search("ruby") @@ -29,42 +29,42 @@ def test_item_search_with_invalid_request def test_item_search_with_no_result resp = AmazonAssociate::Request.item_search("afdsafds") - + assert resp.is_valid_request? - assert_equal "We did not find any matches for your request.", + assert_equal "We did not find any matches for your request.", resp.error end - + def test_item_search_uk resp = AmazonAssociate::Request.item_search("ruby", :country => :uk) assert resp.is_valid_request? end - + def test_item_search_by_author resp = AmazonAssociate::Request.item_search("dave", :type => :author) assert resp.is_valid_request? end - + def test_item_get resp = AmazonAssociate::Request.item_search("0974514055") item = resp.first_item - + # test get - assert_equal "Programming Ruby: The Pragmatic Programmers' Guide, Second Edition", + assert_equal "Programming Ruby: The Pragmatic Programmers' Guide, Second Edition", item.get("itemattributes/title") - + # test get_array - assert_equal ["Dave Thomas", "Chad Fowler", "Andy Hunt"], + assert_equal ["Dave Thomas", "Chad Fowler", "Andy Hunt"], item.get_array("author") # test get_hash small_image = item.get_hash("smallimage") - + assert_equal 3, small_image.keys.size assert small_image[:url] != nil assert_equal "75", small_image[:height] assert_equal "59", small_image[:width] - + # test / reviews = item/"editorialreview" reviews.each do |review| @@ -73,14 +73,14 @@ def test_item_get assert AmazonAssociate::Element.get_unescaped(review, "content") end end - + ## Test item_lookup def test_item_lookup resp = AmazonAssociate::Request.item_lookup("0974514055") - assert_equal "Programming Ruby: The Pragmatic Programmers' Guide, Second Edition", + assert_equal "Programming Ruby: The Pragmatic Programmers' Guide, Second Edition", resp.first_item.get("itemattributes/title") end - + def test_item_lookup_with_invalid_request resp = AmazonAssociate::Request.item_lookup(nil) assert resp.has_error? @@ -89,20 +89,20 @@ def test_item_lookup_with_invalid_request def test_item_lookup_with_no_result resp = AmazonAssociate::Request.item_lookup("abc") - + assert resp.is_valid_request? assert_match(/ABC is not a valid value for ItemId/, resp.error) - end - + end + def test_search_and_convert resp = AmazonAssociate::Request.item_lookup("0974514055") title = resp.first_item.get("itemattributes/title") authors = resp.first_item.search_and_convert("author") - + assert_equal "Programming Ruby: The Pragmatic Programmers' Guide, Second Edition", title assert authors.is_a?(Array) assert 3, authors.size assert_equal "Dave Thomas", authors.first.get end - + end diff --git a/test/test_helper.rb b/test/test_helper.rb index 4b00d0b..763bc6e 100644 --- a/test/test_helper.rb +++ b/test/test_helper.rb @@ -12,9 +12,9 @@ AmazonAssociate::Request.configure do |options| options[:aWS_access_key_id] = ENV["AWS_ACCESS_KEY"] || "" options[:secret_key] = ENV["AWS_SECRET_KEY"] || "" - + #raise exception if user has not entered their access key if options[:aWS_access_key_id] == "" - raise "Access key is not entered - enter an access key in test_helper.rb if you'd like to run tests" + raise "Access key is not entered - enter an access key in test_helper.rb if you'd like to run tests" end end