sucker 1.1.4 → 1.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (47) hide show
  1. data/README.md +13 -19
  2. data/lib/sucker.rb +4 -4
  3. data/lib/sucker/parameters.rb +28 -0
  4. data/lib/sucker/request.rb +100 -88
  5. data/lib/sucker/response.rb +10 -0
  6. data/lib/sucker/version.rb +1 -1
  7. data/spec/fixtures/cassette_library/{unit → spec}/sucker/request.yml +4 -4
  8. data/spec/fixtures/cassette_library/spec/sucker/response.yml +26 -0
  9. data/spec/sucker/parameters_spec.rb +61 -0
  10. data/spec/sucker/request_spec.rb +276 -0
  11. data/spec/{unit/sucker → sucker}/response_spec.rb +39 -60
  12. data/spec/{unit/sucker_spec.rb → sucker_spec.rb} +0 -4
  13. data/spec/support/vcr.rb +0 -1
  14. metadata +69 -114
  15. data/spec/fixtures/cassette_library/integration/alternate_versions.yml +0 -26
  16. data/spec/fixtures/cassette_library/integration/errors.yml +0 -26
  17. data/spec/fixtures/cassette_library/integration/france.yml +0 -26
  18. data/spec/fixtures/cassette_library/integration/images.yml +0 -26
  19. data/spec/fixtures/cassette_library/integration/item_lookup/multiple.yml +0 -26
  20. data/spec/fixtures/cassette_library/integration/item_lookup/single.yml +0 -26
  21. data/spec/fixtures/cassette_library/integration/item_search.yml +0 -26
  22. data/spec/fixtures/cassette_library/integration/japan.yml +0 -26
  23. data/spec/fixtures/cassette_library/integration/keyword_search.yml +0 -26
  24. data/spec/fixtures/cassette_library/integration/kindle.yml +0 -26
  25. data/spec/fixtures/cassette_library/integration/kindle_2.yml +0 -26
  26. data/spec/fixtures/cassette_library/integration/multiple_locales.yml +0 -151
  27. data/spec/fixtures/cassette_library/integration/power_search.yml +0 -26
  28. data/spec/fixtures/cassette_library/integration/related_items/child.yml +0 -26
  29. data/spec/fixtures/cassette_library/integration/related_items/parent.yml +0 -26
  30. data/spec/fixtures/cassette_library/integration/seller_listings_search.yml +0 -26
  31. data/spec/fixtures/cassette_library/integration/twenty_items.yml +0 -26
  32. data/spec/fixtures/cassette_library/unit/sucker/response.yml +0 -26
  33. data/spec/integration/alternate_versions_spec.rb +0 -35
  34. data/spec/integration/errors_spec.rb +0 -40
  35. data/spec/integration/france_spec.rb +0 -42
  36. data/spec/integration/images_spec.rb +0 -41
  37. data/spec/integration/item_lookup_spec.rb +0 -71
  38. data/spec/integration/item_search_spec.rb +0 -41
  39. data/spec/integration/japan_spec.rb +0 -35
  40. data/spec/integration/keyword_search_spec.rb +0 -33
  41. data/spec/integration/kindle_spec.rb +0 -55
  42. data/spec/integration/multiple_locales_spec.rb +0 -70
  43. data/spec/integration/power_search_spec.rb +0 -41
  44. data/spec/integration/related_items_spec.rb +0 -53
  45. data/spec/integration/seller_listing_search_spec.rb +0 -32
  46. data/spec/integration/twenty_items_spec.rb +0 -49
  47. data/spec/unit/sucker/request_spec.rb +0 -282
@@ -1,3 +1,3 @@
1
1
  module Sucker #:nodoc:
2
- VERSION = "1.1.4"
2
+ VERSION = '1.2.0'
3
3
  end
@@ -2,7 +2,7 @@
2
2
  - !ruby/struct:VCR::HTTPInteraction
3
3
  request: !ruby/struct:VCR::Request
4
4
  method: :get
5
- uri: http://ecs.amazonaws.com:80/onca/xml?AWSAccessKeyId=key&AssociateTag=&Service=AWSECommerceService&Signature=KhbhltMa2lob8mGADxdK7GjHHWHAe4sLkbs7h7Xto3M=&Timestamp=2010-12-15T07:14:37Z&Version=2010-09-01
5
+ uri: http://ecs.amazonaws.com:80/onca/xml?AWSAccessKeyId=key&AssociateTag=&Service=AWSECommerceService&Signature=5sbmkIO1PqtCCUH0Ih9Fx/3q9ER1FuXk2UPFLlISrIQ=&Timestamp=2011-01-17T15:20:03Z&Version=2010-11-01
6
6
  body:
7
7
  headers:
8
8
  response: !ruby/struct:VCR::Response
@@ -11,13 +11,13 @@
11
11
  message: OK
12
12
  headers:
13
13
  date:
14
- - Wed, 15 Dec 2010 07:14:37 GMT
14
+ - Mon, 17 Jan 2011 15:20:05 GMT
15
15
  server:
16
16
  - Server
17
17
  x-amz-id-1:
18
- - 0E8S4ENZ8Q9WBHRS7211
18
+ - 1218DXHJBXZ5J480J8QM
19
19
  x-amz-id-2:
20
- - 4r6BnL5Ix6csd4KWILexsqszhPU99B63G0hcnRHvPww=
20
+ - SJpoXux3oMHHhZyjDxwhVVy8JrcptMTdzE1nK8SxSm0=
21
21
  nncoection:
22
22
  - close
23
23
  - close
@@ -0,0 +1,26 @@
1
+ ---
2
+ - !ruby/struct:VCR::HTTPInteraction
3
+ request: !ruby/struct:VCR::Request
4
+ method: :get
5
+ uri: http://ecs.amazonaws.com:80/onca/xml?AWSAccessKeyId=0ZVSQ33MDFPQS8H2PM02&AssociateTag=&IdType=ASIN&ItemId=0816614024,0143105825&Operation=ItemLookup&Service=AWSECommerceService&Signature=mb2SRZUnxqPRrI4SdOLZqkCmm5HjXE2Urd0PIr/vzWU=&Timestamp=2011-01-17T15:20:11Z&Version=2010-11-01
6
+ body:
7
+ headers:
8
+ response: !ruby/struct:VCR::Response
9
+ status: !ruby/struct:VCR::ResponseStatus
10
+ code: 200
11
+ message: OK
12
+ headers:
13
+ date:
14
+ - Mon, 17 Jan 2011 15:20:12 GMT
15
+ server:
16
+ - Server
17
+ content-type:
18
+ - text/xml;charset=UTF-8
19
+ vary:
20
+ - Accept-Encoding,User-Agent
21
+ nncoection:
22
+ - close
23
+ transfer-encoding:
24
+ - chunked
25
+ body: "<?xml version=\"1.0\" ?><ItemLookupResponse xmlns=\"http://webservices.amazon.com/AWSECommerceService/2010-11-01\"><OperationRequest><RequestId>c5f72c52-3206-4a9f-a30f-a58e1a5f4445</RequestId><Arguments><Argument Name=\"Operation\" Value=\"ItemLookup\"></Argument><Argument Name=\"Service\" Value=\"AWSECommerceService\"></Argument><Argument Name=\"Signature\" Value=\"mb2SRZUnxqPRrI4SdOLZqkCmm5HjXE2Urd0PIr/vzWU=\"></Argument><Argument Name=\"AssociateTag\"></Argument><Argument Name=\"Version\" Value=\"2010-11-01\"></Argument><Argument Name=\"ItemId\" Value=\"0816614024,0143105825\"></Argument><Argument Name=\"IdType\" Value=\"ASIN\"></Argument><Argument Name=\"AWSAccessKeyId\" Value=\"0ZVSQ33MDFPQS8H2PM02\"></Argument><Argument Name=\"Timestamp\" Value=\"2011-01-17T15:20:11Z\"></Argument></Arguments><RequestProcessingTime>0.0103990000000000</RequestProcessingTime></OperationRequest><Items><Request><IsValid>True</IsValid><ItemLookupRequest><Condition>New</Condition><DeliveryMethod>Ship</DeliveryMethod><IdType>ASIN</IdType><MerchantId>Amazon</MerchantId><OfferPage>1</OfferPage><ItemId>0816614024</ItemId><ItemId>0143105825</ItemId><ResponseGroup>Small</ResponseGroup><ReviewPage>1</ReviewPage><ReviewSort>-SubmissionDate</ReviewSort><VariationPage>All</VariationPage></ItemLookupRequest></Request><Item><ASIN>0816614024</ASIN><DetailPageURL>http://www.amazon.com/Thousand-Plateaus-Schizophrenia-Gilles-Deleuze/dp/0816614024%3FSubscriptionId%3D0ZVSQ33MDFPQS8H2PM02%26tag%3Dws%26linkCode%3Dxm2%26camp%3D2025%26creative%3D165953%26creativeASIN%3D0816614024</DetailPageURL><ItemLinks><ItemLink><Description>Technical Details</Description><URL>http://www.amazon.com/Thousand-Plateaus-Schizophrenia-Gilles-Deleuze/dp/tech-data/0816614024%3FSubscriptionId%3D0ZVSQ33MDFPQS8H2PM02%26tag%3Dws%26linkCode%3Dxm2%26camp%3D2025%26creative%3D386001%26creativeASIN%3D0816614024</URL></ItemLink><ItemLink><Description>Add To Baby Registry</Description><URL>http://www.amazon.com/gp/registry/baby/add-item.html%3Fasin.0%3D0816614024%26SubscriptionId%3D0ZVSQ33MDFPQS8H2PM02%26tag%3Dws%26linkCode%3Dxm2%26camp%3D2025%26creative%3D386001%26creativeASIN%3D0816614024</URL></ItemLink><ItemLink><Description>Add To Wedding Registry</Description><URL>http://www.amazon.com/gp/registry/wedding/add-item.html%3Fasin.0%3D0816614024%26SubscriptionId%3D0ZVSQ33MDFPQS8H2PM02%26tag%3Dws%26linkCode%3Dxm2%26camp%3D2025%26creative%3D386001%26creativeASIN%3D0816614024</URL></ItemLink><ItemLink><Description>Add To Wishlist</Description><URL>http://www.amazon.com/gp/registry/wishlist/add-item.html%3Fasin.0%3D0816614024%26SubscriptionId%3D0ZVSQ33MDFPQS8H2PM02%26tag%3Dws%26linkCode%3Dxm2%26camp%3D2025%26creative%3D386001%26creativeASIN%3D0816614024</URL></ItemLink><ItemLink><Description>Tell A Friend</Description><URL>http://www.amazon.com/gp/pdp/taf/0816614024%3FSubscriptionId%3D0ZVSQ33MDFPQS8H2PM02%26tag%3Dws%26linkCode%3Dxm2%26camp%3D2025%26creative%3D386001%26creativeASIN%3D0816614024</URL></ItemLink><ItemLink><Description>All Customer Reviews</Description><URL>http://www.amazon.com/review/product/0816614024%3FSubscriptionId%3D0ZVSQ33MDFPQS8H2PM02%26tag%3Dws%26linkCode%3Dxm2%26camp%3D2025%26creative%3D386001%26creativeASIN%3D0816614024</URL></ItemLink><ItemLink><Description>All Offers</Description><URL>http://www.amazon.com/gp/offer-listing/0816614024%3FSubscriptionId%3D0ZVSQ33MDFPQS8H2PM02%26tag%3Dws%26linkCode%3Dxm2%26camp%3D2025%26creative%3D386001%26creativeASIN%3D0816614024</URL></ItemLink></ItemLinks><ItemAttributes><Author>Gilles Deleuze</Author><Creator Role=\"Contributor\">Felix Guattari</Creator><Manufacturer>Univ Of Minnesota Press</Manufacturer><ProductGroup>Book</ProductGroup><Title>Thousand Plateaus: Capitalism and Schizophrenia</Title></ItemAttributes></Item><Item><ASIN>0143105825</ASIN><DetailPageURL>http://www.amazon.com/Anti-Oedipus-Capitalism-Schizophrenia-Penguin-Classics/dp/0143105825%3FSubscriptionId%3D0ZVSQ33MDFPQS8H2PM02%26tag%3Dws%26linkCode%3Dxm2%26camp%3D2025%26creative%3D165953%26creativeASIN%3D0143105825</DetailPageURL><ItemLinks><ItemLink><Description>Technical Details</Description><URL>http://www.amazon.com/Anti-Oedipus-Capitalism-Schizophrenia-Penguin-Classics/dp/tech-data/0143105825%3FSubscriptionId%3D0ZVSQ33MDFPQS8H2PM02%26tag%3Dws%26linkCode%3Dxm2%26camp%3D2025%26creative%3D386001%26creativeASIN%3D0143105825</URL></ItemLink><ItemLink><Description>Add To Baby Registry</Description><URL>http://www.amazon.com/gp/registry/baby/add-item.html%3Fasin.0%3D0143105825%26SubscriptionId%3D0ZVSQ33MDFPQS8H2PM02%26tag%3Dws%26linkCode%3Dxm2%26camp%3D2025%26creative%3D386001%26creativeASIN%3D0143105825</URL></ItemLink><ItemLink><Description>Add To Wedding Registry</Description><URL>http://www.amazon.com/gp/registry/wedding/add-item.html%3Fasin.0%3D0143105825%26SubscriptionId%3D0ZVSQ33MDFPQS8H2PM02%26tag%3Dws%26linkCode%3Dxm2%26camp%3D2025%26creative%3D386001%26creativeASIN%3D0143105825</URL></ItemLink><ItemLink><Description>Add To Wishlist</Description><URL>http://www.amazon.com/gp/registry/wishlist/add-item.html%3Fasin.0%3D0143105825%26SubscriptionId%3D0ZVSQ33MDFPQS8H2PM02%26tag%3Dws%26linkCode%3Dxm2%26camp%3D2025%26creative%3D386001%26creativeASIN%3D0143105825</URL></ItemLink><ItemLink><Description>Tell A Friend</Description><URL>http://www.amazon.com/gp/pdp/taf/0143105825%3FSubscriptionId%3D0ZVSQ33MDFPQS8H2PM02%26tag%3Dws%26linkCode%3Dxm2%26camp%3D2025%26creative%3D386001%26creativeASIN%3D0143105825</URL></ItemLink><ItemLink><Description>All Customer Reviews</Description><URL>http://www.amazon.com/review/product/0143105825%3FSubscriptionId%3D0ZVSQ33MDFPQS8H2PM02%26tag%3Dws%26linkCode%3Dxm2%26camp%3D2025%26creative%3D386001%26creativeASIN%3D0143105825</URL></ItemLink><ItemLink><Description>All Offers</Description><URL>http://www.amazon.com/gp/offer-listing/0143105825%3FSubscriptionId%3D0ZVSQ33MDFPQS8H2PM02%26tag%3Dws%26linkCode%3Dxm2%26camp%3D2025%26creative%3D386001%26creativeASIN%3D0143105825</URL></ItemLink></ItemLinks><ItemAttributes><Author>Gilles Deleuze</Author><Author>Felix Guattari</Author><Creator Role=\"Translator\">Robert Hurley</Creator><Creator Role=\"Translator\">Mark Seem</Creator><Creator Role=\"Introduction\">Mark Seem</Creator><Creator Role=\"Translator\">Helen Lane</Creator><Creator Role=\"Preface\">Michel Foucault</Creator><Manufacturer>Penguin Classics</Manufacturer><ProductGroup>Book</ProductGroup><Title>Anti-Oedipus: Capitalism and Schizophrenia (Penguin Classics)</Title></ItemAttributes></Item></Items></ItemLookupResponse>"
26
+ http_version: "1.1"
@@ -0,0 +1,61 @@
1
+ require 'spec_helper'
2
+
3
+ module Sucker
4
+ describe Parameters do
5
+ let(:parameters) do
6
+ Parameters.new
7
+ end
8
+
9
+ it "is a Hash" do
10
+ Parameters.ancestors.should include Hash
11
+ end
12
+
13
+ context "when initialized" do
14
+ it "sets `Service`" do
15
+ parameters.should have_key "Service"
16
+ end
17
+
18
+ it "sets `Version`" do
19
+ parameters.should have_key "Version"
20
+ end
21
+
22
+ it "set `Timestamp`" do
23
+ parameters.should have_key "Timestamp"
24
+ end
25
+ end
26
+
27
+ describe "#normalize" do
28
+ it "casts keys to string" do
29
+ parameters[:Foo] = 0
30
+ normalized = parameters.normalize
31
+
32
+ normalized.should have_key "Foo"
33
+ normalized.should_not have_key :foo
34
+ end
35
+
36
+ it "camelizes keys" do
37
+ parameters["foo_bar"] = 0
38
+ normalized = parameters.normalize
39
+
40
+ normalized.should have_key "FooBar"
41
+ normalized.should_not have_key "foo_bar"
42
+ end
43
+
44
+ it "casts numeric values to string" do
45
+ parameters["Foo"] = 1
46
+ parameters.normalize["Foo"].should eql "1"
47
+ end
48
+
49
+ it "converts array values to string" do
50
+ parameters["Foo"] = ['bar', 'baz']
51
+ parameters.normalize["Foo"].should eql 'bar,baz'
52
+ end
53
+ end
54
+
55
+ describe "#timestamp" do
56
+ it "generates a timestamp" do
57
+ parameters.send(:timestamp).should match /^\d+-\d+-\d+T\d+:\d+:\d+Z$/
58
+ end
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,276 @@
1
+ require "spec_helper"
2
+
3
+ module Sucker
4
+ describe Request do
5
+ use_vcr_cassette "spec/sucker/request", :record => :new_episodes
6
+
7
+ let(:worker) do
8
+ Sucker.new(
9
+ :locale => :us,
10
+ :key => "key",
11
+ :secret => "secret")
12
+ end
13
+
14
+ describe "#<<" do
15
+ it "merges a hash into the existing parameters" do
16
+ worker << { "foo" => "bar" }
17
+ worker.parameters["foo"].should eql "bar"
18
+ end
19
+ end
20
+
21
+ describe "#version=" do
22
+ it "sets the Amazon API version" do
23
+ worker.version = "foo"
24
+ worker.parameters["Version"].should eql "foo"
25
+ end
26
+ end
27
+
28
+ describe "#associate_tag" do
29
+ it "returns the associate tag for the current locale" do
30
+ worker.instance_variable_set(:@associate_tags, { :us => 'foo-bar'})
31
+
32
+ worker.associate_tag.should eql 'foo-bar'
33
+ end
34
+
35
+ it "returns blank if no associate tag is set for the current locale" do
36
+ worker.associate_tag.should be_blank
37
+ end
38
+ end
39
+
40
+ describe "#associate_tag=" do
41
+ it "sets the associate tag for the current locale" do
42
+ worker.associate_tag = "foo-bar"
43
+ associate_tags = worker.instance_variable_get(:@associate_tags)
44
+
45
+ associate_tags.keys.size.should eql 1
46
+ associate_tags[:us].should eql 'foo-bar'
47
+ worker.associate_tag.should eql 'foo-bar'
48
+ end
49
+ end
50
+
51
+ describe "#associate_tags=" do
52
+ it "sets associate tags for the locales" do
53
+ tags = {
54
+ :us => 'foo',
55
+ :uk => 'bar',
56
+ :de => 'baz',
57
+ :ca => 'foo',
58
+ :fr => 'bar',
59
+ :jp => 'baz' }
60
+ worker.associate_tags = tags
61
+
62
+ worker.instance_variable_get(:@associate_tags).should eql tags
63
+ end
64
+ end
65
+
66
+ describe "#curl_opts" do
67
+ it "returns options for curl" do
68
+ worker.curl_opts.should be_an_instance_of Hash
69
+ end
70
+
71
+ context "when given a block" do
72
+
73
+ it "yields options for curl" do
74
+ worker.curl_opts { |c| c.interface = "eth1" }
75
+
76
+ worker.curl_opts[:interface].should eql "eth1"
77
+ end
78
+ end
79
+ end
80
+
81
+ describe "#get" do
82
+ context "when no argument is passed" do
83
+ it "returns a response" do
84
+ worker.get.class.ancestors.should include Response
85
+ end
86
+
87
+ it "sets options on curl" do
88
+ easy = mock
89
+ easy.should_receive(:interface=).once.with("eth1")
90
+ Curl::Easy.stub!(:perform).and_yield(easy)
91
+ Response.should_receive(:new).once
92
+
93
+ worker.curl_opts { |c| c.interface = 'eth1' }
94
+ worker.get
95
+ end
96
+ end
97
+
98
+ context "when one argument is passed" do
99
+ context "when the argument is is `:all`" do
100
+ it "queries all locales" do
101
+ locales = worker.send(:locales)
102
+ worker.should_receive(:get_multi).with(locales)
103
+ worker.get(:all)
104
+ end
105
+ end
106
+
107
+ context "when the argument is not `:all`" do
108
+ it "sets current locale to to the argument" do
109
+ worker.should_receive(:locale=).with(:uk)
110
+ worker.get(:uk)
111
+ end
112
+
113
+ it "calls itself with no argument" do
114
+ worker.class.send :alias_method, :get_original, :get
115
+ worker.should_receive(:get).with(no_args())
116
+ worker.get_original(:uk)
117
+ end
118
+ end
119
+ end
120
+
121
+ context "when multiple arguments are passed" do
122
+ it "queries multiple locales" do
123
+ worker.should_receive(:get_multi).with([:us, :uk])
124
+ worker.get(:us, :uk)
125
+ end
126
+ end
127
+ end
128
+
129
+ describe "#key" do
130
+ it "returns the Amazon AWS access key for the current locale" do
131
+ worker.instance_variable_set(:@keys, { :us => 'foo' })
132
+
133
+ worker.key.should eql 'foo'
134
+ end
135
+
136
+ it "raises an argument error if key is missing" do
137
+ worker.instance_variable_get(:@keys)[:us] = nil
138
+ expect do
139
+ worker.key
140
+ end.to raise_error 'AWS access key missing'
141
+ end
142
+ end
143
+
144
+ describe "#key=" do
145
+ it "sets a global Amazon AWS access key" do
146
+ worker.key = "foo"
147
+ keys = worker.instance_variable_get(:@keys)
148
+
149
+ keys.size.should eql Request::HOSTS.size
150
+ keys.values.uniq.should eql ["foo"]
151
+ end
152
+ end
153
+
154
+ describe "#keys=" do
155
+ it "sets distinct Amazon AWS access keys for the locales" do
156
+ keys = {
157
+ :us => 'foo',
158
+ :uk => 'bar',
159
+ :de => 'baz',
160
+ :ca => 'foo',
161
+ :fr => 'bar',
162
+ :jp => 'baz' }
163
+ worker.keys = keys
164
+
165
+ worker.instance_variable_get(:@keys).should eql keys
166
+ end
167
+ end
168
+
169
+ describe "#locale" do
170
+ it "returns the current locale" do
171
+ worker.locale.should eql :us
172
+ end
173
+
174
+ it "raises an argument error if locale is not set" do
175
+ worker.instance_variable_set(:@locale, nil)
176
+ expect do
177
+ worker.locale
178
+ end.to raise_error 'Locale not set'
179
+ end
180
+ end
181
+
182
+ describe "#locale=" do
183
+ it "sets the current locale" do
184
+ worker.locale= :uk
185
+ worker.locale.should eql :uk
186
+ end
187
+
188
+ it "raises an argument error if locale is invalid" do
189
+ expect do
190
+ worker.locale= :br
191
+ end.to raise_error 'Invalid locale'
192
+ end
193
+ end
194
+
195
+ # private
196
+
197
+ describe "#build_query" do
198
+ let(:query) do
199
+ worker.send(:build_query)
200
+ end
201
+
202
+ it "canonicalizes query" do
203
+ query.should match /Service=([^&]+)&Timestamp=([^&]+)&Version=([^&]+)/
204
+ end
205
+
206
+ it "includes a timestamp" do
207
+ query.should include 'Timestamp'
208
+ end
209
+
210
+ it "sorts query" do
211
+ worker.parameters["A"] = "foo"
212
+ query.should match /^A=foo/
213
+ end
214
+ end
215
+
216
+ describe "#build_signed_query" do
217
+ let(:query) { worker.send(:build_signed_query) }
218
+
219
+ it "includes the key for the current locale" do
220
+ worker.key = 'foo'
221
+ query.should include 'AWSAccessKeyId=foo'
222
+ end
223
+
224
+ it "includes the associate tag for the current locale" do
225
+ worker.associate_tag = 'foo'
226
+ query.should include 'AssociateTag=foo'
227
+ end
228
+
229
+ it "returns a signed query string" do
230
+ query = worker.send :build_signed_query
231
+ query.should include 'Signature='
232
+ end
233
+ end
234
+
235
+ describe "#escape" do
236
+ it "URL-encodes a string" do
237
+ worker.send(:escape, 'foo,bar').should eql "foo%2Cbar"
238
+ end
239
+ end
240
+
241
+ describe "#get_multi" do
242
+ it "returns an array of responses" do
243
+ responses = worker.send(:get_multi, [:us, :uk])
244
+
245
+ responses.should be_an_instance_of Array
246
+ responses.each { |resp| resp.should be_an_instance_of Response }
247
+ end
248
+
249
+ context "when given a block" do
250
+ it "yields responses" do
251
+ locales = worker.send(:locales)
252
+ count = 0
253
+ worker.send(:get_multi, locales) do |resp|
254
+ resp.should be_an_instance_of Response
255
+ count += 1
256
+ end
257
+
258
+ count.should eql locales.size
259
+ end
260
+ end
261
+ end
262
+
263
+ describe "#host" do
264
+ it "returns a host" do
265
+ worker.locale = "fr"
266
+ worker.send(:host).should eql "ecs.amazonaws.fr"
267
+ end
268
+ end
269
+
270
+ describe "#uri" do
271
+ it "returns the URI with which to query Amazon" do
272
+ worker.send(:uri).should be_an_instance_of URI::HTTP
273
+ end
274
+ end
275
+ end
276
+ end
@@ -2,10 +2,8 @@
2
2
  require "spec_helper"
3
3
 
4
4
  module Sucker
5
-
6
5
  describe Response do
7
-
8
- use_vcr_cassette "unit/sucker/response", :record => :new_episodes
6
+ use_vcr_cassette "spec/sucker/response", :record => :new_episodes
9
7
 
10
8
  let(:asins) { ["0816614024", "0143105825"] }
11
9
 
@@ -17,13 +15,11 @@ module Sucker
17
15
  worker << {
18
16
  "Operation" => "ItemLookup",
19
17
  "IdType" => "ASIN",
20
- "ResponseGroup" => ["ItemAttributes", "OfferFull"],
21
18
  "ItemId" => asins }
22
19
  worker.get
23
20
  end
24
21
 
25
22
  describe ".new" do
26
-
27
23
  it "initializes the response body" do
28
24
  response.body.should be_an_instance_of String
29
25
  end
@@ -39,43 +35,10 @@ module Sucker
39
35
  it "initializes the request URI" do
40
36
  response.uri.should be_an_instance_of String
41
37
  end
42
-
43
- end
44
-
45
- describe "#xml" do
46
-
47
- it "returns a Nokogiri document" do
48
- response.xml.should be_an_instance_of Nokogiri::XML::Document
49
- end
50
-
51
- end
52
-
53
- describe "#find" do
54
-
55
- context "when there are matches" do
56
-
57
- it "returns an array of matching nodes" do
58
- node = response.find("ItemAttributes")
59
- node.map { |book| book["ISBN"] }.should eql asins
60
- end
61
-
62
- end
63
-
64
- context "when there are no matches" do
65
-
66
- it "returns an empty array" do
67
- node = response.find("Foo")
68
- node.should eql []
69
- end
70
-
71
- end
72
-
73
38
  end
74
39
 
75
40
  describe "#each" do
76
-
77
41
  context "when a block is given" do
78
-
79
42
  it "yields each match to a block" do
80
43
  has_yielded = false
81
44
 
@@ -86,51 +49,70 @@ module Sucker
86
49
 
87
50
  has_yielded.should be_true
88
51
  end
89
-
90
52
  end
91
53
 
92
54
  context "when no block is given" do
93
-
94
55
  it "raises error" do
95
56
  expect do
96
57
  response.each("ItemAttributes")
97
58
  end.to raise_error(LocalJumpError)
98
59
  end
60
+ end
61
+ end
62
+
63
+ context "when response contains errors" do
64
+ before do
65
+ response.body = "<?xml version=\"1.0\" ?><ItemLookupResponse xmlns=\"http://webservices.amazon.com/AWSECommerceService/2010-09-01\"><Errors><Error>foo</Error><Error>bar</Error></Errors>"
66
+ end
99
67
 
68
+ describe "#errors" do
69
+ it "returns an array of errors" do
70
+ response.errors.count.should eql 2
71
+ end
100
72
  end
101
73
 
74
+ describe "#has_errors?" do
75
+ it "returns true if the response has errors" do
76
+ response.should have_errors
77
+ end
78
+ end
102
79
  end
103
80
 
81
+ describe "#find" do
82
+ context "when there are matches" do
104
83
 
105
- describe "#map" do
84
+ it "returns an array of matching nodes" do
85
+ response.find("ASIN").should eql asins
86
+ end
87
+ end
106
88
 
107
- context "when a block is given" do
89
+ context "when there are no matches" do
90
+ it "returns an empty array" do
91
+ node = response.find("Foo")
92
+ node.should eql []
93
+ end
94
+ end
95
+ end
108
96
 
97
+ describe "#map" do
98
+ context "when a block is given" do
109
99
  it "yields each match to a block and maps returned values" do
110
- # Collect EANs
111
- eans = response.map("ItemAttributes") { |item| item["EAN"] }
100
+ titles = response.map("ItemAttributes") { |item| item["Title"] }
112
101
 
113
- eans.should be_an_instance_of Array
114
- eans.each { |ean| ean.match(/^[0-9]{13}$/).should be_true }
102
+ titles.count.should eql 2
115
103
  end
116
-
117
104
  end
118
105
 
119
106
  context "when no block is given" do
120
-
121
107
  it "raises error" do
122
108
  expect do
123
109
  response.map("ItemAttributes")
124
110
  end.to raise_error(LocalJumpError)
125
111
  end
126
-
127
112
  end
128
-
129
113
  end
130
114
 
131
-
132
115
  describe "#to_hash" do
133
-
134
116
  it "returns a hash" do
135
117
  response.to_hash.should be_an_instance_of Hash
136
118
  end
@@ -154,30 +136,27 @@ module Sucker
154
136
  response.body = "<Title>スティーブ・ジョブズ 驚異のプレゼン―人々を惹きつける18の法則</Title>"
155
137
  response.to_hash["Title"].should eql "スティーブ・ジョブズ 驚異のプレゼン―人々を惹きつける18の法則"
156
138
  end
157
-
158
139
  end
159
140
 
160
141
  describe "#valid?" do
161
-
162
142
  context "when HTTP status is OK" do
163
-
164
143
  it "returns true" do
165
144
  response.should be_valid
166
145
  end
167
-
168
146
  end
169
147
 
170
148
  context "when HTTP status is not OK" do
171
-
172
149
  it "returns false" do
173
150
  response.code = 403
174
151
  response.should_not be_valid
175
152
  end
176
-
177
153
  end
178
-
179
154
  end
180
155
 
156
+ describe "#xml" do
157
+ it "returns a Nokogiri document" do
158
+ response.xml.should be_an_instance_of Nokogiri::XML::Document
159
+ end
160
+ end
181
161
  end
182
-
183
162
  end