mws-connect 0.0.1
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.
- 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
|