harvest 0.8.2

Sign up to get free protection for your applications and to get access to all the features.
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