stripe 1.8.7 → 1.8.8

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 CHANGED
@@ -1,3 +1,4 @@
1
1
  /stripe-*.gem
2
2
  /Gemfile.lock
3
3
  .rvmrc
4
+ Gemfile.lock
@@ -1,3 +1,7 @@
1
+ === 1.8.8 2013-10-3
2
+
3
+ * Add support for metadata API
4
+
1
5
  === 1.8.7 2013-08-18
2
6
 
3
7
  * Add support for closing disputes.
data/Rakefile CHANGED
@@ -1,9 +1,15 @@
1
- task :default => [:test]
1
+ task :default => [:all]
2
2
 
3
3
  task :test do
4
4
  ret = true
5
- Dir["test/**/*.rb"].each do |f|
5
+ Dir["test/**/*_test.rb"].each do |f|
6
6
  ret = ret && ruby(f, '')
7
7
  end
8
- exit(ret)
9
8
  end
9
+
10
+ task :all do
11
+ Rake::Task["test"].invoke
12
+ require 'active_support/all'
13
+ Rake::Task["test"].reenable
14
+ Rake::Task["test"].invoke
15
+ end
data/VERSION CHANGED
@@ -1 +1 @@
1
- 1.8.7
1
+ 1.8.8
@@ -2,16 +2,56 @@ module Stripe
2
2
  module APIOperations
3
3
  module Update
4
4
  def save
5
- if @unsaved_values.length > 0
6
- values = @unsaved_values.reduce({}) do |h, k|
7
- h.update(k => @values[k].nil? ? '' : @values[k])
8
- end
5
+ values = serialize_params(self)
6
+
7
+ if @values[:metadata]
8
+ values[:metadata] = serialize_metadata
9
+ end
10
+
11
+ if values.length > 0
9
12
  values.delete(:id)
13
+
10
14
  response, api_key = Stripe.request(:post, url, @api_key, values)
11
15
  refresh_from(response, api_key)
12
16
  end
13
17
  self
14
18
  end
19
+
20
+ def serialize_metadata
21
+ if @unsaved_values.include?(:metadata)
22
+ # the metadata object has been reassigned
23
+ # i.e. as object.metadata = {key => val}
24
+ metadata_update = @values[:metadata] # new hash
25
+ new_keys = metadata_update.keys.map(&:to_sym)
26
+ # remove keys at the server, but not known locally
27
+ keys_to_unset = @previous_metadata.keys - new_keys
28
+ keys_to_unset.each {|key| metadata_update[key] = ''}
29
+
30
+ metadata_update
31
+ else
32
+ # metadata is a StripeObject, and can be serialized normally
33
+ serialize_params(@values[:metadata])
34
+ end
35
+ end
36
+
37
+ def serialize_params(obj)
38
+ case obj
39
+ when nil
40
+ ''
41
+ when StripeObject
42
+ unsaved_keys = obj.instance_variable_get(:@unsaved_values)
43
+ obj_values = obj.instance_variable_get(:@values)
44
+ update_hash = {}
45
+
46
+ unsaved_keys.each do |k|
47
+ update_hash[k] = serialize_params(obj_values[k])
48
+ end
49
+
50
+ update_hash
51
+ else
52
+ obj
53
+ end
54
+ end
15
55
  end
16
56
  end
17
57
  end
@@ -47,6 +47,7 @@ module Stripe
47
47
  def refresh_from(values, api_key, partial=false)
48
48
  @api_key = api_key
49
49
 
50
+ @previous_metadata = values[:metadata]
50
51
  removed = partial ? Set.new : Set.new(@values.keys - values.keys)
51
52
  added = Set.new(values.keys - @values.keys)
52
53
  # Wipe old state before setting new. This is useful for e.g. updating a
@@ -2,5 +2,6 @@ module Stripe
2
2
  class Transfer < APIResource
3
3
  include Stripe::APIOperations::List
4
4
  include Stripe::APIOperations::Create
5
+ include Stripe::APIOperations::Update
5
6
  end
6
7
  end
@@ -1,3 +1,3 @@
1
1
  module Stripe
2
- VERSION = '1.8.7'
2
+ VERSION = '1.8.8'
3
3
  end
@@ -0,0 +1,14 @@
1
+ require File.expand_path('../../test_helper', __FILE__)
2
+
3
+ module Stripe
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))
8
+ a = Stripe::Account.retrieve
9
+ assert_equal "test+bindings@stripe.com", a.email
10
+ assert !a.charge_enabled
11
+ assert !a.details_submitted
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,345 @@
1
+ # -*- coding: utf-8 -*-
2
+ require File.expand_path('../../test_helper', __FILE__)
3
+
4
+ module Stripe
5
+ class ApiResourceTest < Test::Unit::TestCase
6
+ should "creating a new APIResource should not fetch over the network" do
7
+ @mock.expects(:get).never
8
+ c = Stripe::Customer.new("someid")
9
+ end
10
+
11
+ should "creating a new APIResource from a hash should not fetch over the network" do
12
+ @mock.expects(:get).never
13
+ c = Stripe::Customer.construct_from({
14
+ :id => "somecustomer",
15
+ :card => {:id => "somecard", :object => "card"},
16
+ :object => "customer"
17
+ })
18
+ end
19
+
20
+ should "setting an attribute should not cause a network request" do
21
+ @mock.expects(:get).never
22
+ @mock.expects(:post).never
23
+ c = Stripe::Customer.new("test_customer");
24
+ c.card = {:id => "somecard", :object => "card"}
25
+ end
26
+
27
+ should "accessing id should not issue a fetch" do
28
+ @mock.expects(:get).never
29
+ c = Stripe::Customer.new("test_customer");
30
+ c.id
31
+ end
32
+
33
+ should "not specifying api credentials should raise an exception" do
34
+ Stripe.api_key = nil
35
+ assert_raises Stripe::AuthenticationError do
36
+ Stripe::Customer.new("test_customer").refresh
37
+ end
38
+ end
39
+
40
+ should "specifying api credentials containing whitespace should raise an exception" do
41
+ Stripe.api_key = "key "
42
+ assert_raises Stripe::AuthenticationError do
43
+ Stripe::Customer.new("test_customer").refresh
44
+ end
45
+ end
46
+
47
+ should "specifying invalid api credentials should raise an exception" do
48
+ Stripe.api_key = "invalid"
49
+ response = test_response(test_invalid_api_key_error, 401)
50
+ assert_raises Stripe::AuthenticationError do
51
+ @mock.expects(:get).once.raises(RestClient::ExceptionWithResponse.new(response, 401))
52
+ Stripe::Customer.retrieve("failing_customer")
53
+ end
54
+ end
55
+
56
+ should "AuthenticationErrors should have an http status, http body, and JSON body" do
57
+ Stripe.api_key = "invalid"
58
+ response = test_response(test_invalid_api_key_error, 401)
59
+ begin
60
+ @mock.expects(:get).once.raises(RestClient::ExceptionWithResponse.new(response, 401))
61
+ Stripe::Customer.retrieve("failing_customer")
62
+ rescue Stripe::AuthenticationError => e
63
+ assert_equal(401, e.http_status)
64
+ assert_equal(true, !!e.http_body)
65
+ assert_equal(true, !!e.json_body[:error][:message])
66
+ assert_equal(test_invalid_api_key_error['error']['message'], e.json_body[:error][:message])
67
+ end
68
+ end
69
+
70
+ context "when specifying per-object credentials" do
71
+ context "with no global API key set" do
72
+ should "use the per-object credential when creating" do
73
+ Stripe.expects(:execute_request).with do |opts|
74
+ opts[:headers][:authorization] == 'Bearer sk_test_local'
75
+ end.returns(test_response(test_charge))
76
+
77
+ Stripe::Charge.create({:card => {:number => '4242424242424242'}},
78
+ 'sk_test_local')
79
+ end
80
+ end
81
+
82
+ context "with a global API key set" do
83
+ setup do
84
+ Stripe.api_key = "global"
85
+ end
86
+
87
+ teardown do
88
+ Stripe.api_key = nil
89
+ end
90
+
91
+ should "use the per-object credential when creating" do
92
+ Stripe.expects(:execute_request).with do |opts|
93
+ opts[:headers][:authorization] == 'Bearer local'
94
+ end.returns(test_response(test_charge))
95
+
96
+ Stripe::Charge.create({:card => {:number => '4242424242424242'}},
97
+ 'local')
98
+ end
99
+
100
+ should "use the per-object credential when retrieving and making other calls" do
101
+ Stripe.expects(:execute_request).with do |opts|
102
+ opts[:url] == "#{Stripe.api_base}/v1/charges/ch_test_charge" &&
103
+ opts[:headers][:authorization] == 'Bearer local'
104
+ end.returns(test_response(test_charge))
105
+ Stripe.expects(:execute_request).with do |opts|
106
+ opts[:url] == "#{Stripe.api_base}/v1/charges/ch_test_charge/refund" &&
107
+ opts[:headers][:authorization] == 'Bearer local'
108
+ end.returns(test_response(test_charge))
109
+
110
+ ch = Stripe::Charge.retrieve('ch_test_charge', 'local')
111
+ ch.refund
112
+ end
113
+ end
114
+ end
115
+
116
+ context "with valid credentials" do
117
+ should "urlencode values in GET params" do
118
+ response = test_response(test_charge_array)
119
+ @mock.expects(:get).with("#{Stripe.api_base}/v1/charges?customer=test%20customer", nil, nil).returns(response)
120
+ charges = Stripe::Charge.all(:customer => 'test customer').data
121
+ assert charges.kind_of? Array
122
+ end
123
+
124
+ should "construct URL properly with base query parameters" do
125
+ response = test_response(test_invoice_customer_array)
126
+ @mock.expects(:get).with("#{Stripe.api_base}/v1/invoices?customer=test_customer", nil, nil).returns(response)
127
+ invoices = Stripe::Invoice.all(:customer => 'test_customer')
128
+
129
+ @mock.expects(:get).with("#{Stripe.api_base}/v1/invoices?customer=test_customer&paid=true", nil, nil).returns(response)
130
+ invoices.all(:paid => true)
131
+ end
132
+
133
+ should "a 400 should give an InvalidRequestError with http status, body, and JSON body" do
134
+ response = test_response(test_missing_id_error, 400)
135
+ @mock.expects(:get).once.raises(RestClient::ExceptionWithResponse.new(response, 404))
136
+ begin
137
+ Stripe::Customer.retrieve("foo")
138
+ rescue Stripe::InvalidRequestError => e
139
+ assert_equal(400, e.http_status)
140
+ assert_equal(true, !!e.http_body)
141
+ assert_equal(true, e.json_body.kind_of?(Hash))
142
+ end
143
+ end
144
+
145
+ should "a 401 should give an AuthenticationError with http status, body, and JSON body" do
146
+ response = test_response(test_missing_id_error, 401)
147
+ @mock.expects(:get).once.raises(RestClient::ExceptionWithResponse.new(response, 404))
148
+ begin
149
+ Stripe::Customer.retrieve("foo")
150
+ rescue Stripe::AuthenticationError => e
151
+ assert_equal(401, e.http_status)
152
+ assert_equal(true, !!e.http_body)
153
+ assert_equal(true, e.json_body.kind_of?(Hash))
154
+ end
155
+ end
156
+
157
+ should "a 402 should give a CardError with http status, body, and JSON body" do
158
+ response = test_response(test_missing_id_error, 402)
159
+ @mock.expects(:get).once.raises(RestClient::ExceptionWithResponse.new(response, 404))
160
+ begin
161
+ Stripe::Customer.retrieve("foo")
162
+ rescue Stripe::CardError => e
163
+ assert_equal(402, e.http_status)
164
+ assert_equal(true, !!e.http_body)
165
+ assert_equal(true, e.json_body.kind_of?(Hash))
166
+ end
167
+ end
168
+
169
+ should "a 404 should give an InvalidRequestError with http status, body, and JSON body" do
170
+ response = test_response(test_missing_id_error, 404)
171
+ @mock.expects(:get).once.raises(RestClient::ExceptionWithResponse.new(response, 404))
172
+ begin
173
+ Stripe::Customer.retrieve("foo")
174
+ rescue Stripe::InvalidRequestError => e
175
+ assert_equal(404, e.http_status)
176
+ assert_equal(true, !!e.http_body)
177
+ assert_equal(true, e.json_body.kind_of?(Hash))
178
+ end
179
+ end
180
+
181
+ should "setting a nil value for a param should exclude that param from the request" do
182
+ @mock.expects(:get).with do |url, api_key, params|
183
+ uri = URI(url)
184
+ query = CGI.parse(uri.query)
185
+ (url =~ %r{^#{Stripe.api_base}/v1/charges?} &&
186
+ query.keys.sort == ['offset', 'sad'])
187
+ end.returns(test_response({ :count => 1, :data => [test_charge] }))
188
+ c = Stripe::Charge.all(:count => nil, :offset => 5, :sad => false)
189
+
190
+ @mock.expects(:post).with do |url, api_key, params|
191
+ url == "#{Stripe.api_base}/v1/charges" &&
192
+ api_key.nil? &&
193
+ CGI.parse(params) == { 'amount' => ['50'], 'currency' => ['usd'] }
194
+ end.returns(test_response({ :count => 1, :data => [test_charge] }))
195
+ c = Stripe::Charge.create(:amount => 50, :currency => 'usd', :card => { :number => nil })
196
+ end
197
+
198
+ should "requesting with a unicode ID should result in a request" do
199
+ response = test_response(test_missing_id_error, 404)
200
+ @mock.expects(:get).once.with("#{Stripe.api_base}/v1/customers/%E2%98%83", nil, nil).raises(RestClient::ExceptionWithResponse.new(response, 404))
201
+ c = Stripe::Customer.new("☃")
202
+ assert_raises(Stripe::InvalidRequestError) { c.refresh }
203
+ end
204
+
205
+ should "requesting with no ID should result in an InvalidRequestError with no request" do
206
+ c = Stripe::Customer.new
207
+ assert_raises(Stripe::InvalidRequestError) { c.refresh }
208
+ end
209
+
210
+ should "making a GET request with parameters should have a query string and no body" do
211
+ params = { :limit => 1 }
212
+ @mock.expects(:get).once.with("#{Stripe.api_base}/v1/charges?limit=1", nil, nil).returns(test_response([test_charge]))
213
+ c = Stripe::Charge.all(params)
214
+ end
215
+
216
+ should "making a POST request with parameters should have a body and no query string" do
217
+ params = { :amount => 100, :currency => 'usd', :card => 'sc_token' }
218
+ @mock.expects(:post).once.with do |url, get, post|
219
+ get.nil? && CGI.parse(post) == {'amount' => ['100'], 'currency' => ['usd'], 'card' => ['sc_token']}
220
+ end.returns(test_response(test_charge))
221
+ c = Stripe::Charge.create(params)
222
+ end
223
+
224
+ should "loading an object should issue a GET request" do
225
+ @mock.expects(:get).once.returns(test_response(test_customer))
226
+ c = Stripe::Customer.new("test_customer")
227
+ c.refresh
228
+ end
229
+
230
+ should "using array accessors should be the same as the method interface" do
231
+ @mock.expects(:get).once.returns(test_response(test_customer))
232
+ c = Stripe::Customer.new("test_customer")
233
+ c.refresh
234
+ assert_equal c.created, c[:created]
235
+ assert_equal c.created, c['created']
236
+ c['created'] = 12345
237
+ assert_equal c.created, 12345
238
+ end
239
+
240
+ should "accessing a property other than id or parent on an unfetched object should fetch it" do
241
+ @mock.expects(:get).once.returns(test_response(test_customer))
242
+ c = Stripe::Customer.new("test_customer")
243
+ c.charges
244
+ end
245
+
246
+ should "updating an object should issue a POST request with only the changed properties" do
247
+ @mock.expects(:post).with do |url, api_key, params|
248
+ url == "#{Stripe.api_base}/v1/customers/c_test_customer" && api_key.nil? && CGI.parse(params) == {'description' => ['another_mn']}
249
+ end.once.returns(test_response(test_customer))
250
+ c = Stripe::Customer.construct_from(test_customer)
251
+ c.description = "another_mn"
252
+ c.save
253
+ end
254
+
255
+ should "updating should merge in returned properties" do
256
+ @mock.expects(:post).once.returns(test_response(test_customer))
257
+ c = Stripe::Customer.new("c_test_customer")
258
+ c.description = "another_mn"
259
+ c.save
260
+ assert_equal false, c.livemode
261
+ end
262
+
263
+ should "deleting should send no props and result in an object that has no props other deleted" do
264
+ @mock.expects(:get).never
265
+ @mock.expects(:post).never
266
+ @mock.expects(:delete).with("#{Stripe.api_base}/v1/customers/c_test_customer", nil, nil).once.returns(test_response({ "id" => "test_customer", "deleted" => true }))
267
+
268
+ c = Stripe::Customer.construct_from(test_customer)
269
+ c.delete
270
+ assert_equal true, c.deleted
271
+
272
+ assert_raises NoMethodError do
273
+ c.livemode
274
+ end
275
+ end
276
+
277
+ should "loading an object with properties that have specific types should instantiate those classes" do
278
+ @mock.expects(:get).once.returns(test_response(test_charge))
279
+ c = Stripe::Charge.retrieve("test_charge")
280
+ assert c.card.kind_of?(Stripe::StripeObject) && c.card.object == 'card'
281
+ end
282
+
283
+ should "loading all of an APIResource should return an array of recursively instantiated objects" do
284
+ @mock.expects(:get).once.returns(test_response(test_charge_array))
285
+ c = Stripe::Charge.all.data
286
+ assert c.kind_of? Array
287
+ assert c[0].kind_of? Stripe::Charge
288
+ assert c[0].card.kind_of?(Stripe::StripeObject) && c[0].card.object == 'card'
289
+ end
290
+
291
+ context "error checking" do
292
+
293
+ should "404s should raise an InvalidRequestError" do
294
+ response = test_response(test_missing_id_error, 404)
295
+ @mock.expects(:get).once.raises(RestClient::ExceptionWithResponse.new(response, 404))
296
+
297
+ begin
298
+ Stripe::Customer.new("test_customer").refresh
299
+ assert false #shouldn't get here either
300
+ rescue Stripe::InvalidRequestError => e # we don't use assert_raises because we want to examine e
301
+ assert e.kind_of? Stripe::InvalidRequestError
302
+ assert_equal "id", e.param
303
+ assert_equal "Missing id", e.message
304
+ return
305
+ end
306
+
307
+ assert false #shouldn't get here
308
+ end
309
+
310
+ should "5XXs should raise an APIError" do
311
+ response = test_response(test_api_error, 500)
312
+ @mock.expects(:get).once.raises(RestClient::ExceptionWithResponse.new(response, 500))
313
+
314
+ begin
315
+ Stripe::Customer.new("test_customer").refresh
316
+ assert false #shouldn't get here either
317
+ rescue Stripe::APIError => e # we don't use assert_raises because we want to examine e
318
+ assert e.kind_of? Stripe::APIError
319
+ return
320
+ end
321
+
322
+ assert false #shouldn't get here
323
+ end
324
+
325
+ should "402s should raise a CardError" do
326
+ response = test_response(test_invalid_exp_year_error, 402)
327
+ @mock.expects(:get).once.raises(RestClient::ExceptionWithResponse.new(response, 402))
328
+
329
+ begin
330
+ Stripe::Customer.new("test_customer").refresh
331
+ assert false #shouldn't get here either
332
+ rescue Stripe::CardError => e # we don't use assert_raises because we want to examine e
333
+ assert e.kind_of? Stripe::CardError
334
+ assert_equal "invalid_expiry_year", e.code
335
+ assert_equal "exp_year", e.param
336
+ assert_equal "Your card's expiration year is invalid", e.message
337
+ return
338
+ end
339
+
340
+ assert false #shouldn't get here
341
+ end
342
+ end
343
+ end
344
+ end
345
+ end