harvest 0.8.2

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 (38) hide show
  1. data/HISTORY +3 -0
  2. data/LICENSE +23 -0
  3. data/README.rdoc +173 -0
  4. data/Rakefile +44 -0
  5. data/lib/harvest.rb +35 -0
  6. data/lib/harvest/base.rb +77 -0
  7. data/lib/harvest/harvest_resource.rb +15 -0
  8. data/lib/harvest/plugins/active_resource_inheritable_headers.rb +36 -0
  9. data/lib/harvest/plugins/toggleable.rb +12 -0
  10. data/lib/harvest/resources/client.rb +8 -0
  11. data/lib/harvest/resources/entry.rb +34 -0
  12. data/lib/harvest/resources/expense.rb +22 -0
  13. data/lib/harvest/resources/expense_category.rb +7 -0
  14. data/lib/harvest/resources/person.rb +44 -0
  15. data/lib/harvest/resources/project.rb +51 -0
  16. data/lib/harvest/resources/task.rb +8 -0
  17. data/lib/harvest/resources/task_assignment.rb +27 -0
  18. data/lib/harvest/resources/user_assignment.rb +27 -0
  19. data/test/integration/client_integration.rb +17 -0
  20. data/test/integration/client_teardown.rb +11 -0
  21. data/test/integration/expense_category_integration.rb +16 -0
  22. data/test/integration/expense_category_teardown.rb +12 -0
  23. data/test/integration/harvest_integration_test.rb +47 -0
  24. data/test/integration/project_integration.rb +19 -0
  25. data/test/integration/project_teardown.rb +12 -0
  26. data/test/integration/task_integration.rb +19 -0
  27. data/test/integration/task_teardown.rb +12 -0
  28. data/test/test_helper.rb +51 -0
  29. data/test/unit/base_test.rb +88 -0
  30. data/test/unit/resources/client_test.rb +82 -0
  31. data/test/unit/resources/expense_category_test.rb +49 -0
  32. data/test/unit/resources/expense_test.rb +14 -0
  33. data/test/unit/resources/person_test.rb +150 -0
  34. data/test/unit/resources/project_test.rb +154 -0
  35. data/test/unit/resources/task_assignment_test.rb +72 -0
  36. data/test/unit/resources/task_test.rb +82 -0
  37. data/test/unit/resources/user_assignment_test.rb +71 -0
  38. metadata +111 -0
@@ -0,0 +1,82 @@
1
+ require File.join(File.dirname(__FILE__), "..", "..", "test_helper")
2
+
3
+ class ClientTest < Test::Unit::TestCase
4
+
5
+ def setup_resources
6
+ @client = {:id => 1, :name => "Widgets&Co"}.to_xml(:root => "client")
7
+ @clients = [{:id => 1, :name => "Widgets&Co"}].to_xml(:root => "clients")
8
+ end
9
+
10
+ def mock_client_responses
11
+ ActiveResource::HttpMock.respond_to do |mock|
12
+ mock.get "/clients.xml", {}, @clients
13
+ mock.get "/clients/1.xml", {}, @client
14
+ mock.post "/clients.xml", {}, @client, 201, "Location" => "/clients/5.xml"
15
+ mock.put "/clients/1.xml", {}, nil, 200
16
+ mock.delete "/clients/1.xml", {}, nil, 200
17
+ mock.put "/clients/1/toggle.xml", {}, nil, 200
18
+ end
19
+ end
20
+
21
+ context "Client actions" do
22
+ setup do
23
+ setup_resources
24
+ mock_client_responses
25
+ end
26
+
27
+ should "get index" do
28
+ Harvest::Resources::Client.find(:all)
29
+ expected_request = ActiveResource::Request.new(:get, "/clients.xml")
30
+ assert ActiveResource::HttpMock.requests.include?(expected_request)
31
+ end
32
+
33
+ should "get a single client" do
34
+ Harvest::Resources::Client.find(1)
35
+ expected_request = ActiveResource::Request.new(:get, "/clients/1.xml")
36
+ assert ActiveResource::HttpMock.requests.include?(expected_request)
37
+ end
38
+
39
+ should "create a new client" do
40
+ client = Harvest::Resources::Client.new(:name => "Widgets&Co")
41
+ client.save
42
+ expected_request = ActiveResource::Request.new(:post, "/clients.xml")
43
+ assert ActiveResource::HttpMock.requests.include?(expected_request)
44
+ end
45
+
46
+ should "update an existing client" do
47
+ client = Harvest::Resources::Client.find(1)
48
+ client.name = "Sprockets & Co"
49
+ client.save
50
+ expected_request = ActiveResource::Request.new(:put, "/clients/1.xml")
51
+ assert ActiveResource::HttpMock.requests.include?(expected_request)
52
+ end
53
+
54
+ should "delete an existing client" do
55
+ Harvest::Resources::Client.delete(1)
56
+ expected_request = ActiveResource::Request.new(:delete, "/clients/1.xml")
57
+ assert ActiveResource::HttpMock.requests.include?(expected_request)
58
+ end
59
+
60
+ end
61
+
62
+ context "Toggling active/inactive status" do
63
+ setup do
64
+ setup_resources
65
+ mock_client_responses
66
+ end
67
+
68
+ should "hit the toggle method" do
69
+ client = Harvest::Resources::Client.find(1)
70
+ client.toggle
71
+ expected_request = ActiveResource::Request.new(:put, "/clients/1/toggle.xml")
72
+ assert ActiveResource::HttpMock.requests.include?(expected_request)
73
+ end
74
+
75
+ should "return 200 Success toggle method" do
76
+ client = Harvest::Resources::Client.find(1)
77
+ assert client.toggle.code == 200
78
+ end
79
+
80
+ end
81
+
82
+ end
@@ -0,0 +1,49 @@
1
+ require File.join(File.dirname(__FILE__), "..", "..", "test_helper")
2
+
3
+ class ExpenseCategoryTest < Test::Unit::TestCase
4
+
5
+ def setup_resources
6
+ @expense_category = {:id => 1, :name => "Mileage"}.to_xml(:root => "expense_category")
7
+ @expense_categories = [{:id => 1, :name => "Mileage"}].to_xml(:root => "expense_categories")
8
+ end
9
+
10
+ def mock_responses
11
+ ActiveResource::HttpMock.respond_to do |mock|
12
+ mock.get "/expense_categories.xml", {}, @expense_categories
13
+ mock.post "/expense_categories.xml", {}, @expence_categories, 201, "Location" => "/expense_categories/5.xml"
14
+ mock.put "/expense_categories/1.xml", {}, nil, 200
15
+ mock.delete "/expense_categories/1.xml", {}, nil, 200
16
+ end
17
+ end
18
+
19
+ context "expense_category actions" do
20
+ setup do
21
+ setup_resources
22
+ mock_responses
23
+ end
24
+
25
+ # Note: The api technically supports updates; however, it doesn't support a show and
26
+ # therefore doesn't work well with activeresource.
27
+
28
+ should "get index" do
29
+ Harvest::Resources::ExpenseCategory.find(:all)
30
+ expected_request = ActiveResource::Request.new(:get, "/expense_categories.xml")
31
+ assert ActiveResource::HttpMock.requests.include?(expected_request)
32
+ end
33
+
34
+ should "create a new expense_category" do
35
+ expense_category = Harvest::Resources::ExpenseCategory.new(:name => "Widgets&Co")
36
+ expense_category.save
37
+ expected_request = ActiveResource::Request.new(:post, "/expense_categories.xml")
38
+ assert ActiveResource::HttpMock.requests.include?(expected_request)
39
+ end
40
+
41
+ should "delete an existing expense_category" do
42
+ Harvest::Resources::ExpenseCategory.delete(1)
43
+ expected_request = ActiveResource::Request.new(:delete, "/expense_categories/1.xml")
44
+ assert ActiveResource::HttpMock.requests.include?(expected_request)
45
+ end
46
+
47
+ end
48
+
49
+ end
@@ -0,0 +1,14 @@
1
+ require File.join(File.dirname(__FILE__), "..", "..", "test_helper")
2
+
3
+ class ExpenseAssignmentTest < Test::Unit::TestCase
4
+
5
+ context "ExpenseAssignment class" do
6
+
7
+ should "adjust the site setting when the person_id is set" do
8
+ expense_class = Harvest::Resources::Expense.clone
9
+ expense_class.person_id = 5
10
+ assert_equal "http://example.com/people/5", expense_class.site.to_s
11
+ end
12
+
13
+ end
14
+ end
@@ -0,0 +1,150 @@
1
+ require File.join(File.dirname(__FILE__), "..", "..", "test_helper")
2
+
3
+ class PersonTest < Test::Unit::TestCase
4
+
5
+ def setup_resources
6
+ @person_xml = {:id => 1, :name => "Joe Coder"}.to_xml(:root => "person")
7
+ @people = [{:id => 1, :name => "Joe Coder"}].to_xml(:root => "people")
8
+ @entry = [{:id => 2, :project_id => 50}].to_xml(:root => "day-entries")
9
+ @entries = [{:id => 1, :project_id => "25"},
10
+ {:id => 2, :project_id => 50} ].to_xml(:root => "day-entries")
11
+ @expenses = [{:id => 1, :project_id => "25"},
12
+ {:id => 2, :project_id => 50} ].to_xml(:root => "expenses")
13
+ end
14
+
15
+ def mock_responses
16
+ ActiveResource::HttpMock.respond_to do |mock|
17
+ mock.get "/people.xml", {}, @people
18
+ mock.get "/people/1.xml", {}, @person_xml
19
+ mock.post "/people.xml", {}, @person_xml, 201, "Location" => "/people/5.xml"
20
+ mock.put "/people/1.xml", {}, nil, 200
21
+ mock.delete "/people/1.xml", {}, nil, 200
22
+ mock.put "/people/1/toggle.xml", {}, nil, 200
23
+ mock.get "/people/1/entries.xml?from=20080101&to=20080131", {}, @entries
24
+ mock.get "/people/1/entries.xml?from=20080101&project_id=3&to=20080131", {}, @entry
25
+ mock.get "/people/1/expenses.xml?from=20080101&to=20080131", {}, @expenses
26
+ end
27
+ end
28
+
29
+ context "People CRUD actions -- " do
30
+ setup do
31
+ setup_resources
32
+ mock_responses
33
+ end
34
+
35
+ should "get index" do
36
+ Harvest::Resources::Person.find(:all)
37
+ expected_request = ActiveResource::Request.new(:get, "/people.xml")
38
+ assert ActiveResource::HttpMock.requests.include?(expected_request)
39
+ end
40
+
41
+ should "get a single project" do
42
+ Harvest::Resources::Person.find(1)
43
+ expected_request = ActiveResource::Request.new(:get, "/people/1.xml")
44
+ assert ActiveResource::HttpMock.requests.include?(expected_request)
45
+ end
46
+
47
+ should "create a new project" do
48
+ project = Harvest::Resources::Person.new(:name => "Widgets&Co")
49
+ project.save
50
+ expected_request = ActiveResource::Request.new(:post, "/people.xml")
51
+ assert ActiveResource::HttpMock.requests.include?(expected_request)
52
+ end
53
+
54
+ should "update an existing project" do
55
+ project = Harvest::Resources::Person.find(1)
56
+ project.name = "Joe Coder"
57
+ project.save
58
+ expected_request = ActiveResource::Request.new(:put, "/people/1.xml")
59
+ assert ActiveResource::HttpMock.requests.include?(expected_request)
60
+ end
61
+
62
+ should "delete an existing project" do
63
+ Harvest::Resources::Person.delete(1)
64
+ expected_request = ActiveResource::Request.new(:delete, "/people/1.xml")
65
+ assert ActiveResource::HttpMock.requests.include?(expected_request)
66
+ end
67
+
68
+ end
69
+
70
+
71
+ context "Toggling active/inactive status" do
72
+ setup do
73
+ setup_resources
74
+ mock_responses
75
+ end
76
+
77
+ should "hit the toggle method" do
78
+ person = Harvest::Resources::Person.find(1)
79
+ person.toggle
80
+ expected_request = ActiveResource::Request.new(:put, "/people/1/toggle.xml")
81
+ assert ActiveResource::HttpMock.requests.include?(expected_request)
82
+ end
83
+
84
+ should "return 200 Success toggle method" do
85
+ person = Harvest::Resources::Person.find(1)
86
+ assert person.toggle.code == 200
87
+ end
88
+
89
+ end
90
+
91
+ context "Getting entries" do
92
+ setup do
93
+ setup_resources
94
+ mock_responses
95
+ @person = Harvest::Resources::Person.find(1)
96
+ end
97
+
98
+ should "raise an error if start and end are not included" do
99
+ assert_raises ArgumentError, "Must specify :start and :end as dates." do
100
+ @person.entries
101
+ end
102
+ end
103
+
104
+ should "raise an error if end date precedes start date" do
105
+ assert_raises ArgumentError, "Must specify :start and :end as dates." do
106
+ @person.entries(:from => Time.utc(2007, 1, 1), :to => Time.utc(2006, 1, 1))
107
+ end
108
+ end
109
+
110
+ should "return the project site prefix" do
111
+ entry_class = Harvest::Resources::Entry.clone
112
+ entry_class.person_id = @person.id
113
+ assert_equal "http://example.com/people/1", entry_class.site.to_s
114
+ end
115
+
116
+ end
117
+
118
+ context "Reports -- " do
119
+ setup do
120
+ setup_resources
121
+ mock_responses
122
+ @from = Time.utc(2008, 1, 1)
123
+ @to = Time.utc(2008, 1, 31)
124
+ @person = Harvest::Resources::Person.find(1)
125
+ @request_path = "/people/1/entries.xml?from=20080101&to=20080131"
126
+ @expense_path = "/people/1/expenses.xml?from=20080101&to=20080131"
127
+ end
128
+
129
+ should "get all entries for a given date range" do
130
+ @person.entries(:from => @from, :to => @to)
131
+ expected_request = ActiveResource::Request.new(:get, @request_path)
132
+ assert ActiveResource::HttpMock.requests.include?(expected_request)
133
+ end
134
+
135
+ should "get all entries for the given date range and user" do
136
+ path = "/people/1/entries.xml?from=20080101&project_id=3&to=20080131"
137
+ @person.entries(:from => @from, :to => @to, :project_id => 3)
138
+ expected_request = ActiveResource::Request.new(:get, path)
139
+ assert ActiveResource::HttpMock.requests.include?(expected_request)
140
+ end
141
+
142
+ should "return all expense entries logged by the given user" do
143
+ @person.expenses(:from => @from, :to => @to)
144
+ expected_request = ActiveResource::Request.new(:get, @expense_path)
145
+ assert ActiveResource::HttpMock.requests.include?(expected_request)
146
+ end
147
+
148
+ end
149
+
150
+ end
@@ -0,0 +1,154 @@
1
+ require File.join(File.dirname(__FILE__), "..", "..", "test_helper")
2
+
3
+ class ProjectTest < Test::Unit::TestCase
4
+
5
+ def setup_resources
6
+ @project_xml = {:id => 1, :name => "Widget Redesign"}.to_xml(:root => "project")
7
+ @projects = [{:id => 1, :name => "Widget Redesign"}].to_xml(:root => "projects")
8
+ @entry = [{:id => 2, :project_id => 50}].to_xml(:root => "day-entries")
9
+ @entries = [{:id => 1, :project_id => "25"},
10
+ {:id => 2, :project_id => 50}].to_xml(:root => "day-entries")
11
+ @user_assignment = {:id => 1, :user_id => 5}.to_xml(:root => "user-assignment")
12
+ end
13
+
14
+ def mock_responses
15
+ ActiveResource::HttpMock.respond_to do |mock|
16
+ mock.get "/projects.xml", {}, @projects
17
+ mock.get "/projects/1.xml", {}, @project_xml
18
+ mock.post "/projects.xml", {}, @project, 201, "Location" => "/projects/5.xml"
19
+ mock.put "/projects/1.xml", {}, nil, 200
20
+ mock.delete "/projects/1.xml", {}, nil, 200
21
+ mock.put "/projects/1/toggle.xml", {}, nil, 200
22
+ mock.get "/projects/1/entries.xml?from=20080101&to=20080131", {}, @entries
23
+ mock.get "/projects/1/entries.xml?from=20080101&to=20080131&user_id=3", {}, @entry
24
+ end
25
+ end
26
+
27
+ context "Project CRUD actions -- " do
28
+ setup do
29
+ setup_resources
30
+ mock_responses
31
+ end
32
+
33
+ should "get index" do
34
+ Harvest::Resources::Project.find(:all)
35
+ expected_request = ActiveResource::Request.new(:get, "/projects.xml")
36
+ assert ActiveResource::HttpMock.requests.include?(expected_request)
37
+ end
38
+
39
+ should "get a single project" do
40
+ Harvest::Resources::Project.find(1)
41
+ expected_request = ActiveResource::Request.new(:get, "/projects/1.xml")
42
+ assert ActiveResource::HttpMock.requests.include?(expected_request)
43
+ end
44
+
45
+ should "create a new project" do
46
+ project = Harvest::Resources::Project.new(:name => "Widgets&Co")
47
+ project.save
48
+ expected_request = ActiveResource::Request.new(:post, "/projects.xml")
49
+ assert ActiveResource::HttpMock.requests.include?(expected_request)
50
+ end
51
+
52
+ should "update an existing project" do
53
+ project = Harvest::Resources::Project.find(1)
54
+ project.name = "Sprockets & Co"
55
+ project.save
56
+ expected_request = ActiveResource::Request.new(:put, "/projects/1.xml")
57
+ assert ActiveResource::HttpMock.requests.include?(expected_request)
58
+ end
59
+
60
+ should "delete an existing project" do
61
+ Harvest::Resources::Project.delete(1)
62
+ expected_request = ActiveResource::Request.new(:delete, "/projects/1.xml")
63
+ assert ActiveResource::HttpMock.requests.include?(expected_request)
64
+ end
65
+
66
+ end
67
+
68
+ context "Toggling active/inactive status" do
69
+ setup do
70
+ setup_resources
71
+ mock_responses
72
+ end
73
+
74
+ should "hit the toggle method" do
75
+ project = Harvest::Resources::Project.find(1)
76
+ project.toggle
77
+ expected_request = ActiveResource::Request.new(:put, "/projects/1/toggle.xml")
78
+ assert ActiveResource::HttpMock.requests.include?(expected_request)
79
+ end
80
+
81
+ should "return 200 Success toggle method" do
82
+ project = Harvest::Resources::Project.find(1)
83
+ assert project.toggle.code == 200
84
+ end
85
+
86
+ end
87
+
88
+ context "Nesting " do
89
+ setup do
90
+ setup_resources
91
+ mock_responses
92
+ @project = Harvest::Resources::Project.find(1)
93
+ end
94
+
95
+ should "get user assignments" do
96
+ end
97
+
98
+ should "get task assignments" do
99
+ end
100
+
101
+ end
102
+
103
+ context "Listing entries" do
104
+ setup do
105
+ setup_resources
106
+ mock_responses
107
+ @project = Harvest::Resources::Project.find(1)
108
+ end
109
+
110
+ should "raise an error if start and end are not included" do
111
+ assert_raises ArgumentError, "Must specify :start and :end as dates." do
112
+ @project.entries
113
+ end
114
+ end
115
+
116
+ should "raise an error if end date precedes start date" do
117
+ assert_raises ArgumentError, "Must specify :start and :end as dates." do
118
+ @project.entries(:from => Time.utc(2007, 1, 1), :to => Time.utc(2006, 1, 1))
119
+ end
120
+ end
121
+
122
+ should "return the project site prefix" do
123
+ entry_class = Harvest::Resources::Entry.clone
124
+ entry_class.project_id = @project.id
125
+ assert_equal "http://example.com/projects/1", entry_class.site.to_s
126
+ end
127
+
128
+ end
129
+
130
+ context "Reports -- " do
131
+ setup do
132
+ setup_resources
133
+ mock_responses
134
+ @from = Time.utc(2008, 1, 1)
135
+ @to = Time.utc(2008, 1, 31)
136
+ @project = Harvest::Resources::Project.find(1)
137
+ @request_path = "/projects/1/entries.xml?from=20080101&to=20080131"
138
+ end
139
+
140
+ should "get all entries for a given date range" do
141
+ @project.entries(:from => @from, :to => @to)
142
+ expected_request = ActiveResource::Request.new(:get, @request_path)
143
+ assert ActiveResource::HttpMock.requests.include?(expected_request)
144
+ end
145
+
146
+ should "get all entries for the given date range and user" do
147
+ @project.entries(:from => @from, :to => @to, :user_id => 3)
148
+ expected_request = ActiveResource::Request.new(:get, @request_path + "&user_id=3")
149
+ assert ActiveResource::HttpMock.requests.include?(expected_request)
150
+ end
151
+
152
+ end
153
+
154
+ end