diff options
author | Ruben Davila <rdavila84@gmail.com> | 2017-01-18 19:48:16 +0300 |
---|---|---|
committer | Ruben Davila <rdavila84@gmail.com> | 2017-01-18 19:48:16 +0300 |
commit | 0f3c9355c1b57a56b4027df4deb78a2520596b15 (patch) | |
tree | 2b97df455017aa1c0c347b5f6d7255c295d9af67 /spec | |
parent | 63b36241945a7f9bb280f360b3b269de8c5be8f6 (diff) |
Add some API endpoints for time tracking.
New endpoints are:
POST :project_id/(issues|merge_requests)/(:issue_id|:merge_request_id)/time_estimate"
POST :project_id/(issues|merge_requests)/(:issue_id|:merge_request_id)/reset_time_estimate"
POST :project_id/(issues|merge_requests)/(:issue_id|:merge_request_id)/add_spent_time"
POST :project_id/(issues|merge_requests)/(:issue_id|:merge_request_id)/reset_spent_time"
GET :project_id/(issues|merge_requests)/(:issue_id|:merge_request_id)/time_stats"
Diffstat (limited to 'spec')
-rw-r--r-- | spec/models/concerns/issuable_spec.rb | 10 | ||||
-rw-r--r-- | spec/requests/api/issues_spec.rb | 6 | ||||
-rw-r--r-- | spec/requests/api/merge_requests_spec.rb | 8 | ||||
-rw-r--r-- | spec/services/slash_commands/interpret_service_spec.rb | 6 | ||||
-rw-r--r-- | spec/services/system_note_service_spec.rb | 4 | ||||
-rw-r--r-- | spec/support/api/time_tracking_shared_examples.rb | 132 |
6 files changed, 155 insertions, 11 deletions
diff --git a/spec/models/concerns/issuable_spec.rb b/spec/models/concerns/issuable_spec.rb index 344906c581b..d7d31892e12 100644 --- a/spec/models/concerns/issuable_spec.rb +++ b/spec/models/concerns/issuable_spec.rb @@ -414,7 +414,7 @@ describe Issue, "Issuable" do let(:issue) { create(:issue) } def spend_time(seconds) - issue.spend_time(seconds, user) + issue.spend_time(duration: seconds, user: user) issue.save! end @@ -438,10 +438,10 @@ describe Issue, "Issuable" do end context 'when time to substract exceeds the total time spent' do - it 'should not alter the total time spent' do - spend_time(-3600) - - expect(issue.total_time_spent).to eq(1800) + it 'raise a validation error' do + expect do + spend_time(-3600) + end.to raise_error(ActiveRecord::RecordInvalid) end end end diff --git a/spec/requests/api/issues_spec.rb b/spec/requests/api/issues_spec.rb index 12dd4bd83f7..807c999b84a 100644 --- a/spec/requests/api/issues_spec.rb +++ b/spec/requests/api/issues_spec.rb @@ -1193,4 +1193,10 @@ describe API::Issues, api: true do expect(response).to have_http_status(404) end end + + describe 'time tracking endpoints' do + let(:issuable) { issue } + + include_examples 'time tracking endpoints', 'issue' + end end diff --git a/spec/requests/api/merge_requests_spec.rb b/spec/requests/api/merge_requests_spec.rb index f032d1b683d..4e4fea1dad8 100644 --- a/spec/requests/api/merge_requests_spec.rb +++ b/spec/requests/api/merge_requests_spec.rb @@ -6,7 +6,7 @@ describe API::MergeRequests, api: true do let(:user) { create(:user) } let(:admin) { create(:user, :admin) } let(:non_member) { create(:user) } - let!(:project) { create(:project, creator_id: user.id, namespace: user.namespace) } + let!(:project) { create(:project, :public, creator_id: user.id, namespace: user.namespace) } let!(:merge_request) { create(:merge_request, :simple, author: user, assignee: user, source_project: project, target_project: project, title: "Test", created_at: base_time) } let!(:merge_request_closed) { create(:merge_request, state: "closed", author: user, assignee: user, source_project: project, target_project: project, title: "Closed test", created_at: base_time + 1.second) } let!(:merge_request_merged) { create(:merge_request, state: "merged", author: user, assignee: user, source_project: project, target_project: project, title: "Merged test", created_at: base_time + 2.seconds, merge_commit_sha: '9999999999999999999999999999999999999999') } @@ -671,6 +671,12 @@ describe API::MergeRequests, api: true do end end + describe 'Time tracking' do + let(:issuable) { merge_request } + + include_examples 'time tracking endpoints', 'merge_request' + end + def mr_with_later_created_and_updated_at_time merge_request merge_request.created_at += 1.hour diff --git a/spec/services/slash_commands/interpret_service_spec.rb b/spec/services/slash_commands/interpret_service_spec.rb index e1358acd7c1..80ae285ef64 100644 --- a/spec/services/slash_commands/interpret_service_spec.rb +++ b/spec/services/slash_commands/interpret_service_spec.rb @@ -222,7 +222,7 @@ describe SlashCommands::InterpretService, services: true do it 'populates spend_time: 3600 if content contains /spend 1h' do _, updates = service.execute(content, issuable) - expect(updates).to eq(spend_time: 3600) + expect(updates).to eq(spend_time: { duration: 3600, user: developer }) end end @@ -230,7 +230,7 @@ describe SlashCommands::InterpretService, services: true do it 'populates spend_time: -1800 if content contains /spend -30m' do _, updates = service.execute(content, issuable) - expect(updates).to eq(spend_time: -1800) + expect(updates).to eq(spend_time: { duration: -1800, user: developer }) end end @@ -246,7 +246,7 @@ describe SlashCommands::InterpretService, services: true do it 'populates spend_time: :reset if content contains /remove_time_spent' do _, updates = service.execute(content, issuable) - expect(updates).to eq(spend_time: :reset) + expect(updates).to eq(spend_time: { duration: :reset, user: developer }) end end diff --git a/spec/services/system_note_service_spec.rb b/spec/services/system_note_service_spec.rb index e85545f46dc..4042f2b0512 100644 --- a/spec/services/system_note_service_spec.rb +++ b/spec/services/system_note_service_spec.rb @@ -765,7 +765,7 @@ describe SystemNoteService, services: true do # We need a custom noteable in order to the shared examples to be green. let(:noteable) do mr = create(:merge_request, source_project: project) - mr.spend_time(1, author) + mr.spend_time(duration: 360000, user: author) mr.save! mr end @@ -801,7 +801,7 @@ describe SystemNoteService, services: true do end def spend_time!(seconds) - noteable.spend_time(seconds, author) + noteable.spend_time(duration: seconds, user: author) noteable.save! end end diff --git a/spec/support/api/time_tracking_shared_examples.rb b/spec/support/api/time_tracking_shared_examples.rb new file mode 100644 index 00000000000..210cd5817e0 --- /dev/null +++ b/spec/support/api/time_tracking_shared_examples.rb @@ -0,0 +1,132 @@ +shared_examples 'an unauthorized API user' do + it { is_expected.to eq(403) } +end + +shared_examples 'time tracking endpoints' do |issuable_name| + issuable_collection_name = issuable_name.pluralize + + describe "POST /projects/:id/#{issuable_collection_name}/:#{issuable_name}_id/time_estimate" do + context 'with an unauthorized user' do + subject { post(api("/projects/#{project.id}/#{issuable_collection_name}/#{issuable.id}/time_estimate", non_member), duration: '1w') } + + it_behaves_like 'an unauthorized API user' + end + + it "sets the time estimate for #{issuable_name}" do + post api("/projects/#{project.id}/#{issuable_collection_name}/#{issuable.id}/time_estimate", user), duration: '1w' + + expect(response).to have_http_status(200) + expect(json_response['human_time_estimate']).to eq('1w') + end + + describe 'updating the current estimate' do + before do + post api("/projects/#{project.id}/#{issuable_collection_name}/#{issuable.id}/time_estimate", user), duration: '1w' + end + + context 'when duration has a bad format' do + it 'does not modify the original estimate' do + post api("/projects/#{project.id}/#{issuable_collection_name}/#{issuable.id}/time_estimate", user), duration: 'foo' + + expect(response).to have_http_status(400) + expect(issuable.reload.human_time_estimate).to eq('1w') + end + end + + context 'with a valid duration' do + it 'updates the estimate' do + post api("/projects/#{project.id}/#{issuable_collection_name}/#{issuable.id}/time_estimate", user), duration: '3w1h' + + expect(response).to have_http_status(200) + expect(issuable.reload.human_time_estimate).to eq('3w 1h') + end + end + end + end + + describe "POST /projects/:id/#{issuable_collection_name}/:#{issuable_name}_id/reset_time_estimate" do + context 'with an unauthorized user' do + subject { post(api("/projects/#{project.id}/#{issuable_collection_name}/#{issuable.id}/reset_time_estimate", non_member)) } + + it_behaves_like 'an unauthorized API user' + end + + it "resets the time estimate for #{issuable_name}" do + post api("/projects/#{project.id}/#{issuable_collection_name}/#{issuable.id}/reset_time_estimate", user) + + expect(response).to have_http_status(200) + expect(json_response['time_estimate']).to eq(0) + end + end + + describe "POST /projects/:id/#{issuable_collection_name}/:#{issuable_name}_id/add_spent_time" do + context 'with an unauthorized user' do + subject do + post api("/projects/#{project.id}/#{issuable_collection_name}/#{issuable.id}/add_spent_time", non_member), + duration: '2h' + end + + it_behaves_like 'an unauthorized API user' + end + + it "add spent time for #{issuable_name}" do + post api("/projects/#{project.id}/#{issuable_collection_name}/#{issuable.id}/add_spent_time", user), + duration: '2h' + + expect(response).to have_http_status(201) + expect(json_response['human_total_time_spent']).to eq('2h') + end + + context 'when subtracting time' do + it 'subtracts time of the total spent time' do + issuable.update_attributes!(spend_time: { duration: 7200, user: user }) + + post api("/projects/#{project.id}/#{issuable_collection_name}/#{issuable.id}/add_spent_time", user), + duration: '-1h' + + expect(response).to have_http_status(201) + expect(json_response['total_time_spent']).to eq(3600) + end + end + + context 'when time to subtract is greater than the total spent time' do + it 'does not modify the total time spent' do + issuable.update_attributes!(spend_time: { duration: 7200, user: user }) + + post api("/projects/#{project.id}/#{issuable_collection_name}/#{issuable.id}/add_spent_time", user), + duration: '-1w' + + expect(response).to have_http_status(400) + expect(json_response['message']['time_spent'].first).to match(/exceeds the total time spent/) + end + end + end + + describe "POST /projects/:id/#{issuable_collection_name}/:#{issuable_name}_id/reset_spent_time" do + context 'with an unauthorized user' do + subject { post(api("/projects/#{project.id}/#{issuable_collection_name}/#{issuable.id}/reset_spent_time", non_member)) } + + it_behaves_like 'an unauthorized API user' + end + + it "resets spent time for #{issuable_name}" do + post api("/projects/#{project.id}/#{issuable_collection_name}/#{issuable.id}/reset_spent_time", user) + + expect(response).to have_http_status(200) + expect(json_response['total_time_spent']).to eq(0) + end + end + + describe "GET /projects/:id/#{issuable_collection_name}/:#{issuable_name}_id/time_stats" do + it "returns the time stats for #{issuable_name}" do + issuable.update_attributes!(spend_time: { duration: 1800, user: user }, + time_estimate: 3600) + + get api("/projects/#{project.id}/#{issuable_collection_name}/#{issuable.id}/time_stats", user) + + expect(response).to have_http_status(200) + expect(json_response['total_time_spent']).to eq(1800) + expect(json_response['time_estimate']).to eq(3600) + end + end +end |