paid 0.1.0 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +5 -1
- data/.travis.yml +16 -0
- data/History.txt +4 -0
- data/README.md +58 -0
- data/Rakefile +9 -29
- data/VERSION +1 -0
- data/bin/paid-console +7 -0
- data/gemfiles/default-with-activesupport.gemfile +10 -0
- data/gemfiles/json.gemfile +12 -0
- data/gemfiles/yajl.gemfile +12 -0
- data/lib/paid.rb +129 -177
- data/lib/paid/account.rb +14 -1
- data/lib/paid/api_class.rb +336 -0
- data/lib/paid/api_list.rb +47 -0
- data/lib/paid/api_resource.rb +8 -25
- data/lib/paid/api_singleton.rb +5 -0
- data/lib/paid/customer.rb +36 -21
- data/lib/paid/errors/api_error.rb +6 -0
- data/lib/paid/event.rb +22 -1
- data/lib/paid/invoice.rb +16 -21
- data/lib/paid/plan.rb +18 -2
- data/lib/paid/subscription.rb +17 -11
- data/lib/paid/transaction.rb +19 -12
- data/lib/paid/util.rb +53 -106
- data/lib/paid/version.rb +1 -1
- data/paid.gemspec +10 -11
- data/tasks/api_test.rb +187 -0
- data/test/mock_resource.rb +69 -0
- data/test/paid/account_test.rb +41 -4
- data/test/paid/api_class_test.rb +412 -0
- data/test/paid/api_list_test.rb +17 -0
- data/test/paid/api_resource_test.rb +13 -343
- data/test/paid/api_singleton_test.rb +12 -0
- data/test/paid/authentication_test.rb +50 -0
- data/test/paid/customer_test.rb +189 -29
- data/test/paid/event_test.rb +74 -0
- data/test/paid/invoice_test.rb +101 -20
- data/test/paid/plan_test.rb +84 -8
- data/test/paid/status_codes_test.rb +63 -0
- data/test/paid/subscription_test.rb +100 -20
- data/test/paid/transaction_test.rb +110 -37
- data/test/paid/util_test.rb +15 -24
- data/test/test_data.rb +144 -93
- data/test/test_helper.rb +6 -4
- metadata +32 -26
- data/Gemfile.lock +0 -54
- data/README.rdoc +0 -35
- data/lib/data/ca-certificates.crt +0 -0
- data/lib/paid/alias.rb +0 -16
- data/lib/paid/api_operations/create.rb +0 -17
- data/lib/paid/api_operations/delete.rb +0 -11
- data/lib/paid/api_operations/list.rb +0 -17
- data/lib/paid/api_operations/update.rb +0 -57
- data/lib/paid/certificate_blacklist.rb +0 -55
- data/lib/paid/list_object.rb +0 -37
- data/lib/paid/paid_object.rb +0 -187
- data/lib/paid/singleton_api_resource.rb +0 -20
- data/lib/tasks/paid_tasks.rake +0 -4
- data/test/paid/alias_test.rb +0 -22
- data/test/paid/certificate_blacklist_test.rb +0 -18
- data/test/paid/list_object_test.rb +0 -16
- data/test/paid/paid_object_test.rb +0 -27
- data/test/paid/properties_test.rb +0 -103
data/paid.gemspec
CHANGED
@@ -1,18 +1,16 @@
|
|
1
1
|
$:.unshift(File.join(File.dirname(__FILE__), 'lib'))
|
2
2
|
|
3
|
-
|
4
|
-
require "paid/version"
|
3
|
+
require 'paid/version'
|
5
4
|
|
6
|
-
|
7
|
-
|
8
|
-
s.
|
9
|
-
s.version = Paid::VERSION
|
10
|
-
s.authors = ['Ryan Jackson']
|
11
|
-
s.email = ['ryan@paidapi.com']
|
12
|
-
s.homepage = 'http://docs.paidapi.com'
|
13
|
-
s.summary = 'Ruby bindings for Paid API'
|
5
|
+
spec = Gem::Specification.new do |s|
|
6
|
+
s.name = 'paid'
|
7
|
+
s.summary = 'Ruby bindings for Paid API'
|
14
8
|
s.description = 'Paid is the programmatic way to manage payments. See https://paidapi.com for details.'
|
15
|
-
s.
|
9
|
+
s.homepage = 'http://docs.paidapi.com'
|
10
|
+
s.authors = ['Jon Calhoun', 'Ryan Jackson']
|
11
|
+
s.email = ['joncalhoun@gmail.com', 'ryan@paidapi.com']
|
12
|
+
s.version = Paid::VERSION
|
13
|
+
s.license = 'MIT'
|
16
14
|
|
17
15
|
s.add_dependency('rest-client', '~> 1.4')
|
18
16
|
s.add_dependency('mime-types', '>= 1.25', '< 3.0')
|
@@ -28,3 +26,4 @@ Gem::Specification.new do |s|
|
|
28
26
|
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
29
27
|
s.require_paths = ['lib']
|
30
28
|
end
|
29
|
+
|
data/tasks/api_test.rb
ADDED
@@ -0,0 +1,187 @@
|
|
1
|
+
require 'paid'
|
2
|
+
|
3
|
+
class APITest
|
4
|
+
def initialize(api_key)
|
5
|
+
Paid.api_key = api_key
|
6
|
+
end
|
7
|
+
|
8
|
+
def run
|
9
|
+
account = run_account_test
|
10
|
+
customer = run_customer_tests
|
11
|
+
plan = run_plan_tests
|
12
|
+
subscription = run_subscription_tests(customer, plan)
|
13
|
+
transaction = run_transaction_tests(customer)
|
14
|
+
invoice = run_invoice_tests(customer)
|
15
|
+
event = run_events_tests
|
16
|
+
run_advanced_tests(transaction, invoice, subscription)
|
17
|
+
end
|
18
|
+
|
19
|
+
def run_advanced_tests(transaction, invoice, subscription)
|
20
|
+
puts "Marking the transaction as paid..."
|
21
|
+
transaction.mark_as_paid
|
22
|
+
puts "Marked transaction=#{transaction.id} as paid."
|
23
|
+
|
24
|
+
puts "Issuing the invoice..."
|
25
|
+
invoice.issue
|
26
|
+
puts "Invoice=#{invoice.id} issued."
|
27
|
+
|
28
|
+
puts "Marking the invoice as paid..."
|
29
|
+
invoice.mark_as_paid(:via => :ach)
|
30
|
+
puts "Marked invoice=#{invoice.id} as paid."
|
31
|
+
|
32
|
+
puts "Cancelling subscription=#{subscription.id}..."
|
33
|
+
subscription.cancel
|
34
|
+
puts "Subscription cancelled."
|
35
|
+
end
|
36
|
+
|
37
|
+
def run_events_tests
|
38
|
+
puts "Looking up all events..."
|
39
|
+
events = Paid::Event.all
|
40
|
+
puts "Found #{events.length} events."
|
41
|
+
|
42
|
+
puts "Retrieving the first event..."
|
43
|
+
event = Paid::Event.retrieve(events.first.id)
|
44
|
+
puts "Retrieved the event with the id=#{event.id}"
|
45
|
+
|
46
|
+
event
|
47
|
+
end
|
48
|
+
|
49
|
+
def run_invoice_tests(customer)
|
50
|
+
puts "Creating an invoice with customer=#{customer.id}"
|
51
|
+
invoice = customer.generate_invoice
|
52
|
+
puts "Created: #{invoice.inspect}"
|
53
|
+
|
54
|
+
puts "Looking up all invoices..."
|
55
|
+
invoices = Paid::Invoice.all
|
56
|
+
puts "Found #{invoices.length} invoices."
|
57
|
+
|
58
|
+
puts "Retrieving the generated invoice..."
|
59
|
+
invoice = Paid::Invoice.retrieve(invoice.id)
|
60
|
+
puts "Retrieved the invoice with the id=#{invoice.id}"
|
61
|
+
|
62
|
+
puts "Retrieving the customer=#{customer.id}'s invoices..."
|
63
|
+
invoices = customer.invoices
|
64
|
+
puts "Retrieved: #{invoices.inspect}"
|
65
|
+
|
66
|
+
invoice
|
67
|
+
end
|
68
|
+
|
69
|
+
def run_transaction_tests(customer)
|
70
|
+
puts "Creating 2 transactions with customer=#{customer.id}"
|
71
|
+
transaction = Paid::Transaction.create({
|
72
|
+
:amount => 100,
|
73
|
+
:description => 'a description',
|
74
|
+
:customer => customer.id,
|
75
|
+
:paid => false
|
76
|
+
})
|
77
|
+
transaction_b = Paid::Transaction.create({
|
78
|
+
:amount => 1000,
|
79
|
+
:description => 'another description',
|
80
|
+
:customer => customer.id,
|
81
|
+
:paid => false
|
82
|
+
})
|
83
|
+
puts "Created: #{transaction.inspect} + 1 other"
|
84
|
+
|
85
|
+
puts "Looking up all transactions..."
|
86
|
+
transactions = Paid::Transaction.all
|
87
|
+
puts "Found #{transactions.length} transactions."
|
88
|
+
|
89
|
+
puts "Retrieving the created transaction..."
|
90
|
+
transaction = Paid::Transaction.retrieve(transaction.id)
|
91
|
+
puts "Retrieved the transaction with the id=#{transaction.id}"
|
92
|
+
|
93
|
+
puts "Updating the transaction's name..."
|
94
|
+
transaction.description = "an updated description..."
|
95
|
+
transaction.save
|
96
|
+
puts "Updated the transaction with id=#{transaction.id} with the new description #{transaction.description.inspect}"
|
97
|
+
|
98
|
+
puts "Looking up customer=#{customer.id}'s transactions..."
|
99
|
+
transactions = customer.transactions
|
100
|
+
puts "Retrieved: #{transactions.inspect}"
|
101
|
+
|
102
|
+
transaction
|
103
|
+
end
|
104
|
+
|
105
|
+
def run_subscription_tests(customer, plan)
|
106
|
+
puts "Creating a subscription for customer=#{customer.id} and plan=#{plan.id}..."
|
107
|
+
subscription = Paid::Subscription.create({
|
108
|
+
:starts_on => (Time.now + 1 * 60 * 60 * 24).strftime("%Y-%m-%d"),
|
109
|
+
:plan => plan.id,
|
110
|
+
:customer => customer.id
|
111
|
+
})
|
112
|
+
puts "Created: #{subscription.inspect}"
|
113
|
+
|
114
|
+
puts "Looking up all subscriptions..."
|
115
|
+
subscriptions = Paid::Subscription.all
|
116
|
+
puts "Found #{subscriptions.length} subscriptions."
|
117
|
+
|
118
|
+
puts "Retrieving the created subscription..."
|
119
|
+
subscription = Paid::Subscription.retrieve(subscription.id)
|
120
|
+
puts "Retrieved the subscription with the id=#{subscription.id}"
|
121
|
+
|
122
|
+
subscription
|
123
|
+
end
|
124
|
+
|
125
|
+
def run_plan_tests
|
126
|
+
puts "Creating a plan..."
|
127
|
+
plan = Paid::Plan.create({
|
128
|
+
:description => "Plan for testing stuff",
|
129
|
+
:name => "Test Plan #{Time.now.to_i}-#{rand(2000)}",
|
130
|
+
:interval => "month",
|
131
|
+
:interval_count => 1,
|
132
|
+
:amount => 5000
|
133
|
+
})
|
134
|
+
puts "Created: #{plan.inspect}"
|
135
|
+
|
136
|
+
puts "Looking up all plans..."
|
137
|
+
plans = Paid::Plan.all
|
138
|
+
puts "Found #{plans.length} plans."
|
139
|
+
|
140
|
+
puts "Retrieving the created plan..."
|
141
|
+
plan = Paid::Plan.retrieve(plan.id)
|
142
|
+
puts "Retrieved the plan with the id=#{plan.id}"
|
143
|
+
|
144
|
+
plan
|
145
|
+
end
|
146
|
+
|
147
|
+
def run_customer_tests
|
148
|
+
puts "Creating a customer..."
|
149
|
+
customer = Paid::Customer.create({
|
150
|
+
:name => "Paid",
|
151
|
+
:email => "hello@paidapi.com",
|
152
|
+
:description => "Obviously this is just a description.",
|
153
|
+
:phone => "4155069330",
|
154
|
+
:address_line1 => "2261 Market Street",
|
155
|
+
:address_line2 => "#567",
|
156
|
+
:address_city => "San Francisco",
|
157
|
+
:address_state => "CA",
|
158
|
+
:address_zip => "94114"
|
159
|
+
})
|
160
|
+
puts "Created: #{customer.inspect}"
|
161
|
+
|
162
|
+
puts "Looking up all customers..."
|
163
|
+
customers = Paid::Customer.all
|
164
|
+
puts "Found #{customers.length} customers"
|
165
|
+
|
166
|
+
puts "Retrieving the created customer..."
|
167
|
+
customer = Paid::Customer.retrieve(customer.id)
|
168
|
+
puts "Retrieved the customer with id=#{customer.id}"
|
169
|
+
|
170
|
+
# TODO(joncalhoun): Add by_external_id lookup test
|
171
|
+
|
172
|
+
puts "Updating the customer's name..."
|
173
|
+
customer.name = "Paid Inc"
|
174
|
+
customer.save
|
175
|
+
puts "Updated the customer with id=#{customer.id} with the new name #{customer.name.inspect}"
|
176
|
+
|
177
|
+
customer
|
178
|
+
end
|
179
|
+
|
180
|
+
def run_account_test
|
181
|
+
puts "Looking up the account..."
|
182
|
+
account = Paid::Account.retrieve
|
183
|
+
puts "Retrieved the account with id=#{account.id}"
|
184
|
+
account
|
185
|
+
end
|
186
|
+
|
187
|
+
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
# Setup a fake resource for testing the APIResource
|
2
|
+
|
3
|
+
class NestedResource < Paid::APIResource
|
4
|
+
attribute :price
|
5
|
+
|
6
|
+
def self.path
|
7
|
+
"/nested_resources"
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
class MockResource < Paid::APIResource
|
12
|
+
attribute :name
|
13
|
+
attribute :tarray
|
14
|
+
attribute :thash
|
15
|
+
attribute :nested, NestedResource
|
16
|
+
|
17
|
+
api_class_method :retrieve, :get, ":path/:id", :arguments => [:id]
|
18
|
+
api_class_method :all, :get, :constructor => Paid::APIList.constructor(MockResource)
|
19
|
+
api_class_method :create, :post
|
20
|
+
api_class_method :many_args_get, :get, ":path/:b/many", :arguments => [:a, :b, :c]
|
21
|
+
api_class_method :many_args_post, :post, ":path/:b/many", :arguments => [:a, :b, :c]
|
22
|
+
api_class_method :crazy_path, :get, ":crazy"
|
23
|
+
|
24
|
+
api_class_method :with_con_self, :get, :constructor => :self
|
25
|
+
api_class_method :with_con_class, :get, :constructor => MockResource
|
26
|
+
api_class_method :with_con_lambda, :get, :constructor => lambda{ |json| "lamdba result" }
|
27
|
+
api_class_method :with_con_default, :get
|
28
|
+
|
29
|
+
def self.default_lambda
|
30
|
+
lambda do |this|
|
31
|
+
self.default_values
|
32
|
+
end
|
33
|
+
end
|
34
|
+
api_class_method :with_lambda, :post, :default_params => self.default_lambda
|
35
|
+
api_class_method :with_symbol, :post, :default_params => :default_values
|
36
|
+
api_class_method :with_symbol_and_args, :post, :default_params => :default_values, :arguments => [:name]
|
37
|
+
|
38
|
+
api_instance_method :refresh, :get, :constructor => :self
|
39
|
+
api_instance_method :save, :put, :default_params => changed_lambda, :constructor => :self
|
40
|
+
api_instance_method :delete, :delete
|
41
|
+
api_instance_method :custom_path, :get, ":path", :arguments => [:path]
|
42
|
+
api_instance_method :name_path, :get, ":name"
|
43
|
+
api_instance_method :crazy_path, :get, ":crazy"
|
44
|
+
|
45
|
+
api_instance_method :with_con_self, :get, :constructor => :self
|
46
|
+
api_instance_method :with_con_class, :get, :constructor => MockResource
|
47
|
+
api_instance_method :with_con_lambda, :get, :constructor => lambda{ |json| "lamdba result" }
|
48
|
+
api_instance_method :with_con_default, :get
|
49
|
+
|
50
|
+
api_instance_method :with_lambda, :put, :default_params => changed_lambda
|
51
|
+
api_instance_method :with_symbol, :put, :default_params => :changed_attributes
|
52
|
+
api_instance_method :with_symbol_and_args, :put, :default_params => :changed_attributes, :arguments => [:name]
|
53
|
+
|
54
|
+
def self.path
|
55
|
+
"/mocks"
|
56
|
+
end
|
57
|
+
|
58
|
+
def self.crazy
|
59
|
+
"/crazy_path"
|
60
|
+
end
|
61
|
+
|
62
|
+
def self.default_values
|
63
|
+
{
|
64
|
+
:name => "default name",
|
65
|
+
:tarray => [1,2,3]
|
66
|
+
}
|
67
|
+
end
|
68
|
+
|
69
|
+
end
|
data/test/paid/account_test.rb
CHANGED
@@ -2,11 +2,48 @@ require File.expand_path('../../test_helper', __FILE__)
|
|
2
2
|
|
3
3
|
module Paid
|
4
4
|
class AccountTest < Test::Unit::TestCase
|
5
|
-
|
6
|
-
|
7
|
-
|
5
|
+
setup do
|
6
|
+
@account_url = "#{Paid.api_base}/v0/account"
|
7
|
+
end
|
8
|
+
|
9
|
+
should 'be retrievable' do
|
10
|
+
@mock.expects(:get).once.with(@account_url, anything, anything).returns(test_response(test_account))
|
8
11
|
a = Paid::Account.retrieve
|
9
|
-
|
12
|
+
assert(a.is_a?(Paid::Account))
|
13
|
+
assert_equal(test_account[:id], a.id)
|
14
|
+
end
|
15
|
+
|
16
|
+
context 'Retrieved Paid::Account instance' do
|
17
|
+
setup do
|
18
|
+
@mock.expects(:get).once.returns(test_response(test_account))
|
19
|
+
@account = Paid::Account.retrieve
|
20
|
+
end
|
21
|
+
|
22
|
+
should 'have the id attribute' do
|
23
|
+
assert_equal(test_account[:id], @account.id)
|
24
|
+
end
|
25
|
+
|
26
|
+
should 'have the object attribute' do
|
27
|
+
assert_equal(test_account[:object], @account.object)
|
28
|
+
end
|
29
|
+
|
30
|
+
should 'have the business_name attribute' do
|
31
|
+
assert_equal(test_account[:business_name], @account.business_name)
|
32
|
+
end
|
33
|
+
|
34
|
+
should 'have the business_url attribute' do
|
35
|
+
assert_equal(test_account[:business_url], @account.business_url)
|
36
|
+
end
|
37
|
+
|
38
|
+
should 'have the business_logo attribute' do
|
39
|
+
assert_equal(test_account[:business_logo], @account.business_logo)
|
40
|
+
end
|
10
41
|
end
|
42
|
+
|
43
|
+
should 'be registered' do
|
44
|
+
assert(APIClass.subclasses.include?(Paid::Account))
|
45
|
+
assert_equal(Paid::Account, APIClass.subclass_fetch("account"))
|
46
|
+
end
|
47
|
+
|
11
48
|
end
|
12
49
|
end
|
@@ -0,0 +1,412 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
require File.expand_path('../../test_helper', __FILE__)
|
3
|
+
|
4
|
+
module Paid
|
5
|
+
class ApiClassTest < Test::Unit::TestCase
|
6
|
+
|
7
|
+
context 'Non-network actions' do
|
8
|
+
setup do
|
9
|
+
@mock.expects(:get).never
|
10
|
+
@mock.expects(:post).never
|
11
|
+
@mock.expects(:put).never
|
12
|
+
@mock.expects(:delete).never
|
13
|
+
end
|
14
|
+
|
15
|
+
should 'not fetch over the network when creating a new APIClass' do
|
16
|
+
MockResource.new('fake_id')
|
17
|
+
end
|
18
|
+
|
19
|
+
should 'not fetch over the network when creating a new APIClass from a hash' do
|
20
|
+
MockResource.construct(test_mock_resource)
|
21
|
+
end
|
22
|
+
|
23
|
+
should 'not fetch over the network when setting an attribute' do
|
24
|
+
c = MockResource.new('fake_id')
|
25
|
+
c.name = 'Another Name'
|
26
|
+
end
|
27
|
+
|
28
|
+
should 'not fetch over the network when accessing an attribute' do
|
29
|
+
c = MockResource.new('fake_id')
|
30
|
+
c.id
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
# These GET, POST, etc should really be in a dif test, but this is easier.
|
35
|
+
context 'Making a GET request' do
|
36
|
+
should 'urlencode values in params and have no payload' do
|
37
|
+
response = test_response(test_mock_resource_list)
|
38
|
+
|
39
|
+
# The test is to basically make sure this expectation passes.
|
40
|
+
@mock.expects(:get).with do |url, headers, params|
|
41
|
+
(url == "#{Paid.api_base}#{MockResource.path}?page=1&filter=test%20filter" ||
|
42
|
+
url == "#{Paid.api_base}#{MockResource.path}?filter=test%20filter&page=1") &&
|
43
|
+
params == nil
|
44
|
+
end.returns(response)
|
45
|
+
|
46
|
+
list = MockResource.all({
|
47
|
+
:page => 1,
|
48
|
+
:filter => 'test filter',
|
49
|
+
})
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
context 'Making a DELETE request' do
|
54
|
+
should 'urlencode values in params and have no payload' do
|
55
|
+
@mock.expects(:get).once.returns(test_response(test_mock_resource))
|
56
|
+
mock_resource = MockResource.retrieve("fake_id")
|
57
|
+
|
58
|
+
@mock.expects(:delete).once.with do |url, headers, payload|
|
59
|
+
url == "#{Paid.api_base}#{mock_resource.path}?reason=delinquent%20payments" && payload.nil?
|
60
|
+
end.returns(test_response({}))
|
61
|
+
mock_resource.delete(:reason => "delinquent payments")
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
context 'Making a PUT request' do
|
66
|
+
should 'have a payload with no query string' do
|
67
|
+
@mock.expects(:get).once.returns(test_response(test_mock_resource))
|
68
|
+
mock_resource = MockResource.retrieve("fake_id")
|
69
|
+
mock_resource.name = "new name"
|
70
|
+
|
71
|
+
@mock.expects(:put).once.with do |url, header, payload|
|
72
|
+
payload == { :name => "new name" }
|
73
|
+
end.returns(test_response(test_mock_resource))
|
74
|
+
mock_resource.save
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
context 'Making a POST request' do
|
79
|
+
should 'have a payload with no query string' do
|
80
|
+
params = { :name => "some name" }
|
81
|
+
@mock.expects(:post).once.with("#{Paid.api_base}#{MockResource.path}", anything, params).returns(test_response(test_mock_resource))
|
82
|
+
|
83
|
+
MockResource.create(params)
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
context 'APIClass :default_params' do
|
88
|
+
context 'api_instance_method' do
|
89
|
+
setup do
|
90
|
+
@response = test_response(test_mock_resource_list)
|
91
|
+
@mr = MockResource.new(test_mock_resource)
|
92
|
+
end
|
93
|
+
|
94
|
+
should 'call any provided lambdas and set the result as params' do
|
95
|
+
@mock.expects(:put).once.with(anything, anything, { :name => "new name" }).returns(@response)
|
96
|
+
|
97
|
+
@mr.name = "new name"
|
98
|
+
@mr.with_lambda
|
99
|
+
end
|
100
|
+
|
101
|
+
should 'call any method defined by a symbol and set the results as params' do
|
102
|
+
@mock.expects(:put).once.with(anything, anything, { :name => "new name" }).returns(@response)
|
103
|
+
|
104
|
+
@mr.name = "new name"
|
105
|
+
@mr.with_symbol
|
106
|
+
end
|
107
|
+
|
108
|
+
context 'order priority' do
|
109
|
+
# Intended order of priority:
|
110
|
+
# 1. Params. eg in mock_resource.save(params, opts), params should take
|
111
|
+
# priority with duplicate keys.
|
112
|
+
# 2. Arguments. These should take priority over default values from :params
|
113
|
+
# method.
|
114
|
+
# 3. Results from method defined by :default_params. This can be a symbol that is
|
115
|
+
# the name of a method to call, or a lambda (though a hash is preferred).
|
116
|
+
should 'prioritize params argument over args and default_params method' do
|
117
|
+
params = {
|
118
|
+
:name => "not arg name",
|
119
|
+
:tarray => ["not method tarray"],
|
120
|
+
:thash => { :val => "custom hash" }
|
121
|
+
}
|
122
|
+
@mock.expects(:put).once.with(anything, anything, params).returns(@response)
|
123
|
+
|
124
|
+
@mr.tarray = ["method array"]
|
125
|
+
@mr.with_symbol_and_args("arg name", params)
|
126
|
+
end
|
127
|
+
|
128
|
+
should 'prioritize arguments over :default_params' do
|
129
|
+
@mock.expects(:put).once.with(anything, anything, { :name => "arg name" }).returns(@response)
|
130
|
+
|
131
|
+
@mr.name = "changed name"
|
132
|
+
@mr.with_symbol_and_args("arg name")
|
133
|
+
end
|
134
|
+
|
135
|
+
should 'use :default_params method as even when args and params are present' do
|
136
|
+
@mock.expects(:put).once.with(anything, anything, {
|
137
|
+
:thash => { :val => "params hash" },
|
138
|
+
:name => "arg name",
|
139
|
+
:tarray => ["change array"],
|
140
|
+
}).returns(@response)
|
141
|
+
|
142
|
+
@mr.tarray = ["change array"]
|
143
|
+
@mr.with_symbol_and_args("arg name", { :thash => { :val => "params hash" } })
|
144
|
+
end
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
148
|
+
context 'api_class_method' do
|
149
|
+
setup do
|
150
|
+
@response = test_response(test_mock_resource_list)
|
151
|
+
end
|
152
|
+
|
153
|
+
should 'call any provided lambdas and set the result as params' do
|
154
|
+
@mock.expects(:post).once.with(anything, anything, MockResource.default_values).returns(@response)
|
155
|
+
MockResource.with_lambda
|
156
|
+
end
|
157
|
+
|
158
|
+
should 'call any method defined by a symbol and set the results as params' do
|
159
|
+
@mock.expects(:post).once.with(anything, anything, MockResource.default_values).returns(@response)
|
160
|
+
MockResource.with_symbol
|
161
|
+
end
|
162
|
+
|
163
|
+
context 'order priority' do
|
164
|
+
# Intended order of priority:
|
165
|
+
# 1. Params. eg in mock_resource.save(params, opts), params should take
|
166
|
+
# priority with duplicate keys.
|
167
|
+
# 2. Arguments. These should take priority over default values from :params
|
168
|
+
# method.
|
169
|
+
# 3. Results from method defined by :default_params. This can be a symbol that is
|
170
|
+
# the name of a method to call, or a lambda (though a hash is preferred).
|
171
|
+
should 'prioritize params argument over args and default_params method' do
|
172
|
+
params = {
|
173
|
+
:name => "not arg name",
|
174
|
+
:tarray => ["not method tarray"],
|
175
|
+
:thash => { :val => "custom hash" }
|
176
|
+
}
|
177
|
+
@mock.expects(:post).once.with(anything, anything, params).returns(@response)
|
178
|
+
MockResource.with_symbol_and_args("name arg", params)
|
179
|
+
end
|
180
|
+
|
181
|
+
should 'prioritize arguments over :default_params' do
|
182
|
+
params = Util.sorta_deep_clone(MockResource.default_values)
|
183
|
+
params[:name] = "name arg"
|
184
|
+
@mock.expects(:post).once.with(anything, anything, params).returns(@response)
|
185
|
+
MockResource.with_symbol_and_args("name arg", params)
|
186
|
+
end
|
187
|
+
|
188
|
+
should 'use :default_params method as even when args and params are present' do
|
189
|
+
params = {
|
190
|
+
:name => "name arg",
|
191
|
+
:tarray => MockResource.default_values[:tarray].dup,
|
192
|
+
:thash => { :val => "custom hash" }
|
193
|
+
}
|
194
|
+
@mock.expects(:post).once.with(anything, anything, params).returns(@response)
|
195
|
+
MockResource.with_symbol_and_args("name arg", { :thash => { :val => "custom hash" }})
|
196
|
+
end
|
197
|
+
end
|
198
|
+
end
|
199
|
+
end
|
200
|
+
|
201
|
+
|
202
|
+
context 'APIClass#attribute' do
|
203
|
+
should 'create a getter method' do
|
204
|
+
assert(MockResource.method_defined?(:name))
|
205
|
+
end
|
206
|
+
|
207
|
+
should 'create a setter method' do
|
208
|
+
assert(MockResource.method_defined?(:name=))
|
209
|
+
end
|
210
|
+
|
211
|
+
should 'have no changed attributes after init' do
|
212
|
+
mr = MockResource.new(test_mock_resource)
|
213
|
+
assert(mr.changed_attributes.empty?)
|
214
|
+
end
|
215
|
+
|
216
|
+
should 'keep track of changed attributes' do
|
217
|
+
mr = MockResource.new(test_mock_resource)
|
218
|
+
assert(mr.changed_attributes.empty?)
|
219
|
+
mr.name = "new name"
|
220
|
+
assert_equal({:name => "new name"}, mr.changed_attributes)
|
221
|
+
end
|
222
|
+
|
223
|
+
should 'keep track of changed arrays' do
|
224
|
+
mr = MockResource.new(test_mock_resource)
|
225
|
+
assert(mr.changed_attributes.empty?)
|
226
|
+
mr.tarray << "new"
|
227
|
+
assert_equal({:tarray => test_mock_resource[:tarray] + ["new"]}, mr.changed_attributes)
|
228
|
+
end
|
229
|
+
|
230
|
+
should 'keep track of changed hashes' do
|
231
|
+
mr = MockResource.new(test_mock_resource)
|
232
|
+
assert(mr.changed_attributes.empty?)
|
233
|
+
mr.thash[:some_key] = "new value"
|
234
|
+
assert_equal({:thash => { :some_key => "new value" }}, mr.changed_attributes)
|
235
|
+
end
|
236
|
+
|
237
|
+
context 'constructors' do
|
238
|
+
should 'instantiate on #new' do
|
239
|
+
mr = MockResource.new(test_mock_resource)
|
240
|
+
assert(mr.nested.is_a?(NestedResource))
|
241
|
+
end
|
242
|
+
|
243
|
+
should 'instantiate on #construct' do
|
244
|
+
mr = MockResource.construct(test_mock_resource)
|
245
|
+
assert(mr.nested.is_a?(NestedResource))
|
246
|
+
end
|
247
|
+
|
248
|
+
should 'instantiate on #refresh_from' do
|
249
|
+
mr = MockResource.new('fake_id')
|
250
|
+
assert(mr.nested.nil?)
|
251
|
+
|
252
|
+
mr.refresh_from(test_mock_resource)
|
253
|
+
assert(mr.nested.is_a?(NestedResource))
|
254
|
+
end
|
255
|
+
end
|
256
|
+
end
|
257
|
+
|
258
|
+
context 'APIClass :constructor' do
|
259
|
+
context 'for api_class_method' do
|
260
|
+
setup do
|
261
|
+
@mock.expects(:get).once.returns(test_response(test_mock_resource))
|
262
|
+
end
|
263
|
+
|
264
|
+
should 'create a new MockResource with :constructor => :self' do
|
265
|
+
mr = MockResource.with_con_self
|
266
|
+
assert(mr.is_a?(MockResource))
|
267
|
+
end
|
268
|
+
|
269
|
+
should 'create a new MockResource with :constructor => MockResource' do
|
270
|
+
mr = MockResource.with_con_class
|
271
|
+
assert(mr.is_a?(MockResource))
|
272
|
+
end
|
273
|
+
|
274
|
+
should 'use the lambda with :constructor => lambda{...}' do
|
275
|
+
mr = MockResource.with_con_lambda
|
276
|
+
assert_equal("lamdba result", mr)
|
277
|
+
end
|
278
|
+
|
279
|
+
should 'create a new MockResource with no constructor defined' do
|
280
|
+
mr = MockResource.with_con_default
|
281
|
+
assert(mr.is_a?(MockResource))
|
282
|
+
end
|
283
|
+
end
|
284
|
+
|
285
|
+
context 'for api_instance_method' do
|
286
|
+
setup do
|
287
|
+
@mock.expects(:get).once.returns(test_response(test_mock_resource))
|
288
|
+
@mr = MockResource.new('fake_id')
|
289
|
+
end
|
290
|
+
|
291
|
+
should 'update this instance with :constructor => :self' do
|
292
|
+
@mr.with_con_self
|
293
|
+
assert(@mr.is_a?(MockResource))
|
294
|
+
assert_equal(test_mock_resource[:id], @mr.id)
|
295
|
+
end
|
296
|
+
|
297
|
+
should 'create a new instance with :constructor => MockResource' do
|
298
|
+
res = @mr.with_con_class
|
299
|
+
assert(res.is_a?(MockResource))
|
300
|
+
assert_not_equal(@mr.id, res.id)
|
301
|
+
end
|
302
|
+
|
303
|
+
should 'use the lambda with :constructor => lambda{...}' do
|
304
|
+
res = @mr.with_con_lambda
|
305
|
+
assert_equal("lamdba result", res)
|
306
|
+
end
|
307
|
+
|
308
|
+
should 'update this instance with no constructor defined' do
|
309
|
+
@mr.with_con_default
|
310
|
+
assert(@mr.is_a?(MockResource))
|
311
|
+
assert_equal(test_mock_resource[:id], @mr.id)
|
312
|
+
end
|
313
|
+
end
|
314
|
+
end
|
315
|
+
|
316
|
+
context 'APIClass api_*_method arguments' do
|
317
|
+
should 'throw an ArgumentError if too few arguments are provided' do
|
318
|
+
assert_raises(ArgumentError) { MockResource.retrieve }
|
319
|
+
end
|
320
|
+
|
321
|
+
should 'throw an ArgumentError with the name of missing arguments' do
|
322
|
+
begin
|
323
|
+
MockResource.retrieve
|
324
|
+
assert(false, "ArgumentError was expected.")
|
325
|
+
rescue ArgumentError => e
|
326
|
+
assert(e.message =~ /id/)
|
327
|
+
end
|
328
|
+
end
|
329
|
+
|
330
|
+
should 'throw an ArgumentError if too many arguments are provided' do
|
331
|
+
assert_raises(ArgumentError) { MockResource.retrieve(1, 2, {}, {}) }
|
332
|
+
end
|
333
|
+
|
334
|
+
should 'throw an ArgumentError if the param argument is invalid' do
|
335
|
+
assert_raises(ArgumentError) { MockResource.retrieve(1, 2) }
|
336
|
+
end
|
337
|
+
|
338
|
+
should 'throw an ArgumentError if the opts argument is invalid' do
|
339
|
+
assert_raises(ArgumentError) { MockResource.retrieve(1, {}, "abc") }
|
340
|
+
end
|
341
|
+
|
342
|
+
should 'not throw an ArgumentError if the opts or params are nil' do
|
343
|
+
@mock.expects(:get).times(2).returns(test_response(test_mock_resource))
|
344
|
+
MockResource.retrieve(1, nil, {})
|
345
|
+
MockResource.retrieve(1, {}, nil)
|
346
|
+
end
|
347
|
+
|
348
|
+
should 'urlencode unused arguments via GET' do
|
349
|
+
response = test_response(test_mock_resource)
|
350
|
+
@mock.expects(:get).with do |url, headers, params|
|
351
|
+
(url == "#{Paid.api_base}#{MockResource.path}/bval/many?a=aval&c=cval" ||
|
352
|
+
url == "#{Paid.api_base}#{MockResource.path}/bval/many?c=cval&a=aval") &&
|
353
|
+
params.nil?
|
354
|
+
end.returns(response)
|
355
|
+
|
356
|
+
MockResource.many_args_get("aval", "bval", "cval")
|
357
|
+
end
|
358
|
+
|
359
|
+
should 'assign unused arguments to the params payload via POST' do
|
360
|
+
response = test_response(test_mock_resource)
|
361
|
+
@mock.expects(:post).with("#{Paid.api_base}#{MockResource.path}/bval/many", anything, { :a => "aval", :c => "cval" }).returns(response)
|
362
|
+
|
363
|
+
MockResource.many_args_post("aval", "bval", "cval")
|
364
|
+
end
|
365
|
+
end
|
366
|
+
|
367
|
+
context 'APIClass api_instance_method paths' do
|
368
|
+
should 'use the provided argument if it is present' do
|
369
|
+
response = test_response(test_mock_resource)
|
370
|
+
@mock.expects(:get).with("#{Paid.api_base}/custom_path", anything, anything).returns(response)
|
371
|
+
|
372
|
+
mr = MockResource.new(test_mock_resource)
|
373
|
+
mr.custom_path("/custom_path")
|
374
|
+
end
|
375
|
+
|
376
|
+
should 'use the instance method for path values' do
|
377
|
+
response = test_response(test_mock_resource)
|
378
|
+
name = "/mock_resource_name"
|
379
|
+
@mock.expects(:get).with("#{Paid.api_base}#{name}", anything, anything).returns(response)
|
380
|
+
|
381
|
+
mr = MockResource.new(test_mock_resource)
|
382
|
+
mr.name = name
|
383
|
+
mr.name_path
|
384
|
+
end
|
385
|
+
|
386
|
+
should 'use the class method for path values' do
|
387
|
+
response = test_response(test_mock_resource)
|
388
|
+
@mock.expects(:get).with("#{Paid.api_base}#{MockResource.crazy}", anything, anything).returns(response)
|
389
|
+
|
390
|
+
mr = MockResource.new(test_mock_resource)
|
391
|
+
mr.crazy_path
|
392
|
+
end
|
393
|
+
end
|
394
|
+
|
395
|
+
context 'APIClass api_class_method paths' do
|
396
|
+
should 'use the provided argument if it is present' do
|
397
|
+
response = test_response(test_mock_resource)
|
398
|
+
@mock.expects(:get).with("#{Paid.api_base}#{MockResource.path}/fake_id", anything, anything).returns(response)
|
399
|
+
|
400
|
+
mr = MockResource.retrieve('fake_id')
|
401
|
+
end
|
402
|
+
|
403
|
+
should 'use the class method for path values' do
|
404
|
+
response = test_response(test_mock_resource)
|
405
|
+
@mock.expects(:get).with("#{Paid.api_base}#{MockResource.crazy}", anything, anything).returns(response)
|
406
|
+
|
407
|
+
MockResource.crazy_path
|
408
|
+
end
|
409
|
+
end
|
410
|
+
|
411
|
+
end
|
412
|
+
end
|