stripe 3.0.3 → 3.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.travis.yml +23 -0
- data/Gemfile +1 -2
- data/History.txt +4 -0
- data/README.md +28 -3
- data/Rakefile +0 -12
- data/VERSION +1 -1
- data/lib/stripe.rb +24 -0
- data/lib/stripe/stripe_client.rb +166 -19
- data/lib/stripe/util.rb +127 -8
- data/lib/stripe/version.rb +1 -1
- data/test/api_stub_helpers.rb +0 -125
- data/test/stripe/account_test.rb +11 -13
- data/test/stripe/alipay_account_test.rb +2 -4
- data/test/stripe/api_resource_test.rb +112 -76
- data/test/stripe/apple_pay_domain_test.rb +4 -6
- data/test/stripe/application_fee_refund_test.rb +2 -5
- data/test/stripe/application_fee_test.rb +0 -2
- data/test/stripe/bank_account_test.rb +8 -13
- data/test/stripe/bitcoin_receiver_test.rb +13 -16
- data/test/stripe/bitcoin_transaction_test.rb +2 -4
- data/test/stripe/charge_test.rb +9 -11
- data/test/stripe/country_spec_test.rb +2 -4
- data/test/stripe/coupon_test.rb +6 -8
- data/test/stripe/customer_card_test.rb +13 -9
- data/test/stripe/customer_test.rb +16 -18
- data/test/stripe/dispute_test.rb +8 -10
- data/test/stripe/file_upload_test.rb +3 -3
- data/test/stripe/invoice_item_test.rb +9 -11
- data/test/stripe/invoice_line_item_test.rb +0 -1
- data/test/stripe/invoice_test.rb +39 -21
- data/test/stripe/list_object_test.rb +1 -1
- data/test/stripe/login_link_test.rb +6 -7
- data/test/stripe/order_return_test.rb +2 -4
- data/test/stripe/order_test.rb +10 -12
- data/test/stripe/payout_test.rb +7 -9
- data/test/stripe/plan_test.rb +8 -10
- data/test/stripe/product_test.rb +8 -10
- data/test/stripe/recipient_card_test.rb +13 -9
- data/test/stripe/recipient_test.rb +8 -10
- data/test/stripe/refund_test.rb +7 -9
- data/test/stripe/reversal_test.rb +5 -7
- data/test/stripe/sku_test.rb +9 -11
- data/test/stripe/source_test.rb +16 -15
- data/test/stripe/stripe_client_test.rb +190 -26
- data/test/stripe/subscription_item_test.rb +12 -14
- data/test/stripe/subscription_test.rb +10 -12
- data/test/stripe/three_d_secure_test.rb +3 -5
- data/test/stripe/transfer_test.rb +7 -9
- data/test/stripe/util_test.rb +164 -0
- data/test/test_helper.rb +33 -18
- metadata +2 -8
- data/openapi/fixtures.json +0 -1896
- data/openapi/fixtures.yaml +0 -1505
- data/openapi/spec2.json +0 -24601
- data/openapi/spec2.yaml +0 -18801
- data/test/api_fixtures.rb +0 -29
data/lib/stripe/util.rb
CHANGED
@@ -89,6 +89,20 @@ module Stripe
|
|
89
89
|
end
|
90
90
|
end
|
91
91
|
|
92
|
+
def self.log_info(message, data = {})
|
93
|
+
if Stripe.log_level == Stripe::LEVEL_DEBUG ||Stripe.log_level == Stripe::LEVEL_INFO
|
94
|
+
log_internal(message, data, color: :cyan,
|
95
|
+
level: Stripe::LEVEL_INFO, out: $stdout)
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
def self.log_debug(message, data = {})
|
100
|
+
if Stripe.log_level == Stripe::LEVEL_DEBUG
|
101
|
+
log_internal(message, data, color: :blue,
|
102
|
+
level: Stripe::LEVEL_DEBUG, out: $stdout)
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
92
106
|
def self.file_readable(file)
|
93
107
|
# This is nominally equivalent to File.readable?, but that can
|
94
108
|
# report incorrect results on some more oddball filesystems
|
@@ -220,8 +234,59 @@ module Stripe
|
|
220
234
|
key
|
221
235
|
end
|
222
236
|
|
237
|
+
# Normalizes header keys so that they're all lower case and each
|
238
|
+
# hyphen-delimited section starts with a single capitalized letter. For
|
239
|
+
# example, `request-id` becomes `Request-Id`. This is useful for extracting
|
240
|
+
# certain key values when the user could have set them with a variety of
|
241
|
+
# diffent naming schemes.
|
242
|
+
def self.normalize_headers(headers)
|
243
|
+
headers.inject({}) do |new_headers, (k, v)|
|
244
|
+
if k.is_a?(Symbol)
|
245
|
+
k = titlecase_parts(k.to_s.gsub("_", "-"))
|
246
|
+
elsif k.is_a?(String)
|
247
|
+
k = titlecase_parts(k)
|
248
|
+
end
|
249
|
+
|
250
|
+
new_headers[k] = v
|
251
|
+
new_headers
|
252
|
+
end
|
253
|
+
end
|
254
|
+
|
255
|
+
# Generates a Dashboard link to inspect a request ID based off of a request
|
256
|
+
# ID value and an API key, which is used to attempt to extract whether the
|
257
|
+
# environment is livemode or testmode.
|
258
|
+
def self.request_id_dashboard_url(request_id, api_key)
|
259
|
+
env = !api_key.nil? && api_key.start_with?("sk_live") ? "live" : "test"
|
260
|
+
"https://dashboard.stripe.com/#{env}/logs/#{request_id}"
|
261
|
+
end
|
262
|
+
|
263
|
+
# Constant time string comparison to prevent timing attacks
|
264
|
+
# Code borrowed from ActiveSupport
|
265
|
+
def self.secure_compare(a, b)
|
266
|
+
return false unless a.bytesize == b.bytesize
|
267
|
+
|
268
|
+
l = a.unpack "C#{a.bytesize}"
|
269
|
+
|
270
|
+
res = 0
|
271
|
+
b.each_byte { |byte| res |= byte ^ l.shift }
|
272
|
+
res == 0
|
273
|
+
end
|
274
|
+
|
223
275
|
private
|
224
276
|
|
277
|
+
COLOR_CODES = {
|
278
|
+
:black => 0, :light_black => 60,
|
279
|
+
:red => 1, :light_red => 61,
|
280
|
+
:green => 2, :light_green => 62,
|
281
|
+
:yellow => 3, :light_yellow => 63,
|
282
|
+
:blue => 4, :light_blue => 64,
|
283
|
+
:magenta => 5, :light_magenta => 65,
|
284
|
+
:cyan => 6, :light_cyan => 66,
|
285
|
+
:white => 7, :light_white => 67,
|
286
|
+
:default => 9
|
287
|
+
}
|
288
|
+
private_constant :COLOR_CODES
|
289
|
+
|
225
290
|
# We use a pretty janky version of form encoding (Rack's) that supports
|
226
291
|
# more complex data structures like maps and arrays through the use of
|
227
292
|
# specialized syntax. To encode an array of maps like:
|
@@ -258,17 +323,71 @@ module Stripe
|
|
258
323
|
end
|
259
324
|
end
|
260
325
|
end
|
326
|
+
private_class_method :check_array_of_maps_start_keys!
|
261
327
|
|
262
|
-
#
|
263
|
-
#
|
264
|
-
def self.
|
265
|
-
return
|
328
|
+
# Uses an ANSI escape code to colorize text if it's going to be sent to a
|
329
|
+
# TTY.
|
330
|
+
def self.colorize(val, color, isatty)
|
331
|
+
return val unless isatty
|
266
332
|
|
267
|
-
|
333
|
+
mode = 0 # default
|
334
|
+
foreground = 30 + COLOR_CODES.fetch(color)
|
335
|
+
background = 40 + COLOR_CODES.fetch(:default)
|
268
336
|
|
269
|
-
|
270
|
-
|
271
|
-
|
337
|
+
"\033[#{mode};#{foreground};#{background}m#{val}\033[0m"
|
338
|
+
end
|
339
|
+
private_class_method :colorize
|
340
|
+
|
341
|
+
# TODO: Make these named required arguments when we drop support for Ruby
|
342
|
+
# 2.0.
|
343
|
+
def self.log_internal(message, data = {}, color: nil, level: nil, out: nil)
|
344
|
+
data_str = data.select { |k,v| !v.nil? }.
|
345
|
+
map { |(k,v)|
|
346
|
+
"%s=%s" % [
|
347
|
+
colorize(k, color, out.isatty),
|
348
|
+
wrap_logfmt_value(v)
|
349
|
+
]
|
350
|
+
}.join(" ")
|
351
|
+
|
352
|
+
if out.isatty
|
353
|
+
out.puts "%s %s %s" %
|
354
|
+
[colorize(level[0, 4].upcase, color, out.isatty), message, data_str]
|
355
|
+
else
|
356
|
+
out.puts "message=%s level=%s %s" %
|
357
|
+
[wrap_logfmt_value(message), level, data_str]
|
358
|
+
end
|
359
|
+
end
|
360
|
+
private_class_method :log_internal
|
361
|
+
|
362
|
+
def self.titlecase_parts(s)
|
363
|
+
s.split("-").
|
364
|
+
select { |p| p != "" }.
|
365
|
+
map { |p| p[0].upcase + p[1..-1].downcase }.
|
366
|
+
join("-")
|
367
|
+
end
|
368
|
+
private_class_method :titlecase_parts
|
369
|
+
|
370
|
+
# Wraps a value in double quotes if it looks sufficiently complex so that
|
371
|
+
# it can be read by logfmt parsers.
|
372
|
+
def self.wrap_logfmt_value(val)
|
373
|
+
# If value is any kind of number, just allow it to be formatted directly
|
374
|
+
# to a string (this will handle integers or floats).
|
375
|
+
return val if val.is_a?(Numeric)
|
376
|
+
|
377
|
+
# Hopefully val is a string, but protect in case it's not.
|
378
|
+
val = val.to_s
|
379
|
+
|
380
|
+
if %r{[^\w\-/]} =~ val
|
381
|
+
# If the string contains any special characters, escape any double
|
382
|
+
# quotes it has, remove newlines, and wrap the whole thing in quotes.
|
383
|
+
%{"%s"} % val.gsub('"', '\"').gsub("\n", "")
|
384
|
+
else
|
385
|
+
# Otherwise use the basic value if it looks like a standard set of
|
386
|
+
# characters (and allow a few special characters like hyphens, and
|
387
|
+
# slashes)
|
388
|
+
val
|
389
|
+
end
|
272
390
|
end
|
391
|
+
private_class_method :wrap_logfmt_value
|
273
392
|
end
|
274
393
|
end
|
data/lib/stripe/version.rb
CHANGED
data/test/api_stub_helpers.rb
CHANGED
@@ -1,125 +0,0 @@
|
|
1
|
-
require "json"
|
2
|
-
|
3
|
-
# Provides a set of helpers for a test suite that help to mock out the Stripe
|
4
|
-
# API.
|
5
|
-
module APIStubHelpers
|
6
|
-
protected
|
7
|
-
|
8
|
-
# Uses Webmock to stub out the Stripe API for testing purposes. The stub will
|
9
|
-
# by default respond on any routes that are defined in the bundled OpenAPI
|
10
|
-
# spec with generated response data.
|
11
|
-
#
|
12
|
-
# An `override_app` can be specified to get finer grain control over how a
|
13
|
-
# stubbed endpoint responds. It can be used to modify generated responses,
|
14
|
-
# mock expectations, or even to override the default stub completely.
|
15
|
-
def stub_api
|
16
|
-
stub_request(:any, /^#{Stripe.api_base}/).to_rack(new_api_stub)
|
17
|
-
end
|
18
|
-
|
19
|
-
def stub_connect
|
20
|
-
stub_request(:any, /^#{Stripe.connect_base}/).to_return(:body => "{}")
|
21
|
-
end
|
22
|
-
|
23
|
-
private
|
24
|
-
|
25
|
-
# APIStubMiddleware intercepts a response generated by Committee's stubbing
|
26
|
-
# middleware, and tries to replace it with a better version from a set of
|
27
|
-
# sample fixtures data generated from Stripe's core API service.
|
28
|
-
class APIStubMiddleware
|
29
|
-
API_FIXTURES = APIFixtures.new
|
30
|
-
|
31
|
-
def initialize(app)
|
32
|
-
@app = app
|
33
|
-
end
|
34
|
-
|
35
|
-
def call(env)
|
36
|
-
# We use a vendor specific prefix (`x-resourceId`) embedded in the schema
|
37
|
-
# of any resource in our spec to identify it (e.g. "charge"). This allows
|
38
|
-
# us to cross-reference that response with some data that we might find
|
39
|
-
# in our fixtures file so that we can respond with a higher fidelity
|
40
|
-
# response.
|
41
|
-
schema = env["committee.response_schema"]
|
42
|
-
resource_id = schema.data["x-resourceId"] || ""
|
43
|
-
|
44
|
-
if data = API_FIXTURES[resource_id.to_sym]
|
45
|
-
# standard top-level API resource
|
46
|
-
data = fixturize_lists_recursively(schema, data)
|
47
|
-
env["committee.response"] = data
|
48
|
-
elsif schema.properties["object"].enum == ["list"]
|
49
|
-
# top level list (like from a list endpoint)
|
50
|
-
data = fixturize_list(schema, env["committee.response"])
|
51
|
-
env["committee.response"] = data
|
52
|
-
else
|
53
|
-
raise "no fixture for: #{resource_id}"
|
54
|
-
end
|
55
|
-
@app.call(env)
|
56
|
-
end
|
57
|
-
|
58
|
-
private
|
59
|
-
|
60
|
-
# If schema looks like a Stripe list object, then we look up the resource
|
61
|
-
# that the list is supposed to include and inject it into `data` as a
|
62
|
-
# fixture. Also calls into that other schema recursively so that sublists
|
63
|
-
# within it will also be assigned a fixture.
|
64
|
-
def fixturize_list(schema, data)
|
65
|
-
object_schema = schema.properties["object"]
|
66
|
-
if object_schema && object_schema.enum == ["list"]
|
67
|
-
subschema = schema.properties["data"].items
|
68
|
-
resource_id = subschema.data["x-resourceId"] || ""
|
69
|
-
if subdata = API_FIXTURES[resource_id.to_sym]
|
70
|
-
subdata = fixturize_lists_recursively(subschema, subdata)
|
71
|
-
|
72
|
-
data = data ? data.dup : {}
|
73
|
-
data[:data] = [subdata]
|
74
|
-
end
|
75
|
-
end
|
76
|
-
data
|
77
|
-
end
|
78
|
-
|
79
|
-
# Examines each of the given schema's properties and calls #fixturize_list
|
80
|
-
# on them so that any sublists will be populated with sample fixture data.
|
81
|
-
def fixturize_lists_recursively(schema, data)
|
82
|
-
data = data.dup
|
83
|
-
schema.properties.each do |key, subschema|
|
84
|
-
data[key.to_sym] = fixturize_list(subschema, data[key.to_sym])
|
85
|
-
end
|
86
|
-
data
|
87
|
-
end
|
88
|
-
end
|
89
|
-
|
90
|
-
# A descendant of the standard `Sinatra::Base` that we can use to enrich
|
91
|
-
# certain types of responses.
|
92
|
-
class APIStubApp < Sinatra::Base
|
93
|
-
not_found do
|
94
|
-
"endpoint not found in API stub: #{request.request_method} #{request.path_info}"
|
95
|
-
end
|
96
|
-
end
|
97
|
-
|
98
|
-
# Finds the latest OpenAPI specification in ROOT/openapi/ and parses it for
|
99
|
-
# use with Committee.
|
100
|
-
def self.initialize_spec
|
101
|
-
spec_data = ::JSON.parse(File.read("#{PROJECT_ROOT}/openapi/spec2.json"))
|
102
|
-
|
103
|
-
driver = Committee::Drivers::OpenAPI2.new
|
104
|
-
driver.parse(spec_data)
|
105
|
-
end
|
106
|
-
|
107
|
-
# Creates a new Rack app with Committee middleware it.
|
108
|
-
def new_api_stub
|
109
|
-
Rack::Builder.new {
|
110
|
-
use Committee::Middleware::RequestValidation, schema: @@spec,
|
111
|
-
params_response: true, strict: true
|
112
|
-
use Committee::Middleware::Stub, schema: @@spec,
|
113
|
-
call: true
|
114
|
-
use APIStubMiddleware
|
115
|
-
run APIStubApp.new
|
116
|
-
}
|
117
|
-
end
|
118
|
-
|
119
|
-
# Parse and initialize the OpenAPI spec only once for the entire test suite.
|
120
|
-
@@spec = initialize_spec
|
121
|
-
|
122
|
-
# The default override app. Doesn't respond on any route so generated
|
123
|
-
# responses will always take precedence.
|
124
|
-
@@default_override_app = Sinatra.new
|
125
|
-
end
|
data/test/stripe/account_test.rb
CHANGED
@@ -2,8 +2,6 @@ require File.expand_path('../../test_helper', __FILE__)
|
|
2
2
|
|
3
3
|
module Stripe
|
4
4
|
class AccountTest < Test::Unit::TestCase
|
5
|
-
FIXTURE = API_FIXTURES.fetch(:account)
|
6
|
-
|
7
5
|
should "be listable" do
|
8
6
|
accounts = Stripe::Account.list
|
9
7
|
assert_requested :get, "#{Stripe.api_base}/v1/accounts"
|
@@ -18,8 +16,8 @@ module Stripe
|
|
18
16
|
end
|
19
17
|
|
20
18
|
should "be retrievable using plural endpoint" do
|
21
|
-
account = Stripe::Account.retrieve(
|
22
|
-
assert_requested :get, "#{Stripe.api_base}/v1/accounts
|
19
|
+
account = Stripe::Account.retrieve("acct_123")
|
20
|
+
assert_requested :get, "#{Stripe.api_base}/v1/accounts/acct_123"
|
23
21
|
assert account.kind_of?(Stripe::Account)
|
24
22
|
end
|
25
23
|
|
@@ -42,22 +40,22 @@ module Stripe
|
|
42
40
|
end
|
43
41
|
|
44
42
|
should "be saveable" do
|
45
|
-
account = Stripe::Account.retrieve(
|
43
|
+
account = Stripe::Account.retrieve("acct_123")
|
46
44
|
account.metadata['key'] = 'value'
|
47
45
|
account.save
|
48
|
-
assert_requested :post, "#{Stripe.api_base}/v1/accounts/#{
|
46
|
+
assert_requested :post, "#{Stripe.api_base}/v1/accounts/#{account.id}"
|
49
47
|
end
|
50
48
|
|
51
49
|
should "be updateable" do
|
52
|
-
account = Stripe::Account.update(
|
53
|
-
assert_requested :post, "#{Stripe.api_base}/v1/accounts
|
50
|
+
account = Stripe::Account.update("acct_123", metadata: {foo: 'bar'})
|
51
|
+
assert_requested :post, "#{Stripe.api_base}/v1/accounts/acct_123"
|
54
52
|
assert account.kind_of?(Stripe::Account)
|
55
53
|
end
|
56
54
|
|
57
55
|
should "be deletable" do
|
58
|
-
account = Stripe::Account.retrieve(
|
56
|
+
account = Stripe::Account.retrieve("acct_123")
|
59
57
|
account = account.delete
|
60
|
-
assert_requested :delete, "#{Stripe.api_base}/v1/accounts/#{
|
58
|
+
assert_requested :delete, "#{Stripe.api_base}/v1/accounts/#{account.id}"
|
61
59
|
assert account.kind_of?(Stripe::Account)
|
62
60
|
end
|
63
61
|
|
@@ -66,7 +64,7 @@ module Stripe
|
|
66
64
|
old_stderr = $stderr
|
67
65
|
$stderr = StringIO.new
|
68
66
|
begin
|
69
|
-
account = Stripe::Account.retrieve(
|
67
|
+
account = Stripe::Account.retrieve("acct_123")
|
70
68
|
account.bank_account = "tok_123"
|
71
69
|
message = "NOTE: Stripe::Account#bank_account= is " +
|
72
70
|
"deprecated; use #external_account= instead"
|
@@ -79,7 +77,7 @@ module Stripe
|
|
79
77
|
|
80
78
|
context "#deauthorize" do
|
81
79
|
should "deauthorize an account" do
|
82
|
-
account = Stripe::Account.retrieve(
|
80
|
+
account = Stripe::Account.retrieve("acct_123")
|
83
81
|
|
84
82
|
# Unfortunately, the OpenAPI spec doesn't yet cover anything under the
|
85
83
|
# Connect endpoints, so for just stub this out with Webmock.
|
@@ -92,7 +90,7 @@ module Stripe
|
|
92
90
|
|
93
91
|
context "#legal_entity=" do
|
94
92
|
should 'disallow direct overrides' do
|
95
|
-
account = Stripe::Account.retrieve(
|
93
|
+
account = Stripe::Account.retrieve("acct_123")
|
96
94
|
|
97
95
|
assert_raise NoMethodError do
|
98
96
|
account.legal_entity = {:first_name => 'Blah'}
|
@@ -2,17 +2,15 @@ require File.expand_path('../../test_helper', __FILE__)
|
|
2
2
|
|
3
3
|
module Stripe
|
4
4
|
class AlipayAccountTest < Test::Unit::TestCase
|
5
|
-
FIXTURE = API_FIXTURES.fetch(:alipay_account)
|
6
|
-
|
7
5
|
should "raise on #retrieve" do
|
8
6
|
assert_raises NotImplementedError do
|
9
|
-
Stripe::AlipayAccount.retrieve
|
7
|
+
Stripe::AlipayAccount.retrieve("aliacc_123")
|
10
8
|
end
|
11
9
|
end
|
12
10
|
|
13
11
|
should "raise on #update" do
|
14
12
|
assert_raises NotImplementedError do
|
15
|
-
Stripe::AlipayAccount.update
|
13
|
+
Stripe::AlipayAccount.update("aliacc_123", {})
|
16
14
|
end
|
17
15
|
end
|
18
16
|
end
|
@@ -38,14 +38,14 @@ module Stripe
|
|
38
38
|
end
|
39
39
|
|
40
40
|
should "setting an attribute should not cause a network request" do
|
41
|
-
c = Stripe::Customer.new("
|
41
|
+
c = Stripe::Customer.new("cus_123");
|
42
42
|
c.card = {:id => "somecard", :object => "card"}
|
43
43
|
assert_not_requested :get, %r{#{Stripe.api_base}/.*}
|
44
44
|
assert_not_requested :post, %r{#{Stripe.api_base}/.*}
|
45
45
|
end
|
46
46
|
|
47
47
|
should "accessing id should not issue a fetch" do
|
48
|
-
c = Stripe::Customer.new("
|
48
|
+
c = Stripe::Customer.new("cus_123")
|
49
49
|
c.id
|
50
50
|
assert_not_requested :get, %r{#{Stripe.api_base}/.*}
|
51
51
|
end
|
@@ -53,7 +53,7 @@ module Stripe
|
|
53
53
|
should "not specifying api credentials should raise an exception" do
|
54
54
|
Stripe.api_key = nil
|
55
55
|
assert_raises Stripe::AuthenticationError do
|
56
|
-
Stripe::Customer.new("
|
56
|
+
Stripe::Customer.new("cus_123").refresh
|
57
57
|
end
|
58
58
|
end
|
59
59
|
|
@@ -69,36 +69,36 @@ module Stripe
|
|
69
69
|
should "specifying api credentials containing whitespace should raise an exception" do
|
70
70
|
Stripe.api_key = "key "
|
71
71
|
assert_raises Stripe::AuthenticationError do
|
72
|
-
Stripe::Customer.new("
|
72
|
+
Stripe::Customer.new("cus_123").refresh
|
73
73
|
end
|
74
74
|
end
|
75
75
|
|
76
76
|
should "send expand on fetch properly" do
|
77
|
-
stub_request(:get, "#{Stripe.api_base}/v1/charges/
|
77
|
+
stub_request(:get, "#{Stripe.api_base}/v1/charges/ch_123").
|
78
78
|
with(query: { "expand" => ["customer"] }).
|
79
|
-
to_return(body: JSON.generate(
|
79
|
+
to_return(body: JSON.generate(charge_fixture))
|
80
80
|
|
81
|
-
Stripe::Charge.retrieve({:id => '
|
81
|
+
Stripe::Charge.retrieve({:id => 'ch_123', :expand => [:customer]})
|
82
82
|
end
|
83
83
|
|
84
84
|
should "preserve expand across refreshes" do
|
85
|
-
stub_request(:get, "#{Stripe.api_base}/v1/charges/
|
85
|
+
stub_request(:get, "#{Stripe.api_base}/v1/charges/ch_123").
|
86
86
|
with(query: { "expand" => ["customer"] }).
|
87
|
-
to_return(body: JSON.generate(
|
87
|
+
to_return(body: JSON.generate(charge_fixture))
|
88
88
|
|
89
|
-
ch = Stripe::Charge.retrieve({:id => '
|
89
|
+
ch = Stripe::Charge.retrieve({:id => 'ch_123', :expand => :customer})
|
90
90
|
ch.refresh
|
91
91
|
end
|
92
92
|
|
93
93
|
should "send expand when fetching through ListObject" do
|
94
|
-
stub_request(:get, "#{Stripe.api_base}/v1/customers/
|
95
|
-
to_return(body: JSON.generate(
|
94
|
+
stub_request(:get, "#{Stripe.api_base}/v1/customers/cus_123").
|
95
|
+
to_return(body: JSON.generate(customer_fixture))
|
96
96
|
|
97
|
-
stub_request(:get, "#{Stripe.api_base}/v1/customers/
|
97
|
+
stub_request(:get, "#{Stripe.api_base}/v1/customers/cus_123/sources/cc_test_card").
|
98
98
|
with(query: { "expand" => ["customer"] }).
|
99
|
-
to_return(body: JSON.generate(
|
99
|
+
to_return(body: JSON.generate(customer_fixture))
|
100
100
|
|
101
|
-
customer = Stripe::Customer.retrieve('
|
101
|
+
customer = Stripe::Customer.retrieve('cus_123')
|
102
102
|
customer.sources.retrieve({:id => 'cc_test_card', :expand => :customer})
|
103
103
|
end
|
104
104
|
|
@@ -107,7 +107,7 @@ module Stripe
|
|
107
107
|
should "use the per-object credential when creating" do
|
108
108
|
stub_request(:post, "#{Stripe.api_base}/v1/charges").
|
109
109
|
with(headers: {"Authorization" => "Bearer sk_test_local"}).
|
110
|
-
to_return(body: JSON.generate(
|
110
|
+
to_return(body: JSON.generate(charge_fixture))
|
111
111
|
|
112
112
|
Stripe::Charge.create({:source => 'tok_visa'},
|
113
113
|
'sk_test_local')
|
@@ -125,22 +125,22 @@ module Stripe
|
|
125
125
|
|
126
126
|
should "use the per-object credential when creating" do
|
127
127
|
stub_request(:post, "#{Stripe.api_base}/v1/charges").
|
128
|
-
with(headers: {"Authorization" => "Bearer
|
129
|
-
to_return(body: JSON.generate(
|
128
|
+
with(headers: {"Authorization" => "Bearer sk_test_local"}).
|
129
|
+
to_return(body: JSON.generate(charge_fixture))
|
130
130
|
|
131
131
|
Stripe::Charge.create({:source => 'tok_visa'},
|
132
|
-
'
|
132
|
+
'sk_test_local')
|
133
133
|
end
|
134
134
|
|
135
135
|
should "use the per-object credential when retrieving and making other calls" do
|
136
|
-
stub_request(:get, "#{Stripe.api_base}/v1/charges/
|
137
|
-
with(headers: {"Authorization" => "Bearer
|
138
|
-
to_return(body: JSON.generate(
|
139
|
-
stub_request(:post, "#{Stripe.api_base}/v1/charges/
|
140
|
-
with(headers: {"Authorization" => "Bearer
|
141
|
-
to_return(body:
|
142
|
-
|
143
|
-
ch = Stripe::Charge.retrieve('
|
136
|
+
stub_request(:get, "#{Stripe.api_base}/v1/charges/ch_123").
|
137
|
+
with(headers: {"Authorization" => "Bearer sk_test_local"}).
|
138
|
+
to_return(body: JSON.generate(charge_fixture))
|
139
|
+
stub_request(:post, "#{Stripe.api_base}/v1/charges/ch_123/refunds").
|
140
|
+
with(headers: {"Authorization" => "Bearer sk_test_local"}).
|
141
|
+
to_return(body: "{}")
|
142
|
+
|
143
|
+
ch = Stripe::Charge.retrieve('ch_123', 'sk_test_local')
|
144
144
|
ch.refunds.create
|
145
145
|
end
|
146
146
|
end
|
@@ -151,45 +151,45 @@ module Stripe
|
|
151
151
|
stub_request(:get, "#{Stripe.api_base}/v1/charges").
|
152
152
|
with(query: { customer: "test customer" }).
|
153
153
|
to_return(body: JSON.generate({
|
154
|
-
data: [
|
154
|
+
data: [charge_fixture]
|
155
155
|
}))
|
156
156
|
charges = Stripe::Charge.list(:customer => 'test customer').data
|
157
157
|
assert charges.kind_of? Array
|
158
158
|
end
|
159
159
|
|
160
160
|
should "construct URL properly with base query parameters" do
|
161
|
-
stub_request(:get, "#{Stripe.api_base}/v1/
|
162
|
-
with(query: { customer: "
|
161
|
+
stub_request(:get, "#{Stripe.api_base}/v1/charges").
|
162
|
+
with(query: { customer: "cus_123" }).
|
163
163
|
to_return(body: JSON.generate({
|
164
|
-
data: [
|
165
|
-
url: "/v1/
|
164
|
+
data: [charge_fixture],
|
165
|
+
url: "/v1/charges"
|
166
166
|
}))
|
167
|
-
|
167
|
+
charges = Stripe::Invoice.list(:customer => 'cus_123')
|
168
168
|
|
169
|
-
stub_request(:get, "#{Stripe.api_base}/v1/
|
170
|
-
with(query: { customer: "
|
169
|
+
stub_request(:get, "#{Stripe.api_base}/v1/charges").
|
170
|
+
with(query: { customer: "cus_123", created: "123" }).
|
171
171
|
to_return(body: JSON.generate({
|
172
|
-
data: [
|
173
|
-
url: "/v1/
|
172
|
+
data: [charge_fixture],
|
173
|
+
url: "/v1/charges"
|
174
174
|
}))
|
175
|
-
|
175
|
+
charges.list(:created => 123)
|
176
176
|
end
|
177
177
|
|
178
178
|
should "setting a nil value for a param should exclude that param from the request" do
|
179
179
|
stub_request(:get, "#{Stripe.api_base}/v1/charges").
|
180
180
|
with(query: { offset: 5, sad: false }).
|
181
|
-
to_return(body: JSON.generate({ :count => 1, :data => [
|
181
|
+
to_return(body: JSON.generate({ :count => 1, :data => [charge_fixture] }))
|
182
182
|
Stripe::Charge.list(:count => nil, :offset => 5, :sad => false)
|
183
183
|
|
184
184
|
stub_request(:post, "#{Stripe.api_base}/v1/charges").
|
185
185
|
with(body: { 'amount' => '50', 'currency' => 'usd' }).
|
186
|
-
to_return(body: JSON.generate({ :count => 1, :data => [
|
186
|
+
to_return(body: JSON.generate({ :count => 1, :data => [charge_fixture] }))
|
187
187
|
Stripe::Charge.create(:amount => 50, :currency => 'usd', :card => { :number => nil })
|
188
188
|
end
|
189
189
|
|
190
190
|
should "not trigger a warning if a known opt, such as idempotency_key, is in opts" do
|
191
191
|
stub_request(:post, "#{Stripe.api_base}/v1/charges").
|
192
|
-
to_return(body: JSON.generate(
|
192
|
+
to_return(body: JSON.generate(charge_fixture))
|
193
193
|
old_stderr = $stderr
|
194
194
|
$stderr = StringIO.new
|
195
195
|
begin
|
@@ -202,7 +202,7 @@ module Stripe
|
|
202
202
|
|
203
203
|
should "trigger a warning if a known opt, such as idempotency_key, is in params" do
|
204
204
|
stub_request(:post, "#{Stripe.api_base}/v1/charges").
|
205
|
-
to_return(body: JSON.generate(
|
205
|
+
to_return(body: JSON.generate(charge_fixture))
|
206
206
|
old_stderr = $stderr
|
207
207
|
$stderr = StringIO.new
|
208
208
|
begin
|
@@ -228,28 +228,28 @@ module Stripe
|
|
228
228
|
should "making a GET request with parameters should have a query string and no body" do
|
229
229
|
stub_request(:get, "#{Stripe.api_base}/v1/charges").
|
230
230
|
with(query: { limit: 1 }).
|
231
|
-
to_return(body: JSON.generate({ :data => [
|
231
|
+
to_return(body: JSON.generate({ :data => [charge_fixture] }))
|
232
232
|
Stripe::Charge.list({ :limit => 1 })
|
233
233
|
end
|
234
234
|
|
235
235
|
should "making a POST request with parameters should have a body and no query string" do
|
236
236
|
stub_request(:post, "#{Stripe.api_base}/v1/charges").
|
237
237
|
with(body: {'amount' => '100', 'currency' => 'usd', 'card' => 'sc_token'}).
|
238
|
-
to_return(body: JSON.generate(
|
238
|
+
to_return(body: JSON.generate(charge_fixture))
|
239
239
|
Stripe::Charge.create({ :amount => 100, :currency => 'usd', :card => 'sc_token' })
|
240
240
|
end
|
241
241
|
|
242
242
|
should "loading an object should issue a GET request" do
|
243
|
-
stub_request(:get, "#{Stripe.api_base}/v1/
|
244
|
-
to_return(body: JSON.generate(
|
245
|
-
c = Stripe::
|
243
|
+
stub_request(:get, "#{Stripe.api_base}/v1/charges/ch_123").
|
244
|
+
to_return(body: JSON.generate(charge_fixture))
|
245
|
+
c = Stripe::Charge.new("ch_123")
|
246
246
|
c.refresh
|
247
247
|
end
|
248
248
|
|
249
249
|
should "using array accessors should be the same as the method interface" do
|
250
|
-
stub_request(:get, "#{Stripe.api_base}/v1/
|
251
|
-
to_return(body: JSON.generate(
|
252
|
-
c = Stripe::
|
250
|
+
stub_request(:get, "#{Stripe.api_base}/v1/charges/ch_123").
|
251
|
+
to_return(body: JSON.generate(charge_fixture))
|
252
|
+
c = Stripe::Charge.new("cus_123")
|
253
253
|
c.refresh
|
254
254
|
assert_equal c.created, c[:created]
|
255
255
|
assert_equal c.created, c['created']
|
@@ -259,26 +259,26 @@ module Stripe
|
|
259
259
|
|
260
260
|
should "accessing a property other than id or parent on an unfetched object should fetch it" do
|
261
261
|
stub_request(:get, "#{Stripe.api_base}/v1/charges").
|
262
|
-
with(query: { customer: "
|
263
|
-
to_return(body: JSON.generate(
|
264
|
-
c = Stripe::Customer.new("
|
262
|
+
with(query: { customer: "cus_123" }).
|
263
|
+
to_return(body: JSON.generate(customer_fixture))
|
264
|
+
c = Stripe::Customer.new("cus_123")
|
265
265
|
c.charges
|
266
266
|
end
|
267
267
|
|
268
268
|
should "updating an object should issue a POST request with only the changed properties" do
|
269
|
-
stub_request(:post, "#{Stripe.api_base}/v1/customers/
|
269
|
+
stub_request(:post, "#{Stripe.api_base}/v1/customers/cus_123").
|
270
270
|
with(body: { 'description' => 'another_mn' }).
|
271
|
-
to_return(body: JSON.generate(
|
272
|
-
c = Stripe::Customer.construct_from(
|
271
|
+
to_return(body: JSON.generate(customer_fixture))
|
272
|
+
c = Stripe::Customer.construct_from(customer_fixture)
|
273
273
|
c.description = "another_mn"
|
274
274
|
c.save
|
275
275
|
end
|
276
276
|
|
277
277
|
should "updating should merge in returned properties" do
|
278
|
-
stub_request(:post, "#{Stripe.api_base}/v1/customers/
|
278
|
+
stub_request(:post, "#{Stripe.api_base}/v1/customers/cus_123").
|
279
279
|
with(body: { 'description' => 'another_mn' }).
|
280
|
-
to_return(body: JSON.generate(
|
281
|
-
c = Stripe::Customer.new("
|
280
|
+
to_return(body: JSON.generate(customer_fixture))
|
281
|
+
c = Stripe::Customer.new("cus_123")
|
282
282
|
c.description = "another_mn"
|
283
283
|
c.save
|
284
284
|
assert_equal false, c.livemode
|
@@ -294,23 +294,23 @@ module Stripe
|
|
294
294
|
should "updating should use the supplied api_key" do
|
295
295
|
stub_request(:post, "#{Stripe.api_base}/v1/customers").
|
296
296
|
with(headers: {"Authorization" => "Bearer sk_test_local"}).
|
297
|
-
to_return(body: JSON.generate(
|
297
|
+
to_return(body: JSON.generate(customer_fixture))
|
298
298
|
c = Stripe::Customer.new
|
299
299
|
c.save({}, { :api_key => 'sk_test_local' })
|
300
300
|
assert_equal false, c.livemode
|
301
301
|
end
|
302
302
|
|
303
303
|
should "deleting should send no props and result in an object that has no props other deleted" do
|
304
|
-
stub_request(:delete, "#{Stripe.api_base}/v1/customers/
|
305
|
-
to_return(body: JSON.generate({ "id" => "
|
306
|
-
c = Stripe::Customer.construct_from(
|
304
|
+
stub_request(:delete, "#{Stripe.api_base}/v1/customers/cus_123").
|
305
|
+
to_return(body: JSON.generate({ "id" => "cus_123", "deleted" => true }))
|
306
|
+
c = Stripe::Customer.construct_from(customer_fixture)
|
307
307
|
c.delete
|
308
308
|
end
|
309
309
|
|
310
310
|
should "loading all of an APIResource should return an array of recursively instantiated objects" do
|
311
311
|
stub_request(:get, "#{Stripe.api_base}/v1/charges").
|
312
312
|
to_return(body: JSON.generate({
|
313
|
-
data: [
|
313
|
+
data: [charge_fixture]
|
314
314
|
}))
|
315
315
|
charges = Stripe::Charge.list.data
|
316
316
|
assert charges.kind_of? Array
|
@@ -319,21 +319,21 @@ module Stripe
|
|
319
319
|
end
|
320
320
|
|
321
321
|
should "passing in a stripe_account header should pass it through on call" do
|
322
|
-
stub_request(:get, "#{Stripe.api_base}/v1/customers/
|
323
|
-
with(headers: {"Stripe-Account" => "
|
324
|
-
to_return(body: JSON.generate(
|
325
|
-
Stripe::Customer.retrieve("
|
322
|
+
stub_request(:get, "#{Stripe.api_base}/v1/customers/cus_123").
|
323
|
+
with(headers: {"Stripe-Account" => "acct_123"}).
|
324
|
+
to_return(body: JSON.generate(customer_fixture))
|
325
|
+
Stripe::Customer.retrieve("cus_123", {:stripe_account => 'acct_123'})
|
326
326
|
end
|
327
327
|
|
328
328
|
should "passing in a stripe_account header should pass it through on save" do
|
329
|
-
stub_request(:get, "#{Stripe.api_base}/v1/customers/
|
330
|
-
with(headers: {"Stripe-Account" => "
|
331
|
-
to_return(body: JSON.generate(
|
332
|
-
c = Stripe::Customer.retrieve("
|
333
|
-
|
334
|
-
stub_request(:post, "#{Stripe.api_base}/v1/customers/
|
335
|
-
with(headers: {"Stripe-Account" => "
|
336
|
-
to_return(body: JSON.generate(
|
329
|
+
stub_request(:get, "#{Stripe.api_base}/v1/customers/cus_123").
|
330
|
+
with(headers: {"Stripe-Account" => "acct_123"}).
|
331
|
+
to_return(body: JSON.generate(customer_fixture))
|
332
|
+
c = Stripe::Customer.retrieve("cus_123", {:stripe_account => 'acct_123'})
|
333
|
+
|
334
|
+
stub_request(:post, "#{Stripe.api_base}/v1/customers/cus_123").
|
335
|
+
with(headers: {"Stripe-Account" => "acct_123"}).
|
336
|
+
to_return(body: JSON.generate(customer_fixture))
|
337
337
|
c.description = 'FOO'
|
338
338
|
c.save
|
339
339
|
end
|
@@ -518,5 +518,41 @@ module Stripe
|
|
518
518
|
account.save(:display_name => 'stripe', :metadata => {:key => 'value' })
|
519
519
|
end
|
520
520
|
end
|
521
|
+
|
522
|
+
@@fixtures = {}
|
523
|
+
setup do
|
524
|
+
if @@fixtures.empty?
|
525
|
+
set_fixture(:charge) do
|
526
|
+
Charge.retrieve("ch_123")
|
527
|
+
end
|
528
|
+
set_fixture(:customer) do
|
529
|
+
Customer.retrieve("cus_123")
|
530
|
+
end
|
531
|
+
end
|
532
|
+
end
|
533
|
+
|
534
|
+
private
|
535
|
+
|
536
|
+
def charge_fixture
|
537
|
+
@@fixtures[:charge]
|
538
|
+
end
|
539
|
+
|
540
|
+
def customer_fixture
|
541
|
+
@@fixtures[:customer]
|
542
|
+
end
|
543
|
+
|
544
|
+
def get_fixture(key)
|
545
|
+
@@fixtures.fetch(key)
|
546
|
+
end
|
547
|
+
|
548
|
+
# Expects to retrieve a fixture from stripe-mock (an API call should be
|
549
|
+
# included in the block to yield to) and does very simple memoization.
|
550
|
+
def set_fixture(key)
|
551
|
+
return @@fixtures[key] if @@fixtures.key?(key)
|
552
|
+
|
553
|
+
obj = yield
|
554
|
+
@@fixtures[key] = obj.instance_variable_get(:@values).freeze
|
555
|
+
@@fixtures[key]
|
556
|
+
end
|
521
557
|
end
|
522
558
|
end
|