amazon_flex_pay 0.9.14 → 0.10.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.
@@ -1,23 +1,9 @@
1
1
  module AmazonFlexPay
2
- class << self
3
- # Returns a signature for the given URL and parameters.
4
- def signature(endpoint, params)
5
- uri = URI.parse(endpoint)
6
-
7
- signable_string = [
8
- 'GET',
9
- uri.host,
10
- uri.path,
11
- query_string(params)
12
- ].join("\n")
13
-
14
- Base64.encode64(OpenSSL::HMAC.digest(OpenSSL::Digest::SHA256.new, AmazonFlexPay.secret_key, signable_string)).strip
15
- end
16
-
2
+ module Util
17
3
  # Flattens a possibly-nested hash into a query string for Amazon.
18
4
  # With Amazon, nested hashes are flattened with a period, as follows:
19
5
  #
20
- # AmazonFlexPay.query_string(:foo => {:hello => 'world'})
6
+ # AmazonFlexPay::Util.query_string(:foo => {:hello => 'world'})
21
7
  # => "foo.hello=world"
22
8
  #
23
9
  def query_string(params, prefix = nil) #:nodoc:
@@ -38,5 +24,7 @@ module AmazonFlexPay
38
24
  # note that URI.escape(' ') => '%20', and CGI.escape(' ') => '+'
39
25
  URI.escape(value.to_s, UNSAFE)
40
26
  end
27
+
28
+ extend self
41
29
  end
42
30
  end
@@ -0,0 +1,67 @@
1
+ require_relative '../../test_helper'
2
+
3
+ class AmazonFlexPay::API::BaseRequestTest < AmazonFlexPay::Test
4
+
5
+ class TestRequest < AmazonFlexPay::API::BaseRequest
6
+ attribute :foo
7
+ attribute :amount, :type => :amount
8
+ attribute :stuffs, :collection => :amount
9
+ attribute :method, :enumeration => :payment_method
10
+ end
11
+
12
+ should "respond with data structures even when models are empty" do
13
+ tr = TestRequest.new
14
+ assert tr.stuffs.is_a?(Array)
15
+ assert tr.amount.respond_to?(:value)
16
+ assert !tr.to_hash.has_key?('Stuffs')
17
+ assert !tr.to_hash.has_key?('Amount')
18
+ end
19
+
20
+ should "hash api requests" do
21
+ request = TestRequest.new(:foo => 'bar', :amount => {:value => '3.14', :currency_code => 'USD'})
22
+ hash = request.to_hash
23
+
24
+ # simple attributes
25
+ assert_equal 'bar', hash['Foo']
26
+
27
+ # complex attributes
28
+ assert_equal '3.14', hash['Amount']['Value']
29
+ assert_equal 'USD', hash['Amount']['CurrencyCode']
30
+
31
+ # standard additions
32
+ assert_equal 'TestRequest', hash['Action']
33
+ assert_equal '2011-09-20', hash['Version']
34
+ end
35
+
36
+ should "parameterize api requests" do
37
+ Time.stubs(:now).returns(Time.parse('Jan 1 2011')) # so the signature remains constant
38
+
39
+ request = TestRequest.new(:foo => 'bar', :amount => {:value => '3.14', :currency_code => 'USD'})
40
+ param = request.to_param
41
+
42
+ {
43
+ 'Foo' => 'bar',
44
+ 'AWSAccessKeyId' => 'foo',
45
+ 'SignatureVersion' => 2,
46
+ 'SignatureMethod' => 'HmacSHA256',
47
+ 'Signature' => 'WVrkmK7qt%2FT%2BgtHWcdzqtkLRH8c06l%2FmPv3ZfxyvNyg%3D'
48
+ }.each do |key, value|
49
+ assert param.match(/#{key}=#{value}/), "#{param} should contain #{key}=#{value}"
50
+ end
51
+ end
52
+
53
+ should "not allow unknown values for enumerated attributes" do
54
+ assert_raises ArgumentError do TestRequest.new(:method => 'UNKOWN') end
55
+ end
56
+
57
+ should "allow value sets for enumerated attributes" do
58
+ assert_nothing_raised do
59
+ TestRequest.new(:method => ['CC', 'ACH'])
60
+ end
61
+ end
62
+
63
+ should "convert value sets into comma-separated lists" do
64
+ assert_equal 'a,b', TestRequest.new(:foo => ['a', 'b']).to_hash['Foo']
65
+ end
66
+
67
+ end
@@ -0,0 +1,418 @@
1
+ require_relative '../test_helper'
2
+
3
+ class AmazonFlexPay::APITest < AmazonFlexPay::Test
4
+ include ResponseSamples
5
+
6
+ ## Cancel
7
+
8
+ should "construct a Cancel request" do
9
+ AmazonFlexPay.expects(:submit).with do |request|
10
+ assert request.is_a? AmazonFlexPay::API::Cancel
11
+ assert_equal 'txid', request.transaction_id
12
+ assert_equal 'test', request.description
13
+ end
14
+ AmazonFlexPay.cancel('txid', {:description => 'test'})
15
+ end
16
+
17
+ should "parse a Cancel response" do
18
+ response = nil
19
+ assert_nothing_raised do
20
+ response = AmazonFlexPay::API::Cancel::Response.from_xml(cancel_response)
21
+ end
22
+ assert response.request_id
23
+ assert response.transaction_id
24
+ assert response.transaction_status
25
+ end
26
+
27
+ ## CancelToken
28
+
29
+ should "construct a CancelToken request" do
30
+ AmazonFlexPay.expects(:submit).with do |request|
31
+ assert request.is_a? AmazonFlexPay::API::CancelToken
32
+ assert_equal 'token', request.token_id
33
+ assert_equal 'test', request.reason_text
34
+ end
35
+ AmazonFlexPay.cancel_token('token', {:reason_text => 'test'})
36
+ end
37
+
38
+ should "parse a CancelToken response" do
39
+ response = nil
40
+ assert_nothing_raised do
41
+ response = AmazonFlexPay::API::CancelToken::Response.from_xml(cancel_token_response)
42
+ end
43
+ assert response.request_id
44
+ end
45
+
46
+ ## GetAccountActivity
47
+
48
+ should "construct a GetAccountActivity request" do
49
+ since = Time.now - 60*60*24 # 1.day
50
+ to = Time.now
51
+ AmazonFlexPay.expects(:submit).with do |request|
52
+ assert request.is_a? AmazonFlexPay::API::GetAccountActivity
53
+ assert_equal since, request.start_date
54
+ assert_equal to, request.end_date
55
+ end
56
+ AmazonFlexPay.get_account_activity(since, to)
57
+ end
58
+
59
+ should "parse a GetAccountActivity response" do
60
+ response = nil
61
+ assert_nothing_raised do
62
+ response = AmazonFlexPay::API::GetAccountActivity::Response.from_xml(get_account_activity_response)
63
+ end
64
+ assert response.request_id
65
+ assert_equal 5, response.transactions.count
66
+ end
67
+
68
+ ## GetAccountBalance
69
+
70
+ should "construct a GetAccountBalance request" do
71
+ AmazonFlexPay.expects(:submit).with do |request|
72
+ assert request.is_a? AmazonFlexPay::API::GetAccountBalance
73
+ end
74
+ AmazonFlexPay.get_account_balance
75
+ end
76
+
77
+ should "parse a GetAccountBalance response" do
78
+ response = nil
79
+ assert_nothing_raised do
80
+ response = AmazonFlexPay::API::GetAccountBalance::Response.from_xml(get_account_balance_response)
81
+ end
82
+ assert response.request_id
83
+ assert_equal '7.400000', response.account_balance.total_balance.value
84
+ end
85
+
86
+ ## GetRecipientVerificationStatus
87
+
88
+ should "construct a GetRecipientVerificationStatus request" do
89
+ AmazonFlexPay.expects(:submit).with do |request|
90
+ assert request.is_a? AmazonFlexPay::API::GetRecipientVerificationStatus
91
+ assert_equal 'token', request.recipient_token_id
92
+ end
93
+ AmazonFlexPay.get_recipient_verification_status('token')
94
+ end
95
+
96
+ should "parse a GetRecipientVerificationStatus response" do
97
+ response = nil
98
+ assert_nothing_raised do
99
+ response = AmazonFlexPay::API::GetRecipientVerificationStatus::Response.from_xml(get_recipient_verification_status_response)
100
+ end
101
+ assert response.request_id
102
+ assert response.recipient_verification_status
103
+ end
104
+
105
+ ## GetTokenByCaller
106
+
107
+ should "construct a GetTokenByCaller request by reference" do
108
+ AmazonFlexPay.expects(:submit).with do |request|
109
+ assert request.is_a? AmazonFlexPay::API::GetTokenByCaller
110
+ assert_equal 'reference', request.caller_reference
111
+ end
112
+ AmazonFlexPay.get_token_by_caller_reference('reference')
113
+ end
114
+
115
+ should "construct a GetTokenByCaller request by token id" do
116
+ AmazonFlexPay.expects(:submit).with do |request|
117
+ assert request.is_a? AmazonFlexPay::API::GetTokenByCaller
118
+ assert_equal 'token', request.token_id
119
+ end
120
+ AmazonFlexPay.get_token_by_id('token')
121
+ end
122
+
123
+ should "parse a GetTokenByCaller response" do
124
+ response = nil
125
+ assert_nothing_raised do
126
+ response = AmazonFlexPay::API::GetTokenByCaller::Response.from_xml(get_token_by_caller_response)
127
+ end
128
+ assert response.request_id
129
+ assert response.token.token_id
130
+ assert response.token.token_status
131
+ end
132
+
133
+ ## GetTokenUsage
134
+
135
+ should "construct a GetTokenUsage request" do
136
+ AmazonFlexPay.expects(:submit).with do |request|
137
+ assert request.is_a? AmazonFlexPay::API::GetTokenUsage
138
+ assert_equal 'token', request.token_id
139
+ end
140
+ AmazonFlexPay.get_token_usage('token')
141
+ end
142
+
143
+ should "parse a GetTokenUsage response" do
144
+ response = nil
145
+ assert_nothing_raised do
146
+ response = AmazonFlexPay::API::GetTokenUsage::Response.from_xml(get_token_usage_response)
147
+ end
148
+ assert_equal 2, response.token_usage_limits.count
149
+ assert_equal '10.000000', response.token_usage_limits.first.amount.value
150
+ assert_equal '1', response.token_usage_limits.last.count
151
+ end
152
+
153
+ ## GetTokens
154
+
155
+ should "construct a GetTokens request" do
156
+ AmazonFlexPay.expects(:submit).with do |request|
157
+ assert request.is_a? AmazonFlexPay::API::GetTokens
158
+ end
159
+ AmazonFlexPay.get_tokens
160
+ end
161
+
162
+ should "parse a GetTokens response" do
163
+ response = nil
164
+ assert_nothing_raised do
165
+ response = AmazonFlexPay::API::GetTokens::Response.from_xml(get_tokens_response)
166
+ end
167
+ assert_equal 1, response.tokens.count
168
+ end
169
+
170
+ ## GetTransaction
171
+
172
+ should "construct a GetTransaction request" do
173
+ AmazonFlexPay.expects(:submit).with do |request|
174
+ assert request.is_a? AmazonFlexPay::API::GetTransaction
175
+ assert_equal 'txid', request.transaction_id
176
+ end
177
+ AmazonFlexPay.get_transaction('txid')
178
+ end
179
+
180
+ should "parse a GetTransaction response" do
181
+ response = nil
182
+ assert_nothing_raised do
183
+ response = AmazonFlexPay::API::GetTransaction::Response.from_xml(get_transaction_response)
184
+ end
185
+ assert response.request_id
186
+ assert response.transaction.caller_reference
187
+ assert response.transaction.payment_method
188
+ end
189
+
190
+ should "delegate to transaction attributes" do
191
+ response = AmazonFlexPay::API::GetTransaction::Response.from_xml(get_transaction_response)
192
+ assert_equal response.caller_reference, response.transaction.caller_reference
193
+ assert_equal response.date_completed, response.transaction.date_completed
194
+ end
195
+
196
+ ## GetTransactionStatus
197
+
198
+ should "construct a GetTransactionStatus request" do
199
+ AmazonFlexPay.expects(:submit).with do |request|
200
+ assert request.is_a? AmazonFlexPay::API::GetTransactionStatus
201
+ assert_equal 'txid', request.transaction_id
202
+ end
203
+ AmazonFlexPay.get_transaction_status('txid')
204
+ end
205
+
206
+ should "parse a GetTransactionStatus response" do
207
+ response = nil
208
+ assert_nothing_raised do
209
+ response = AmazonFlexPay::API::GetTransactionStatus::Response.from_xml(get_transaction_status_response)
210
+ end
211
+ assert response.request_id
212
+ assert response.transaction_id
213
+ assert_equal 'Success', response.transaction_status
214
+ end
215
+
216
+ ## Pay
217
+
218
+ should "construct a Pay request" do
219
+ AmazonFlexPay.expects(:submit).with do |request|
220
+ assert request.is_a? AmazonFlexPay::API::Pay
221
+ assert_equal '1.00', request.transaction_amount.value
222
+ assert_equal 'USD', request.transaction_amount.currency_code
223
+ assert_equal 'token', request.sender_token_id
224
+ assert_equal 'myid', request.caller_reference
225
+ end
226
+ AmazonFlexPay.pay('1.00', 'USD', 'token', 'myid')
227
+ end
228
+
229
+ should "parse a Pay response" do
230
+ response = nil
231
+ assert_nothing_raised do
232
+ response = AmazonFlexPay::API::Pay::Response.from_xml(reserve_response)
233
+ end
234
+ assert response.request_id
235
+ assert response.transaction_id
236
+ assert response.transaction_status
237
+ end
238
+
239
+ ## Refund
240
+
241
+ should "construct a Refund request" do
242
+ AmazonFlexPay.expects(:submit).with do |request|
243
+ assert request.is_a? AmazonFlexPay::API::Refund
244
+ assert_equal 'txid', request.transaction_id
245
+ assert_equal 'myid', request.caller_reference
246
+ assert_equal '1.00', request.refund_amount.value
247
+ end
248
+ AmazonFlexPay.refund('txid', 'myid', :refund_amount => {:currency_code => 'USD', :value => '1.00'})
249
+ end
250
+
251
+ should "parse a Refund response" do
252
+ response = nil
253
+ assert_nothing_raised do
254
+ response = AmazonFlexPay::API::Refund::Response.from_xml(refund_response)
255
+ end
256
+ assert response.request_id
257
+ assert response.transaction_id
258
+ assert response.transaction_status
259
+ end
260
+
261
+ ## Reserve
262
+
263
+ should "construct a Reserve request" do
264
+ AmazonFlexPay.expects(:submit).with do |request|
265
+ assert request.is_a? AmazonFlexPay::API::Reserve
266
+ assert_equal '1.00', request.transaction_amount.value
267
+ assert_equal 'USD', request.transaction_amount.currency_code
268
+ assert_equal 'token', request.sender_token_id
269
+ assert_equal 'myid', request.caller_reference
270
+ assert_equal 'Caller', request.descriptor_policy.cs_owner
271
+
272
+ assert request.to_hash['DescriptorPolicy'].has_key?('CSOwner') # funky casing
273
+ end
274
+ AmazonFlexPay.reserve('1.00', 'USD', 'token', 'myid', :descriptor_policy => {:cs_owner => 'Caller', :soft_descriptor_type => 'Static'})
275
+ end
276
+
277
+ should "parse a Reserve response" do
278
+ response = nil
279
+ assert_nothing_raised do
280
+ response = AmazonFlexPay::API::Reserve::Response.from_xml(reserve_response)
281
+ end
282
+ assert response.request_id
283
+ assert response.transaction_id
284
+ assert response.transaction_status
285
+ end
286
+
287
+ ## Settle
288
+
289
+ should "construct a Settle request" do
290
+ AmazonFlexPay.expects(:submit).with do |request|
291
+ assert request.is_a? AmazonFlexPay::API::Settle
292
+ assert_equal 'txid', request.reserve_transaction_id
293
+ assert_equal 'USD', request.transaction_amount.currency_code
294
+ assert_equal '3.14', request.transaction_amount.value
295
+ end
296
+ AmazonFlexPay.settle('txid', :transaction_amount => {:currency_code => 'USD', :value => '3.14'})
297
+ end
298
+
299
+ should "parse a Settle response" do
300
+ response = nil
301
+ assert_nothing_raised do
302
+ response = AmazonFlexPay::API::Settle::Response.from_xml(settle_response)
303
+ end
304
+ assert response.request_id
305
+ assert response.transaction_id
306
+ assert response.transaction_status
307
+ end
308
+
309
+ ## VerifySignature
310
+
311
+ should "construct a VerifySignature request" do
312
+ AmazonFlexPay.expects(:submit).with do |request|
313
+ assert request.is_a? AmazonFlexPay::API::VerifySignature
314
+ assert_equal 'http://example.com/api', request.url_end_point
315
+ assert_equal 'foo=bar', request.http_parameters
316
+ end
317
+ AmazonFlexPay.verify_signature('http://example.com/api', 'foo=bar')
318
+ end
319
+
320
+ should "parse a VerifySignature response" do
321
+ response = nil
322
+ assert_nothing_raised do
323
+ response = AmazonFlexPay::API::VerifySignature::Response.from_xml(verify_signature_response)
324
+ end
325
+ assert response.request_id
326
+ assert response.verification_status
327
+ end
328
+
329
+ ## verifying a request
330
+
331
+ should "verify a GET request" do
332
+ request = stub(:get? => true, :protocol => 'http://', :host_with_port => 'example.com', :path => '/foo/bar', :query_string => 'a=1&b=2')
333
+ AmazonFlexPay.expects(:verify_signature).with('http://example.com/foo/bar', 'a=1&b=2').returns(true)
334
+ assert AmazonFlexPay.verify_request(request)
335
+ end
336
+
337
+ should "verify a POST request" do
338
+ request = stub(:get? => false, :protocol => 'http://', :host_with_port => 'example.com', :path => '/foo/bar', :raw_post => 'a=1&b=2')
339
+ AmazonFlexPay.expects(:verify_signature).with('http://example.com/foo/bar', 'a=1&b=2').returns(true)
340
+ assert AmazonFlexPay.verify_request(request)
341
+ end
342
+
343
+ ## Submit
344
+
345
+ class TestRequest < AmazonFlexPay::API::BaseRequest
346
+ attribute :foo
347
+
348
+ class Response < AmazonFlexPay::API::BaseRequest::BaseResponse; end
349
+ end
350
+
351
+
352
+ should "store the request in the response" do
353
+ RestClient.expects(:get).returns(stub(:body => cancel_token_response, :code => 200))
354
+ request = TestRequest.new(:foo => 'bar')
355
+ response = AmazonFlexPay.send(:submit, request)
356
+ assert_equal 'bar', response.request.foo
357
+ end
358
+
359
+ should "instrument successful responses" do
360
+ events = []
361
+ callback = proc{ |*args| events << ActiveSupport::Notifications::Event.new(*args) }
362
+
363
+ ActiveSupport::Notifications.subscribed(callback, "amazon_flex_pay.api") do
364
+ RestClient.expects(:get).returns(stub(:body => cancel_token_response, :code => 200))
365
+ request = TestRequest.new(:foo => 'bar')
366
+ AmazonFlexPay.send(:submit, request)
367
+ end
368
+
369
+ assert_equal 1, events.size
370
+ assert_equal 'TestRequest', events.first.payload[:action]
371
+ assert_equal 200, events.first.payload[:code]
372
+ assert events.first.payload.has_key?(:request)
373
+ assert events.first.payload.has_key?(:response)
374
+ assert events.first.duration > 0.1, events.first.duration.to_s
375
+ end
376
+
377
+ should "catch and parse errors" do
378
+ net_http_res = stub(:code => 400)
379
+ http_response = RestClient::Response.create(error_response, net_http_res, nil)
380
+ RestClient.expects(:get).raises(RestClient::BadRequest.new(http_response))
381
+
382
+ error = nil
383
+ begin
384
+ request = TestRequest.new(:foo => 'bar')
385
+ AmazonFlexPay.send(:submit, request)
386
+ rescue AmazonFlexPay::API::InvalidParams => e
387
+ error = e
388
+ end
389
+ assert error.request_id
390
+ assert_equal 'InvalidParams', error.code
391
+ assert error.message.match(/has to be a valid/)
392
+ end
393
+
394
+ should "instrument error responses" do
395
+ events = []
396
+ callback = proc{ |*args| events << ActiveSupport::Notifications::Event.new(*args) }
397
+
398
+ ActiveSupport::Notifications.subscribed(callback, "amazon_flex_pay.api") do
399
+ net_http_res = stub(:code => 400)
400
+ http_response = RestClient::Response.create(error_response, net_http_res, nil)
401
+ RestClient.expects(:get).raises(RestClient::BadRequest.new(http_response))
402
+
403
+ begin
404
+ request = TestRequest.new(:foo => 'bar')
405
+ AmazonFlexPay.send(:submit, request)
406
+ rescue AmazonFlexPay::API::Error
407
+ end
408
+ end
409
+
410
+ assert_equal 1, events.size
411
+ assert_equal 'TestRequest', events.first.payload[:action]
412
+ assert_equal 400, events.first.payload[:code]
413
+ assert events.first.payload.has_key?(:request)
414
+ assert events.first.payload.has_key?(:response)
415
+ assert events.first.duration > 0.1, events.first.duration.to_s
416
+ end
417
+
418
+ end