rainforest 1.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (47) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +4 -0
  3. data/.travis.yml +10 -0
  4. data/CONTRIBUTORS +1 -0
  5. data/Gemfile +2 -0
  6. data/History.txt +4 -0
  7. data/LICENSE +21 -0
  8. data/README.md +50 -0
  9. data/Rakefile +15 -0
  10. data/VERSION +1 -0
  11. data/bin/rainforest-console +7 -0
  12. data/gemfiles/default-with-activesupport.gemfile +3 -0
  13. data/gemfiles/json.gemfile +4 -0
  14. data/gemfiles/yajl.gemfile +4 -0
  15. data/lib/.DS_Store +0 -0
  16. data/lib/data/ca-certificates.crt +3918 -0
  17. data/lib/rainforest.rb +271 -0
  18. data/lib/rainforest/api_operations/create.rb +16 -0
  19. data/lib/rainforest/api_operations/delete.rb +11 -0
  20. data/lib/rainforest/api_operations/list.rb +18 -0
  21. data/lib/rainforest/api_operations/update.rb +61 -0
  22. data/lib/rainforest/api_resource.rb +33 -0
  23. data/lib/rainforest/errors/api_connection_error.rb +4 -0
  24. data/lib/rainforest/errors/api_error.rb +4 -0
  25. data/lib/rainforest/errors/authentication_error.rb +4 -0
  26. data/lib/rainforest/errors/invalid_request_error.rb +10 -0
  27. data/lib/rainforest/errors/rainforest_error.rb +20 -0
  28. data/lib/rainforest/json.rb +21 -0
  29. data/lib/rainforest/list_object.rb +35 -0
  30. data/lib/rainforest/rainforest_object.rb +168 -0
  31. data/lib/rainforest/run.rb +8 -0
  32. data/lib/rainforest/singleton_api_resource.rb +20 -0
  33. data/lib/rainforest/test.rb +14 -0
  34. data/lib/rainforest/util.rb +101 -0
  35. data/lib/rainforest/version.rb +3 -0
  36. data/rainforest.gemspec +26 -0
  37. data/test/stripe/account_test.rb +14 -0
  38. data/test/stripe/api_resource_test.rb +345 -0
  39. data/test/stripe/charge_test.rb +67 -0
  40. data/test/stripe/coupon_test.rb +11 -0
  41. data/test/stripe/customer_test.rb +70 -0
  42. data/test/stripe/invoice_test.rb +20 -0
  43. data/test/stripe/list_object_test.rb +16 -0
  44. data/test/stripe/metadata_test.rb +114 -0
  45. data/test/stripe/util_test.rb +29 -0
  46. data/test/test_helper.rb +356 -0
  47. metadata +191 -0
@@ -0,0 +1,20 @@
1
+ require File.expand_path('../../test_helper', __FILE__)
2
+
3
+ module Rainforest
4
+ class InvoiceTest < Test::Unit::TestCase
5
+ should "retrieve should retrieve invoices" do
6
+ @mock.expects(:get).once.returns(test_response(test_invoice))
7
+ i = Rainforest::Invoice.retrieve('in_test_invoice')
8
+ assert_equal 'in_test_invoice', i.id
9
+ end
10
+
11
+ should "pay should pay an invoice" do
12
+ @mock.expects(:get).once.returns(test_response(test_invoice))
13
+ i = Rainforest::Invoice.retrieve('in_test_invoice')
14
+
15
+ @mock.expects(:post).once.with('https://api.rainforest.com/v1/invoices/in_test_invoice/pay', nil, '').returns(test_response(test_paid_invoice))
16
+ i.pay
17
+ assert_equal i.next_payment_attempt, nil
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,16 @@
1
+ require File.expand_path('../../test_helper', __FILE__)
2
+
3
+ module Rainforest
4
+ class ListObjectTest < Test::Unit::TestCase
5
+ should "be able to retrieve full lists given a listobject" do
6
+ @mock.expects(:get).twice.returns(test_response(test_charge_array))
7
+ c = Rainforest::Charge.all
8
+ assert c.kind_of?(Rainforest::ListObject)
9
+ assert_equal('/v1/charges', c.url)
10
+ all = c.all
11
+ assert all.kind_of?(Rainforest::ListObject)
12
+ assert_equal('/v1/charges', all.url)
13
+ assert all.data.kind_of?(Array)
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,114 @@
1
+ require File.expand_path('../../test_helper', __FILE__)
2
+
3
+ module Rainforest
4
+ class MetadataTest < Test::Unit::TestCase
5
+ setup do
6
+ @metadata_supported = {
7
+ :charge => {
8
+ :new => Rainforest::Charge.method(:new),
9
+ :test => method(:test_charge),
10
+ :url => "/v1/charges/#{test_charge()[:id]}"
11
+ },
12
+ :customer => {
13
+ :new => Rainforest::Customer.method(:new),
14
+ :test => method(:test_customer),
15
+ :url => "/v1/customers/#{test_customer()[:id]}"
16
+ },
17
+ :recipient => {
18
+ :new => Rainforest::Recipient.method(:new),
19
+ :test => method(:test_recipient),
20
+ :url => "/v1/recipients/#{test_recipient()[:id]}"
21
+ },
22
+ :transfer => {
23
+ :new => Rainforest::Transfer.method(:new),
24
+ :test => method(:test_transfer),
25
+ :url => "/v1/transfers/#{test_transfer()[:id]}"
26
+ }
27
+ }
28
+
29
+ @base_url = 'https://api.rainforest.com'
30
+ end
31
+
32
+ should "not touch metadata" do
33
+ update_actions = lambda {|obj| obj.description = 'test'}
34
+ check_metadata({:metadata => {'initial' => 'true'}},
35
+ 'description=test',
36
+ update_actions)
37
+ end
38
+
39
+
40
+ should "update metadata as a whole" do
41
+ update_actions = lambda {|obj| obj.metadata = {'uuid' => '6735'}}
42
+ check_metadata({:metadata => {}},
43
+ 'metadata[uuid]=6735',
44
+ update_actions)
45
+
46
+ if is_greater_than_ruby_1_9?
47
+ check_metadata({:metadata => {:initial => 'true'}},
48
+ 'metadata[uuid]=6735&metadata[initial]=',
49
+ update_actions)
50
+ end
51
+ end
52
+
53
+ should "update metadata keys individually" do
54
+ update_actions = lambda {|obj| obj.metadata['txn_id'] = '134a13'}
55
+ check_metadata({:metadata => {'initial' => 'true'}},
56
+ 'metadata[txn_id]=134a13',
57
+ update_actions)
58
+ end
59
+
60
+ should "clear metadata as a whole" do
61
+ update_actions = lambda {|obj| obj.metadata = nil}
62
+ check_metadata({:metadata => {'initial' => 'true'}},
63
+ 'metadata=',
64
+ update_actions)
65
+ end
66
+
67
+ should "clear metadata keys individually" do
68
+ update_actions = lambda {|obj| obj.metadata['initial'] = nil}
69
+ check_metadata({:metadata => {'initial' => 'true'}},
70
+ 'metadata[initial]=',
71
+ update_actions)
72
+ end
73
+
74
+ should "handle combinations of whole and partial metadata updates" do
75
+ if is_greater_than_ruby_1_9?
76
+ update_actions = lambda do |obj|
77
+ obj.metadata = {'type' => 'summer'}
78
+ obj.metadata['uuid'] = '6735'
79
+ end
80
+ params = {:metadata => {'type' => 'summer', 'uuid' => '6735'}}
81
+ curl_args = Rainforest.uri_encode(params)
82
+ check_metadata({:metadata => {'type' => 'christmas'}},
83
+ curl_args,
84
+ update_actions)
85
+ end
86
+ end
87
+
88
+ def check_metadata (initial_params, curl_args, metadata_update)
89
+ @metadata_supported.each do |name, methods|
90
+ neu = methods[:new]
91
+ test = methods[:test]
92
+ url = @base_url + methods[:url]
93
+
94
+ initial_test_obj = test.call(initial_params)
95
+ @mock.expects(:get).once.returns(test_response(initial_test_obj))
96
+
97
+ final_test_obj = test.call()
98
+ @mock.expects(:post).once.
99
+ returns(test_response(final_test_obj)).
100
+ with(url, nil, curl_args)
101
+
102
+ obj = neu.call("test")
103
+ obj.refresh()
104
+ metadata_update.call(obj)
105
+ obj.save
106
+ end
107
+ end
108
+
109
+ def is_greater_than_ruby_1_9?
110
+ version = RUBY_VERSION.dup # clone preserves frozen state
111
+ Gem::Version.new(version) >= Gem::Version.new('1.9')
112
+ end
113
+ end
114
+ end
@@ -0,0 +1,29 @@
1
+ require File.expand_path('../../test_helper', __FILE__)
2
+
3
+ module Rainforest
4
+ class UtilTest < Test::Unit::TestCase
5
+ should "symbolize_names should convert names to symbols" do
6
+ start = {
7
+ 'foo' => 'bar',
8
+ 'array' => [{ 'foo' => 'bar' }],
9
+ 'nested' => {
10
+ 1 => 2,
11
+ :symbol => 9,
12
+ 'string' => nil
13
+ }
14
+ }
15
+ finish = {
16
+ :foo => 'bar',
17
+ :array => [{ :foo => 'bar' }],
18
+ :nested => {
19
+ 1 => 2,
20
+ :symbol => 9,
21
+ :string => nil
22
+ }
23
+ }
24
+
25
+ symbolized = Rainforest::Util.symbolize_names(start)
26
+ assert_equal(finish, symbolized)
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,356 @@
1
+ require 'rainforest'
2
+ require 'test/unit'
3
+ require 'mocha/setup'
4
+ require 'stringio'
5
+ require 'shoulda'
6
+
7
+ #monkeypatch request methods
8
+ module Rainforest
9
+ @mock_rest_client = nil
10
+
11
+ def self.mock_rest_client=(mock_client)
12
+ @mock_rest_client = mock_client
13
+ end
14
+
15
+ def self.execute_request(opts)
16
+ get_params = (opts[:headers] || {})[:params]
17
+ post_params = opts[:payload]
18
+ case opts[:method]
19
+ when :get then @mock_rest_client.get opts[:url], get_params, post_params
20
+ when :post then @mock_rest_client.post opts[:url], get_params, post_params
21
+ when :delete then @mock_rest_client.delete opts[:url], get_params, post_params
22
+ end
23
+ end
24
+ end
25
+
26
+ def test_response(body, code=200)
27
+ # When an exception is raised, restclient clobbers method_missing. Hence we
28
+ # can't just use the stubs interface.
29
+ body = MultiJson.dump(body) if !(body.kind_of? String)
30
+ m = mock
31
+ m.instance_variable_set('@rainforest_values', { :body => body, :code => code })
32
+ def m.body; @rainforest_values[:body]; end
33
+ def m.code; @rainforest_values[:code]; end
34
+ m
35
+ end
36
+
37
+ def test_balance(params={})
38
+ {
39
+ :pending => [
40
+ {:amount => 12345, :currency => "usd"}
41
+ ],
42
+ :available => [
43
+ {:amount => 6789, :currency => "usd"}
44
+ ],
45
+ :livemode => false,
46
+ :object => "balance"
47
+ }.merge(params)
48
+ end
49
+
50
+ def test_balance_transaction(params={})
51
+ {
52
+ :amount => 100,
53
+ :net => 41,
54
+ :currency => "usd",
55
+ :type => "charge",
56
+ :created => 1371945005,
57
+ :available_on => 1372549805,
58
+ :status => "pending",
59
+ :description => "A test balance transaction",
60
+ :fee => 59,
61
+ :object => "balance_transaction"
62
+ }.merge(params)
63
+ end
64
+
65
+ def test_balance_transaction_array
66
+ {
67
+ :data => [test_balance_transaction, test_balance_transaction, test_balance_transaction],
68
+ :object => "list",
69
+ :url => "/v1/balance/history"
70
+ }
71
+ end
72
+
73
+ def test_customer(params={})
74
+ {
75
+ :subscription_history => [],
76
+ :bills => [],
77
+ :charges => [],
78
+ :livemode => false,
79
+ :object => "customer",
80
+ :id => "c_test_customer",
81
+ :default_card => "cc_test_card",
82
+ :created => 1304114758,
83
+ :cards => test_card_array('c_test_customer'),
84
+ :metadata => {}
85
+ }.merge(params)
86
+ end
87
+
88
+ def test_customer_array
89
+ {
90
+ :data => [test_customer, test_customer, test_customer],
91
+ :object => 'list',
92
+ :url => '/v1/customers'
93
+ }
94
+ end
95
+
96
+ def test_charge(params={})
97
+ {
98
+ :refunded => false,
99
+ :paid => true,
100
+ :amount => 100,
101
+ :card => {
102
+ :type => "Visa",
103
+ :last4 => "4242",
104
+ :exp_month => 11,
105
+ :country => "US",
106
+ :exp_year => 2012,
107
+ :id => "cc_test_card",
108
+ :object => "card"
109
+ },
110
+ :id => "ch_test_charge",
111
+ :reason => "execute_charge",
112
+ :livemode => false,
113
+ :currency => "usd",
114
+ :object => "charge",
115
+ :created => 1304114826,
116
+ :metadata => {}
117
+ }.merge(params)
118
+ end
119
+
120
+ def test_charge_array
121
+ {
122
+ :data => [test_charge, test_charge, test_charge],
123
+ :object => 'list',
124
+ :url => '/v1/charges'
125
+ }
126
+ end
127
+
128
+ def test_card_array(customer_id)
129
+ {
130
+ :data => [test_card, test_card, test_card],
131
+ :object => 'list',
132
+ :url => '/v1/customers/' + customer_id + '/cards'
133
+ }
134
+ end
135
+
136
+ def test_card(params={})
137
+ {
138
+ :type => "Visa",
139
+ :last4 => "4242",
140
+ :exp_month => 11,
141
+ :country => "US",
142
+ :exp_year => 2012,
143
+ :id => "cc_test_card",
144
+ :customer => 'c_test_customer',
145
+ :object => "card"
146
+ }.merge(params)
147
+ end
148
+
149
+ def test_coupon(params={})
150
+ {
151
+ :duration => 'repeating',
152
+ :duration_in_months => 3,
153
+ :percent_off => 25,
154
+ :id => "co_test_coupon",
155
+ :object => "coupon"
156
+ }.merge(params)
157
+ end
158
+
159
+ #FIXME nested overrides would be better than hardcoding plan_id
160
+ def test_subscription(plan_id="gold")
161
+ {
162
+ :current_period_end => 1308681468,
163
+ :status => "trialing",
164
+ :plan => {
165
+ :interval => "month",
166
+ :amount => 7500,
167
+ :trial_period_days => 30,
168
+ :object => "plan",
169
+ :identifier => plan_id
170
+ },
171
+ :current_period_start => 1308595038,
172
+ :start => 1308595038,
173
+ :object => "subscription",
174
+ :trial_start => 1308595038,
175
+ :trial_end => 1308681468,
176
+ :customer => "c_test_customer"
177
+ }
178
+ end
179
+
180
+ def test_invoice
181
+ {
182
+ :id => 'in_test_invoice',
183
+ :object => 'invoice',
184
+ :livemode => false,
185
+ :amount_due => 1000,
186
+ :attempt_count => 0,
187
+ :attempted => false,
188
+ :closed => false,
189
+ :currency => 'usd',
190
+ :customer => 'c_test_customer',
191
+ :date => 1349738950,
192
+ :lines => {
193
+ "invoiceitems" => [
194
+ {
195
+ :id => 'ii_test_invoice_item',
196
+ :object => '',
197
+ :livemode => false,
198
+ :amount => 1000,
199
+ :currency => 'usd',
200
+ :customer => 'c_test_customer',
201
+ :date => 1349738950,
202
+ :description => "A Test Invoice Item",
203
+ :invoice => 'in_test_invoice'
204
+ },
205
+ ],
206
+ },
207
+ :paid => false,
208
+ :period_end => 1349738950,
209
+ :period_start => 1349738950,
210
+ :starting_balance => 0,
211
+ :subtotal => 1000,
212
+ :total => 1000,
213
+ :charge => nil,
214
+ :discount => nil,
215
+ :ending_balance => nil,
216
+ :next_payemnt_attempt => 1349825350,
217
+ }
218
+ end
219
+
220
+ def test_paid_invoice
221
+ test_invoice.merge({
222
+ :attempt_count => 1,
223
+ :attempted => true,
224
+ :closed => true,
225
+ :paid => true,
226
+ :charge => 'ch_test_charge',
227
+ :ending_balance => 0,
228
+ :next_payment_attempt => nil,
229
+ })
230
+ end
231
+
232
+ def test_invoice_customer_array
233
+ {
234
+ :data => [test_invoice],
235
+ :object => 'list',
236
+ :url => '/v1/invoices?customer=test_customer'
237
+ }
238
+ end
239
+
240
+ def test_recipient(params={})
241
+ {
242
+ :name => "Rainforest User",
243
+ :type => "individual",
244
+ :livemode => false,
245
+ :object => "recipient",
246
+ :id => "rp_test_recipient",
247
+ :active_account => {
248
+ :last4 => "6789",
249
+ :bank_name => "STRIPE TEST BANK",
250
+ :country => "US",
251
+ :object => "bank_account"
252
+ },
253
+ :created => 1304114758,
254
+ :verified => true,
255
+ :metadata => {}
256
+ }.merge(params)
257
+ end
258
+
259
+ def test_recipient_array
260
+ {
261
+ :data => [test_recipient, test_recipient, test_recipient],
262
+ :object => 'list',
263
+ :url => '/v1/recipients'
264
+ }
265
+ end
266
+
267
+ def test_transfer(params={})
268
+ {
269
+ :status => 'pending',
270
+ :amount => 100,
271
+ :account => {
272
+ :object => 'bank_account',
273
+ :country => 'US',
274
+ :bank_name => 'STRIPE TEST BANK',
275
+ :last4 => '6789'
276
+ },
277
+ :recipient => 'test_recipient',
278
+ :fee => 0,
279
+ :fee_details => [],
280
+ :id => "tr_test_transfer",
281
+ :livemode => false,
282
+ :currency => "usd",
283
+ :object => "transfer",
284
+ :date => 1304114826,
285
+ :metadata => {}
286
+ }.merge(params)
287
+ end
288
+
289
+ def test_transfer_array
290
+ {
291
+ :data => [test_transfer, test_transfer, test_transfer],
292
+ :object => 'list',
293
+ :url => '/v1/transfers'
294
+ }
295
+ end
296
+
297
+ def test_invalid_api_key_error
298
+ {
299
+ "error" => {
300
+ "type" => "invalid_request_error",
301
+ "message" => "Invalid API Key provided: invalid"
302
+ }
303
+ }
304
+ end
305
+
306
+ def test_invalid_exp_year_error
307
+ {
308
+ "error" => {
309
+ "code" => "invalid_expiry_year",
310
+ "param" => "exp_year",
311
+ "type" => "card_error",
312
+ "message" => "Your card's expiration year is invalid"
313
+ }
314
+ }
315
+ end
316
+
317
+ def test_missing_id_error
318
+ {
319
+ :error => {
320
+ :param => "id",
321
+ :type => "invalid_request_error",
322
+ :message => "Missing id"
323
+ }
324
+ }
325
+ end
326
+
327
+ def test_api_error
328
+ {
329
+ :error => {
330
+ :type => "api_error"
331
+ }
332
+ }
333
+ end
334
+
335
+ def test_delete_discount_response
336
+ {
337
+ :deleted => true,
338
+ :id => "di_test_coupon"
339
+ }
340
+ end
341
+
342
+ class Test::Unit::TestCase
343
+ include Mocha
344
+
345
+ setup do
346
+ @mock = mock
347
+ Rainforest.mock_rest_client = @mock
348
+ Rainforest.api_key="foo"
349
+ end
350
+
351
+ teardown do
352
+ Rainforest.mock_rest_client = nil
353
+ Rainforest.api_key=nil
354
+ end
355
+ end
356
+