rainforest 1.0.1

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.
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
+