stripe-ruby-mock 1.8.3.3 → 1.8.3.4

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/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