freshbooks.rb 3.0.13
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.
- data/History.txt +8 -0
- data/LICENSE +10 -0
- data/Manifest.txt +45 -0
- data/README +44 -0
- data/Rakefile +27 -0
- data/lib/freshbooks.rb +94 -0
- data/lib/freshbooks/base.rb +169 -0
- data/lib/freshbooks/category.rb +11 -0
- data/lib/freshbooks/client.rb +22 -0
- data/lib/freshbooks/connection.rb +153 -0
- data/lib/freshbooks/estimate.rb +15 -0
- data/lib/freshbooks/expense.rb +12 -0
- data/lib/freshbooks/invoice.rb +18 -0
- data/lib/freshbooks/item.rb +11 -0
- data/lib/freshbooks/line.rb +10 -0
- data/lib/freshbooks/links.rb +7 -0
- data/lib/freshbooks/list_proxy.rb +80 -0
- data/lib/freshbooks/payment.rb +13 -0
- data/lib/freshbooks/project.rb +12 -0
- data/lib/freshbooks/recurring.rb +15 -0
- data/lib/freshbooks/response.rb +25 -0
- data/lib/freshbooks/schema/definition.rb +20 -0
- data/lib/freshbooks/schema/mixin.rb +40 -0
- data/lib/freshbooks/staff.rb +13 -0
- data/lib/freshbooks/task.rb +12 -0
- data/lib/freshbooks/time_entry.rb +12 -0
- data/lib/freshbooks/xml_serializer.rb +17 -0
- data/lib/freshbooks/xml_serializer/serializers.rb +109 -0
- data/script/console +10 -0
- data/script/destroy +14 -0
- data/script/generate +14 -0
- data/test/fixtures/freshbooks_credentials.sample.yml +3 -0
- data/test/fixtures/invoice_create_response.xml +4 -0
- data/test/fixtures/invoice_get_response.xml +54 -0
- data/test/fixtures/invoice_list_response.xml +109 -0
- data/test/fixtures/success_response.xml +2 -0
- data/test/mock_connection.rb +13 -0
- data/test/schema/test_definition.rb +36 -0
- data/test/schema/test_mixin.rb +39 -0
- data/test/test_base.rb +97 -0
- data/test/test_connection.rb +145 -0
- data/test/test_helper.rb +48 -0
- data/test/test_invoice.rb +125 -0
- data/test/test_list_proxy.rb +60 -0
- data/test/test_page.rb +50 -0
- metadata +148 -0
data/script/console
ADDED
@@ -0,0 +1,10 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# File: script/console
|
3
|
+
irb = RUBY_PLATFORM =~ /(:?mswin|mingw)/ ? 'irb.bat' : 'irb'
|
4
|
+
|
5
|
+
libs = " -r irb/completion"
|
6
|
+
# Perhaps use a console_lib to store any extra methods I may want available in the cosole
|
7
|
+
# libs << " -r #{File.dirname(__FILE__) + '/../lib/console_lib/console_logger.rb'}"
|
8
|
+
libs << " -r #{File.dirname(__FILE__) + '/../lib/freshbooks.rb'}"
|
9
|
+
puts "Loading freshbooks.rb gem"
|
10
|
+
exec "#{irb} #{libs} --simple-prompt"
|
data/script/destroy
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
APP_ROOT = File.expand_path(File.join(File.dirname(__FILE__), '..'))
|
3
|
+
|
4
|
+
begin
|
5
|
+
require 'rubigen'
|
6
|
+
rescue LoadError
|
7
|
+
require 'rubygems'
|
8
|
+
require 'rubigen'
|
9
|
+
end
|
10
|
+
require 'rubigen/scripts/destroy'
|
11
|
+
|
12
|
+
ARGV.shift if ['--help', '-h'].include?(ARGV[0])
|
13
|
+
RubiGen::Base.use_component_sources! [:rubygems, :newgem, :newgem_theme, :test_unit]
|
14
|
+
RubiGen::Scripts::Destroy.new.run(ARGV)
|
data/script/generate
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
APP_ROOT = File.expand_path(File.join(File.dirname(__FILE__), '..'))
|
3
|
+
|
4
|
+
begin
|
5
|
+
require 'rubigen'
|
6
|
+
rescue LoadError
|
7
|
+
require 'rubygems'
|
8
|
+
require 'rubigen'
|
9
|
+
end
|
10
|
+
require 'rubigen/scripts/generate'
|
11
|
+
|
12
|
+
ARGV.shift if ['--help', '-h'].include?(ARGV[0])
|
13
|
+
RubiGen::Base.use_component_sources! [:rubygems, :newgem, :newgem_theme, :test_unit]
|
14
|
+
RubiGen::Scripts::Generate.new.run(ARGV)
|
@@ -0,0 +1,54 @@
|
|
1
|
+
<?xml version="1.0"?>
|
2
|
+
<response status="ok">
|
3
|
+
<invoice>
|
4
|
+
<invoice_id>1</invoice_id>
|
5
|
+
<client_id>1</client_id>
|
6
|
+
<number>number1</number>
|
7
|
+
<recurring_id>1</recurring_id>
|
8
|
+
<organization>Organization 1</organization>
|
9
|
+
<status>draft</status>
|
10
|
+
<amount>100.00</amount>
|
11
|
+
<amount_outstanding>50.00</amount_outstanding>
|
12
|
+
<date>2009-02-01</date>
|
13
|
+
|
14
|
+
<po_number>1</po_number>
|
15
|
+
<discount>1</discount>
|
16
|
+
<notes>notes1</notes>
|
17
|
+
<terms>terms1</terms>
|
18
|
+
|
19
|
+
<first_name>first_name1</first_name>
|
20
|
+
<last_name>last_name1</last_name>
|
21
|
+
<p_street1>p_street11</p_street1>
|
22
|
+
<p_street2>p_street21</p_street2>
|
23
|
+
<p_city>p_city1</p_city>
|
24
|
+
<p_state>p_state1</p_state>
|
25
|
+
<p_country>p_country1</p_country>
|
26
|
+
<p_code>p_code1</p_code>
|
27
|
+
|
28
|
+
<return_uri>return_uri1</return_uri>
|
29
|
+
<updated>2009-08-1 01:00:00</updated>
|
30
|
+
|
31
|
+
<links>
|
32
|
+
<client_view>client_view1</client_view>
|
33
|
+
<view>view1</view>
|
34
|
+
<edit>edit1</edit>
|
35
|
+
</links>
|
36
|
+
|
37
|
+
<lines>
|
38
|
+
<line>
|
39
|
+
<amount>1</amount>
|
40
|
+
<name>name1</name>
|
41
|
+
<description>description1</description>
|
42
|
+
<unit_cost>1</unit_cost>
|
43
|
+
<quantity>1</quantity>
|
44
|
+
<tax1_name>tax1_name1</tax1_name>
|
45
|
+
<tax2_name>tax2_name1</tax2_name>
|
46
|
+
<tax1_percent>1</tax1_percent>
|
47
|
+
<tax2_percent>1</tax2_percent>
|
48
|
+
</line>
|
49
|
+
</lines>
|
50
|
+
|
51
|
+
<url deprecated="true">https://sample.freshbooks.com/inv/12345-1-6d30b</url>
|
52
|
+
<auth_url deprecated="true">https://sample.freshbooks.com/inv/12345-1-6d30b-z</auth_url>
|
53
|
+
</invoice>
|
54
|
+
</response>
|
@@ -0,0 +1,109 @@
|
|
1
|
+
<?xml version="1.0" encoding="utf-8"?>
|
2
|
+
<response status="ok">
|
3
|
+
<invoices page="1" per_page="2" pages="2" total="3">
|
4
|
+
<invoice>
|
5
|
+
<invoice_id>1</invoice_id>
|
6
|
+
<number>number1</number>
|
7
|
+
<client_id>1</client_id>
|
8
|
+
<recurring_id>1</recurring_id>
|
9
|
+
<organization>Organization 1</organization>
|
10
|
+
<status>draft</status>
|
11
|
+
<amount>100.00</amount>
|
12
|
+
<amount_outstanding>50.00</amount_outstanding>
|
13
|
+
<date>2009-02-01</date>
|
14
|
+
|
15
|
+
<po_number>1</po_number>
|
16
|
+
<discount>1</discount>
|
17
|
+
<notes>notes1</notes>
|
18
|
+
<terms>terms1</terms>
|
19
|
+
|
20
|
+
<first_name>first_name1</first_name>
|
21
|
+
<last_name>last_name1</last_name>
|
22
|
+
<p_street1>p_street11</p_street1>
|
23
|
+
<p_street2>p_street21</p_street2>
|
24
|
+
<p_city>p_city1</p_city>
|
25
|
+
<p_state>p_state1</p_state>
|
26
|
+
<p_country>p_country1</p_country>
|
27
|
+
<p_code>p_code1</p_code>
|
28
|
+
|
29
|
+
<return_uri>return_uri1</return_uri>
|
30
|
+
<updated>2009-08-1 01:00:00</updated>
|
31
|
+
|
32
|
+
<links>
|
33
|
+
<client_view>client_view1</client_view>
|
34
|
+
<view>view1</view>
|
35
|
+
<edit>edit1</edit>
|
36
|
+
</links>
|
37
|
+
|
38
|
+
<lines>
|
39
|
+
<line>
|
40
|
+
<amount>1</amount>
|
41
|
+
<name>name1</name>
|
42
|
+
<description>description1</description>
|
43
|
+
<unit_cost>1</unit_cost>
|
44
|
+
<quantity>1</quantity>
|
45
|
+
<tax1_name>tax1_name1</tax1_name>
|
46
|
+
<tax2_name>tax2_name1</tax2_name>
|
47
|
+
<tax1_percent>1</tax1_percent>
|
48
|
+
<tax2_percent>1</tax2_percent>
|
49
|
+
</line>
|
50
|
+
</lines>
|
51
|
+
|
52
|
+
<url deprecated="true">https://sample.freshbooks.com/inv/12345-1-6d30b</url>
|
53
|
+
<auth_url deprecated="true">https://sample.freshbooks.com/inv/12345-1-6d30b-z</auth_url>
|
54
|
+
|
55
|
+
</invoice>
|
56
|
+
<invoice>
|
57
|
+
<invoice_id>2</invoice_id>
|
58
|
+
<number>number2</number>
|
59
|
+
<client_id>2</client_id>
|
60
|
+
<recurring_id>2</recurring_id>
|
61
|
+
<organization>Organization 2</organization>
|
62
|
+
<status>draft</status>
|
63
|
+
<amount>200.00</amount>
|
64
|
+
<amount_outstanding>100.00</amount_outstanding>
|
65
|
+
<date>2009-02-02</date>
|
66
|
+
|
67
|
+
<po_number>2</po_number>
|
68
|
+
<discount>2</discount>
|
69
|
+
<notes>notes2</notes>
|
70
|
+
<terms>terms2</terms>
|
71
|
+
|
72
|
+
<first_name>first_name2</first_name>
|
73
|
+
<last_name>last_name2</last_name>
|
74
|
+
<p_street1>p_street12</p_street1>
|
75
|
+
<p_street2>p_street22</p_street2>
|
76
|
+
<p_city>p_city2</p_city>
|
77
|
+
<p_state>p_state2</p_state>
|
78
|
+
<p_country>p_country2</p_country>
|
79
|
+
<p_code>p_code2</p_code>
|
80
|
+
|
81
|
+
<return_uri>return_uri2</return_uri>
|
82
|
+
<updated>2009-08-2 02:00:00</updated>
|
83
|
+
|
84
|
+
<links>
|
85
|
+
<client_view>client_view2</client_view>
|
86
|
+
<view>view2</view>
|
87
|
+
<edit>edit2</edit>
|
88
|
+
</links>
|
89
|
+
|
90
|
+
<lines>
|
91
|
+
<line>
|
92
|
+
<amount>1</amount>
|
93
|
+
<name>name1</name>
|
94
|
+
<description>description1</description>
|
95
|
+
<unit_cost>1</unit_cost>
|
96
|
+
<quantity>1</quantity>
|
97
|
+
<tax1_name>tax1_name1</tax1_name>
|
98
|
+
<tax2_name>tax2_name1</tax2_name>
|
99
|
+
<tax1_percent>1</tax1_percent>
|
100
|
+
<tax2_percent>1</tax2_percent>
|
101
|
+
</line>
|
102
|
+
</lines>
|
103
|
+
|
104
|
+
<url deprecated="true">https://sample.freshbooks.com/inv/12345-1-6d30b</url>
|
105
|
+
<auth_url deprecated="true">https://sample.freshbooks.com/inv/12345-1-6d30b-z</auth_url>
|
106
|
+
|
107
|
+
</invoice>
|
108
|
+
</invoices>
|
109
|
+
</response>
|
@@ -0,0 +1,36 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../test_helper.rb'
|
2
|
+
|
3
|
+
module Schema
|
4
|
+
class TestDefinition < Test::Unit::TestCase
|
5
|
+
def setup
|
6
|
+
@definition = FreshBooks::Schema::Definition.new
|
7
|
+
end
|
8
|
+
|
9
|
+
def test_method_missing
|
10
|
+
# Empty
|
11
|
+
assert_equal 0, @definition.members.size
|
12
|
+
|
13
|
+
# One type
|
14
|
+
@definition.string :name
|
15
|
+
assert_equal 1, @definition.members.size
|
16
|
+
assert_equal({ :type => :string, :read_only => false }, @definition.members["name"])
|
17
|
+
|
18
|
+
# Multiple attributes
|
19
|
+
@definition.fixnum :version, :po_number
|
20
|
+
assert_equal 3, @definition.members.size
|
21
|
+
assert_equal({ :type => :fixnum, :read_only => false }, @definition.members["version"])
|
22
|
+
assert_equal({ :type => :fixnum, :read_only => false }, @definition.members["po_number"])
|
23
|
+
|
24
|
+
# Multiple times
|
25
|
+
@definition.fixnum :lock_number
|
26
|
+
assert_equal 4, @definition.members.size
|
27
|
+
assert_equal({ :type => :fixnum, :read_only => false }, @definition.members["lock_number"])
|
28
|
+
end
|
29
|
+
|
30
|
+
def test_method_missing_extra_options
|
31
|
+
@definition.fixnum :version, :po_number, :read_only => true
|
32
|
+
assert_equal({ :type => :fixnum, :read_only => true }, @definition.members["version"])
|
33
|
+
assert_equal({ :type => :fixnum, :read_only => true }, @definition.members["po_number"])
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../test_helper.rb'
|
2
|
+
|
3
|
+
module Schema
|
4
|
+
class TestMixin < Test::Unit::TestCase
|
5
|
+
def test_define_schema__unique_definition_per_class
|
6
|
+
assert MyItem.schema_definition.members.include?("name")
|
7
|
+
assert !MyItem.schema_definition.members.include?("name2")
|
8
|
+
|
9
|
+
assert MyItem2.schema_definition.members.include?("name2")
|
10
|
+
assert !MyItem2.schema_definition.members.include?("name")
|
11
|
+
end
|
12
|
+
|
13
|
+
def test_define_schema__creates_attr_accessors
|
14
|
+
assert MyItem.public_method_defined?("name")
|
15
|
+
assert MyItem.public_method_defined?("name=")
|
16
|
+
|
17
|
+
assert MyItem2.public_method_defined?("name2")
|
18
|
+
assert MyItem2.public_method_defined?("name2=")
|
19
|
+
end
|
20
|
+
|
21
|
+
def test_define_schema__creates_read_only_attr_accessors
|
22
|
+
assert MyItem.public_method_defined?("read_only_name")
|
23
|
+
assert MyItem.protected_method_defined?("read_only_name=")
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
class MyItem < FreshBooks::Base
|
28
|
+
define_schema do |s|
|
29
|
+
s.string :name
|
30
|
+
s.string :read_only_name, :read_only => true
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
class MyItem2 < FreshBooks::Base
|
35
|
+
define_schema do |s|
|
36
|
+
s.string :name2
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
data/test/test_base.rb
ADDED
@@ -0,0 +1,97 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/test_helper.rb'
|
2
|
+
|
3
|
+
class TestBase < Test::Unit::TestCase
|
4
|
+
def test_establish_connection
|
5
|
+
assert_nil FreshBooks::Base.connection
|
6
|
+
|
7
|
+
FreshBooks::Base.establish_connection("company.freshbooks.com", "auth_token")
|
8
|
+
connection = FreshBooks::Base.connection
|
9
|
+
assert_not_nil connection
|
10
|
+
assert_equal "company.freshbooks.com", connection.account_url
|
11
|
+
assert_equal "auth_token", connection.auth_token
|
12
|
+
|
13
|
+
FreshBooks::Base.establish_connection("company2.freshbooks.com", "auth_token2")
|
14
|
+
connection = FreshBooks::Base.connection
|
15
|
+
assert_not_nil connection
|
16
|
+
assert_equal "company2.freshbooks.com", connection.account_url
|
17
|
+
assert_equal "auth_token2", connection.auth_token
|
18
|
+
end
|
19
|
+
|
20
|
+
def test_new_from_xml_to_xml__round_trip
|
21
|
+
xml = <<-EOS
|
22
|
+
<my_item>
|
23
|
+
<name>name1</name>
|
24
|
+
<amount>4.5</amount>
|
25
|
+
<read_only_number>5</read_only_number>
|
26
|
+
<number>6</number>
|
27
|
+
<visible>1</visible>
|
28
|
+
<date>2008-02-01</date>
|
29
|
+
<created_at>2008-10-22 13:57:00</created_at>
|
30
|
+
<my_address>
|
31
|
+
<street1>street1</street1>
|
32
|
+
</my_address>
|
33
|
+
<my_lines>
|
34
|
+
<my_line>
|
35
|
+
<description>description</description>
|
36
|
+
</my_line>
|
37
|
+
</my_lines>
|
38
|
+
</my_item>
|
39
|
+
EOS
|
40
|
+
doc = REXML::Document.new(xml)
|
41
|
+
|
42
|
+
item = FreshBooks::MyItem.new_from_xml(doc.root)
|
43
|
+
assert_equal "name1", item.name
|
44
|
+
assert_equal 5, item.read_only_number
|
45
|
+
assert_equal 6, item.number
|
46
|
+
assert_equal 4.5, item.amount
|
47
|
+
assert_equal true, item.visible
|
48
|
+
assert_equal Date.new(2008, 2, 1), item.date
|
49
|
+
assert_equal DateTime.parse("2008-10-22 13:57:00 -04:00"), item.created_at
|
50
|
+
assert_equal "street1", item.my_address.street1
|
51
|
+
assert_equal 1, item.my_lines.size
|
52
|
+
assert_equal "description", item.my_lines.first.description
|
53
|
+
|
54
|
+
# If someone knows a good way to compare xml docs where ordering doesn't matter
|
55
|
+
# let me know. This can be refactored and improved greatly.
|
56
|
+
xml_out = item.to_xml.to_s.strip
|
57
|
+
assert_equal "<my_item>", xml_out.first(9)
|
58
|
+
assert xml_out.include?("<name>name1</name>")
|
59
|
+
assert xml_out.include?("<amount>4.5</amount>")
|
60
|
+
assert xml_out.include?("<visible>1</visible>")
|
61
|
+
assert !xml_out.include?("<read_only_number>5</read_only_number>") # this is read only
|
62
|
+
assert xml_out.include?("<number>6</number>")
|
63
|
+
assert xml_out.include?("<date>2008-02-01</date>")
|
64
|
+
assert xml_out.include?("<created_at>2008-10-22 13:57:00</created_at>")
|
65
|
+
assert xml_out.include?("<my_address><street1>street1</street1></my_address>")
|
66
|
+
assert xml_out.include?("<my_lines><my_line><description>description</description></my_line></my_lines>")
|
67
|
+
end
|
68
|
+
|
69
|
+
end
|
70
|
+
|
71
|
+
module FreshBooks
|
72
|
+
class MyItem < FreshBooks::Base
|
73
|
+
define_schema do |s|
|
74
|
+
s.string :name
|
75
|
+
s.fixnum :read_only_number, :read_only => true
|
76
|
+
s.fixnum :number
|
77
|
+
s.float :amount
|
78
|
+
s.boolean :visible
|
79
|
+
s.date :date
|
80
|
+
s.date_time :created_at
|
81
|
+
s.object :my_address
|
82
|
+
s.array :my_lines
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
class MyAddress < FreshBooks::Base
|
87
|
+
define_schema do |s|
|
88
|
+
s.string :street1
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
class MyLine < FreshBooks::Base
|
93
|
+
define_schema do |s|
|
94
|
+
s.string :description
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
@@ -0,0 +1,145 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/test_helper.rb'
|
2
|
+
|
3
|
+
class TestConnection < Test::Unit::TestCase
|
4
|
+
def setup
|
5
|
+
@connection = FreshBooks::Connection.new("company.freshbooks.com", "auth_token")
|
6
|
+
end
|
7
|
+
|
8
|
+
def test_connection_accessors
|
9
|
+
assert_equal "company.freshbooks.com", @connection.account_url
|
10
|
+
assert_equal "auth_token", @connection.auth_token
|
11
|
+
end
|
12
|
+
|
13
|
+
def test_connection_request_headers
|
14
|
+
request_headers = { "key" => "value" }
|
15
|
+
connection = FreshBooks::Connection.new("company.freshbooks.com", "auth_token", request_headers)
|
16
|
+
assert_equal request_headers, connection.request_headers
|
17
|
+
end
|
18
|
+
|
19
|
+
|
20
|
+
def test_create_request__array_of_elements
|
21
|
+
request = @connection.send(:create_request, 'mymethod', [['element1', 'value1'], [:element2, :value2]])
|
22
|
+
assert_equal "<?xml version='1.0' encoding='UTF-8'?><request method='mymethod'><element1>value1</element1><element2>value2</element2></request>", request
|
23
|
+
end
|
24
|
+
|
25
|
+
def test_create_request__base_object_element
|
26
|
+
invoice = FreshBooks::Invoice.new
|
27
|
+
invoice.expects(:to_xml).with().returns("<invoice><number>23</number></invoice>")
|
28
|
+
|
29
|
+
request = @connection.send(:create_request, 'mymethod', 'invoice' => invoice)
|
30
|
+
assert_equal "<?xml version='1.0' encoding='UTF-8'?><request method='mymethod'><invoice><number>23</number></invoice></request>", request
|
31
|
+
end
|
32
|
+
|
33
|
+
def test_check_for_api_error__success
|
34
|
+
body = "body xml"
|
35
|
+
response = Net::HTTPSuccess.new("1.1", "200", "message")
|
36
|
+
response.expects(:body).with().returns(body)
|
37
|
+
assert_equal body, @connection.send(:check_for_api_error, response)
|
38
|
+
end
|
39
|
+
|
40
|
+
def test_check_for_api_error__unknown_system
|
41
|
+
response = Net::HTTPMovedPermanently.new("1.1", "301", "message")
|
42
|
+
response.stubs(:[]).with("location").returns("loginSearch")
|
43
|
+
assert_raise(FreshBooks::UnknownSystemError) do
|
44
|
+
@connection.send(:check_for_api_error, response)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def test_check_for_api_error__deactivated
|
49
|
+
response = Net::HTTPMovedPermanently.new("1.1", "301", "message")
|
50
|
+
response.stubs(:[]).with("location").returns("deactivated")
|
51
|
+
assert_raise(FreshBooks::AccountDeactivatedError) do
|
52
|
+
@connection.send(:check_for_api_error, response)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
def test_check_for_api_error__unauthorized
|
57
|
+
response = Net::HTTPUnauthorized.new("1.1", "401", "message")
|
58
|
+
assert_raise(FreshBooks::AuthenticationError) do
|
59
|
+
@connection.send(:check_for_api_error, response)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
def test_check_for_api_error__bad_request
|
64
|
+
response = Net::HTTPBadRequest.new("1.1", "401", "message")
|
65
|
+
assert_raise(FreshBooks::ApiAccessNotEnabledError) do
|
66
|
+
@connection.send(:check_for_api_error, response)
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
def test_check_for_api_error__internal_error
|
71
|
+
response = Net::HTTPBadGateway.new("1.1", "502", "message")
|
72
|
+
assert_raise(FreshBooks::InternalError) do
|
73
|
+
@connection.send(:check_for_api_error, response)
|
74
|
+
end
|
75
|
+
|
76
|
+
response = Net::HTTPMovedPermanently.new("1.1", "301", "message")
|
77
|
+
response.stubs(:[]).with("location").returns("somePage")
|
78
|
+
assert_raise(FreshBooks::InternalError) do
|
79
|
+
@connection.send(:check_for_api_error, response)
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
def test_close_is_only_called_once_in_ntexted_start_sessions
|
84
|
+
@connection.expects(:obtain_connection)
|
85
|
+
@connection.expects(:close)
|
86
|
+
|
87
|
+
@connection.start_session { @connection.start_session { } }
|
88
|
+
end
|
89
|
+
|
90
|
+
def test_reconnect
|
91
|
+
connection = stub()
|
92
|
+
|
93
|
+
@connection.expects(:close).with()
|
94
|
+
@connection.expects(:obtain_connection).with(true).returns(connection)
|
95
|
+
|
96
|
+
assert_equal connection, @connection.send(:reconnect)
|
97
|
+
end
|
98
|
+
|
99
|
+
def test_post_request_successfull_request
|
100
|
+
request = "<request></request>"
|
101
|
+
response = "<response></response>"
|
102
|
+
|
103
|
+
http_connection = stub()
|
104
|
+
http_connection.expects(:request).with(request).returns(response)
|
105
|
+
@connection.expects(:start_session).with().yields(http_connection)
|
106
|
+
|
107
|
+
assert_equal response, @connection.send(:post_request, request)
|
108
|
+
end
|
109
|
+
|
110
|
+
def test_post_request_eof_error_retry
|
111
|
+
request = "<request></request>"
|
112
|
+
response = "<response></response>"
|
113
|
+
eof_error = EOFError.new("End of file error")
|
114
|
+
|
115
|
+
bad_http_connection = stub()
|
116
|
+
bad_http_connection.expects(:request).with(request).raises(eof_error)
|
117
|
+
|
118
|
+
new_http_connection = stub()
|
119
|
+
new_http_connection.expects(:request).with(request).returns(response)
|
120
|
+
|
121
|
+
@connection.expects(:start_session).with().yields(bad_http_connection)
|
122
|
+
@connection.expects(:reconnect).with().returns(new_http_connection)
|
123
|
+
|
124
|
+
assert_equal response, @connection.send(:post_request, request)
|
125
|
+
end
|
126
|
+
|
127
|
+
def test_post_request_eof_error_retry_only_retry_once
|
128
|
+
request = "<request></request>"
|
129
|
+
response = "<response></response>"
|
130
|
+
eof_error = EOFError.new("End of file error")
|
131
|
+
|
132
|
+
bad_http_connection = stub()
|
133
|
+
bad_http_connection.expects(:request).with(request).raises(eof_error)
|
134
|
+
|
135
|
+
new_http_connection = stub()
|
136
|
+
new_http_connection.expects(:request).with(request).raises(eof_error)
|
137
|
+
|
138
|
+
@connection.expects(:start_session).with().yields(bad_http_connection)
|
139
|
+
@connection.expects(:reconnect).with().returns(new_http_connection)
|
140
|
+
|
141
|
+
assert_raises(EOFError, eof_error.message) do
|
142
|
+
@connection.send(:post_request, request)
|
143
|
+
end
|
144
|
+
end
|
145
|
+
end
|