stripe 1.31.0 → 1.58.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (103) hide show
  1. checksums.yaml +4 -4
  2. data/.github/ISSUE_TEMPLATE.md +5 -0
  3. data/.travis.yml +2 -12
  4. data/Gemfile +29 -4
  5. data/History.txt +168 -0
  6. data/README.md +134 -0
  7. data/Rakefile +10 -0
  8. data/VERSION +1 -1
  9. data/bin/stripe-console +12 -5
  10. data/lib/data/ca-certificates.crt +3868 -5114
  11. data/lib/stripe/account.rb +41 -21
  12. data/lib/stripe/alipay_account.rb +20 -0
  13. data/lib/stripe/api_operations/create.rb +1 -1
  14. data/lib/stripe/api_operations/delete.rb +1 -1
  15. data/lib/stripe/api_operations/list.rb +1 -2
  16. data/lib/stripe/api_operations/save.rb +87 -0
  17. data/lib/stripe/api_resource.rb +37 -4
  18. data/lib/stripe/apple_pay_domain.rb +12 -0
  19. data/lib/stripe/application_fee.rb +8 -8
  20. data/lib/stripe/application_fee_refund.rb +7 -3
  21. data/lib/stripe/balance_transaction.rb +1 -1
  22. data/lib/stripe/bank_account.rb +9 -5
  23. data/lib/stripe/bitcoin_receiver.rb +6 -6
  24. data/lib/stripe/bitcoin_transaction.rb +1 -1
  25. data/lib/stripe/card.rb +9 -5
  26. data/lib/stripe/charge.rb +30 -12
  27. data/lib/stripe/country_spec.rb +9 -0
  28. data/lib/stripe/coupon.rb +1 -1
  29. data/lib/stripe/customer.rb +6 -4
  30. data/lib/stripe/dispute.rb +2 -2
  31. data/lib/stripe/errors.rb +82 -0
  32. data/lib/stripe/file_upload.rb +1 -1
  33. data/lib/stripe/invoice.rb +3 -3
  34. data/lib/stripe/invoice_item.rb +1 -1
  35. data/lib/stripe/list_object.rb +7 -6
  36. data/lib/stripe/order.rb +10 -2
  37. data/lib/stripe/order_return.rb +9 -0
  38. data/lib/stripe/plan.rb +1 -1
  39. data/lib/stripe/product.rb +2 -10
  40. data/lib/stripe/recipient.rb +1 -1
  41. data/lib/stripe/refund.rb +1 -1
  42. data/lib/stripe/reversal.rb +7 -3
  43. data/lib/stripe/singleton_api_resource.rb +3 -3
  44. data/lib/stripe/sku.rb +2 -2
  45. data/lib/stripe/source.rb +11 -0
  46. data/lib/stripe/stripe_object.rb +167 -91
  47. data/lib/stripe/subscription.rb +15 -9
  48. data/lib/stripe/subscription_item.rb +12 -0
  49. data/lib/stripe/three_d_secure.rb +9 -0
  50. data/lib/stripe/transfer.rb +3 -4
  51. data/lib/stripe/util.rb +100 -28
  52. data/lib/stripe/version.rb +1 -1
  53. data/lib/stripe.rb +283 -140
  54. data/stripe.gemspec +5 -18
  55. data/test/stripe/account_test.rb +55 -9
  56. data/test/stripe/alipay_account_test.rb +11 -0
  57. data/test/stripe/api_operations_test.rb +31 -0
  58. data/test/stripe/api_resource_test.rb +204 -10
  59. data/test/stripe/apple_pay_domain_test.rb +34 -0
  60. data/test/stripe/application_fee_test.rb +8 -5
  61. data/test/stripe/bitcoin_receiver_test.rb +2 -2
  62. data/test/stripe/charge_refund_test.rb +12 -0
  63. data/test/stripe/charge_test.rb +32 -4
  64. data/test/stripe/country_spec_test.rb +43 -0
  65. data/test/stripe/coupon_test.rb +9 -1
  66. data/test/stripe/customer_card_test.rb +2 -2
  67. data/test/stripe/customer_test.rb +24 -1
  68. data/test/stripe/dispute_test.rb +8 -0
  69. data/test/stripe/errors_test.rb +18 -0
  70. data/test/stripe/invoice_item_test.rb +19 -0
  71. data/test/stripe/invoice_test.rb +27 -1
  72. data/test/stripe/list_object_test.rb +36 -15
  73. data/test/stripe/order_return_test.rb +25 -0
  74. data/test/stripe/order_test.rb +21 -1
  75. data/test/stripe/plan_test.rb +31 -0
  76. data/test/stripe/product_test.rb +17 -7
  77. data/test/stripe/recipient_card_test.rb +2 -2
  78. data/test/stripe/recipient_test.rb +21 -0
  79. data/test/stripe/refund_test.rb +10 -1
  80. data/test/stripe/sku_test.rb +15 -6
  81. data/test/stripe/source_test.rb +83 -0
  82. data/test/stripe/stripe_object_test.rb +180 -11
  83. data/test/stripe/subscription_item_test.rb +76 -0
  84. data/test/stripe/subscription_test.rb +161 -37
  85. data/test/stripe/three_d_secure_test.rb +22 -0
  86. data/test/stripe/transfer_test.rb +8 -0
  87. data/test/stripe/util_test.rb +48 -16
  88. data/test/stripe_test.rb +58 -0
  89. data/test/test_data.rb +337 -27
  90. data/test/test_helper.rb +7 -3
  91. metadata +47 -133
  92. data/README.rdoc +0 -68
  93. data/gemfiles/default-with-activesupport.gemfile +0 -10
  94. data/gemfiles/json.gemfile +0 -12
  95. data/gemfiles/yajl.gemfile +0 -12
  96. data/lib/stripe/api_operations/update.rb +0 -58
  97. data/lib/stripe/errors/api_connection_error.rb +0 -4
  98. data/lib/stripe/errors/api_error.rb +0 -4
  99. data/lib/stripe/errors/authentication_error.rb +0 -4
  100. data/lib/stripe/errors/card_error.rb +0 -12
  101. data/lib/stripe/errors/invalid_request_error.rb +0 -11
  102. data/lib/stripe/errors/rate_limit_error.rb +0 -4
  103. data/lib/stripe/errors/stripe_error.rb +0 -26
@@ -52,7 +52,23 @@ module Stripe
52
52
  assert_equal 'secret-key', account.keys.secret
53
53
  end
54
54
 
55
- should "be updatable" do
55
+ should "be rejectable" do
56
+ account_data = {:id => 'acct_foo'}
57
+ @mock.expects(:get).
58
+ once.
59
+ with('https://api.stripe.com/v1/accounts/acct_foo', nil, nil).
60
+ returns(make_response(account_data))
61
+
62
+ @mock.expects(:post).
63
+ once.
64
+ with("https://api.stripe.com/v1/accounts/acct_foo/reject", nil, 'reason=fraud').
65
+ returns(make_response(account_data))
66
+
67
+ account = Stripe::Account.retrieve('acct_foo')
68
+ account.reject(:reason => 'fraud')
69
+ end
70
+
71
+ should "be saveable" do
56
72
  resp = {
57
73
  :id => 'acct_foo',
58
74
  :legal_entity => {
@@ -77,6 +93,20 @@ module Stripe
77
93
  a.save
78
94
  end
79
95
 
96
+ should "be updatable" do
97
+ resp = {
98
+ :id => 'acct_foo',
99
+ :business_name => 'ACME Corp',
100
+ }
101
+ @mock.expects(:post).
102
+ once.
103
+ with('https://api.stripe.com/v1/accounts/acct_foo', nil, 'business_name=ACME+Corp').
104
+ returns(make_response(resp))
105
+
106
+ a = Stripe::Account.update('acct_foo', :business_name => "ACME Corp")
107
+ assert_equal('ACME Corp', a.business_name)
108
+ end
109
+
80
110
  should 'disallow direct overrides of legal_entity' do
81
111
  account = Stripe::Account.construct_from(make_account({
82
112
  :keys => {
@@ -121,7 +151,7 @@ module Stripe
121
151
  :id => 'acct_1234',
122
152
  :external_accounts => {
123
153
  :object => "list",
124
- :url => "/v1/accounts/acct_1234/external_accounts",
154
+ :resource_url => "/v1/accounts/acct_1234/external_accounts",
125
155
  :data => [],
126
156
  }
127
157
  }
@@ -140,7 +170,7 @@ module Stripe
140
170
  :id => 'acct_1234',
141
171
  :external_accounts => {
142
172
  :object => "list",
143
- :url => "/v1/accounts/acct_1234/external_accounts",
173
+ :resource_url => "/v1/accounts/acct_1234/external_accounts",
144
174
  :data => [{
145
175
  :id => "ba_1234",
146
176
  :object => "bank_account",
@@ -155,8 +185,8 @@ module Stripe
155
185
  should "#serialize_params an a new additional_owners" do
156
186
  obj = Stripe::Util.convert_to_stripe_object({
157
187
  :object => "account",
158
- :legal_entity => {
159
- },
188
+ :legal_entity => Stripe::StripeObject.construct_from({
189
+ }),
160
190
  }, {})
161
191
  obj.legal_entity.additional_owners = [
162
192
  { :first_name => "Joe" },
@@ -171,7 +201,7 @@ module Stripe
171
201
  }
172
202
  }
173
203
  }
174
- assert_equal(expected, obj.class.serialize_params(obj))
204
+ assert_equal(expected, obj.serialize_params)
175
205
  end
176
206
 
177
207
  should "#serialize_params on an partially changed additional_owners" do
@@ -197,7 +227,7 @@ module Stripe
197
227
  }
198
228
  }
199
229
  }
200
- assert_equal(expected, obj.class.serialize_params(obj))
230
+ assert_equal(expected, obj.serialize_params)
201
231
  end
202
232
 
203
233
  should "#serialize_params on an unchanged additional_owners" do
@@ -220,7 +250,7 @@ module Stripe
220
250
  :additional_owners => {}
221
251
  }
222
252
  }
223
- assert_equal(expected, obj.class.serialize_params(obj))
253
+ assert_equal(expected, obj.serialize_params)
224
254
  end
225
255
 
226
256
  # Note that the empty string that we send for this one has a special
@@ -246,7 +276,23 @@ module Stripe
246
276
  :additional_owners => ""
247
277
  }
248
278
  }
249
- assert_equal(expected, obj.class.serialize_params(obj))
279
+ assert_equal(expected, obj.serialize_params)
280
+ end
281
+
282
+ context "#bank_account=" do
283
+ should "warn that #bank_account= is deprecated" do
284
+ old_stderr = $stderr
285
+ $stderr = StringIO.new
286
+ begin
287
+ a = Stripe::Account.new("test_account")
288
+ a.bank_account = "tok_123"
289
+ message = "NOTE: Stripe::Account#bank_account= is " +
290
+ "deprecated; use #external_account= instead"
291
+ assert_match Regexp.new(message), $stderr.string
292
+ ensure
293
+ $stderr = old_stderr
294
+ end
295
+ end
250
296
  end
251
297
  end
252
298
  end
@@ -0,0 +1,11 @@
1
+ require File.expand_path('../../test_helper', __FILE__)
2
+
3
+ module Stripe
4
+ class AlipayAccountTest < Test::Unit::TestCase
5
+ should "raise if accessing Stripe::Alipay.account directly" do
6
+ assert_raises NotImplementedError do
7
+ Stripe::AlipayAccount.retrieve "card_12345"
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,31 @@
1
+ # -*- coding: utf-8 -*-
2
+ require File.expand_path('../../test_helper', __FILE__)
3
+
4
+ module Stripe
5
+ class ApiOperationsTest < Test::Unit::TestCase
6
+ class UpdateableResource < APIResource
7
+ include Stripe::APIOperations::Save
8
+
9
+ def self.protected_fields
10
+ [:protected]
11
+ end
12
+ end
13
+
14
+ context ".update" do
15
+ should "post the correct parameters to the resource URL" do
16
+ @mock.expects(:post).once.
17
+ with("#{Stripe.api_base}/v1/updateableresources/id", nil, 'foo=bar').
18
+ returns(make_response({foo: 'bar'}))
19
+ resource = UpdateableResource::update("id", { foo: "bar" })
20
+ assert_equal('bar', resource.foo)
21
+ end
22
+
23
+ should "error on protected fields" do
24
+ e = assert_raises do
25
+ UpdateableResource::update("id", { protected: "bar" })
26
+ end
27
+ assert_equal "Cannot update protected field: protected", e.message
28
+ end
29
+ end
30
+ end
31
+ end
@@ -3,6 +3,26 @@ require File.expand_path('../../test_helper', __FILE__)
3
3
 
4
4
  module Stripe
5
5
  class ApiResourceTest < Test::Unit::TestCase
6
+ class NestedTestAPIResource < Stripe::APIResource
7
+ save_nested_resource :external_account
8
+ end
9
+
10
+ context ".save_nested_resource" do
11
+ should "can have a scalar set" do
12
+ r = NestedTestAPIResource.new("test_resource")
13
+ r.external_account = "tok_123"
14
+ assert_equal "tok_123", r.external_account
15
+ end
16
+
17
+ should "set a flag if given an object source" do
18
+ r = NestedTestAPIResource.new("test_resource")
19
+ r.external_account = {
20
+ :object => 'card'
21
+ }
22
+ assert_equal true, r.external_account.save_with_parent
23
+ end
24
+ end
25
+
6
26
  should "creating a new APIResource should not fetch over the network" do
7
27
  @mock.expects(:get).never
8
28
  Stripe::Customer.new("someid")
@@ -174,7 +194,7 @@ module Stripe
174
194
  context "with no global API key set" do
175
195
  should "use the per-object credential when creating" do
176
196
  Stripe.expects(:execute_request).with do |opts|
177
- opts[:headers][:authorization] == 'Bearer sk_test_local'
197
+ opts[:headers]['Authorization'] == 'Bearer sk_test_local'
178
198
  end.returns(make_response(make_charge))
179
199
 
180
200
  Stripe::Charge.create({:card => {:number => '4242424242424242'}},
@@ -193,7 +213,7 @@ module Stripe
193
213
 
194
214
  should "use the per-object credential when creating" do
195
215
  Stripe.expects(:execute_request).with do |opts|
196
- opts[:headers][:authorization] == 'Bearer local'
216
+ opts[:headers]['Authorization'] == 'Bearer local'
197
217
  end.returns(make_response(make_charge))
198
218
 
199
219
  Stripe::Charge.create({:card => {:number => '4242424242424242'}},
@@ -203,15 +223,15 @@ module Stripe
203
223
  should "use the per-object credential when retrieving and making other calls" do
204
224
  Stripe.expects(:execute_request).with do |opts|
205
225
  opts[:url] == "#{Stripe.api_base}/v1/charges/ch_test_charge" &&
206
- opts[:headers][:authorization] == 'Bearer local'
226
+ opts[:headers]['Authorization'] == 'Bearer local'
207
227
  end.returns(make_response(make_charge))
208
228
  Stripe.expects(:execute_request).with do |opts|
209
- opts[:url] == "#{Stripe.api_base}/v1/charges/ch_test_charge/refund" &&
210
- opts[:headers][:authorization] == 'Bearer local'
211
- end.returns(make_response(make_charge))
229
+ opts[:url] == "#{Stripe.api_base}/v1/charges/ch_test_charge/refunds" &&
230
+ opts[:headers]['Authorization'] == 'Bearer local'
231
+ end.returns(make_response(make_refund))
212
232
 
213
233
  ch = Stripe::Charge.retrieve('ch_test_charge', 'local')
214
- ch.refund
234
+ ch.refunds.create
215
235
  end
216
236
  end
217
237
  end
@@ -280,6 +300,18 @@ module Stripe
280
300
  end
281
301
  end
282
302
 
303
+ should "a 403 should give a PermissionError with http status, body, and JSON body" do
304
+ response = make_response(make_missing_id_error, 403)
305
+ @mock.expects(:get).once.raises(RestClient::ExceptionWithResponse.new(response, 403))
306
+ begin
307
+ Stripe::Customer.retrieve("foo")
308
+ rescue Stripe::PermissionError => e
309
+ assert_equal(403, e.http_status)
310
+ assert_equal(true, !!e.http_body)
311
+ assert_equal(true, e.json_body.kind_of?(Hash))
312
+ end
313
+ end
314
+
283
315
  should "a 404 should give an InvalidRequestError with http status, body, and JSON body" do
284
316
  response = make_response(make_missing_id_error, 404)
285
317
  @mock.expects(:get).once.raises(RestClient::ExceptionWithResponse.new(response, 404))
@@ -387,6 +419,31 @@ module Stripe
387
419
  assert_equal false, c.livemode
388
420
  end
389
421
 
422
+ should "updating should send along the idempotency-key header" do
423
+ Stripe.expects(:execute_request).with do |opts|
424
+ opts[:headers][:idempotency_key] == 'bar'
425
+ end.returns(make_response(make_customer))
426
+ c = Stripe::Customer.new
427
+ c.save({}, { :idempotency_key => 'bar' })
428
+ assert_equal false, c.livemode
429
+ end
430
+
431
+ should "updating should fail if api_key is overwritten with nil" do
432
+ c = Stripe::Customer.new
433
+ assert_raises TypeError do
434
+ c.save({}, { :api_key => nil })
435
+ end
436
+ end
437
+
438
+ should "updating should use the supplied api_key" do
439
+ Stripe.expects(:execute_request).with do |opts|
440
+ opts[:headers]['Authorization'] == 'Bearer sk_test_local'
441
+ end.returns(make_response(make_customer))
442
+ c = Stripe::Customer.new
443
+ c.save({}, { :api_key => 'sk_test_local' })
444
+ assert_equal false, c.livemode
445
+ end
446
+
390
447
  should "deleting should send no props and result in an object that has no props other deleted" do
391
448
  @mock.expects(:get).never
392
449
  @mock.expects(:post).never
@@ -420,7 +477,7 @@ module Stripe
420
477
  opts[:url] == "#{Stripe.api_base}/v1/customers/c_test_customer" &&
421
478
  opts[:headers][:stripe_account] == 'acct_abc'
422
479
  end.once.returns(make_response(make_customer))
423
- c = Stripe::Customer.retrieve("c_test_customer", {:stripe_account => 'acct_abc'})
480
+ Stripe::Customer.retrieve("c_test_customer", {:stripe_account => 'acct_abc'})
424
481
  end
425
482
 
426
483
  should "passing in a stripe_account header should pass it through on save" do
@@ -652,10 +709,147 @@ module Stripe
652
709
  :display_name => nil,
653
710
  })
654
711
 
655
- @mock.expects(:post).once.with("#{Stripe.api_base}/v1/accounts", nil, 'display_name=stripe').
712
+ @mock.expects(:post).once.with("#{Stripe.api_base}/v1/accounts", nil, 'display_name=stripe&metadata[key]=value').
656
713
  returns(make_response({"id" => "charge_id"}))
657
714
 
658
- account.save(:display_name => 'stripe')
715
+ account.save(:display_name => 'stripe', :metadata => {:key => 'value' })
716
+ end
717
+ end
718
+
719
+ context "with retries" do
720
+ setup do
721
+ Stripe.stubs(:max_network_retries).returns(2)
722
+ end
723
+
724
+ should 'retry failed network requests if specified and raise if error persists' do
725
+ Stripe.expects(:sleep_time).at_least_once.returns(0)
726
+ @mock.expects(:post).times(3).with('https://api.stripe.com/v1/charges', nil, 'amount=50&currency=usd').
727
+ raises(Errno::ECONNREFUSED.new)
728
+
729
+ err = assert_raises Stripe::APIConnectionError do
730
+ Stripe::Charge.create(:amount => 50, :currency => 'usd', :card => { :number => nil })
731
+ end
732
+ assert_match(/Request was retried 2 times/, err.message)
733
+ end
734
+
735
+ should 'retry failed network requests if specified and return successful response' do
736
+ Stripe.expects(:sleep_time).at_least_once.returns(0)
737
+ response = make_response({"id" => "myid"})
738
+ @mock.expects(:post).times(2).with('https://api.stripe.com/v1/charges', nil, 'amount=50&currency=usd').
739
+ raises(Errno::ECONNREFUSED.new).
740
+ then.
741
+ returns(response)
742
+
743
+ result = Stripe::Charge.create(:amount => 50, :currency => 'usd', :card => { :number => nil })
744
+ assert_equal "myid", result.id
745
+ end
746
+
747
+ should 'not add an idempotency key to GET requests' do
748
+ SecureRandom.expects(:uuid).times(0)
749
+ Stripe.expects(:execute_request).with do |opts|
750
+ opts[:headers][:idempotency_key].nil?
751
+ end.returns(make_response({"id" => "myid"}))
752
+
753
+ Stripe::Charge.list
754
+ end
755
+
756
+ should 'ensure there is always an idempotency_key on POST requests' do
757
+ SecureRandom.expects(:uuid).at_least_once.returns("random_key")
758
+ Stripe.expects(:execute_request).with do |opts|
759
+ opts[:headers]['Idempotency-Key'] == "random_key"
760
+ end.returns(make_response({"id" => "myid"}))
761
+
762
+ Stripe::Charge.create(:amount => 50, :currency => 'usd', :card => { :number => nil })
763
+ end
764
+
765
+ should 'ensure there is always an idempotency_key on DELETE requests' do
766
+ SecureRandom.expects(:uuid).at_least_once.returns("random_key")
767
+ Stripe.expects(:execute_request).with do |opts|
768
+ opts[:headers]['Idempotency-Key'] == "random_key"
769
+ end.returns(make_response({"id" => "myid"}))
770
+
771
+ c = Stripe::Customer.construct_from(make_customer)
772
+ c.delete
773
+ end
774
+
775
+ should 'not override a provided idempotency_key' do
776
+ # Note that this expectation looks like `:idempotency_key` instead of
777
+ # the header `Idempotency-Key` because it's user provided as seen
778
+ # below. The ones injected by the library itself look like headers
779
+ # (`Idempotency-Key`), but rest-client does allow this symbol
780
+ # formatting and will properly override the system generated one as
781
+ # expected.
782
+ Stripe.expects(:execute_request).with do |opts|
783
+ opts[:headers][:idempotency_key] == "provided_key"
784
+ end.returns(make_response({"id" => "myid"}))
785
+
786
+ Stripe::Charge.create({:amount => 50, :currency => 'usd', :card => { :number => nil }}, {:idempotency_key => 'provided_key'})
787
+ end
788
+
789
+ end
790
+
791
+ context ".should_retry?" do
792
+ setup do
793
+ Stripe.stubs(:max_network_retries).returns(2)
794
+ end
795
+
796
+ should 'retry on a low-level network error' do
797
+ assert Stripe.should_retry?(Errno::ECONNREFUSED.new, 0)
798
+ end
799
+
800
+ should 'retry on timeout' do
801
+ assert Stripe.should_retry?(RestClient::RequestTimeout.new, 0)
802
+ end
803
+
804
+ should 'retry on a conflict' do
805
+ assert Stripe.should_retry?(RestClient::Conflict.new, 0)
806
+ end
807
+
808
+ should 'not retry at maximum count' do
809
+ refute Stripe.should_retry?(RuntimeError.new, Stripe.max_network_retries)
810
+ end
811
+
812
+ should 'not retry on a certificate validation error' do
813
+ refute Stripe.should_retry?(RestClient::SSLCertificateNotVerified.new('message'), 0)
814
+ end
815
+ end
816
+
817
+ context ".sleep_time" do
818
+ should "should grow exponentially" do
819
+ Stripe.stubs(:rand).returns(1)
820
+ Stripe.stubs(:max_network_retry_delay).returns(999)
821
+ assert_equal(Stripe.initial_network_retry_delay, Stripe.sleep_time(1))
822
+ assert_equal(Stripe.initial_network_retry_delay * 2, Stripe.sleep_time(2))
823
+ assert_equal(Stripe.initial_network_retry_delay * 4, Stripe.sleep_time(3))
824
+ assert_equal(Stripe.initial_network_retry_delay * 8, Stripe.sleep_time(4))
825
+ end
826
+
827
+ should "enforce the max_network_retry_delay" do
828
+ Stripe.stubs(:rand).returns(1)
829
+ Stripe.stubs(:initial_network_retry_delay).returns(1)
830
+ Stripe.stubs(:max_network_retry_delay).returns(2)
831
+ assert_equal(1, Stripe.sleep_time(1))
832
+ assert_equal(2, Stripe.sleep_time(2))
833
+ assert_equal(2, Stripe.sleep_time(3))
834
+ assert_equal(2, Stripe.sleep_time(4))
835
+ end
836
+
837
+ should "add some randomness" do
838
+ random_value = 0.8
839
+ Stripe.stubs(:rand).returns(random_value)
840
+ Stripe.stubs(:initial_network_retry_delay).returns(1)
841
+ Stripe.stubs(:max_network_retry_delay).returns(8)
842
+
843
+ base_value = Stripe.initial_network_retry_delay * (0.5 * (1 + random_value))
844
+
845
+ # the initial value cannot be smaller than the base,
846
+ # so the randomness is ignored
847
+ assert_equal(Stripe.initial_network_retry_delay, Stripe.sleep_time(1))
848
+
849
+ # after the first one, the randomness is applied
850
+ assert_equal(base_value * 2, Stripe.sleep_time(2))
851
+ assert_equal(base_value * 4, Stripe.sleep_time(3))
852
+ assert_equal(base_value * 8, Stripe.sleep_time(4))
659
853
  end
660
854
  end
661
855
  end
@@ -0,0 +1,34 @@
1
+ require File.expand_path('../../test_helper', __FILE__)
2
+
3
+ module Stripe
4
+ class ApplePayDomainTest < Test::Unit::TestCase
5
+ should "create should return a new Apple Pay domain" do
6
+ @mock.expects(:post).once
7
+ .with('https://api.stripe.com/v1/apple_pay/domains', nil, '')
8
+ .returns(make_response(make_apple_pay_domain))
9
+ d = Stripe::ApplePayDomain.create
10
+ assert_equal "apwc_test_domain", d.id
11
+ end
12
+
13
+ should "domains should be deletable" do
14
+ @mock.expects(:get).once
15
+ .with('https://api.stripe.com/v1/apple_pay/domains/apwc_test_domain', nil, nil)
16
+ .returns(make_response(make_apple_pay_domain))
17
+ @mock.expects(:delete).once.returns(make_response(make_apple_pay_domain(:deleted => true)))
18
+ domain = Stripe::ApplePayDomain.retrieve('apwc_test_domain')
19
+ domain.delete
20
+ assert domain.deleted
21
+ end
22
+
23
+ should "domains should be listable" do
24
+ @mock.expects(:get).once.with('https://api.stripe.com/v1/apple_pay/domains', nil, nil)
25
+ .returns(make_response(make_apple_pay_domain_array))
26
+ domains = Stripe::ApplePayDomain.list
27
+ assert domains.data.kind_of?(Array)
28
+ assert_equal 3, domains.data.length
29
+ domains.each do |domain|
30
+ assert domain.kind_of?(Stripe::ApplePayDomain)
31
+ end
32
+ end
33
+ end
34
+ end
@@ -12,11 +12,14 @@ module Stripe
12
12
  end
13
13
 
14
14
  should "application fees should be refundable" do
15
- @mock.expects(:get).never
16
- @mock.expects(:post).once.returns(make_response({:id => "fee_test_fee", :refunded => true}))
17
- fee = Stripe::ApplicationFee.new("test_application_fee")
18
- fee.refund
19
- assert fee.refunded
15
+ fee = Stripe::ApplicationFee.construct_from(make_application_fee)
16
+
17
+ @mock.expects(:post).once.
18
+ with("#{Stripe.api_base}/v1/application_fees/#{fee.id}/refunds", nil, '').
19
+ returns(make_response(make_application_fee_refund))
20
+
21
+ refund = fee.refunds.create
22
+ assert refund.is_a?(Stripe::ApplicationFeeRefund)
20
23
  end
21
24
  end
22
25
  end
@@ -47,14 +47,14 @@ module Stripe
47
47
  should "delete a bitcoin receiver with no customer through top-level API" do
48
48
  @mock.expects(:delete).with("#{Stripe.api_base}/v1/bitcoin/receivers/btcrcv_test_receiver", nil, nil).once.returns(make_response({:deleted => true, :id => "btcrcv_test_receiver"}))
49
49
  receiver = Stripe::BitcoinReceiver.construct_from(make_bitcoin_receiver)
50
- response = receiver.delete
50
+ receiver.delete
51
51
  assert(receiver.deleted)
52
52
  end
53
53
 
54
54
  should "delete a bitcoin receiver with a customer through customer's subresource API" do
55
55
  @mock.expects(:delete).with("#{Stripe.api_base}/v1/customers/customer_foo/sources/btcrcv_test_receiver", nil, nil).once.returns(make_response({:deleted => true, :id => "btcrcv_test_receiver"}))
56
56
  receiver = Stripe::BitcoinReceiver.construct_from(make_bitcoin_receiver(:customer => 'customer_foo'))
57
- response = receiver.delete
57
+ receiver.delete
58
58
  assert(receiver.deleted)
59
59
  end
60
60
  end
@@ -51,5 +51,17 @@ module Stripe
51
51
  refund = charge.refunds.create(:amount => 20)
52
52
  assert_equal 'test_new_refund', refund.id
53
53
  end
54
+
55
+ should "should refund a charge with given amount" do
56
+ @mock.expects(:get).
57
+ with("#{Stripe.api_base}/v1/charges/test_charge", nil, nil).
58
+ twice.returns(make_response(make_charge(:id => 'test_charge')))
59
+ @mock.expects(:post).
60
+ with("#{Stripe.api_base}/v1/charges/test_charge/refunds", nil, 'amount=20').
61
+ once.returns(make_response(make_refund(:amount => 20)))
62
+
63
+ charge = Stripe::Charge.retrieve('test_charge')
64
+ charge.refund(:amount => 20)
65
+ end
54
66
  end
55
67
  end
@@ -12,10 +12,24 @@ module Stripe
12
12
  end
13
13
 
14
14
  should "charges should be refundable" do
15
+ c = Stripe::Charge.construct_from(make_charge)
15
16
  @mock.expects(:get).never
16
- @mock.expects(:post).once.returns(make_response({:id => "ch_test_charge", :refunded => true}))
17
- c = Stripe::Charge.new("test_charge")
18
- c.refund
17
+ @mock.expects(:post).once.returns(make_response(make_refund(:charge => c)))
18
+ r = c.refunds.create
19
+ assert r.is_a?(Stripe::Refund)
20
+ end
21
+
22
+ should "charges should be refundable for old API versions" do
23
+ # "refunds" was a plain array in old API versions but is not a Stripe
24
+ # list (see the implementation of `make_charge` for a current example)
25
+ data = make_charge.merge!(:refunds => [])
26
+ c = Stripe::Charge.construct_from(data)
27
+ @mock.expects(:get).never
28
+ @mock.expects(:post).once.
29
+ with("#{Stripe.api_base}/v1/charges/#{c.id}/refund", nil, '').
30
+ returns(make_response(data.merge(:refunded => true)))
31
+ c = c.refund
32
+ assert c.is_a?(Stripe::Charge)
19
33
  assert c.refunded
20
34
  end
21
35
 
@@ -28,6 +42,14 @@ module Stripe
28
42
  end
29
43
 
30
44
  should "charges should be updateable" do
45
+ @mock.expects(:post).once.
46
+ with('https://api.stripe.com/v1/charges/test_charge', nil, 'metadata[foo]=bar').
47
+ returns(make_response(make_charge(metadata: {'foo' => 'bar'})))
48
+ c = Stripe::Charge.update("test_charge", metadata: {foo: 'bar'})
49
+ assert_equal('bar', c.metadata['foo'])
50
+ end
51
+
52
+ should "charges should be saveable" do
31
53
  @mock.expects(:get).once.returns(make_response(make_charge))
32
54
  @mock.expects(:post).once.returns(make_response(make_charge))
33
55
  c = Stripe::Charge.new("test_charge")
@@ -58,6 +80,12 @@ module Stripe
58
80
  assert c.card.kind_of?(Stripe::StripeObject) && c.card.object == 'card'
59
81
  end
60
82
 
83
+ should "charges should have Outcome objects associated with their outcome property" do
84
+ @mock.expects(:get).once.returns(make_response(make_charge))
85
+ c = Stripe::Charge.retrieve("test_charge")
86
+ assert c.outcome.kind_of?(Stripe::StripeObject) && c.outcome.type == 'authorized'
87
+ end
88
+
61
89
  should "execute should return a new, fully executed charge when passed correct `card` parameters" do
62
90
  @mock.expects(:post).with do |url, api_key, params|
63
91
  url == "#{Stripe.api_base}/v1/charges" && api_key.nil? && CGI.parse(params) == {
@@ -110,7 +138,7 @@ module Stripe
110
138
  :amount => 100,
111
139
  :source => 'btcrcv_test_receiver',
112
140
  :currency => "usd",
113
- :level3 => [{:red => 'firstred'}, {:one => 'fish', :red => 'another'}]
141
+ :level3 => [{:red => 'firstred'}, {:red => 'another', :one => 'fish'}]
114
142
  })
115
143
  assert c.paid
116
144
  end
@@ -0,0 +1,43 @@
1
+ require File.expand_path('../../test_helper', __FILE__)
2
+
3
+ module Stripe
4
+ class CountrySpecTest < Test::Unit::TestCase
5
+ should "be listable" do
6
+ @mock.expects(:get).once.
7
+ returns(make_response(country_spec_array))
8
+ c = Stripe::CountrySpec.list
9
+
10
+ assert_equal('/v1/country_specs', c.resource_url)
11
+ assert_equal('list', c.object)
12
+ assert(c.data.kind_of?(Array))
13
+ assert_equal('US', c.data[0].id)
14
+ assert(c.data[0].kind_of?(Stripe::CountrySpec))
15
+ end
16
+
17
+ should "be retrievable" do
18
+ resp = make_country_spec
19
+ @mock.expects(:get).once.
20
+ with('https://api.stripe.com/v1/country_specs/US', nil, nil).
21
+ returns(make_response(resp))
22
+ s = Stripe::CountrySpec.retrieve('US')
23
+
24
+ assert_equal('/v1/country_specs/US', s.resource_url)
25
+ assert_equal('country_spec', s.object)
26
+ assert(s.kind_of?(Stripe::CountrySpec))
27
+
28
+ s.supported_bank_account_currencies.map{ |k,v| assert v.kind_of?(Array) }
29
+ assert_equal(['US'], s.supported_bank_account_currencies['usd'])
30
+ assert(s.supported_payment_currencies.include?('usd'))
31
+ assert s.supported_payment_currencies.kind_of?(Array)
32
+ assert s.supported_payment_methods.kind_of?(Array)
33
+
34
+ ['individual', 'company'].map{ |type|
35
+ item = s.verification_fields[type]
36
+ assert item.minimum.include?('external_account')
37
+ assert item.additional.include?('legal_entity.verification.document')
38
+ assert item.additional.kind_of?(Array)
39
+ assert item.minimum.kind_of?(Array)
40
+ }
41
+ end
42
+ end
43
+ end
@@ -8,7 +8,7 @@ module Stripe
8
8
  assert_equal "co_test_coupon", c.id
9
9
  end
10
10
 
11
- should "coupons should be updateable" do
11
+ should "coupons should be saveable" do
12
12
  @mock.expects(:get).once.returns(make_response(make_coupon))
13
13
  @mock.expects(:post).once.returns(make_response(make_coupon))
14
14
  c = Stripe::Coupon.new("test_coupon")
@@ -16,5 +16,13 @@ module Stripe
16
16
  c.metadata['foo'] = 'bar'
17
17
  c.save
18
18
  end
19
+
20
+ should "coupons should be updateable" do
21
+ @mock.expects(:post).once.
22
+ with("https://api.stripe.com/v1/coupons/test_coupon", nil, "metadata[foo]=bar").
23
+ returns(make_response(make_coupon(metadata: {foo: 'bar'})))
24
+ c = Stripe::Coupon.update("test_coupon", metadata: {foo: 'bar'})
25
+ assert_equal('bar', c.metadata['foo'])
26
+ end
19
27
  end
20
28
  end