peddler 1.6.7 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +69 -67
- data/lib/mws/feeds/client.rb +15 -12
- data/lib/mws/finances/client.rb +12 -11
- data/lib/mws/fulfillment_inbound_shipment/client.rb +79 -107
- data/lib/mws/fulfillment_inventory/client.rb +5 -5
- data/lib/mws/fulfillment_outbound_shipment/client.rb +36 -44
- data/lib/mws/merchant_fulfillment/client.rb +11 -17
- data/lib/mws/off_amazon_payments/client.rb +38 -68
- data/lib/mws/orders/client.rb +28 -24
- data/lib/mws/products/client.rb +118 -153
- data/lib/mws/recommendations/client.rb +13 -17
- data/lib/mws/reports/client.rb +24 -23
- data/lib/mws/sellers/client.rb +5 -5
- data/lib/mws/subscriptions/client.rb +25 -36
- data/lib/peddler/client.rb +47 -124
- data/lib/peddler/errors/builder.rb +40 -14
- data/lib/peddler/errors/class_generator.rb +34 -0
- data/lib/peddler/errors/error.rb +13 -3
- data/lib/peddler/headers.rb +27 -11
- data/lib/peddler/marketplace.rb +30 -11
- data/lib/peddler/vcr_matcher.rb +11 -1
- data/lib/peddler/version.rb +1 -1
- data/lib/peddler/xml_parser.rb +4 -2
- data/lib/peddler/xml_response_parser.rb +1 -1
- data/test/helper.rb +0 -1
- data/test/integration/test_errors.rb +2 -14
- data/test/integration/test_feeds.rb +0 -3
- data/test/integration/test_multibyte_queries.rb +1 -1
- data/test/integration/test_mws_headers.rb +3 -2
- data/test/integration/test_orders.rb +2 -1
- data/test/integration/test_products.rb +9 -9
- data/test/integration/test_recommendations.rb +1 -1
- data/test/integration/test_subscriptions.rb +2 -2
- data/test/integration_helper.rb +1 -1
- data/test/mws.yml +36 -0
- data/test/mws.yml.example +8 -12
- data/test/null_client.rb +10 -8
- data/test/unit/mws/test_feeds_client.rb +1 -2
- data/test/unit/mws/test_fulfillment_outbound_shipment_client.rb +1 -1
- data/test/unit/mws/test_off_amazon_payments_client.rb +1 -1
- data/test/unit/mws/test_orders_client.rb +7 -6
- data/test/unit/mws/test_products_client.rb +13 -28
- data/test/unit/mws/test_recommendations_client.rb +1 -2
- data/test/unit/mws/test_reports_client.rb +1 -1
- data/test/unit/mws/test_subscriptions_client.rb +1 -130
- data/test/unit/peddler/errors/test_builder.rb +54 -7
- data/test/unit/peddler/errors/test_class_generator.rb +18 -0
- data/test/unit/peddler/errors/test_error.rb +7 -2
- data/test/unit/peddler/test_client.rb +136 -190
- data/test/unit/peddler/test_flat_file_parser.rb +2 -2
- data/test/unit/peddler/test_headers.rb +19 -9
- data/test/unit/peddler/test_marketplace.rb +18 -5
- data/test/unit/peddler/test_vcr_matcher.rb +3 -1
- data/test/vcr_cassettes/Feeds.yml +4816 -5224
- data/test/vcr_cassettes/Reports.yml +3278 -2604
- metadata +8 -9
- data/lib/peddler/errors.rb +0 -12
- data/lib/peddler/errors/handler.rb +0 -59
- data/test/unit/peddler/errors/test_handler.rb +0 -62
- data/test/unit/peddler/test_errors.rb +0 -26
@@ -4,15 +4,62 @@ require 'helper'
|
|
4
4
|
require 'peddler/errors/builder'
|
5
5
|
|
6
6
|
class TestPeddlerErrorsBuilder < MiniTest::Test
|
7
|
-
def
|
8
|
-
Peddler::Errors::Builder.
|
9
|
-
assert Peddler::Errors::Foo
|
7
|
+
def setup
|
8
|
+
@error = Peddler::Errors::Builder.call(@cause)
|
10
9
|
end
|
11
10
|
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
11
|
+
class CausedByHTTPStatusError < TestPeddlerErrorsBuilder
|
12
|
+
def setup
|
13
|
+
@code = 'FeedProcessingResultNotReady'
|
14
|
+
@message = 'Feed Submission Result is not ready for Feed 123'
|
15
|
+
body = <<-XML
|
16
|
+
<ErrorResponse>
|
17
|
+
<Error>
|
18
|
+
<Code>#{@code}</Code>
|
19
|
+
<Message>#{@message}</Message>
|
20
|
+
</Error>
|
21
|
+
</ErrorResponse>
|
22
|
+
XML
|
23
|
+
@cause = Excon::Error::NotFound.new(
|
24
|
+
'Expected(200) <=> Actual(404 Not Found)',
|
25
|
+
nil,
|
26
|
+
OpenStruct.new(body: body)
|
27
|
+
)
|
28
|
+
super
|
29
|
+
end
|
30
|
+
|
31
|
+
def test_generates_custom_error
|
32
|
+
assert_includes @error.class.name, @code
|
33
|
+
end
|
34
|
+
|
35
|
+
def test_provides_message
|
36
|
+
assert_equal @message, @error.message
|
37
|
+
end
|
38
|
+
|
39
|
+
def test_provides_cause
|
40
|
+
assert_equal @cause, @error.cause
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
class CausedByInternalServerError < TestPeddlerErrorsBuilder
|
45
|
+
def setup
|
46
|
+
body = <<-XML
|
47
|
+
<ErrorResponse>
|
48
|
+
<Error>
|
49
|
+
<Code>500</Code>
|
50
|
+
</Error>
|
51
|
+
</ErrorResponse>
|
52
|
+
XML
|
53
|
+
@cause = Excon::Error::InternalServerError.new(
|
54
|
+
nil,
|
55
|
+
nil,
|
56
|
+
OpenStruct.new(body: body)
|
57
|
+
)
|
58
|
+
super
|
59
|
+
end
|
60
|
+
|
61
|
+
def test_returns_nothing
|
62
|
+
assert_nil @error
|
16
63
|
end
|
17
64
|
end
|
18
65
|
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'helper'
|
4
|
+
require 'peddler/errors/class_generator'
|
5
|
+
|
6
|
+
class TestPeddlerErrorsClassGenerator < MiniTest::Test
|
7
|
+
def test_builds_error_class
|
8
|
+
Peddler::Errors::ClassGenerator.call('Foo')
|
9
|
+
assert Peddler::Errors::Foo
|
10
|
+
end
|
11
|
+
|
12
|
+
def test_thread_safety
|
13
|
+
Peddler::Errors::ClassGenerator.call('Foo')
|
14
|
+
assert_output '', '' do
|
15
|
+
Peddler::Errors::ClassGenerator.call('Foo')
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -5,7 +5,8 @@ require 'peddler/errors/error'
|
|
5
5
|
|
6
6
|
class TestPeddlerErrorsError < MiniTest::Test
|
7
7
|
def setup
|
8
|
-
@
|
8
|
+
@cause = OpenStruct.new(response: 'response')
|
9
|
+
@error = Peddler::Errors::Error.new('message', @cause)
|
9
10
|
end
|
10
11
|
|
11
12
|
def test_sets_message
|
@@ -13,7 +14,7 @@ class TestPeddlerErrorsError < MiniTest::Test
|
|
13
14
|
end
|
14
15
|
|
15
16
|
def test_sets_cause
|
16
|
-
assert_equal
|
17
|
+
assert_equal @cause, @error.cause
|
17
18
|
end
|
18
19
|
|
19
20
|
def test_defines_common_errors
|
@@ -25,4 +26,8 @@ class TestPeddlerErrorsError < MiniTest::Test
|
|
25
26
|
def test_allows_nil_arguments
|
26
27
|
Peddler::Errors::Error.new
|
27
28
|
end
|
29
|
+
|
30
|
+
def test_delegates_response_to_cause
|
31
|
+
assert_equal @cause.response, @error.response
|
32
|
+
end
|
28
33
|
end
|
@@ -5,10 +5,7 @@ require 'null_client'
|
|
5
5
|
|
6
6
|
class TestPeddlerClient < MiniTest::Test
|
7
7
|
def setup
|
8
|
-
@response_body = 'foo'
|
9
8
|
Excon.defaults[:mock] = true
|
10
|
-
Excon.stub({}, body: @response_body, status: 200)
|
11
|
-
|
12
9
|
@klass = Class.new(Null::Client)
|
13
10
|
@client = @klass.new
|
14
11
|
@client.configure_with_mock_data!
|
@@ -20,238 +17,187 @@ class TestPeddlerClient < MiniTest::Test
|
|
20
17
|
Excon.defaults.delete(:mock)
|
21
18
|
end
|
22
19
|
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
@klass.path('/Foo')
|
30
|
-
|
31
|
-
@client.path = '/Foo/Bar'
|
32
|
-
assert @client.aws_endpoint.match(%r{/Foo/Bar$})
|
33
|
-
end
|
34
|
-
|
35
|
-
def test_default_path
|
36
|
-
assert_equal '/', @klass.path
|
37
|
-
end
|
38
|
-
|
39
|
-
def test_has_user_agent
|
40
|
-
assert @client.connection.data[:headers].key?('User-Agent')
|
41
|
-
end
|
42
|
-
|
43
|
-
def test_inherits_parents_params
|
44
|
-
assert_equal Peddler::Client.params, @klass.params
|
45
|
-
end
|
46
|
-
|
47
|
-
def test_inherits_parents_path
|
48
|
-
assert_equal @klass.path, Class.new(@klass).path
|
49
|
-
end
|
20
|
+
class HappyPath < TestPeddlerClient
|
21
|
+
def setup
|
22
|
+
@response_body = 'foo'
|
23
|
+
Excon.stub({}, body: @response_body, status: 200)
|
24
|
+
super
|
25
|
+
end
|
50
26
|
|
51
|
-
|
52
|
-
|
53
|
-
|
27
|
+
def test_has_user_agent
|
28
|
+
assert @client.connection.data[:headers].key?('User-Agent')
|
29
|
+
end
|
54
30
|
|
55
|
-
|
56
|
-
|
57
|
-
|
31
|
+
def test_inherits_parents_params
|
32
|
+
assert_equal Peddler::Client.params, @klass.params
|
33
|
+
end
|
58
34
|
|
59
|
-
|
60
|
-
|
61
|
-
|
35
|
+
def test_params_include_seller_id
|
36
|
+
assert @klass.params.key?('SellerId')
|
37
|
+
end
|
62
38
|
|
63
|
-
|
64
|
-
|
65
|
-
config.aws_access_key_id = '123'
|
39
|
+
def test_params_include_auth_token
|
40
|
+
@klass.params.key?('MWSAuthToken')
|
66
41
|
end
|
67
42
|
|
68
|
-
|
69
|
-
|
43
|
+
def test_inherits_parents_parser
|
44
|
+
assert_equal @klass.parser, Class.new(@klass).parser
|
45
|
+
end
|
70
46
|
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
47
|
+
def test_sets_marketplace
|
48
|
+
marketplace = Peddler::Marketplace.find('US')
|
49
|
+
@client.marketplace = 'US'
|
50
|
+
assert_equal marketplace, @client.marketplace
|
51
|
+
@client.marketplace = marketplace
|
52
|
+
assert_equal marketplace, @client.marketplace
|
53
|
+
end
|
75
54
|
|
76
|
-
|
77
|
-
|
78
|
-
|
55
|
+
def test_configures_when_initialising
|
56
|
+
client = @klass.new(aws_access_key_id: '123')
|
57
|
+
assert_equal '123', client.aws_access_key_id
|
58
|
+
end
|
79
59
|
|
80
|
-
|
81
|
-
|
60
|
+
def test_sets_content_type_header_for_latin_flat_file
|
61
|
+
@client.body = 'foo'
|
62
|
+
content_type = @client.headers.fetch('Content-Type')
|
82
63
|
|
83
|
-
|
84
|
-
|
85
|
-
@client.body = 'foo'
|
86
|
-
content_type = @client.headers.fetch('Content-Type')
|
64
|
+
assert_equal 'text/tab-separated-values; charset=CP1252', content_type
|
65
|
+
end
|
87
66
|
|
88
|
-
|
89
|
-
|
67
|
+
def test_sets_content_type_header_for_chinese_flat_file
|
68
|
+
@client.marketplace = 'CN'
|
69
|
+
@client.body = 'foo'
|
70
|
+
content_type = @client.headers.fetch('Content-Type')
|
90
71
|
|
91
|
-
|
92
|
-
|
93
|
-
@client.body = 'foo'
|
94
|
-
content_type = @client.headers.fetch('Content-Type')
|
72
|
+
assert_equal 'text/tab-separated-values; charset=UTF-16', content_type
|
73
|
+
end
|
95
74
|
|
96
|
-
|
97
|
-
|
75
|
+
def test_sets_content_type_header_for_japanese_flat_file
|
76
|
+
@client.marketplace = 'JP'
|
77
|
+
@client.body = 'foo'
|
78
|
+
content_type = @client.headers.fetch('Content-Type')
|
98
79
|
|
99
|
-
|
100
|
-
|
101
|
-
content_type = @client.headers.fetch('Content-Type')
|
80
|
+
assert_equal 'text/tab-separated-values; charset=Windows-31J', content_type
|
81
|
+
end
|
102
82
|
|
103
|
-
|
104
|
-
|
83
|
+
def test_sets_content_type_header_for_xml
|
84
|
+
@client.body = '<?xml version="1.0"?><Foo></Foo>'
|
85
|
+
content_type = @client.headers.fetch('Content-Type')
|
105
86
|
|
106
|
-
|
107
|
-
|
108
|
-
assert_equal 'Windows-1252', @client.body.encoding.to_s
|
109
|
-
end
|
87
|
+
assert_equal 'text/xml', content_type
|
88
|
+
end
|
110
89
|
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
end
|
90
|
+
def test_encodes_body_for_latin_flat_file
|
91
|
+
@client.body = 'foo'
|
92
|
+
assert_equal 'Windows-1252', @client.body.encoding.to_s
|
93
|
+
end
|
116
94
|
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
95
|
+
def test_encodes_body_for_chinese_flat_file
|
96
|
+
@client.marketplace = 'CN'
|
97
|
+
@client.body = 'foo'
|
98
|
+
assert_equal 'UTF-16', @client.body.encoding.to_s
|
99
|
+
end
|
122
100
|
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
101
|
+
def test_encodes_body_for_japanese_flat_file
|
102
|
+
@client.marketplace = 'JP'
|
103
|
+
@client.body = 'foo'
|
104
|
+
assert_equal 'Windows-31J', @client.body.encoding.to_s
|
105
|
+
end
|
127
106
|
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
end
|
107
|
+
def test_runs_a_request
|
108
|
+
res = @client.run
|
109
|
+
assert_equal @response_body, res.body
|
110
|
+
end
|
133
111
|
|
134
|
-
|
135
|
-
|
136
|
-
@client.body = 'foo'
|
137
|
-
assert_raises(Excon::Error::ServiceUnavailable) do
|
112
|
+
def test_clears_body_when_run_succeeds
|
113
|
+
@client.body = 'foo'
|
138
114
|
@client.run
|
115
|
+
assert_nil @client.body
|
139
116
|
end
|
140
|
-
refute_nil @client.body
|
141
|
-
end
|
142
|
-
|
143
|
-
def test_streams_response
|
144
|
-
chunks = ''
|
145
|
-
streamer = ->(chunk, _, _) { chunks += chunk }
|
146
|
-
@client.run(&streamer)
|
147
|
-
|
148
|
-
assert_equal @response_body, chunks
|
149
|
-
end
|
150
117
|
|
151
|
-
|
152
|
-
|
153
|
-
|
118
|
+
def test_streams_response
|
119
|
+
chunks = ''
|
120
|
+
streamer = ->(chunk, _, _) { chunks += chunk }
|
121
|
+
@client.run(&streamer)
|
154
122
|
|
155
|
-
|
156
|
-
events.update(name => params)
|
157
|
-
yield if block_given?
|
158
|
-
end
|
123
|
+
assert_equal @response_body, chunks
|
159
124
|
end
|
160
125
|
|
161
|
-
|
162
|
-
|
126
|
+
class Instrumentor
|
127
|
+
class << self
|
128
|
+
attr_accessor :events
|
163
129
|
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
assert headers.key?('User-Agent')
|
170
|
-
end
|
130
|
+
def instrument(name, params = {})
|
131
|
+
events.update(name => params)
|
132
|
+
yield if block_given?
|
133
|
+
end
|
134
|
+
end
|
171
135
|
|
172
|
-
|
173
|
-
|
136
|
+
@events = {}
|
137
|
+
end
|
174
138
|
|
175
|
-
|
139
|
+
def test_request_preserves_user_agent
|
140
|
+
@client.defaults.update(instrumentor: Instrumentor)
|
176
141
|
@client.run
|
177
|
-
|
142
|
+
headers = Instrumentor.events['excon.request'][:headers]
|
178
143
|
|
179
|
-
|
180
|
-
assert_equal 503, e.response.status
|
144
|
+
assert headers.key?('User-Agent')
|
181
145
|
end
|
182
|
-
@client.run # no longer raises
|
183
|
-
|
184
|
-
Excon.stubs.clear
|
185
146
|
end
|
186
147
|
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
148
|
+
class MWSErrorPath < TestPeddlerClient
|
149
|
+
def setup
|
150
|
+
body = <<-XML
|
151
|
+
<ErrorResponse>
|
152
|
+
<Error>
|
153
|
+
<Code>RequestThrottled</Code>
|
154
|
+
</Error>
|
155
|
+
</ErrorResponse>
|
156
|
+
XML
|
157
|
+
Excon.stub({}, body: body, status: 503)
|
158
|
+
super
|
192
159
|
end
|
193
160
|
|
194
|
-
|
195
|
-
|
161
|
+
def test_default_error_handling
|
162
|
+
assert_raises Peddler::Errors::RequestThrottled do
|
163
|
+
@client.run
|
164
|
+
end
|
196
165
|
end
|
197
|
-
@client.run
|
198
166
|
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
@klass.on_error do |e|
|
206
|
-
assert_equal 503, e.response.status
|
207
|
-
end
|
208
|
-
@client.run # no longer raises
|
209
|
-
|
210
|
-
klass = Class.new(Null::Client)
|
211
|
-
other_client = klass.new
|
212
|
-
other_client.configure_with_mock_data!
|
213
|
-
other_client.operation('Foo')
|
214
|
-
assert_raises(Excon::Error::ServiceUnavailable) do
|
215
|
-
other_client.run
|
167
|
+
def test_does_not_clear_body_when_run_fails
|
168
|
+
@client.body = 'foo'
|
169
|
+
assert_raises Peddler::Errors::RequestThrottled do
|
170
|
+
@client.run
|
171
|
+
end
|
172
|
+
refute_nil @client.body
|
216
173
|
end
|
217
|
-
|
218
|
-
Excon.stubs.clear
|
219
174
|
end
|
220
175
|
|
221
|
-
|
222
|
-
|
223
|
-
body
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
assert e.response.parse
|
176
|
+
class OtherHTTPStatusErrorPath < TestPeddlerClient
|
177
|
+
def setup
|
178
|
+
body = <<-XML
|
179
|
+
<ErrorResponse>
|
180
|
+
<Error>
|
181
|
+
<Code>500</Code>
|
182
|
+
</Error>
|
183
|
+
</ErrorResponse>
|
184
|
+
XML
|
185
|
+
Excon.stub({}, body: body, status: 500)
|
186
|
+
super
|
233
187
|
end
|
234
188
|
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
Excon.stub({}, status: 503)
|
240
|
-
|
241
|
-
@client.on_error do |_, res|
|
242
|
-
assert_equal 503, res.status
|
243
|
-
end
|
244
|
-
assert_output nil, /DEPRECATION/ do
|
245
|
-
@client.run
|
189
|
+
def test_error_handling
|
190
|
+
assert_raises Excon::Error::InternalServerError do
|
191
|
+
@client.run
|
192
|
+
end
|
246
193
|
end
|
247
194
|
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
assert_equal @client.primary_marketplace_id, @client.marketplace_id
|
195
|
+
def test_does_not_clear_body_when_run_fails
|
196
|
+
@client.body = 'foo'
|
197
|
+
assert_raises Excon::Error::InternalServerError do
|
198
|
+
@client.run
|
199
|
+
end
|
200
|
+
refute_nil @client.body
|
201
|
+
end
|
256
202
|
end
|
257
203
|
end
|