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