stripe-ruby-mock 1.8.3.3 → 1.8.3.4

Sign up to get free protection for your applications and to get access to all the features.
data/README.md CHANGED
@@ -14,7 +14,7 @@
14
14
 
15
15
  ## Description
16
16
 
17
- ** *WARNING: THIS LIBRARY IS INCOMPLETE* **
17
+ ** *WARNING: THIS LIBRARY IS INCOMPLETE AND IN ACTIVE DEVELOPMENT* **
18
18
 
19
19
  At its core, this library overrides [stripe-ruby's](https://github.com/stripe/stripe-ruby)
20
20
  request method to skip all http calls and
@@ -24,7 +24,6 @@ without the need to actually hit stripe's servers.
24
24
  You can use stripe-ruby-mock with any ruby testing library. Here's a quick dummy example with RSpec:
25
25
 
26
26
  ```ruby
27
- require 'stripe'
28
27
  require 'stripe_mock'
29
28
 
30
29
  describe MyApp do
@@ -45,7 +44,7 @@ end
45
44
 
46
45
  ## Mocking Errors
47
46
 
48
- Tired of manually inputting fake credit card numbers to test against errors? Tire no longer!
47
+ Tired of manually inputting fake credit card numbers to test against errors? Tire no more!
49
48
 
50
49
  ```ruby
51
50
  it "mocks a declined card error" do
@@ -96,11 +95,56 @@ StripeMock.prepare_card_error(:processing_error)
96
95
 
97
96
  You can see the details of each error in [lib/stripe_mock/api/errors.rb](lib/stripe_mock/api/errors.rb)
98
97
 
98
+ ## Running the Mock Server
99
+
100
+ Sometimes you want your test stripe data to persist for a bit, such as during integration tests
101
+ running on different processes. In such cases you'll want to start the stripe mock server:
102
+
103
+ $ stripe-mock-server # Default port is 4999
104
+ $ stripe-mock-server 4000
105
+
106
+ Then, instead of `StripeMock.start`, you'll want to use `StripeMock.start_client`:
107
+
108
+ ```ruby
109
+ describe MyApp do
110
+ before do
111
+ @client = StripeMock.start_client
112
+ end
113
+
114
+ after do
115
+ StripeMock.stop_client
116
+ #
117
+ # Alternatively:
118
+ #
119
+ # @client.close!
120
+ # StripeMock.stop_client(:clear_server_data => true)
121
+ end
122
+ end
123
+ ```
124
+
125
+ This is all essentially the same as using `StripeMock.start`, except that the stripe test
126
+ data is held in its own server process.
127
+
128
+ Here are some other neat things you can do with the client:
129
+
130
+ ```ruby
131
+ @client.state #=> 'ready'
132
+
133
+ @client.set_server_debug(true)
134
+ @client.get_server_data(:customers) # Also works for :charges, :plans, etc.
135
+ @client.clear_server_data
136
+
137
+ @client.close!
138
+ @client.state #=> 'closed'
139
+ ```
140
+
99
141
  ## TODO
100
142
 
101
143
  * Cover all stripe urls/methods
102
144
  * Create hash for storing/retrieving all stripe objects in-memory
103
145
  * Currently implemented for: **Customers**, **Charges**, and **Plans**
146
+ * Throw useful errors that emulate Stripe's
147
+ * For example: "You must supply either a card or a customer id" for `Stripe::Charge`
104
148
 
105
149
  ## Copyright
106
150
 
@@ -0,0 +1,13 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ lib = File.expand_path(File.dirname(__FILE__) + '/../lib')
4
+ $LOAD_PATH.unshift(lib) if File.directory?(lib) && !$LOAD_PATH.include?(lib)
5
+
6
+ args = ARGV.dup
7
+ ARGV.clear
8
+ port = (args.shift || 4999).to_i
9
+
10
+ require 'stripe_mock'
11
+ require 'stripe_mock/server'
12
+
13
+ StripeMock.start_server(port)
@@ -0,0 +1,29 @@
1
+ module StripeMock
2
+
3
+ def self.client; @client; end
4
+
5
+ def self.start_client(port=4999)
6
+ alias_stripe_method :request, StripeMock.method(:redirect_to_mock_server)
7
+ @client = Client.new(port)
8
+ @state = 'remote'
9
+ @client
10
+ end
11
+
12
+ def self.stop_client(opts={})
13
+ return false unless @state == 'remote'
14
+ @state = 'ready'
15
+
16
+ alias_stripe_method :request, @original_request_method
17
+ @client.clear_data if opts[:clear_server_data] == true
18
+ @client.close!
19
+ @client = nil
20
+ true
21
+ end
22
+
23
+ private
24
+
25
+ def self.redirect_to_mock_server(method, url, api_key, params={}, headers={})
26
+ Stripe::Util.symbolize_names @client.mock_request(method, url, api_key, params, headers)
27
+ end
28
+
29
+ end
@@ -14,7 +14,7 @@ module StripeMock
14
14
  private
15
15
 
16
16
  def self.card_error_args
17
- @__map = {
17
+ @__map ||= {
18
18
  incorrect_number: ["The card number is incorrect", 'number', 'incorrect_number', 402],
19
19
  invalid_number: ["The card number is not a valid credit card number", 'number', 'invalid_number', 402],
20
20
  invalid_expiry_month: ["The card's expiration month is invalid", 'exp_month', 'invalid_expiry_month', 402],
@@ -1,27 +1,27 @@
1
1
  module StripeMock
2
2
 
3
- @@first_start = true
4
- @@instance = nil
3
+ @state = 'ready'
4
+ @instance = nil
5
+ @original_request_method = Stripe.method(:request)
5
6
 
6
7
  def self.start
7
- if @@first_start == true
8
- @@original_request_method = Stripe.method(:request)
9
- @@first_start = false
10
- end
11
- @@instance = Instance.new
12
- alias_stripe_method :request, @@instance.method(:mock_request)
8
+ @instance = Instance.new
9
+ alias_stripe_method :request, @instance.method(:mock_request)
10
+ @state = 'local'
13
11
  end
14
12
 
15
13
  def self.stop
16
- return if @@instance.nil?
17
- alias_stripe_method :request, @@original_request_method
18
- @@instance = nil
14
+ return unless @state == 'local'
15
+ alias_stripe_method :request, @original_request_method
16
+ @instance = nil
17
+ @state = 'ready'
19
18
  end
20
19
 
21
20
  def self.alias_stripe_method(new_name, method_object)
22
21
  Stripe.define_singleton_method(new_name) {|*args| method_object.call(*args) }
23
22
  end
24
23
 
25
- def self.instance; @@instance; end
24
+ def self.instance; @instance; end
25
+ def self.state; @state; end
26
26
 
27
27
  end
@@ -0,0 +1,48 @@
1
+ module StripeMock
2
+
3
+ class Client
4
+ attr_reader :port, :state
5
+
6
+ def initialize(port)
7
+ @port = port
8
+ @pipe = Jimson::Client.new("http://0.0.0.0:#{port}")
9
+ # Ensure client can connect to server
10
+ timeout_wrap { @pipe.ping }
11
+ @state = 'ready'
12
+ end
13
+
14
+ def mock_request(method, url, api_key, params={}, headers={})
15
+ timeout_wrap { @pipe.mock_request(method, url, api_key, params, headers) }
16
+ end
17
+
18
+ def get_server_data(key)
19
+ timeout_wrap { @pipe.get_data(key) }
20
+ end
21
+
22
+ def set_server_debug(toggle)
23
+ timeout_wrap { @pipe.set_debug(toggle) }
24
+ end
25
+
26
+ def clear_server_data
27
+ timeout_wrap { @pipe.clear }
28
+ end
29
+
30
+ def close!
31
+ @state = 'closed'
32
+ StripeMock.stop_client(:clear_server_data => false)
33
+ end
34
+
35
+ def timeout_wrap
36
+ raise ClosedClientConnectionError if @state == 'closed'
37
+ yield
38
+ rescue ClosedClientConnectionError
39
+ raise
40
+ rescue Errno::ECONNREFUSED => e
41
+ raise StripeMock::ServerTimeoutError.new(e)
42
+ rescue StandardError => e
43
+ puts "Unexpected StripeMock Client Error: #{e.inspect}"
44
+ {}
45
+ end
46
+ end
47
+
48
+ end
@@ -0,0 +1,9 @@
1
+ module StripeMock
2
+ class ClosedClientConnectionError < StripeMockError
3
+
4
+ def initialize
5
+ super("This StripeMock client has already been closed.")
6
+ end
7
+
8
+ end
9
+ 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
@@ -18,7 +18,7 @@ module StripeMock
18
18
 
19
19
 
20
20
  attr_reader :charges, :customers, :plans
21
- attr_accessor :pending_error
21
+ attr_accessor :pending_error, :debug
22
22
 
23
23
  def initialize
24
24
  @customers = {}
@@ -27,11 +27,20 @@ module StripeMock
27
27
 
28
28
  @id_counter = 0
29
29
  @pending_error = nil
30
+ @debug = false
30
31
  end
31
32
 
32
33
  def mock_request(method, url, api_key, params={}, headers={})
33
34
  return {} if method == :xtest
34
35
 
36
+ # Ensure params hash has symbols as keys
37
+ params = Stripe::Util.symbolize_names(params)
38
+
39
+ if @debug == true
40
+ puts "[StripeMock req] #{method} #{url}"
41
+ puts " #{params}"
42
+ end
43
+
35
44
  if @pending_error
36
45
  raise @pending_error
37
46
  @pending_error = nil
@@ -41,7 +50,9 @@ module StripeMock
41
50
  handler = @@handlers.find {|h| method_url =~ h[:route] }
42
51
 
43
52
  if handler
44
- self.send handler[:name], handler[:route], method_url, params, headers
53
+ self.send(handler[:name], handler[:route], method_url, params, headers).tap {|json|
54
+ puts "[StripeMock res] #{json}" if @debug == true
55
+ }
45
56
  else
46
57
  puts "WARNING: Unrecognized method + url: [#{method} #{url}]"
47
58
  puts " params: #{params}"
@@ -51,9 +62,9 @@ module StripeMock
51
62
 
52
63
  private
53
64
 
54
- def new_id
65
+ def new_id(prefix)
55
66
  # Stripe ids must be strings
56
- (@id_counter += 1).to_s
67
+ "test_#{prefix}_#{@id_counter += 1}"
57
68
  end
58
69
 
59
70
  end
@@ -8,7 +8,7 @@ module StripeMock
8
8
  end
9
9
 
10
10
  def new_charge(route, method_url, params, headers)
11
- id = new_id
11
+ id = new_id('ch')
12
12
  charges[id] = Data.test_charge(params.merge :id => id)
13
13
  end
14
14
 
@@ -11,7 +11,7 @@ module StripeMock
11
11
  end
12
12
 
13
13
  def new_customer(route, method_url, params, headers)
14
- id = new_id
14
+ id = new_id('cus')
15
15
  customers[id] = Data.test_customer(params.merge :id => id)
16
16
  end
17
17
 
@@ -8,7 +8,7 @@ module StripeMock
8
8
  end
9
9
 
10
10
  def new_plan(route, method_url, params, headers)
11
- params[:id] ||= new_id
11
+ params[:id] ||= new_id('plan')
12
12
  plans[ params[:id] ] = Data.test_plan(params)
13
13
  end
14
14
 
@@ -0,0 +1,42 @@
1
+ require 'thin'
2
+ require 'jimson-temp'
3
+
4
+ module StripeMock
5
+
6
+ def self.start_server(port=4999)
7
+ server = Jimson::Server.new(Server.new,
8
+ :host => '0.0.0.0',
9
+ :port => port,
10
+ :server => :thin,
11
+ :show_errors => true
12
+ )
13
+ server.start
14
+ end
15
+
16
+ class Server
17
+ extend Jimson::Handler
18
+
19
+ def initialize
20
+ self.clear_data
21
+ end
22
+
23
+ def mock_request(*args)
24
+ @instance.mock_request(*args)
25
+ end
26
+
27
+ def get_data(key)
28
+ @instance.send(key)
29
+ end
30
+
31
+ def clear_data
32
+ @instance = Instance.new
33
+ end
34
+
35
+ def set_debug(toggle)
36
+ @instance.debug = toggle
37
+ end
38
+
39
+ def ping; true; end
40
+ end
41
+
42
+ end
@@ -1,4 +1,4 @@
1
1
  module StripeMock
2
2
  # stripe-ruby-mock version
3
- VERSION = "1.8.3.3"
3
+ VERSION = "1.8.3.4"
4
4
  end
data/lib/stripe_mock.rb CHANGED
@@ -1,12 +1,19 @@
1
1
  require 'ostruct'
2
+ require 'jimson-temp'
3
+ require 'stripe'
2
4
 
3
5
  require 'stripe_mock/version'
4
6
  require 'stripe_mock/data'
5
7
 
6
8
  require 'stripe_mock/errors/stripe_mock_error'
7
9
  require 'stripe_mock/errors/uninitialized_instance_error'
10
+ require 'stripe_mock/errors/server_timeout_error'
11
+ require 'stripe_mock/errors/closed_client_connection_error'
12
+
13
+ require 'stripe_mock/client'
8
14
 
9
15
  require 'stripe_mock/api/instance'
16
+ require 'stripe_mock/api/client'
10
17
  require 'stripe_mock/api/errors'
11
18
 
12
19
  require 'stripe_mock/request_handlers/charges.rb'
@@ -0,0 +1,18 @@
1
+ require 'spec_helper'
2
+
3
+ describe StripeMock::Instance do
4
+
5
+ before { StripeMock.start }
6
+ after { StripeMock.stop }
7
+
8
+ it "handles both string and symbol hash keys" do
9
+ string_params = {
10
+ "id" => "str_abcde",
11
+ :name => "String Plan"
12
+ }
13
+ res = StripeMock.instance.mock_request('post', '/v1/plans', 'api_key', string_params)
14
+ expect(res[:id]).to eq('str_abcde')
15
+ expect(res[:name]).to eq('String Plan')
16
+ end
17
+
18
+ end
@@ -0,0 +1,101 @@
1
+ require 'spec_helper'
2
+
3
+ describe 'StripeMock Server' do
4
+
5
+ before(:all) do
6
+ Dante::Runner.new('stripe-mock-server').execute(
7
+ :daemonize => true, :pid_path => './stripe-mock-server.pid'
8
+ ){
9
+ StripeMock.start_server(4999)
10
+ }
11
+ end
12
+
13
+ after(:all) do
14
+ Dante::Runner.new('stripe-mock-server').execute(
15
+ :kill => true, :pid_path => './stripe-mock-server.pid'
16
+ )
17
+ end
18
+
19
+
20
+ before do
21
+ @client = StripeMock.start_client
22
+ end
23
+
24
+ after { StripeMock.stop_client }
25
+
26
+
27
+ it "uses an RPC client for mock requests" do
28
+ charge = Stripe::Charge.create(
29
+ amount: 987,
30
+ currency: 'USD',
31
+ card: 'card_token_abcde',
32
+ description: 'card charge'
33
+ )
34
+ expect(charge.amount).to eq(987)
35
+ expect(charge.currency).to eq('USD')
36
+ expect(charge.description).to eq('card charge')
37
+ end
38
+
39
+
40
+ it "should not clear server data in between client sessions by default" do
41
+ customer = Stripe::Customer.create(email: 'johnny@appleseed.com')
42
+ expect(customer.email).to eq('johnny@appleseed.com')
43
+
44
+ server_customer_data = StripeMock.client.get_server_data(:customers)[customer.id]
45
+ expect(server_customer_data).to_not be_nil
46
+ expect(server_customer_data['email']).to eq('johnny@appleseed.com')
47
+
48
+ StripeMock.stop_client
49
+ StripeMock.start_client
50
+
51
+ server_customer_data = StripeMock.client.get_server_data(:customers)[customer.id]
52
+ expect(server_customer_data).to_not be_nil
53
+ expect(server_customer_data['email']).to eq('johnny@appleseed.com')
54
+ end
55
+
56
+
57
+ it "returns a response with symbolized hash keys" do
58
+ response = StripeMock.redirect_to_mock_server('get', '/v1/plans/x', 'xxx')
59
+ response.keys.each {|k| expect(k).to be_a(Symbol) }
60
+ end
61
+
62
+
63
+ it "can toggle debug" do
64
+ StripeMock.client.set_server_debug(true)
65
+ StripeMock.client.set_server_debug(false)
66
+ StripeMock.client.set_server_debug(true)
67
+ end
68
+
69
+
70
+ it "raises an error when client is stopped" do
71
+ expect(@client).to be_a StripeMock::Client
72
+ expect(@client.state).to eq('ready')
73
+
74
+ StripeMock.stop_client
75
+ expect(@client.state).to eq('closed')
76
+ expect { @client.clear_server_data }.to raise_error StripeMock::ClosedClientConnectionError
77
+ end
78
+
79
+
80
+ it "raises an error when client connection is closed" do
81
+ expect(@client).to be_a StripeMock::Client
82
+ expect(@client.state).to eq('ready')
83
+
84
+ @client.close!
85
+ expect(@client.state).to eq('closed')
86
+ expect(StripeMock.stop_client).to eq(false)
87
+ end
88
+
89
+
90
+ it "throws an error when server is not running" do
91
+ StripeMock.stop_client
92
+ begin
93
+ StripeMock.start_client(1515)
94
+ # We should never get here
95
+ expect(false).to eq(true)
96
+ rescue StripeMock::ServerTimeoutError => e
97
+ expect(e.associated_error).to be_a(Errno::ECONNREFUSED)
98
+ end
99
+ end
100
+
101
+ end
data/spec/spec_helper.rb CHANGED
@@ -2,3 +2,5 @@ gem 'rspec', '~> 2.4'
2
2
  require 'rspec'
3
3
  require 'stripe'
4
4
  require 'stripe_mock'
5
+ require 'stripe_mock/server'
6
+ require 'dante'
@@ -13,6 +13,7 @@ describe 'Charge API' do
13
13
  description: 'card charge'
14
14
  )
15
15
 
16
+ expect(charge.id).to match(/^test_ch/)
16
17
  expect(charge.amount).to eq(999)
17
18
  expect(charge.description).to eq('card charge')
18
19
  end
@@ -11,6 +11,7 @@ describe 'Customer API' do
11
11
  card: 'some_card_token',
12
12
  description: "a description"
13
13
  })
14
+ expect(customer.id).to match(/^test_cus/)
14
15
  expect(customer.email).to eq('johnny@appleseed.com')
15
16
  expect(customer.description).to eq('a description')
16
17
  end
File without changes
@@ -18,7 +18,9 @@ Gem::Specification.new do |gem|
18
18
  gem.require_paths = ['lib']
19
19
 
20
20
  gem.add_dependency 'stripe', '~> 1.8.3'
21
+ gem.add_dependency 'jimson-temp'
21
22
 
22
23
  gem.add_development_dependency 'rspec', '~> 2.4'
23
24
  gem.add_development_dependency 'rubygems-tasks', '~> 0.2'
25
+ gem.add_development_dependency 'dante', '~> 0.1.5'
24
26
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: stripe-ruby-mock
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.8.3.3
4
+ version: 1.8.3.4
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2013-05-31 00:00:00.000000000 Z
12
+ date: 2013-06-12 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: stripe
@@ -27,6 +27,22 @@ dependencies:
27
27
  - - ~>
28
28
  - !ruby/object:Gem::Version
29
29
  version: 1.8.3
30
+ - !ruby/object:Gem::Dependency
31
+ name: jimson-temp
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ! '>='
36
+ - !ruby/object:Gem::Version
37
+ version: '0'
38
+ type: :runtime
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ! '>='
44
+ - !ruby/object:Gem::Version
45
+ version: '0'
30
46
  - !ruby/object:Gem::Dependency
31
47
  name: rspec
32
48
  requirement: !ruby/object:Gem::Requirement
@@ -59,9 +75,26 @@ dependencies:
59
75
  - - ~>
60
76
  - !ruby/object:Gem::Version
61
77
  version: '0.2'
78
+ - !ruby/object:Gem::Dependency
79
+ name: dante
80
+ requirement: !ruby/object:Gem::Requirement
81
+ none: false
82
+ requirements:
83
+ - - ~>
84
+ - !ruby/object:Gem::Version
85
+ version: 0.1.5
86
+ type: :development
87
+ prerelease: false
88
+ version_requirements: !ruby/object:Gem::Requirement
89
+ none: false
90
+ requirements:
91
+ - - ~>
92
+ - !ruby/object:Gem::Version
93
+ version: 0.1.5
62
94
  description: A drop-in library to test stripe without hitting their servers
63
95
  email: gilbertbgarza@gmail.com
64
- executables: []
96
+ executables:
97
+ - stripe-mock-server
65
98
  extensions: []
66
99
  extra_rdoc_files: []
67
100
  files:
@@ -71,10 +104,15 @@ files:
71
104
  - LICENSE.txt
72
105
  - README.md
73
106
  - Rakefile
107
+ - bin/stripe-mock-server
74
108
  - lib/stripe_mock.rb
109
+ - lib/stripe_mock/api/client.rb
75
110
  - lib/stripe_mock/api/errors.rb
76
111
  - lib/stripe_mock/api/instance.rb
112
+ - lib/stripe_mock/client.rb
77
113
  - lib/stripe_mock/data.rb
114
+ - lib/stripe_mock/errors/closed_client_connection_error.rb
115
+ - lib/stripe_mock/errors/server_timeout_error.rb
78
116
  - lib/stripe_mock/errors/stripe_mock_error.rb
79
117
  - lib/stripe_mock/errors/uninitialized_instance_error.rb
80
118
  - lib/stripe_mock/instance.rb
@@ -82,8 +120,11 @@ files:
82
120
  - lib/stripe_mock/request_handlers/customers.rb
83
121
  - lib/stripe_mock/request_handlers/invoice_items.rb
84
122
  - lib/stripe_mock/request_handlers/plans.rb
123
+ - lib/stripe_mock/server.rb
85
124
  - lib/stripe_mock/version.rb
125
+ - spec/instance_spec.rb
86
126
  - spec/readme_spec.rb
127
+ - spec/server_spec.rb
87
128
  - spec/spec_helper.rb
88
129
  - spec/stripe/charge_spec.rb
89
130
  - spec/stripe/customer_spec.rb
@@ -91,6 +132,7 @@ files:
91
132
  - spec/stripe/invoice_item_spec.rb
92
133
  - spec/stripe/plan_spec.rb
93
134
  - spec/stripe_mock_spec.rb
135
+ - spec/support/server_daemon.rb
94
136
  - stripe-ruby-mock.gemspec
95
137
  homepage: https://github.com/mindeavor/stripe-ruby-mock
96
138
  licenses:
@@ -118,7 +160,9 @@ signing_key:
118
160
  specification_version: 3
119
161
  summary: TDD with stripe
120
162
  test_files:
163
+ - spec/instance_spec.rb
121
164
  - spec/readme_spec.rb
165
+ - spec/server_spec.rb
122
166
  - spec/spec_helper.rb
123
167
  - spec/stripe/charge_spec.rb
124
168
  - spec/stripe/customer_spec.rb
@@ -126,3 +170,4 @@ test_files:
126
170
  - spec/stripe/invoice_item_spec.rb
127
171
  - spec/stripe/plan_spec.rb
128
172
  - spec/stripe_mock_spec.rb
173
+ - spec/support/server_daemon.rb