mws-connect 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +19 -0
- data/.sublime-project +19 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +111 -0
- data/Rakefile +1 -0
- data/lib/mws.rb +34 -0
- data/lib/mws/apis.rb +6 -0
- data/lib/mws/apis/feeds.rb +20 -0
- data/lib/mws/apis/feeds/api.rb +103 -0
- data/lib/mws/apis/feeds/distance.rb +23 -0
- data/lib/mws/apis/feeds/feed.rb +114 -0
- data/lib/mws/apis/feeds/image_listing.rb +44 -0
- data/lib/mws/apis/feeds/inventory.rb +77 -0
- data/lib/mws/apis/feeds/measurement.rb +32 -0
- data/lib/mws/apis/feeds/money.rb +31 -0
- data/lib/mws/apis/feeds/price_listing.rb +48 -0
- data/lib/mws/apis/feeds/product.rb +173 -0
- data/lib/mws/apis/feeds/sale_price.rb +31 -0
- data/lib/mws/apis/feeds/shipping.rb +160 -0
- data/lib/mws/apis/feeds/submission_info.rb +45 -0
- data/lib/mws/apis/feeds/submission_result.rb +87 -0
- data/lib/mws/apis/feeds/transaction.rb +37 -0
- data/lib/mws/apis/feeds/weight.rb +19 -0
- data/lib/mws/apis/orders.rb +23 -0
- data/lib/mws/connection.rb +84 -0
- data/lib/mws/enum.rb +81 -0
- data/lib/mws/errors.rb +32 -0
- data/lib/mws/query.rb +45 -0
- data/lib/mws/serializer.rb +81 -0
- data/lib/mws/signer.rb +20 -0
- data/lib/mws/utils.rb +50 -0
- data/mws.gemspec +25 -0
- data/scripts/catalog-workflow +136 -0
- data/spec/mws/apis/feeds/api_spec.rb +229 -0
- data/spec/mws/apis/feeds/distance_spec.rb +43 -0
- data/spec/mws/apis/feeds/feed_spec.rb +92 -0
- data/spec/mws/apis/feeds/image_listing_spec.rb +109 -0
- data/spec/mws/apis/feeds/inventory_spec.rb +135 -0
- data/spec/mws/apis/feeds/measurement_spec.rb +84 -0
- data/spec/mws/apis/feeds/money_spec.rb +43 -0
- data/spec/mws/apis/feeds/price_listing_spec.rb +90 -0
- data/spec/mws/apis/feeds/product_spec.rb +264 -0
- data/spec/mws/apis/feeds/shipping_spec.rb +78 -0
- data/spec/mws/apis/feeds/submission_info_spec.rb +111 -0
- data/spec/mws/apis/feeds/submission_result_spec.rb +157 -0
- data/spec/mws/apis/feeds/transaction_spec.rb +64 -0
- data/spec/mws/apis/feeds/weight_spec.rb +43 -0
- data/spec/mws/apis/orders_spec.rb +9 -0
- data/spec/mws/connection_spec.rb +331 -0
- data/spec/mws/enum_spec.rb +166 -0
- data/spec/mws/query_spec.rb +104 -0
- data/spec/mws/serializer_spec.rb +187 -0
- data/spec/mws/signer_spec.rb +67 -0
- data/spec/mws/utils_spec.rb +147 -0
- data/spec/spec_helper.rb +10 -0
- metadata +220 -0
@@ -0,0 +1,111 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'nokogiri'
|
3
|
+
|
4
|
+
module Mws::Apis::Feeds
|
5
|
+
|
6
|
+
describe SubmissionInfo do
|
7
|
+
|
8
|
+
let(:submitted_node) do
|
9
|
+
Nokogiri::XML::Builder.new do
|
10
|
+
FeedSubmissionInfo {
|
11
|
+
FeedSubmissionId 5868304010
|
12
|
+
FeedType '_POST_PRODUCT_DATA_'
|
13
|
+
SubmittedDate '2012-10-16T21:19:08+00:00'
|
14
|
+
FeedProcessingStatus '_SUBMITTED_'
|
15
|
+
}
|
16
|
+
end.doc.root
|
17
|
+
end
|
18
|
+
|
19
|
+
let(:in_progress_node) do
|
20
|
+
Nokogiri::XML::Builder.new do
|
21
|
+
FeedSubmissionInfo {
|
22
|
+
FeedSubmissionId 5868304010
|
23
|
+
FeedType '_POST_PRODUCT_DATA_'
|
24
|
+
SubmittedDate '2012-10-16T21:19:08+00:00'
|
25
|
+
FeedProcessingStatus '_IN_PROGRESS_'
|
26
|
+
StartedProcessingDate '2012-10-16T21:21:35+00:00'
|
27
|
+
}
|
28
|
+
end.doc.root
|
29
|
+
end
|
30
|
+
|
31
|
+
let(:done_node) do
|
32
|
+
Nokogiri::XML::Builder.new do
|
33
|
+
FeedSubmissionInfo {
|
34
|
+
FeedSubmissionId 5868304010
|
35
|
+
FeedType '_POST_PRODUCT_DATA_'
|
36
|
+
SubmittedDate '2012-10-16T21:19:08+00:00'
|
37
|
+
FeedProcessingStatus '_DONE_'
|
38
|
+
StartedProcessingDate '2012-10-16T21:21:35+00:00'
|
39
|
+
CompletedProcessingDate '2012-10-16T21:23:40+00:00'
|
40
|
+
}
|
41
|
+
end.doc.root
|
42
|
+
end
|
43
|
+
|
44
|
+
it 'should not allow instance creation via new' do
|
45
|
+
expect { SubmissionInfo.new }.to raise_error NoMethodError
|
46
|
+
end
|
47
|
+
|
48
|
+
context '.from_xml' do
|
49
|
+
|
50
|
+
it 'should be able to create an info object in a submitted state' do
|
51
|
+
info = SubmissionInfo.from_xml submitted_node
|
52
|
+
info.id.should == "5868304010"
|
53
|
+
info.status.should == SubmissionInfo::Status.SUBMITTED.sym
|
54
|
+
info.type.should == Feed::Type.PRODUCT.sym
|
55
|
+
info.submitted.should == Time.parse('2012-10-16T21:19:08+00:00')
|
56
|
+
info.started.should be_nil
|
57
|
+
info.completed.should be_nil
|
58
|
+
end
|
59
|
+
|
60
|
+
it 'should be able to create an info object in and in progress state' do
|
61
|
+
info = SubmissionInfo.from_xml in_progress_node
|
62
|
+
info.id.should == "5868304010"
|
63
|
+
info.status.should == SubmissionInfo::Status.IN_PROGRESS.sym
|
64
|
+
info.type.should == Feed::Type.PRODUCT.sym
|
65
|
+
info.submitted.should == Time.parse('2012-10-16T21:19:08+00:00')
|
66
|
+
info.started.should == Time.parse('2012-10-16T21:21:35+00:00')
|
67
|
+
info.completed.should be_nil
|
68
|
+
end
|
69
|
+
|
70
|
+
it 'should be able to create an info object in a done state' do
|
71
|
+
info = SubmissionInfo.from_xml done_node
|
72
|
+
info.id.should == "5868304010"
|
73
|
+
info.status.should == SubmissionInfo::Status.DONE.sym
|
74
|
+
info.type.should == Feed::Type.PRODUCT.sym
|
75
|
+
info.submitted.should == Time.parse('2012-10-16T21:19:08+00:00')
|
76
|
+
info.started.should == Time.parse('2012-10-16T21:21:35+00:00')
|
77
|
+
info.completed.should == Time.parse('2012-10-16T21:23:40+00:00')
|
78
|
+
end
|
79
|
+
|
80
|
+
end
|
81
|
+
|
82
|
+
context '#==' do
|
83
|
+
|
84
|
+
it 'should be reflexive' do
|
85
|
+
a = SubmissionInfo.from_xml submitted_node
|
86
|
+
(a == a).should be true
|
87
|
+
end
|
88
|
+
|
89
|
+
it 'should be symmetric' do
|
90
|
+
a = SubmissionInfo.from_xml submitted_node
|
91
|
+
b = SubmissionInfo.from_xml submitted_node
|
92
|
+
(a == b).should == (b == a)
|
93
|
+
end
|
94
|
+
|
95
|
+
it 'should be transitive' do
|
96
|
+
a = SubmissionInfo.from_xml submitted_node
|
97
|
+
b = SubmissionInfo.from_xml submitted_node
|
98
|
+
c = SubmissionInfo.from_xml submitted_node
|
99
|
+
(a == c).should == (a == b && b == c)
|
100
|
+
end
|
101
|
+
|
102
|
+
it 'should handle comparison to nil' do
|
103
|
+
a = SubmissionInfo.from_xml submitted_node
|
104
|
+
(a == nil).should be false
|
105
|
+
end
|
106
|
+
|
107
|
+
end
|
108
|
+
|
109
|
+
end
|
110
|
+
|
111
|
+
end
|
@@ -0,0 +1,157 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'nokogiri'
|
3
|
+
|
4
|
+
module Mws::Apis::Feeds
|
5
|
+
|
6
|
+
class SubmissionResult
|
7
|
+
attr_reader :responses
|
8
|
+
end
|
9
|
+
|
10
|
+
describe SubmissionResult do
|
11
|
+
let(:success_node) do
|
12
|
+
Nokogiri::XML::Builder.new do
|
13
|
+
Message {
|
14
|
+
MessageID 1
|
15
|
+
ProcessingReport {
|
16
|
+
DocumentTransactionID 5868304010
|
17
|
+
StatusCode 'Complete'
|
18
|
+
ProcessingSummary {
|
19
|
+
MessagesProcessed 1
|
20
|
+
MessagesSuccessful 1
|
21
|
+
MessagesWithError 0
|
22
|
+
MessagesWithWarning 0
|
23
|
+
}
|
24
|
+
}
|
25
|
+
}
|
26
|
+
end.doc.root
|
27
|
+
end
|
28
|
+
let(:error_node) do
|
29
|
+
Nokogiri::XML::Builder.new do
|
30
|
+
Message {
|
31
|
+
MessageID 1
|
32
|
+
ProcessingReport {
|
33
|
+
DocumentTransactionID 5868304010
|
34
|
+
StatusCode 'Complete'
|
35
|
+
ProcessingSummary {
|
36
|
+
MessagesProcessed 2
|
37
|
+
MessagesSuccessful 0
|
38
|
+
MessagesWithError 2
|
39
|
+
MessagesWithWarning 1
|
40
|
+
}
|
41
|
+
Result {
|
42
|
+
MessageID 1
|
43
|
+
ResultCode 'Error'
|
44
|
+
ResultMessageCode 8560
|
45
|
+
ResultDescription 'Result description 1'
|
46
|
+
AdditionalInfo {
|
47
|
+
SKU '3455449'
|
48
|
+
}
|
49
|
+
}
|
50
|
+
Result {
|
51
|
+
MessageID 2
|
52
|
+
ResultCode 'Error'
|
53
|
+
ResultMessageCode 5000
|
54
|
+
ResultDescription "Result description 2"
|
55
|
+
AdditionalInfo {
|
56
|
+
SKU '8744969'
|
57
|
+
}
|
58
|
+
}
|
59
|
+
Result {
|
60
|
+
MessageID 3
|
61
|
+
ResultCode 'Warning'
|
62
|
+
ResultMessageCode 5001
|
63
|
+
ResultDescription "Result description 3"
|
64
|
+
AdditionalInfo {
|
65
|
+
SKU '7844970'
|
66
|
+
}
|
67
|
+
}
|
68
|
+
}
|
69
|
+
}
|
70
|
+
end.doc.root
|
71
|
+
end
|
72
|
+
|
73
|
+
it 'should not allow instance creation via new' do
|
74
|
+
expect { SubmissionResult.new }.to raise_error NoMethodError
|
75
|
+
end
|
76
|
+
|
77
|
+
describe '.from_xml' do
|
78
|
+
|
79
|
+
it 'should be able to be constructed from valid success xml' do
|
80
|
+
result = SubmissionResult.from_xml success_node
|
81
|
+
result.transaction_id.should == '5868304010'
|
82
|
+
result.status.should == SubmissionResult::Status.COMPLETE.sym
|
83
|
+
result.messages_processed.should == 1
|
84
|
+
result.count_for(:success).should == 1
|
85
|
+
result.count_for(:error).should == 0
|
86
|
+
result.count_for(:warning).should == 0
|
87
|
+
result.responses.should be_empty
|
88
|
+
end
|
89
|
+
|
90
|
+
it 'should be able to be constructed from valid error xml' do
|
91
|
+
result = SubmissionResult.from_xml error_node
|
92
|
+
result.transaction_id.should == '5868304010'
|
93
|
+
result.status.should == SubmissionResult::Status.COMPLETE.sym
|
94
|
+
result.messages_processed.should == 2
|
95
|
+
result.count_for(:success).should == 0
|
96
|
+
result.count_for(:error).should == 2
|
97
|
+
result.count_for(:warning).should == 1
|
98
|
+
result.responses.size.should == 3
|
99
|
+
|
100
|
+
response = result.response_for 1
|
101
|
+
response.type.should == SubmissionResult::Response::Type.ERROR.sym
|
102
|
+
response.code.should == 8560
|
103
|
+
response.description == 'Result description 1'
|
104
|
+
response.additional_info.should == {
|
105
|
+
sku: '3455449'
|
106
|
+
}
|
107
|
+
|
108
|
+
|
109
|
+
response = result.response_for 2
|
110
|
+
response.type.should == SubmissionResult::Response::Type.ERROR.sym
|
111
|
+
response.code.should == 5000
|
112
|
+
response.description == 'Result description 2'
|
113
|
+
response.additional_info.should == {
|
114
|
+
sku: '8744969'
|
115
|
+
}
|
116
|
+
|
117
|
+
response = result.response_for 3
|
118
|
+
response.type.should == SubmissionResult::Response::Type.WARNING.sym
|
119
|
+
response.code.should == 5001
|
120
|
+
response.description == 'Result description 3'
|
121
|
+
response.additional_info.should == {
|
122
|
+
sku: '7844970'
|
123
|
+
}
|
124
|
+
end
|
125
|
+
|
126
|
+
end
|
127
|
+
|
128
|
+
context '#==' do
|
129
|
+
|
130
|
+
it 'should be reflexive' do
|
131
|
+
a = SubmissionResult.from_xml success_node
|
132
|
+
(a == a).should be true
|
133
|
+
end
|
134
|
+
|
135
|
+
it 'should be symmetric' do
|
136
|
+
a = SubmissionResult.from_xml success_node
|
137
|
+
b = SubmissionResult.from_xml success_node
|
138
|
+
(a == b).should == (b == a)
|
139
|
+
end
|
140
|
+
|
141
|
+
it 'should be transitive' do
|
142
|
+
a = SubmissionResult.from_xml success_node
|
143
|
+
b = SubmissionResult.from_xml success_node
|
144
|
+
c = SubmissionResult.from_xml success_node
|
145
|
+
(a == c).should == (a == b && b == c)
|
146
|
+
end
|
147
|
+
|
148
|
+
it 'should handle comparison to nil' do
|
149
|
+
a = SubmissionResult.from_xml success_node
|
150
|
+
(a == nil).should be false
|
151
|
+
end
|
152
|
+
|
153
|
+
end
|
154
|
+
|
155
|
+
end
|
156
|
+
|
157
|
+
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'nokogiri'
|
3
|
+
|
4
|
+
module Mws::Apis::Feeds
|
5
|
+
|
6
|
+
describe Transaction do
|
7
|
+
|
8
|
+
let(:submission_info) do
|
9
|
+
SubmissionInfo.from_xml(
|
10
|
+
Nokogiri::XML::Builder.new do
|
11
|
+
FeedSubmissionInfo {
|
12
|
+
FeedSubmissionId 5868304010
|
13
|
+
FeedType '_POST_PRODUCT_DATA_'
|
14
|
+
SubmittedDate '2012-10-16T21:19:08+00:00'
|
15
|
+
FeedProcessingStatus '_SUBMITTED_'
|
16
|
+
}
|
17
|
+
end.doc.root
|
18
|
+
)
|
19
|
+
end
|
20
|
+
|
21
|
+
describe '.new' do
|
22
|
+
|
23
|
+
it 'should be able to create a transaction with no items' do
|
24
|
+
transaction = Transaction.new submission_info
|
25
|
+
transaction.id.should == "5868304010"
|
26
|
+
transaction.status.should == SubmissionInfo::Status.SUBMITTED.sym
|
27
|
+
transaction.type.should == Feed::Type.PRODUCT.sym
|
28
|
+
transaction.submitted.should == Time.parse('2012-10-16T21:19:08+00:00')
|
29
|
+
transaction.items.should be_empty
|
30
|
+
end
|
31
|
+
|
32
|
+
it 'should be able to create a transaction with items' do
|
33
|
+
transaction = Transaction.new submission_info do
|
34
|
+
item 1, '12345678', :update
|
35
|
+
item 2, '87654321', :update, :main
|
36
|
+
item 3, '87654321', :delete, :other
|
37
|
+
end
|
38
|
+
|
39
|
+
transaction.items.length.should == 3
|
40
|
+
|
41
|
+
item = transaction.items[0]
|
42
|
+
item.id.should == 1
|
43
|
+
item.sku.should == '12345678'
|
44
|
+
item.operation.should == :update
|
45
|
+
item.qualifier.should be_nil
|
46
|
+
|
47
|
+
item = transaction.items[1]
|
48
|
+
item.id.should == 2
|
49
|
+
item.sku.should == '87654321'
|
50
|
+
item.operation.should == :update
|
51
|
+
item.qualifier.should == :main
|
52
|
+
|
53
|
+
item = transaction.items[2]
|
54
|
+
item.id.should == 3
|
55
|
+
item.sku.should == '87654321'
|
56
|
+
item.operation.should == :delete
|
57
|
+
item.qualifier.should == :other
|
58
|
+
end
|
59
|
+
|
60
|
+
end
|
61
|
+
|
62
|
+
end
|
63
|
+
|
64
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
module Mws::Apis::Feeds
|
4
|
+
|
5
|
+
describe Weight do
|
6
|
+
|
7
|
+
context '.new' do
|
8
|
+
|
9
|
+
it 'should default to pounds' do
|
10
|
+
weight = Weight.new 40
|
11
|
+
weight.amount.should == 40
|
12
|
+
weight.unit.should == :pounds
|
13
|
+
end
|
14
|
+
|
15
|
+
it 'should accept a valid unit override' do
|
16
|
+
weight = Weight.new 0, :ounces
|
17
|
+
weight.amount.should == 0
|
18
|
+
weight.unit.should == :ounces
|
19
|
+
end
|
20
|
+
|
21
|
+
it 'should validate the unit override' do
|
22
|
+
expect {
|
23
|
+
Weight.new 50, :cent
|
24
|
+
}.to raise_error Mws::Errors::ValidationError, "Invalid unit of measure 'cent'"
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
28
|
+
|
29
|
+
context '#to_xml' do
|
30
|
+
|
31
|
+
it 'should properly serialize to XML' do
|
32
|
+
weight = Weight.new 25, :grams
|
33
|
+
expected = Nokogiri::XML::Builder.new do
|
34
|
+
Weight 25, unitOfMeasure: 'GR'
|
35
|
+
end.doc.root.to_xml
|
36
|
+
weight.to_xml.should == expected
|
37
|
+
end
|
38
|
+
|
39
|
+
end
|
40
|
+
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
@@ -0,0 +1,331 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'nokogiri'
|
3
|
+
|
4
|
+
module Mws
|
5
|
+
|
6
|
+
class Connection
|
7
|
+
attr_reader :scheme, :host, :merchant, :access, :secret
|
8
|
+
public :request, :response_for, :parse
|
9
|
+
end
|
10
|
+
|
11
|
+
describe Connection do
|
12
|
+
|
13
|
+
let(:defaults) {
|
14
|
+
{
|
15
|
+
merchant: 'GSWCJ4UBA31UTJ',
|
16
|
+
access: 'AYQAKIAJSCWMLYXAQ6K3',
|
17
|
+
secret: 'Ubzq/NskSrW4m5ncq53kddzBej7O7IE5Yx9drGrX'
|
18
|
+
}
|
19
|
+
}
|
20
|
+
|
21
|
+
let(:connection) {
|
22
|
+
Mws.connect(defaults)
|
23
|
+
}
|
24
|
+
|
25
|
+
context '.new' do
|
26
|
+
|
27
|
+
it 'should default scheme to https' do
|
28
|
+
connection.scheme.should == 'https'
|
29
|
+
end
|
30
|
+
|
31
|
+
it 'should accept a custom scheme' do
|
32
|
+
Connection.new(defaults.merge(scheme: 'http')).scheme.should == 'http'
|
33
|
+
end
|
34
|
+
|
35
|
+
it 'should default host to mws.amazonservices.com' do
|
36
|
+
connection.host.should == 'mws.amazonservices.com'
|
37
|
+
end
|
38
|
+
|
39
|
+
it 'should accept a custom host' do
|
40
|
+
Connection.new(defaults.merge(host: 'mws.amazonservices.uk')).host.should == 'mws.amazonservices.uk'
|
41
|
+
end
|
42
|
+
|
43
|
+
it 'should require a merchant identifier' do
|
44
|
+
expect {
|
45
|
+
Connection.new(
|
46
|
+
access: defaults[:access],
|
47
|
+
secret: defaults[:secret]
|
48
|
+
)
|
49
|
+
}.to raise_error Mws::Errors::ValidationError, 'A merchant identifier must be specified.'
|
50
|
+
end
|
51
|
+
|
52
|
+
it 'should accept a merchant identifier' do
|
53
|
+
connection.merchant.should == 'GSWCJ4UBA31UTJ'
|
54
|
+
end
|
55
|
+
|
56
|
+
it 'should require an access key' do
|
57
|
+
expect {
|
58
|
+
Connection.new(
|
59
|
+
merchant: defaults[:merchant],
|
60
|
+
secret: defaults[:secret]
|
61
|
+
)
|
62
|
+
}.to raise_error Mws::Errors::ValidationError, 'An access key must be specified.'
|
63
|
+
end
|
64
|
+
|
65
|
+
it 'should accept an access key' do
|
66
|
+
connection.access.should == 'AYQAKIAJSCWMLYXAQ6K3'
|
67
|
+
end
|
68
|
+
|
69
|
+
it 'should require a secret key' do
|
70
|
+
expect {
|
71
|
+
Connection.new(
|
72
|
+
merchant: defaults[:merchant],
|
73
|
+
access: defaults[:access]
|
74
|
+
)
|
75
|
+
}.to raise_error Mws::Errors::ValidationError, 'A secret key must be specified.'
|
76
|
+
end
|
77
|
+
|
78
|
+
it 'should accept a secret key' do
|
79
|
+
connection.secret.should == 'Ubzq/NskSrW4m5ncq53kddzBej7O7IE5Yx9drGrX'
|
80
|
+
end
|
81
|
+
|
82
|
+
end
|
83
|
+
|
84
|
+
context '#get' do
|
85
|
+
|
86
|
+
it 'should appropriately delegate to #request' do
|
87
|
+
connection.should_receive(:request).with(:get, '/foo', { market: 'ATVPDKIKX0DER' }, nil, { version: 1 })
|
88
|
+
connection.get('/foo', { market: 'ATVPDKIKX0DER' }, { version: 1 })
|
89
|
+
end
|
90
|
+
|
91
|
+
end
|
92
|
+
|
93
|
+
context '#post' do
|
94
|
+
|
95
|
+
it 'should appropriately delegate to #request' do
|
96
|
+
connection.should_receive(:request).with(:post, '/foo', { market: 'ATVPDKIKX0DER' }, 'test_body', { version: 1 })
|
97
|
+
connection.post('/foo', { market: 'ATVPDKIKX0DER' }, 'test_body', { version: 1 })
|
98
|
+
end
|
99
|
+
|
100
|
+
end
|
101
|
+
|
102
|
+
context '#request' do
|
103
|
+
|
104
|
+
it 'should construct a query, signer and make the request' do
|
105
|
+
Query.should_receive(:new).with(
|
106
|
+
action: nil,
|
107
|
+
version: nil,
|
108
|
+
merchant: 'GSWCJ4UBA31UTJ',
|
109
|
+
access: 'AYQAKIAJSCWMLYXAQ6K3',
|
110
|
+
list_pattern: nil
|
111
|
+
).and_return('the_query')
|
112
|
+
signer = double('signer')
|
113
|
+
Signer.should_receive(:new).with(
|
114
|
+
method: :get,
|
115
|
+
host: 'mws.amazonservices.com',
|
116
|
+
path: '/foo',
|
117
|
+
secret: 'Ubzq/NskSrW4m5ncq53kddzBej7O7IE5Yx9drGrX'
|
118
|
+
).and_return(signer)
|
119
|
+
signer.should_receive(:sign).with('the_query').and_return('the_signed_query')
|
120
|
+
connection.should_receive(:response_for).with(:get, '/foo', 'the_signed_query', nil).and_return('the_response')
|
121
|
+
connection.should_receive(:parse).with('the_response', {})
|
122
|
+
connection.request(:get, '/foo', {}, nil, {})
|
123
|
+
end
|
124
|
+
|
125
|
+
it 'should merge additional request parameters into the query' do
|
126
|
+
connection = Connection.new(
|
127
|
+
merchant: 'GSWCJ4UBA31UTJ',
|
128
|
+
access: 'AYQAKIAJSCWMLYXAQ6K3',
|
129
|
+
secret: 'Ubzq/NskSrW4m5ncq53kddzBej7O7IE5Yx9drGrX'
|
130
|
+
)
|
131
|
+
Query.should_receive(:new).with(
|
132
|
+
action: nil,
|
133
|
+
version: nil,
|
134
|
+
merchant: 'GSWCJ4UBA31UTJ',
|
135
|
+
access: 'AYQAKIAJSCWMLYXAQ6K3',
|
136
|
+
list_pattern: nil,
|
137
|
+
foo: 'bar',
|
138
|
+
baz: 'quk'
|
139
|
+
).and_return('the_query')
|
140
|
+
signer = double('signer')
|
141
|
+
Signer.should_receive(:new).with(
|
142
|
+
method: :get,
|
143
|
+
host: 'mws.amazonservices.com',
|
144
|
+
path: '/foo',
|
145
|
+
secret: 'Ubzq/NskSrW4m5ncq53kddzBej7O7IE5Yx9drGrX'
|
146
|
+
).and_return(signer)
|
147
|
+
signer.should_receive(:sign).with('the_query').and_return('the_signed_query')
|
148
|
+
connection.should_receive(:response_for).with(:get, '/foo', 'the_signed_query', nil).and_return('the_response')
|
149
|
+
connection.should_receive(:parse).with('the_response', {})
|
150
|
+
connection.request(:get, '/foo', { foo: 'bar', baz: 'quk' }, nil, {})
|
151
|
+
end
|
152
|
+
|
153
|
+
it 'should accept overrides to action, version and list_pattern' do
|
154
|
+
Query.should_receive(:new).with(
|
155
|
+
action: 'SubmitFeed',
|
156
|
+
version: '2009-01-01',
|
157
|
+
merchant: 'GSWCJ4UBA31UTJ',
|
158
|
+
access: 'AYQAKIAJSCWMLYXAQ6K3',
|
159
|
+
list_pattern: 'a_list_pattern'
|
160
|
+
).and_return('the_query')
|
161
|
+
signer = double('signer')
|
162
|
+
Signer.should_receive(:new).with(
|
163
|
+
method: :get,
|
164
|
+
host: 'mws.amazonservices.com',
|
165
|
+
path: '/foo',
|
166
|
+
secret: 'Ubzq/NskSrW4m5ncq53kddzBej7O7IE5Yx9drGrX'
|
167
|
+
).and_return(signer)
|
168
|
+
signer.should_receive(:sign).with('the_query').and_return('the_signed_query')
|
169
|
+
connection.should_receive(:response_for).with(:get, '/foo', 'the_signed_query', nil).and_return('the_response')
|
170
|
+
connection.should_receive(:parse).with('the_response', { action: 'SubmitFeed', version: '2009-01-01' })
|
171
|
+
connection.request(:get, '/foo', {}, nil, { action: 'SubmitFeed', version: '2009-01-01', list_pattern: 'a_list_pattern' })
|
172
|
+
end
|
173
|
+
|
174
|
+
end
|
175
|
+
|
176
|
+
context '#parse' do
|
177
|
+
|
178
|
+
it 'should parse error messages correctly' do
|
179
|
+
body = <<-XML
|
180
|
+
<?xml version="1.0"?>
|
181
|
+
<ErrorResponse xmlns="https://mws.amazonservices.com/Orders/2011-01-01">
|
182
|
+
<Error>
|
183
|
+
<Type>Sender</Type>
|
184
|
+
<Code>InvalidParameterValue</Code>
|
185
|
+
<Message>CreatedAfter or LastUpdatedAfter must be specified</Message>
|
186
|
+
</Error>
|
187
|
+
<RequestId>fb03503e-97e3-4ed1-88e9-d93f4d2111c1</RequestId>
|
188
|
+
</ErrorResponse>
|
189
|
+
XML
|
190
|
+
expect { connection.parse(body, {}) }.to raise_error do | error |
|
191
|
+
error.should be_a Errors::ServerError
|
192
|
+
error.type.should == 'Sender'
|
193
|
+
error.code.should == 'InvalidParameterValue'
|
194
|
+
error.message.should == 'CreatedAfter or LastUpdatedAfter must be specified'
|
195
|
+
error.details.should == 'None'
|
196
|
+
end
|
197
|
+
end
|
198
|
+
|
199
|
+
it 'should parse result based on custom action' do
|
200
|
+
body = <<-XML
|
201
|
+
<?xml version="1.0"?>
|
202
|
+
<ListOrdersResponse xmlns="https://mws.amazonservices.com/Orders/2011-01-01">
|
203
|
+
<ListOrdersResult>
|
204
|
+
<Orders/>
|
205
|
+
<CreatedBefore>2012-11-19T20:54:33Z</CreatedBefore>
|
206
|
+
</ListOrdersResult>
|
207
|
+
<ResponseMetadata>
|
208
|
+
<RequestId>931137cb-add7-4232-ac08-b701435c8447</RequestId>
|
209
|
+
</ResponseMetadata>
|
210
|
+
</ListOrdersResponse>
|
211
|
+
XML
|
212
|
+
result = connection.parse(body, action: 'ListOrders').name.should == 'ListOrdersResult'
|
213
|
+
end
|
214
|
+
|
215
|
+
it 'shoudl parse result base on custom xpath' do
|
216
|
+
body = <<-XML
|
217
|
+
<?xml version="1.0"?>
|
218
|
+
<ListOrdersResponse xmlns="https://mws.amazonservices.com/Orders/2011-01-01">
|
219
|
+
<ListOrdersResult>
|
220
|
+
<Orders/>
|
221
|
+
<CreatedBefore>2012-11-19T20:54:33Z</CreatedBefore>
|
222
|
+
</ListOrdersResult>
|
223
|
+
<ResponseMetadata>
|
224
|
+
<RequestId>931137cb-add7-4232-ac08-b701435c8447</RequestId>
|
225
|
+
</ResponseMetadata>
|
226
|
+
</ListOrdersResponse>
|
227
|
+
XML
|
228
|
+
result = connection.parse(body, xpath: '/ListOrdersResponse/ListOrdersResult').name.should == 'ListOrdersResult'
|
229
|
+
end
|
230
|
+
|
231
|
+
end
|
232
|
+
|
233
|
+
context '#response_for' do
|
234
|
+
|
235
|
+
it 'should properly handle a secure get request' do
|
236
|
+
response = double(:response)
|
237
|
+
response.should_receive(:body).exactly(3).times.and_return('response_body')
|
238
|
+
http = double(:http)
|
239
|
+
http.should_receive(:request) do | req |
|
240
|
+
req.should be_a Net::HTTP::Get
|
241
|
+
req.method.should == 'GET'
|
242
|
+
req.path.should == '/?foo=bar'
|
243
|
+
req['User-Agent'].should == 'MWS Connect/0.0.1 (Language=Ruby)'
|
244
|
+
req['Accept-Encoding'].should == 'text/xml'
|
245
|
+
response
|
246
|
+
end
|
247
|
+
Net::HTTP.should_receive(:start).with('mws.amazonservices.com', 443, use_ssl: true).and_yield(http)
|
248
|
+
connection.response_for(:get, '/', 'foo=bar', nil).should == 'response_body'
|
249
|
+
end
|
250
|
+
|
251
|
+
it 'should properly handle an insecure get request' do
|
252
|
+
connection = Connection.new(defaults.merge(scheme: 'http'))
|
253
|
+
response = double(:response)
|
254
|
+
response.should_receive(:body).exactly(3).times.and_return('response_body')
|
255
|
+
http = double(:http)
|
256
|
+
http.should_receive(:request) do | req |
|
257
|
+
req.should be_a Net::HTTP::Get
|
258
|
+
req.method.should == 'GET'
|
259
|
+
req.path.should == '/?foo=bar'
|
260
|
+
req['User-Agent'].should == 'MWS Connect/0.0.1 (Language=Ruby)'
|
261
|
+
req['Accept-Encoding'].should == 'text/xml'
|
262
|
+
response
|
263
|
+
end
|
264
|
+
Net::HTTP.should_receive(:start).with('mws.amazonservices.com', 80, use_ssl: false).and_yield(http)
|
265
|
+
connection.response_for(:get, '/', 'foo=bar', nil).should == 'response_body'
|
266
|
+
end
|
267
|
+
|
268
|
+
it 'should properly handle requests with transport level errors' do
|
269
|
+
response = double(:response)
|
270
|
+
response.should_receive(:body).and_return(nil)
|
271
|
+
response.should_receive(:code).and_return(500)
|
272
|
+
response.should_receive(:msg).and_return('Internal Server Error')
|
273
|
+
http = double(:http)
|
274
|
+
http.should_receive(:request) do | req |
|
275
|
+
req.should be_a Net::HTTP::Get
|
276
|
+
req.method.should == 'GET'
|
277
|
+
req.path.should == '/?foo=bar'
|
278
|
+
req['User-Agent'].should == 'MWS Connect/0.0.1 (Language=Ruby)'
|
279
|
+
req['Accept-Encoding'].should == 'text/xml'
|
280
|
+
response
|
281
|
+
end
|
282
|
+
Net::HTTP.should_receive(:start).with('mws.amazonservices.com', 443, use_ssl: true).and_yield(http)
|
283
|
+
expect { connection.response_for(:get, '/', 'foo=bar', nil) }.to raise_error do | error |
|
284
|
+
error.should be_a Errors::ServerError
|
285
|
+
error.type.should == 'Server'
|
286
|
+
error.code.should == 500
|
287
|
+
error.message.should == 'Internal Server Error'
|
288
|
+
error.detail.should == 'None'
|
289
|
+
end
|
290
|
+
end
|
291
|
+
|
292
|
+
it 'should properly handle a post without a body' do
|
293
|
+
response = double(:response)
|
294
|
+
response.should_receive(:body).exactly(3).times.and_return('response_body')
|
295
|
+
http = double(:http)
|
296
|
+
http.should_receive(:request) do | req |
|
297
|
+
req.should be_a Net::HTTP::Post
|
298
|
+
req.method.should == 'POST'
|
299
|
+
req.path.should == '/?foo=bar'
|
300
|
+
req['User-Agent'].should == 'MWS Connect/0.0.1 (Language=Ruby)'
|
301
|
+
req['Accept-Encoding'].should == 'text/xml'
|
302
|
+
response
|
303
|
+
end
|
304
|
+
Net::HTTP.should_receive(:start).with('mws.amazonservices.com', 443, use_ssl: true).and_yield(http)
|
305
|
+
connection.response_for(:post, '/', 'foo=bar', nil).should == 'response_body'
|
306
|
+
end
|
307
|
+
|
308
|
+
it 'should properly handle a post with a body' do
|
309
|
+
response = double(:response)
|
310
|
+
response.should_receive(:body).exactly(3).times.and_return('response_body')
|
311
|
+
http = double(:http)
|
312
|
+
http.should_receive(:request) do | req |
|
313
|
+
req.should be_a Net::HTTP::Post
|
314
|
+
req.method.should == 'POST'
|
315
|
+
req.path.should == '/?foo=bar'
|
316
|
+
req.content_type.should == 'text/xml'
|
317
|
+
req.body.should == 'request_body'
|
318
|
+
req['Content-MD5'] = Digest::MD5.base64digest('request_body').strip
|
319
|
+
req['User-Agent'].should == 'MWS Connect/0.0.1 (Language=Ruby)'
|
320
|
+
req['Accept-Encoding'].should == 'text/xml'
|
321
|
+
response
|
322
|
+
end
|
323
|
+
Net::HTTP.should_receive(:start).with('mws.amazonservices.com', 443, use_ssl: true).and_yield(http)
|
324
|
+
connection.response_for(:post, '/', 'foo=bar', 'request_body').should == 'response_body'
|
325
|
+
end
|
326
|
+
|
327
|
+
end
|
328
|
+
|
329
|
+
end
|
330
|
+
|
331
|
+
end
|