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.
- checksums.yaml +7 -0
- data/.gitignore +4 -0
- data/.travis.yml +11 -0
- data/CONTRIBUTORS +1 -0
- data/Gemfile +2 -0
- data/History.txt +0 -0
- data/LICENSE +21 -0
- data/README.rdoc +43 -0
- data/Rakefile +16 -0
- data/VERSION +1 -0
- data/bin/peakium-console +7 -0
- data/gemfiles/default-with-activesupport.gemfile +3 -0
- data/gemfiles/json.gemfile +4 -0
- data/gemfiles/yajl.gemfile +4 -0
- data/lib/data/ca-certificates.crt +3828 -0
- data/lib/peakium/api_operations/create.rb +16 -0
- data/lib/peakium/api_operations/delete.rb +11 -0
- data/lib/peakium/api_operations/list.rb +21 -0
- data/lib/peakium/api_operations/update.rb +17 -0
- data/lib/peakium/api_resource.rb +33 -0
- data/lib/peakium/api_resources/customer.rb +25 -0
- data/lib/peakium/api_resources/event.rb +28 -0
- data/lib/peakium/api_resources/event_webhook.rb +5 -0
- data/lib/peakium/api_resources/gateway.rb +19 -0
- data/lib/peakium/api_resources/invoice.rb +26 -0
- data/lib/peakium/api_resources/payment_session.rb +5 -0
- data/lib/peakium/api_resources/submission_form.rb +12 -0
- data/lib/peakium/api_resources/subscription.rb +26 -0
- data/lib/peakium/api_resources/webhook.rb +21 -0
- data/lib/peakium/errors/api_connection_error.rb +4 -0
- data/lib/peakium/errors/api_error.rb +4 -0
- data/lib/peakium/errors/authentication_error.rb +4 -0
- data/lib/peakium/errors/invalid_request_error.rb +10 -0
- data/lib/peakium/errors/peakium_error.rb +20 -0
- data/lib/peakium/list_object.rb +31 -0
- data/lib/peakium/peakium_object.rb +167 -0
- data/lib/peakium/util.rb +115 -0
- data/lib/peakium/version.rb +3 -0
- data/lib/peakium.rb +265 -0
- data/peakium.gemspec +27 -0
- data/test/peakium/api_resource_test.rb +315 -0
- data/test/peakium/customer_test.rb +21 -0
- data/test/peakium/event_test.rb +30 -0
- data/test/peakium/event_webhook_test.rb +13 -0
- data/test/peakium/gateway_test.rb +35 -0
- data/test/peakium/invoice_test.rb +21 -0
- data/test/peakium/list_object_test.rb +16 -0
- data/test/peakium/payment_session_test.rb +13 -0
- data/test/peakium/submission_form_test.rb +12 -0
- data/test/peakium/subscription_test.rb +13 -0
- data/test/peakium/util_test.rb +29 -0
- data/test/peakium/webhook_test.rb +20 -0
- data/test/test_helper.rb +337 -0
- 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
|