diff options
author | Lin Jen-Shin <godfat@godfat.org> | 2016-10-18 09:31:30 +0000 |
---|---|---|
committer | Lin Jen-Shin <godfat@godfat.org> | 2016-10-18 09:31:30 +0000 |
commit | 68f964ad14a007a99df3d8d7f76d125fbe7f67c9 (patch) | |
tree | 26c0938530c3b761678cda2607427f6de3eba7c8 /spec/services | |
parent | a04e9f9b61d93ca872fe108d83f519ba6151631e (diff) | |
parent | 4e6af0c3fa335d138343dce3e0216303a9b1cd79 (diff) | |
download | gitlab-ce-68f964ad14a007a99df3d8d7f76d125fbe7f67c9.tar.gz |
Merge remote-tracking branch 'upstream/master' into show-commit-status-from-source-project
* upstream/master: (409 commits)
Update endpoint to username validator
change border color to variable
Add todo for deprecated user routes and more information about deprecation to changelog
Provide better error message to the user
Apply better hierarchy to markdown headers and issue/mr titles
Swapped button text manipulation outcomes for the toggle query
Fixed find file keyboard navigation
Update CHANGELOG for 8.12.7
Added download-button class and applied button margin
Enable activerecord_sane_schema_dumper for test
Updated logo from @luke
Fix broken specs on MySQL after https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/6896
Fix Test Env (proper error handling when gitlab-shell is not clonned)
Fix randomly crashing spinach test for merge request
[Great spinach fix] Replace gsub with delete
Remove carriage returns from commit description as summary is on a newline and will always include carriage returns
Convert due_date_select.js filetype to es6.
Stop directly parsing due_date with Date.parse, prefer parsing implicitly.
Improve spec for pipeline metrics worker
Add Pipeline metrics worker
...
Diffstat (limited to 'spec/services')
23 files changed, 560 insertions, 142 deletions
diff --git a/spec/services/boards/create_service_spec.rb b/spec/services/boards/create_service_spec.rb index a1a4dd4c57c..fde807cc410 100644 --- a/spec/services/boards/create_service_spec.rb +++ b/spec/services/boards/create_service_spec.rb @@ -2,33 +2,31 @@ require 'spec_helper' describe Boards::CreateService, services: true do describe '#execute' do + let(:project) { create(:empty_project) } + subject(:service) { described_class.new(project, double) } context 'when project does not have a board' do - let(:project) { create(:empty_project, board: nil) } - it 'creates a new board' do expect { service.execute }.to change(Board, :count).by(1) end it 'creates default lists' do - service.execute + board = service.execute - expect(project.board.lists.size).to eq 2 - expect(project.board.lists.first).to be_backlog - expect(project.board.lists.last).to be_done + expect(board.lists.size).to eq 2 + expect(board.lists.first).to be_backlog + expect(board.lists.last).to be_done end end context 'when project has a board' do - let!(:project) { create(:project_with_board) } - - it 'does not create a new board' do - expect { service.execute }.not_to change(Board, :count) + before do + create(:board, project: project) end - it 'does not create board lists' do - expect { service.execute }.not_to change(project.board.lists, :count) + it 'does not create a new board' do + expect { service.execute }.not_to change(project.boards, :count) end end end diff --git a/spec/services/boards/issues/create_service_spec.rb b/spec/services/boards/issues/create_service_spec.rb index 33e10e79f6d..360ee398f77 100644 --- a/spec/services/boards/issues/create_service_spec.rb +++ b/spec/services/boards/issues/create_service_spec.rb @@ -2,13 +2,13 @@ require 'spec_helper' describe Boards::Issues::CreateService, services: true do describe '#execute' do - let(:project) { create(:project_with_board) } - let(:board) { project.board } + let(:project) { create(:empty_project) } + let(:board) { create(:board, project: project) } let(:user) { create(:user) } let(:label) { create(:label, project: project, name: 'in-progress') } let!(:list) { create(:list, board: board, label: label, position: 0) } - subject(:service) { described_class.new(project, user, title: 'New issue') } + subject(:service) { described_class.new(project, user, board_id: board.id, list_id: list.id, title: 'New issue') } before do project.team << [user, :developer] @@ -17,15 +17,15 @@ describe Boards::Issues::CreateService, services: true do it 'delegates the create proceedings to Issues::CreateService' do expect_any_instance_of(Issues::CreateService).to receive(:execute).once - service.execute(list) + service.execute end it 'creates a new issue' do - expect { service.execute(list) }.to change(project.issues, :count).by(1) + expect { service.execute }.to change(project.issues, :count).by(1) end it 'adds the label of the list to the issue' do - issue = service.execute(list) + issue = service.execute expect(issue.labels).to eq [label] end diff --git a/spec/services/boards/issues/list_service_spec.rb b/spec/services/boards/issues/list_service_spec.rb index 5b9f454fd2d..7c206cf3ce7 100644 --- a/spec/services/boards/issues/list_service_spec.rb +++ b/spec/services/boards/issues/list_service_spec.rb @@ -3,8 +3,8 @@ require 'spec_helper' describe Boards::Issues::ListService, services: true do describe '#execute' do let(:user) { create(:user) } - let(:project) { create(:project_with_board) } - let(:board) { project.board } + let(:project) { create(:empty_project) } + let(:board) { create(:board, project: project) } let(:bug) { create(:label, project: project, name: 'Bug') } let(:development) { create(:label, project: project, name: 'Development') } @@ -13,10 +13,10 @@ describe Boards::Issues::ListService, services: true do let(:p2) { create(:label, title: 'P2', project: project, priority: 2) } let(:p3) { create(:label, title: 'P3', project: project, priority: 3) } - let!(:backlog) { project.board.backlog_list } + let!(:backlog) { create(:backlog_list, board: board) } let!(:list1) { create(:list, board: board, label: development, position: 0) } let!(:list2) { create(:list, board: board, label: testing, position: 1) } - let!(:done) { project.board.done_list } + let!(:done) { create(:done_list, board: board) } let!(:opened_issue1) { create(:labeled_issue, project: project, labels: [bug]) } let!(:opened_issue2) { create(:labeled_issue, project: project, labels: [p2]) } @@ -37,7 +37,7 @@ describe Boards::Issues::ListService, services: true do end it 'delegates search to IssuesFinder' do - params = { id: list1.id } + params = { board_id: board.id, id: list1.id } expect_any_instance_of(IssuesFinder).to receive(:execute).once.and_call_original @@ -46,7 +46,7 @@ describe Boards::Issues::ListService, services: true do context 'sets default order to priority' do it 'returns opened issues when listing issues from Backlog' do - params = { id: backlog.id } + params = { board_id: board.id, id: backlog.id } issues = described_class.new(project, user, params).execute @@ -54,7 +54,7 @@ describe Boards::Issues::ListService, services: true do end it 'returns closed issues when listing issues from Done' do - params = { id: done.id } + params = { board_id: board.id, id: done.id } issues = described_class.new(project, user, params).execute @@ -62,12 +62,29 @@ describe Boards::Issues::ListService, services: true do end it 'returns opened issues that have label list applied when listing issues from a label list' do - params = { id: list1.id } + params = { board_id: board.id, id: list1.id } issues = described_class.new(project, user, params).execute expect(issues).to eq [list1_issue3, list1_issue1, list1_issue2] end end + + context 'with list that does not belong to the board' do + it 'raises an error' do + list = create(:list) + service = described_class.new(project, user, board_id: board.id, id: list.id) + + expect { service.execute }.to raise_error(ActiveRecord::RecordNotFound) + end + end + + context 'with invalid list id' do + it 'raises an error' do + service = described_class.new(project, user, board_id: board.id, id: nil) + + expect { service.execute }.to raise_error(ActiveRecord::RecordNotFound) + end + end end end diff --git a/spec/services/boards/issues/move_service_spec.rb b/spec/services/boards/issues/move_service_spec.rb index 180f1b08631..c43b2aec490 100644 --- a/spec/services/boards/issues/move_service_spec.rb +++ b/spec/services/boards/issues/move_service_spec.rb @@ -3,17 +3,17 @@ require 'spec_helper' describe Boards::Issues::MoveService, services: true do describe '#execute' do let(:user) { create(:user) } - let(:project) { create(:project_with_board) } - let(:board) { project.board } + let(:project) { create(:empty_project) } + let(:board1) { create(:board, project: project) } let(:bug) { create(:label, project: project, name: 'Bug') } let(:development) { create(:label, project: project, name: 'Development') } let(:testing) { create(:label, project: project, name: 'Testing') } - let!(:backlog) { project.board.backlog_list } - let!(:list1) { create(:list, board: board, label: development, position: 0) } - let!(:list2) { create(:list, board: board, label: testing, position: 1) } - let!(:done) { project.board.done_list } + let!(:backlog) { create(:backlog_list, board: board1) } + let!(:list1) { create(:list, board: board1, label: development, position: 0) } + let!(:list2) { create(:list, board: board1, label: testing, position: 1) } + let!(:done) { create(:done_list, board: board1) } before do project.team << [user, :developer] @@ -22,7 +22,7 @@ describe Boards::Issues::MoveService, services: true do context 'when moving from backlog' do it 'adds the label of the list it goes to' do issue = create(:labeled_issue, project: project, labels: [bug]) - params = { from_list_id: backlog.id, to_list_id: list1.id } + params = { board_id: board1.id, from_list_id: backlog.id, to_list_id: list1.id } described_class.new(project, user, params).execute(issue) @@ -33,7 +33,7 @@ describe Boards::Issues::MoveService, services: true do context 'when moving to backlog' do it 'removes all list-labels' do issue = create(:labeled_issue, project: project, labels: [bug, development, testing]) - params = { from_list_id: list1.id, to_list_id: backlog.id } + params = { board_id: board1.id, from_list_id: list1.id, to_list_id: backlog.id } described_class.new(project, user, params).execute(issue) @@ -44,7 +44,7 @@ describe Boards::Issues::MoveService, services: true do context 'when moving from backlog to done' do it 'closes the issue' do issue = create(:labeled_issue, project: project, labels: [bug]) - params = { from_list_id: backlog.id, to_list_id: done.id } + params = { board_id: board1.id, from_list_id: backlog.id, to_list_id: done.id } described_class.new(project, user, params).execute(issue) issue.reload @@ -56,7 +56,7 @@ describe Boards::Issues::MoveService, services: true do context 'when moving an issue between lists' do let(:issue) { create(:labeled_issue, project: project, labels: [bug, development]) } - let(:params) { { from_list_id: list1.id, to_list_id: list2.id } } + let(:params) { { board_id: board1.id, from_list_id: list1.id, to_list_id: list2.id } } it 'delegates the label changes to Issues::UpdateService' do expect_any_instance_of(Issues::UpdateService).to receive(:execute).with(issue).once @@ -72,8 +72,12 @@ describe Boards::Issues::MoveService, services: true do end context 'when moving to done' do - let(:issue) { create(:labeled_issue, project: project, labels: [bug, development, testing]) } - let(:params) { { from_list_id: list2.id, to_list_id: done.id } } + let(:board2) { create(:board, project: project) } + let(:regression) { create(:label, project: project, name: 'Regression') } + let!(:list3) { create(:list, board: board2, label: regression, position: 1) } + + let(:issue) { create(:labeled_issue, project: project, labels: [bug, development, testing, regression]) } + let(:params) { { board_id: board1.id, from_list_id: list2.id, to_list_id: done.id } } it 'delegates the close proceedings to Issues::CloseService' do expect_any_instance_of(Issues::CloseService).to receive(:execute).with(issue).once @@ -81,7 +85,7 @@ describe Boards::Issues::MoveService, services: true do described_class.new(project, user, params).execute(issue) end - it 'removes all list-labels and close the issue' do + it 'removes all list-labels from project boards and close the issue' do described_class.new(project, user, params).execute(issue) issue.reload @@ -92,7 +96,7 @@ describe Boards::Issues::MoveService, services: true do context 'when moving from done' do let(:issue) { create(:labeled_issue, :closed, project: project, labels: [bug]) } - let(:params) { { from_list_id: done.id, to_list_id: list2.id } } + let(:params) { { board_id: board1.id, from_list_id: done.id, to_list_id: list2.id } } it 'delegates the re-open proceedings to Issues::ReopenService' do expect_any_instance_of(Issues::ReopenService).to receive(:execute).with(issue).once @@ -112,7 +116,7 @@ describe Boards::Issues::MoveService, services: true do context 'when moving from done to backlog' do it 'reopens the issue' do issue = create(:labeled_issue, :closed, project: project, labels: [bug]) - params = { from_list_id: done.id, to_list_id: backlog.id } + params = { board_id: board1.id, from_list_id: done.id, to_list_id: backlog.id } described_class.new(project, user, params).execute(issue) issue.reload @@ -124,7 +128,7 @@ describe Boards::Issues::MoveService, services: true do context 'when moving to same list' do let(:issue) { create(:labeled_issue, project: project, labels: [bug, development]) } - let(:params) { { from_list_id: list1.id, to_list_id: list1.id } } + let(:params) { { board_id: board1.id, from_list_id: list1.id, to_list_id: list1.id } } it 'returns false' do expect(described_class.new(project, user, params).execute(issue)).to eq false diff --git a/spec/services/boards/list_service_spec.rb b/spec/services/boards/list_service_spec.rb new file mode 100644 index 00000000000..dff33e4bcbb --- /dev/null +++ b/spec/services/boards/list_service_spec.rb @@ -0,0 +1,37 @@ +require 'spec_helper' + +describe Boards::ListService, services: true do + describe '#execute' do + let(:project) { create(:empty_project) } + + subject(:service) { described_class.new(project, double) } + + context 'when project does not have a board' do + it 'creates a new project board' do + expect { service.execute }.to change(project.boards, :count).by(1) + end + + it 'delegates the project board creation to Boards::CreateService' do + expect_any_instance_of(Boards::CreateService).to receive(:execute).once + + service.execute + end + end + + context 'when project has a board' do + before do + create(:board, project: project) + end + + it 'does not create a new board' do + expect { service.execute }.not_to change(project.boards, :count) + end + end + + it 'returns project boards' do + board = create(:board, project: project) + + expect(service.execute).to match_array [board] + end + end +end diff --git a/spec/services/boards/lists/create_service_spec.rb b/spec/services/boards/lists/create_service_spec.rb index bff9c1fd1fe..e7806add916 100644 --- a/spec/services/boards/lists/create_service_spec.rb +++ b/spec/services/boards/lists/create_service_spec.rb @@ -2,8 +2,8 @@ require 'spec_helper' describe Boards::Lists::CreateService, services: true do describe '#execute' do - let(:project) { create(:project_with_board) } - let(:board) { project.board } + let(:project) { create(:empty_project) } + let(:board) { create(:board, project: project) } let(:user) { create(:user) } let(:label) { create(:label, project: project, name: 'in-progress') } @@ -11,7 +11,7 @@ describe Boards::Lists::CreateService, services: true do context 'when board lists is empty' do it 'creates a new list at beginning of the list' do - list = service.execute + list = service.execute(board) expect(list.position).to eq 0 end @@ -19,7 +19,7 @@ describe Boards::Lists::CreateService, services: true do context 'when board lists has backlog, and done lists' do it 'creates a new list at beginning of the list' do - list = service.execute + list = service.execute(board) expect(list.position).to eq 0 end @@ -30,7 +30,7 @@ describe Boards::Lists::CreateService, services: true do create(:list, board: board, position: 0) create(:list, board: board, position: 1) - list = service.execute + list = service.execute(board) expect(list.position).to eq 2 end @@ -40,7 +40,7 @@ describe Boards::Lists::CreateService, services: true do it 'creates a new list at end of the label lists' do list1 = create(:list, board: board, position: 0) - list2 = service.execute + list2 = service.execute(board) expect(list1.reload.position).to eq 0 expect(list2.reload.position).to eq 1 @@ -52,7 +52,7 @@ describe Boards::Lists::CreateService, services: true do label = create(:label, name: 'in-development') service = described_class.new(project, user, label_id: label.id) - expect { service.execute }.to raise_error(ActiveRecord::RecordNotFound) + expect { service.execute(board) }.to raise_error(ActiveRecord::RecordNotFound) end end end diff --git a/spec/services/boards/lists/destroy_service_spec.rb b/spec/services/boards/lists/destroy_service_spec.rb index 474c4512471..628caf03476 100644 --- a/spec/services/boards/lists/destroy_service_spec.rb +++ b/spec/services/boards/lists/destroy_service_spec.rb @@ -2,8 +2,8 @@ require 'spec_helper' describe Boards::Lists::DestroyService, services: true do describe '#execute' do - let(:project) { create(:project_with_board) } - let(:board) { project.board } + let(:project) { create(:empty_project) } + let(:board) { create(:board, project: project) } let(:user) { create(:user) } context 'when list type is label' do @@ -15,11 +15,11 @@ describe Boards::Lists::DestroyService, services: true do end it 'decrements position of higher lists' do - backlog = project.board.backlog_list + backlog = board.backlog_list development = create(:list, board: board, position: 0) review = create(:list, board: board, position: 1) staging = create(:list, board: board, position: 2) - done = project.board.done_list + done = board.done_list described_class.new(project, user).execute(development) @@ -31,14 +31,14 @@ describe Boards::Lists::DestroyService, services: true do end it 'does not remove list from board when list type is backlog' do - list = project.board.backlog_list + list = board.backlog_list service = described_class.new(project, user) expect { service.execute(list) }.not_to change(board.lists, :count) end it 'does not remove list from board when list type is done' do - list = project.board.done_list + list = board.done_list service = described_class.new(project, user) expect { service.execute(list) }.not_to change(board.lists, :count) diff --git a/spec/services/boards/lists/generate_service_spec.rb b/spec/services/boards/lists/generate_service_spec.rb index 4171e4d816c..8b2f5e81338 100644 --- a/spec/services/boards/lists/generate_service_spec.rb +++ b/spec/services/boards/lists/generate_service_spec.rb @@ -2,15 +2,15 @@ require 'spec_helper' describe Boards::Lists::GenerateService, services: true do describe '#execute' do - let(:project) { create(:project_with_board) } - let(:board) { project.board } + let(:project) { create(:empty_project) } + let(:board) { create(:board, project: project) } let(:user) { create(:user) } subject(:service) { described_class.new(project, user) } context 'when board lists is empty' do it 'creates the default lists' do - expect { service.execute }.to change(board.lists, :count).by(2) + expect { service.execute(board) }.to change(board.lists, :count).by(2) end end @@ -18,13 +18,13 @@ describe Boards::Lists::GenerateService, services: true do it 'does not creates the default lists' do create(:list, board: board) - expect { service.execute }.not_to change(board.lists, :count) + expect { service.execute(board) }.not_to change(board.lists, :count) end end context 'when project labels does not contains any list label' do it 'creates labels' do - expect { service.execute }.to change(project.labels, :count).by(2) + expect { service.execute(board) }.to change(project.labels, :count).by(2) end end @@ -32,7 +32,7 @@ describe Boards::Lists::GenerateService, services: true do it 'creates the missing labels' do create(:label, project: project, name: 'Doing') - expect { service.execute }.to change(project.labels, :count).by(1) + expect { service.execute(board) }.to change(project.labels, :count).by(1) end end end diff --git a/spec/services/boards/lists/list_service_spec.rb b/spec/services/boards/lists/list_service_spec.rb new file mode 100644 index 00000000000..334cee3f06d --- /dev/null +++ b/spec/services/boards/lists/list_service_spec.rb @@ -0,0 +1,16 @@ +require 'spec_helper' + +describe Boards::Lists::ListService, services: true do + describe '#execute' do + it "returns board's lists" do + project = create(:empty_project) + board = create(:board, project: project) + label = create(:label, project: project) + list = create(:list, board: board, label: label) + + service = described_class.new(project, double) + + expect(service.execute(board)).to eq [board.backlog_list, list, board.done_list] + end + end +end diff --git a/spec/services/boards/lists/move_service_spec.rb b/spec/services/boards/lists/move_service_spec.rb index 102ed67449d..63fa0bb8c5f 100644 --- a/spec/services/boards/lists/move_service_spec.rb +++ b/spec/services/boards/lists/move_service_spec.rb @@ -2,16 +2,16 @@ require 'spec_helper' describe Boards::Lists::MoveService, services: true do describe '#execute' do - let(:project) { create(:project_with_board) } - let(:board) { project.board } + let(:project) { create(:empty_project) } + let(:board) { create(:board, project: project) } let(:user) { create(:user) } - let!(:backlog) { project.board.backlog_list } + let!(:backlog) { create(:backlog_list, board: board) } let!(:planning) { create(:list, board: board, position: 0) } let!(:development) { create(:list, board: board, position: 1) } let!(:review) { create(:list, board: board, position: 2) } let!(:staging) { create(:list, board: board, position: 3) } - let!(:done) { project.board.done_list } + let!(:done) { create(:done_list, board: board) } context 'when list type is set to label' do it 'keeps position of lists when new position is nil' do diff --git a/spec/services/compare_service_spec.rb b/spec/services/compare_service_spec.rb new file mode 100644 index 00000000000..3760f19aaa2 --- /dev/null +++ b/spec/services/compare_service_spec.rb @@ -0,0 +1,21 @@ +require 'spec_helper' + +describe CompareService, services: true do + let(:project) { create(:project) } + let(:user) { create(:user) } + let(:service) { described_class.new } + + describe '#execute' do + context 'compare with base, like feature...fix' do + subject { service.execute(project, 'feature', project, 'fix', straight: false) } + + it { expect(subject.diffs.size).to eq(1) } + end + + context 'straight compare, like feature..fix' do + subject { service.execute(project, 'feature', project, 'fix', straight: true) } + + it { expect(subject.diffs.size).to eq(3) } + end + end +end diff --git a/spec/services/create_deployment_service_spec.rb b/spec/services/create_deployment_service_spec.rb index 343b4385bf2..5fe56e7725f 100644 --- a/spec/services/create_deployment_service_spec.rb +++ b/spec/services/create_deployment_service_spec.rb @@ -84,11 +84,22 @@ describe CreateDeploymentService, services: true do expect(subject).to be_persisted end end + + context 'when project was removed' do + let(:project) { nil } + + it 'does not create deployment or environment' do + expect { subject }.not_to raise_error + + expect(Environment.count).to be_zero + expect(Deployment.count).to be_zero + end + end end describe 'processing of builds' do let(:environment) { nil } - + shared_examples 'does not create environment and deployment' do it 'does not create a new environment' do expect { subject }.not_to change { Environment.count } @@ -133,12 +144,12 @@ describe CreateDeploymentService, services: true do context 'without environment specified' do let(:build) { create(:ci_build, project: project) } - + it_behaves_like 'does not create environment and deployment' do subject { build.success } end end - + context 'when environment is specified' do let(:pipeline) { create(:ci_pipeline, project: project) } let(:build) { create(:ci_build, pipeline: pipeline, environment: 'production', options: options) } diff --git a/spec/services/git_push_service_spec.rb b/spec/services/git_push_service_spec.rb index 8e3e12114f2..dd2a9e9903a 100644 --- a/spec/services/git_push_service_spec.rb +++ b/spec/services/git_push_service_spec.rb @@ -184,8 +184,8 @@ describe GitPushService, services: true do context "Updates merge requests" do it "when pushing a new branch for the first time" do - expect(project).to receive(:update_merge_requests). - with(@blankrev, 'newrev', 'refs/heads/master', user) + expect(UpdateMergeRequestsWorker).to receive(:perform_async). + with(project.id, user.id, @blankrev, 'newrev', 'refs/heads/master') execute_service(project, user, @blankrev, 'newrev', 'refs/heads/master' ) end end diff --git a/spec/services/merge_requests/assign_issues_service_spec.rb b/spec/services/merge_requests/assign_issues_service_spec.rb new file mode 100644 index 00000000000..7aeb95a15ea --- /dev/null +++ b/spec/services/merge_requests/assign_issues_service_spec.rb @@ -0,0 +1,49 @@ +require 'spec_helper' + +describe MergeRequests::AssignIssuesService, services: true do + let(:user) { create(:user) } + let(:project) { create(:project, :public) } + let(:issue) { create(:issue, project: project) } + let(:merge_request) { create(:merge_request, :simple, source_project: project, author: user, description: "fixes #{issue.to_reference}") } + let(:service) { described_class.new(project, user, merge_request: merge_request) } + + before do + project.team << [user, :developer] + end + + it 'finds unassigned issues fixed in merge request' do + expect(service.assignable_issues.map(&:id)).to include(issue.id) + end + + it 'ignores issues already assigned to any user' do + issue.update!(assignee: create(:user)) + + expect(service.assignable_issues).to be_empty + end + + it 'ignores issues the user cannot update assignee on' do + project.team.truncate + + expect(service.assignable_issues).to be_empty + end + + it 'ignores all issues unless current_user is merge_request.author' do + merge_request.update!(author: create(:user)) + + expect(service.assignable_issues).to be_empty + end + + it 'accepts precomputed data for closes_issues' do + issue2 = create(:issue, project: project) + service2 = described_class.new(project, + user, + merge_request: merge_request, + closes_issues: [issue, issue2]) + + expect(service2.assignable_issues.count).to eq 2 + end + + it 'assigns these to the merge request owner' do + expect { service.execute }.to change { issue.reload.assignee }.to(user) + end +end diff --git a/spec/services/merge_requests/build_service_spec.rb b/spec/services/merge_requests/build_service_spec.rb index 0d586e2216b..3a3f07ddcb9 100644 --- a/spec/services/merge_requests/build_service_spec.rb +++ b/spec/services/merge_requests/build_service_spec.rb @@ -52,12 +52,28 @@ describe MergeRequests::BuildService, services: true do end end - context 'no commits in the diff' do - let(:commits) { [] } + context 'same source and target branch' do + let(:source_branch) { 'master' } it 'forbids the merge request from being created' do expect(merge_request.can_be_created).to eq(false) end + + it 'adds an error message to the merge request' do + expect(merge_request.errors).to contain_exactly('You must select different branches') + end + end + + context 'no commits in the diff' do + let(:commits) { [] } + + it 'allows the merge request to be created' do + expect(merge_request.can_be_created).to eq(true) + end + + it 'adds a WIP prefix to the merge request title' do + expect(merge_request.title).to eq('WIP: Feature branch') + end end context 'one commit in the diff' do diff --git a/spec/services/merge_requests/merge_when_build_succeeds_service_spec.rb b/spec/services/merge_requests/merge_when_build_succeeds_service_spec.rb index 9a29e400654..b80cfd8f450 100644 --- a/spec/services/merge_requests/merge_when_build_succeeds_service_spec.rb +++ b/spec/services/merge_requests/merge_when_build_succeeds_service_spec.rb @@ -58,57 +58,67 @@ describe MergeRequests::MergeWhenBuildSucceedsService do end describe "#trigger" do - context 'build with ref' do - let(:build) { create(:ci_build, ref: mr_merge_if_green_enabled.source_branch, status: "success") } + let(:merge_request_ref) { mr_merge_if_green_enabled.source_branch } + let(:merge_request_head) do + project.commit(mr_merge_if_green_enabled.source_branch).id + end - it "merges all merge requests with merge when build succeeds enabled" do - allow_any_instance_of(MergeRequest).to receive(:pipeline).and_return(pipeline) - allow(pipeline).to receive(:success?).and_return(true) + context 'when triggered by pipeline with valid ref and sha' do + let(:triggering_pipeline) do + create(:ci_pipeline, project: project, ref: merge_request_ref, + sha: merge_request_head, status: 'success') + end + it "merges all merge requests with merge when build succeeds enabled" do expect(MergeWorker).to receive(:perform_async) - service.trigger(build) + service.trigger(triggering_pipeline) end end - context 'triggered by an old build' do - let(:old_build) { create(:ci_build, ref: mr_merge_if_green_enabled.source_branch, status: "success") } - let(:build) { create(:ci_build, ref: mr_merge_if_green_enabled.source_branch, status: "success") } - - it "merges all merge requests with merge when build succeeds enabled" do - allow_any_instance_of(MergeRequest).to receive(:pipeline).and_return(pipeline) - allow(pipeline).to receive(:success?).and_return(true) - allow(old_build).to receive(:sha).and_return('1234abcdef') + context 'when triggered by an old pipeline' do + let(:old_pipeline) do + create(:ci_pipeline, project: project, ref: merge_request_ref, + sha: '1234abcdef', status: 'success') + end + it 'it does not merge merge request' do expect(MergeWorker).not_to receive(:perform_async) - service.trigger(old_build) + service.trigger(old_pipeline) end end - context 'commit status without ref' do - let(:commit_status) { create(:generic_commit_status, status: 'success') } - - before { mr_merge_if_green_enabled } - - it "doesn't merge a requests for status on other branch" do - allow(project.repository).to receive(:branch_names_contains).with(commit_status.sha).and_return([]) + context 'when triggered by pipeline from a different branch' do + let(:unrelated_pipeline) do + create(:ci_pipeline, project: project, ref: 'feature', + sha: merge_request_head, status: 'success') + end + it 'does not merge request' do expect(MergeWorker).not_to receive(:perform_async) - service.trigger(commit_status) + service.trigger(unrelated_pipeline) end + end + end - it 'discovers branches and merges all merge requests when status is success' do - allow(project.repository).to receive(:branch_names_contains). - with(commit_status.sha).and_return([mr_merge_if_green_enabled.source_branch]) - allow(pipeline).to receive(:success?).and_return(true) - allow_any_instance_of(MergeRequest).to receive(:pipeline).and_return(pipeline) - allow(pipeline).to receive(:success?).and_return(true) + describe "#cancel" do + before do + service.cancel(mr_merge_if_green_enabled) + end - expect(MergeWorker).to receive(:perform_async) - service.trigger(commit_status) - end + it "resets all the merge_when_build_succeeds params" do + expect(mr_merge_if_green_enabled.merge_when_build_succeeds).to be_falsey + expect(mr_merge_if_green_enabled.merge_params).to eq({}) + expect(mr_merge_if_green_enabled.merge_user).to be nil + end + + it 'Posts a system note' do + note = mr_merge_if_green_enabled.notes.last + expect(note.note).to include 'Canceled the automatic merge' end + end - context 'properly handles multiple stages' do + describe 'pipeline integration' do + context 'when there are multiple stages in the pipeline' do let(:ref) { mr_merge_if_green_enabled.source_branch } let(:sha) { project.commit(ref).id } @@ -148,21 +158,4 @@ describe MergeRequests::MergeWhenBuildSucceedsService do end end end - - describe "#cancel" do - before do - service.cancel(mr_merge_if_green_enabled) - end - - it "resets all the merge_when_build_succeeds params" do - expect(mr_merge_if_green_enabled.merge_when_build_succeeds).to be_falsey - expect(mr_merge_if_green_enabled.merge_params).to eq({}) - expect(mr_merge_if_green_enabled.merge_user).to be nil - end - - it 'Posts a system note' do - note = mr_merge_if_green_enabled.notes.last - expect(note.note).to include 'Canceled the automatic merge' - end - end end diff --git a/spec/services/merge_requests/refresh_service_spec.rb b/spec/services/merge_requests/refresh_service_spec.rb index 59d3912018a..e515bc9f89c 100644 --- a/spec/services/merge_requests/refresh_service_spec.rb +++ b/spec/services/merge_requests/refresh_service_spec.rb @@ -62,7 +62,8 @@ describe MergeRequests::RefreshService, services: true do it { expect(@merge_request.notes).not_to be_empty } it { expect(@merge_request).to be_open } - it { expect(@merge_request.merge_when_build_succeeds).to be_falsey} + it { expect(@merge_request.merge_when_build_succeeds).to be_falsey } + it { expect(@merge_request.diff_head_sha).to eq(@newrev) } it { expect(@fork_merge_request).to be_open } it { expect(@fork_merge_request.notes).to be_empty } it { expect(@build_failed_todo).to be_done } @@ -118,7 +119,7 @@ describe MergeRequests::RefreshService, services: true do it { expect(@merge_request.notes).to be_empty } it { expect(@merge_request).to be_open } - it { expect(@fork_merge_request.notes.last.note).to include('Added 4 commits') } + it { expect(@fork_merge_request.notes.last.note).to include('Added 28 commits') } it { expect(@fork_merge_request).to be_open } it { expect(@build_failed_todo).to be_pending } it { expect(@fork_build_failed_todo).to be_pending } @@ -169,7 +170,7 @@ describe MergeRequests::RefreshService, services: true do notes = @fork_merge_request.notes.reorder(:created_at).map(&:note) expect(notes[0]).to include('Restored source branch `master`') - expect(notes[1]).to include('Added 4 commits') + expect(notes[1]).to include('Added 28 commits') expect(@fork_merge_request).to be_open end end diff --git a/spec/services/merge_requests/resolve_service_spec.rb b/spec/services/merge_requests/resolve_service_spec.rb index d71932458fa..388abb6a0df 100644 --- a/spec/services/merge_requests/resolve_service_spec.rb +++ b/spec/services/merge_requests/resolve_service_spec.rb @@ -24,15 +24,26 @@ describe MergeRequests::ResolveService do end describe '#execute' do - context 'with valid params' do + context 'with section params' do let(:params) do { - sections: { - '2f6fcd96b88b36ce98c38da085c795a27d92a3dd_14_14' => 'head', - '6eb14e00385d2fb284765eb1cd8d420d33d63fc9_9_9' => 'head', - '6eb14e00385d2fb284765eb1cd8d420d33d63fc9_21_21' => 'origin', - '6eb14e00385d2fb284765eb1cd8d420d33d63fc9_49_49' => 'origin' - }, + files: [ + { + old_path: 'files/ruby/popen.rb', + new_path: 'files/ruby/popen.rb', + sections: { + '2f6fcd96b88b36ce98c38da085c795a27d92a3dd_14_14' => 'head' + } + }, { + old_path: 'files/ruby/regex.rb', + new_path: 'files/ruby/regex.rb', + sections: { + '6eb14e00385d2fb284765eb1cd8d420d33d63fc9_9_9' => 'head', + '6eb14e00385d2fb284765eb1cd8d420d33d63fc9_21_21' => 'origin', + '6eb14e00385d2fb284765eb1cd8d420d33d63fc9_49_49' => 'origin' + } + } + ], commit_message: 'This is a commit message!' } end @@ -49,7 +60,7 @@ describe MergeRequests::ResolveService do it 'creates a commit with the correct parents' do expect(merge_request.source_branch_head.parents.map(&:id)). to eq(['1450cd639e0bc6721eb02800169e464f212cde06', - '75284c70dd26c87f2a3fb65fd5a1f0b0138d3a6b']) + '824be604a34828eb682305f0d963056cfac87b2d']) end end @@ -74,8 +85,96 @@ describe MergeRequests::ResolveService do end end - context 'when a resolution is missing' do - let(:invalid_params) { { sections: { '2f6fcd96b88b36ce98c38da085c795a27d92a3dd_14_14' => 'head' } } } + context 'with content and sections params' do + let(:popen_content) { "class Popen\nend" } + + let(:params) do + { + files: [ + { + old_path: 'files/ruby/popen.rb', + new_path: 'files/ruby/popen.rb', + content: popen_content + }, { + old_path: 'files/ruby/regex.rb', + new_path: 'files/ruby/regex.rb', + sections: { + '6eb14e00385d2fb284765eb1cd8d420d33d63fc9_9_9' => 'head', + '6eb14e00385d2fb284765eb1cd8d420d33d63fc9_21_21' => 'origin', + '6eb14e00385d2fb284765eb1cd8d420d33d63fc9_49_49' => 'origin' + } + } + ], + commit_message: 'This is a commit message!' + } + end + + before do + MergeRequests::ResolveService.new(project, user, params).execute(merge_request) + end + + it 'creates a commit with the message' do + expect(merge_request.source_branch_head.message).to eq(params[:commit_message]) + end + + it 'creates a commit with the correct parents' do + expect(merge_request.source_branch_head.parents.map(&:id)). + to eq(['1450cd639e0bc6721eb02800169e464f212cde06', + '824be604a34828eb682305f0d963056cfac87b2d']) + end + + it 'sets the content to the content given' do + blob = merge_request.source_project.repository.blob_at(merge_request.source_branch_head.sha, + 'files/ruby/popen.rb') + + expect(blob.data).to eq(popen_content) + end + end + + context 'when a resolution section is missing' do + let(:invalid_params) do + { + files: [ + { + old_path: 'files/ruby/popen.rb', + new_path: 'files/ruby/popen.rb', + content: '' + }, { + old_path: 'files/ruby/regex.rb', + new_path: 'files/ruby/regex.rb', + sections: { '6eb14e00385d2fb284765eb1cd8d420d33d63fc9_9_9' => 'head' } + } + ], + commit_message: 'This is a commit message!' + } + end + + let(:service) { MergeRequests::ResolveService.new(project, user, invalid_params) } + + it 'raises a MissingResolution error' do + expect { service.execute(merge_request) }. + to raise_error(Gitlab::Conflict::File::MissingResolution) + end + end + + context 'when the content of a file is unchanged' do + let(:invalid_params) do + { + files: [ + { + old_path: 'files/ruby/popen.rb', + new_path: 'files/ruby/popen.rb', + content: '' + }, { + old_path: 'files/ruby/regex.rb', + new_path: 'files/ruby/regex.rb', + content: merge_request.conflicts.file_for_path('files/ruby/regex.rb', 'files/ruby/regex.rb').content + } + ], + commit_message: 'This is a commit message!' + } + end + let(:service) { MergeRequests::ResolveService.new(project, user, invalid_params) } it 'raises a MissingResolution error' do @@ -83,5 +182,27 @@ describe MergeRequests::ResolveService do to raise_error(Gitlab::Conflict::File::MissingResolution) end end + + context 'when a file is missing' do + let(:invalid_params) do + { + files: [ + { + old_path: 'files/ruby/popen.rb', + new_path: 'files/ruby/popen.rb', + content: '' + } + ], + commit_message: 'This is a commit message!' + } + end + + let(:service) { MergeRequests::ResolveService.new(project, user, invalid_params) } + + it 'raises a MissingFiles error' do + expect { service.execute(merge_request) }. + to raise_error(MergeRequests::ResolveService::MissingFiles) + end + end end end diff --git a/spec/services/merge_requests/update_service_spec.rb b/spec/services/merge_requests/update_service_spec.rb index 33db34c0f62..2433a7dad06 100644 --- a/spec/services/merge_requests/update_service_spec.rb +++ b/spec/services/merge_requests/update_service_spec.rb @@ -17,6 +17,7 @@ describe MergeRequests::UpdateService, services: true do before do project.team << [user, :master] project.team << [user2, :developer] + project.team << [user3, :developer] end describe 'execute' do @@ -104,6 +105,18 @@ describe MergeRequests::UpdateService, services: true do expect(note).not_to be_nil expect(note.note).to eq 'Target branch changed from `master` to `target`' end + + context 'when not including source branch removal options' do + before do + opts.delete(:force_remove_source_branch) + end + + it 'maintains the original options' do + update_merge_request(opts) + + expect(@merge_request.merge_params["force_remove_source_branch"]).to eq("1") + end + end end context 'todos' do @@ -188,6 +201,11 @@ describe MergeRequests::UpdateService, services: true do let!(:non_subscriber) { create(:user) } let!(:subscriber) { create(:user).tap { |u| label.toggle_subscription(u) } } + before do + project.team << [non_subscriber, :developer] + project.team << [subscriber, :developer] + end + it 'sends notifications for subscribers of newly added labels' do opts = { label_ids: [label.id] } diff --git a/spec/services/notification_service_spec.rb b/spec/services/notification_service_spec.rb index d820646ebdf..699b9925b4e 100644 --- a/spec/services/notification_service_spec.rb +++ b/spec/services/notification_service_spec.rb @@ -331,7 +331,7 @@ describe NotificationService, services: true do describe '#new_note' do it "records sent notifications" do # Ensure create SentNotification by noteable = merge_request 6 times, not noteable = note - expect(SentNotification).to receive(:record_note).with(note, any_args).exactly(4).times.and_call_original + expect(SentNotification).to receive(:record_note).with(note, any_args).exactly(3).times.and_call_original notification.new_note(note) @@ -1169,6 +1169,61 @@ describe NotificationService, services: true do end end + context 'guest user in private project' do + let(:private_project) { create(:empty_project, :private) } + let(:guest) { create(:user) } + let(:developer) { create(:user) } + let(:assignee) { create(:user) } + let(:merge_request) { create(:merge_request, source_project: private_project, assignee: assignee) } + let(:merge_request1) { create(:merge_request, source_project: private_project, assignee: assignee, description: "cc @#{guest.username}") } + let(:note) { create(:note, noteable: merge_request, project: private_project) } + + before do + private_project.team << [assignee, :developer] + private_project.team << [developer, :developer] + private_project.team << [guest, :guest] + + ActionMailer::Base.deliveries.clear + end + + it 'filters out guests when new note is created' do + expect(SentNotification).to receive(:record).with(merge_request, any_args).exactly(1).times + + notification.new_note(note) + + should_not_email(guest) + should_email(assignee) + end + + it 'filters out guests when new merge request is created' do + notification.new_merge_request(merge_request1, @u_disabled) + + should_not_email(guest) + should_email(assignee) + end + + it 'filters out guests when merge request is closed' do + notification.close_mr(merge_request, developer) + + should_not_email(guest) + should_email(assignee) + end + + it 'filters out guests when merge request is reopened' do + notification.reopen_mr(merge_request, developer) + + should_not_email(guest) + should_email(assignee) + end + + it 'filters out guests when merge request is merged' do + notification.merge_mr(merge_request, developer) + + should_not_email(guest) + should_email(assignee) + end + end + def build_team(project) @u_watcher = create_global_setting_for(create(:user), :watch) @u_participating = create_global_setting_for(create(:user), :participating) diff --git a/spec/services/slash_commands/interpret_service_spec.rb b/spec/services/slash_commands/interpret_service_spec.rb index ae4d286d250..b57e338b782 100644 --- a/spec/services/slash_commands/interpret_service_spec.rb +++ b/spec/services/slash_commands/interpret_service_spec.rb @@ -86,6 +86,25 @@ describe SlashCommands::InterpretService, services: true do end end + shared_examples 'multiple label command' do + it 'fetches label ids and populates add_label_ids if content contains multiple /label' do + bug # populate the label + inprogress # populate the label + _, updates = service.execute(content, issuable) + + expect(updates).to eq(add_label_ids: [inprogress.id, bug.id]) + end + end + + shared_examples 'multiple label with same argument' do + it 'prevents duplicate label ids and populates add_label_ids if content contains multiple /label' do + inprogress # populate the label + _, updates = service.execute(content, issuable) + + expect(updates).to eq(add_label_ids: [inprogress.id]) + end + end + shared_examples 'unlabel command' do it 'fetches label ids and populates remove_label_ids if content contains /unlabel' do issuable.update(label_ids: [inprogress.id]) # populate the label @@ -95,6 +114,15 @@ describe SlashCommands::InterpretService, services: true do end end + shared_examples 'multiple unlabel command' do + it 'fetches label ids and populates remove_label_ids if content contains mutiple /unlabel' do + issuable.update(label_ids: [inprogress.id, bug.id]) # populate the label + _, updates = service.execute(content, issuable) + + expect(updates).to eq(remove_label_ids: [inprogress.id, bug.id]) + end + end + shared_examples 'unlabel command with no argument' do it 'populates label_ids: [] if content contains /unlabel with no arguments' do issuable.update(label_ids: [inprogress.id]) # populate the label @@ -285,6 +313,16 @@ describe SlashCommands::InterpretService, services: true do let(:issuable) { merge_request } end + it_behaves_like 'multiple label command' do + let(:content) { %(/label ~"#{inprogress.title}" \n/label ~#{bug.title}) } + let(:issuable) { issue } + end + + it_behaves_like 'multiple label with same argument' do + let(:content) { %(/label ~"#{inprogress.title}" \n/label ~#{inprogress.title}) } + let(:issuable) { issue } + end + it_behaves_like 'unlabel command' do let(:content) { %(/unlabel ~"#{inprogress.title}") } let(:issuable) { issue } @@ -295,6 +333,11 @@ describe SlashCommands::InterpretService, services: true do let(:issuable) { merge_request } end + it_behaves_like 'multiple unlabel command' do + let(:content) { %(/unlabel ~"#{inprogress.title}" \n/unlabel ~#{bug.title}) } + let(:issuable) { issue } + end + it_behaves_like 'unlabel command with no argument' do let(:content) { %(/unlabel) } let(:issuable) { issue } diff --git a/spec/services/system_note_service_spec.rb b/spec/services/system_note_service_spec.rb index 304d4e62396..b4ba28dfe8e 100644 --- a/spec/services/system_note_service_spec.rb +++ b/spec/services/system_note_service_spec.rb @@ -54,7 +54,7 @@ describe SystemNoteService, services: true do it 'adds a message line for each commit' do new_commits.each_with_index do |commit, i| # Skip the header - expect(note_lines[i + 1]).to eq "* #{commit.short_id} - #{commit.title}" + expect(HTMLEntities.new.decode(note_lines[i + 1])).to eq "* #{commit.short_id} - #{commit.title}" end end end @@ -81,7 +81,7 @@ describe SystemNoteService, services: true do end it 'includes a commit count' do - expect(summary_line).to end_with " - 2 commits from branch `feature`" + expect(summary_line).to end_with " - 26 commits from branch `feature`" end end @@ -91,7 +91,7 @@ describe SystemNoteService, services: true do end it 'includes a commit count' do - expect(summary_line).to end_with " - 2 commits from branch `feature`" + expect(summary_line).to end_with " - 26 commits from branch `feature`" end end @@ -537,7 +537,7 @@ describe SystemNoteService, services: true do let(:mergereq) { create(:merge_request, :simple, target_project: project, source_project: project) } let(:jira_issue) { ExternalIssue.new("JIRA-1", project)} let(:jira_tracker) { project.jira_service } - let(:commit) { project.commit } + let(:commit) { project.repository.commits('master').find { |commit| commit.id == '5937ac0a7beb003549fc5fd26fc247adbce4a52e' } } context 'in JIRA issue tracker' do before do diff --git a/spec/services/todo_service_spec.rb b/spec/services/todo_service_spec.rb index b41f6f14fbd..ed55791d24e 100644 --- a/spec/services/todo_service_spec.rb +++ b/spec/services/todo_service_spec.rb @@ -345,7 +345,7 @@ describe TodoService, services: true do service.new_merge_request(mr_assigned, author) should_create_todo(user: member, target: mr_assigned, action: Todo::MENTIONED) - should_create_todo(user: guest, target: mr_assigned, action: Todo::MENTIONED) + should_not_create_todo(user: guest, target: mr_assigned, action: Todo::MENTIONED) should_create_todo(user: author, target: mr_assigned, action: Todo::MENTIONED) should_not_create_todo(user: john_doe, target: mr_assigned, action: Todo::MENTIONED) should_not_create_todo(user: non_member, target: mr_assigned, action: Todo::MENTIONED) @@ -357,7 +357,7 @@ describe TodoService, services: true do service.update_merge_request(mr_assigned, author) should_create_todo(user: member, target: mr_assigned, action: Todo::MENTIONED) - should_create_todo(user: guest, target: mr_assigned, action: Todo::MENTIONED) + should_not_create_todo(user: guest, target: mr_assigned, action: Todo::MENTIONED) should_create_todo(user: john_doe, target: mr_assigned, action: Todo::MENTIONED) should_create_todo(user: author, target: mr_assigned, action: Todo::MENTIONED) should_not_create_todo(user: non_member, target: mr_assigned, action: Todo::MENTIONED) @@ -381,6 +381,7 @@ describe TodoService, services: true do should_not_create_todo(user: john_doe, target: mr_assigned, action: Todo::MENTIONED) should_not_create_todo(user: member, target: mr_assigned, action: Todo::MENTIONED) should_not_create_todo(user: non_member, target: mr_assigned, action: Todo::MENTIONED) + should_not_create_todo(user: guest, target: mr_assigned, action: Todo::MENTIONED) end it 'does not raise an error when description not change' do @@ -430,6 +431,11 @@ describe TodoService, services: true do should_create_todo(user: john_doe, target: mr_assigned, author: john_doe, action: Todo::ASSIGNED) end + + it 'does not create a todo for guests' do + service.reassigned_merge_request(mr_assigned, author) + should_not_create_todo(user: guest, target: mr_assigned, action: Todo::MENTIONED) + end end describe '#merge_merge_request' do @@ -441,6 +447,11 @@ describe TodoService, services: true do expect(first_todo.reload).to be_done expect(second_todo.reload).to be_done end + + it 'does not create todo for guests' do + service.merge_merge_request(mr_assigned, john_doe) + should_not_create_todo(user: guest, target: mr_assigned, action: Todo::MENTIONED) + end end describe '#new_award_emoji' do @@ -495,6 +506,13 @@ describe TodoService, services: true do should_create_todo(user: john_doe, target: mr_unassigned, author: author, action: Todo::MENTIONED, note: legacy_diff_note_on_merge_request) end + + it 'does not create todo for guests' do + note_on_merge_request = create :note_on_merge_request, project: project, noteable: mr_assigned, note: mentions + service.new_note(note_on_merge_request, author) + + should_not_create_todo(user: guest, target: mr_assigned, action: Todo::MENTIONED) + end end end |