stripe 1.18.0 → 1.30.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (81) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +1 -0
  3. data/.travis.yml +11 -1
  4. data/History.txt +98 -0
  5. data/README.rdoc +19 -10
  6. data/VERSION +1 -1
  7. data/lib/stripe/account.rb +46 -4
  8. data/lib/stripe/api_operations/create.rb +3 -10
  9. data/lib/stripe/api_operations/delete.rb +4 -4
  10. data/lib/stripe/api_operations/list.rb +17 -9
  11. data/lib/stripe/api_operations/request.rb +41 -0
  12. data/lib/stripe/api_operations/update.rb +41 -40
  13. data/lib/stripe/api_resource.rb +7 -4
  14. data/lib/stripe/application_fee.rb +3 -4
  15. data/lib/stripe/application_fee_refund.rb +1 -1
  16. data/lib/stripe/balance_transaction.rb +1 -1
  17. data/lib/stripe/bank_account.rb +19 -0
  18. data/lib/stripe/bitcoin_receiver.rb +12 -2
  19. data/lib/stripe/bitcoin_transaction.rb +5 -0
  20. data/lib/stripe/card.rb +6 -4
  21. data/lib/stripe/charge.rb +14 -22
  22. data/lib/stripe/coupon.rb +2 -2
  23. data/lib/stripe/customer.rb +24 -26
  24. data/lib/stripe/dispute.rb +16 -0
  25. data/lib/stripe/errors/card_error.rb +3 -2
  26. data/lib/stripe/errors/invalid_request_error.rb +3 -2
  27. data/lib/stripe/errors/rate_limit_error.rb +4 -0
  28. data/lib/stripe/errors/stripe_error.rb +8 -2
  29. data/lib/stripe/event.rb +1 -1
  30. data/lib/stripe/file_upload.rb +12 -22
  31. data/lib/stripe/invoice.rb +8 -8
  32. data/lib/stripe/invoice_item.rb +2 -2
  33. data/lib/stripe/list_object.rb +77 -13
  34. data/lib/stripe/order.rb +19 -0
  35. data/lib/stripe/plan.rb +2 -2
  36. data/lib/stripe/product.rb +16 -0
  37. data/lib/stripe/recipient.rb +2 -2
  38. data/lib/stripe/refund.rb +2 -9
  39. data/lib/stripe/reversal.rb +14 -0
  40. data/lib/stripe/singleton_api_resource.rb +2 -2
  41. data/lib/stripe/sku.rb +8 -0
  42. data/lib/stripe/stripe_object.rb +232 -46
  43. data/lib/stripe/subscription.rb +3 -3
  44. data/lib/stripe/token.rb +1 -1
  45. data/lib/stripe/transfer.rb +3 -3
  46. data/lib/stripe/util.rb +64 -21
  47. data/lib/stripe/version.rb +1 -1
  48. data/lib/stripe.rb +102 -67
  49. data/stripe.gemspec +0 -2
  50. data/test/stripe/account_test.rb +135 -6
  51. data/test/stripe/api_resource_test.rb +326 -42
  52. data/test/stripe/application_fee_refund_test.rb +6 -6
  53. data/test/stripe/application_fee_test.rb +3 -3
  54. data/test/stripe/balance_test.rb +11 -0
  55. data/test/stripe/bitcoin_receiver_test.rb +30 -7
  56. data/test/stripe/bitcoin_transaction_test.rb +29 -0
  57. data/test/stripe/charge_refund_test.rb +55 -0
  58. data/test/stripe/charge_test.rb +32 -13
  59. data/test/stripe/coupon_test.rb +3 -3
  60. data/test/stripe/customer_card_test.rb +20 -14
  61. data/test/stripe/customer_test.rb +15 -15
  62. data/test/stripe/dispute_test.rb +45 -0
  63. data/test/stripe/file_upload_test.rb +17 -6
  64. data/test/stripe/invoice_test.rb +18 -4
  65. data/test/stripe/list_object_test.rb +126 -2
  66. data/test/stripe/metadata_test.rb +28 -13
  67. data/test/stripe/order_test.rb +52 -0
  68. data/test/stripe/product_test.rb +41 -0
  69. data/test/stripe/recipient_card_test.rb +9 -9
  70. data/test/stripe/refund_test.rb +23 -15
  71. data/test/stripe/reversal_test.rb +47 -0
  72. data/test/stripe/sku_test.rb +24 -0
  73. data/test/stripe/stripe_object_test.rb +67 -6
  74. data/test/stripe/subscription_test.rb +13 -13
  75. data/test/stripe/transfer_test.rb +4 -4
  76. data/test/stripe/util_test.rb +45 -29
  77. data/test/stripe_test.rb +16 -0
  78. data/test/test_data.rb +273 -66
  79. metadata +47 -76
  80. data/lib/stripe/certificate_blacklist.rb +0 -55
  81. data/test/stripe/certificate_blacklist_test.rb +0 -18
data/lib/stripe.rb CHANGED
@@ -1,9 +1,12 @@
1
1
  # Stripe Ruby bindings
2
2
  # API spec at https://stripe.com/docs/api
3
3
  require 'cgi'
4
- require 'set'
5
4
  require 'openssl'
6
- require 'rest_client'
5
+ require 'rbconfig'
6
+ require 'set'
7
+ require 'socket'
8
+
9
+ require 'rest-client'
7
10
  require 'json'
8
11
 
9
12
  # Version
@@ -14,6 +17,7 @@ require 'stripe/api_operations/create'
14
17
  require 'stripe/api_operations/update'
15
18
  require 'stripe/api_operations/delete'
16
19
  require 'stripe/api_operations/list'
20
+ require 'stripe/api_operations/request'
17
21
 
18
22
  # Resources
19
23
  require 'stripe/util'
@@ -25,7 +29,6 @@ require 'stripe/account'
25
29
  require 'stripe/balance'
26
30
  require 'stripe/balance_transaction'
27
31
  require 'stripe/customer'
28
- require 'stripe/certificate_blacklist'
29
32
  require 'stripe/invoice'
30
33
  require 'stripe/invoice_item'
31
34
  require 'stripe/charge'
@@ -36,13 +39,19 @@ require 'stripe/token'
36
39
  require 'stripe/event'
37
40
  require 'stripe/transfer'
38
41
  require 'stripe/recipient'
42
+ require 'stripe/bank_account'
39
43
  require 'stripe/card'
40
44
  require 'stripe/subscription'
41
45
  require 'stripe/application_fee'
42
46
  require 'stripe/refund'
47
+ require 'stripe/reversal'
43
48
  require 'stripe/application_fee_refund'
44
49
  require 'stripe/bitcoin_receiver'
45
50
  require 'stripe/bitcoin_transaction'
51
+ require 'stripe/dispute'
52
+ require 'stripe/product'
53
+ require 'stripe/sku'
54
+ require 'stripe/order'
46
55
 
47
56
  # Errors
48
57
  require 'stripe/errors/stripe_error'
@@ -51,19 +60,24 @@ require 'stripe/errors/api_connection_error'
51
60
  require 'stripe/errors/card_error'
52
61
  require 'stripe/errors/invalid_request_error'
53
62
  require 'stripe/errors/authentication_error'
63
+ require 'stripe/errors/rate_limit_error'
54
64
 
55
65
  module Stripe
56
66
  DEFAULT_CA_BUNDLE_PATH = File.dirname(__FILE__) + '/data/ca-certificates.crt'
67
+
57
68
  @api_base = 'https://api.stripe.com'
58
69
  @connect_base = 'https://connect.stripe.com'
70
+ @uploads_base = 'https://uploads.stripe.com'
59
71
 
60
72
  @ssl_bundle_path = DEFAULT_CA_BUNDLE_PATH
61
73
  @verify_ssl_certs = true
62
- @CERTIFICATE_VERIFIED = false
63
74
 
75
+ @open_timeout = 30
76
+ @read_timeout = 80
64
77
 
65
78
  class << self
66
- attr_accessor :api_key, :api_base, :verify_ssl_certs, :api_version, :connect_base
79
+ attr_accessor :api_key, :api_base, :verify_ssl_certs, :api_version, :connect_base, :uploads_base,
80
+ :open_timeout, :read_timeout
67
81
  end
68
82
 
69
83
  def self.api_url(url='', api_base_url=nil)
@@ -74,29 +88,31 @@ module Stripe
74
88
  api_base_url = api_base_url || @api_base
75
89
 
76
90
  unless api_key ||= @api_key
77
- raise AuthenticationError.new('No API key provided. ' +
78
- 'Set your API key using "Stripe.api_key = <API-KEY>". ' +
79
- 'You can generate API keys from the Stripe web interface. ' +
80
- 'See https://stripe.com/api for details, or email support@stripe.com ' +
91
+ raise AuthenticationError.new('No API key provided. ' \
92
+ 'Set your API key using "Stripe.api_key = <API-KEY>". ' \
93
+ 'You can generate API keys from the Stripe web interface. ' \
94
+ 'See https://stripe.com/api for details, or email support@stripe.com ' \
81
95
  'if you have any questions.')
82
96
  end
83
97
 
84
98
  if api_key =~ /\s/
85
- raise AuthenticationError.new('Your API key is invalid, as it contains ' +
86
- 'whitespace. (HINT: You can double-check your API key from the ' +
87
- 'Stripe web interface. See https://stripe.com/api for details, or ' +
99
+ raise AuthenticationError.new('Your API key is invalid, as it contains ' \
100
+ 'whitespace. (HINT: You can double-check your API key from the ' \
101
+ 'Stripe web interface. See https://stripe.com/api for details, or ' \
88
102
  'email support@stripe.com if you have any questions.)')
89
103
  end
90
104
 
91
- request_opts = { :verify_ssl => false }
92
-
93
- if ssl_preflight_passed?
94
- request_opts.update(:verify_ssl => OpenSSL::SSL::VERIFY_PEER,
95
- :ssl_ca_file => @ssl_bundle_path)
96
- end
97
-
98
- if @verify_ssl_certs and !@CERTIFICATE_VERIFIED
99
- @CERTIFICATE_VERIFIED = CertificateBlacklist.check_ssl_cert(api_base_url, @ssl_bundle_path)
105
+ if verify_ssl_certs
106
+ request_opts = {:verify_ssl => OpenSSL::SSL::VERIFY_PEER,
107
+ :ssl_ca_file => @ssl_bundle_path}
108
+ else
109
+ request_opts = {:verify_ssl => false}
110
+ unless @verify_ssl_warned
111
+ @verify_ssl_warned = true
112
+ $stderr.puts("WARNING: Running without SSL cert verification. " \
113
+ "You should never do this in production. " \
114
+ "Execute 'Stripe.verify_ssl_certs = true' to enable verification.")
115
+ end
100
116
  end
101
117
 
102
118
  params = Util.objects_to_ids(params)
@@ -105,19 +121,19 @@ module Stripe
105
121
  case method.to_s.downcase.to_sym
106
122
  when :get, :head, :delete
107
123
  # Make params into GET parameters
108
- url += "#{URI.parse(url).query ? '&' : '?'}#{uri_encode(params)}" if params && params.any?
124
+ url += "#{URI.parse(url).query ? '&' : '?'}#{Util.encode_parameters(params)}" if params && params.any?
109
125
  payload = nil
110
126
  else
111
127
  if headers[:content_type] && headers[:content_type] == "multipart/form-data"
112
128
  payload = params
113
129
  else
114
- payload = uri_encode(params)
130
+ payload = Util.encode_parameters(params)
115
131
  end
116
132
  end
117
133
 
118
134
  request_opts.update(:headers => request_headers(api_key).update(headers),
119
- :method => method, :open_timeout => 30,
120
- :payload => payload, :url => url, :timeout => 80)
135
+ :method => method, :open_timeout => open_timeout,
136
+ :payload => payload, :url => url, :timeout => read_timeout)
121
137
 
122
138
  begin
123
139
  response = execute_request(request_opts)
@@ -132,8 +148,8 @@ module Stripe
132
148
  raise
133
149
  end
134
150
  rescue RestClient::ExceptionWithResponse => e
135
- if rcode = e.http_code and rbody = e.http_body
136
- handle_api_error(rcode, rbody)
151
+ if e.response
152
+ handle_api_error(e.response)
137
153
  else
138
154
  handle_restclient_error(e, api_base_url)
139
155
  end
@@ -146,23 +162,6 @@ module Stripe
146
162
 
147
163
  private
148
164
 
149
- def self.ssl_preflight_passed?
150
- if !verify_ssl_certs && !@no_verify
151
- $stderr.puts "WARNING: Running without SSL cert verification. " +
152
- "Execute 'Stripe.verify_ssl_certs = true' to enable verification."
153
-
154
- @no_verify = true
155
-
156
- elsif !Util.file_readable(@ssl_bundle_path) && !@no_bundle
157
- $stderr.puts "WARNING: Running without SSL cert verification " +
158
- "because #{@ssl_bundle_path} isn't readable"
159
-
160
- @no_bundle = true
161
- end
162
-
163
- !(@no_verify || @no_bundle)
164
- end
165
-
166
165
  def self.user_agent
167
166
  @uname ||= get_uname
168
167
  lang_version = "#{RUBY_VERSION} p#{RUBY_PATCHLEVEL} (#{RUBY_RELEASE_DATE})"
@@ -172,21 +171,48 @@ module Stripe
172
171
  :lang => 'ruby',
173
172
  :lang_version => lang_version,
174
173
  :platform => RUBY_PLATFORM,
174
+ :engine => defined?(RUBY_ENGINE) ? RUBY_ENGINE : '',
175
175
  :publisher => 'stripe',
176
- :uname => @uname
176
+ :uname => @uname,
177
+ :hostname => Socket.gethostname,
177
178
  }
178
179
 
179
180
  end
180
181
 
181
182
  def self.get_uname
182
- `uname -a 2>/dev/null`.strip if RUBY_PLATFORM =~ /linux|darwin/i
183
- rescue Errno::ENOMEM => ex # couldn't create subprocess
183
+ if File.exist?('/proc/version')
184
+ File.read('/proc/version').strip
185
+ else
186
+ case RbConfig::CONFIG['host_os']
187
+ when /linux|darwin|bsd|sunos|solaris|cygwin/i
188
+ _uname_uname
189
+ when /mswin|mingw/i
190
+ _uname_ver
191
+ else
192
+ "unknown platform"
193
+ end
194
+ end
195
+ end
196
+
197
+ def self._uname_uname
198
+ (`uname -a 2>/dev/null` || '').strip
199
+ rescue Errno::ENOMEM # couldn't create subprocess
184
200
  "uname lookup failed"
185
201
  end
186
202
 
203
+ def self._uname_ver
204
+ (`ver` || '').strip
205
+ rescue Errno::ENOMEM # couldn't create subprocess
206
+ "uname lookup failed"
207
+ end
208
+
209
+ # DEPRECATED. Use `Util#encode_parameters` instead.
187
210
  def self.uri_encode(params)
188
- Util.flatten_params(params).
189
- map { |k,v| "#{k}=#{Util.url_encode(v)}" }.join('&')
211
+ Util.encode_parameters(params)
212
+ end
213
+ class << self
214
+ extend Gem::Deprecate
215
+ deprecate :uri_encode, "Stripe::Util#encode_parameters", 2016, 01
190
216
  end
191
217
 
192
218
  def self.request_headers(api_key)
@@ -227,45 +253,54 @@ module Stripe
227
253
  "(HTTP response code was #{rcode})", rcode, rbody)
228
254
  end
229
255
 
230
- def self.handle_api_error(rcode, rbody)
256
+ def self.handle_api_error(resp)
231
257
  begin
232
- error_obj = JSON.parse(rbody)
258
+ error_obj = JSON.parse(resp.body)
233
259
  error_obj = Util.symbolize_names(error_obj)
234
- error = error_obj[:error] or raise StripeError.new # escape from parsing
260
+ error = error_obj[:error]
261
+ raise StripeError.new unless error && error.is_a?(Hash)
235
262
 
236
263
  rescue JSON::ParserError, StripeError
237
- raise general_api_error(rcode, rbody)
264
+ raise general_api_error(resp.code, resp.body)
238
265
  end
239
266
 
240
- case rcode
267
+ case resp.code
241
268
  when 400, 404
242
- raise invalid_request_error error, rcode, rbody, error_obj
269
+ raise invalid_request_error(error, resp, error_obj)
243
270
  when 401
244
- raise authentication_error error, rcode, rbody, error_obj
271
+ raise authentication_error(error, resp, error_obj)
245
272
  when 402
246
- raise card_error error, rcode, rbody, error_obj
273
+ raise card_error(error, resp, error_obj)
274
+ when 429
275
+ raise rate_limit_error(error, resp, error_obj)
247
276
  else
248
- raise api_error error, rcode, rbody, error_obj
277
+ raise api_error(error, resp, error_obj)
249
278
  end
250
279
 
251
280
  end
252
281
 
253
- def self.invalid_request_error(error, rcode, rbody, error_obj)
254
- InvalidRequestError.new(error[:message], error[:param], rcode,
255
- rbody, error_obj)
282
+ def self.invalid_request_error(error, resp, error_obj)
283
+ InvalidRequestError.new(error[:message], error[:param], resp.code,
284
+ resp.body, error_obj, resp.headers)
285
+ end
286
+
287
+ def self.authentication_error(error, resp, error_obj)
288
+ AuthenticationError.new(error[:message], resp.code, resp.body, error_obj,
289
+ resp.headers)
256
290
  end
257
291
 
258
- def self.authentication_error(error, rcode, rbody, error_obj)
259
- AuthenticationError.new(error[:message], rcode, rbody, error_obj)
292
+ def self.rate_limit_error(error, resp, error_obj)
293
+ RateLimitError.new(error[:message], resp.code, resp.body, error_obj,
294
+ resp.headers)
260
295
  end
261
296
 
262
- def self.card_error(error, rcode, rbody, error_obj)
297
+ def self.card_error(error, resp, error_obj)
263
298
  CardError.new(error[:message], error[:param], error[:code],
264
- rcode, rbody, error_obj)
299
+ resp.code, resp.body, error_obj, resp.headers)
265
300
  end
266
301
 
267
- def self.api_error(error, rcode, rbody, error_obj)
268
- APIError.new(error[:message], rcode, rbody, error_obj)
302
+ def self.api_error(error, resp, error_obj)
303
+ APIError.new(error[:message], resp.code, resp.body, error_obj, resp.headers)
269
304
  end
270
305
 
271
306
  def self.handle_restclient_error(e, api_base_url=nil)
data/stripe.gemspec CHANGED
@@ -13,14 +13,12 @@ spec = Gem::Specification.new do |s|
13
13
  s.license = 'MIT'
14
14
 
15
15
  s.add_dependency('rest-client', '~> 1.4')
16
- s.add_dependency('mime-types', '>= 1.25', '< 3.0')
17
16
  s.add_dependency('json', '~> 1.8.1')
18
17
 
19
18
  s.add_development_dependency('mocha', '~> 0.13.2')
20
19
  s.add_development_dependency('shoulda', '~> 3.4.0')
21
20
  s.add_development_dependency('test-unit')
22
21
  s.add_development_dependency('rake')
23
- s.add_development_dependency('pry')
24
22
 
25
23
  s.files = `git ls-files`.split("\n")
26
24
  s.test_files = `git ls-files -- test/*`.split("\n")
@@ -2,25 +2,154 @@ require File.expand_path('../../test_helper', __FILE__)
2
2
 
3
3
  module Stripe
4
4
  class AccountTest < Test::Unit::TestCase
5
- should "account should be retrievable" do
6
- resp = {:email => "test+bindings@stripe.com", :charge_enabled => false, :details_submitted => false}
7
- @mock.expects(:get).once.returns(test_response(resp))
5
+ should "be retrievable" do
6
+ resp = make_account({
7
+ :charges_enabled => false,
8
+ :details_submitted => false,
9
+ :email => "test+bindings@stripe.com",
10
+ })
11
+ @mock.expects(:get).
12
+ once.
13
+ with('https://api.stripe.com/v1/account', nil, nil).
14
+ returns(make_response(resp))
8
15
  a = Stripe::Account.retrieve
9
16
  assert_equal "test+bindings@stripe.com", a.email
10
- assert !a.charge_enabled
17
+ assert !a.charges_enabled
11
18
  assert !a.details_submitted
12
19
  end
13
20
 
21
+ should "be retrievable via plural endpoint" do
22
+ resp = make_account({
23
+ :charges_enabled => false,
24
+ :details_submitted => false,
25
+ :email => "test+bindings@stripe.com",
26
+ })
27
+ @mock.expects(:get).
28
+ once.
29
+ with('https://api.stripe.com/v1/accounts/acct_foo', nil, nil).
30
+ returns(make_response(resp))
31
+ a = Stripe::Account.retrieve('acct_foo')
32
+ assert_equal "test+bindings@stripe.com", a.email
33
+ assert !a.charges_enabled
34
+ assert !a.details_submitted
35
+ end
36
+
37
+ should "be retrievable using an API key as the only argument" do
38
+ account = mock
39
+ Stripe::Account.expects(:new).once.with(nil, {:api_key => 'sk_foobar'}).returns(account)
40
+ account.expects(:refresh).once
41
+ Stripe::Account.retrieve('sk_foobar')
42
+ end
43
+
44
+ should "allow access to keys by method" do
45
+ account = Stripe::Account.construct_from(make_account({
46
+ :keys => {
47
+ :publishable => 'publishable-key',
48
+ :secret => 'secret-key',
49
+ }
50
+ }))
51
+ assert_equal 'publishable-key', account.keys.publishable
52
+ assert_equal 'secret-key', account.keys.secret
53
+ end
54
+
55
+ should "be updatable" do
56
+ resp = {
57
+ :id => 'acct_foo',
58
+ :legal_entity => {
59
+ :address => {
60
+ :line1 => '1 Two Three'
61
+ }
62
+ }
63
+ }
64
+ @mock.expects(:get).
65
+ once.
66
+ with('https://api.stripe.com/v1/accounts/acct_foo', nil, nil).
67
+ returns(make_response(resp))
68
+
69
+ @mock.expects(:post).
70
+ once.
71
+ with('https://api.stripe.com/v1/accounts/acct_foo', nil, 'legal_entity[address][line1]=2+Three+Four&legal_entity[first_name]=Bob').
72
+ returns(make_response(resp))
73
+
74
+ a = Stripe::Account.retrieve('acct_foo')
75
+ a.legal_entity.first_name = 'Bob'
76
+ a.legal_entity.address.line1 = '2 Three Four'
77
+ a.save
78
+ end
79
+
80
+ should 'disallow direct overrides of legal_entity' do
81
+ account = Stripe::Account.construct_from(make_account({
82
+ :keys => {
83
+ :publishable => 'publishable-key',
84
+ :secret => 'secret-key',
85
+ },
86
+ :legal_entity => {
87
+ :first_name => 'Bling'
88
+ }
89
+ }))
90
+
91
+ assert_raise NoMethodError do
92
+ account.legal_entity = {:first_name => 'Blah'}
93
+ end
94
+
95
+ account.legal_entity.first_name = 'Blah'
96
+ end
97
+
14
98
  should "be able to deauthorize an account" do
15
99
  resp = {:id => 'acct_1234', :email => "test+bindings@stripe.com", :charge_enabled => false, :details_submitted => false}
16
- @mock.expects(:get).once.returns(test_response(resp))
100
+ @mock.expects(:get).once.returns(make_response(resp))
17
101
  a = Stripe::Account.retrieve
18
102
 
19
103
 
20
104
  @mock.expects(:post).once.with do |url, api_key, params|
21
105
  url == "#{Stripe.connect_base}/oauth/deauthorize" && api_key.nil? && CGI.parse(params) == { 'client_id' => [ 'ca_1234' ], 'stripe_user_id' => [ a.id ]}
22
- end.returns(test_response({ 'stripe_user_id' => a.id }))
106
+ end.returns(make_response({ 'stripe_user_id' => a.id }))
23
107
  a.deauthorize('ca_1234', 'sk_test_1234')
24
108
  end
109
+
110
+ should "reject nil api keys" do
111
+ assert_raise TypeError do
112
+ Stripe::Account.retrieve(nil)
113
+ end
114
+ assert_raise TypeError do
115
+ Stripe::Account.retrieve(:api_key => nil)
116
+ end
117
+ end
118
+
119
+ should "be able to create a bank account" do
120
+ resp = {
121
+ :id => 'acct_1234',
122
+ :external_accounts => {
123
+ :object => "list",
124
+ :url => "/v1/accounts/acct_1234/external_accounts",
125
+ :data => [],
126
+ }
127
+ }
128
+ @mock.expects(:get).once.returns(make_response(resp))
129
+ a = Stripe::Account.retrieve
130
+
131
+ @mock.expects(:post).
132
+ once.
133
+ with('https://api.stripe.com/v1/accounts/acct_1234/external_accounts', nil, 'external_account=btok_1234').
134
+ returns(make_response(resp))
135
+ a.external_accounts.create({:external_account => 'btok_1234'})
136
+ end
137
+
138
+ should "be able to retrieve a bank account" do
139
+ resp = {
140
+ :id => 'acct_1234',
141
+ :external_accounts => {
142
+ :object => "list",
143
+ :url => "/v1/accounts/acct_1234/external_accounts",
144
+ :data => [{
145
+ :id => "ba_1234",
146
+ :object => "bank_account",
147
+ }],
148
+ }
149
+ }
150
+ @mock.expects(:get).once.returns(make_response(resp))
151
+ a = Stripe::Account.retrieve
152
+ assert_equal(BankAccount, a.external_accounts.data[0].class)
153
+ end
25
154
  end
26
155
  end