mustwin-stripe-ruby-mock 1.8.4.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.gitignore +5 -0
- data/.rspec +1 -0
- data/.travis.yml +5 -0
- data/ChangeLog.rdoc +4 -0
- data/Gemfile +7 -0
- data/LICENSE.txt +22 -0
- data/README.md +264 -0
- data/Rakefile +28 -0
- data/bin/stripe-mock-server +19 -0
- data/lib/stripe_mock.rb +46 -0
- data/lib/stripe_mock/api/card_tokens.rb +22 -0
- data/lib/stripe_mock/api/client.rb +37 -0
- data/lib/stripe_mock/api/debug.rb +11 -0
- data/lib/stripe_mock/api/errors.rb +41 -0
- data/lib/stripe_mock/api/instance.rb +27 -0
- data/lib/stripe_mock/api/server.rb +24 -0
- data/lib/stripe_mock/api/strict.rb +11 -0
- data/lib/stripe_mock/api/webhooks.rb +64 -0
- data/lib/stripe_mock/client.rb +84 -0
- data/lib/stripe_mock/data.rb +317 -0
- data/lib/stripe_mock/error_queue.rb +23 -0
- data/lib/stripe_mock/errors/closed_client_connection_error.rb +9 -0
- data/lib/stripe_mock/errors/server_timeout_error.rb +12 -0
- data/lib/stripe_mock/errors/stripe_mock_error.rb +15 -0
- data/lib/stripe_mock/errors/uninitialized_instance_error.rb +9 -0
- data/lib/stripe_mock/errors/unstarted_state_error.rb +9 -0
- data/lib/stripe_mock/errors/unsupported_request_error.rb +4 -0
- data/lib/stripe_mock/instance.rb +108 -0
- data/lib/stripe_mock/request_handlers/charges.rb +33 -0
- data/lib/stripe_mock/request_handlers/customers.rb +107 -0
- data/lib/stripe_mock/request_handlers/invoice_items.rb +15 -0
- data/lib/stripe_mock/request_handlers/plans.rb +43 -0
- data/lib/stripe_mock/server.rb +58 -0
- data/lib/stripe_mock/util.rb +22 -0
- data/lib/stripe_mock/version.rb +4 -0
- data/lib/stripe_mock/webhook_fixtures/account.application.deauthorized.json +12 -0
- data/lib/stripe_mock/webhook_fixtures/account.updated.json +24 -0
- data/lib/stripe_mock/webhook_fixtures/charge.dispute.closed.json +21 -0
- data/lib/stripe_mock/webhook_fixtures/charge.dispute.created.json +21 -0
- data/lib/stripe_mock/webhook_fixtures/charge.dispute.updated.json +24 -0
- data/lib/stripe_mock/webhook_fixtures/charge.failed.json +57 -0
- data/lib/stripe_mock/webhook_fixtures/charge.refunded.json +57 -0
- data/lib/stripe_mock/webhook_fixtures/charge.succeeded.json +57 -0
- data/lib/stripe_mock/webhook_fixtures/coupon.created.json +22 -0
- data/lib/stripe_mock/webhook_fixtures/coupon.deleted.json +22 -0
- data/lib/stripe_mock/webhook_fixtures/customer.created.json +40 -0
- data/lib/stripe_mock/webhook_fixtures/customer.deleted.json +40 -0
- data/lib/stripe_mock/webhook_fixtures/customer.discount.created.json +28 -0
- data/lib/stripe_mock/webhook_fixtures/customer.discount.deleted.json +28 -0
- data/lib/stripe_mock/webhook_fixtures/customer.discount.updated.json +43 -0
- data/lib/stripe_mock/webhook_fixtures/customer.subscription.created.json +34 -0
- data/lib/stripe_mock/webhook_fixtures/customer.subscription.deleted.json +34 -0
- data/lib/stripe_mock/webhook_fixtures/customer.subscription.trial_will_end.json +34 -0
- data/lib/stripe_mock/webhook_fixtures/customer.subscription.updated.json +47 -0
- data/lib/stripe_mock/webhook_fixtures/customer.updated.json +43 -0
- data/lib/stripe_mock/webhook_fixtures/invoice.created.json +64 -0
- data/lib/stripe_mock/webhook_fixtures/invoice.payment_failed.json +64 -0
- data/lib/stripe_mock/webhook_fixtures/invoice.payment_succeeded.json +64 -0
- data/lib/stripe_mock/webhook_fixtures/invoice.updated.json +67 -0
- data/lib/stripe_mock/webhook_fixtures/invoiceitem.created.json +21 -0
- data/lib/stripe_mock/webhook_fixtures/invoiceitem.deleted.json +21 -0
- data/lib/stripe_mock/webhook_fixtures/invoiceitem.updated.json +24 -0
- data/lib/stripe_mock/webhook_fixtures/plan.created.json +20 -0
- data/lib/stripe_mock/webhook_fixtures/plan.deleted.json +20 -0
- data/lib/stripe_mock/webhook_fixtures/plan.updated.json +23 -0
- data/lib/stripe_mock/webhook_fixtures/transfer.created.json +23 -0
- data/lib/stripe_mock/webhook_fixtures/transfer.failed.json +23 -0
- data/lib/stripe_mock/webhook_fixtures/transfer.paid.json +23 -0
- data/lib/stripe_mock/webhook_fixtures/transfer.updated.json +26 -0
- data/lib/trollop.rb +782 -0
- data/spec/_dummy/webhooks/dummy.event.json +6 -0
- data/spec/fixtures/stripe_webhooks/account.updated.json +7 -0
- data/spec/fixtures/stripe_webhooks/custom.account.updated.json +5 -0
- data/spec/instance_spec.rb +49 -0
- data/spec/readme_spec.rb +72 -0
- data/spec/server_spec.rb +131 -0
- data/spec/shared_stripe_examples/card_token_examples.rb +28 -0
- data/spec/shared_stripe_examples/charge_examples.rb +123 -0
- data/spec/shared_stripe_examples/customer_examples.rb +218 -0
- data/spec/shared_stripe_examples/error_mock_examples.rb +152 -0
- data/spec/shared_stripe_examples/invoice_item_examples.rb +17 -0
- data/spec/shared_stripe_examples/plan_examples.rb +123 -0
- data/spec/spec_helper.rb +11 -0
- data/spec/stripe_mock_spec.rb +40 -0
- data/spec/support/stripe_examples.rb +18 -0
- data/spec/util_spec.rb +45 -0
- data/spec/webhook_spec.rb +77 -0
- data/stripe-ruby-mock.gemspec +27 -0
- metadata +253 -0
@@ -0,0 +1,23 @@
|
|
1
|
+
module StripeMock
|
2
|
+
class ErrorQueue
|
3
|
+
|
4
|
+
def initialize
|
5
|
+
@queue = []
|
6
|
+
end
|
7
|
+
|
8
|
+
def queue(error, handler_names)
|
9
|
+
@queue << handler_names.map {|n| [n, error]}
|
10
|
+
end
|
11
|
+
|
12
|
+
def error_for_handler_name(handler_name)
|
13
|
+
return nil if @queue.count == 0
|
14
|
+
triggers = @queue.first
|
15
|
+
(triggers.assoc(:all) || triggers.assoc(handler_name) || [])[1]
|
16
|
+
end
|
17
|
+
|
18
|
+
def dequeue
|
19
|
+
@queue.shift
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
module StripeMock
|
2
|
+
class ServerTimeoutError < StripeMockError
|
3
|
+
|
4
|
+
attr_reader :associated_error
|
5
|
+
|
6
|
+
def initialize(associated_error)
|
7
|
+
@associated_error = associated_error
|
8
|
+
super("Unable to connect to stripe mock server (did you forget to run `$ stripe-mock-server`?)")
|
9
|
+
end
|
10
|
+
|
11
|
+
end
|
12
|
+
end
|
@@ -0,0 +1,108 @@
|
|
1
|
+
module StripeMock
|
2
|
+
class Instance
|
3
|
+
|
4
|
+
# Handlers are ordered by priority
|
5
|
+
@@handlers = []
|
6
|
+
|
7
|
+
def self.add_handler(route, name)
|
8
|
+
@@handlers << {
|
9
|
+
:route => %r{^#{route}$},
|
10
|
+
:name => name
|
11
|
+
}
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.handler_for_method_url(method_url)
|
15
|
+
@@handlers.find {|h| method_url =~ h[:route] }
|
16
|
+
end
|
17
|
+
|
18
|
+
include StripeMock::RequestHandlers::Charges
|
19
|
+
include StripeMock::RequestHandlers::Customers
|
20
|
+
include StripeMock::RequestHandlers::InvoiceItems
|
21
|
+
include StripeMock::RequestHandlers::Plans
|
22
|
+
|
23
|
+
|
24
|
+
attr_reader :charges, :customers, :plans, :error_queue
|
25
|
+
attr_accessor :debug, :strict
|
26
|
+
|
27
|
+
def initialize
|
28
|
+
@customers = {}
|
29
|
+
@charges = {}
|
30
|
+
@plans = {}
|
31
|
+
@recipient_tokens = {}
|
32
|
+
@card_tokens = {}
|
33
|
+
|
34
|
+
@id_counter = 0
|
35
|
+
@error_queue = ErrorQueue.new
|
36
|
+
@debug = false
|
37
|
+
@strict = true
|
38
|
+
end
|
39
|
+
|
40
|
+
def mock_request(method, url, api_key, params={}, headers={})
|
41
|
+
return {} if method == :xtest
|
42
|
+
|
43
|
+
# Ensure params hash has symbols as keys
|
44
|
+
params = Stripe::Util.symbolize_names(params)
|
45
|
+
|
46
|
+
method_url = "#{method} #{url}"
|
47
|
+
|
48
|
+
if handler = Instance.handler_for_method_url(method_url)
|
49
|
+
if @debug == true
|
50
|
+
puts "[StripeMock req]::#{handler[:name]} #{method} #{url}"
|
51
|
+
puts " #{params}"
|
52
|
+
end
|
53
|
+
|
54
|
+
if mock_error = @error_queue.error_for_handler_name(handler[:name])
|
55
|
+
@error_queue.dequeue
|
56
|
+
raise mock_error
|
57
|
+
else
|
58
|
+
res = self.send(handler[:name], handler[:route], method_url, params, headers)
|
59
|
+
puts " [res] #{res}" if @debug == true
|
60
|
+
[res, api_key]
|
61
|
+
end
|
62
|
+
else
|
63
|
+
puts "WARNING: Unrecognized method + url: [#{method} #{url}]"
|
64
|
+
puts " params: #{params}"
|
65
|
+
[{}, api_key]
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
def generate_recipient_token(recipient_params)
|
70
|
+
token = new_id 'tok'
|
71
|
+
recipient_params[:id] = new_id 'rec'
|
72
|
+
@recipient_tokens[token] = Data.mock_card(recipient_params)
|
73
|
+
token
|
74
|
+
end
|
75
|
+
|
76
|
+
def generate_card_token(card_params)
|
77
|
+
token = new_id 'tok'
|
78
|
+
card_params[:id] = new_id 'cc'
|
79
|
+
@card_tokens[token] = Data.mock_card(card_params)
|
80
|
+
token
|
81
|
+
end
|
82
|
+
|
83
|
+
def get_card_by_token(token)
|
84
|
+
if token.nil? || @card_tokens[token].nil?
|
85
|
+
Data.mock_card :id => new_id('cc')
|
86
|
+
else
|
87
|
+
@card_tokens.delete(token)
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
private
|
92
|
+
|
93
|
+
def assert_existance(type, id, obj, message=nil)
|
94
|
+
return unless @strict == true
|
95
|
+
|
96
|
+
if obj.nil?
|
97
|
+
msg = message || "No such #{type}: #{id}"
|
98
|
+
raise Stripe::InvalidRequestError.new(msg, type.to_s, 404)
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
def new_id(prefix)
|
103
|
+
# Stripe ids must be strings
|
104
|
+
"test_#{prefix}_#{@id_counter += 1}"
|
105
|
+
end
|
106
|
+
|
107
|
+
end
|
108
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module StripeMock
|
2
|
+
module RequestHandlers
|
3
|
+
module Charges
|
4
|
+
|
5
|
+
def Charges.included(klass)
|
6
|
+
klass.add_handler 'post /v1/charges', :new_charge
|
7
|
+
klass.add_handler 'get /v1/charges/(.*)', :get_charge
|
8
|
+
klass.add_handler 'post /v1/charges/(.*)/capture', :capture_charge
|
9
|
+
end
|
10
|
+
|
11
|
+
def new_charge(route, method_url, params, headers)
|
12
|
+
id = new_id('ch')
|
13
|
+
charges[id] = Data.mock_charge(params.merge :id => id)
|
14
|
+
end
|
15
|
+
|
16
|
+
def get_charge(route, method_url, params, headers)
|
17
|
+
route =~ method_url
|
18
|
+
assert_existance :charge, $1, charges[$1]
|
19
|
+
charges[$1] ||= Data.mock_charge(:id => $1)
|
20
|
+
end
|
21
|
+
|
22
|
+
def capture_charge(route, method_url, params, headers)
|
23
|
+
route =~ method_url
|
24
|
+
charge = charges[$1]
|
25
|
+
assert_existance :charge, $1, charge
|
26
|
+
|
27
|
+
charge[:captured] = true
|
28
|
+
charge
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,107 @@
|
|
1
|
+
module StripeMock
|
2
|
+
module RequestHandlers
|
3
|
+
module Customers
|
4
|
+
|
5
|
+
def Customers.included(klass)
|
6
|
+
klass.add_handler 'post /v1/customers', :new_customer
|
7
|
+
klass.add_handler 'post /v1/customers/(.*)/subscription', :update_subscription
|
8
|
+
klass.add_handler 'delete /v1/customers/(.*)/subscription', :cancel_subscription
|
9
|
+
klass.add_handler 'post /v1/customers/(.*)', :update_customer
|
10
|
+
klass.add_handler 'get /v1/customers/(.*)', :get_customer
|
11
|
+
klass.add_handler 'delete /v1/customers/(.*)', :delete_customer
|
12
|
+
klass.add_handler 'get /v1/customers', :list_customers
|
13
|
+
end
|
14
|
+
|
15
|
+
def new_customer(route, method_url, params, headers)
|
16
|
+
params[:id] ||= new_id('cus')
|
17
|
+
cards = []
|
18
|
+
if params[:card]
|
19
|
+
cards << get_card_by_token(params.delete(:card))
|
20
|
+
params[:default_card] = cards.first[:id]
|
21
|
+
end
|
22
|
+
customers[ params[:id] ] = Data.mock_customer(cards, params)
|
23
|
+
end
|
24
|
+
|
25
|
+
def update_subscription(route, method_url, params, headers)
|
26
|
+
route =~ method_url
|
27
|
+
|
28
|
+
customer = customers[$1]
|
29
|
+
assert_existance :customer, $1, customer
|
30
|
+
|
31
|
+
plan = plans[ params[:plan] ]
|
32
|
+
assert_existance :plan, params[:plan], plan
|
33
|
+
|
34
|
+
# Ensure customer has card to charge if plan has no trial and is not free
|
35
|
+
if customer[:default_card].nil? && plan[:trial_period_days].nil? && plan[:amount] != 0
|
36
|
+
raise Stripe::InvalidRequestError.new('You must supply a valid card', nil, 400)
|
37
|
+
end
|
38
|
+
|
39
|
+
sub = Data.mock_subscription id: new_id('su'), plan: plan, customer: $1
|
40
|
+
customer[:subscription] = sub
|
41
|
+
end
|
42
|
+
|
43
|
+
def cancel_subscription(route, method_url, params, headers)
|
44
|
+
route =~ method_url
|
45
|
+
|
46
|
+
customer = customers[$1]
|
47
|
+
assert_existance :customer, $1, customer
|
48
|
+
|
49
|
+
sub = customer[:subscription]
|
50
|
+
assert_existance nil, nil, sub, "No active subscription for customer: #{$1}"
|
51
|
+
|
52
|
+
customer[:subscription] = nil
|
53
|
+
|
54
|
+
plan = plans[ sub[:plan][:id] ]
|
55
|
+
assert_existance :plan, params[:plan], plan
|
56
|
+
|
57
|
+
Data.mock_delete_subscription(id: sub[:id])
|
58
|
+
end
|
59
|
+
|
60
|
+
def update_customer(route, method_url, params, headers)
|
61
|
+
route =~ method_url
|
62
|
+
assert_existance :customer, $1, customers[$1]
|
63
|
+
|
64
|
+
cus = customers[$1] ||= Data.mock_customer([], :id => $1)
|
65
|
+
cus.merge!(params)
|
66
|
+
|
67
|
+
if params[:card]
|
68
|
+
new_card = get_card_by_token(params.delete(:card))
|
69
|
+
|
70
|
+
if cus[:cards][:count] == 0
|
71
|
+
cus[:cards][:count] += 1
|
72
|
+
else
|
73
|
+
cus[:cards][:data].delete_if {|card| card[:id] == cus[:default_card]}
|
74
|
+
end
|
75
|
+
|
76
|
+
cus[:cards][:data] << new_card
|
77
|
+
cus[:default_card] = new_card[:id]
|
78
|
+
end
|
79
|
+
|
80
|
+
cus
|
81
|
+
end
|
82
|
+
|
83
|
+
def delete_customer(route, method_url, params, headers)
|
84
|
+
route =~ method_url
|
85
|
+
assert_existance :customer, $1, customers[$1]
|
86
|
+
|
87
|
+
customers[$1] = {
|
88
|
+
id: customers[$1][:id],
|
89
|
+
deleted: true
|
90
|
+
}
|
91
|
+
|
92
|
+
customers[$1]
|
93
|
+
end
|
94
|
+
|
95
|
+
def get_customer(route, method_url, params, headers)
|
96
|
+
route =~ method_url
|
97
|
+
assert_existance :customer, $1, customers[$1]
|
98
|
+
customers[$1] ||= Data.mock_customer([], :id => $1)
|
99
|
+
end
|
100
|
+
|
101
|
+
def list_customers(route, method_url, params, headers)
|
102
|
+
customers.values
|
103
|
+
end
|
104
|
+
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module StripeMock
|
2
|
+
module RequestHandlers
|
3
|
+
module InvoiceItems
|
4
|
+
|
5
|
+
def InvoiceItems.included(klass)
|
6
|
+
klass.add_handler 'post /v1/invoiceitems', :new_invoice_item
|
7
|
+
end
|
8
|
+
|
9
|
+
def new_invoice_item(route, method_url, params, headers)
|
10
|
+
Data.mock_invoice(params)
|
11
|
+
end
|
12
|
+
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
module StripeMock
|
2
|
+
module RequestHandlers
|
3
|
+
module Plans
|
4
|
+
|
5
|
+
def Plans.included(klass)
|
6
|
+
klass.add_handler 'post /v1/plans', :new_plan
|
7
|
+
klass.add_handler 'post /v1/plans/(.*)', :update_plan
|
8
|
+
klass.add_handler 'get /v1/plans/(.*)', :get_plan
|
9
|
+
klass.add_handler 'delete /v1/plans/(.*)', :delete_plan
|
10
|
+
klass.add_handler 'get /v1/plans', :list_plans
|
11
|
+
end
|
12
|
+
|
13
|
+
def new_plan(route, method_url, params, headers)
|
14
|
+
params[:id] ||= new_id('plan')
|
15
|
+
plans[ params[:id] ] = Data.mock_plan(params)
|
16
|
+
end
|
17
|
+
|
18
|
+
def update_plan(route, method_url, params, headers)
|
19
|
+
route =~ method_url
|
20
|
+
assert_existance :plan, $1, plans[$1]
|
21
|
+
plans[$1] ||= Data.mock_plan(:id => $1)
|
22
|
+
plans[$1].merge!(params)
|
23
|
+
end
|
24
|
+
|
25
|
+
def get_plan(route, method_url, params, headers)
|
26
|
+
route =~ method_url
|
27
|
+
assert_existance :plan, $1, plans[$1]
|
28
|
+
plans[$1] ||= Data.mock_plan(:id => $1)
|
29
|
+
end
|
30
|
+
|
31
|
+
def delete_plan(route, method_url, params, headers)
|
32
|
+
route =~ method_url
|
33
|
+
assert_existance :plan, $1, plans[$1]
|
34
|
+
plans.delete($1)
|
35
|
+
end
|
36
|
+
|
37
|
+
def list_plans(route, method_url, params, headers)
|
38
|
+
plans.values
|
39
|
+
end
|
40
|
+
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
require 'jimson-temp'
|
2
|
+
|
3
|
+
module StripeMock
|
4
|
+
|
5
|
+
class Server
|
6
|
+
extend Jimson::Handler
|
7
|
+
|
8
|
+
def self.start_new(opts)
|
9
|
+
server = Jimson::Server.new(Server.new,
|
10
|
+
:host => opts[:host] || '0.0.0.0',
|
11
|
+
:port => opts[:port] || 4999,
|
12
|
+
:server => opts[:server] || :thin,
|
13
|
+
:show_errors => true
|
14
|
+
)
|
15
|
+
server.start
|
16
|
+
end
|
17
|
+
|
18
|
+
def initialize
|
19
|
+
self.clear_data
|
20
|
+
end
|
21
|
+
|
22
|
+
def mock_request(*args)
|
23
|
+
begin
|
24
|
+
@instance.mock_request(*args)
|
25
|
+
rescue Stripe::InvalidRequestError => e
|
26
|
+
{
|
27
|
+
:error_raised => 'invalid_request',
|
28
|
+
:error_params => [e.message, e.param, e.http_status, e.http_body, e.json_body]
|
29
|
+
}
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def get_data(key)
|
34
|
+
@instance.send(key)
|
35
|
+
end
|
36
|
+
|
37
|
+
def clear_data
|
38
|
+
@instance = Instance.new
|
39
|
+
end
|
40
|
+
|
41
|
+
def set_debug(toggle)
|
42
|
+
@instance.debug = toggle
|
43
|
+
end
|
44
|
+
|
45
|
+
def set_strict(toggle)
|
46
|
+
@instance.strict = toggle
|
47
|
+
end
|
48
|
+
|
49
|
+
def generate_card_token(card_params)
|
50
|
+
@instance.generate_card_token(card_params)
|
51
|
+
end
|
52
|
+
|
53
|
+
def debug?; @instance.debug; end
|
54
|
+
def strict?; @instance.strict; end
|
55
|
+
def ping; true; end
|
56
|
+
end
|
57
|
+
|
58
|
+
end
|