peakium 0.1.0 → 0.1.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 (54) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +4 -0
  3. data/.travis.yml +11 -0
  4. data/CONTRIBUTORS +1 -0
  5. data/Gemfile +2 -0
  6. data/History.txt +0 -0
  7. data/LICENSE +21 -0
  8. data/README.rdoc +43 -0
  9. data/Rakefile +16 -0
  10. data/VERSION +1 -0
  11. data/bin/peakium-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/data/ca-certificates.crt +3828 -0
  16. data/lib/peakium/api_operations/create.rb +16 -0
  17. data/lib/peakium/api_operations/delete.rb +11 -0
  18. data/lib/peakium/api_operations/list.rb +21 -0
  19. data/lib/peakium/api_operations/update.rb +17 -0
  20. data/lib/peakium/api_resource.rb +33 -0
  21. data/lib/peakium/api_resources/customer.rb +25 -0
  22. data/lib/peakium/api_resources/event.rb +28 -0
  23. data/lib/peakium/api_resources/event_webhook.rb +5 -0
  24. data/lib/peakium/api_resources/gateway.rb +19 -0
  25. data/lib/peakium/api_resources/invoice.rb +26 -0
  26. data/lib/peakium/api_resources/payment_session.rb +5 -0
  27. data/lib/peakium/api_resources/submission_form.rb +12 -0
  28. data/lib/peakium/api_resources/subscription.rb +26 -0
  29. data/lib/peakium/api_resources/webhook.rb +21 -0
  30. data/lib/peakium/errors/api_connection_error.rb +4 -0
  31. data/lib/peakium/errors/api_error.rb +4 -0
  32. data/lib/peakium/errors/authentication_error.rb +4 -0
  33. data/lib/peakium/errors/invalid_request_error.rb +10 -0
  34. data/lib/peakium/errors/peakium_error.rb +20 -0
  35. data/lib/peakium/list_object.rb +31 -0
  36. data/lib/peakium/peakium_object.rb +167 -0
  37. data/lib/peakium/util.rb +115 -0
  38. data/lib/peakium/version.rb +3 -0
  39. data/lib/peakium.rb +265 -0
  40. data/peakium.gemspec +27 -0
  41. data/test/peakium/api_resource_test.rb +315 -0
  42. data/test/peakium/customer_test.rb +21 -0
  43. data/test/peakium/event_test.rb +30 -0
  44. data/test/peakium/event_webhook_test.rb +13 -0
  45. data/test/peakium/gateway_test.rb +35 -0
  46. data/test/peakium/invoice_test.rb +21 -0
  47. data/test/peakium/list_object_test.rb +16 -0
  48. data/test/peakium/payment_session_test.rb +13 -0
  49. data/test/peakium/submission_form_test.rb +12 -0
  50. data/test/peakium/subscription_test.rb +13 -0
  51. data/test/peakium/util_test.rb +29 -0
  52. data/test/peakium/webhook_test.rb +20 -0
  53. data/test/test_helper.rb +337 -0
  54. metadata +99 -52
data/lib/peakium.rb ADDED
@@ -0,0 +1,265 @@
1
+ # Peakium Ruby bindings
2
+ # API spec at https://github.com/peakium/peakium-api
3
+ require 'cgi'
4
+ require 'set'
5
+ require 'openssl'
6
+ require 'rest_client'
7
+ require 'json'
8
+
9
+ # Version
10
+ require 'peakium/version'
11
+
12
+ # API operations
13
+ require 'peakium/api_operations/create'
14
+ require 'peakium/api_operations/update'
15
+ require 'peakium/api_operations/delete'
16
+ require 'peakium/api_operations/list'
17
+
18
+ # Resources
19
+ require 'peakium/util'
20
+ require 'peakium/peakium_object'
21
+ require 'peakium/api_resource'
22
+ require 'peakium/list_object'
23
+
24
+ # Resources
25
+ require 'peakium/api_resources/customer'
26
+ require 'peakium/api_resources/event'
27
+ require 'peakium/api_resources/event_webhook'
28
+ require 'peakium/api_resources/gateway'
29
+ require 'peakium/api_resources/invoice'
30
+ require 'peakium/api_resources/payment_session'
31
+ require 'peakium/api_resources/subscription'
32
+ require 'peakium/api_resources/submission_form'
33
+ require 'peakium/api_resources/webhook'
34
+
35
+ # Errors
36
+ require 'peakium/errors/peakium_error'
37
+ require 'peakium/errors/api_error'
38
+ require 'peakium/errors/api_connection_error'
39
+ require 'peakium/errors/invalid_request_error'
40
+ require 'peakium/errors/authentication_error'
41
+
42
+ module Peakium
43
+ @api_base = 'https://secure.peakium.com/api'
44
+
45
+ @ssl_bundle_path = File.dirname(__FILE__) + '/data/ca-certificates.crt'
46
+ @verify_ssl_certs = true
47
+
48
+ class << self
49
+ attr_accessor :api_key, :api_base, :verify_ssl_certs, :api_version
50
+ end
51
+
52
+ def self.api_url(endpoint_url='')
53
+ @api_base + endpoint_url
54
+ end
55
+
56
+ def self.request(method, endpoint_url, api_key, params={}, headers={})
57
+ unless api_key ||= @api_key
58
+ raise AuthenticationError.new('No API key provided. ' +
59
+ 'Set your API key using "Peakium.api_key = <API-KEY>". ' +
60
+ 'You can generate API keys from the Peakium web interface. ' +
61
+ 'Go to https://manage.peakium.com/.')
62
+ end
63
+
64
+ if api_key =~ /\s/
65
+ raise AuthenticationError.new('Your API key is invalid, as it contains ' +
66
+ 'whitespace. (HINT: You can double-check your API key from the ' +
67
+ 'Peakium web interface. Go to https://manage.peakium.com/.)')
68
+ end
69
+
70
+ request_opts = { :verify_ssl => false }
71
+
72
+ if ssl_preflight_passed?
73
+ request_opts.update(:verify_ssl => OpenSSL::SSL::VERIFY_PEER,
74
+ :ssl_ca_file => @ssl_bundle_path)
75
+ end
76
+
77
+ params = Util.objects_to_ids(params)
78
+ url = api_url(endpoint_url)
79
+
80
+ case method.to_s.downcase.to_sym
81
+ when :get, :head, :delete
82
+ # Make params into GET parameters
83
+ url += "#{URI.parse(url).query ? '&' : '?'}#{uri_encode(params)}" if params && params.any?
84
+ payload = nil
85
+ else
86
+ if params.instance_of? String
87
+ payload = params
88
+ else
89
+ payload = uri_encode(params)
90
+ end
91
+ end
92
+
93
+ request_opts.update(:headers => request_headers(api_key).update(headers),
94
+ :method => method, :open_timeout => 30,
95
+ :payload => payload, :url => url, :timeout => 80)
96
+
97
+ begin
98
+ response = execute_request(request_opts)
99
+ rescue SocketError => e
100
+ handle_restclient_error(e)
101
+ rescue NoMethodError => e
102
+ # Work around RestClient bug
103
+ if e.message =~ /\WRequestFailed\W/
104
+ e = APIConnectionError.new('Unexpected HTTP response code')
105
+ handle_restclient_error(e)
106
+ else
107
+ raise
108
+ end
109
+ rescue RestClient::ExceptionWithResponse => e
110
+ if rcode = e.http_code and rbody = e.http_body
111
+ handle_api_error(rcode, rbody)
112
+ else
113
+ handle_restclient_error(e)
114
+ end
115
+ rescue RestClient::Exception, Errno::ECONNREFUSED => e
116
+ handle_restclient_error(e)
117
+ end
118
+
119
+ [parse(response), api_key]
120
+ end
121
+
122
+ private
123
+
124
+ def self.ssl_preflight_passed?
125
+ if !verify_ssl_certs && !@no_verify
126
+ $stderr.puts "WARNING: Running without SSL cert verification. " +
127
+ "Execute 'Peakium.verify_ssl_certs = true' to enable verification."
128
+
129
+ @no_verify = true
130
+
131
+ elsif !Util.file_readable(@ssl_bundle_path) && !@no_bundle
132
+ $stderr.puts "WARNING: Running without SSL cert verification " +
133
+ "because #{@ssl_bundle_path} isn't readable"
134
+
135
+ @no_bundle = true
136
+ end
137
+
138
+ !(@no_verify || @no_bundle)
139
+ end
140
+
141
+ def self.user_agent
142
+ @uname ||= get_uname
143
+ lang_version = "#{RUBY_VERSION} p#{RUBY_PATCHLEVEL} (#{RUBY_RELEASE_DATE})"
144
+
145
+ {
146
+ :bindings_version => Peakium::VERSION,
147
+ :lang => 'ruby',
148
+ :lang_version => lang_version,
149
+ :platform => RUBY_PLATFORM,
150
+ :publisher => 'peakium',
151
+ :uname => @uname
152
+ }
153
+
154
+ end
155
+
156
+ def self.get_uname
157
+ `uname -a 2>/dev/null`.strip if RUBY_PLATFORM =~ /linux|darwin/i
158
+ rescue Errno::ENOMEM => ex # couldn't create subprocess
159
+ "uname lookup failed"
160
+ end
161
+
162
+ def self.uri_encode(params)
163
+ Util.flatten_params(params).
164
+ map { |k,v| "#{k}=#{Util.url_encode(v)}" }.join('&')
165
+ end
166
+
167
+ def self.request_headers(api_key)
168
+ headers = {
169
+ :user_agent => "Peakium/v1 RubyBindings/#{Peakium::VERSION}",
170
+ :authorization => "Bearer #{api_key}",
171
+ :content_type => 'application/x-www-form-urlencoded'
172
+ }
173
+
174
+ headers[:peakium_version] = api_version if api_version
175
+
176
+ begin
177
+ headers.update(:x_peakium_client_user_agent => JSON.generate(user_agent))
178
+ rescue => e
179
+ headers.update(:x_peakium_client_raw_user_agent => user_agent.inspect,
180
+ :error => "#{e} (#{e.class})")
181
+ end
182
+ end
183
+
184
+ def self.execute_request(opts)
185
+ RestClient::Request.execute(opts)
186
+ end
187
+
188
+ def self.parse(response)
189
+ begin
190
+ # Would use :symbolize_names => true, but apparently there is
191
+ # some library out there that makes symbolize_names not work.
192
+ response = JSON.parse(response.body)
193
+ rescue JSON::ParserError
194
+ raise general_api_error(response.code, response.body)
195
+ end
196
+
197
+ Util.symbolize_names(response)
198
+ end
199
+
200
+ def self.general_api_error(rcode, rbody)
201
+ APIError.new("Invalid response object from API: #{rbody.inspect} " +
202
+ "(HTTP response code was #{rcode})", rcode, rbody)
203
+ end
204
+
205
+ def self.handle_api_error(rcode, rbody)
206
+ begin
207
+ error_obj = JSON.parse(rbody)
208
+ error_obj = Util.symbolize_names(error_obj)
209
+ error = error_obj[:error] or raise PeakiumError.new # escape from parsing
210
+
211
+ rescue JSON::ParserError, PeakiumError
212
+ raise general_api_error(rcode, rbody)
213
+ end
214
+
215
+ case rcode
216
+ when 400, 404
217
+ raise invalid_request_error error, rcode, rbody, error_obj
218
+ when 401
219
+ raise authentication_error error, rcode, rbody, error_obj
220
+ else
221
+ raise api_error error, rcode, rbody, error_obj
222
+ end
223
+
224
+ end
225
+
226
+ def self.invalid_request_error(error, rcode, rbody, error_obj)
227
+ InvalidRequestError.new(error[:message], error[:param], rcode,
228
+ rbody, error_obj)
229
+ end
230
+
231
+ def self.authentication_error(error, rcode, rbody, error_obj)
232
+ AuthenticationError.new(error[:message], rcode, rbody, error_obj)
233
+ end
234
+
235
+ def self.api_error(error, rcode, rbody, error_obj)
236
+ APIError.new(error[:message], rcode, rbody, error_obj)
237
+ end
238
+
239
+ def self.handle_restclient_error(e)
240
+ case e
241
+ when RestClient::ServerBrokeConnection, RestClient::RequestTimeout
242
+ message = "Could not connect to Peakium (#{@api_base}). " +
243
+ "Please check your internet connection and try again. " +
244
+ "If this problem persists, let us know at contact@peakium.com."
245
+
246
+ when RestClient::SSLCertificateNotVerified
247
+ message = "Could not verify Peakium's SSL certificate. " +
248
+ "Please make sure that your network is not intercepting certificates. " +
249
+ "(Try going to https://secure.peakium.com/v1 in your browser.) " +
250
+ "If this problem persists, let us know at contact@peakium.com."
251
+
252
+ when SocketError
253
+ message = "Unexpected error communicating when trying to connect to Peakium. " +
254
+ "You may be seeing this message because your DNS is not working. " +
255
+ "To check, try running 'host secure.peakium.com' from the command line."
256
+
257
+ else
258
+ message = "Unexpected error communicating with Peakium. " +
259
+ "If this problem persists, let us know at contact@peakium.com."
260
+
261
+ end
262
+
263
+ raise APIConnectionError.new(message + "\n\n(Network error: #{e.message})")
264
+ end
265
+ end
data/peakium.gemspec ADDED
@@ -0,0 +1,27 @@
1
+ $:.unshift(File.join(File.dirname(__FILE__), 'lib'))
2
+
3
+ require 'peakium/version'
4
+
5
+ spec = Gem::Specification.new do |s|
6
+ s.name = 'peakium'
7
+ s.version = Peakium::VERSION
8
+ s.summary = 'Ruby bindings for the Peakium API'
9
+ s.description = 'Peakium allows global, flexible recurring payments. See https://peakium.com for details.'
10
+ s.authors = ['Dan Schultzer']
11
+ s.email = ['dan@dreamconception.com']
12
+ s.homepage = 'https://github.com/peakium/peakium-api'
13
+ s.license = 'MIT'
14
+
15
+ s.add_dependency('rest-client', '~> 1.4')
16
+ s.add_dependency('json', '~> 1.8.1')
17
+
18
+ s.add_development_dependency('mocha', '~> 0.13.2')
19
+ s.add_development_dependency('shoulda', '~> 3.4.0')
20
+ s.add_development_dependency('test-unit')
21
+ s.add_development_dependency('rake')
22
+
23
+ s.files = `git ls-files`.split("\n")
24
+ s.test_files = `git ls-files -- test/*`.split("\n")
25
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
26
+ s.require_paths = ['lib']
27
+ end
@@ -0,0 +1,315 @@
1
+ # -*- coding: utf-8 -*-
2
+ require File.expand_path('../../test_helper', __FILE__)
3
+
4
+ module Peakium
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
+ g = Peakium::Gateway.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
+ g = Peakium::Gateway.construct_from({
14
+ :id => "somegateway",
15
+ :object => "gateway"
16
+ })
17
+ end
18
+
19
+ should "setting an attribute should not cause a network request" do
20
+ @mock.expects(:get).never
21
+ @mock.expects(:post).never
22
+ g = Peakium::Gateway.new("gw_test_gateway");
23
+ g.name = "Gateway Test";
24
+ end
25
+
26
+ should "accessing id should not issue a fetch over the network" do
27
+ @mock.expects(:get).never
28
+ g = Peakium::Gateway.new("gw_test_gateway");
29
+ g.id
30
+ end
31
+
32
+ should "not specifying api credentials should raise an exception" do
33
+ Peakium.api_key = nil
34
+ assert_raises Peakium::AuthenticationError do
35
+ Peakium::Gateway.new("gw_test_gateway").refresh
36
+ end
37
+ end
38
+
39
+ should "specifying api credentials containing whitespace should raise an exception" do
40
+ Peakium.api_key = "key "
41
+ assert_raises Peakium::AuthenticationError do
42
+ Peakium::Gateway.new("gw_test_gateway").refresh
43
+ end
44
+ end
45
+
46
+ should "specifying invalid api credentials should raise an exception" do
47
+ Peakium.api_key = "invalid"
48
+ response = test_response(test_invalid_api_key_error, 401)
49
+ assert_raises Peakium::AuthenticationError do
50
+ @mock.expects(:get).once.raises(RestClient::ExceptionWithResponse.new(response, 401))
51
+ Peakium::Gateway.retrieve("gw_failing_gateway")
52
+ end
53
+ end
54
+
55
+ should "AuthenticationErrors should have an http status, http body, and JSON body" do
56
+ Peakium.api_key = "invalid"
57
+ response = test_response(test_invalid_api_key_error, 401)
58
+ begin
59
+ @mock.expects(:get).once.raises(RestClient::ExceptionWithResponse.new(response, 401))
60
+ Peakium::Gateway.retrieve("gw_failing_gateway")
61
+ rescue Peakium::AuthenticationError => e
62
+ assert_equal(401, e.http_status)
63
+ assert_equal(true, !!e.http_body)
64
+ assert_equal(true, !!e.json_body[:error][:message])
65
+ assert_equal(test_invalid_api_key_error['error']['message'], e.json_body[:error][:message])
66
+ end
67
+ end
68
+
69
+ context "when specifying per-object credentials" do
70
+ context "with no global API key set" do
71
+ should "use the per-object credential when creating" do
72
+ Peakium.expects(:execute_request).with do |opts|
73
+ opts[:headers][:authorization] == 'Bearer sk_test_local'
74
+ end.returns(test_response(test_gateway))
75
+
76
+ Peakium::Gateway.create({:name => "test", :module => "test", :settings => []},
77
+ 'sk_test_local')
78
+ end
79
+ end
80
+
81
+ context "with a global API key set" do
82
+ setup do
83
+ Peakium.api_key = "global"
84
+ end
85
+
86
+ teardown do
87
+ Peakium.api_key = nil
88
+ end
89
+
90
+ should "use the per-object credential when creating" do
91
+ Peakium.expects(:execute_request).with do |opts|
92
+ opts[:headers][:authorization] == 'Bearer local'
93
+ end.returns(test_response(test_gateway))
94
+
95
+ Peakium::Gateway.create({:name => "test", :module => "test", :settings => []},
96
+ 'local')
97
+ end
98
+
99
+ should "use the per-object credential when retrieving and making other calls" do
100
+ Peakium.expects(:execute_request).with do |opts|
101
+ opts[:url] == "#{Peakium.api_base}/v1/gateways/gw_test_gateway" &&
102
+ opts[:headers][:authorization] == 'Bearer local'
103
+ end.returns(test_response(test_gateway))
104
+ Peakium.expects(:execute_request).with do |opts|
105
+ opts[:url] == "#{Peakium.api_base}/v1/gateways/gw_test_gateway/default" &&
106
+ opts[:headers][:authorization] == 'Bearer local'
107
+ end.returns(test_response(test_gateway))
108
+
109
+ gw = Peakium::Gateway.retrieve('gw_test_gateway', 'local')
110
+ gw.set_default
111
+ end
112
+ end
113
+ end
114
+
115
+ context "with valid credentials" do
116
+
117
+ should "urlencode values in GET params" do
118
+ response = test_response(test_payment_session_array)
119
+ @mock.expects(:get).with("#{Peakium.api_base}/v1/payment_sessions?customer=test%20customer", nil, nil).returns(response)
120
+ payment_sessions = Peakium::PaymentSession.all(:customer => 'test customer').data
121
+ assert payment_sessions.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("#{Peakium.api_base}/v1/invoices?customer=test_customer", nil, nil).returns(response)
127
+ invoices = Peakium::Invoice.all(:customer => 'test_customer')
128
+
129
+ @mock.expects(:get).with("#{Peakium.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
+ Peakium::Gateway.retrieve("foo")
138
+ rescue Peakium::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
+ Peakium::Gateway.retrieve("foo")
150
+ rescue Peakium::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 404 should give an InvalidRequestError with http status, body, and JSON body" do
158
+ response = test_response(test_missing_id_error, 404)
159
+ @mock.expects(:get).once.raises(RestClient::ExceptionWithResponse.new(response, 404))
160
+ begin
161
+ Peakium::Gateway.retrieve("foo")
162
+ rescue Peakium::InvalidRequestError => e
163
+ assert_equal(404, 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 "setting a nil value for a param should exclude that param from the request" do
170
+ @mock.expects(:get).with do |url, api_key, params|
171
+ uri = URI(url)
172
+ query = CGI.parse(uri.query)
173
+ (url =~ %r{^#{Peakium.api_base}/v1/gateways?} &&
174
+ query.keys.sort == ['offset', 'sad'])
175
+ end.returns(test_response({ :count => 1, :data => [test_gateway] }))
176
+ g = Peakium::Gateway.all(:count => nil, :offset => 5, :sad => false)
177
+
178
+ @mock.expects(:post).with do |url, api_key, params|
179
+ url == "#{Peakium.api_base}/v1/gateways" &&
180
+ api_key.nil? &&
181
+ CGI.parse(params) == { 'name' => ['test'], 'module' => ['test'] }
182
+ end.returns(test_response({ :count => 1, :data => [test_gateway] }))
183
+ g = Peakium::Gateway.create(:name => "test", :module => "test", :settings => [])
184
+ end
185
+
186
+ should "requesting with a unicode ID should result in a request" do
187
+ response = test_response(test_missing_id_error, 404)
188
+ @mock.expects(:get).once.with("#{Peakium.api_base}/v1/gateways/%E2%98%83", nil, nil).raises(RestClient::ExceptionWithResponse.new(response, 404))
189
+ g = Peakium::Gateway.new("☃")
190
+ assert_raises(Peakium::InvalidRequestError) { g.refresh }
191
+ end
192
+
193
+ should "requesting with no ID should result in an InvalidRequestError with no request" do
194
+ g = Peakium::Gateway.new
195
+ assert_raises(Peakium::InvalidRequestError) { g.refresh }
196
+ end
197
+
198
+ should "making a GET request with parameters should have a query string and no body" do
199
+ params = { :limit => 1 }
200
+ @mock.expects(:get).once.with("#{Peakium.api_base}/v1/gateways?limit=1", nil, nil).returns(test_response([test_gateway]))
201
+ g = Peakium::Gateway.all(params)
202
+ end
203
+
204
+ should "making a POST request with parameters should have a body and no query string" do
205
+ params = { :name => 'Test gateway', :module => 'test' }
206
+ @mock.expects(:post).once.with do |url, get, post|
207
+ get.nil? && CGI.parse(post) == {'name' => ['Test gateway'], 'module' => ['test']}
208
+ end.returns(test_response(test_gateway))
209
+ g = Peakium::Gateway.create(params)
210
+ end
211
+
212
+ should "loading an object should issue a GET request" do
213
+ @mock.expects(:get).once.returns(test_response(test_gateway))
214
+ g = Peakium::Gateway.new("gw_test_gateway")
215
+ g.refresh
216
+ end
217
+
218
+ should "using array accessors should be the same as the method interface" do
219
+ @mock.expects(:get).once.returns(test_response(test_gateway))
220
+ g = Peakium::Gateway.new("gw_test_gateway")
221
+ g.refresh
222
+ assert_equal g.created, g[:created]
223
+ assert_equal g.created, g['created']
224
+ g['created'] = 12345
225
+ assert_equal g.created, 12345
226
+ end
227
+
228
+ should "accessing a property other than id or parent on an unfetched object should fetch it" do
229
+ @mock.expects(:get).once.returns(test_response(test_customer))
230
+ g = Peakium::Customer.new("test_cusotmer")
231
+ g.subscriptions
232
+ end
233
+
234
+ should "updating an object should issue a POST request with only the changed properties" do
235
+ @mock.expects(:post).with do |url, api_key, params|
236
+ url == "#{Peakium.api_base}/v1/gateways/gw_test_gateway" && api_key.nil? && CGI.parse(params) == {'name' => ['another name']}
237
+ end.once.returns(test_response(test_gateway))
238
+ g = Peakium::Gateway.construct_from(test_gateway)
239
+ g.name = "another name"
240
+ g.save
241
+ end
242
+
243
+ should "updating should merge in returned properties" do
244
+ @mock.expects(:post).once.returns(test_response(test_gateway))
245
+ g = Peakium::Gateway.new("gw_test_gateway")
246
+ g.name = "another name"
247
+ g.save
248
+ assert_equal false, g.livemode
249
+ end
250
+
251
+ should "deleting should send no props and result in an object that has no props other deleted" do
252
+ @mock.expects(:get).never
253
+ @mock.expects(:post).never
254
+ @mock.expects(:delete).with("#{Peakium.api_base}/v1/webhooks/#{CGI.escape("http://example.com/webhook_endpoint/")}", nil, nil).once.returns(test_response({ "url" => "http\:\/\/example.com\/webhook_endpoint\/", "deleted" => true }))
255
+
256
+ g = Peakium::Webhook.construct_from(test_webhook)
257
+ g.delete
258
+ assert_equal true, g.deleted
259
+
260
+ assert_raises NoMethodError do
261
+ g.livemode
262
+ end
263
+ end
264
+
265
+ should "loading an object with properties that have specific types should instantiate those classes" do
266
+ @mock.expects(:get).once.returns(test_response(test_gateway))
267
+ g = Peakium::Gateway.retrieve("gw_test_gateway")
268
+ assert g.module.kind_of?(Peakium::PeakiumObject) && g.module.object == 'gateway_module'
269
+ end
270
+
271
+ should "loading all of an APIResource should return an array of recursively instantiated objects" do
272
+ @mock.expects(:get).once.returns(test_response(test_gateway_array))
273
+ g = Peakium::Gateway.all.data
274
+ assert g.kind_of? Array
275
+ assert g[0].kind_of? Peakium::Gateway
276
+ assert g[0].module.kind_of?(Peakium::PeakiumObject) && g[0].module.object == 'gateway_module'
277
+ end
278
+
279
+ context "error checking" do
280
+
281
+ should "404s should raise an InvalidRequestError" do
282
+ response = test_response(test_missing_id_error, 404)
283
+ @mock.expects(:get).once.raises(RestClient::ExceptionWithResponse.new(response, 404))
284
+
285
+ begin
286
+ Peakium::Gateway.new("gw_test_gateway").refresh
287
+ assert false #shouldn't get here either
288
+ rescue Peakium::InvalidRequestError => e # we don't use assert_raises because we want to examine e
289
+ assert e.kind_of? Peakium::InvalidRequestError
290
+ assert_equal "id", e.param
291
+ assert_equal "Missing id", e.message
292
+ return
293
+ end
294
+
295
+ assert false #shouldn't get here
296
+ end
297
+
298
+ should "5XXs should raise an APIError" do
299
+ response = test_response(test_api_error, 500)
300
+ @mock.expects(:get).once.raises(RestClient::ExceptionWithResponse.new(response, 500))
301
+
302
+ begin
303
+ Peakium::Gateway.new("gw_test_gateway").refresh
304
+ assert false #shouldn't get here either
305
+ rescue Peakium::APIError => e # we don't use assert_raises because we want to examine e
306
+ assert e.kind_of? Peakium::APIError
307
+ return
308
+ end
309
+
310
+ assert false #shouldn't get here
311
+ end
312
+ end
313
+ end
314
+ end
315
+ end
@@ -0,0 +1,21 @@
1
+ # -*- coding: utf-8 -*-
2
+ require File.expand_path('../../test_helper', __FILE__)
3
+
4
+ module Peakium
5
+ class CustomerTest < Test::Unit::TestCase
6
+ should "customers should be listable" do
7
+ @mock.expects(:get).once.returns(test_response(test_customer_array))
8
+ c = Peakium::Customer.all.data
9
+ assert c.kind_of? Array
10
+ assert c[0].kind_of? Peakium::Customer
11
+ end
12
+
13
+ should "be able to cancel a customer's subscription" do
14
+ @mock.expects(:get).once.returns(test_response(test_customer))
15
+ c = Peakium::Customer.retrieve("test_customer")
16
+
17
+ @mock.expects(:delete).once.with("#{Peakium.api_base}/v1/customers/test_customer/subscriptions/test_subscription", nil, nil).returns(test_response(test_subscription()))
18
+ s = c.cancel_subscription('test_subscription');
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,30 @@
1
+ # -*- coding: utf-8 -*-
2
+ require File.expand_path('../../test_helper', __FILE__)
3
+
4
+ module Peakium
5
+ class EventTest < Test::Unit::TestCase
6
+ should "events should be listable" do
7
+ @mock.expects(:get).once.returns(test_response(test_event_array))
8
+ e = Peakium::Event.all.data
9
+ assert e.kind_of? Array
10
+ assert e[0].kind_of? Peakium::Event
11
+ end
12
+
13
+ should "be able to validate an event" do
14
+ @mock.expects(:get).once.returns(test_response(test_event))
15
+ e = Peakium::Event.retrieve("ev_test_event")
16
+
17
+ @mock.expects(:post).once.with("#{Peakium.api_base}/v1/events/ev_test_event/validate", nil, e.to_json).returns(test_response(test_event()))
18
+ e = e.validate(e.to_json);
19
+ end
20
+
21
+
22
+ should "be able to send/resend an event" do
23
+ @mock.expects(:get).once.returns(test_response(test_event))
24
+ e = Peakium::Event.retrieve("ev_test_event")
25
+
26
+ @mock.expects(:post).once.with("#{Peakium.api_base}/v1/events/ev_test_event/send", nil, 'force=true').returns(test_response(test_event()))
27
+ e = e.send({:force => true});
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,13 @@
1
+ # -*- coding: utf-8 -*-
2
+ require File.expand_path('../../test_helper', __FILE__)
3
+
4
+ module Peakium
5
+ class EventWebhookTest < Test::Unit::TestCase
6
+ should "event webhooks should be listable" do
7
+ @mock.expects(:get).once.returns(test_response(test_event_webhook_array))
8
+ ew = Peakium::EventWebhook.all.data
9
+ assert ew.kind_of? Array
10
+ assert ew[0].kind_of? Peakium::EventWebhook
11
+ end
12
+ end
13
+ end