diff options
Diffstat (limited to 'spec')
179 files changed, 3344 insertions, 1161 deletions
diff --git a/spec/controllers/blob_controller_spec.rb b/spec/controllers/blob_controller_spec.rb index 2fcb4a6a528..44e011fd3a8 100644 --- a/spec/controllers/blob_controller_spec.rb +++ b/spec/controllers/blob_controller_spec.rb @@ -19,8 +19,8 @@ describe Projects::BlobController do before do get(:show, - namespace_id: project.namespace.to_param, - project_id: project.to_param, + namespace_id: project.namespace, + project_id: project, id: id) end @@ -50,8 +50,8 @@ describe Projects::BlobController do before do get(:show, - namespace_id: project.namespace.to_param, - project_id: project.to_param, + namespace_id: project.namespace, + project_id: project, id: id) controller.instance_variable_set(:@blob, nil) end diff --git a/spec/controllers/projects/blame_controller_spec.rb b/spec/controllers/projects/blame_controller_spec.rb index addc5e7ec33..c086b386381 100644 --- a/spec/controllers/projects/blame_controller_spec.rb +++ b/spec/controllers/projects/blame_controller_spec.rb @@ -16,8 +16,8 @@ describe Projects::BlameController do before do get(:show, - namespace_id: project.namespace.to_param, - project_id: project.to_param, + namespace_id: project.namespace, + project_id: project, id: id) end diff --git a/spec/controllers/projects/blob_controller_spec.rb b/spec/controllers/projects/blob_controller_spec.rb index 7d4636e98d1..ec36a64b415 100644 --- a/spec/controllers/projects/blob_controller_spec.rb +++ b/spec/controllers/projects/blob_controller_spec.rb @@ -14,8 +14,8 @@ describe Projects::BlobController do render_views def do_get(opts = {}) - params = { namespace_id: project.namespace.to_param, - project_id: project.to_param, + params = { namespace_id: project.namespace, + project_id: project, id: 'master/CHANGELOG' } get :diff, params.merge(opts) end @@ -40,8 +40,8 @@ describe Projects::BlobController do describe 'PUT update' do let(:default_params) do { - namespace_id: project.namespace.to_param, - project_id: project.to_param, + namespace_id: project.namespace, + project_id: project, id: 'master/CHANGELOG', target_branch: 'master', content: 'Added changes', @@ -96,8 +96,8 @@ describe Projects::BlobController do context 'when editing on the fork' do before do - default_params[:namespace_id] = forked_project.namespace.to_param - default_params[:project_id] = forked_project.to_param + default_params[:namespace_id] = forked_project.namespace + default_params[:project_id] = forked_project end it 'redirects to blob' do diff --git a/spec/controllers/projects/boards/issues_controller_spec.rb b/spec/controllers/projects/boards/issues_controller_spec.rb index ad15e3942a5..3d0533cb516 100644 --- a/spec/controllers/projects/boards/issues_controller_spec.rb +++ b/spec/controllers/projects/boards/issues_controller_spec.rb @@ -90,7 +90,7 @@ describe Projects::Boards::IssuesController do params = { namespace_id: project.namespace.to_param, - project_id: project.to_param, + project_id: project, board_id: board.to_param, list_id: list.try(:to_param) } @@ -146,7 +146,7 @@ describe Projects::Boards::IssuesController do sign_in(user) post :create, namespace_id: project.namespace.to_param, - project_id: project.to_param, + project_id: project, board_id: board.to_param, list_id: list.to_param, issue: { title: title }, @@ -209,7 +209,7 @@ describe Projects::Boards::IssuesController do sign_in(user) patch :update, namespace_id: project.namespace.to_param, - project_id: project.to_param, + project_id: project, board_id: board.to_param, id: issue.to_param, from_list_id: from_list_id, diff --git a/spec/controllers/projects/boards/lists_controller_spec.rb b/spec/controllers/projects/boards/lists_controller_spec.rb index b3f9f76a50c..432f3c53c90 100644 --- a/spec/controllers/projects/boards/lists_controller_spec.rb +++ b/spec/controllers/projects/boards/lists_controller_spec.rb @@ -47,7 +47,7 @@ describe Projects::Boards::ListsController do sign_in(user) get :index, namespace_id: project.namespace.to_param, - project_id: project.to_param, + project_id: project, board_id: board.to_param, format: :json end @@ -104,7 +104,7 @@ describe Projects::Boards::ListsController do sign_in(user) post :create, namespace_id: project.namespace.to_param, - project_id: project.to_param, + project_id: project, board_id: board.to_param, list: { label_id: label_id }, format: :json @@ -157,7 +157,7 @@ describe Projects::Boards::ListsController do sign_in(user) patch :update, namespace_id: project.namespace.to_param, - project_id: project.to_param, + project_id: project, board_id: board.to_param, id: list.to_param, list: { position: position }, @@ -200,7 +200,7 @@ describe Projects::Boards::ListsController do sign_in(user) delete :destroy, namespace_id: project.namespace.to_param, - project_id: project.to_param, + project_id: project, board_id: board.to_param, id: list.to_param, format: :json @@ -244,7 +244,7 @@ describe Projects::Boards::ListsController do sign_in(user) post :generate, namespace_id: project.namespace.to_param, - project_id: project.to_param, + project_id: project, board_id: board.to_param, format: :json end diff --git a/spec/controllers/projects/boards_controller_spec.rb b/spec/controllers/projects/boards_controller_spec.rb index cc19035740e..aed3a45c413 100644 --- a/spec/controllers/projects/boards_controller_spec.rb +++ b/spec/controllers/projects/boards_controller_spec.rb @@ -50,8 +50,8 @@ describe Projects::BoardsController do end def list_boards(format: :html) - get :index, namespace_id: project.namespace.to_param, - project_id: project.to_param, + get :index, namespace_id: project.namespace, + project_id: project, format: format end end @@ -100,8 +100,8 @@ describe Projects::BoardsController do end def read_board(board:, format: :html) - get :show, namespace_id: project.namespace.to_param, - project_id: project.to_param, + get :show, namespace_id: project.namespace, + project_id: project, id: board.to_param, format: format end diff --git a/spec/controllers/projects/branches_controller_spec.rb b/spec/controllers/projects/branches_controller_spec.rb index effd8bcd982..e70737376af 100644 --- a/spec/controllers/projects/branches_controller_spec.rb +++ b/spec/controllers/projects/branches_controller_spec.rb @@ -22,8 +22,8 @@ describe Projects::BranchesController do sign_in(user) post :create, - namespace_id: project.namespace.to_param, - project_id: project.to_param, + namespace_id: project.namespace, + project_id: project, branch_name: branch, ref: ref end @@ -76,8 +76,8 @@ describe Projects::BranchesController do it 'redirects' do post :create, - namespace_id: project.namespace.to_param, - project_id: project.to_param, + namespace_id: project.namespace, + project_id: project, branch_name: branch, issue_iid: issue.iid @@ -89,8 +89,8 @@ describe Projects::BranchesController do expect(SystemNoteService).to receive(:new_issue_branch).with(issue, project, user, "1-feature-branch") post :create, - namespace_id: project.namespace.to_param, - project_id: project.to_param, + namespace_id: project.namespace, + project_id: project, branch_name: branch, issue_iid: issue.iid end @@ -143,8 +143,8 @@ describe Projects::BranchesController do expect(SystemNoteService).not_to receive(:new_issue_branch) post :create, - namespace_id: project.namespace.to_param, - project_id: project.to_param, + namespace_id: project.namespace, + project_id: project, branch_name: branch, issue_iid: issue.iid end @@ -163,8 +163,8 @@ describe Projects::BranchesController do post :destroy, format: :html, id: 'foo/bar/baz', - namespace_id: project.namespace.to_param, - project_id: project.to_param + namespace_id: project.namespace, + project_id: project expect(response).to have_http_status(303) end @@ -179,8 +179,8 @@ describe Projects::BranchesController do post :destroy, format: :js, id: branch, - namespace_id: project.namespace.to_param, - project_id: project.to_param + namespace_id: project.namespace, + project_id: project end context "valid branch name, valid source" do @@ -210,8 +210,8 @@ describe Projects::BranchesController do describe "DELETE destroy_all_merged" do def destroy_all_merged delete :destroy_all_merged, - namespace_id: project.namespace.to_param, - project_id: project.to_param + namespace_id: project.namespace, + project_id: project end context 'when user is allowed to push' do diff --git a/spec/controllers/projects/commit_controller_spec.rb b/spec/controllers/projects/commit_controller_spec.rb index ebd2d0e092b..640baa3a01c 100644 --- a/spec/controllers/projects/commit_controller_spec.rb +++ b/spec/controllers/projects/commit_controller_spec.rb @@ -17,8 +17,8 @@ describe Projects::CommitController do def go(extra_params = {}) params = { - namespace_id: project.namespace.to_param, - project_id: project.to_param + namespace_id: project.namespace, + project_id: project } get :show, params.merge(extra_params) @@ -125,8 +125,8 @@ describe Projects::CommitController do it 'renders it' do get(:show, - namespace_id: fork_project.namespace.to_param, - project_id: fork_project.to_param, + namespace_id: fork_project.namespace, + project_id: fork_project, id: commit.id) expect(response).to be_success @@ -139,8 +139,8 @@ describe Projects::CommitController do commit = project.commit('5937ac0a7beb003549fc5fd26fc247adbce4a52e') get(:branches, - namespace_id: project.namespace.to_param, - project_id: project.to_param, + namespace_id: project.namespace, + project_id: project, id: commit.id) expect(assigns(:branches)).to include("master", "feature_conflict") @@ -152,8 +152,8 @@ describe Projects::CommitController do context 'when target branch is not provided' do it 'renders the 404 page' do post(:revert, - namespace_id: project.namespace.to_param, - project_id: project.to_param, + namespace_id: project.namespace, + project_id: project, id: commit.id) expect(response).not_to be_success @@ -164,8 +164,8 @@ describe Projects::CommitController do context 'when the revert was successful' do it 'redirects to the commits page' do post(:revert, - namespace_id: project.namespace.to_param, - project_id: project.to_param, + namespace_id: project.namespace, + project_id: project, target_branch: 'master', id: commit.id) @@ -177,8 +177,8 @@ describe Projects::CommitController do context 'when the revert failed' do before do post(:revert, - namespace_id: project.namespace.to_param, - project_id: project.to_param, + namespace_id: project.namespace, + project_id: project, target_branch: 'master', id: commit.id) end @@ -186,8 +186,8 @@ describe Projects::CommitController do it 'redirects to the commit page' do # Reverting a commit that has been already reverted. post(:revert, - namespace_id: project.namespace.to_param, - project_id: project.to_param, + namespace_id: project.namespace, + project_id: project, target_branch: 'master', id: commit.id) @@ -201,8 +201,8 @@ describe Projects::CommitController do context 'when target branch is not provided' do it 'renders the 404 page' do post(:cherry_pick, - namespace_id: project.namespace.to_param, - project_id: project.to_param, + namespace_id: project.namespace, + project_id: project, id: master_pickable_commit.id) expect(response).not_to be_success @@ -213,8 +213,8 @@ describe Projects::CommitController do context 'when the cherry-pick was successful' do it 'redirects to the commits page' do post(:cherry_pick, - namespace_id: project.namespace.to_param, - project_id: project.to_param, + namespace_id: project.namespace, + project_id: project, target_branch: 'master', id: master_pickable_commit.id) @@ -226,8 +226,8 @@ describe Projects::CommitController do context 'when the cherry_pick failed' do before do post(:cherry_pick, - namespace_id: project.namespace.to_param, - project_id: project.to_param, + namespace_id: project.namespace, + project_id: project, target_branch: 'master', id: master_pickable_commit.id) end @@ -235,8 +235,8 @@ describe Projects::CommitController do it 'redirects to the commit page' do # Cherry-picking a commit that has been already cherry-picked. post(:cherry_pick, - namespace_id: project.namespace.to_param, - project_id: project.to_param, + namespace_id: project.namespace, + project_id: project, target_branch: 'master', id: master_pickable_commit.id) @@ -249,8 +249,8 @@ describe Projects::CommitController do describe 'GET diff_for_path' do def diff_for_path(extra_params = {}) params = { - namespace_id: project.namespace.to_param, - project_id: project.to_param + namespace_id: project.namespace, + project_id: project } get :diff_for_path, params.merge(extra_params) @@ -313,8 +313,8 @@ describe Projects::CommitController do describe 'GET pipelines' do def get_pipelines(extra_params = {}) params = { - namespace_id: project.namespace.to_param, - project_id: project.to_param + namespace_id: project.namespace, + project_id: project } get :pipelines, params.merge(extra_params) diff --git a/spec/controllers/projects/commits_controller_spec.rb b/spec/controllers/projects/commits_controller_spec.rb index 54b8d1108a5..e26731fb691 100644 --- a/spec/controllers/projects/commits_controller_spec.rb +++ b/spec/controllers/projects/commits_controller_spec.rb @@ -16,8 +16,8 @@ describe Projects::CommitsController do context "when the ref does not exist with the suffix" do it "renders as atom" do get(:show, - namespace_id: project.namespace.to_param, - project_id: project.to_param, + namespace_id: project.namespace, + project_id: project, id: "master.atom") expect(response).to be_success @@ -33,8 +33,8 @@ describe Projects::CommitsController do allow_any_instance_of(Repository).to receive(:commit).with('master.atom').and_return(commit) get(:show, - namespace_id: project.namespace.to_param, - project_id: project.to_param, + namespace_id: project.namespace, + project_id: project, id: "master.atom") end diff --git a/spec/controllers/projects/compare_controller_spec.rb b/spec/controllers/projects/compare_controller_spec.rb index e811c76fb31..15ac4e0925a 100644 --- a/spec/controllers/projects/compare_controller_spec.rb +++ b/spec/controllers/projects/compare_controller_spec.rb @@ -13,8 +13,8 @@ describe Projects::CompareController do it 'compare shows some diffs' do get(:show, - namespace_id: project.namespace.to_param, - project_id: project.to_param, + namespace_id: project.namespace, + project_id: project, from: ref_from, to: ref_to) @@ -25,8 +25,8 @@ describe Projects::CompareController do it 'compare shows some diffs with ignore whitespace change option' do get(:show, - namespace_id: project.namespace.to_param, - project_id: project.to_param, + namespace_id: project.namespace, + project_id: project, from: '08f22f25', to: '66eceea0', w: 1) @@ -43,8 +43,8 @@ describe Projects::CompareController do describe 'non-existent refs' do it 'uses invalid source ref' do get(:show, - namespace_id: project.namespace.to_param, - project_id: project.to_param, + namespace_id: project.namespace, + project_id: project, from: 'non-existent', to: ref_to) @@ -55,8 +55,8 @@ describe Projects::CompareController do it 'uses invalid target ref' do get(:show, - namespace_id: project.namespace.to_param, - project_id: project.to_param, + namespace_id: project.namespace, + project_id: project, from: ref_from, to: 'non-existent') @@ -67,8 +67,8 @@ describe Projects::CompareController do it 'redirects back to index when params[:from] is empty and preserves params[:to]' do post(:create, - namespace_id: project.namespace.to_param, - project_id: project.to_param, + namespace_id: project.namespace, + project_id: project, from: '', to: 'master') @@ -77,8 +77,8 @@ describe Projects::CompareController do it 'redirects back to index when params[:to] is empty and preserves params[:from]' do post(:create, - namespace_id: project.namespace.to_param, - project_id: project.to_param, + namespace_id: project.namespace, + project_id: project, from: 'master', to: '') @@ -87,8 +87,8 @@ describe Projects::CompareController do it 'redirects back to index when params[:from] and params[:to] are empty' do post(:create, - namespace_id: project.namespace.to_param, - project_id: project.to_param, + namespace_id: project.namespace, + project_id: project, from: '', to: '') @@ -99,8 +99,8 @@ describe Projects::CompareController do describe 'GET diff_for_path' do def diff_for_path(extra_params = {}) params = { - namespace_id: project.namespace.to_param, - project_id: project.to_param + namespace_id: project.namespace, + project_id: project } get :diff_for_path, params.merge(extra_params) diff --git a/spec/controllers/projects/cycle_analytics_controller_spec.rb b/spec/controllers/projects/cycle_analytics_controller_spec.rb index 6a6d71a16ee..6fae52edbad 100644 --- a/spec/controllers/projects/cycle_analytics_controller_spec.rb +++ b/spec/controllers/projects/cycle_analytics_controller_spec.rb @@ -13,8 +13,8 @@ describe Projects::CycleAnalyticsController do context 'with no data' do it 'is true' do get(:show, - namespace_id: project.namespace.to_param, - project_id: project.to_param) + namespace_id: project.namespace, + project_id: project) expect(response).to be_success expect(assigns(:cycle_analytics_no_data)).to eq(true) @@ -32,8 +32,8 @@ describe Projects::CycleAnalyticsController do it 'is false' do get(:show, - namespace_id: project.namespace.to_param, - project_id: project.to_param) + namespace_id: project.namespace, + project_id: project) expect(response).to be_success expect(assigns(:cycle_analytics_no_data)).to eq(false) diff --git a/spec/controllers/projects/find_file_controller_spec.rb b/spec/controllers/projects/find_file_controller_spec.rb index a4884256c92..6a5433bcc9c 100644 --- a/spec/controllers/projects/find_file_controller_spec.rb +++ b/spec/controllers/projects/find_file_controller_spec.rb @@ -17,8 +17,8 @@ describe Projects::FindFileController do before do get(:show, - namespace_id: project.namespace.to_param, - project_id: project.to_param, + namespace_id: project.namespace, + project_id: project, id: id) end @@ -36,8 +36,8 @@ describe Projects::FindFileController do describe "GET #list" do def go(format: 'json') get :list, - namespace_id: project.namespace.to_param, - project_id: project.to_param, + namespace_id: project.namespace, + project_id: project, id: id, format: format end diff --git a/spec/controllers/projects/forks_controller_spec.rb b/spec/controllers/projects/forks_controller_spec.rb index a867668d97b..8282d79298f 100644 --- a/spec/controllers/projects/forks_controller_spec.rb +++ b/spec/controllers/projects/forks_controller_spec.rb @@ -9,8 +9,8 @@ describe Projects::ForksController do describe 'GET index' do def get_forks get :index, - namespace_id: project.namespace.to_param, - project_id: project.to_param + namespace_id: project.namespace, + project_id: project end context 'when fork is public' do @@ -71,8 +71,8 @@ describe Projects::ForksController do describe 'GET new' do def get_new get :new, - namespace_id: project.namespace.to_param, - project_id: project.to_param + namespace_id: project.namespace, + project_id: project end context 'when user is signed in' do @@ -99,8 +99,8 @@ describe Projects::ForksController do describe 'POST create' do def post_create post :create, - namespace_id: project.namespace.to_param, - project_id: project.to_param, + namespace_id: project.namespace, + project_id: project, namespace_key: user.namespace.id end diff --git a/spec/controllers/projects/graphs_controller_spec.rb b/spec/controllers/projects/graphs_controller_spec.rb index bbe8e4bf6b2..c4a7aa7d63e 100644 --- a/spec/controllers/projects/graphs_controller_spec.rb +++ b/spec/controllers/projects/graphs_controller_spec.rb @@ -34,7 +34,7 @@ describe Projects::GraphsController do end it 'sets the correct colour according to language' do - get(:languages, namespace_id: project.namespace.path, project_id: project.path, id: 'master') + get(:languages, namespace_id: project.namespace, project_id: project, id: 'master') expected_values.each do |val| expect(assigns(:languages)).to include(a_hash_including(val)) diff --git a/spec/controllers/projects/group_links_controller_spec.rb b/spec/controllers/projects/group_links_controller_spec.rb index a976a9c27ab..ca4a8e871c0 100644 --- a/spec/controllers/projects/group_links_controller_spec.rb +++ b/spec/controllers/projects/group_links_controller_spec.rb @@ -14,8 +14,8 @@ describe Projects::GroupLinksController do describe '#create' do shared_context 'link project to group' do before do - post(:create, namespace_id: project.namespace.to_param, - project_id: project.to_param, + post(:create, namespace_id: project.namespace, + project_id: project, link_group_id: group.id, link_group_access: ProjectGroupLink.default_access) end @@ -50,8 +50,8 @@ describe Projects::GroupLinksController do context 'when project group id equal link group id' do before do - post(:create, namespace_id: project.namespace.to_param, - project_id: project.to_param, + post(:create, namespace_id: project.namespace, + project_id: project, link_group_id: group2.id, link_group_access: ProjectGroupLink.default_access) end @@ -69,8 +69,8 @@ describe Projects::GroupLinksController do context 'when link group id is not present' do before do - post(:create, namespace_id: project.namespace.to_param, - project_id: project.to_param, + post(:create, namespace_id: project.namespace, + project_id: project, link_group_access: ProjectGroupLink.default_access) end diff --git a/spec/controllers/projects/imports_controller_spec.rb b/spec/controllers/projects/imports_controller_spec.rb index 2acbba469e3..7c75815f3c4 100644 --- a/spec/controllers/projects/imports_controller_spec.rb +++ b/spec/controllers/projects/imports_controller_spec.rb @@ -13,13 +13,13 @@ describe Projects::ImportsController do end it 'renders template' do - get :show, namespace_id: project.namespace.to_param, project_id: project.to_param + get :show, namespace_id: project.namespace.to_param, project_id: project expect(response).to render_template :show end it 'sets flash.now if params is present' do - get :show, namespace_id: project.namespace.to_param, project_id: project.to_param, continue: { to: '/', notice_now: 'Started' } + get :show, namespace_id: project.namespace.to_param, project_id: project, continue: { to: '/', notice_now: 'Started' } expect(flash.now[:notice]).to eq 'Started' end @@ -39,13 +39,13 @@ describe Projects::ImportsController do end it 'renders template' do - get :show, namespace_id: project.namespace.to_param, project_id: project.to_param + get :show, namespace_id: project.namespace.to_param, project_id: project expect(response).to render_template :show end it 'sets flash.now if params is present' do - get :show, namespace_id: project.namespace.to_param, project_id: project.to_param, continue: { to: '/', notice_now: 'In progress' } + get :show, namespace_id: project.namespace.to_param, project_id: project, continue: { to: '/', notice_now: 'In progress' } expect(flash.now[:notice]).to eq 'In progress' end @@ -57,7 +57,7 @@ describe Projects::ImportsController do end it 'redirects to new_namespace_project_import_path' do - get :show, namespace_id: project.namespace.to_param, project_id: project.to_param + get :show, namespace_id: project.namespace.to_param, project_id: project expect(response).to redirect_to new_namespace_project_import_path(project.namespace, project) end @@ -72,7 +72,7 @@ describe Projects::ImportsController do it 'redirects to namespace_project_path' do allow_any_instance_of(Project).to receive(:forked?).and_return(true) - get :show, namespace_id: project.namespace.to_param, project_id: project.to_param + get :show, namespace_id: project.namespace.to_param, project_id: project expect(flash[:notice]).to eq 'The project was successfully forked.' expect(response).to redirect_to namespace_project_path(project.namespace, project) @@ -81,7 +81,7 @@ describe Projects::ImportsController do context 'when project is external' do it 'redirects to namespace_project_path' do - get :show, namespace_id: project.namespace.to_param, project_id: project.to_param + get :show, namespace_id: project.namespace.to_param, project_id: project expect(flash[:notice]).to eq 'The project was successfully imported.' expect(response).to redirect_to namespace_project_path(project.namespace, project) @@ -97,7 +97,7 @@ describe Projects::ImportsController do end it 'redirects to params[:to]' do - get :show, namespace_id: project.namespace.to_param, project_id: project.to_param, continue: params + get :show, namespace_id: project.namespace.to_param, project_id: project, continue: params expect(flash[:notice]).to eq params[:notice] expect(response).to redirect_to params[:to] @@ -111,7 +111,7 @@ describe Projects::ImportsController do end it 'redirects to namespace_project_path' do - get :show, namespace_id: project.namespace.to_param, project_id: project.to_param + get :show, namespace_id: project.namespace.to_param, project_id: project expect(response).to redirect_to namespace_project_path(project.namespace, project) end diff --git a/spec/controllers/projects/issues_controller_spec.rb b/spec/controllers/projects/issues_controller_spec.rb index 7871b6a9e10..46c758b4654 100644 --- a/spec/controllers/projects/issues_controller_spec.rb +++ b/spec/controllers/projects/issues_controller_spec.rb @@ -12,7 +12,7 @@ describe Projects::IssuesController do allow(project).to receive(:external_issue_tracker).and_return(external) controller.instance_variable_set(:@project, project) - get :index, namespace_id: project.namespace.path, project_id: project + get :index, namespace_id: project.namespace, project_id: project expect(response).to redirect_to('https://example.com/project') end @@ -27,13 +27,13 @@ describe Projects::IssuesController do it_behaves_like "issuables list meta-data", :issue it "returns index" do - get :index, namespace_id: project.namespace.path, project_id: project.path + get :index, namespace_id: project.namespace, project_id: project expect(response).to have_http_status(200) end it "returns 301 if request path doesn't match project path" do - get :index, namespace_id: project.namespace.path, project_id: project.path.upcase + get :index, namespace_id: project.namespace, project_id: project.path.upcase expect(response).to redirect_to(namespace_project_issues_path(project.namespace, project)) end @@ -42,7 +42,7 @@ describe Projects::IssuesController do project.issues_enabled = false project.save - get :index, namespace_id: project.namespace.path, project_id: project.path + get :index, namespace_id: project.namespace, project_id: project expect(response).to have_http_status(404) end @@ -50,7 +50,7 @@ describe Projects::IssuesController do controller.instance_variable_set(:@project, project) allow(project).to receive(:default_issues_tracker?).and_return(false) - get :index, namespace_id: project.namespace.path, project_id: project.path + get :index, namespace_id: project.namespace, project_id: project expect(response).to have_http_status(404) end end @@ -67,8 +67,8 @@ describe Projects::IssuesController do it 'redirects to last_page if page number is larger than number of pages' do get :index, - namespace_id: project.namespace.path.to_param, - project_id: project.path.to_param, + namespace_id: project.namespace.to_param, + project_id: project, page: (last_page + 1).to_param expect(response).to redirect_to(namespace_project_issues_path(page: last_page, state: controller.params[:state], scope: controller.params[:scope])) @@ -76,8 +76,8 @@ describe Projects::IssuesController do it 'redirects to specified page' do get :index, - namespace_id: project.namespace.path.to_param, - project_id: project.path.to_param, + namespace_id: project.namespace.to_param, + project_id: project, page: last_page.to_param expect(assigns(:issues).current_page).to eq(last_page) @@ -94,7 +94,7 @@ describe Projects::IssuesController do end it 'builds a new issue' do - get :new, namespace_id: project.namespace.path, project_id: project + get :new, namespace_id: project.namespace, project_id: project expect(assigns(:issue)).to be_a_new(Issue) end @@ -104,7 +104,7 @@ describe Projects::IssuesController do project_with_repository.team << [user, :developer] mr = create(:merge_request_with_diff_notes, source_project: project_with_repository) - get :new, namespace_id: project_with_repository.namespace.path, project_id: project_with_repository, merge_request_for_resolving_discussions: mr.iid + get :new, namespace_id: project_with_repository.namespace, project_id: project_with_repository, merge_request_for_resolving_discussions: mr.iid expect(assigns(:issue).title).not_to be_empty expect(assigns(:issue).description).not_to be_empty @@ -117,7 +117,7 @@ describe Projects::IssuesController do allow(project).to receive(:external_issue_tracker).and_return(external) controller.instance_variable_set(:@project, project) - get :new, namespace_id: project.namespace.path, project_id: project + get :new, namespace_id: project.namespace, project_id: project expect(response).to redirect_to('https://example.com/issues/new') end @@ -125,14 +125,16 @@ describe Projects::IssuesController do end describe 'PUT #update' do + before do + sign_in(user) + project.team << [user, :developer] + end + + it_behaves_like 'update invalid issuable', Issue + context 'when moving issue to another private project' do let(:another_project) { create(:empty_project, :private) } - before do - sign_in(user) - project.team << [user, :developer] - end - context 'when user has access to move issue' do before { another_project.team << [user, :reporter] } @@ -251,7 +253,7 @@ describe Projects::IssuesController do def update_issue(issue_params = {}, additional_params = {}) params = { namespace_id: project.namespace.to_param, - project_id: project.to_param, + project_id: project, id: issue.iid, issue: issue_params }.merge(additional_params) @@ -262,7 +264,7 @@ describe Projects::IssuesController do def move_issue put :update, namespace_id: project.namespace.to_param, - project_id: project.to_param, + project_id: project, id: issue.iid, issue: { title: 'New title' }, move_to_project_id: another_project.id @@ -342,7 +344,7 @@ describe Projects::IssuesController do def get_issues get :index, namespace_id: project.namespace.to_param, - project_id: project.to_param + project_id: project end end @@ -405,7 +407,7 @@ describe Projects::IssuesController do def go(id:) get :show, namespace_id: project.namespace.to_param, - project_id: project.to_param, + project_id: project, id: id end end @@ -416,7 +418,7 @@ describe Projects::IssuesController do def go(id:) get :edit, namespace_id: project.namespace.to_param, - project_id: project.to_param, + project_id: project, id: id end end @@ -427,7 +429,7 @@ describe Projects::IssuesController do def go(id:) put :update, namespace_id: project.namespace.to_param, - project_id: project.to_param, + project_id: project, id: id, issue: { title: 'New title' } end @@ -442,7 +444,7 @@ describe Projects::IssuesController do post :create, { namespace_id: project.namespace.to_param, - project_id: project.to_param, + project_id: project, issue: { title: 'Title', description: 'Description' }.merge(issue_attrs) }.merge(additional_params) @@ -464,7 +466,7 @@ describe Projects::IssuesController do end def post_issue(issue_params) - post :create, namespace_id: project.namespace.to_param, project_id: project.to_param, issue: issue_params, merge_request_for_resolving_discussions: merge_request.iid + post :create, namespace_id: project.namespace.to_param, project_id: project, issue: issue_params, merge_request_for_resolving_discussions: merge_request.iid end it 'creates an issue for the project' do @@ -607,8 +609,8 @@ describe Projects::IssuesController do project.team << [admin, :master] sign_in(admin) post :mark_as_spam, { - namespace_id: project.namespace.path, - project_id: project.path, + namespace_id: project.namespace, + project_id: project, id: issue.iid } end @@ -624,7 +626,7 @@ describe Projects::IssuesController do context "when the user is a developer" do before { sign_in(user) } it "rejects a developer to destroy an issue" do - delete :destroy, namespace_id: project.namespace.path, project_id: project.path, id: issue.iid + delete :destroy, namespace_id: project.namespace, project_id: project, id: issue.iid expect(response).to have_http_status(404) end end @@ -637,7 +639,7 @@ describe Projects::IssuesController do before { sign_in(owner) } it "deletes the issue" do - delete :destroy, namespace_id: project.namespace.path, project_id: project.path, id: issue.iid + delete :destroy, namespace_id: project.namespace, project_id: project, id: issue.iid expect(response).to have_http_status(302) expect(controller).to set_flash[:notice].to(/The issue was successfully deleted\./).now @@ -646,7 +648,7 @@ describe Projects::IssuesController do it 'delegates the update of the todos count cache to TodoService' do expect_any_instance_of(TodoService).to receive(:destroy_issue).with(issue, owner).once - delete :destroy, namespace_id: project.namespace.path, project_id: project.path, id: issue.iid + delete :destroy, namespace_id: project.namespace, project_id: project, id: issue.iid end end end @@ -659,8 +661,8 @@ describe Projects::IssuesController do it "toggles the award emoji" do expect do - post(:toggle_award_emoji, namespace_id: project.namespace.path, - project_id: project.path, id: issue.iid, name: "thumbsup") + post(:toggle_award_emoji, namespace_id: project.namespace, + project_id: project, id: issue.iid, name: "thumbsup") end.to change { issue.award_emoji.count }.by(1) expect(response).to have_http_status(200) diff --git a/spec/controllers/projects/labels_controller_spec.rb b/spec/controllers/projects/labels_controller_spec.rb index 3e0326dd47d..6a6e9bf378a 100644 --- a/spec/controllers/projects/labels_controller_spec.rb +++ b/spec/controllers/projects/labels_controller_spec.rb @@ -67,7 +67,7 @@ describe Projects::LabelsController do end def list_labels - get :index, namespace_id: project.namespace.to_param, project_id: project.to_param + get :index, namespace_id: project.namespace.to_param, project_id: project end end @@ -76,7 +76,7 @@ describe Projects::LabelsController do let(:personal_project) { create(:empty_project, namespace: user.namespace) } it 'creates labels' do - post :generate, namespace_id: personal_project.namespace.to_param, project_id: personal_project.to_param + post :generate, namespace_id: personal_project.namespace.to_param, project_id: personal_project expect(response).to have_http_status(302) end @@ -84,7 +84,7 @@ describe Projects::LabelsController do context 'project belonging to a group' do it 'creates labels' do - post :generate, namespace_id: project.namespace.to_param, project_id: project.to_param + post :generate, namespace_id: project.namespace.to_param, project_id: project expect(response).to have_http_status(302) end @@ -109,7 +109,7 @@ describe Projects::LabelsController do end def toggle_subscription(label) - post :toggle_subscription, namespace_id: project.namespace.to_param, project_id: project.to_param, id: label.to_param + post :toggle_subscription, namespace_id: project.namespace.to_param, project_id: project, id: label.to_param end end @@ -119,7 +119,7 @@ describe Projects::LabelsController do context 'not group owner' do it 'denies access' do - post :promote, namespace_id: project.namespace.to_param, project_id: project.to_param, id: label_1.to_param + post :promote, namespace_id: project.namespace.to_param, project_id: project, id: label_1.to_param expect(response).to have_http_status(404) end @@ -131,13 +131,13 @@ describe Projects::LabelsController do end it 'gives access' do - post :promote, namespace_id: project.namespace.to_param, project_id: project.to_param, id: label_1.to_param + post :promote, namespace_id: project.namespace.to_param, project_id: project, id: label_1.to_param expect(response).to redirect_to(namespace_project_labels_path) end it 'promotes the label' do - post :promote, namespace_id: project.namespace.to_param, project_id: project.to_param, id: label_1.to_param + post :promote, namespace_id: project.namespace.to_param, project_id: project, id: label_1.to_param expect(Label.where(id: label_1.id)).to be_empty expect(GroupLabel.find_by(title: promoted_label_name)).not_to be_nil @@ -151,7 +151,7 @@ describe Projects::LabelsController do end it 'returns to label list' do - post :promote, namespace_id: project.namespace.to_param, project_id: project.to_param, id: label_1.to_param + post :promote, namespace_id: project.namespace.to_param, project_id: project, id: label_1.to_param expect(response).to redirect_to(namespace_project_labels_path) end end diff --git a/spec/controllers/projects/mattermosts_controller_spec.rb b/spec/controllers/projects/mattermosts_controller_spec.rb index cae733f0cfb..c5abf11cfa5 100644 --- a/spec/controllers/projects/mattermosts_controller_spec.rb +++ b/spec/controllers/projects/mattermosts_controller_spec.rb @@ -18,7 +18,7 @@ describe Projects::MattermostsController do it 'accepts the request' do get(:new, namespace_id: project.namespace.to_param, - project_id: project.to_param) + project_id: project) expect(response).to have_http_status(200) end @@ -30,7 +30,7 @@ describe Projects::MattermostsController do subject do post(:create, namespace_id: project.namespace.to_param, - project_id: project.to_param, + project_id: project, mattermost: mattermost_params) end diff --git a/spec/controllers/projects/merge_requests_controller_spec.rb b/spec/controllers/projects/merge_requests_controller_spec.rb index af13649eec5..250d64f7055 100644 --- a/spec/controllers/projects/merge_requests_controller_spec.rb +++ b/spec/controllers/projects/merge_requests_controller_spec.rb @@ -43,7 +43,8 @@ describe Projects::MergeRequestsController do submit_new_merge_request(format: :json) expect(response).to be_ok - expect(json_response).not_to be_empty + expect(json_response).to have_key 'pipelines' + expect(json_response['pipelines']).not_to be_empty end end end @@ -51,7 +52,7 @@ describe Projects::MergeRequestsController do def submit_new_merge_request(format: :html) get :new, namespace_id: fork_project.namespace.to_param, - project_id: fork_project.to_param, + project_id: fork_project, merge_request: { source_branch: 'remove-submodule', target_branch: 'master' @@ -64,7 +65,7 @@ describe Projects::MergeRequestsController do it "loads labels into the @labels variable" do get action, namespace_id: project.namespace.to_param, - project_id: project.to_param, + project_id: project, id: merge_request.iid, format: 'html' expect(assigns(:labels)).not_to be_nil @@ -76,7 +77,7 @@ describe Projects::MergeRequestsController do it "does generally work" do get(:show, namespace_id: project.namespace.to_param, - project_id: project.to_param, + project_id: project, id: merge_request.iid, format: format) @@ -90,7 +91,7 @@ describe Projects::MergeRequestsController do get(:show, namespace_id: project.namespace.to_param, - project_id: project.to_param, + project_id: project, id: merge_request.iid, format: format) end @@ -98,7 +99,7 @@ describe Projects::MergeRequestsController do it "renders it" do get(:show, namespace_id: project.namespace.to_param, - project_id: project.to_param, + project_id: project, id: merge_request.iid, format: format) @@ -111,7 +112,7 @@ describe Projects::MergeRequestsController do get(:show, namespace_id: project.namespace.to_param, - project_id: project.to_param, + project_id: project, id: merge_request.iid, format: format) @@ -126,7 +127,7 @@ describe Projects::MergeRequestsController do it "triggers workhorse to serve the request" do get(:show, namespace_id: project.namespace.to_param, - project_id: project.to_param, + project_id: project, id: merge_request.iid, format: :diff) @@ -138,7 +139,7 @@ describe Projects::MergeRequestsController do it 'triggers workhorse to serve the request' do get(:show, namespace_id: project.namespace.to_param, - project_id: project.to_param, + project_id: project, id: merge_request.iid, format: :patch) @@ -153,7 +154,7 @@ describe Projects::MergeRequestsController do def get_merge_requests(page = nil) get :index, namespace_id: project.namespace.to_param, - project_id: project.to_param, + project_id: project, state: 'opened', page: page.to_param end @@ -216,8 +217,8 @@ describe Projects::MergeRequestsController do it 'closes MR without errors' do post :update, - namespace_id: project.namespace.path, - project_id: project.path, + namespace_id: project.namespace, + project_id: project, id: merge_request.iid, merge_request: { state_event: 'close' @@ -231,8 +232,8 @@ describe Projects::MergeRequestsController do merge_request.close! put :update, - namespace_id: project.namespace.path, - project_id: project.path, + namespace_id: project.namespace, + project_id: project, id: merge_request.iid, merge_request: { title: 'New title' @@ -246,8 +247,8 @@ describe Projects::MergeRequestsController do merge_request.close! put :update, - namespace_id: project.namespace.path, - project_id: project.path, + namespace_id: project.namespace, + project_id: project, id: merge_request.iid, merge_request: { target_branch: 'new_branch' @@ -255,14 +256,16 @@ describe Projects::MergeRequestsController do expect { merge_request.reload.target_branch }.not_to change { merge_request.target_branch } end + + it_behaves_like 'update invalid issuable', MergeRequest end end describe 'POST merge' do let(:base_params) do { - namespace_id: project.namespace.path, - project_id: project.path, + namespace_id: project.namespace, + project_id: project, id: merge_request.iid, format: 'raw' } @@ -317,41 +320,41 @@ describe Projects::MergeRequestsController do merge_with_sha end - context 'when merge_when_build_succeeds is passed' do - def merge_when_build_succeeds - post :merge, base_params.merge(sha: merge_request.diff_head_sha, merge_when_build_succeeds: '1') + context 'when the pipeline succeeds is passed' do + def merge_when_pipeline_succeeds + post :merge, base_params.merge(sha: merge_request.diff_head_sha, merge_when_pipeline_succeeds: '1') end before do create(:ci_empty_pipeline, project: project, sha: merge_request.diff_head_sha, ref: merge_request.source_branch) end - it 'returns :merge_when_build_succeeds' do - merge_when_build_succeeds + it 'returns :merge_when_pipeline_succeeds' do + merge_when_pipeline_succeeds - expect(assigns(:status)).to eq(:merge_when_build_succeeds) + expect(assigns(:status)).to eq(:merge_when_pipeline_succeeds) end - it 'sets the MR to merge when the build succeeds' do - service = double(:merge_when_build_succeeds_service) + it 'sets the MR to merge when the pipeline succeeds' do + service = double(:merge_when_pipeline_succeeds_service) expect(MergeRequests::MergeWhenPipelineSucceedsService) .to receive(:new).with(project, anything, anything) .and_return(service) expect(service).to receive(:execute).with(merge_request) - merge_when_build_succeeds + merge_when_pipeline_succeeds end - context 'when project.only_allow_merge_if_build_succeeds? is true' do + context 'when project.only_allow_merge_if_pipeline_succeeds? is true' do before do - project.update_column(:only_allow_merge_if_build_succeeds, true) + project.update_column(:only_allow_merge_if_pipeline_succeeds, true) end - it 'returns :merge_when_build_succeeds' do - merge_when_build_succeeds + it 'returns :merge_when_pipeline_succeeds' do + merge_when_pipeline_succeeds - expect(assigns(:status)).to eq(:merge_when_build_succeeds) + expect(assigns(:status)).to eq(:merge_when_pipeline_succeeds) end end end @@ -426,7 +429,7 @@ describe Projects::MergeRequestsController do describe "DELETE destroy" do it "denies access to users unless they're admin or project owner" do - delete :destroy, namespace_id: project.namespace.path, project_id: project.path, id: merge_request.iid + delete :destroy, namespace_id: project.namespace, project_id: project, id: merge_request.iid expect(response).to have_http_status(404) end @@ -439,7 +442,7 @@ describe Projects::MergeRequestsController do before { sign_in owner } it "deletes the merge request" do - delete :destroy, namespace_id: project.namespace.path, project_id: project.path, id: merge_request.iid + delete :destroy, namespace_id: project.namespace, project_id: project, id: merge_request.iid expect(response).to have_http_status(302) expect(controller).to set_flash[:notice].to(/The merge request was successfully deleted\./).now @@ -448,7 +451,7 @@ describe Projects::MergeRequestsController do it 'delegates the update of the todos count cache to TodoService' do expect_any_instance_of(TodoService).to receive(:destroy_merge_request).with(merge_request, owner).once - delete :destroy, namespace_id: project.namespace.path, project_id: project.path, id: merge_request.iid + delete :destroy, namespace_id: project.namespace, project_id: project, id: merge_request.iid end end end @@ -457,7 +460,7 @@ describe Projects::MergeRequestsController do def go(extra_params = {}) params = { namespace_id: project.namespace.to_param, - project_id: project.to_param, + project_id: project, id: merge_request.iid } @@ -537,7 +540,7 @@ describe Projects::MergeRequestsController do def diff_for_path(extra_params = {}) params = { namespace_id: project.namespace.to_param, - project_id: project.to_param + project_id: project } get :diff_for_path, params.merge(extra_params) @@ -601,7 +604,7 @@ describe Projects::MergeRequestsController do before do other_project.team << [user, :master] - diff_for_path(id: merge_request.iid, old_path: existing_path, new_path: existing_path, project_id: other_project.to_param) + diff_for_path(id: merge_request.iid, old_path: existing_path, new_path: existing_path, project_id: other_project) end it 'returns a 404' do @@ -667,7 +670,7 @@ describe Projects::MergeRequestsController do def go(format: 'html') get :commits, namespace_id: project.namespace.to_param, - project_id: project.to_param, + project_id: project, id: merge_request.iid, format: format end @@ -707,7 +710,7 @@ describe Projects::MergeRequestsController do before do get :pipelines, namespace_id: project.namespace.to_param, - project_id: project.to_param, + project_id: project, id: merge_request.iid, format: :json end @@ -726,7 +729,7 @@ describe Projects::MergeRequestsController do get :conflicts, namespace_id: merge_request_with_conflicts.project.namespace.to_param, - project_id: merge_request_with_conflicts.project.to_param, + project_id: merge_request_with_conflicts.project, id: merge_request_with_conflicts.iid, format: 'json' end @@ -744,7 +747,7 @@ describe Projects::MergeRequestsController do before do get :conflicts, namespace_id: merge_request_with_conflicts.project.namespace.to_param, - project_id: merge_request_with_conflicts.project.to_param, + project_id: merge_request_with_conflicts.project, id: merge_request_with_conflicts.iid, format: 'json' end @@ -807,7 +810,7 @@ describe Projects::MergeRequestsController do post :remove_wip, namespace_id: merge_request.project.namespace.to_param, - project_id: merge_request.project.to_param, + project_id: merge_request.project, id: merge_request.iid expect(merge_request.reload.title).to eq(merge_request.wipless_title) @@ -818,7 +821,7 @@ describe Projects::MergeRequestsController do def conflict_for_path(path) get :conflict_for_path, namespace_id: merge_request_with_conflicts.project.namespace.to_param, - project_id: merge_request_with_conflicts.project.to_param, + project_id: merge_request_with_conflicts.project, id: merge_request_with_conflicts.iid, old_path: path, new_path: path, @@ -874,7 +877,7 @@ describe Projects::MergeRequestsController do def resolve_conflicts(files) post :resolve_conflicts, namespace_id: merge_request_with_conflicts.project.namespace.to_param, - project_id: merge_request_with_conflicts.project.to_param, + project_id: merge_request_with_conflicts.project, id: merge_request_with_conflicts.iid, format: 'json', files: files, @@ -1025,7 +1028,7 @@ describe Projects::MergeRequestsController do post :assign_related_issues, namespace_id: project.namespace.to_param, - project_id: project.to_param, + project_id: project, id: merge_request.iid end @@ -1080,7 +1083,7 @@ describe Projects::MergeRequestsController do get :ci_environments_status, namespace_id: merge_request.project.namespace.to_param, - project_id: merge_request.project.to_param, + project_id: merge_request.project, id: merge_request.iid, format: 'json' end @@ -1093,8 +1096,8 @@ describe Projects::MergeRequestsController do describe 'GET merge_widget_refresh' do let(:params) do { - namespace_id: project.namespace.path, - project_id: project.path, + namespace_id: project.namespace, + project_id: project, id: merge_request.iid, format: :raw } @@ -1132,14 +1135,14 @@ describe Projects::MergeRequestsController do end context 'when waiting for build' do - let(:merge_request) { create(:merge_request, source_project: project, merge_when_build_succeeds: true, merge_user: user) } + let(:merge_request) { create(:merge_request, source_project: project, merge_when_pipeline_succeeds: true, merge_user: user) } it 'returns an OK response' do expect(response).to have_http_status(:ok) end - it 'sets status to :merge_when_build_succeeds' do - expect(assigns(:status)).to eq(:merge_when_build_succeeds) + it 'sets status to :merge_when_pipeline_succeeds' do + expect(assigns(:status)).to eq(:merge_when_pipeline_succeeds) expect(response).to render_template('merge') end end diff --git a/spec/controllers/projects/pipelines_controller_spec.rb b/spec/controllers/projects/pipelines_controller_spec.rb index 9a1e79c281a..04bb5cbbd59 100644 --- a/spec/controllers/projects/pipelines_controller_spec.rb +++ b/spec/controllers/projects/pipelines_controller_spec.rb @@ -17,8 +17,8 @@ describe Projects::PipelinesController do create(:ci_empty_pipeline, status: 'created', project: project) create(:ci_empty_pipeline, status: 'success', project: project) - get :index, namespace_id: project.namespace.path, - project_id: project.path, + get :index, namespace_id: project.namespace, + project_id: project, format: :json end @@ -62,8 +62,8 @@ describe Projects::PipelinesController do end def get_stage(name) - get :stage, namespace_id: project.namespace.path, - project_id: project.path, + get :stage, namespace_id: project.namespace, + project_id: project, id: pipeline.id, stage: name, format: :json diff --git a/spec/controllers/projects/protected_branches_controller_spec.rb b/spec/controllers/projects/protected_branches_controller_spec.rb index da6112a13f7..e378b5714fe 100644 --- a/spec/controllers/projects/protected_branches_controller_spec.rb +++ b/spec/controllers/projects/protected_branches_controller_spec.rb @@ -4,7 +4,7 @@ describe Projects::ProtectedBranchesController do describe "GET #index" do let(:project) { create(:project_empty_repo, :public) } it "redirects empty repo to projects page" do - get(:index, namespace_id: project.namespace.to_param, project_id: project.to_param) + get(:index, namespace_id: project.namespace.to_param, project_id: project) end end end diff --git a/spec/controllers/projects/raw_controller_spec.rb b/spec/controllers/projects/raw_controller_spec.rb index b23d6e257ba..4cebe3884bf 100644 --- a/spec/controllers/projects/raw_controller_spec.rb +++ b/spec/controllers/projects/raw_controller_spec.rb @@ -10,7 +10,7 @@ describe Projects::RawController do it 'delivers ASCII file' do get(:show, namespace_id: public_project.namespace.to_param, - project_id: public_project.to_param, + project_id: public_project, id: id) expect(response).to have_http_status(200) @@ -27,7 +27,7 @@ describe Projects::RawController do it 'sets image content type header' do get(:show, namespace_id: public_project.namespace.to_param, - project_id: public_project.to_param, + project_id: public_project, id: id) expect(response).to have_http_status(200) @@ -51,7 +51,7 @@ describe Projects::RawController do expect(controller).to receive(:send_file).with("#{Gitlab.config.shared.path}/lfs-objects/91/ef/f75a492a3ed0dfcb544d7f31326bc4014c8551849c192fd1e48d4dd2c897", filename: "lfs_object.iso", disposition: 'attachment') get(:show, namespace_id: public_project.namespace.to_param, - project_id: public_project.to_param, + project_id: public_project, id: id) expect(response).to have_http_status(200) @@ -62,7 +62,7 @@ describe Projects::RawController do it 'does not serve the file' do get(:show, namespace_id: public_project.namespace.to_param, - project_id: public_project.to_param, + project_id: public_project, id: id) expect(response).to have_http_status(404) diff --git a/spec/controllers/projects/refs_controller_spec.rb b/spec/controllers/projects/refs_controller_spec.rb index d8fb4667c67..3a3e7467ef2 100644 --- a/spec/controllers/projects/refs_controller_spec.rb +++ b/spec/controllers/projects/refs_controller_spec.rb @@ -13,7 +13,7 @@ describe Projects::RefsController do def default_get(format = :html) get :logs_tree, namespace_id: project.namespace.to_param, - project_id: project.to_param, + project_id: project, id: 'master', path: 'foo/bar/baz.html', format: format @@ -23,7 +23,7 @@ describe Projects::RefsController do xhr :get, :logs_tree, namespace_id: project.namespace.to_param, - project_id: project.to_param, id: 'master', + project_id: project, id: 'master', path: 'foo/bar/baz.html', format: format end diff --git a/spec/controllers/projects/releases_controller_spec.rb b/spec/controllers/projects/releases_controller_spec.rb index 69fcc26c77e..358f26dfb02 100644 --- a/spec/controllers/projects/releases_controller_spec.rb +++ b/spec/controllers/projects/releases_controller_spec.rb @@ -16,7 +16,7 @@ describe Projects::ReleasesController do tag_id = release.tag project.releases.destroy_all - get :edit, namespace_id: project.namespace.path, project_id: project.path, tag_id: tag_id + get :edit, namespace_id: project.namespace, project_id: project, tag_id: tag_id release = assigns(:release) expect(release).not_to be_nil @@ -24,7 +24,7 @@ describe Projects::ReleasesController do end it 'retrieves an existing release' do - get :edit, namespace_id: project.namespace.path, project_id: project.path, tag_id: release.tag + get :edit, namespace_id: project.namespace, project_id: project, tag_id: release.tag release = assigns(:release) expect(release).not_to be_nil @@ -48,7 +48,7 @@ describe Projects::ReleasesController do def update_release(description) put :update, namespace_id: project.namespace.to_param, - project_id: project.to_param, + project_id: project, tag_id: release.tag, release: { description: description } end diff --git a/spec/controllers/projects/repositories_controller_spec.rb b/spec/controllers/projects/repositories_controller_spec.rb index 04e88879fb8..9c55d159fa0 100644 --- a/spec/controllers/projects/repositories_controller_spec.rb +++ b/spec/controllers/projects/repositories_controller_spec.rb @@ -6,7 +6,7 @@ describe Projects::RepositoriesController do describe "GET archive" do context 'as a guest' do it 'responds with redirect in correct format' do - get :archive, namespace_id: project.namespace.path, project_id: project.path, format: "zip" + get :archive, namespace_id: project.namespace, project_id: project, format: "zip" expect(response.header["Content-Type"]).to start_with('text/html') expect(response).to be_redirect @@ -22,7 +22,7 @@ describe Projects::RepositoriesController do end it "uses Gitlab::Workhorse" do - get :archive, namespace_id: project.namespace.path, project_id: project.path, ref: "master", format: "zip" + get :archive, namespace_id: project.namespace, project_id: project, ref: "master", format: "zip" expect(response.header[Gitlab::Workhorse::SEND_DATA_HEADER]).to start_with("git-archive:") end @@ -33,7 +33,7 @@ describe Projects::RepositoriesController do end it "renders Not Found" do - get :archive, namespace_id: project.namespace.path, project_id: project.path, ref: "master", format: "zip" + get :archive, namespace_id: project.namespace, project_id: project, ref: "master", format: "zip" expect(response).to have_http_status(404) end diff --git a/spec/controllers/projects/snippets_controller_spec.rb b/spec/controllers/projects/snippets_controller_spec.rb index 8bab094a79e..24a59caff4e 100644 --- a/spec/controllers/projects/snippets_controller_spec.rb +++ b/spec/controllers/projects/snippets_controller_spec.rb @@ -17,16 +17,16 @@ describe Projects::SnippetsController do it 'redirects to last_page if page number is larger than number of pages' do get :index, - namespace_id: project.namespace.path, - project_id: project.path, page: (last_page + 1).to_param + namespace_id: project.namespace, + project_id: project, page: (last_page + 1).to_param expect(response).to redirect_to(namespace_project_snippets_path(page: last_page)) end it 'redirects to specified page' do get :index, - namespace_id: project.namespace.path, - project_id: project.path, page: last_page.to_param + namespace_id: project.namespace, + project_id: project, page: last_page.to_param expect(assigns(:snippets).current_page).to eq(last_page) expect(response).to have_http_status(200) @@ -38,7 +38,7 @@ describe Projects::SnippetsController do context 'when anonymous' do it 'does not include the private snippet' do - get :index, namespace_id: project.namespace.path, project_id: project.path + get :index, namespace_id: project.namespace, project_id: project expect(assigns(:snippets)).not_to include(project_snippet) expect(response).to have_http_status(200) @@ -49,7 +49,7 @@ describe Projects::SnippetsController do before { sign_in(user) } it 'renders the snippet' do - get :index, namespace_id: project.namespace.path, project_id: project.path + get :index, namespace_id: project.namespace, project_id: project expect(assigns(:snippets)).to include(project_snippet) expect(response).to have_http_status(200) @@ -60,7 +60,7 @@ describe Projects::SnippetsController do before { sign_in(user2) } it 'renders the snippet' do - get :index, namespace_id: project.namespace.path, project_id: project.path + get :index, namespace_id: project.namespace, project_id: project expect(assigns(:snippets)).to include(project_snippet) expect(response).to have_http_status(200) @@ -77,7 +77,7 @@ describe Projects::SnippetsController do post :create, { namespace_id: project.namespace.to_param, - project_id: project.to_param, + project_id: project, project_snippet: { title: 'Title', content: 'Content' }.merge(snippet_params) }.merge(additional_params) end @@ -152,7 +152,7 @@ describe Projects::SnippetsController do put :update, { namespace_id: project.namespace.to_param, - project_id: project.to_param, + project_id: project, id: snippet.id, project_snippet: { title: 'Title', content: 'Content' }.merge(snippet_params) }.merge(additional_params) @@ -281,8 +281,8 @@ describe Projects::SnippetsController do sign_in(admin) post :mark_as_spam, - namespace_id: project.namespace.path, - project_id: project.path, + namespace_id: project.namespace, + project_id: project, id: snippet.id end @@ -300,7 +300,7 @@ describe Projects::SnippetsController do context 'when anonymous' do it 'responds with status 404' do - get action, namespace_id: project.namespace.path, project_id: project.path, id: project_snippet.to_param + get action, namespace_id: project.namespace, project_id: project, id: project_snippet.to_param expect(response).to have_http_status(404) end @@ -310,7 +310,7 @@ describe Projects::SnippetsController do before { sign_in(user) } it 'renders the snippet' do - get action, namespace_id: project.namespace.path, project_id: project.path, id: project_snippet.to_param + get action, namespace_id: project.namespace, project_id: project, id: project_snippet.to_param expect(assigns(:snippet)).to eq(project_snippet) expect(response).to have_http_status(200) @@ -321,7 +321,7 @@ describe Projects::SnippetsController do before { sign_in(user2) } it 'renders the snippet' do - get action, namespace_id: project.namespace.path, project_id: project.path, id: project_snippet.to_param + get action, namespace_id: project.namespace, project_id: project, id: project_snippet.to_param expect(assigns(:snippet)).to eq(project_snippet) expect(response).to have_http_status(200) @@ -332,7 +332,7 @@ describe Projects::SnippetsController do context 'when the project snippet does not exist' do context 'when anonymous' do it 'responds with status 404' do - get action, namespace_id: project.namespace.path, project_id: project.path, id: 42 + get action, namespace_id: project.namespace, project_id: project, id: 42 expect(response).to have_http_status(404) end @@ -342,7 +342,7 @@ describe Projects::SnippetsController do before { sign_in(user) } it 'responds with status 404' do - get action, namespace_id: project.namespace.path, project_id: project.path, id: 42 + get action, namespace_id: project.namespace, project_id: project, id: 42 expect(response).to have_http_status(404) end @@ -364,8 +364,8 @@ describe Projects::SnippetsController do context 'CRLF line ending' do let(:params) do { - namespace_id: project.namespace.path, - project_id: project.path, + namespace_id: project.namespace, + project_id: project, id: project_snippet.to_param } end diff --git a/spec/controllers/projects/tags_controller_spec.rb b/spec/controllers/projects/tags_controller_spec.rb index c36a5fdd66c..fc97bac64cd 100644 --- a/spec/controllers/projects/tags_controller_spec.rb +++ b/spec/controllers/projects/tags_controller_spec.rb @@ -6,7 +6,7 @@ describe Projects::TagsController do let!(:invalid_release) { create(:release, project: project, tag: 'does-not-exist') } describe 'GET index' do - before { get :index, namespace_id: project.namespace.to_param, project_id: project.to_param } + before { get :index, namespace_id: project.namespace.to_param, project_id: project } it 'returns the tags for the page' do expect(assigns(:tags).map(&:name)).to eq(['v1.1.0', 'v1.0.0']) @@ -19,7 +19,7 @@ describe Projects::TagsController do end describe 'GET show' do - before { get :show, namespace_id: project.namespace.to_param, project_id: project.to_param, id: id } + before { get :show, namespace_id: project.namespace.to_param, project_id: project, id: id } context "valid tag" do let(:id) { 'v1.0.0' } diff --git a/spec/controllers/projects/templates_controller_spec.rb b/spec/controllers/projects/templates_controller_spec.rb index 80f84a388ce..70e7f9ca96e 100644 --- a/spec/controllers/projects/templates_controller_spec.rb +++ b/spec/controllers/projects/templates_controller_spec.rb @@ -14,13 +14,13 @@ describe Projects::TemplatesController do before do project.add_user(user, Gitlab::Access::MASTER) - project.repository.commit_file(user, file_path_1, 'something valid', - message: 'test 3', branch_name: 'master', update: false) + project.repository.create_file(user, file_path_1, 'something valid', + message: 'test 3', branch_name: 'master') end describe '#show' do it 'renders template name and content as json' do - get(:show, namespace_id: project.namespace.to_param, template_type: "issue", key: "bug", project_id: project.path, format: :json) + get(:show, namespace_id: project.namespace.to_param, template_type: "issue", key: "bug", project_id: project, format: :json) expect(response.status).to eq(200) expect(body["name"]).to eq("bug") @@ -29,21 +29,21 @@ describe Projects::TemplatesController do it 'renders 404 when unauthorized' do sign_in(user2) - get(:show, namespace_id: project.namespace.to_param, template_type: "issue", key: "bug", project_id: project.path, format: :json) + get(:show, namespace_id: project.namespace.to_param, template_type: "issue", key: "bug", project_id: project, format: :json) expect(response.status).to eq(404) end it 'renders 404 when template type is not found' do sign_in(user) - get(:show, namespace_id: project.namespace.to_param, template_type: "dont_exist", key: "bug", project_id: project.path, format: :json) + get(:show, namespace_id: project.namespace.to_param, template_type: "dont_exist", key: "bug", project_id: project, format: :json) expect(response.status).to eq(404) end it 'renders 404 without errors' do sign_in(user) - expect { get(:show, namespace_id: project.namespace.to_param, template_type: "dont_exist", key: "bug", project_id: project.path, format: :json) }.not_to raise_error + expect { get(:show, namespace_id: project.namespace.to_param, template_type: "dont_exist", key: "bug", project_id: project, format: :json) }.not_to raise_error end end end diff --git a/spec/controllers/projects/todo_controller_spec.rb b/spec/controllers/projects/todo_controller_spec.rb index 415c264e0dd..9a7beeff6fe 100644 --- a/spec/controllers/projects/todo_controller_spec.rb +++ b/spec/controllers/projects/todo_controller_spec.rb @@ -12,8 +12,8 @@ describe Projects::TodosController do describe 'POST create' do def go post :create, - namespace_id: project.namespace.path, - project_id: project.path, + namespace_id: project.namespace, + project_id: project, issuable_id: issue.id, issuable_type: 'issue', format: 'html' @@ -80,8 +80,8 @@ describe Projects::TodosController do describe 'POST create' do def go post :create, - namespace_id: project.namespace.path, - project_id: project.path, + namespace_id: project.namespace, + project_id: project, issuable_id: merge_request.id, issuable_type: 'merge_request', format: 'html' diff --git a/spec/controllers/projects/tree_controller_spec.rb b/spec/controllers/projects/tree_controller_spec.rb index b81645a3d2d..ab94e292e48 100644 --- a/spec/controllers/projects/tree_controller_spec.rb +++ b/spec/controllers/projects/tree_controller_spec.rb @@ -18,7 +18,7 @@ describe Projects::TreeController do before do get(:show, namespace_id: project.namespace.to_param, - project_id: project.to_param, + project_id: project, id: id) end @@ -74,7 +74,7 @@ describe Projects::TreeController do before do get(:show, namespace_id: project.namespace.to_param, - project_id: project.to_param, + project_id: project, id: id) end @@ -94,7 +94,7 @@ describe Projects::TreeController do before do post(:create_dir, namespace_id: project.namespace.to_param, - project_id: project.to_param, + project_id: project, id: 'master', dir_name: path, target_branch: target_branch, diff --git a/spec/controllers/projects/uploads_controller_spec.rb b/spec/controllers/projects/uploads_controller_spec.rb index 0347e789576..699c6f77cec 100644 --- a/spec/controllers/projects/uploads_controller_spec.rb +++ b/spec/controllers/projects/uploads_controller_spec.rb @@ -16,7 +16,7 @@ describe Projects::UploadsController do it "returns an error" do post :create, namespace_id: project.namespace.to_param, - project_id: project.to_param, + project_id: project, format: :json expect(response).to have_http_status(422) end @@ -26,7 +26,7 @@ describe Projects::UploadsController do before do post :create, namespace_id: project.namespace.to_param, - project_id: project.to_param, + project_id: project, file: jpg, format: :json end @@ -41,7 +41,7 @@ describe Projects::UploadsController do before do post :create, namespace_id: project.namespace.to_param, - project_id: project.to_param, + project_id: project, file: txt, format: :json end @@ -57,7 +57,7 @@ describe Projects::UploadsController do let(:go) do get :show, namespace_id: project.namespace.to_param, - project_id: project.to_param, + project_id: project, secret: "123456", filename: "image.jpg" end diff --git a/spec/controllers/projects/variables_controller_spec.rb b/spec/controllers/projects/variables_controller_spec.rb index 9fa358f7d62..e3f3b4fe8eb 100644 --- a/spec/controllers/projects/variables_controller_spec.rb +++ b/spec/controllers/projects/variables_controller_spec.rb @@ -12,7 +12,7 @@ describe Projects::VariablesController do describe 'POST #create' do context 'variable is valid' do it 'shows a success flash message' do - post :create, namespace_id: project.namespace.to_param, project_id: project.to_param, + post :create, namespace_id: project.namespace.to_param, project_id: project, variable: { key: "one", value: "two" } expect(flash[:notice]).to include 'Variables were successfully updated.' @@ -22,7 +22,7 @@ describe Projects::VariablesController do context 'variable is invalid' do it 'shows an alert flash message' do - post :create, namespace_id: project.namespace.to_param, project_id: project.to_param, + post :create, namespace_id: project.namespace.to_param, project_id: project, variable: { key: "..one", value: "two" } expect(response).to render_template("projects/variables/show") @@ -40,7 +40,7 @@ describe Projects::VariablesController do end it 'shows a success flash message' do - post :update, namespace_id: project.namespace.to_param, project_id: project.to_param, + post :update, namespace_id: project.namespace.to_param, project_id: project, id: variable.id, variable: { key: variable.key, value: 'two' } expect(flash[:notice]).to include 'Variable was successfully updated.' @@ -48,7 +48,7 @@ describe Projects::VariablesController do end it 'renders the action #show if the variable key is invalid' do - post :update, namespace_id: project.namespace.to_param, project_id: project.to_param, + post :update, namespace_id: project.namespace.to_param, project_id: project, id: variable.id, variable: { key: '?', value: variable.value } expect(response).to have_http_status(200) diff --git a/spec/controllers/projects_controller_spec.rb b/spec/controllers/projects_controller_spec.rb index e7aa8745b99..202759664a0 100644 --- a/spec/controllers/projects_controller_spec.rb +++ b/spec/controllers/projects_controller_spec.rb @@ -35,7 +35,7 @@ describe ProjectsController do let(:private_project) { create(:empty_project, :private) } it "does not initialize notification setting" do - get :show, namespace_id: private_project.namespace.path, id: private_project.path + get :show, namespace_id: private_project.namespace, id: private_project expect(assigns(:notification_setting)).to be_nil end end @@ -43,7 +43,7 @@ describe ProjectsController do context "user has access to project" do context "and does not have notification setting" do it "initializes notification as disabled" do - get :show, namespace_id: public_project.namespace.path, id: public_project.path + get :show, namespace_id: public_project.namespace, id: public_project expect(assigns(:notification_setting).level).to eq("global") end end @@ -56,7 +56,7 @@ describe ProjectsController do end it "shows current notification setting" do - get :show, namespace_id: public_project.namespace.path, id: public_project.path + get :show, namespace_id: public_project.namespace, id: public_project expect(assigns(:notification_setting).level).to eq("watch") end end @@ -71,7 +71,7 @@ describe ProjectsController do end it 'shows wiki homepage' do - get :show, namespace_id: project.namespace.path, id: project.path + get :show, namespace_id: project.namespace, id: project expect(response).to render_template('projects/_wiki') end @@ -79,7 +79,7 @@ describe ProjectsController do it 'shows issues list page if wiki is disabled' do project.project_feature.update_attribute(:wiki_access_level, ProjectFeature::DISABLED) - get :show, namespace_id: project.namespace.path, id: project.path + get :show, namespace_id: project.namespace, id: project expect(response).to render_template('projects/issues/_issues') end @@ -88,7 +88,7 @@ describe ProjectsController do project.project_feature.update_attribute(:wiki_access_level, ProjectFeature::DISABLED) project.project_feature.update_attribute(:issues_access_level, ProjectFeature::DISABLED) - get :show, namespace_id: project.namespace.path, id: project.path + get :show, namespace_id: project.namespace, id: project expect(response).to render_template("projects/_customize_workflow") end @@ -96,7 +96,7 @@ describe ProjectsController do it 'shows activity if enabled by user' do user.update_attribute(:project_view, 'activity') - get :show, namespace_id: project.namespace.path, id: project.path + get :show, namespace_id: project.namespace, id: project expect(response).to render_template("projects/_activity") end @@ -113,7 +113,7 @@ describe ProjectsController do before do user.update_attributes(project_view: project_view) - get :show, namespace_id: empty_project.namespace.path, id: empty_project.path + get :show, namespace_id: empty_project.namespace, id: empty_project end it "renders the empty project view" do @@ -133,7 +133,7 @@ describe ProjectsController do before do user.update_attributes(project_view: project_view) - get :show, namespace_id: empty_project.namespace.path, id: empty_project.path + get :show, namespace_id: empty_project.namespace, id: empty_project end it "renders the empty project view" do @@ -154,7 +154,7 @@ describe ProjectsController do allow(controller).to receive(:current_user).and_return(user) allow(user).to receive(:project_view).and_return('activity') - get :show, namespace_id: public_project.namespace.path, id: public_project.path + get :show, namespace_id: public_project.namespace, id: public_project expect(response).to render_template('_activity') end @@ -162,7 +162,7 @@ describe ProjectsController do allow(controller).to receive(:current_user).and_return(user) allow(user).to receive(:project_view).and_return('readme') - get :show, namespace_id: public_project.namespace.path, id: public_project.path + get :show, namespace_id: public_project.namespace, id: public_project expect(response).to render_template('_readme') end @@ -170,7 +170,7 @@ describe ProjectsController do allow(controller).to receive(:current_user).and_return(user) allow(user).to receive(:project_view).and_return('files') - get :show, namespace_id: public_project.namespace.path, id: public_project.path + get :show, namespace_id: public_project.namespace, id: public_project expect(response).to render_template('_files') end end @@ -178,7 +178,7 @@ describe ProjectsController do context "when requested with case sensitive namespace and project path" do context "when there is a match with the same casing" do it "loads the project" do - get :show, namespace_id: public_project.namespace.path, id: public_project.path + get :show, namespace_id: public_project.namespace, id: public_project expect(assigns(:project)).to eq(public_project) expect(response).to have_http_status(200) @@ -187,10 +187,10 @@ describe ProjectsController do context "when there is a match with different casing" do it "redirects to the normalized path" do - get :show, namespace_id: public_project.namespace.path, id: public_project.path.upcase + get :show, namespace_id: public_project.namespace, id: public_project.path.upcase expect(assigns(:project)).to eq(public_project) - expect(response).to redirect_to("/#{public_project.path_with_namespace}") + expect(response).to redirect_to("/#{public_project.full_path}") end end end @@ -208,7 +208,7 @@ describe ProjectsController do project = create(:empty_project, pending_delete: true) sign_in(user) - get :show, namespace_id: project.namespace.path, id: project.path + get :show, namespace_id: project.namespace, id: project expect(response.status).to eq 404 end @@ -218,7 +218,7 @@ describe ProjectsController do it 'redirects to project page (format.html)' do project = create(:project, :public) - get :show, namespace_id: project.namespace.path, id: project.path, format: :git + get :show, namespace_id: project.namespace, id: project, format: :git expect(response).to have_http_status(302) expect(response).to redirect_to(namespace_project_path) @@ -239,7 +239,7 @@ describe ProjectsController do sign_in(admin) put :update, - namespace_id: project.namespace.to_param, + namespace_id: project.namespace, id: project.id, project: project_params @@ -257,7 +257,7 @@ describe ProjectsController do sign_in(admin) orig_id = project.id - delete :destroy, namespace_id: project.namespace.path, id: project.path + delete :destroy, namespace_id: project.namespace, id: project expect { Project.find(orig_id) }.to raise_error(ActiveRecord::RecordNotFound) expect(response).to have_http_status(302) @@ -277,7 +277,7 @@ describe ProjectsController do project.merge_requests << merge_request sign_in(admin) - delete :destroy, namespace_id: fork_project.namespace.path, id: fork_project.path + delete :destroy, namespace_id: fork_project.namespace, id: fork_project expect(merge_request.reload.state).to eq('closed') end @@ -287,8 +287,8 @@ describe ProjectsController do describe 'PUT #new_issue_address' do subject do put :new_issue_address, - namespace_id: project.namespace.to_param, - id: project.to_param + namespace_id: project.namespace, + id: project user.reload end @@ -316,23 +316,23 @@ describe ProjectsController do sign_in(user) expect(user.starred?(public_project)).to be_falsey post(:toggle_star, - namespace_id: public_project.namespace.to_param, - id: public_project.to_param) + namespace_id: public_project.namespace, + id: public_project) expect(user.starred?(public_project)).to be_truthy post(:toggle_star, - namespace_id: public_project.namespace.to_param, - id: public_project.to_param) + namespace_id: public_project.namespace, + id: public_project) expect(user.starred?(public_project)).to be_falsey end it "does nothing if user is not signed in" do post(:toggle_star, - namespace_id: project.namespace.to_param, - id: public_project.to_param) + namespace_id: project.namespace, + id: public_project) expect(user.starred?(public_project)).to be_falsey post(:toggle_star, - namespace_id: project.namespace.to_param, - id: public_project.to_param) + namespace_id: project.namespace, + id: public_project) expect(user.starred?(public_project)).to be_falsey end end @@ -366,8 +366,8 @@ describe ProjectsController do it 'does nothing if project was not forked' do delete(:remove_fork, - namespace_id: unforked_project.namespace.to_param, - id: unforked_project.to_param, format: :js) + namespace_id: unforked_project.namespace, + id: unforked_project, format: :js) expect(flash[:notice]).to be_nil expect(response).to render_template(:remove_fork) @@ -377,8 +377,8 @@ describe ProjectsController do it "does nothing if user is not signed in" do delete(:remove_fork, - namespace_id: project.namespace.to_param, - id: project.to_param, format: :js) + namespace_id: project.namespace, + id: project, format: :js) expect(response).to have_http_status(401) end end @@ -387,7 +387,7 @@ describe ProjectsController do let(:public_project) { create(:project, :public) } it "gets a list of branches and tags" do - get :refs, namespace_id: public_project.namespace.path, id: public_project.path + get :refs, namespace_id: public_project.namespace, id: public_project parsed_body = JSON.parse(response.body) expect(parsed_body["Branches"]).to include("master") @@ -396,7 +396,7 @@ describe ProjectsController do end it "gets a list of branches, tags and commits" do - get :refs, namespace_id: public_project.namespace.path, id: public_project.path, ref: "123456" + get :refs, namespace_id: public_project.namespace, id: public_project, ref: "123456" parsed_body = JSON.parse(response.body) expect(parsed_body["Branches"]).to include("master") diff --git a/spec/controllers/root_controller_spec.rb b/spec/controllers/root_controller_spec.rb index b14d275f7fa..b32eb39b1fb 100644 --- a/spec/controllers/root_controller_spec.rb +++ b/spec/controllers/root_controller_spec.rb @@ -2,6 +2,26 @@ require 'spec_helper' describe RootController do describe 'GET index' do + context 'when user is not logged in' do + it 'redirects to the sign-in page' do + get :index + + expect(response).to redirect_to(new_user_session_path) + end + + context 'when a custom home page URL is defined' do + before do + stub_application_setting(home_page_url: 'https://gitlab.com') + end + + it 'redirects the user to the custom home page URL' do + get :index + + expect(response).to redirect_to('https://gitlab.com') + end + end + end + context 'with a user' do let(:user) { create(:user) } @@ -12,55 +32,60 @@ describe RootController do context 'who has customized their dashboard setting for starred projects' do before do - user.update_attribute(:dashboard, 'stars') + user.dashboard = 'stars' end it 'redirects to their specified dashboard' do get :index + expect(response).to redirect_to starred_dashboard_projects_path end end context 'who has customized their dashboard setting for project activities' do before do - user.update_attribute(:dashboard, 'project_activity') + user.dashboard = 'project_activity' end it 'redirects to the activity list' do get :index + expect(response).to redirect_to activity_dashboard_path end end context 'who has customized their dashboard setting for starred project activities' do before do - user.update_attribute(:dashboard, 'starred_project_activity') + user.dashboard = 'starred_project_activity' end it 'redirects to the activity list' do get :index + expect(response).to redirect_to activity_dashboard_path(filter: 'starred') end end context 'who has customized their dashboard setting for groups' do before do - user.update_attribute(:dashboard, 'groups') + user.dashboard = 'groups' end it 'redirects to their group list' do get :index + expect(response).to redirect_to dashboard_groups_path end end context 'who has customized their dashboard setting for todos' do before do - user.update_attribute(:dashboard, 'todos') + user.dashboard = 'todos' end it 'redirects to their todo list' do get :index + expect(response).to redirect_to dashboard_todos_path end end @@ -68,6 +93,7 @@ describe RootController do context 'who uses the default dashboard setting' do it 'renders the default dashboard' do get :index + expect(response).to render_template 'dashboard/projects/index' end end diff --git a/spec/factories/merge_requests.rb b/spec/factories/merge_requests.rb index 22f84150bb3..ae0bbbd6aeb 100644 --- a/spec/factories/merge_requests.rb +++ b/spec/factories/merge_requests.rb @@ -59,8 +59,8 @@ FactoryGirl.define do target_branch "master" end - trait :merge_when_build_succeeds do - merge_when_build_succeeds true + trait :merge_when_pipeline_succeeds do + merge_when_pipeline_succeeds true merge_user author end diff --git a/spec/factories/projects.rb b/spec/factories/projects.rb index c80b09e9b9d..586efdefdb3 100644 --- a/spec/factories/projects.rb +++ b/spec/factories/projects.rb @@ -138,27 +138,24 @@ FactoryGirl.define do project.add_user(args[:user], args[:access]) - project.repository.commit_file( + project.repository.create_file( args[:user], ".gitlab/#{args[:path]}/bug.md", 'something valid', message: 'test 3', - branch_name: 'master', - update: false) - project.repository.commit_file( + branch_name: 'master') + project.repository.create_file( args[:user], ".gitlab/#{args[:path]}/template_test.md", 'template_test', message: 'test 1', - branch_name: 'master', - update: false) - project.repository.commit_file( + branch_name: 'master') + project.repository.create_file( args[:user], ".gitlab/#{args[:path]}/feature_proposal.md", 'feature_proposal', message: 'test 2', - branch_name: 'master', - update: false) + branch_name: 'master') end end end diff --git a/spec/factories/todos.rb b/spec/factories/todos.rb index a5265f1b189..c1ac3bb84ad 100644 --- a/spec/factories/todos.rb +++ b/spec/factories/todos.rb @@ -18,11 +18,6 @@ FactoryGirl.define do action { Todo::DIRECTLY_ADDRESSED } end - trait :on_commit do - commit_id RepoHelpers.sample_commit.id - target_type "Commit" - end - trait :build_failed do action { Todo::BUILD_FAILED } target factory: :merge_request @@ -48,4 +43,13 @@ FactoryGirl.define do state :done end end + + factory :on_commit_todo, class: Todo do + project factory: :empty_project + author + user + action { Todo::ASSIGNED } + commit_id RepoHelpers.sample_commit.id + target_type "Commit" + end end diff --git a/spec/factories/users.rb b/spec/factories/users.rb index 1732b1a0081..249dabbaae8 100644 --- a/spec/factories/users.rb +++ b/spec/factories/users.rb @@ -26,6 +26,11 @@ FactoryGirl.define do two_factor_via_otp end + trait :ghost do + ghost true + after(:build) { |user, _| user.block! } + end + trait :two_factor_via_otp do before(:create) do |user| user.otp_required_for_login = true diff --git a/spec/features/admin/admin_disables_git_access_protocol_spec.rb b/spec/features/admin/admin_disables_git_access_protocol_spec.rb index e8e080ce3e2..273cacd82cd 100644 --- a/spec/features/admin/admin_disables_git_access_protocol_spec.rb +++ b/spec/features/admin/admin_disables_git_access_protocol_spec.rb @@ -32,7 +32,7 @@ feature 'Admin disables Git access protocol', feature: true do scenario 'shows only HTTP url' do visit_project - expect(page).to have_content("git clone #{project.http_url_to_repo}") + expect(page).to have_content("git clone #{project.http_url_to_repo(admin)}") expect(page).not_to have_selector('#clone-dropdown') end end diff --git a/spec/features/atom/users_spec.rb b/spec/features/atom/users_spec.rb index f8c3ccb416b..b740e191f48 100644 --- a/spec/features/atom/users_spec.rb +++ b/spec/features/atom/users_spec.rb @@ -61,7 +61,7 @@ describe "User Feed", feature: true do end it 'has XHTML summaries in merge request descriptions' do - expect(body).to match /Here is the fix: <\/p><div[^>]*><a[^>]*><img[^>]*\/><\/a><\/div>/ + expect(body).to match /Here is the fix: <a[^>]*><img[^>]*\/><\/a>/ end end end diff --git a/spec/features/dashboard/project_member_activity_index_spec.rb b/spec/features/dashboard/project_member_activity_index_spec.rb index ba77093a6d4..49d93db58a9 100644 --- a/spec/features/dashboard/project_member_activity_index_spec.rb +++ b/spec/features/dashboard/project_member_activity_index_spec.rb @@ -12,7 +12,7 @@ feature 'Project member activity', feature: true, js: true do def visit_activities_and_wait_with_event(event_type) Event.create(project: project, author_id: user.id, action: event_type) - visit activity_namespace_project_path(project.namespace.path, project.path) + visit activity_namespace_project_path(project.namespace, project) wait_for_ajax end diff --git a/spec/features/issues/award_emoji_spec.rb b/spec/features/issues/award_emoji_spec.rb index 73e43316dc7..3ab3d2d4229 100644 --- a/spec/features/issues/award_emoji_spec.rb +++ b/spec/features/issues/award_emoji_spec.rb @@ -67,6 +67,18 @@ describe 'Awards Emoji', feature: true do expect(page).not_to have_selector(emoji_counter) end end + + context 'execute /award slash command' do + it 'toggles the emoji award on noteable', js: true do + execute_slash_command('/award :100:') + + expect(find(noteable_award_counter)).to have_text("1") + + execute_slash_command('/award :100:') + + expect(page).not_to have_selector(noteable_award_counter) + end + end end end @@ -80,6 +92,15 @@ describe 'Awards Emoji', feature: true do end end + def execute_slash_command(cmd) + within('.js-main-target-form') do + fill_in 'note[note]', with: cmd + click_button 'Comment' + end + + wait_for_ajax + end + def thumbsup_emoji page.all(emoji_counter).first end @@ -92,6 +113,10 @@ describe 'Awards Emoji', feature: true do 'span.js-counter' end + def noteable_award_counter + ".awards .active" + end + def toggle_smiley_emoji(status) within('.note') do find('.note-emoji-button').click diff --git a/spec/features/issues_spec.rb b/spec/features/issues_spec.rb index 1e0db4a0499..1c8267b1593 100644 --- a/spec/features/issues_spec.rb +++ b/spec/features/issues_spec.rb @@ -1,6 +1,7 @@ require 'spec_helper' describe 'Issues', feature: true do + include DropzoneHelper include IssueHelpers include SortingHelper include WaitForAjax @@ -570,19 +571,13 @@ describe 'Issues', feature: true do end it 'uploads file when dragging into textarea' do - drop_in_dropzone test_image_file - - # Wait for the file to upload - sleep 1 + dropzone_file Rails.root.join('spec', 'fixtures', 'banana_sample.gif') expect(page.find_field("issue_description").value).to have_content 'banana_sample' end it 'adds double newline to end of attachment markdown' do - drop_in_dropzone test_image_file - - # Wait for the file to upload - sleep 1 + dropzone_file Rails.root.join('spec', 'fixtures', 'banana_sample.gif') expect(page.find_field("issue_description").value).to match /\n\n$/ end @@ -665,25 +660,4 @@ describe 'Issues', feature: true do end end end - - def drop_in_dropzone(file_path) - # Generate a fake input selector - page.execute_script <<-JS - var fakeFileInput = window.$('<input/>').attr( - {id: 'fakeFileInput', type: 'file'} - ).appendTo('body'); - JS - # Attach the file to the fake input selector with Capybara - attach_file("fakeFileInput", file_path) - # Add the file to a fileList array and trigger the fake drop event - page.execute_script <<-JS - var fileList = [$('#fakeFileInput')[0].files[0]]; - var e = jQuery.Event('drop', { dataTransfer : { files : fileList } }); - $('.div-dropzone')[0].dropzone.listeners[0].events.drop(e); - JS - end - - def test_image_file - File.join(Rails.root, 'spec', 'fixtures', 'banana_sample.gif') - end end diff --git a/spec/features/merge_requests/merge_when_pipeline_succeeds_spec.rb b/spec/features/merge_requests/merge_when_pipeline_succeeds_spec.rb index 2ea9c317bd1..ed7193b9777 100644 --- a/spec/features/merge_requests/merge_when_pipeline_succeeds_spec.rb +++ b/spec/features/merge_requests/merge_when_pipeline_succeeds_spec.rb @@ -75,7 +75,7 @@ feature 'Merge When Pipeline Succeeds', :feature, :js do context 'when it was enabled and then canceled' do let(:merge_request) do create(:merge_request_with_diffs, - :merge_when_build_succeeds, + :merge_when_pipeline_succeeds, source_project: project, title: 'Bug NS-04', author: user, @@ -97,7 +97,7 @@ feature 'Merge When Pipeline Succeeds', :feature, :js do author: user, merge_user: user, title: 'MepMep', - merge_when_build_succeeds: true) + merge_when_pipeline_succeeds: true) end let!(:build) do diff --git a/spec/features/merge_requests/only_allow_merge_if_build_succeeds_spec.rb b/spec/features/merge_requests/only_allow_merge_if_build_succeeds_spec.rb index d2f5c4afc93..447764566e0 100644 --- a/spec/features/merge_requests/only_allow_merge_if_build_succeeds_spec.rb +++ b/spec/features/merge_requests/only_allow_merge_if_build_succeeds_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -feature 'Only allow merge requests to be merged if the build succeeds', feature: true do +feature 'Only allow merge requests to be merged if the pipeline succeeds', feature: true do let(:merge_request) { create(:merge_request_with_diffs) } let(:project) { merge_request.target_project } @@ -27,9 +27,9 @@ feature 'Only allow merge requests to be merged if the build succeeds', feature: status: status) end - context 'when merge requests can only be merged if the build succeeds' do + context 'when merge requests can only be merged if the pipeline succeeds' do before do - project.update_attribute(:only_allow_merge_if_build_succeeds, true) + project.update_attribute(:only_allow_merge_if_pipeline_succeeds, true) end context 'when CI is running' do @@ -88,7 +88,7 @@ feature 'Only allow merge requests to be merged if the build succeeds', feature: context 'when merge requests can be merged when the build failed' do before do - project.update_attribute(:only_allow_merge_if_build_succeeds, false) + project.update_attribute(:only_allow_merge_if_pipeline_succeeds, false) end context 'when CI is running' do diff --git a/spec/features/milestone_spec.rb b/spec/features/milestone_spec.rb index a2e40546588..c3297de709a 100644 --- a/spec/features/milestone_spec.rb +++ b/spec/features/milestone_spec.rb @@ -24,7 +24,7 @@ feature 'Milestone', feature: true do find('input[name="commit"]').click expect(find('.alert-success')).to have_content('Assign some issues to this milestone.') - expect(page).to have_content('Nov 16, 2016 - Dec 16, 2016') + expect(page).to have_content('Nov 16, 2016–Dec 16, 2016') end end diff --git a/spec/features/profile_spec.rb b/spec/features/profile_spec.rb index 7a562b5e03d..406d7cf791c 100644 --- a/spec/features/profile_spec.rb +++ b/spec/features/profile_spec.rb @@ -4,7 +4,7 @@ describe 'Profile account page', feature: true do let(:user) { create(:user) } before do - login_as :user + login_as(user) end describe 'when signup is enabled' do @@ -16,7 +16,7 @@ describe 'Profile account page', feature: true do it { expect(page).to have_content('Remove account') } it 'deletes the account' do - expect { click_link 'Delete account' }.to change { User.count }.by(-1) + expect { click_link 'Delete account' }.to change { User.where(id: user.id).count }.by(-1) expect(current_path).to eq(new_user_session_path) end end diff --git a/spec/features/profiles/keys_spec.rb b/spec/features/profiles/keys_spec.rb index eb1050d21c6..2f436f153aa 100644 --- a/spec/features/profiles/keys_spec.rb +++ b/spec/features/profiles/keys_spec.rb @@ -15,7 +15,7 @@ feature 'Profile > SSH Keys', feature: true do scenario 'auto-populates the title', js: true do fill_in('Key', with: attributes_for(:key).fetch(:key)) - expect(find_field('Title').value).to eq 'dummy@gitlab.com' + expect(page).to have_field("Title", with: "dummy@gitlab.com") end scenario 'saves the new key' do diff --git a/spec/features/projects/developer_views_empty_project_instructions_spec.rb b/spec/features/projects/developer_views_empty_project_instructions_spec.rb index 0c51fe72ca4..2352329d58c 100644 --- a/spec/features/projects/developer_views_empty_project_instructions_spec.rb +++ b/spec/features/projects/developer_views_empty_project_instructions_spec.rb @@ -56,8 +56,14 @@ feature 'Developer views empty project instructions', feature: true do end def expect_instructions_for(protocol) - msg = :"#{protocol.downcase}_url_to_repo" - - expect(page).to have_content("git clone #{project.send(msg)}") + url = + case protocol + when 'ssh' + project.ssh_url_to_repo + when 'http' + project.http_url_to_repo(developer) + end + + expect(page).to have_content("git clone #{url}") end end diff --git a/spec/features/projects/files/project_owner_creates_license_file_spec.rb b/spec/features/projects/files/project_owner_creates_license_file_spec.rb index f8ef4577a26..ccadc936567 100644 --- a/spec/features/projects/files/project_owner_creates_license_file_spec.rb +++ b/spec/features/projects/files/project_owner_creates_license_file_spec.rb @@ -6,7 +6,7 @@ feature 'project owner creates a license file', feature: true, js: true do let(:project_master) { create(:user) } let(:project) { create(:project) } background do - project.repository.remove_file(project_master, 'LICENSE', + project.repository.delete_file(project_master, 'LICENSE', message: 'Remove LICENSE', branch_name: 'master') project.team << [project_master, :master] login_as(project_master) diff --git a/spec/features/projects/issuable_templates_spec.rb b/spec/features/projects/issuable_templates_spec.rb index e90a033b8c4..62d0aedda48 100644 --- a/spec/features/projects/issuable_templates_spec.rb +++ b/spec/features/projects/issuable_templates_spec.rb @@ -18,20 +18,18 @@ feature 'issuable templates', feature: true, js: true do let(:description_addition) { ' appending to description' } background do - project.repository.commit_file( + project.repository.create_file( user, '.gitlab/issue_templates/bug.md', template_content, message: 'added issue template', - branch_name: 'master', - update: false) - project.repository.commit_file( + branch_name: 'master') + project.repository.create_file( user, '.gitlab/issue_templates/test.md', longtemplate_content, message: 'added issue template', - branch_name: 'master', - update: false) + branch_name: 'master') visit edit_namespace_project_issue_path project.namespace, project, issue fill_in :'issue[title]', with: 'test issue title' end @@ -79,13 +77,12 @@ feature 'issuable templates', feature: true, js: true do let(:issue) { create(:issue, author: user, assignee: user, project: project) } background do - project.repository.commit_file( + project.repository.create_file( user, '.gitlab/issue_templates/bug.md', template_content, message: 'added issue template', - branch_name: 'master', - update: false) + branch_name: 'master') visit edit_namespace_project_issue_path project.namespace, project, issue fill_in :'issue[title]', with: 'test issue title' fill_in :'issue[description]', with: prior_description @@ -104,13 +101,12 @@ feature 'issuable templates', feature: true, js: true do let(:merge_request) { create(:merge_request, :with_diffs, source_project: project) } background do - project.repository.commit_file( + project.repository.create_file( user, '.gitlab/merge_request_templates/feature-proposal.md', template_content, message: 'added merge request template', - branch_name: 'master', - update: false) + branch_name: 'master') visit edit_namespace_project_merge_request_path project.namespace, project, merge_request fill_in :'merge_request[title]', with: 'test merge request title' end @@ -135,13 +131,12 @@ feature 'issuable templates', feature: true, js: true do fork_project.team << [fork_user, :master] create(:forked_project_link, forked_to_project: fork_project, forked_from_project: project) login_as fork_user - project.repository.commit_file( + project.repository.create_file( fork_user, '.gitlab/merge_request_templates/feature-proposal.md', template_content, message: 'added merge request template', - branch_name: 'master', - update: false) + branch_name: 'master') visit edit_namespace_project_merge_request_path project.namespace, project, merge_request fill_in :'merge_request[title]', with: 'test merge request title' end diff --git a/spec/features/projects/members/sorting_spec.rb b/spec/features/projects/members/sorting_spec.rb index d6ebb523f95..c7a32a65e49 100644 --- a/spec/features/projects/members/sorting_spec.rb +++ b/spec/features/projects/members/sorting_spec.rb @@ -85,7 +85,7 @@ feature 'Projects > Members > Sorting', feature: true do end def visit_members_list(sort:) - visit namespace_project_project_members_path(project.namespace.to_param, project.to_param, sort: sort) + visit namespace_project_project_members_path(project.namespace.to_param, project, sort: sort) end def first_member diff --git a/spec/features/projects/pipelines/pipelines_spec.rb b/spec/features/projects/pipelines/pipelines_spec.rb index 592dc4483d2..22bf1bfbdf0 100644 --- a/spec/features/projects/pipelines/pipelines_spec.rb +++ b/spec/features/projects/pipelines/pipelines_spec.rb @@ -328,6 +328,18 @@ describe 'Pipelines', :feature, :js do expect(build.reload).to be_canceled end end + + context 'dropdown jobs list' do + it 'should keep the dropdown open when the user ctr/cmd + clicks in the job name' do + find('.js-builds-dropdown-button').trigger('click') + + execute_script('var e = $.Event("keydown", { keyCode: 64 }); $("body").trigger(e);') + + find('.mini-pipeline-graph-dropdown-item').trigger('click') + + expect(page).to have_selector('.js-ci-action-icon') + end + end end context 'with pagination' do @@ -359,8 +371,14 @@ describe 'Pipelines', :feature, :js do visit new_namespace_project_pipeline_path(project.namespace, project) end - context 'for valid commit' do - before { fill_in('pipeline[ref]', with: 'master') } + context 'for valid commit', js: true do + before do + click_button project.default_branch + + page.within '.dropdown-menu' do + click_link 'master' + end + end context 'with gitlab-ci.yml' do before { stub_ci_pipeline_to_return_yaml_file } @@ -377,15 +395,6 @@ describe 'Pipelines', :feature, :js do it { expect(page).to have_content('Missing .gitlab-ci.yml file') } end end - - context 'for invalid commit' do - before do - fill_in('pipeline[ref]', with: 'invalid-reference') - click_on 'Create pipeline' - end - - it { expect(page).to have_content('Reference not found') } - end end describe 'Create pipelines' do @@ -397,18 +406,22 @@ describe 'Pipelines', :feature, :js do describe 'new pipeline page' do it 'has field to add a new pipeline' do - expect(page).to have_field('pipeline[ref]') + expect(page).to have_selector('.js-branch-select') + expect(find('.js-branch-select')).to have_content project.default_branch expect(page).to have_content('Create for') end end describe 'find pipelines' do it 'shows filtered pipelines', js: true do - fill_in('pipeline[ref]', with: 'fix') - find('input#ref').native.send_keys(:keydown) + click_button project.default_branch - within('.ui-autocomplete') do - expect(page).to have_selector('li', text: 'fix') + page.within '.dropdown-menu' do + find('.dropdown-input-field').native.send_keys('fix') + + page.within '.dropdown-content' do + expect(page).to have_content('fix') + end end end end diff --git a/spec/features/uploads/user_uploads_avatar_to_group_spec.rb b/spec/features/uploads/user_uploads_avatar_to_group_spec.rb new file mode 100644 index 00000000000..f88a515f7fc --- /dev/null +++ b/spec/features/uploads/user_uploads_avatar_to_group_spec.rb @@ -0,0 +1,26 @@ +require 'rails_helper' + +feature 'User uploads avatar to group', feature: true do + scenario 'they see the new avatar' do + user = create(:user) + group = create(:group) + group.add_owner(user) + login_as(user) + + visit edit_group_path(group) + attach_file( + 'group_avatar', + Rails.root.join('spec', 'fixtures', 'dk.png'), + visible: false + ) + + click_button 'Save group' + + visit group_path(group) + + expect(page).to have_selector(%Q(img[src$="/uploads/group/avatar/#{group.id}/dk.png"])) + + # Cheating here to verify something that isn't user-facing, but is important + expect(group.reload.avatar.file).to exist + end +end diff --git a/spec/features/uploads/user_uploads_avatar_to_profile_spec.rb b/spec/features/uploads/user_uploads_avatar_to_profile_spec.rb new file mode 100644 index 00000000000..0dfd29045e5 --- /dev/null +++ b/spec/features/uploads/user_uploads_avatar_to_profile_spec.rb @@ -0,0 +1,24 @@ +require 'rails_helper' + +feature 'User uploads avatar to profile', feature: true do + scenario 'they see their new avatar' do + user = create(:user) + login_as(user) + + visit profile_path + attach_file( + 'user_avatar', + Rails.root.join('spec', 'fixtures', 'dk.png'), + visible: false + ) + + click_button 'Update profile settings' + + visit user_path(user) + + expect(page).to have_selector(%Q(img[src$="/uploads/user/avatar/#{user.id}/dk.png"])) + + # Cheating here to verify something that isn't user-facing, but is important + expect(user.reload.avatar.file).to exist + end +end diff --git a/spec/features/uploads/user_uploads_file_to_note_spec.rb b/spec/features/uploads/user_uploads_file_to_note_spec.rb new file mode 100644 index 00000000000..0c160dd74b4 --- /dev/null +++ b/spec/features/uploads/user_uploads_file_to_note_spec.rb @@ -0,0 +1,22 @@ +require 'rails_helper' + +feature 'User uploads file to note', feature: true do + include DropzoneHelper + + let(:user) { create(:user) } + let(:project) { create(:empty_project, creator: user, namespace: user.namespace) } + + scenario 'they see the attached file', js: true do + issue = create(:issue, project: project, author: user) + + login_as(user) + visit namespace_project_issue_path(project.namespace, project, issue) + + dropzone_file(Rails.root.join('spec', 'fixtures', 'dk.png')) + click_button 'Comment' + wait_for_ajax + + expect(find('a.no-attachment-icon img[alt="dk"]')['src']) + .to match(%r{/#{project.full_path}/uploads/\h{32}/dk\.png$}) + end +end diff --git a/spec/features/user_callout_spec.rb b/spec/features/user_callout_spec.rb new file mode 100644 index 00000000000..336c4092c98 --- /dev/null +++ b/spec/features/user_callout_spec.rb @@ -0,0 +1,37 @@ +require 'spec_helper' + +describe 'User Callouts', js: true do + let(:user) { create(:user) } + let(:project) { create(:empty_project, path: 'gitlab', name: 'sample') } + + before do + login_as(user) + project.team << [user, :master] + end + + it 'takes you to the profile preferences when the link is clicked' do + visit dashboard_projects_path + click_link 'Check it out' + expect(current_path).to eq profile_preferences_path + end + + describe 'user callout should appear in two routes' do + it 'shows up on the user profile' do + visit user_path(user) + expect(find('.user-callout')).to have_content 'Customize your experience' + end + + it 'shows up on the dashboard projects' do + visit dashboard_projects_path + expect(find('.user-callout')).to have_content 'Customize your experience' + end + end + + it 'hides the user callout when click on the dismiss icon' do + visit user_path(user) + within('.user-callout') do + find('.close-user-callout').click + end + expect(page).not_to have_selector('#user-callout') + end +end diff --git a/spec/helpers/application_helper_spec.rb b/spec/helpers/application_helper_spec.rb index fd40fe99941..4ffdd530171 100644 --- a/spec/helpers/application_helper_spec.rb +++ b/spec/helpers/application_helper_spec.rb @@ -58,7 +58,7 @@ describe ApplicationHelper do project = create(:empty_project, avatar: File.open(uploaded_image_temp_path)) avatar_url = "http://#{Gitlab.config.gitlab.host}/uploads/project/avatar/#{project.id}/banana_sample.gif" - expect(helper.project_icon("#{project.namespace.to_param}/#{project.to_param}").to_s). + expect(helper.project_icon(project.full_path).to_s). to eq "<img src=\"#{avatar_url}\" alt=\"Banana sample\" />" end @@ -68,7 +68,7 @@ describe ApplicationHelper do allow_any_instance_of(Project).to receive(:avatar_in_git).and_return(true) avatar_url = "http://#{Gitlab.config.gitlab.host}#{namespace_project_avatar_path(project.namespace, project)}" - expect(helper.project_icon("#{project.namespace.to_param}/#{project.to_param}").to_s).to match( + expect(helper.project_icon(project.full_path).to_s).to match( image_tag(avatar_url)) end end diff --git a/spec/helpers/milestones_helper_spec.rb b/spec/helpers/milestones_helper_spec.rb index 14a95479339..68b20a1e4fc 100644 --- a/spec/helpers/milestones_helper_spec.rb +++ b/spec/helpers/milestones_helper_spec.rb @@ -17,7 +17,7 @@ describe MilestonesHelper do it { expect(result_for(due_date: yesterday)).to eq("expired on #{yesterday_formatted}") } it { expect(result_for(start_date: tomorrow)).to eq("starts on #{tomorrow_formatted}") } it { expect(result_for(start_date: yesterday)).to eq("started on #{yesterday_formatted}") } - it { expect(result_for(start_date: yesterday, due_date: tomorrow)).to eq("#{yesterday_formatted} - #{tomorrow_formatted}") } + it { expect(result_for(start_date: yesterday, due_date: tomorrow)).to eq("#{yesterday_formatted}–#{tomorrow_formatted}") } end describe '#milestone_counts' do diff --git a/spec/javascripts/boards/board_card_spec.js b/spec/javascripts/boards/board_card_spec.js new file mode 100644 index 00000000000..be31f644e20 --- /dev/null +++ b/spec/javascripts/boards/board_card_spec.js @@ -0,0 +1,168 @@ +/* global Vue */ +/* global List */ +/* global ListLabel */ +/* global listObj */ +/* global boardsMockInterceptor */ +/* global BoardService */ + +require('~/boards/models/list'); +require('~/boards/models/label'); +require('~/boards/stores/boards_store'); +const boardCard = require('~/boards/components/board_card').default; +require('./mock_data'); + +describe('Issue card', () => { + let vm; + + beforeEach((done) => { + Vue.http.interceptors.push(boardsMockInterceptor); + + gl.boardService = new BoardService('/test/issue-boards/board', '', '1'); + gl.issueBoards.BoardsStore.create(); + gl.issueBoards.BoardsStore.detail.issue = {}; + + const BoardCardComp = Vue.extend(boardCard); + const list = new List(listObj); + const label1 = new ListLabel({ + id: 3, + title: 'testing 123', + color: 'blue', + text_color: 'white', + description: 'test', + }); + + setTimeout(() => { + list.issues[0].labels.push(label1); + + vm = new BoardCardComp({ + propsData: { + list, + issue: list.issues[0], + issueLinkBase: '/', + disabled: false, + index: 0, + rootPath: '/', + }, + }).$mount(); + done(); + }, 0); + }); + + afterEach(() => { + Vue.http.interceptors = _.without(Vue.http.interceptors, boardsMockInterceptor); + }); + + it('returns false when detailIssue is empty', () => { + expect(vm.issueDetailVisible).toBe(false); + }); + + it('returns true when detailIssue is equal to card issue', () => { + gl.issueBoards.BoardsStore.detail.issue = vm.issue; + + expect(vm.issueDetailVisible).toBe(true); + }); + + it('adds user-can-drag class if not disabled', () => { + expect(vm.$el.classList.contains('user-can-drag')).toBe(true); + }); + + it('does not add user-can-drag class disabled', (done) => { + vm.disabled = true; + + setTimeout(() => { + expect(vm.$el.classList.contains('user-can-drag')).toBe(false); + done(); + }, 0); + }); + + it('does not add disabled class', () => { + expect(vm.$el.classList.contains('is-disabled')).toBe(false); + }); + + it('adds disabled class is disabled is true', (done) => { + vm.disabled = true; + + setTimeout(() => { + expect(vm.$el.classList.contains('is-disabled')).toBe(true); + done(); + }, 0); + }); + + describe('mouse events', () => { + const triggerEvent = (eventName, el = vm.$el) => { + const event = document.createEvent('MouseEvents'); + event.initMouseEvent(eventName, true, true, window, 1, 0, 0, 0, 0, false, false, + false, false, 0, null); + + el.dispatchEvent(event); + }; + + it('sets showDetail to true on mousedown', () => { + triggerEvent('mousedown'); + + expect(vm.showDetail).toBe(true); + }); + + it('sets showDetail to false on mousemove', () => { + triggerEvent('mousedown'); + + expect(vm.showDetail).toBe(true); + + triggerEvent('mousemove'); + + expect(vm.showDetail).toBe(false); + }); + + it('does not set detail issue if showDetail is false', () => { + expect(gl.issueBoards.BoardsStore.detail.issue).toEqual({}); + }); + + it('does not set detail issue if link is clicked', () => { + triggerEvent('mouseup', vm.$el.querySelector('a')); + + expect(gl.issueBoards.BoardsStore.detail.issue).toEqual({}); + }); + + it('does not set detail issue if button is clicked', () => { + triggerEvent('mouseup', vm.$el.querySelector('button')); + + expect(gl.issueBoards.BoardsStore.detail.issue).toEqual({}); + }); + + it('does not set detail issue if showDetail is false after mouseup', () => { + triggerEvent('mouseup'); + + expect(gl.issueBoards.BoardsStore.detail.issue).toEqual({}); + }); + + it('sets detail issue to card issue on mouse up', () => { + triggerEvent('mousedown'); + triggerEvent('mouseup'); + + expect(gl.issueBoards.BoardsStore.detail.issue).toEqual(vm.issue); + expect(gl.issueBoards.BoardsStore.detail.list).toEqual(vm.list); + }); + + it('adds active class if detail issue is set', (done) => { + triggerEvent('mousedown'); + triggerEvent('mouseup'); + + setTimeout(() => { + expect(vm.$el.classList.contains('is-active')).toBe(true); + done(); + }, 0); + }); + + it('resets detail issue to empty if already set', () => { + triggerEvent('mousedown'); + triggerEvent('mouseup'); + + expect(gl.issueBoards.BoardsStore.detail.issue).toEqual(vm.issue); + + triggerEvent('mousedown'); + triggerEvent('mouseup'); + + expect(gl.issueBoards.BoardsStore.detail.issue).toEqual({}); + }); + }); +}); diff --git a/spec/javascripts/boards/board_new_issue_spec.js b/spec/javascripts/boards/board_new_issue_spec.js new file mode 100644 index 00000000000..22c9f12951b --- /dev/null +++ b/spec/javascripts/boards/board_new_issue_spec.js @@ -0,0 +1,191 @@ +/* global boardsMockInterceptor */ +/* global BoardService */ +/* global List */ +/* global listObj */ + +import Vue from 'vue'; +import boardNewIssue from '~/boards/components/board_new_issue'; + +require('~/boards/models/list'); +require('./mock_data'); +require('es6-promise').polyfill(); + +describe('Issue boards new issue form', () => { + let vm; + let list; + const promiseReturn = { + json() { + return { + iid: 100, + }; + }, + }; + const submitIssue = () => { + vm.$el.querySelector('.btn-success').click(); + }; + + beforeEach((done) => { + const BoardNewIssueComp = Vue.extend(boardNewIssue); + + Vue.http.interceptors.push(boardsMockInterceptor); + gl.boardService = new BoardService('/test/issue-boards/board', '', '1'); + gl.issueBoards.BoardsStore.create(); + gl.IssueBoardsApp = new Vue(); + + setTimeout(() => { + list = new List(listObj); + + spyOn(gl.boardService, 'newIssue').and.callFake(() => new Promise((resolve, reject) => { + if (vm.title === 'error') { + reject(); + } else { + resolve(promiseReturn); + } + })); + + vm = new BoardNewIssueComp({ + propsData: { + list, + }, + }).$mount(); + + done(); + }, 0); + }); + + afterEach(() => { + Vue.http.interceptors = _.without(Vue.http.interceptors, boardsMockInterceptor); + }); + + it('disables submit button if title is empty', () => { + expect(vm.$el.querySelector('.btn-success').disabled).toBe(true); + }); + + it('enables submit button if title is not empty', (done) => { + vm.title = 'Testing Title'; + + setTimeout(() => { + expect(vm.$el.querySelector('.form-control').value).toBe('Testing Title'); + expect(vm.$el.querySelector('.btn-success').disabled).not.toBe(true); + + done(); + }, 0); + }); + + it('clears title after clicking cancel', (done) => { + vm.$el.querySelector('.btn-default').click(); + + setTimeout(() => { + expect(vm.title).toBe(''); + done(); + }, 0); + }); + + it('does not create new issue if title is empty', (done) => { + submitIssue(); + + setTimeout(() => { + expect(gl.boardService.newIssue).not.toHaveBeenCalled(); + done(); + }, 0); + }); + + describe('submit success', () => { + it('creates new issue', (done) => { + vm.title = 'submit title'; + + setTimeout(() => { + submitIssue(); + + expect(gl.boardService.newIssue).toHaveBeenCalled(); + done(); + }, 0); + }); + + it('enables button after submit', (done) => { + vm.title = 'submit issue'; + + setTimeout(() => { + submitIssue(); + + expect(vm.$el.querySelector('.btn-success').disbled).not.toBe(true); + done(); + }, 0); + }); + + it('clears title after submit', (done) => { + vm.title = 'submit issue'; + + setTimeout(() => { + submitIssue(); + + expect(vm.title).toBe(''); + done(); + }, 0); + }); + + it('adds new issue to list after submit', (done) => { + vm.title = 'submit issue'; + + setTimeout(() => { + submitIssue(); + + expect(list.issues.length).toBe(2); + expect(list.issues[1].title).toBe('submit issue'); + expect(list.issues[1].subscribed).toBe(true); + done(); + }, 0); + }); + + it('sets detail issue after submit', (done) => { + vm.title = 'submit issue'; + + setTimeout(() => { + submitIssue(); + + expect(gl.issueBoards.BoardsStore.detail.issue.title).toBe('submit issue'); + done(); + }); + }); + + it('sets detail list after submit', (done) => { + vm.title = 'submit issue'; + + setTimeout(() => { + submitIssue(); + + expect(gl.issueBoards.BoardsStore.detail.list.id).toBe(list.id); + done(); + }, 0); + }); + }); + + describe('submit error', () => { + it('removes issue', (done) => { + vm.title = 'error'; + + setTimeout(() => { + submitIssue(); + + setTimeout(() => { + expect(list.issues.length).toBe(1); + done(); + }, 500); + }, 0); + }); + + it('shows error', (done) => { + vm.title = 'error'; + submitIssue(); + + setTimeout(() => { + submitIssue(); + + setTimeout(() => { + expect(vm.error).toBe(true); + done(); + }, 500); + }, 0); + }); + }); +}); diff --git a/spec/javascripts/boards/list_spec.js.es6 b/spec/javascripts/boards/list_spec.js.es6 index 4397a32fedc..c8a18af7198 100644 --- a/spec/javascripts/boards/list_spec.js.es6 +++ b/spec/javascripts/boards/list_spec.js.es6 @@ -3,7 +3,9 @@ /* global boardsMockInterceptor */ /* global BoardService */ /* global List */ +/* global ListIssue */ /* global listObj */ +/* global listObjDuplicate */ require('~/lib/utils/url_utility'); require('~/boards/models/issue'); @@ -84,4 +86,23 @@ describe('List model', () => { done(); }, 0); }); + + it('sends service request to update issue label', () => { + const listDup = new List(listObjDuplicate); + const issue = new ListIssue({ + title: 'Testing', + iid: 1, + confidential: false, + labels: [list.label, listDup.label] + }); + + list.issues.push(issue); + listDup.issues.push(issue); + + spyOn(gl.boardService, 'moveIssue').and.callThrough(); + + listDup.updateIssueLabel(list, issue); + + expect(gl.boardService.moveIssue).toHaveBeenCalledWith(issue.id, list.id, listDup.id); + }); }); diff --git a/spec/javascripts/fixtures/branches.rb b/spec/javascripts/fixtures/branches.rb index 0e7c2351b66..a059818145b 100644 --- a/spec/javascripts/fixtures/branches.rb +++ b/spec/javascripts/fixtures/branches.rb @@ -20,7 +20,7 @@ describe Projects::BranchesController, '(JavaScript fixtures)', type: :controlle it 'branches/new_branch.html.raw' do |example| get :new, namespace_id: project.namespace.to_param, - project_id: project.to_param + project_id: project expect(response).to be_success store_frontend_fixture(response, example.description) diff --git a/spec/javascripts/fixtures/builds.rb b/spec/javascripts/fixtures/builds.rb index 978e25a1c32..320de791b08 100644 --- a/spec/javascripts/fixtures/builds.rb +++ b/spec/javascripts/fixtures/builds.rb @@ -24,7 +24,7 @@ describe Projects::BuildsController, '(JavaScript fixtures)', type: :controller it 'builds/build-with-artifacts.html.raw' do |example| get :show, namespace_id: project.namespace.to_param, - project_id: project.to_param, + project_id: project, id: build_with_artifacts.to_param expect(response).to be_success diff --git a/spec/javascripts/fixtures/issues.rb b/spec/javascripts/fixtures/issues.rb index 06f708f9e15..88e3f860809 100644 --- a/spec/javascripts/fixtures/issues.rb +++ b/spec/javascripts/fixtures/issues.rb @@ -41,7 +41,7 @@ describe Projects::IssuesController, '(JavaScript fixtures)', type: :controller def render_issue(fixture_file_name, issue) get :show, namespace_id: project.namespace.to_param, - project_id: project.to_param, + project_id: project, id: issue.to_param expect(response).to be_success diff --git a/spec/javascripts/fixtures/merge_requests.rb b/spec/javascripts/fixtures/merge_requests.rb index 62984097099..ee893b76c84 100644 --- a/spec/javascripts/fixtures/merge_requests.rb +++ b/spec/javascripts/fixtures/merge_requests.rb @@ -27,7 +27,7 @@ describe Projects::MergeRequestsController, '(JavaScript fixtures)', type: :cont def render_merge_request(fixture_file_name, merge_request) get :show, namespace_id: project.namespace.to_param, - project_id: project.to_param, + project_id: project, id: merge_request.to_param expect(response).to be_success diff --git a/spec/javascripts/fixtures/projects.json b/spec/javascripts/fixtures/projects.json index 4ce7f5c601a..1339ee00870 100644 --- a/spec/javascripts/fixtures/projects.json +++ b/spec/javascripts/fixtures/projects.json @@ -43,7 +43,7 @@ "avatar_url": null, "star_count": 0, "forks_count": 0, - "only_allow_merge_if_build_succeeds": false, + "only_allow_merge_if_pipeline_succeeds": false, "open_issues_count": 0, "permissions": { "project_access": null, @@ -88,7 +88,7 @@ "avatar_url": null, "star_count": 0, "forks_count": 0, - "only_allow_merge_if_build_succeeds": false, + "only_allow_merge_if_pipeline_succeeds": false, "open_issues_count": 5, "permissions": { "project_access": { @@ -139,7 +139,7 @@ "avatar_url": null, "star_count": 0, "forks_count": 0, - "only_allow_merge_if_build_succeeds": true, + "only_allow_merge_if_pipeline_succeeds": true, "open_issues_count": 4, "permissions": { "project_access": null, @@ -187,7 +187,7 @@ "avatar_url": null, "star_count": 0, "forks_count": 0, - "only_allow_merge_if_build_succeeds": true, + "only_allow_merge_if_pipeline_succeeds": true, "open_issues_count": 4, "permissions": { "project_access": null, @@ -235,7 +235,7 @@ "avatar_url": null, "star_count": 0, "forks_count": 0, - "only_allow_merge_if_build_succeeds": false, + "only_allow_merge_if_pipeline_succeeds": false, "open_issues_count": 5, "permissions": { "project_access": null, @@ -283,7 +283,7 @@ "avatar_url": null, "star_count": 0, "forks_count": 0, - "only_allow_merge_if_build_succeeds": false, + "only_allow_merge_if_pipeline_succeeds": false, "open_issues_count": 5, "permissions": { "project_access": { @@ -334,7 +334,7 @@ "avatar_url": null, "star_count": 0, "forks_count": 0, - "only_allow_merge_if_build_succeeds": false, + "only_allow_merge_if_pipeline_succeeds": false, "open_issues_count": 3, "permissions": { "project_access": null, @@ -382,7 +382,7 @@ "avatar_url": null, "star_count": 0, "forks_count": 0, - "only_allow_merge_if_build_succeeds": false, + "only_allow_merge_if_pipeline_succeeds": false, "open_issues_count": 5, "permissions": { "project_access": { @@ -433,7 +433,7 @@ "avatar_url": null, "star_count": 0, "forks_count": 0, - "only_allow_merge_if_build_succeeds": false, + "only_allow_merge_if_pipeline_succeeds": false, "open_issues_count": 5, "permissions": { "project_access": null, diff --git a/spec/javascripts/fixtures/projects.rb b/spec/javascripts/fixtures/projects.rb index 56513219e1e..6c33b240e5c 100644 --- a/spec/javascripts/fixtures/projects.rb +++ b/spec/javascripts/fixtures/projects.rb @@ -20,7 +20,7 @@ describe ProjectsController, '(JavaScript fixtures)', type: :controller do it 'projects/dashboard.html.raw' do |example| get :show, namespace_id: project.namespace.to_param, - id: project.to_param + id: project expect(response).to be_success store_frontend_fixture(response, example.description) diff --git a/spec/javascripts/fixtures/todos.rb b/spec/javascripts/fixtures/todos.rb index 2c08b06ea9e..a81ef8c5492 100644 --- a/spec/javascripts/fixtures/todos.rb +++ b/spec/javascripts/fixtures/todos.rb @@ -39,8 +39,8 @@ describe 'Todos (JavaScript fixtures)' do it 'todos/todos.json' do |example| post :create, - namespace_id: namespace.path, - project_id: project.path, + namespace_id: namespace, + project_id: project, issuable_type: 'issue', issuable_id: issue_2.id, format: 'json' diff --git a/spec/javascripts/fixtures/user_callout.html.haml b/spec/javascripts/fixtures/user_callout.html.haml new file mode 100644 index 00000000000..275359bde0a --- /dev/null +++ b/spec/javascripts/fixtures/user_callout.html.haml @@ -0,0 +1,2 @@ +.user-callout{ 'callout-svg' => custom_icon('icon_customization') } + diff --git a/spec/javascripts/graphs/stat_graph_contributors_graph_spec.js b/spec/javascripts/graphs/stat_graph_contributors_graph_spec.js index a954bb60560..861f26e162f 100644 --- a/spec/javascripts/graphs/stat_graph_contributors_graph_spec.js +++ b/spec/javascripts/graphs/stat_graph_contributors_graph_spec.js @@ -1,9 +1,7 @@ -/* eslint-disable quotes, jasmine/no-suite-dupes, vars-on-top, no-var, max-len */ -/* global d3 */ -/* global ContributorsGraph */ -/* global ContributorsMasterGraph */ +/* eslint-disable quotes, jasmine/no-suite-dupes, vars-on-top, no-var */ -require('~/graphs/stat_graph_contributors_graph'); +import d3 from 'd3'; +import { ContributorsGraph, ContributorsMasterGraph } from '~/graphs/stat_graph_contributors_graph'; describe("ContributorsGraph", function () { describe("#set_x_domain", function () { diff --git a/spec/javascripts/graphs/stat_graph_contributors_util_spec.js b/spec/javascripts/graphs/stat_graph_contributors_util_spec.js index b15764abe8c..9b47ab62181 100644 --- a/spec/javascripts/graphs/stat_graph_contributors_util_spec.js +++ b/spec/javascripts/graphs/stat_graph_contributors_util_spec.js @@ -1,7 +1,6 @@ /* eslint-disable quotes, no-var, camelcase, object-property-newline, comma-dangle, max-len, vars-on-top, quote-props */ -/* global ContributorsStatGraphUtil */ -require('~/graphs/stat_graph_contributors_util'); +import ContributorsStatGraphUtil from '~/graphs/stat_graph_contributors_util'; describe("ContributorsStatGraphUtil", function () { describe("#parse_log", function () { diff --git a/spec/javascripts/graphs/stat_graph_spec.js b/spec/javascripts/graphs/stat_graph_spec.js deleted file mode 100644 index 876c23361bc..00000000000 --- a/spec/javascripts/graphs/stat_graph_spec.js +++ /dev/null @@ -1,20 +0,0 @@ -/* eslint-disable quotes */ -/* global StatGraph */ - -require('~/graphs/stat_graph'); - -describe("StatGraph", function () { - describe("#get_log", function () { - it("returns log", function () { - StatGraph.log = "test"; - expect(StatGraph.get_log()).toBe("test"); - }); - }); - - describe("#set_log", function () { - it("sets the log", function () { - StatGraph.set_log("test"); - expect(StatGraph.log).toBe("test"); - }); - }); -}); diff --git a/spec/javascripts/user_callout_spec.js.es6 b/spec/javascripts/user_callout_spec.js.es6 new file mode 100644 index 00000000000..6ee63f56a26 --- /dev/null +++ b/spec/javascripts/user_callout_spec.js.es6 @@ -0,0 +1,37 @@ +const UserCallout = require('~/user_callout'); + +const USER_CALLOUT_COOKIE = 'user_callout_dismissed'; +const Cookie = window.Cookies; + +describe('UserCallout', () => { + const fixtureName = 'static/user_callout.html.raw'; + preloadFixtures(fixtureName); + + beforeEach(function () { + loadFixtures(fixtureName); + this.userCallout = new UserCallout(); + this.closeButton = $('.close-user-callout'); + this.userCalloutBtn = $('.user-callout-btn'); + this.userCalloutContainer = $('.user-callout'); + Cookie.set(USER_CALLOUT_COOKIE, 'false'); + }); + + afterEach(function () { + Cookie.set(USER_CALLOUT_COOKIE, 'false'); + }); + + it('shows when cookie is set to false', function () { + expect(Cookie.get(USER_CALLOUT_COOKIE)).toBeDefined(); + expect(this.userCalloutContainer.is(':visible')).toBe(true); + }); + + it('hides when user clicks on the dismiss-icon', function () { + this.closeButton.click(); + expect(Cookie.get(USER_CALLOUT_COOKIE)).toBe('true'); + }); + + it('hides when user clicks on the "check it out" button', function () { + this.userCalloutBtn.click(); + expect(Cookie.get(USER_CALLOUT_COOKIE)).toBe('true'); + }); +}); diff --git a/spec/javascripts/vue_shared/components/table_pagination_spec.js.es6 b/spec/javascripts/vue_shared/components/table_pagination_spec.js.es6 index dd495cb43bc..9cb067921a7 100644 --- a/spec/javascripts/vue_shared/components/table_pagination_spec.js.es6 +++ b/spec/javascripts/vue_shared/components/table_pagination_spec.js.es6 @@ -6,12 +6,10 @@ describe('Pagination component', () => { const changeChanges = { one: '', - two: '', }; - const change = (one, two) => { + const change = (one) => { changeChanges.one = one; - changeChanges.two = two; }; it('should render and start at page 1', () => { @@ -34,7 +32,6 @@ describe('Pagination component', () => { component.changePage({ target: { innerText: '1' } }); expect(changeChanges.one).toEqual(1); - expect(changeChanges.two).toEqual(null); }); it('should go to the previous page', () => { @@ -55,7 +52,6 @@ describe('Pagination component', () => { component.changePage({ target: { innerText: 'Prev' } }); expect(changeChanges.one).toEqual(1); - expect(changeChanges.two).toEqual(null); }); it('should go to the next page', () => { @@ -76,7 +72,6 @@ describe('Pagination component', () => { component.changePage({ target: { innerText: 'Next' } }); expect(changeChanges.one).toEqual(5); - expect(changeChanges.two).toEqual(null); }); it('should go to the last page', () => { @@ -97,7 +92,6 @@ describe('Pagination component', () => { component.changePage({ target: { innerText: 'Last >>' } }); expect(changeChanges.one).toEqual(10); - expect(changeChanges.two).toEqual(null); }); it('should go to the first page', () => { @@ -118,7 +112,6 @@ describe('Pagination component', () => { component.changePage({ target: { innerText: '<< First' } }); expect(changeChanges.one).toEqual(1); - expect(changeChanges.two).toEqual(null); }); it('should do nothing', () => { @@ -139,7 +132,6 @@ describe('Pagination component', () => { component.changePage({ target: { innerText: '...' } }); expect(changeChanges.one).toEqual(1); - expect(changeChanges.two).toEqual(null); }); }); diff --git a/spec/lib/banzai/filter/image_link_filter_spec.rb b/spec/lib/banzai/filter/image_link_filter_spec.rb index a2a1ed58d1b..294558b3db2 100644 --- a/spec/lib/banzai/filter/image_link_filter_spec.rb +++ b/spec/lib/banzai/filter/image_link_filter_spec.rb @@ -13,8 +13,8 @@ describe Banzai::Filter::ImageLinkFilter, lib: true do end it 'does not wrap a duplicate link' do - exp = act = %q(<a href="/whatever">#{image('/uploads/e90decf88d8f96fe9e1389afc2e4a91f/test.jpg')}</a>) - expect(filter(act).to_html).to eq exp + doc = filter(%Q(<a href="/whatever">#{image('/uploads/e90decf88d8f96fe9e1389afc2e4a91f/test.jpg')}</a>)) + expect(doc.to_html).to match /^<a href="\/whatever"><img[^>]*><\/a>$/ end it 'works with external images' do @@ -22,8 +22,8 @@ describe Banzai::Filter::ImageLinkFilter, lib: true do expect(doc.at_css('img')['src']).to eq doc.at_css('a')['href'] end - it 'wraps the image with a link and a div' do - doc = filter(image('/uploads/e90decf88d8f96fe9e1389afc2e4a91f/test.jpg')) - expect(doc.to_html).to include('<div class="image-container">') + it 'works with inline images' do + doc = filter(%Q(<p>test #{image('/uploads/e90decf88d8f96fe9e1389afc2e4a91f/test.jpg')} inline</p>)) + expect(doc.to_html).to match /^<p>test <a[^>]*><img[^>]*><\/a> inline<\/p>$/ end end diff --git a/spec/lib/constraints/project_url_constrainer_spec.rb b/spec/lib/constraints/project_url_constrainer_spec.rb index a5251e9a8c2..4f25ad88960 100644 --- a/spec/lib/constraints/project_url_constrainer_spec.rb +++ b/spec/lib/constraints/project_url_constrainer_spec.rb @@ -6,7 +6,7 @@ describe ProjectUrlConstrainer, lib: true do describe '#matches?' do context 'valid request' do - let(:request) { build_request(namespace.path, project.path) } + let(:request) { build_request(namespace.full_path, project.path) } it { expect(subject.matches?(request)).to be_truthy } end @@ -19,7 +19,7 @@ describe ProjectUrlConstrainer, lib: true do end context "project id ending with .git" do - let(:request) { build_request(namespace.path, project.path + '.git') } + let(:request) { build_request(namespace.full_path, project.path + '.git') } it { expect(subject.matches?(request)).to be_falsey } end diff --git a/spec/lib/gitlab/conflict/file_spec.rb b/spec/lib/gitlab/conflict/file_spec.rb index 7e5531d92dc..780ac0ad97e 100644 --- a/spec/lib/gitlab/conflict/file_spec.rb +++ b/spec/lib/gitlab/conflict/file_spec.rb @@ -251,7 +251,7 @@ FILE describe '#as_json' do it 'includes the blob path for the file' do expect(conflict_file.as_json[:blob_path]). - to eq("/#{project.namespace.to_param}/#{merge_request.project.to_param}/blob/#{our_commit.oid}/files/ruby/regex.rb") + to eq("/#{project.full_path}/blob/#{our_commit.oid}/files/ruby/regex.rb") end it 'includes the blob icon for the file' do diff --git a/spec/lib/gitlab/git/blob_spec.rb b/spec/lib/gitlab/git/blob_spec.rb index 0c321f0343c..8049e2c120d 100644 --- a/spec/lib/gitlab/git/blob_spec.rb +++ b/spec/lib/gitlab/git/blob_spec.rb @@ -222,191 +222,6 @@ describe Gitlab::Git::Blob, seed_helper: true do end end - describe :commit do - let(:repository) { Gitlab::Git::Repository.new(TEST_REPO_PATH) } - - let(:commit_options) do - { - file: { - content: 'Lorem ipsum...', - path: 'documents/story.txt' - }, - author: { - email: 'user@example.com', - name: 'Test User', - time: Time.now - }, - committer: { - email: 'user@example.com', - name: 'Test User', - time: Time.now - }, - commit: { - message: 'Wow such commit', - branch: 'fix-mode' - } - } - end - - let(:commit_sha) { Gitlab::Git::Blob.commit(repository, commit_options) } - let(:commit) { repository.lookup(commit_sha) } - - it 'should add file with commit' do - # Commit message valid - expect(commit.message).to eq('Wow such commit') - - tree = commit.tree.to_a.find { |tree| tree[:name] == 'documents' } - - # Directory was created - expect(tree[:type]).to eq(:tree) - - # File was created - expect(repository.lookup(tree[:oid]).first[:name]).to eq('story.txt') - end - - describe "ref updating" do - it 'creates a commit but does not udate a ref' do - commit_opts = commit_options.tap{ |opts| opts[:commit][:update_ref] = false} - commit_sha = Gitlab::Git::Blob.commit(repository, commit_opts) - commit = repository.lookup(commit_sha) - - # Commit message valid - expect(commit.message).to eq('Wow such commit') - - # Does not update any related ref - expect(repository.lookup("fix-mode").oid).not_to eq(commit.oid) - expect(repository.lookup("HEAD").oid).not_to eq(commit.oid) - end - end - - describe 'reject updates' do - it 'should reject updates' do - commit_options[:file][:update] = false - commit_options[:file][:path] = 'files/executables/ls' - - expect{ commit_sha }.to raise_error('Filename already exists; update not allowed') - end - end - - describe 'file modes' do - it 'should preserve file modes with commit' do - commit_options[:file][:path] = 'files/executables/ls' - - entry = Gitlab::Git::Blob.find_entry_by_path(repository, commit.tree.oid, commit_options[:file][:path]) - expect(entry[:filemode]).to eq(0100755) - end - end - end - - describe :rename do - let(:repository) { Gitlab::Git::Repository.new(TEST_NORMAL_REPO_PATH) } - let(:rename_options) do - { - file: { - path: 'NEWCONTRIBUTING.md', - previous_path: 'CONTRIBUTING.md', - content: 'Lorem ipsum...', - update: true - }, - author: { - email: 'user@example.com', - name: 'Test User', - time: Time.now - }, - committer: { - email: 'user@example.com', - name: 'Test User', - time: Time.now - }, - commit: { - message: 'Rename readme', - branch: 'master' - } - } - end - - let(:rename_options2) do - { - file: { - content: 'Lorem ipsum...', - path: 'bin/new_executable', - previous_path: 'bin/executable', - }, - author: { - email: 'user@example.com', - name: 'Test User', - time: Time.now - }, - committer: { - email: 'user@example.com', - name: 'Test User', - time: Time.now - }, - commit: { - message: 'Updates toberenamed.txt', - branch: 'master', - update_ref: false - } - } - end - - it 'maintains file permissions when renaming' do - mode = 0o100755 - - Gitlab::Git::Blob.rename(repository, rename_options2) - - expect(repository.rugged.index.get(rename_options2[:file][:path])[:mode]).to eq(mode) - end - - it 'renames the file with commit and not change file permissions' do - ref = rename_options[:commit][:branch] - - expect(repository.rugged.index.get('CONTRIBUTING.md')).not_to be_nil - expect { Gitlab::Git::Blob.rename(repository, rename_options) }.to change { repository.commit_count(ref) }.by(1) - - expect(repository.rugged.index.get('CONTRIBUTING.md')).to be_nil - expect(repository.rugged.index.get('NEWCONTRIBUTING.md')).not_to be_nil - end - end - - describe :remove do - let(:repository) { Gitlab::Git::Repository.new(TEST_REPO_PATH) } - - let(:commit_options) do - { - file: { - path: 'README.md' - }, - author: { - email: 'user@example.com', - name: 'Test User', - time: Time.now - }, - committer: { - email: 'user@example.com', - name: 'Test User', - time: Time.now - }, - commit: { - message: 'Remove readme', - branch: 'feature' - } - } - end - - let(:commit_sha) { Gitlab::Git::Blob.remove(repository, commit_options) } - let(:commit) { repository.lookup(commit_sha) } - let(:blob) { Gitlab::Git::Blob.find(repository, commit_sha, "README.md") } - - it 'should remove file with commit' do - # Commit message valid - expect(commit.message).to eq('Remove readme') - - # File was removed - expect(blob).to be_nil - end - end - describe :lfs_pointers do context 'file a valid lfs pointer' do let(:blob) do diff --git a/spec/lib/gitlab/git/index_spec.rb b/spec/lib/gitlab/git/index_spec.rb new file mode 100644 index 00000000000..d0c7ca60ddc --- /dev/null +++ b/spec/lib/gitlab/git/index_spec.rb @@ -0,0 +1,220 @@ +require 'spec_helper' + +describe Gitlab::Git::Index, seed_helper: true do + let(:repository) { Gitlab::Git::Repository.new(TEST_REPO_PATH) } + let(:index) { described_class.new(repository) } + + before do + index.read_tree(repository.lookup('master').tree) + end + + describe '#create' do + let(:options) do + { + content: 'Lorem ipsum...', + file_path: 'documents/story.txt' + } + end + + context 'when no file at that path exists' do + it 'creates the file in the index' do + index.create(options) + + entry = index.get(options[:file_path]) + + expect(entry).not_to be_nil + expect(repository.lookup(entry[:oid]).content).to eq(options[:content]) + end + end + + context 'when a file at that path exists' do + before do + options[:file_path] = 'files/executables/ls' + end + + it 'raises an error' do + expect { index.create(options) }.to raise_error('Filename already exists') + end + end + + context 'when content is in base64' do + before do + options[:content] = Base64.encode64(options[:content]) + options[:encoding] = 'base64' + end + + it 'decodes base64' do + index.create(options) + + entry = index.get(options[:file_path]) + expect(repository.lookup(entry[:oid]).content).to eq(Base64.decode64(options[:content])) + end + end + + context 'when content contains CRLF' do + before do + repository.autocrlf = :input + options[:content] = "Hello,\r\nWorld" + end + + it 'converts to LF' do + index.create(options) + + entry = index.get(options[:file_path]) + expect(repository.lookup(entry[:oid]).content).to eq("Hello,\nWorld") + end + end + end + + describe '#create_dir' do + let(:options) do + { + file_path: 'newdir' + } + end + + context 'when no file or dir at that path exists' do + it 'creates the dir in the index' do + index.create_dir(options) + + entry = index.get(options[:file_path] + '/.gitkeep') + + expect(entry).not_to be_nil + end + end + + context 'when a file at that path exists' do + before do + options[:file_path] = 'files/executables/ls' + end + + it 'raises an error' do + expect { index.create_dir(options) }.to raise_error('Directory already exists as a file') + end + end + + context 'when a directory at that path exists' do + before do + options[:file_path] = 'files/executables' + end + + it 'raises an error' do + expect { index.create_dir(options) }.to raise_error('Directory already exists') + end + end + end + + describe '#update' do + let(:options) do + { + content: 'Lorem ipsum...', + file_path: 'README.md' + } + end + + context 'when no file at that path exists' do + before do + options[:file_path] = 'documents/story.txt' + end + + it 'raises an error' do + expect { index.update(options) }.to raise_error("File doesn't exist") + end + end + + context 'when a file at that path exists' do + it 'updates the file in the index' do + index.update(options) + + entry = index.get(options[:file_path]) + + expect(repository.lookup(entry[:oid]).content).to eq(options[:content]) + end + + it 'preserves file mode' do + options[:file_path] = 'files/executables/ls' + + index.update(options) + + entry = index.get(options[:file_path]) + + expect(entry[:mode]).to eq(0100755) + end + end + end + + describe '#move' do + let(:options) do + { + content: 'Lorem ipsum...', + previous_path: 'README.md', + file_path: 'NEWREADME.md' + } + end + + context 'when no file at that path exists' do + it 'raises an error' do + options[:previous_path] = 'documents/story.txt' + + expect { index.move(options) }.to raise_error("File doesn't exist") + end + end + + context 'when a file at that path exists' do + it 'removes the old file in the index' do + index.move(options) + + entry = index.get(options[:previous_path]) + + expect(entry).to be_nil + end + + it 'creates the new file in the index' do + index.move(options) + + entry = index.get(options[:file_path]) + + expect(entry).not_to be_nil + expect(repository.lookup(entry[:oid]).content).to eq(options[:content]) + end + + it 'preserves file mode' do + options[:previous_path] = 'files/executables/ls' + + index.move(options) + + entry = index.get(options[:file_path]) + + expect(entry[:mode]).to eq(0100755) + end + end + end + + describe '#delete' do + let(:options) do + { + file_path: 'README.md' + } + end + + context 'when no file at that path exists' do + before do + options[:file_path] = 'documents/story.txt' + end + + it 'raises an error' do + expect { index.delete(options) }.to raise_error("File doesn't exist") + end + end + + context 'when a file at that path exists' do + it 'removes the file in the index' do + index.delete(options) + + entry = index.get(options[:file_path]) + + expect(entry).to be_nil + end + end + end +end diff --git a/spec/lib/gitlab/git/repository_spec.rb b/spec/lib/gitlab/git/repository_spec.rb index 2a915bf426f..1919542ca25 100644 --- a/spec/lib/gitlab/git/repository_spec.rb +++ b/spec/lib/gitlab/git/repository_spec.rb @@ -529,7 +529,7 @@ describe Gitlab::Git::Repository, seed_helper: true do commit_with_new_name = nil rename_commit = nil - before(:all) do + before(:context) do # Add new commits so that there's a renamed file in the commit history repo = Gitlab::Git::Repository.new(TEST_REPO_PATH).rugged @@ -538,49 +538,119 @@ describe Gitlab::Git::Repository, seed_helper: true do commit_with_new_name = new_commit_edit_new_file(repo) end + after(:context) do + # Erase our commits so other tests get the original repo + repo = Gitlab::Git::Repository.new(TEST_REPO_PATH).rugged + repo.references.update("refs/heads/master", SeedRepo::LastCommit::ID) + end + context "where 'follow' == true" do - options = { ref: "master", follow: true } + let(:options) { { ref: "master", follow: true } } context "and 'path' is a directory" do - let(:log_commits) do - repository.log(options.merge(path: "encoding")) - end + it "does not follow renames" do + log_commits = repository.log(options.merge(path: "encoding")) - it "should not follow renames" do - expect(log_commits).to include(commit_with_new_name) - expect(log_commits).to include(rename_commit) - expect(log_commits).not_to include(commit_with_old_name) + aggregate_failures do + expect(log_commits).to include(commit_with_new_name) + expect(log_commits).to include(rename_commit) + expect(log_commits).not_to include(commit_with_old_name) + end end end context "and 'path' is a file that matches the new filename" do - let(:log_commits) do - repository.log(options.merge(path: "encoding/CHANGELOG")) + context 'without offset' do + it "follows renames" do + log_commits = repository.log(options.merge(path: "encoding/CHANGELOG")) + + aggregate_failures do + expect(log_commits).to include(commit_with_new_name) + expect(log_commits).to include(rename_commit) + expect(log_commits).to include(commit_with_old_name) + end + end end - it "should follow renames" do - expect(log_commits).to include(commit_with_new_name) - expect(log_commits).to include(rename_commit) - expect(log_commits).to include(commit_with_old_name) + context 'with offset=1' do + it "follows renames and skip the latest commit" do + log_commits = repository.log(options.merge(path: "encoding/CHANGELOG", offset: 1)) + + aggregate_failures do + expect(log_commits).not_to include(commit_with_new_name) + expect(log_commits).to include(rename_commit) + expect(log_commits).to include(commit_with_old_name) + end + end + end + + context 'with offset=1', 'and limit=1' do + it "follows renames, skip the latest commit and return only one commit" do + log_commits = repository.log(options.merge(path: "encoding/CHANGELOG", offset: 1, limit: 1)) + + expect(log_commits).to contain_exactly(rename_commit) + end + end + + context 'with offset=1', 'and limit=2' do + it "follows renames, skip the latest commit and return only two commits" do + log_commits = repository.log(options.merge(path: "encoding/CHANGELOG", offset: 1, limit: 2)) + + aggregate_failures do + expect(log_commits).to contain_exactly(rename_commit, commit_with_old_name) + end + end + end + + context 'with offset=2' do + it "follows renames and skip the latest commit" do + log_commits = repository.log(options.merge(path: "encoding/CHANGELOG", offset: 2)) + + aggregate_failures do + expect(log_commits).not_to include(commit_with_new_name) + expect(log_commits).not_to include(rename_commit) + expect(log_commits).to include(commit_with_old_name) + end + end + end + + context 'with offset=2', 'and limit=1' do + it "follows renames, skip the two latest commit and return only one commit" do + log_commits = repository.log(options.merge(path: "encoding/CHANGELOG", offset: 2, limit: 1)) + + expect(log_commits).to contain_exactly(commit_with_old_name) + end + end + + context 'with offset=2', 'and limit=2' do + it "follows renames, skip the two latest commit and return only one commit" do + log_commits = repository.log(options.merge(path: "encoding/CHANGELOG", offset: 2, limit: 2)) + + aggregate_failures do + expect(log_commits).not_to include(commit_with_new_name) + expect(log_commits).not_to include(rename_commit) + expect(log_commits).to include(commit_with_old_name) + end + end end end context "and 'path' is a file that matches the old filename" do - let(:log_commits) do - repository.log(options.merge(path: "CHANGELOG")) - end + it "does not follow renames" do + log_commits = repository.log(options.merge(path: "CHANGELOG")) - it "should not follow renames" do - expect(log_commits).to include(commit_with_old_name) - expect(log_commits).to include(rename_commit) - expect(log_commits).not_to include(commit_with_new_name) + aggregate_failures do + expect(log_commits).not_to include(commit_with_new_name) + expect(log_commits).to include(rename_commit) + expect(log_commits).to include(commit_with_old_name) + end end end context "unknown ref" do - let(:log_commits) { repository.log(options.merge(ref: 'unknown')) } + it "returns an empty array" do + log_commits = repository.log(options.merge(ref: 'unknown')) - it "should return empty" do expect(log_commits).to eq([]) end end @@ -699,12 +769,6 @@ describe Gitlab::Git::Repository, seed_helper: true do end end end - - after(:all) do - # Erase our commits so other tests get the original repo - repo = Gitlab::Git::Repository.new(TEST_REPO_PATH).rugged - repo.references.update("refs/heads/master", SeedRepo::LastCommit::ID) - end end describe "#commits_between" do @@ -844,81 +908,6 @@ describe Gitlab::Git::Repository, seed_helper: true do end end - describe '#mkdir' do - let(:commit_options) do - { - author: { - email: 'user@example.com', - name: 'Test User', - time: Time.now - }, - committer: { - email: 'user@example.com', - name: 'Test User', - time: Time.now - }, - commit: { - message: 'Test message', - branch: 'refs/heads/fix', - } - } - end - - def generate_diff_for_path(path) - "diff --git a/#{path}/.gitkeep b/#{path}/.gitkeep -new file mode 100644 -index 0000000..e69de29 ---- /dev/null -+++ b/#{path}/.gitkeep\n" - end - - shared_examples 'mkdir diff check' do |path, expected_path| - it 'creates a directory' do - result = repository.mkdir(path, commit_options) - expect(result).not_to eq(nil) - - # Verify another mkdir doesn't create a directory that already exists - expect{ repository.mkdir(path, commit_options) }.to raise_error('Directory already exists') - end - end - - describe 'creates a directory in root directory' do - it_should_behave_like 'mkdir diff check', 'new_dir', 'new_dir' - end - - describe 'creates a directory in subdirectory' do - it_should_behave_like 'mkdir diff check', 'files/ruby/test', 'files/ruby/test' - end - - describe 'creates a directory in subdirectory with a slash' do - it_should_behave_like 'mkdir diff check', '/files/ruby/test2', 'files/ruby/test2' - end - - describe 'creates a directory in subdirectory with multiple slashes' do - it_should_behave_like 'mkdir diff check', '//files/ruby/test3', 'files/ruby/test3' - end - - describe 'handles relative paths' do - it_should_behave_like 'mkdir diff check', 'files/ruby/../test_relative', 'files/test_relative' - end - - describe 'creates nested directories' do - it_should_behave_like 'mkdir diff check', 'files/missing/test', 'files/missing/test' - end - - it 'does not attempt to create a directory with invalid relative path' do - expect{ repository.mkdir('../files/missing/test', commit_options) }.to raise_error('Invalid path') - end - - it 'does not attempt to overwrite a file' do - expect{ repository.mkdir('README.md', commit_options) }.to raise_error('Directory already exists as a file') - end - - it 'does not attempt to overwrite a directory' do - expect{ repository.mkdir('files', commit_options) }.to raise_error('Directory already exists') - end - end - describe "#ls_files" do let(:master_file_paths) { repository.ls_files("master") } let(:not_existed_branch) { repository.ls_files("not_existed_branch") } diff --git a/spec/lib/gitlab/git_access_spec.rb b/spec/lib/gitlab/git_access_spec.rb index d37890de9ae..48f7754bed8 100644 --- a/spec/lib/gitlab/git_access_spec.rb +++ b/spec/lib/gitlab/git_access_spec.rb @@ -209,13 +209,12 @@ describe Gitlab::GitAccess, lib: true do stub_git_hooks project.repository.add_branch(user, unprotected_branch, 'feature') target_branch = project.repository.lookup('feature') - source_branch = project.repository.commit_file( + source_branch = project.repository.create_file( user, FFaker::InternetSE.login_user_name, FFaker::HipsterIpsum.paragraph, message: FFaker::HipsterIpsum.sentence, - branch_name: unprotected_branch, - update: false) + branch_name: unprotected_branch) rugged = project.repository.rugged author = { email: "email@example.com", time: Time.now, name: "Example Git User" } diff --git a/spec/lib/gitlab/gitaly_client/notifications_spec.rb b/spec/lib/gitlab/gitaly_client/notifications_spec.rb new file mode 100644 index 00000000000..a6252c99aa1 --- /dev/null +++ b/spec/lib/gitlab/gitaly_client/notifications_spec.rb @@ -0,0 +1,20 @@ +require 'spec_helper' + +describe Gitlab::GitalyClient::Notifications do + let(:client) { Gitlab::GitalyClient::Notifications.new } + + before do + allow(Gitlab.config.gitaly).to receive(:socket_path).and_return('path/to/gitaly.socket') + end + + describe '#post_receive' do + let(:repo_path) { '/path/to/my_repo.git' } + + it 'sends a post_receive message' do + expect_any_instance_of(Gitaly::Notifications::Stub). + to receive(:post_receive).with(post_receive_request_with_repo_path(repo_path)) + + client.post_receive(repo_path) + end + end +end diff --git a/spec/lib/gitlab/import_export/import_export_spec.rb b/spec/lib/gitlab/import_export/import_export_spec.rb index 20743811dab..f3fd0d82875 100644 --- a/spec/lib/gitlab/import_export/import_export_spec.rb +++ b/spec/lib/gitlab/import_export/import_export_spec.rb @@ -10,7 +10,7 @@ describe Gitlab::ImportExport, services: true do end it 'contains the namespace path' do - expect(described_class.export_filename(project: project)).to include(project.namespace.full_path) + expect(described_class.export_filename(project: project)).to include(project.namespace.full_path.tr('/', '_')) end it 'does not go over a certain length' do diff --git a/spec/lib/gitlab/import_export/project.json b/spec/lib/gitlab/import_export/project.json index 2e9f60432b4..c3d5c451a3c 100644 --- a/spec/lib/gitlab/import_export/project.json +++ b/spec/lib/gitlab/import_export/project.json @@ -2539,7 +2539,7 @@ "merge_params": { "force_remove_source_branch": null }, - "merge_when_build_succeeds": true, + "merge_when_pipeline_succeeds": true, "merge_user_id": null, "merge_commit_sha": null, "deleted_at": null, @@ -2976,7 +2976,7 @@ "merge_params": { "force_remove_source_branch": null }, - "merge_when_build_succeeds": false, + "merge_when_pipeline_succeeds": false, "merge_user_id": null, "merge_commit_sha": null, "deleted_at": null, @@ -3260,7 +3260,7 @@ "merge_params": { "force_remove_source_branch": null }, - "merge_when_build_succeeds": false, + "merge_when_pipeline_succeeds": false, "merge_user_id": null, "merge_commit_sha": null, "deleted_at": null, @@ -3544,7 +3544,7 @@ "merge_params": { "force_remove_source_branch": null }, - "merge_when_build_succeeds": false, + "merge_when_pipeline_succeeds": false, "merge_user_id": null, "merge_commit_sha": null, "deleted_at": null, @@ -4234,7 +4234,7 @@ "merge_params": { "force_remove_source_branch": null }, - "merge_when_build_succeeds": false, + "merge_when_pipeline_succeeds": false, "merge_user_id": null, "merge_commit_sha": null, "deleted_at": null, @@ -4782,7 +4782,7 @@ "merge_params": { "force_remove_source_branch": null }, - "merge_when_build_succeeds": false, + "merge_when_pipeline_succeeds": false, "merge_user_id": null, "merge_commit_sha": null, "deleted_at": null, @@ -5281,7 +5281,7 @@ "merge_params": { "force_remove_source_branch": null }, - "merge_when_build_succeeds": false, + "merge_when_pipeline_succeeds": false, "merge_user_id": null, "merge_commit_sha": null, "deleted_at": null, @@ -5541,7 +5541,7 @@ "merge_params": { "force_remove_source_branch": null }, - "merge_when_build_succeeds": false, + "merge_when_pipeline_succeeds": false, "merge_user_id": null, "merge_commit_sha": null, "deleted_at": null, @@ -6231,7 +6231,7 @@ "merge_params": { "force_remove_source_branch": null }, - "merge_when_build_succeeds": false, + "merge_when_pipeline_succeeds": false, "merge_user_id": null, "merge_commit_sha": null, "deleted_at": null, diff --git a/spec/lib/gitlab/import_export/safe_model_attributes.yml b/spec/lib/gitlab/import_export/safe_model_attributes.yml index c5ac702d831..6534902b52d 100644 --- a/spec/lib/gitlab/import_export/safe_model_attributes.yml +++ b/spec/lib/gitlab/import_export/safe_model_attributes.yml @@ -142,7 +142,7 @@ MergeRequest: - updated_by_id - merge_error - merge_params -- merge_when_build_succeeds +- merge_when_pipeline_succeeds - merge_user_id - merge_commit_sha - deleted_at diff --git a/spec/lib/gitlab/regex_spec.rb b/spec/lib/gitlab/regex_spec.rb index 089ec4e2737..ba45e2d758c 100644 --- a/spec/lib/gitlab/regex_spec.rb +++ b/spec/lib/gitlab/regex_spec.rb @@ -51,8 +51,8 @@ describe Gitlab::Regex, lib: true do it { is_expected.not_to match('foo-') } end - describe 'NAMESPACE_REF_REGEX_STR' do - subject { %r{\A#{Gitlab::Regex::NAMESPACE_REF_REGEX_STR}\z} } + describe 'FULL_NAMESPACE_REGEX_STR' do + subject { %r{\A#{Gitlab::Regex::FULL_NAMESPACE_REGEX_STR}\z} } it { is_expected.to match('gitlab.org') } it { is_expected.to match('gitlab.org/gitlab-git') } diff --git a/spec/models/abuse_report_spec.rb b/spec/models/abuse_report_spec.rb index c4486a32082..4e71597521d 100644 --- a/spec/models/abuse_report_spec.rb +++ b/spec/models/abuse_report_spec.rb @@ -2,7 +2,7 @@ require 'rails_helper' RSpec.describe AbuseReport, type: :model do subject { create(:abuse_report) } - let(:user) { create(:user) } + let(:user) { create(:admin) } it { expect(subject).to be_valid } diff --git a/spec/models/application_setting_spec.rb b/spec/models/application_setting_spec.rb index 4086e00e363..01ca1584ed2 100644 --- a/spec/models/application_setting_spec.rb +++ b/spec/models/application_setting_spec.rb @@ -29,6 +29,40 @@ describe ApplicationSetting, models: true do it { is_expected.not_to allow_value(['test']).for(:disabled_oauth_sign_in_sources) } end + describe 'default_artifacts_expire_in' do + it 'sets an error if it cannot parse' do + setting.update(default_artifacts_expire_in: 'a') + + expect_invalid + end + + it 'sets an error if it is blank' do + setting.update(default_artifacts_expire_in: ' ') + + expect_invalid + end + + it 'sets the value if it is valid' do + setting.update(default_artifacts_expire_in: '30 days') + + expect(setting).to be_valid + expect(setting.default_artifacts_expire_in).to eq('30 days') + end + + it 'sets the value if it is 0' do + setting.update(default_artifacts_expire_in: '0') + + expect(setting).to be_valid + expect(setting.default_artifacts_expire_in).to eq('0') + end + + def expect_invalid + expect(setting).to be_invalid + expect(setting.errors.messages) + .to have_key(:default_artifacts_expire_in) + end + end + it { is_expected.to validate_presence_of(:max_attachment_size) } it do diff --git a/spec/models/ci/build_spec.rb b/spec/models/ci/build_spec.rb index 63b6c3c65a6..5743c555cbe 100644 --- a/spec/models/ci/build_spec.rb +++ b/spec/models/ci/build_spec.rb @@ -162,11 +162,17 @@ describe Ci::Build, :models do is_expected.to be_nil end - it 'when resseting value' do + it 'when resetting value' do build.artifacts_expire_in = nil is_expected.to be_nil end + + it 'when setting to 0' do + build.artifacts_expire_in = '0' + + is_expected.to be_nil + end end describe '#commit' do @@ -175,20 +181,6 @@ describe Ci::Build, :models do end end - describe '#create_from' do - before do - build.status = 'success' - build.save - end - let(:create_from_build) { Ci::Build.create_from build } - - it 'exists a pending task' do - expect(Ci::Build.pending.count(:all)).to eq 0 - create_from_build - expect(Ci::Build.pending.count(:all)).to be > 0 - end - end - describe '#depends_on_builds' do let!(:build) { create(:ci_build, pipeline: pipeline, name: 'build', stage_idx: 0, stage: 'build') } let!(:rspec_test) { create(:ci_build, pipeline: pipeline, name: 'rspec', stage_idx: 1, stage: 'test') } @@ -1239,8 +1231,8 @@ describe Ci::Build, :models do { key: 'CI_SERVER_REVISION', value: Gitlab::REVISION, public: true }, { key: 'CI_PROJECT_ID', value: project.id.to_s, public: true }, { key: 'CI_PROJECT_NAME', value: project.path, public: true }, - { key: 'CI_PROJECT_PATH', value: project.path_with_namespace, public: true }, - { key: 'CI_PROJECT_NAMESPACE', value: project.namespace.path, public: true }, + { key: 'CI_PROJECT_PATH', value: project.full_path, public: true }, + { key: 'CI_PROJECT_NAMESPACE', value: project.namespace.full_path, public: true }, { key: 'CI_PROJECT_URL', value: project.web_url, public: true }, { key: 'CI_PIPELINE_ID', value: pipeline.id.to_s, public: true } ] diff --git a/spec/models/concerns/routable_spec.rb b/spec/models/concerns/routable_spec.rb index e008ec28fa4..677e60e1282 100644 --- a/spec/models/concerns/routable_spec.rb +++ b/spec/models/concerns/routable_spec.rb @@ -86,7 +86,7 @@ describe Group, 'Routable' do let(:nested_group) { create(:group, parent: group) } it { expect(group.full_path).to eq(group.path) } - it { expect(nested_group.full_path).to eq("#{group.path}/#{nested_group.path}") } + it { expect(nested_group.full_path).to eq("#{group.full_path}/#{nested_group.path}") } end describe '#full_name' do @@ -102,7 +102,7 @@ describe Project, 'Routable' do describe '#full_path' do let(:project) { build_stubbed(:empty_project) } - it { expect(project.full_path).to eq "#{project.namespace.path}/#{project.path}" } + it { expect(project.full_path).to eq "#{project.namespace.full_path}/#{project.path}" } end describe '#full_name' do diff --git a/spec/models/concerns/uniquify_spec.rb b/spec/models/concerns/uniquify_spec.rb new file mode 100644 index 00000000000..83187d732e4 --- /dev/null +++ b/spec/models/concerns/uniquify_spec.rb @@ -0,0 +1,33 @@ +require 'spec_helper' + +describe Uniquify, models: true do + let(:uniquify) { described_class.new } + + describe "#string" do + it 'returns the given string if it does not exist' do + result = uniquify.string('test_string') { |s| false } + + expect(result).to eq('test_string') + end + + it 'returns the given string with a counter attached if the string exists' do + result = uniquify.string('test_string') { |s| s == 'test_string' } + + expect(result).to eq('test_string1') + end + + it 'increments the counter for each candidate string that also exists' do + result = uniquify.string('test_string') { |s| s == 'test_string' || s == 'test_string1' } + + expect(result).to eq('test_string2') + end + + it 'allows passing in a base function that defines the location of the counter' do + result = uniquify.string(-> (counter) { "test_#{counter}_string" }) do |s| + s == 'test__string' + end + + expect(result).to eq('test_1_string') + end + end +end diff --git a/spec/models/cycle_analytics/production_spec.rb b/spec/models/cycle_analytics/production_spec.rb index b9fe492fe2c..e6a826a9418 100644 --- a/spec/models/cycle_analytics/production_spec.rb +++ b/spec/models/cycle_analytics/production_spec.rb @@ -21,13 +21,12 @@ describe 'CycleAnalytics#production', feature: true do ["production deploy happens after merge request is merged (along with other changes)", lambda do |context, data| # Make other changes on master - sha = context.project.repository.commit_file( + sha = context.project.repository.create_file( context.user, context.random_git_name, 'content', message: 'commit message', - branch_name: 'master', - update: false) + branch_name: 'master') context.project.repository.commit(sha) context.deploy_master diff --git a/spec/models/cycle_analytics/staging_spec.rb b/spec/models/cycle_analytics/staging_spec.rb index 78ec518ac86..3a02ed81adb 100644 --- a/spec/models/cycle_analytics/staging_spec.rb +++ b/spec/models/cycle_analytics/staging_spec.rb @@ -26,13 +26,12 @@ describe 'CycleAnalytics#staging', feature: true do ["production deploy happens after merge request is merged (along with other changes)", lambda do |context, data| # Make other changes on master - sha = context.project.repository.commit_file( + sha = context.project.repository.create_file( context.user, context.random_git_name, 'content', message: 'commit message', - branch_name: 'master', - update: false) + branch_name: 'master') context.project.repository.commit(sha) context.deploy_master diff --git a/spec/models/merge_request_spec.rb b/spec/models/merge_request_spec.rb index fa1b0396bcf..e000d0d38b3 100644 --- a/spec/models/merge_request_spec.rb +++ b/spec/models/merge_request_spec.rb @@ -37,12 +37,12 @@ describe MergeRequest, models: true do end it "is invalid without merge user" do - subject.merge_when_build_succeeds = true + subject.merge_when_pipeline_succeeds = true expect(subject).not_to be_valid end it "is valid with merge user" do - subject.merge_when_build_succeeds = true + subject.merge_when_pipeline_succeeds = true subject.merge_user = build(:user) expect(subject).to be_valid @@ -55,7 +55,7 @@ describe MergeRequest, models: true do it { is_expected.to respond_to(:can_be_merged?) } it { is_expected.to respond_to(:cannot_be_merged?) } it { is_expected.to respond_to(:merge_params) } - it { is_expected.to respond_to(:merge_when_build_succeeds) } + it { is_expected.to respond_to(:merge_when_pipeline_succeeds) } end describe '.in_projects' do @@ -508,17 +508,17 @@ describe MergeRequest, models: true do end end - describe "#reset_merge_when_build_succeeds" do + describe "#reset_merge_when_pipeline_succeeds" do let(:merge_if_green) do - create :merge_request, merge_when_build_succeeds: true, merge_user: create(:user), + create :merge_request, merge_when_pipeline_succeeds: true, merge_user: create(:user), merge_params: { "should_remove_source_branch" => "1", "commit_message" => "msg" } end it "sets the item to false" do - merge_if_green.reset_merge_when_build_succeeds + merge_if_green.reset_merge_when_pipeline_succeeds merge_if_green.reload - expect(merge_if_green.merge_when_build_succeeds).to be_falsey + expect(merge_if_green.merge_when_pipeline_succeeds).to be_falsey expect(merge_if_green.merge_params["should_remove_source_branch"]).to be_nil expect(merge_if_green.merge_params["commit_message"]).to be_nil end @@ -812,7 +812,7 @@ describe MergeRequest, models: true do end describe '#check_if_can_be_merged' do - let(:project) { create(:empty_project, only_allow_merge_if_build_succeeds: true) } + let(:project) { create(:empty_project, only_allow_merge_if_pipeline_succeeds: true) } subject { create(:merge_request, source_project: project, merge_status: :unchecked) } @@ -833,12 +833,6 @@ describe MergeRequest, models: true do it 'becomes unmergeable' do expect { subject.check_if_can_be_merged }.to change { subject.merge_status }.to('cannot_be_merged') end - - it 'creates Todo on unmergeability' do - expect_any_instance_of(TodoService).to receive(:merge_request_became_unmergeable).with(subject) - - subject.check_if_can_be_merged - end end context 'when it has conflicts' do @@ -933,7 +927,7 @@ describe MergeRequest, models: true do end describe '#mergeable_ci_state?' do - let(:project) { create(:empty_project, only_allow_merge_if_build_succeeds: true) } + let(:project) { create(:empty_project, only_allow_merge_if_pipeline_succeeds: true) } let(:pipeline) { create(:ci_empty_pipeline) } subject { build(:merge_request, target_project: project) } @@ -976,7 +970,7 @@ describe MergeRequest, models: true do end context 'when merges are not restricted to green builds' do - subject { build(:merge_request, target_project: build(:empty_project, only_allow_merge_if_build_succeeds: false)) } + subject { build(:merge_request, target_project: build(:empty_project, only_allow_merge_if_pipeline_succeeds: false)) } context 'and a failed pipeline is associated' do before do @@ -1581,7 +1575,7 @@ describe MergeRequest, models: true do status: status) end - let(:project) { create(:project, :public, :repository, only_allow_merge_if_build_succeeds: true) } + let(:project) { create(:project, :public, :repository, only_allow_merge_if_pipeline_succeeds: true) } let(:developer) { create(:user) } let(:user) { create(:user) } let(:merge_request) { create(:merge_request, source_project: project) } diff --git a/spec/models/namespace_spec.rb b/spec/models/namespace_spec.rb index 35d932f1c64..3f9c4289de9 100644 --- a/spec/models/namespace_spec.rb +++ b/spec/models/namespace_spec.rb @@ -36,7 +36,7 @@ describe Namespace, models: true do end describe '#to_param' do - it { expect(namespace.to_param).to eq(namespace.path) } + it { expect(namespace.to_param).to eq(namespace.full_path) } end describe '#human_name' do @@ -151,7 +151,7 @@ describe Namespace, models: true do describe :rm_dir do let!(:project) { create(:empty_project, namespace: namespace) } - let!(:path) { File.join(Gitlab.config.repositories.storages.default, namespace.path) } + let!(:path) { File.join(Gitlab.config.repositories.storages.default, namespace.full_path) } it "removes its dirs when deleted" do namespace.destroy diff --git a/spec/models/project_group_link_spec.rb b/spec/models/project_group_link_spec.rb index 59a4ae1b799..9b711bfc007 100644 --- a/spec/models/project_group_link_spec.rb +++ b/spec/models/project_group_link_spec.rb @@ -7,12 +7,27 @@ describe ProjectGroupLink do end describe "Validation" do - let!(:project_group_link) { create(:project_group_link) } + let(:parent_group) { create(:group) } + let(:group) { create(:group, parent: parent_group) } + let(:project) { create(:project, group: group) } + let!(:project_group_link) { create(:project_group_link, project: project) } it { should validate_presence_of(:project_id) } it { should validate_uniqueness_of(:group_id).scoped_to(:project_id).with_message(/already shared/) } it { should validate_presence_of(:group) } it { should validate_presence_of(:group_access) } + + it "doesn't allow a project to be shared with the group it is in" do + project_group_link.group = group + + expect(project_group_link).not_to be_valid + end + + it "doesn't allow a project to be shared with an ancestor of the group it is in" do + project_group_link.group = parent_group + + expect(project_group_link).not_to be_valid + end end describe "destroying a record", truncate: true do diff --git a/spec/models/project_services/drone_ci_service_spec.rb b/spec/models/project_services/drone_ci_service_spec.rb index 47ca802ebc2..044737c6026 100644 --- a/spec/models/project_services/drone_ci_service_spec.rb +++ b/spec/models/project_services/drone_ci_service_spec.rb @@ -28,7 +28,7 @@ describe DroneCiService, models: true, caching: true do shared_context :drone_ci_service do let(:drone) { DroneCiService.new } let(:project) { create(:project, :repository, name: 'project') } - let(:path) { "#{project.namespace.path}/#{project.path}" } + let(:path) { project.full_path } let(:drone_url) { 'http://drone.example.com' } let(:sha) { '2ab7834c' } let(:branch) { 'dev' } diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb index b0087a9e15d..ee4f4092062 100644 --- a/spec/models/project_spec.rb +++ b/spec/models/project_spec.rb @@ -402,7 +402,7 @@ describe Project, models: true do let(:project) { create(:empty_project, path: "somewhere") } it 'returns the full web URL for this repo' do - expect(project.web_url).to eq("#{Gitlab.config.gitlab.url}/#{project.namespace.path}/somewhere") + expect(project.web_url).to eq("#{Gitlab.config.gitlab.url}/#{project.namespace.full_path}/somewhere") end end @@ -803,7 +803,7 @@ describe Project, models: true do end let(:avatar_path) do - "/#{project.namespace.name}/#{project.path}/avatar" + "/#{project.full_path}/avatar" end it { should eq "http://#{Gitlab.config.gitlab.host}#{avatar_path}" } @@ -1148,16 +1148,14 @@ describe Project, models: true do end it 'renames a repository' do - ns = project.namespace_dir - expect(gitlab_shell).to receive(:mv_repository). ordered. - with(project.repository_storage_path, "#{ns}/foo", "#{ns}/#{project.path}"). + with(project.repository_storage_path, "#{project.namespace.full_path}/foo", "#{project.full_path}"). and_return(true) expect(gitlab_shell).to receive(:mv_repository). ordered. - with(project.repository_storage_path, "#{ns}/foo.wiki", "#{ns}/#{project.path}.wiki"). + with(project.repository_storage_path, "#{project.namespace.full_path}/foo.wiki", "#{project.full_path}.wiki"). and_return(true) expect_any_instance_of(SystemHooksService). @@ -1166,7 +1164,7 @@ describe Project, models: true do expect_any_instance_of(Gitlab::UploadsTransfer). to receive(:rename_project). - with('foo', project.path, ns) + with('foo', project.path, project.namespace.full_path) expect(project).to receive(:expire_caches_before_rename) @@ -1538,7 +1536,7 @@ describe Project, models: true do it 'schedules a RepositoryForkWorker job' do expect(RepositoryForkWorker).to receive(:perform_async). with(project.id, forked_from_project.repository_storage_path, - forked_from_project.path_with_namespace, project.namespace.path) + forked_from_project.path_with_namespace, project.namespace.full_path) project.add_import_job end @@ -1752,7 +1750,7 @@ describe Project, models: true do describe 'inside_path' do let!(:project1) { create(:empty_project) } let!(:project2) { create(:empty_project) } - let!(:path) { project1.namespace.path } + let!(:path) { project1.namespace.full_path } it { expect(Project.inside_path(path)).to eq([project1]) } end @@ -1767,7 +1765,7 @@ describe Project, models: true do end before do - project.repository.commit_file(User.last, '.gitlab/route-map.yml', route_map, message: 'Add .gitlab/route-map.yml', branch_name: 'master', update: false) + project.repository.create_file(User.last, '.gitlab/route-map.yml', route_map, message: 'Add .gitlab/route-map.yml', branch_name: 'master') end context 'when there is a .gitlab/route-map.yml at the commit' do @@ -1896,4 +1894,25 @@ describe Project, models: true do end end end + + describe '#http_url_to_repo' do + let(:project) { create :empty_project } + + context 'when no user is given' do + it 'returns the url to the repo without a username' do + url = project.http_url_to_repo + + expect(url).to eq(project.http_url_to_repo) + expect(url).not_to include('@') + end + end + + context 'when user is given' do + it 'returns the url to the repo with the username' do + user = build_stubbed(:user) + + expect(project.http_url_to_repo(user)).to match(%r{https?:\/\/#{user.username}@}) + end + end + end end diff --git a/spec/models/repository_spec.rb b/spec/models/repository_spec.rb index 43aac31d8b7..ae203fada12 100644 --- a/spec/models/repository_spec.rb +++ b/spec/models/repository_spec.rb @@ -291,10 +291,10 @@ describe Repository, models: true do end end - describe "#commit_dir" do + describe "#create_dir" do it "commits a change that creates a new directory" do expect do - repository.commit_dir(user, 'newdir', + repository.create_dir(user, 'newdir', message: 'Create newdir', branch_name: 'master') end.to change { repository.commits('master').count }.by(1) @@ -307,7 +307,7 @@ describe Repository, models: true do it "creates a fork and commit to the forked project" do expect do - repository.commit_dir(user, 'newdir', + repository.create_dir(user, 'newdir', message: 'Create newdir', branch_name: 'patch', start_branch_name: 'master', start_project: forked_project) end.to change { repository.commits('master').count }.by(0) @@ -323,7 +323,7 @@ describe Repository, models: true do context "when an author is specified" do it "uses the given email/name to set the commit's author" do expect do - repository.commit_dir(user, 'newdir', + repository.create_dir(user, 'newdir', message: 'Add newdir', branch_name: 'master', author_email: author_email, author_name: author_name) @@ -337,25 +337,23 @@ describe Repository, models: true do end end - describe "#commit_file" do - it 'commits change to a file successfully' do + describe "#create_file" do + it 'commits new file successfully' do expect do - repository.commit_file(user, 'CHANGELOG', 'Changelog!', - message: 'Updates file content', - branch_name: 'master', - update: true) + repository.create_file(user, 'NEWCHANGELOG', 'Changelog!', + message: 'Create changelog', + branch_name: 'master') end.to change { repository.commits('master').count }.by(1) - blob = repository.blob_at('master', 'CHANGELOG') + blob = repository.blob_at('master', 'NEWCHANGELOG') expect(blob.data).to eq('Changelog!') end it 'respects the autocrlf setting' do - repository.commit_file(user, 'hello.txt', "Hello,\r\nWorld", + repository.create_file(user, 'hello.txt', "Hello,\r\nWorld", message: 'Add hello world', - branch_name: 'master', - update: true) + branch_name: 'master') blob = repository.blob_at('master', 'hello.txt') @@ -365,10 +363,9 @@ describe Repository, models: true do context "when an author is specified" do it "uses the given email/name to set the commit's author" do expect do - repository.commit_file(user, 'README', 'README!', + repository.create_file(user, 'NEWREADME', 'README!', message: 'Add README', branch_name: 'master', - update: true, author_email: author_email, author_name: author_name) end.to change { repository.commits('master').count }.by(1) @@ -382,6 +379,18 @@ describe Repository, models: true do end describe "#update_file" do + it 'updates file successfully' do + expect do + repository.update_file(user, 'CHANGELOG', 'Changelog!', + message: 'Update changelog', + branch_name: 'master') + end.to change { repository.commits('master').count }.by(1) + + blob = repository.blob_at('master', 'CHANGELOG') + + expect(blob.data).to eq('Changelog!') + end + it 'updates filename successfully' do expect do repository.update_file(user, 'NEWLICENSE', 'Copyright!', @@ -398,9 +407,6 @@ describe Repository, models: true do context "when an author is specified" do it "uses the given email/name to set the commit's author" do - repository.commit_file(user, 'README', 'README!', - message: 'Add README', branch_name: 'master', update: true) - expect do repository.update_file(user, 'README', 'Updated README!', branch_name: 'master', @@ -418,13 +424,10 @@ describe Repository, models: true do end end - describe "#remove_file" do + describe "#delete_file" do it 'removes file successfully' do - repository.commit_file(user, 'README', 'README!', - message: 'Add README', branch_name: 'master', update: true) - expect do - repository.remove_file(user, 'README', + repository.delete_file(user, 'README', message: 'Remove README', branch_name: 'master') end.to change { repository.commits('master').count }.by(1) @@ -433,11 +436,8 @@ describe Repository, models: true do context "when an author is specified" do it "uses the given email/name to set the commit's author" do - repository.commit_file(user, 'README', 'README!', - message: 'Add README', branch_name: 'master', update: true) - expect do - repository.remove_file(user, 'README', + repository.delete_file(user, 'README', message: 'Remove README', branch_name: 'master', author_email: author_email, author_name: author_name) end.to change { repository.commits('master').count }.by(1) @@ -587,14 +587,14 @@ describe Repository, models: true do describe "#license_blob", caching: true do before do - repository.remove_file( + repository.delete_file( user, 'LICENSE', message: 'Remove LICENSE', branch_name: 'master') end it 'handles when HEAD points to non-existent ref' do - repository.commit_file( + repository.create_file( user, 'LICENSE', 'Copyright!', - message: 'Add LICENSE', branch_name: 'master', update: false) + message: 'Add LICENSE', branch_name: 'master') allow(repository).to receive(:file_on_head). and_raise(Rugged::ReferenceError) @@ -603,27 +603,27 @@ describe Repository, models: true do end it 'looks in the root_ref only' do - repository.remove_file(user, 'LICENSE', + repository.delete_file(user, 'LICENSE', message: 'Remove LICENSE', branch_name: 'markdown') - repository.commit_file(user, 'LICENSE', + repository.create_file(user, 'LICENSE', Licensee::License.new('mit').content, - message: 'Add LICENSE', branch_name: 'markdown', update: false) + message: 'Add LICENSE', branch_name: 'markdown') expect(repository.license_blob).to be_nil end it 'detects license file with no recognizable open-source license content' do - repository.commit_file(user, 'LICENSE', 'Copyright!', - message: 'Add LICENSE', branch_name: 'master', update: false) + repository.create_file(user, 'LICENSE', 'Copyright!', + message: 'Add LICENSE', branch_name: 'master') expect(repository.license_blob.name).to eq('LICENSE') end %w[LICENSE LICENCE LiCensE LICENSE.md LICENSE.foo COPYING COPYING.md].each do |filename| it "detects '#{filename}'" do - repository.commit_file(user, filename, + repository.create_file(user, filename, Licensee::License.new('mit').content, - message: "Add #{filename}", branch_name: 'master', update: false) + message: "Add #{filename}", branch_name: 'master') expect(repository.license_blob.name).to eq(filename) end @@ -632,7 +632,7 @@ describe Repository, models: true do describe '#license_key', caching: true do before do - repository.remove_file(user, 'LICENSE', + repository.delete_file(user, 'LICENSE', message: 'Remove LICENSE', branch_name: 'master') end @@ -647,16 +647,16 @@ describe Repository, models: true do end it 'detects license file with no recognizable open-source license content' do - repository.commit_file(user, 'LICENSE', 'Copyright!', - message: 'Add LICENSE', branch_name: 'master', update: false) + repository.create_file(user, 'LICENSE', 'Copyright!', + message: 'Add LICENSE', branch_name: 'master') expect(repository.license_key).to be_nil end it 'returns the license key' do - repository.commit_file(user, 'LICENSE', + repository.create_file(user, 'LICENSE', Licensee::License.new('mit').content, - message: 'Add LICENSE', branch_name: 'master', update: false) + message: 'Add LICENSE', branch_name: 'master') expect(repository.license_key).to eq('mit') end @@ -913,10 +913,9 @@ describe Repository, models: true do expect(empty_repository).to receive(:expire_emptiness_caches) expect(empty_repository).to receive(:expire_branches_cache) - empty_repository.commit_file(user, 'CHANGELOG', 'Changelog!', + empty_repository.create_file(user, 'CHANGELOG', 'Changelog!', message: 'Updates file content', - branch_name: 'master', - update: false) + branch_name: 'master') end end end @@ -1796,7 +1795,7 @@ describe Repository, models: true do describe '#gitlab_ci_yml_for' do before do - repository.commit_file(User.last, '.gitlab-ci.yml', 'CONTENT', message: 'Add .gitlab-ci.yml', branch_name: 'master', update: false) + repository.create_file(User.last, '.gitlab-ci.yml', 'CONTENT', message: 'Add .gitlab-ci.yml', branch_name: 'master') end context 'when there is a .gitlab-ci.yml at the commit' do @@ -1814,7 +1813,7 @@ describe Repository, models: true do describe '#route_map_for' do before do - repository.commit_file(User.last, '.gitlab/route-map.yml', 'CONTENT', message: 'Add .gitlab/route-map.yml', branch_name: 'master', update: false) + repository.create_file(User.last, '.gitlab/route-map.yml', 'CONTENT', message: 'Add .gitlab/route-map.yml', branch_name: 'master') end context 'when there is a .gitlab/route-map.yml at the commit' do diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb index b69fd24c586..e86b4a761d9 100644 --- a/spec/models/user_spec.rb +++ b/spec/models/user_spec.rb @@ -22,7 +22,7 @@ describe User, models: true do it { is_expected.to have_many(:deploy_keys).dependent(:destroy) } it { is_expected.to have_many(:events).dependent(:destroy) } it { is_expected.to have_many(:recent_events).class_name('Event') } - it { is_expected.to have_many(:issues).dependent(:destroy) } + it { is_expected.to have_many(:issues).dependent(:restrict_with_exception) } it { is_expected.to have_many(:notes).dependent(:destroy) } it { is_expected.to have_many(:assigned_issues).dependent(:nullify) } it { is_expected.to have_many(:merge_requests).dependent(:destroy) } @@ -208,6 +208,22 @@ describe User, models: true do end end end + + describe 'ghost users' do + it 'does not allow a non-blocked ghost user' do + user = build(:user, :ghost) + user.state = 'active' + + expect(user).to be_invalid + end + + it 'allows a blocked ghost user' do + user = build(:user, :ghost) + user.state = 'blocked' + + expect(user).to be_valid + end + end end describe "scopes" do @@ -1413,7 +1429,7 @@ describe User, models: true do it { expect(user.nested_groups).to eq([nested_group]) } end - describe '#nested_projects' do + describe '#nested_groups_projects' do let!(:user) { create(:user) } let!(:group) { create(:group) } let!(:nested_group) { create(:group, parent: group) } @@ -1428,7 +1444,7 @@ describe User, models: true do other_project.add_developer(create(:user)) end - it { expect(user.nested_projects).to eq([nested_project]) } + it { expect(user.nested_groups_projects).to eq([nested_project]) } end describe '#refresh_authorized_projects', redis: true do @@ -1490,4 +1506,41 @@ describe User, models: true do expect(user.admin).to be true end end + + describe '.ghost' do + it "creates a ghost user if one isn't already present" do + ghost = User.ghost + + expect(ghost).to be_ghost + expect(ghost).to be_persisted + end + + it "does not create a second ghost user if one is already present" do + expect do + User.ghost + User.ghost + end.to change { User.count }.by(1) + expect(User.ghost).to eq(User.ghost) + end + + context "when a regular user exists with the username 'ghost'" do + it "creates a ghost user with a non-conflicting username" do + create(:user, username: 'ghost') + ghost = User.ghost + + expect(ghost).to be_persisted + expect(ghost.username).to eq('ghost1') + end + end + + context "when a regular user exists with the email 'ghost@example.com'" do + it "creates a ghost user with a non-conflicting email" do + create(:user, email: 'ghost@example.com') + ghost = User.ghost + + expect(ghost).to be_persisted + expect(ghost.email).to eq('ghost1@example.com') + end + end + end end diff --git a/spec/policies/user_policy_spec.rb b/spec/policies/user_policy_spec.rb new file mode 100644 index 00000000000..d5761390d39 --- /dev/null +++ b/spec/policies/user_policy_spec.rb @@ -0,0 +1,37 @@ +require 'spec_helper' + +describe UserPolicy, models: true do + let(:current_user) { create(:user) } + let(:user) { create(:user) } + + subject { described_class.abilities(current_user, user).to_set } + + describe "reading a user's information" do + it { is_expected.to include(:read_user) } + end + + describe "destroying a user" do + context "when a regular user tries to destroy another regular user" do + it { is_expected.not_to include(:destroy_user) } + end + + context "when a regular user tries to destroy themselves" do + let(:current_user) { user } + + it { is_expected.to include(:destroy_user) } + end + + context "when an admin user tries to destroy a regular user" do + let(:current_user) { create(:user, :admin) } + + it { is_expected.to include(:destroy_user) } + end + + context "when an admin user tries to destroy a ghost user" do + let(:current_user) { create(:user, :admin) } + let(:user) { create(:user, :ghost) } + + it { is_expected.not_to include(:destroy_user) } + end + end +end diff --git a/spec/requests/api/access_requests_spec.rb b/spec/requests/api/access_requests_spec.rb index 919c98d6437..46edbd49b28 100644 --- a/spec/requests/api/access_requests_spec.rb +++ b/spec/requests/api/access_requests_spec.rb @@ -200,7 +200,7 @@ describe API::AccessRequests, api: true do expect do delete api("/#{source_type.pluralize}/#{source.id}/access_requests/#{access_requester.id}", access_requester) - expect(response).to have_http_status(200) + expect(response).to have_http_status(204) end.to change { source.requesters.count }.by(-1) end end @@ -210,7 +210,7 @@ describe API::AccessRequests, api: true do expect do delete api("/#{source_type.pluralize}/#{source.id}/access_requests/#{access_requester.id}", master) - expect(response).to have_http_status(200) + expect(response).to have_http_status(204) end.to change { source.requesters.count }.by(-1) end diff --git a/spec/requests/api/award_emoji_spec.rb b/spec/requests/api/award_emoji_spec.rb index 6cc1ef315db..9756991162e 100644 --- a/spec/requests/api/award_emoji_spec.rb +++ b/spec/requests/api/award_emoji_spec.rb @@ -242,9 +242,9 @@ describe API::AwardEmoji, api: true do it 'deletes the award' do expect do delete api("/projects/#{project.id}/issues/#{issue.id}/award_emoji/#{award_emoji.id}", user) - end.to change { issue.award_emoji.count }.from(1).to(0) - expect(response).to have_http_status(200) + expect(response).to have_http_status(204) + end.to change { issue.award_emoji.count }.from(1).to(0) end it 'returns a 404 error when the award emoji can not be found' do @@ -258,9 +258,9 @@ describe API::AwardEmoji, api: true do it 'deletes the award' do expect do delete api("/projects/#{project.id}/merge_requests/#{merge_request.id}/award_emoji/#{downvote.id}", user) - end.to change { merge_request.award_emoji.count }.from(1).to(0) - expect(response).to have_http_status(200) + expect(response).to have_http_status(204) + end.to change { merge_request.award_emoji.count }.from(1).to(0) end it 'returns a 404 error when note id not found' do @@ -277,9 +277,9 @@ describe API::AwardEmoji, api: true do it 'deletes the award' do expect do delete api("/projects/#{project.id}/snippets/#{snippet.id}/award_emoji/#{award.id}", user) - end.to change { snippet.award_emoji.count }.from(1).to(0) - expect(response).to have_http_status(200) + expect(response).to have_http_status(204) + end.to change { snippet.award_emoji.count }.from(1).to(0) end end end @@ -290,9 +290,9 @@ describe API::AwardEmoji, api: true do it 'deletes the award' do expect do delete api("/projects/#{project.id}/issues/#{issue.id}/notes/#{note.id}/award_emoji/#{rocket.id}", user) - end.to change { note.award_emoji.count }.from(1).to(0) - expect(response).to have_http_status(200) + expect(response).to have_http_status(204) + end.to change { note.award_emoji.count }.from(1).to(0) end end end diff --git a/spec/requests/api/boards_spec.rb b/spec/requests/api/boards_spec.rb index 71df534ebe1..87c36639cd4 100644 --- a/spec/requests/api/boards_spec.rb +++ b/spec/requests/api/boards_spec.rb @@ -195,8 +195,7 @@ describe API::Boards, api: true do it "deletes the list if an admin requests it" do delete api("#{base_url}/#{dev_list.id}", owner) - expect(response).to have_http_status(200) - expect(json_response['position']).to eq(1) + expect(response).to have_http_status(204) end end end diff --git a/spec/requests/api/branches_spec.rb b/spec/requests/api/branches_spec.rb index 5571f6cc107..ab5a7e4d3de 100644 --- a/spec/requests/api/branches_spec.rb +++ b/spec/requests/api/branches_spec.rb @@ -325,15 +325,14 @@ describe API::Branches, api: true do it "removes branch" do delete api("/projects/#{project.id}/repository/branches/#{branch_name}", user) - expect(response).to have_http_status(200) - expect(json_response['branch']).to eq(branch_name) + + expect(response).to have_http_status(204) end it "removes a branch with dots in the branch name" do delete api("/projects/#{project.id}/repository/branches/with.1.2.3", user) - expect(response).to have_http_status(200) - expect(json_response['branch']).to eq("with.1.2.3") + expect(response).to have_http_status(204) end it 'returns 404 if branch not exists' do @@ -360,9 +359,11 @@ describe API::Branches, api: true do allow_any_instance_of(Repository).to receive(:rm_branch).and_return(true) end - it 'returns 200' do + it 'returns 202 with json body' do delete api("/projects/#{project.id}/repository/merged_branches", user) - expect(response).to have_http_status(200) + + expect(response).to have_http_status(202) + expect(json_response['message']).to eql('202 Accepted') end it 'returns a 403 error if guest' do diff --git a/spec/requests/api/broadcast_messages_spec.rb b/spec/requests/api/broadcast_messages_spec.rb index 921d8714173..024fa66848c 100644 --- a/spec/requests/api/broadcast_messages_spec.rb +++ b/spec/requests/api/broadcast_messages_spec.rb @@ -174,8 +174,11 @@ describe API::BroadcastMessages, api: true do end it 'deletes the broadcast message for admins' do - expect { delete api("/broadcast_messages/#{message.id}", admin) } - .to change { BroadcastMessage.count }.by(-1) + expect do + delete api("/broadcast_messages/#{message.id}", admin) + + expect(response).to have_http_status(204) + end.to change { BroadcastMessage.count }.by(-1) end end end diff --git a/spec/requests/api/commits_spec.rb b/spec/requests/api/commits_spec.rb index 8b3dfedc5a9..5190fcca2d1 100644 --- a/spec/requests/api/commits_spec.rb +++ b/spec/requests/api/commits_spec.rb @@ -148,7 +148,7 @@ describe API::Commits, api: true do end context 'with project path in URL' do - let(:url) { "/projects/#{project.namespace.path}%2F#{project.path}/repository/commits" } + let(:url) { "/projects/#{project.full_path.gsub('/', '%2F')}/repository/commits" } it 'a new file in project repo' do post api(url, user), valid_c_params diff --git a/spec/requests/api/deploy_keys_spec.rb b/spec/requests/api/deploy_keys_spec.rb index 7e682e91bd1..4f4b18cf0e0 100644 --- a/spec/requests/api/deploy_keys_spec.rb +++ b/spec/requests/api/deploy_keys_spec.rb @@ -116,6 +116,8 @@ describe API::DeployKeys, api: true do it 'should delete existing key' do expect do delete api("/projects/#{project.id}/deploy_keys/#{deploy_key.id}", admin) + + expect(response).to have_http_status(204) end.to change{ project.deploy_keys.count }.by(-1) end diff --git a/spec/requests/api/environments_spec.rb b/spec/requests/api/environments_spec.rb index d0958d39d44..8aac0546513 100644 --- a/spec/requests/api/environments_spec.rb +++ b/spec/requests/api/environments_spec.rb @@ -122,7 +122,7 @@ describe API::Environments, api: true do it 'returns a 200 for an existing environment' do delete api("/projects/#{project.id}/environments/#{environment.id}", user) - expect(response).to have_http_status(200) + expect(response).to have_http_status(204) end it 'returns a 404 for non existing id' do @@ -141,4 +141,39 @@ describe API::Environments, api: true do end end end + + describe 'POST /projects/:id/environments/:environment_id/stop' do + context 'as a master' do + context 'with a stoppable environment' do + before do + environment.update(state: :available) + + post api("/projects/#{project.id}/environments/#{environment.id}/stop", user) + end + + it 'returns a 200' do + expect(response).to have_http_status(200) + end + + it 'actually stops the environment' do + expect(environment.reload).to be_stopped + end + end + + it 'returns a 404 for non existing id' do + post api("/projects/#{project.id}/environments/12345/stop", user) + + expect(response).to have_http_status(404) + expect(json_response['message']).to eq('404 Not found') + end + end + + context 'a non member' do + it 'rejects the request' do + post api("/projects/#{project.id}/environments/#{environment.id}/stop", non_member) + + expect(response).to have_http_status(404) + end + end + end end diff --git a/spec/requests/api/files_spec.rb b/spec/requests/api/files_spec.rb index a8ce0430401..31b1aca6d73 100644 --- a/spec/requests/api/files_spec.rb +++ b/spec/requests/api/files_spec.rb @@ -127,7 +127,7 @@ describe API::Files, api: true do end it "returns a 400 if editor fails to create file" do - allow_any_instance_of(Repository).to receive(:commit_file). + allow_any_instance_of(Repository).to receive(:create_file). and_return(false) post api("/projects/#{project.id}/repository/files", user), valid_params @@ -201,11 +201,7 @@ describe API::Files, api: true do it "deletes existing file in project repo" do delete api("/projects/#{project.id}/repository/files", user), valid_params - expect(response).to have_http_status(200) - expect(json_response['file_path']).to eq(file_path) - last_commit = project.repository.commit.raw - expect(last_commit.author_email).to eq(user.email) - expect(last_commit.author_name).to eq(user.name) + expect(response).to have_http_status(204) end it "returns a 400 bad request if no params given" do @@ -215,7 +211,7 @@ describe API::Files, api: true do end it "returns a 400 if fails to create file" do - allow_any_instance_of(Repository).to receive(:remove_file).and_return(false) + allow_any_instance_of(Repository).to receive(:delete_file).and_return(false) delete api("/projects/#{project.id}/repository/files", user), valid_params @@ -228,10 +224,7 @@ describe API::Files, api: true do delete api("/projects/#{project.id}/repository/files", user), valid_params - expect(response).to have_http_status(200) - last_commit = project.repository.commit.raw - expect(last_commit.author_email).to eq(author_email) - expect(last_commit.author_name).to eq(author_name) + expect(response).to have_http_status(204) end end end diff --git a/spec/requests/api/groups_spec.rb b/spec/requests/api/groups_spec.rb index 9c3a92bedbd..b0ba3ea912d 100644 --- a/spec/requests/api/groups_spec.rb +++ b/spec/requests/api/groups_spec.rb @@ -150,20 +150,10 @@ describe API::Groups, api: true do expect(response_groups).to eq([group1.name, group3.name]) end end - end - - describe 'GET /groups/owned' do - context 'when unauthenticated' do - it 'returns authentication error' do - get api('/groups/owned') - - expect(response).to have_http_status(401) - end - end - context 'when authenticated as group owner' do + context 'when using owned in the request' do it 'returns an array of groups the user owns' do - get api('/groups/owned', user2) + get api('/groups', user2), owned: true expect(response).to have_http_status(200) expect(response).to include_pagination_headers @@ -477,7 +467,7 @@ describe API::Groups, api: true do it "removes group" do delete api("/groups/#{group1.id}", user1) - expect(response).to have_http_status(200) + expect(response).to have_http_status(204) end it "does not remove a group if not an owner" do @@ -506,7 +496,7 @@ describe API::Groups, api: true do it "removes any existing group" do delete api("/groups/#{group2.id}", admin) - expect(response).to have_http_status(200) + expect(response).to have_http_status(204) end it "does not remove a non existing group" do @@ -519,7 +509,7 @@ describe API::Groups, api: true do describe "POST /groups/:id/projects/:project_id" do let(:project) { create(:empty_project) } - let(:project_path) { "#{project.namespace.path}%2F#{project.path}" } + let(:project_path) { project.full_path.gsub('/', '%2F') } before(:each) do allow_any_instance_of(Projects::TransferService). diff --git a/spec/requests/api/internal_spec.rb b/spec/requests/api/internal_spec.rb index ffeacb15f17..f18b8e98707 100644 --- a/spec/requests/api/internal_spec.rb +++ b/spec/requests/api/internal_spec.rb @@ -409,6 +409,34 @@ describe API::Internal, api: true do end end + describe 'POST /notify_post_receive' do + let(:valid_params) do + { repo_path: project.repository.path, secret_token: secret_token } + end + + before do + allow(Gitlab.config.gitaly).to receive(:socket_path).and_return('path/to/gitaly.socket') + end + + it "calls the Gitaly client if it's enabled" do + expect_any_instance_of(Gitlab::GitalyClient::Notifications). + to receive(:post_receive).with(project.repository.path) + + post api("/internal/notify_post_receive"), valid_params + + expect(response).to have_http_status(200) + end + + it "returns 500 if the gitaly call fails" do + expect_any_instance_of(Gitlab::GitalyClient::Notifications). + to receive(:post_receive).with(project.repository.path).and_raise(GRPC::Unavailable) + + post api("/internal/notify_post_receive"), valid_params + + expect(response).to have_http_status(500) + end + end + def project_with_repo_path(path) double().tap do |fake_project| allow(fake_project).to receive_message_chain('repository.path_to_repo' => path) diff --git a/spec/requests/api/issues_spec.rb b/spec/requests/api/issues_spec.rb index 7cb75310204..ddc2e51821e 100644 --- a/spec/requests/api/issues_spec.rb +++ b/spec/requests/api/issues_spec.rb @@ -1175,8 +1175,8 @@ describe API::Issues, api: true do it "deletes the issue if an admin requests it" do delete api("/projects/#{project.id}/issues/#{issue.id}", owner) - expect(response).to have_http_status(200) - expect(json_response['state']).to eq 'opened' + + expect(response).to have_http_status(204) end end diff --git a/spec/requests/api/labels_spec.rb b/spec/requests/api/labels_spec.rb index af271dbd4f5..a1adaba7b98 100644 --- a/spec/requests/api/labels_spec.rb +++ b/spec/requests/api/labels_spec.rb @@ -175,9 +175,10 @@ describe API::Labels, api: true do end describe 'DELETE /projects/:id/labels' do - it 'returns 200 for existing label' do + it 'returns 204 for existing label' do delete api("/projects/#{project.id}/labels", user), name: 'label1' - expect(response).to have_http_status(200) + + expect(response).to have_http_status(204) end it 'returns 404 for non existing label' do diff --git a/spec/requests/api/members_spec.rb b/spec/requests/api/members_spec.rb index 31166b50033..2d37d026a39 100644 --- a/spec/requests/api/members_spec.rb +++ b/spec/requests/api/members_spec.rb @@ -173,11 +173,11 @@ describe API::Members, api: true do expect(response).to have_http_status(400) end - it 'returns 422 when access_level is not valid' do + it 'returns 400 when access_level is not valid' do post api("/#{source_type.pluralize}/#{source.id}/members", master), user_id: stranger.id, access_level: 1234 - expect(response).to have_http_status(422) + expect(response).to have_http_status(400) end end end @@ -230,11 +230,11 @@ describe API::Members, api: true do expect(response).to have_http_status(400) end - it 'returns 422 when access level is not valid' do + it 'returns 400 when access level is not valid' do put api("/#{source_type.pluralize}/#{source.id}/members/#{developer.id}", master), access_level: 1234 - expect(response).to have_http_status(422) + expect(response).to have_http_status(400) end end end @@ -263,18 +263,18 @@ describe API::Members, api: true do expect do delete api("/#{source_type.pluralize}/#{source.id}/members/#{developer.id}", developer) - expect(response).to have_http_status(200) + expect(response).to have_http_status(204) end.to change { source.members.count }.by(-1) end end context 'when authenticated as a master/owner' do context 'and member is a requester' do - it "returns #{source_type == 'project' ? 200 : 404}" do + it 'returns 404' do expect do delete api("/#{source_type.pluralize}/#{source.id}/members/#{access_requester.id}", master) - expect(response).to have_http_status(source_type == 'project' ? 200 : 404) + expect(response).to have_http_status(404) end.not_to change { source.requesters.count } end end @@ -283,15 +283,15 @@ describe API::Members, api: true do expect do delete api("/#{source_type.pluralize}/#{source.id}/members/#{developer.id}", master) - expect(response).to have_http_status(200) + expect(response).to have_http_status(204) end.to change { source.members.count }.by(-1) end end - it "returns #{source_type == 'project' ? 200 : 404} if member does not exist" do + it 'returns 404 if member does not exist' do delete api("/#{source_type.pluralize}/#{source.id}/members/123", master) - expect(response).to have_http_status(source_type == 'project' ? 200 : 404) + expect(response).to have_http_status(404) end end end @@ -342,7 +342,7 @@ describe API::Members, api: true do post api("/projects/#{project.id}/members", master), user_id: stranger.id, access_level: Member::OWNER - expect(response).to have_http_status(422) + expect(response).to have_http_status(400) end.to change { project.members.count }.by(0) end end diff --git a/spec/requests/api/merge_requests_spec.rb b/spec/requests/api/merge_requests_spec.rb index b87d0cd7de9..b3f0876c822 100644 --- a/spec/requests/api/merge_requests_spec.rb +++ b/spec/requests/api/merge_requests_spec.rb @@ -170,7 +170,7 @@ describe API::MergeRequests, api: true do expect(json_response['source_project_id']).to eq(merge_request.source_project.id) expect(json_response['target_project_id']).to eq(merge_request.target_project.id) expect(json_response['work_in_progress']).to be_falsy - expect(json_response['merge_when_build_succeeds']).to be_falsy + expect(json_response['merge_when_pipeline_succeeds']).to be_falsy expect(json_response['merge_status']).to eq('can_be_merged') expect(json_response['should_close_merge_request']).to be_falsy expect(json_response['force_close_merge_request']).to be_falsy @@ -411,7 +411,7 @@ describe API::MergeRequests, api: true do it "destroys the merge request owners can destroy" do delete api("/projects/#{project.id}/merge_requests/#{merge_request.id}", user) - expect(response).to have_http_status(200) + expect(response).to have_http_status(204) end end end @@ -483,11 +483,11 @@ describe API::MergeRequests, api: true do allow_any_instance_of(MergeRequest).to receive(:head_pipeline).and_return(pipeline) allow(pipeline).to receive(:active?).and_return(true) - put api("/projects/#{project.id}/merge_requests/#{merge_request.id}/merge", user), merge_when_build_succeeds: true + put api("/projects/#{project.id}/merge_requests/#{merge_request.id}/merge", user), merge_when_pipeline_succeeds: true expect(response).to have_http_status(200) expect(json_response['title']).to eq('Test') - expect(json_response['merge_when_build_succeeds']).to eq(true) + expect(json_response['merge_when_pipeline_succeeds']).to eq(true) end end diff --git a/spec/requests/api/notes_spec.rb b/spec/requests/api/notes_spec.rb index 3cca4468be7..347f8f6fa3b 100644 --- a/spec/requests/api/notes_spec.rb +++ b/spec/requests/api/notes_spec.rb @@ -225,11 +225,11 @@ describe API::Notes, api: true do context 'when the user is posting an award emoji on an issue created by someone else' do let(:issue2) { create(:issue, project: project) } - it 'returns an award emoji' do + it 'creates a new issue note' do post api("/projects/#{project.id}/issues/#{issue2.id}/notes", user), body: ':+1:' expect(response).to have_http_status(201) - expect(json_response['awardable_id']).to eq issue2.id + expect(json_response['body']).to eq(':+1:') end end @@ -373,7 +373,7 @@ describe API::Notes, api: true do delete api("/projects/#{project.id}/issues/#{issue.id}/"\ "notes/#{issue_note.id}", user) - expect(response).to have_http_status(200) + expect(response).to have_http_status(204) # Check if note is really deleted delete api("/projects/#{project.id}/issues/#{issue.id}/"\ "notes/#{issue_note.id}", user) @@ -392,7 +392,7 @@ describe API::Notes, api: true do delete api("/projects/#{project.id}/snippets/#{snippet.id}/"\ "notes/#{snippet_note.id}", user) - expect(response).to have_http_status(200) + expect(response).to have_http_status(204) # Check if note is really deleted delete api("/projects/#{project.id}/snippets/#{snippet.id}/"\ "notes/#{snippet_note.id}", user) @@ -412,7 +412,7 @@ describe API::Notes, api: true do delete api("/projects/#{project.id}/merge_requests/"\ "#{merge_request.id}/notes/#{merge_request_note.id}", user) - expect(response).to have_http_status(200) + expect(response).to have_http_status(204) # Check if note is really deleted delete api("/projects/#{project.id}/merge_requests/"\ "#{merge_request.id}/notes/#{merge_request_note.id}", user) diff --git a/spec/requests/api/project_hooks_spec.rb b/spec/requests/api/project_hooks_spec.rb index 20c76bd2c05..f286568547d 100644 --- a/spec/requests/api/project_hooks_spec.rb +++ b/spec/requests/api/project_hooks_spec.rb @@ -183,13 +183,9 @@ describe API::ProjectHooks, 'ProjectHooks', api: true do it "deletes hook from project" do expect do delete api("/projects/#{project.id}/hooks/#{hook.id}", user) - end.to change {project.hooks.count}.by(-1) - expect(response).to have_http_status(200) - end - it "returns success when deleting hook" do - delete api("/projects/#{project.id}/hooks/#{hook.id}", user) - expect(response).to have_http_status(200) + expect(response).to have_http_status(204) + end.to change {project.hooks.count}.by(-1) end it "returns a 404 error when deleting non existent hook" do diff --git a/spec/requests/api/project_snippets_spec.rb b/spec/requests/api/project_snippets_spec.rb index da9df56401b..2c4602faf2c 100644 --- a/spec/requests/api/project_snippets_spec.rb +++ b/spec/requests/api/project_snippets_spec.rb @@ -189,7 +189,7 @@ describe API::ProjectSnippets, api: true do delete api("/projects/#{snippet.project.id}/snippets/#{snippet.id}/", admin) - expect(response).to have_http_status(200) + expect(response).to have_http_status(204) end it 'returns 404 for invalid snippet id' do @@ -212,7 +212,7 @@ describe API::ProjectSnippets, api: true do end it 'returns 404 for invalid snippet id' do - delete api("/projects/#{snippet.project.id}/snippets/1234", admin) + get api("/projects/#{snippet.project.id}/snippets/1234/raw", admin) expect(response).to have_http_status(404) expect(json_response['message']).to eq('404 Snippet Not Found') diff --git a/spec/requests/api/projects_spec.rb b/spec/requests/api/projects_spec.rb index 8d139782fdf..7268016ee81 100644 --- a/spec/requests/api/projects_spec.rb +++ b/spec/requests/api/projects_spec.rb @@ -269,10 +269,37 @@ describe API::Projects, api: true do end end - it 'creates new project without path and return 201' do - expect { post api('/projects', user), name: 'foo' }. + it 'creates new project without path but with name and returns 201' do + expect { post api('/projects', user), name: 'Foo Project' }. + to change { Project.count }.by(1) + expect(response).to have_http_status(201) + + project = Project.first + + expect(project.name).to eq('Foo Project') + expect(project.path).to eq('foo-project') + end + + it 'creates new project without name but with path and returns 201' do + expect { post api('/projects', user), path: 'foo_project' }. + to change { Project.count }.by(1) + expect(response).to have_http_status(201) + + project = Project.first + + expect(project.name).to eq('foo_project') + expect(project.path).to eq('foo_project') + end + + it 'creates new project name and path and returns 201' do + expect { post api('/projects', user), path: 'foo-Project', name: 'Foo Project' }. to change { Project.count }.by(1) expect(response).to have_http_status(201) + + project = Project.first + + expect(project.name).to eq('Foo Project') + expect(project.path).to eq('foo-Project') end it 'creates last project before reaching project limit' do @@ -281,7 +308,7 @@ describe API::Projects, api: true do expect(response).to have_http_status(201) end - it 'does not create new project without name and return 400' do + it 'does not create new project without name or path and returns 400' do expect { post api('/projects', user) }.not_to change { Project.count } expect(response).to have_http_status(400) end @@ -293,7 +320,7 @@ describe API::Projects, api: true do issues_enabled: false, merge_requests_enabled: false, wiki_enabled: false, - only_allow_merge_if_build_succeeds: false, + only_allow_merge_if_pipeline_succeeds: false, request_access_enabled: true, only_allow_merge_if_all_discussions_are_resolved: false }) @@ -334,15 +361,15 @@ describe API::Projects, api: true do end it 'sets a project as allowing merge even if build fails' do - project = attributes_for(:project, { only_allow_merge_if_build_succeeds: false }) + project = attributes_for(:project, { only_allow_merge_if_pipeline_succeeds: false }) post api('/projects', user), project - expect(json_response['only_allow_merge_if_build_succeeds']).to be_falsey + expect(json_response['only_allow_merge_if_pipeline_succeeds']).to be_falsey end - it 'sets a project as allowing merge only if build succeeds' do - project = attributes_for(:project, { only_allow_merge_if_build_succeeds: true }) + it 'sets a project as allowing merge only if merge_when_pipeline_succeeds' do + project = attributes_for(:project, { only_allow_merge_if_pipeline_succeeds: true }) post api('/projects', user), project - expect(json_response['only_allow_merge_if_build_succeeds']).to be_truthy + expect(json_response['only_allow_merge_if_pipeline_succeeds']).to be_truthy end it 'sets a project as allowing merge even if discussions are unresolved' do @@ -457,15 +484,15 @@ describe API::Projects, api: true do end it 'sets a project as allowing merge even if build fails' do - project = attributes_for(:project, { only_allow_merge_if_build_succeeds: false }) + project = attributes_for(:project, { only_allow_merge_if_pipeline_succeeds: false }) post api("/projects/user/#{user.id}", admin), project - expect(json_response['only_allow_merge_if_build_succeeds']).to be_falsey + expect(json_response['only_allow_merge_if_pipeline_succeeds']).to be_falsey end - it 'sets a project as allowing merge only if build succeeds' do - project = attributes_for(:project, { only_allow_merge_if_build_succeeds: true }) + it 'sets a project as allowing merge only if merge_when_pipeline_succeeds' do + project = attributes_for(:project, { only_allow_merge_if_pipeline_succeeds: true }) post api("/projects/user/#{user.id}", admin), project - expect(json_response['only_allow_merge_if_build_succeeds']).to be_truthy + expect(json_response['only_allow_merge_if_pipeline_succeeds']).to be_truthy end it 'sets a project as allowing merge even if discussions are unresolved' do @@ -559,7 +586,7 @@ describe API::Projects, api: true do expect(json_response['shared_with_groups'][0]['group_id']).to eq(group.id) expect(json_response['shared_with_groups'][0]['group_name']).to eq(group.name) expect(json_response['shared_with_groups'][0]['group_access_level']).to eq(link.group_access) - expect(json_response['only_allow_merge_if_build_succeeds']).to eq(project.only_allow_merge_if_build_succeeds) + expect(json_response['only_allow_merge_if_pipeline_succeeds']).to eq(project.only_allow_merge_if_pipeline_succeeds) expect(json_response['only_allow_merge_if_all_discussions_are_resolved']).to eq(project.only_allow_merge_if_all_discussions_are_resolved) end @@ -820,8 +847,9 @@ describe API::Projects, api: true do it 'deletes existing project snippet' do expect do delete api("/projects/#{project.id}/snippets/#{snippet.id}", user) + + expect(response).to have_http_status(204) end.to change { Snippet.count }.by(-1) - expect(response).to have_http_status(200) end it 'returns 404 when deleting unknown snippet id' do @@ -905,8 +933,10 @@ describe API::Projects, api: true do project_fork_target.reload expect(project_fork_target.forked_from_project).not_to be_nil expect(project_fork_target.forked?).to be_truthy + delete api("/projects/#{project_fork_target.id}/fork", admin) - expect(response).to have_http_status(200) + + expect(response).to have_http_status(204) project_fork_target.reload expect(project_fork_target.forked_from_project).to be_nil expect(project_fork_target.forked?).not_to be_truthy @@ -1263,7 +1293,9 @@ describe API::Projects, api: true do context 'when authenticated as user' do it 'removes project' do delete api("/projects/#{project.id}", user) - expect(response).to have_http_status(200) + + expect(response).to have_http_status(202) + expect(json_response['message']).to eql('202 Accepted') end it 'does not remove a project if not an owner' do @@ -1287,7 +1319,9 @@ describe API::Projects, api: true do context 'when authenticated as admin' do it 'removes any existing project' do delete api("/projects/#{project.id}", admin) - expect(response).to have_http_status(200) + + expect(response).to have_http_status(202) + expect(json_response['message']).to eql('202 Accepted') end it 'does not remove a non existing project' do diff --git a/spec/requests/api/runner_spec.rb b/spec/requests/api/runner_spec.rb new file mode 100644 index 00000000000..e83202e4196 --- /dev/null +++ b/spec/requests/api/runner_spec.rb @@ -0,0 +1,151 @@ +require 'spec_helper' + +describe API::Runner do + include ApiHelpers + include StubGitlabCalls + + let(:registration_token) { 'abcdefg123456' } + + before do + stub_gitlab_calls + stub_application_setting(runners_registration_token: registration_token) + end + + describe '/api/v4/runners' do + describe 'POST /api/v4/runners' do + context 'when no token is provided' do + it 'returns 400 error' do + post api('/runners') + expect(response).to have_http_status 400 + end + end + + context 'when invalid token is provided' do + it 'returns 403 error' do + post api('/runners'), token: 'invalid' + expect(response).to have_http_status 403 + end + end + + context 'when valid token is provided' do + it 'creates runner with default values' do + post api('/runners'), token: registration_token + + runner = Ci::Runner.first + + expect(response).to have_http_status 201 + expect(json_response['id']).to eq(runner.id) + expect(json_response['token']).to eq(runner.token) + expect(runner.run_untagged).to be true + end + + context 'when project token is used' do + let(:project) { create(:empty_project) } + + it 'creates runner' do + post api('/runners'), token: project.runners_token + + expect(response).to have_http_status 201 + expect(project.runners.size).to eq(1) + end + end + end + + context 'when runner description is provided' do + it 'creates runner' do + post api('/runners'), token: registration_token, + description: 'server.hostname' + + expect(response).to have_http_status 201 + expect(Ci::Runner.first.description).to eq('server.hostname') + end + end + + context 'when runner tags are provided' do + it 'creates runner' do + post api('/runners'), token: registration_token, + tag_list: 'tag1, tag2' + + expect(response).to have_http_status 201 + expect(Ci::Runner.first.tag_list.sort).to eq(%w(tag1 tag2)) + end + end + + context 'when option for running untagged jobs is provided' do + context 'when tags are provided' do + it 'creates runner' do + post api('/runners'), token: registration_token, + run_untagged: false, + tag_list: ['tag'] + + expect(response).to have_http_status 201 + expect(Ci::Runner.first.run_untagged).to be false + expect(Ci::Runner.first.tag_list.sort).to eq(['tag']) + end + end + + context 'when tags are not provided' do + it 'returns 404 error' do + post api('/runners'), token: registration_token, + run_untagged: false + + expect(response).to have_http_status 404 + end + end + end + + context 'when option for locking Runner is provided' do + it 'creates runner' do + post api('/runners'), token: registration_token, + locked: true + + expect(response).to have_http_status 201 + expect(Ci::Runner.first.locked).to be true + end + end + + %w(name version revision platform architecture).each do |param| + context "when info parameter '#{param}' info is present" do + let(:value) { "#{param}_value" } + + it %q(updates provided Runner's parameter) do + post api('/runners'), token: registration_token, + info: { param => value } + + expect(response).to have_http_status 201 + expect(Ci::Runner.first.read_attribute(param.to_sym)).to eq(value) + end + end + end + end + + describe 'DELETE /api/v4/runners' do + context 'when no token is provided' do + it 'returns 400 error' do + delete api('/runners') + + expect(response).to have_http_status 400 + end + end + + context 'when invalid token is provided' do + it 'returns 403 error' do + delete api('/runners'), token: 'invalid' + + expect(response).to have_http_status 403 + end + end + + context 'when valid token is provided' do + let(:runner) { create(:ci_runner) } + + it 'deletes Runner' do + delete api('/runners'), token: runner.token + + expect(response).to have_http_status 204 + expect(Ci::Runner.count).to eq(0) + end + end + end + end +end diff --git a/spec/requests/api/runners_spec.rb b/spec/requests/api/runners_spec.rb index 103d6755888..8a82543a830 100644 --- a/spec/requests/api/runners_spec.rb +++ b/spec/requests/api/runners_spec.rb @@ -277,8 +277,9 @@ describe API::Runners, api: true do it 'deletes runner' do expect do delete api("/runners/#{shared_runner.id}", admin) + + expect(response).to have_http_status(204) end.to change{ Ci::Runner.shared.count }.by(-1) - expect(response).to have_http_status(200) end end @@ -286,15 +287,17 @@ describe API::Runners, api: true do it 'deletes unused runner' do expect do delete api("/runners/#{unused_specific_runner.id}", admin) + + expect(response).to have_http_status(204) end.to change{ Ci::Runner.specific.count }.by(-1) - expect(response).to have_http_status(200) end it 'deletes used runner' do expect do delete api("/runners/#{specific_runner.id}", admin) + + expect(response).to have_http_status(204) end.to change{ Ci::Runner.specific.count }.by(-1) - expect(response).to have_http_status(200) end end @@ -327,8 +330,9 @@ describe API::Runners, api: true do it 'deletes runner for one owned project' do expect do delete api("/runners/#{specific_runner.id}", user) + + expect(response).to have_http_status(204) end.to change{ Ci::Runner.specific.count }.by(-1) - expect(response).to have_http_status(200) end end end @@ -457,8 +461,9 @@ describe API::Runners, api: true do it "disables project's runner" do expect do delete api("/projects/#{project.id}/runners/#{two_projects_runner.id}", user) + + expect(response).to have_http_status(204) end.to change{ project.runners.count }.by(-1) - expect(response).to have_http_status(200) end end diff --git a/spec/requests/api/services_spec.rb b/spec/requests/api/services_spec.rb index 776dc655650..fd334934ca5 100644 --- a/spec/requests/api/services_spec.rb +++ b/spec/requests/api/services_spec.rb @@ -55,7 +55,7 @@ describe API::Services, api: true do it "deletes #{service}" do delete api("/projects/#{project.id}/services/#{dashed_service}", user) - expect(response).to have_http_status(200) + expect(response).to have_http_status(204) project.send(service_method).reload expect(project.send(service_method).activated?).to be_falsey end diff --git a/spec/requests/api/settings_spec.rb b/spec/requests/api/settings_spec.rb index 91e3c333a02..411905edb49 100644 --- a/spec/requests/api/settings_spec.rb +++ b/spec/requests/api/settings_spec.rb @@ -30,8 +30,14 @@ describe API::Settings, 'Settings', api: true do it "updates application settings" do put api("/application/settings", admin), - default_projects_limit: 3, signin_enabled: false, repository_storage: 'custom', koding_enabled: true, koding_url: 'http://koding.example.com', - plantuml_enabled: true, plantuml_url: 'http://plantuml.example.com' + default_projects_limit: 3, + signin_enabled: false, + repository_storage: 'custom', + koding_enabled: true, + koding_url: 'http://koding.example.com', + plantuml_enabled: true, + plantuml_url: 'http://plantuml.example.com', + default_artifacts_expire_in: '2 days' expect(response).to have_http_status(200) expect(json_response['default_projects_limit']).to eq(3) expect(json_response['signin_enabled']).to be_falsey @@ -41,6 +47,7 @@ describe API::Settings, 'Settings', api: true do expect(json_response['koding_url']).to eq('http://koding.example.com') expect(json_response['plantuml_enabled']).to be_truthy expect(json_response['plantuml_url']).to eq('http://plantuml.example.com') + expect(json_response['default_artifacts_expire_in']).to eq('2 days') end end diff --git a/spec/requests/api/snippets_spec.rb b/spec/requests/api/snippets_spec.rb index 41def7cd1d4..5219f6eed42 100644 --- a/spec/requests/api/snippets_spec.rb +++ b/spec/requests/api/snippets_spec.rb @@ -74,7 +74,7 @@ describe API::Snippets, api: true do end it 'returns 404 for invalid snippet id' do - delete api("/snippets/1234", user) + get api("/snippets/1234/raw", user) expect(response).to have_http_status(404) expect(json_response['message']).to eq('404 Snippet Not Found') diff --git a/spec/requests/api/system_hooks_spec.rb b/spec/requests/api/system_hooks_spec.rb index b59da632c00..d1e10f12657 100644 --- a/spec/requests/api/system_hooks_spec.rb +++ b/spec/requests/api/system_hooks_spec.rb @@ -91,6 +91,8 @@ describe API::SystemHooks, api: true do it "deletes a hook" do expect do delete api("/hooks/#{hook.id}", admin) + + expect(response).to have_http_status(204) end.to change { SystemHook.count }.by(-1) end diff --git a/spec/requests/api/tags_spec.rb b/spec/requests/api/tags_spec.rb index 8a4f078182f..b132d033a61 100644 --- a/spec/requests/api/tags_spec.rb +++ b/spec/requests/api/tags_spec.rb @@ -137,8 +137,8 @@ describe API::Tags, api: true do context 'delete tag' do it 'deletes an existing tag' do delete api("/projects/#{project.id}/repository/tags/#{tag_name}", user) - expect(response).to have_http_status(200) - expect(json_response['tag_name']).to eq(tag_name) + + expect(response).to have_http_status(204) end it 'raises 404 if the tag does not exist' do diff --git a/spec/requests/api/todos_spec.rb b/spec/requests/api/todos_spec.rb index f35e963a14b..1e401935662 100644 --- a/spec/requests/api/todos_spec.rb +++ b/spec/requests/api/todos_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' describe API::Todos, api: true do include ApiHelpers - let(:project_1) { create(:empty_project) } + let(:project_1) { create(:empty_project, :test_repo) } let(:project_2) { create(:empty_project) } let(:author_1) { create(:user) } let(:author_2) { create(:user) } @@ -11,7 +11,7 @@ describe API::Todos, api: true do let(:merge_request) { create(:merge_request, source_project: project_1) } let!(:pending_1) { create(:todo, :mentioned, project: project_1, author: author_1, user: john_doe) } let!(:pending_2) { create(:todo, project: project_2, author: author_2, user: john_doe) } - let!(:pending_3) { create(:todo, project: project_1, author: author_2, user: john_doe) } + let!(:pending_3) { create(:on_commit_todo, project: project_1, author: author_2, user: john_doe) } let!(:done) { create(:todo, :done, project: project_1, author: author_1, user: john_doe) } before do diff --git a/spec/requests/api/triggers_spec.rb b/spec/requests/api/triggers_spec.rb index 92dfc2aa277..153e2791cbe 100644 --- a/spec/requests/api/triggers_spec.rb +++ b/spec/requests/api/triggers_spec.rb @@ -190,8 +190,9 @@ describe API::Triggers do it 'deletes trigger' do expect do delete api("/projects/#{project.id}/triggers/#{trigger.token}", user) + + expect(response).to have_http_status(204) end.to change{project.triggers.count}.by(-1) - expect(response).to have_http_status(200) end it 'responds with 404 Not Found if requesting non-existing trigger' do diff --git a/spec/requests/api/users_spec.rb b/spec/requests/api/users_spec.rb index 603da9f49fc..e5e4c84755f 100644 --- a/spec/requests/api/users_spec.rb +++ b/spec/requests/api/users_spec.rb @@ -540,10 +540,12 @@ describe API::Users, api: true do it 'deletes existing key' do user.keys << key user.save + expect do delete api("/users/#{user.id}/keys/#{key.id}", admin) + + expect(response).to have_http_status(204) end.to change { user.keys.count }.by(-1) - expect(response).to have_http_status(200) end it 'returns 404 error if user not found' do @@ -637,10 +639,12 @@ describe API::Users, api: true do it 'deletes existing email' do user.emails << email user.save + expect do delete api("/users/#{user.id}/emails/#{email.id}", admin) + + expect(response).to have_http_status(204) end.to change { user.emails.count }.by(-1) - expect(response).to have_http_status(200) end it 'returns 404 error if user not found' do @@ -671,10 +675,10 @@ describe API::Users, api: true do it "deletes user" do delete api("/users/#{user.id}", admin) - expect(response).to have_http_status(200) + + expect(response).to have_http_status(204) expect { User.find(user.id) }.to raise_error ActiveRecord::RecordNotFound expect { Namespace.find(namespace.id) }.to raise_error ActiveRecord::RecordNotFound - expect(json_response['email']).to eq(user.email) end it "does not delete for unauthenticated user" do @@ -869,10 +873,12 @@ describe API::Users, api: true do it "deletes existed key" do user.keys << key user.save + expect do delete api("/user/keys/#{key.id}", user) + + expect(response).to have_http_status(204) end.to change{user.keys.count}.by(-1) - expect(response).to have_http_status(200) end it "returns 404 if key ID not found" do @@ -976,10 +982,12 @@ describe API::Users, api: true do it "deletes existed email" do user.emails << email user.save + expect do delete api("/user/emails/#{email.id}", user) + + expect(response).to have_http_status(204) end.to change{user.emails.count}.by(-1) - expect(response).to have_http_status(200) end it "returns 404 if email ID not found" do diff --git a/spec/requests/api/v3/award_emoji_spec.rb b/spec/requests/api/v3/award_emoji_spec.rb new file mode 100644 index 00000000000..91145c8e72c --- /dev/null +++ b/spec/requests/api/v3/award_emoji_spec.rb @@ -0,0 +1,74 @@ +require 'spec_helper' + +describe API::V3::AwardEmoji, api: true do + include ApiHelpers + + let(:user) { create(:user) } + let!(:project) { create(:empty_project) } + let(:issue) { create(:issue, project: project) } + let!(:award_emoji) { create(:award_emoji, awardable: issue, user: user) } + let!(:merge_request) { create(:merge_request, source_project: project, target_project: project) } + let!(:downvote) { create(:award_emoji, :downvote, awardable: merge_request, user: user) } + let!(:note) { create(:note, project: project, noteable: issue) } + + before { project.team << [user, :master] } + + describe 'DELETE /projects/:id/awardable/:awardable_id/award_emoji/:award_id' do + context 'when the awardable is an Issue' do + it 'deletes the award' do + expect do + delete v3_api("/projects/#{project.id}/issues/#{issue.id}/award_emoji/#{award_emoji.id}", user) + + expect(response).to have_http_status(200) + end.to change { issue.award_emoji.count }.from(1).to(0) + end + + it 'returns a 404 error when the award emoji can not be found' do + delete v3_api("/projects/#{project.id}/issues/#{issue.id}/award_emoji/12345", user) + + expect(response).to have_http_status(404) + end + end + + context 'when the awardable is a Merge Request' do + it 'deletes the award' do + expect do + delete v3_api("/projects/#{project.id}/merge_requests/#{merge_request.id}/award_emoji/#{downvote.id}", user) + + expect(response).to have_http_status(200) + end.to change { merge_request.award_emoji.count }.from(1).to(0) + end + + it 'returns a 404 error when note id not found' do + delete v3_api("/projects/#{project.id}/merge_requests/#{merge_request.id}/notes/12345", user) + + expect(response).to have_http_status(404) + end + end + + context 'when the awardable is a Snippet' do + let(:snippet) { create(:project_snippet, :public, project: project) } + let!(:award) { create(:award_emoji, awardable: snippet, user: user) } + + it 'deletes the award' do + expect do + delete v3_api("/projects/#{project.id}/snippets/#{snippet.id}/award_emoji/#{award.id}", user) + + expect(response).to have_http_status(200) + end.to change { snippet.award_emoji.count }.from(1).to(0) + end + end + end + + describe 'DELETE /projects/:id/awardable/:awardable_id/award_emoji/:award_emoji_id' do + let!(:rocket) { create(:award_emoji, awardable: note, name: 'rocket', user: user) } + + it 'deletes the award' do + expect do + delete v3_api("/projects/#{project.id}/issues/#{issue.id}/notes/#{note.id}/award_emoji/#{rocket.id}", user) + + expect(response).to have_http_status(200) + end.to change { note.award_emoji.count }.from(1).to(0) + end + end +end diff --git a/spec/requests/api/v3/boards_spec.rb b/spec/requests/api/v3/boards_spec.rb index 8aaf3be4f87..eb95934f354 100644 --- a/spec/requests/api/v3/boards_spec.rb +++ b/spec/requests/api/v3/boards_spec.rb @@ -5,6 +5,7 @@ describe API::V3::Boards, api: true do let(:user) { create(:user) } let(:guest) { create(:user) } + let(:non_member) { create(:user) } let!(:project) { create(:empty_project, :public, creator_id: user.id, namespace: user.namespace ) } let!(:dev_label) do @@ -76,4 +77,37 @@ describe API::V3::Boards, api: true do expect(response).to have_http_status(404) end end + + describe "DELETE /projects/:id/board/lists/:list_id" do + let(:base_url) { "/projects/#{project.id}/boards/#{board.id}/lists" } + + it "rejects a non member from deleting a list" do + delete v3_api("#{base_url}/#{dev_list.id}", non_member) + + expect(response).to have_http_status(403) + end + + it "rejects a user with guest role from deleting a list" do + delete v3_api("#{base_url}/#{dev_list.id}", guest) + + expect(response).to have_http_status(403) + end + + it "returns 404 error if list id not found" do + delete v3_api("#{base_url}/44444", user) + + expect(response).to have_http_status(404) + end + + context "when the user is project owner" do + let(:owner) { create(:user) } + let(:project) { create(:empty_project, namespace: owner.namespace) } + + it "deletes the list if an admin requests it" do + delete v3_api("#{base_url}/#{dev_list.id}", owner) + + expect(response).to have_http_status(200) + end + end + end end diff --git a/spec/requests/api/v3/branches_spec.rb b/spec/requests/api/v3/branches_spec.rb index 0e4c6bc3bc6..e4cedf98e64 100644 --- a/spec/requests/api/v3/branches_spec.rb +++ b/spec/requests/api/v3/branches_spec.rb @@ -5,8 +5,12 @@ describe API::V3::Branches, api: true do include ApiHelpers let(:user) { create(:user) } + let(:user2) { create(:user) } let!(:project) { create(:project, :repository, creator: user) } let!(:master) { create(:project_member, :master, user: user, project: project) } + let!(:guest) { create(:project_member, :guest, user: user2, project: project) } + let!(:branch_name) { 'feature' } + let!(:branch_with_dot) { CreateBranchService.new(project, user).execute("with.1.2.3", "master") } describe "GET /projects/:id/repository/branches" do it "returns an array of project branches" do @@ -20,4 +24,60 @@ describe API::V3::Branches, api: true do expect(branch_names).to match_array(project.repository.branch_names) end end + + describe "DELETE /projects/:id/repository/branches/:branch" do + before do + allow_any_instance_of(Repository).to receive(:rm_branch).and_return(true) + end + + it "removes branch" do + delete v3_api("/projects/#{project.id}/repository/branches/#{branch_name}", user) + + expect(response).to have_http_status(200) + expect(json_response['branch_name']).to eq(branch_name) + end + + it "removes a branch with dots in the branch name" do + delete v3_api("/projects/#{project.id}/repository/branches/with.1.2.3", user) + + expect(response).to have_http_status(200) + expect(json_response['branch_name']).to eq("with.1.2.3") + end + + it 'returns 404 if branch not exists' do + delete v3_api("/projects/#{project.id}/repository/branches/foobar", user) + expect(response).to have_http_status(404) + end + + it "removes protected branch" do + create(:protected_branch, project: project, name: branch_name) + delete v3_api("/projects/#{project.id}/repository/branches/#{branch_name}", user) + expect(response).to have_http_status(405) + expect(json_response['message']).to eq('Protected branch cant be removed') + end + + it "does not remove HEAD branch" do + delete v3_api("/projects/#{project.id}/repository/branches/master", user) + expect(response).to have_http_status(405) + expect(json_response['message']).to eq('Cannot remove HEAD branch') + end + end + + describe "DELETE /projects/:id/repository/merged_branches" do + before do + allow_any_instance_of(Repository).to receive(:rm_branch).and_return(true) + end + + it 'returns 200' do + delete v3_api("/projects/#{project.id}/repository/merged_branches", user) + + expect(response).to have_http_status(200) + end + + it 'returns a 403 error if guest' do + delete v3_api("/projects/#{project.id}/repository/merged_branches", user2) + + expect(response).to have_http_status(403) + end + end end diff --git a/spec/requests/api/v3/broadcast_messages_spec.rb b/spec/requests/api/v3/broadcast_messages_spec.rb new file mode 100644 index 00000000000..06556401a29 --- /dev/null +++ b/spec/requests/api/v3/broadcast_messages_spec.rb @@ -0,0 +1,34 @@ +require 'spec_helper' + +describe API::V3::BroadcastMessages, api: true do + include ApiHelpers + + let(:user) { create(:user) } + let(:admin) { create(:admin) } + + describe 'DELETE /broadcast_messages/:id' do + let!(:message) { create(:broadcast_message) } + + it 'returns a 401 for anonymous users' do + delete v3_api("/broadcast_messages/#{message.id}"), + attributes_for(:broadcast_message) + + expect(response).to have_http_status(401) + end + + it 'returns a 403 for users' do + delete v3_api("/broadcast_messages/#{message.id}", user), + attributes_for(:broadcast_message) + + expect(response).to have_http_status(403) + end + + it 'deletes the broadcast message for admins' do + expect do + delete v3_api("/broadcast_messages/#{message.id}", admin) + + expect(response).to have_http_status(200) + end.to change { BroadcastMessage.count }.by(-1) + end + end +end diff --git a/spec/requests/api/v3/commits_spec.rb b/spec/requests/api/v3/commits_spec.rb index 2d7584c3e59..e298ef055e1 100644 --- a/spec/requests/api/v3/commits_spec.rb +++ b/spec/requests/api/v3/commits_spec.rb @@ -148,7 +148,7 @@ describe API::V3::Commits, api: true do end context 'with project path in URL' do - let(:url) { "/projects/#{project.namespace.path}%2F#{project.path}/repository/commits" } + let(:url) { "/projects/#{project.full_path.gsub('/', '%2F')}/repository/commits" } it 'a new file in project repo' do post v3_api(url, user), valid_c_params diff --git a/spec/requests/api/v3/environments_spec.rb b/spec/requests/api/v3/environments_spec.rb new file mode 100644 index 00000000000..1ac666ab240 --- /dev/null +++ b/spec/requests/api/v3/environments_spec.rb @@ -0,0 +1,39 @@ +require 'spec_helper' + +describe API::V3::Environments, api: true do + include ApiHelpers + + let(:user) { create(:user) } + let(:non_member) { create(:user) } + let(:project) { create(:empty_project, :private, namespace: user.namespace) } + let!(:environment) { create(:environment, project: project) } + + before do + project.team << [user, :master] + end + + describe 'DELETE /projects/:id/environments/:environment_id' do + context 'as a master' do + it 'returns a 200 for an existing environment' do + delete v3_api("/projects/#{project.id}/environments/#{environment.id}", user) + + expect(response).to have_http_status(200) + end + + it 'returns a 404 for non existing id' do + delete v3_api("/projects/#{project.id}/environments/12345", user) + + expect(response).to have_http_status(404) + expect(json_response['message']).to eq('404 Not found') + end + end + + context 'a non member' do + it 'rejects the request' do + delete v3_api("/projects/#{project.id}/environments/#{environment.id}", non_member) + + expect(response).to have_http_status(404) + end + end + end +end diff --git a/spec/requests/api/v3/files_spec.rb b/spec/requests/api/v3/files_spec.rb index 4af05605ec6..93637053626 100644 --- a/spec/requests/api/v3/files_spec.rb +++ b/spec/requests/api/v3/files_spec.rb @@ -2,17 +2,6 @@ require 'spec_helper' describe API::V3::Files, api: true do include ApiHelpers - let(:user) { create(:user) } - let!(:project) { create(:project, :repository, namespace: user.namespace ) } - let(:guest) { create(:user) { |u| project.add_guest(u) } } - let(:file_path) { 'files/ruby/popen.rb' } - let(:params) do - { - file_path: file_path, - ref: 'master' - } - end - let(:author_email) { FFaker::Internet.email } # I have to remove periods from the end of the name # This happened when the user's name had a suffix (i.e. "Sr.") @@ -26,6 +15,18 @@ describe API::V3::Files, api: true do # ... # Author: Foo Sr <foo@example.com> # ... + + let(:user) { create(:user) } + let!(:project) { create(:project, :repository, namespace: user.namespace ) } + let(:guest) { create(:user) { |u| project.add_guest(u) } } + let(:file_path) { 'files/ruby/popen.rb' } + let(:params) do + { + file_path: file_path, + ref: 'master' + } + end + let(:author_email) { FFaker::Internet.email } let(:author_name) { FFaker::Name.name.chomp("\.") } before { project.team << [user, :developer] } @@ -127,7 +128,7 @@ describe API::V3::Files, api: true do end it "returns a 400 if editor fails to create file" do - allow_any_instance_of(Repository).to receive(:commit_file). + allow_any_instance_of(Repository).to receive(:create_file). and_return(false) post v3_api("/projects/#{project.id}/repository/files", user), valid_params @@ -215,7 +216,7 @@ describe API::V3::Files, api: true do end it "returns a 400 if fails to create file" do - allow_any_instance_of(Repository).to receive(:remove_file).and_return(false) + allow_any_instance_of(Repository).to receive(:delete_file).and_return(false) delete v3_api("/projects/#{project.id}/repository/files", user), valid_params diff --git a/spec/requests/api/v3/groups_spec.rb b/spec/requests/api/v3/groups_spec.rb new file mode 100644 index 00000000000..8b29ad03737 --- /dev/null +++ b/spec/requests/api/v3/groups_spec.rb @@ -0,0 +1,35 @@ +require 'spec_helper' + +describe API::V3::Groups, api: true do + include ApiHelpers + include UploadHelpers + + let(:user2) { create(:user) } + let!(:group2) { create(:group, :private) } + let!(:project2) { create(:empty_project, namespace: group2) } + + before do + group2.add_owner(user2) + end + + describe 'GET /groups/owned' do + context 'when unauthenticated' do + it 'returns authentication error' do + get v3_api('/groups/owned') + + expect(response).to have_http_status(401) + end + end + + context 'when authenticated as group owner' do + it 'returns an array of groups the user owns' do + get v3_api('/groups/owned', user2) + + expect(response).to have_http_status(200) + expect(response).to include_pagination_headers + expect(json_response).to be_an Array + expect(json_response.first['name']).to eq(group2.name) + end + end + end +end diff --git a/spec/requests/api/v3/labels_spec.rb b/spec/requests/api/v3/labels_spec.rb index f44403374e9..dfac357d37c 100644 --- a/spec/requests/api/v3/labels_spec.rb +++ b/spec/requests/api/v3/labels_spec.rb @@ -149,4 +149,23 @@ describe API::V3::Labels, api: true do end end end + + describe 'DELETE /projects/:id/labels' do + it 'returns 200 for existing label' do + delete v3_api("/projects/#{project.id}/labels", user), name: 'label1' + + expect(response).to have_http_status(200) + end + + it 'returns 404 for non existing label' do + delete v3_api("/projects/#{project.id}/labels", user), name: 'label2' + expect(response).to have_http_status(404) + expect(json_response['message']).to eq('404 Label Not Found') + end + + it 'returns 400 for wrong parameters' do + delete v3_api("/projects/#{project.id}/labels", user) + expect(response).to have_http_status(400) + end + end end diff --git a/spec/requests/api/v3/members_spec.rb b/spec/requests/api/v3/members_spec.rb index 28c3ca03960..13814ed10c3 100644 --- a/spec/requests/api/v3/members_spec.rb +++ b/spec/requests/api/v3/members_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe API::Members, api: true do +describe API::V3::Members, api: true do include ApiHelpers let(:master) { create(:user) } diff --git a/spec/requests/api/v3/notes_spec.rb b/spec/requests/api/v3/notes_spec.rb index b51cb3055d5..ddef2d5eb04 100644 --- a/spec/requests/api/v3/notes_spec.rb +++ b/spec/requests/api/v3/notes_spec.rb @@ -2,6 +2,7 @@ require 'spec_helper' describe API::V3::Notes, api: true do include ApiHelpers + let(:user) { create(:user) } let!(:project) { create(:empty_project, :public, namespace: user.namespace) } let!(:issue) { create(:issue, project: project, author: user) } @@ -227,11 +228,11 @@ describe API::V3::Notes, api: true do context 'when the user is posting an award emoji on an issue created by someone else' do let(:issue2) { create(:issue, project: project) } - it 'returns an award emoji' do + it 'creates a new issue note' do post v3_api("/projects/#{project.id}/issues/#{issue2.id}/notes", user), body: ':+1:' expect(response).to have_http_status(201) - expect(json_response['awardable_id']).to eq issue2.id + expect(json_response['body']).to eq(':+1:') end end @@ -373,12 +374,12 @@ describe API::V3::Notes, api: true do context 'when noteable is an Issue' do it 'deletes a note' do delete v3_api("/projects/#{project.id}/issues/#{issue.id}/"\ - "notes/#{issue_note.id}", user) + "notes/#{issue_note.id}", user) expect(response).to have_http_status(200) # Check if note is really deleted delete v3_api("/projects/#{project.id}/issues/#{issue.id}/"\ - "notes/#{issue_note.id}", user) + "notes/#{issue_note.id}", user) expect(response).to have_http_status(404) end @@ -392,18 +393,18 @@ describe API::V3::Notes, api: true do context 'when noteable is a Snippet' do it 'deletes a note' do delete v3_api("/projects/#{project.id}/snippets/#{snippet.id}/"\ - "notes/#{snippet_note.id}", user) + "notes/#{snippet_note.id}", user) expect(response).to have_http_status(200) # Check if note is really deleted delete v3_api("/projects/#{project.id}/snippets/#{snippet.id}/"\ - "notes/#{snippet_note.id}", user) + "notes/#{snippet_note.id}", user) expect(response).to have_http_status(404) end it 'returns a 404 error when note id not found' do delete v3_api("/projects/#{project.id}/snippets/#{snippet.id}/"\ - "notes/12345", user) + "notes/12345", user) expect(response).to have_http_status(404) end @@ -412,18 +413,18 @@ describe API::V3::Notes, api: true do context 'when noteable is a Merge Request' do it 'deletes a note' do delete v3_api("/projects/#{project.id}/merge_requests/"\ - "#{merge_request.id}/notes/#{merge_request_note.id}", user) + "#{merge_request.id}/notes/#{merge_request_note.id}", user) expect(response).to have_http_status(200) # Check if note is really deleted delete v3_api("/projects/#{project.id}/merge_requests/"\ - "#{merge_request.id}/notes/#{merge_request_note.id}", user) + "#{merge_request.id}/notes/#{merge_request_note.id}", user) expect(response).to have_http_status(404) end it 'returns a 404 error when note id not found' do delete v3_api("/projects/#{project.id}/merge_requests/"\ - "#{merge_request.id}/notes/12345", user) + "#{merge_request.id}/notes/12345", user) expect(response).to have_http_status(404) end diff --git a/spec/requests/api/v3/projects_spec.rb b/spec/requests/api/v3/projects_spec.rb index 662be3f3531..d8bb562587d 100644 --- a/spec/requests/api/v3/projects_spec.rb +++ b/spec/requests/api/v3/projects_spec.rb @@ -309,10 +309,37 @@ describe API::V3::Projects, api: true do end end - it 'creates new project without path and return 201' do - expect { post v3_api('/projects', user), name: 'foo' }. + it 'creates new project without path but with name and returns 201' do + expect { post v3_api('/projects', user), name: 'Foo Project' }. to change { Project.count }.by(1) expect(response).to have_http_status(201) + + project = Project.first + + expect(project.name).to eq('Foo Project') + expect(project.path).to eq('foo-project') + end + + it 'creates new project without name but with path and returns 201' do + expect { post v3_api('/projects', user), path: 'foo_project' }. + to change { Project.count }.by(1) + expect(response).to have_http_status(201) + + project = Project.first + + expect(project.name).to eq('foo_project') + expect(project.path).to eq('foo_project') + end + + it 'creates new project name and path and returns 201' do + expect { post v3_api('/projects', user), path: 'foo-Project', name: 'Foo Project' }. + to change { Project.count }.by(1) + expect(response).to have_http_status(201) + + project = Project.first + + expect(project.name).to eq('Foo Project') + expect(project.path).to eq('foo-Project') end it 'creates last project before reaching project limit' do @@ -321,7 +348,7 @@ describe API::V3::Projects, api: true do expect(response).to have_http_status(201) end - it 'does not create new project without name and return 400' do + it 'does not create new project without name or path and return 400' do expect { post v3_api('/projects', user) }.not_to change { Project.count } expect(response).to have_http_status(400) end @@ -400,7 +427,7 @@ describe API::V3::Projects, api: true do expect(json_response['only_allow_merge_if_build_succeeds']).to be_falsey end - it 'sets a project as allowing merge only if build succeeds' do + it 'sets a project as allowing merge only if merge_when_pipeline_succeeds' do project = attributes_for(:project, { only_allow_merge_if_build_succeeds: true }) post v3_api('/projects', user), project expect(json_response['only_allow_merge_if_build_succeeds']).to be_truthy @@ -545,7 +572,7 @@ describe API::V3::Projects, api: true do expect(json_response['only_allow_merge_if_build_succeeds']).to be_falsey end - it 'sets a project as allowing merge only if build succeeds' do + it 'sets a project as allowing merge only if merge_when_pipeline_succeeds' do project = attributes_for(:project, { only_allow_merge_if_build_succeeds: true }) post v3_api("/projects/user/#{user.id}", admin), project expect(json_response['only_allow_merge_if_build_succeeds']).to be_truthy @@ -642,7 +669,7 @@ describe API::V3::Projects, api: true do expect(json_response['shared_with_groups'][0]['group_id']).to eq(group.id) expect(json_response['shared_with_groups'][0]['group_name']).to eq(group.name) expect(json_response['shared_with_groups'][0]['group_access_level']).to eq(link.group_access) - expect(json_response['only_allow_merge_if_build_succeeds']).to eq(project.only_allow_merge_if_build_succeeds) + expect(json_response['only_allow_merge_if_build_succeeds']).to eq(project.only_allow_merge_if_pipeline_succeeds) expect(json_response['only_allow_merge_if_all_discussions_are_resolved']).to eq(project.only_allow_merge_if_all_discussions_are_resolved) end diff --git a/spec/requests/api/v3/runners_spec.rb b/spec/requests/api/v3/runners_spec.rb new file mode 100644 index 00000000000..ca335ce9cf0 --- /dev/null +++ b/spec/requests/api/v3/runners_spec.rb @@ -0,0 +1,154 @@ +require 'spec_helper' + +describe API::V3::Runners, api: true do + include ApiHelpers + + let(:admin) { create(:user, :admin) } + let(:user) { create(:user) } + let(:user2) { create(:user) } + + let(:project) { create(:empty_project, creator_id: user.id) } + let(:project2) { create(:empty_project, creator_id: user.id) } + + let!(:shared_runner) { create(:ci_runner, :shared) } + let!(:unused_specific_runner) { create(:ci_runner) } + + let!(:specific_runner) do + create(:ci_runner).tap do |runner| + create(:ci_runner_project, runner: runner, project: project) + end + end + + let!(:two_projects_runner) do + create(:ci_runner).tap do |runner| + create(:ci_runner_project, runner: runner, project: project) + create(:ci_runner_project, runner: runner, project: project2) + end + end + + before do + # Set project access for users + create(:project_member, :master, user: user, project: project) + create(:project_member, :reporter, user: user2, project: project) + end + + describe 'DELETE /runners/:id' do + context 'admin user' do + context 'when runner is shared' do + it 'deletes runner' do + expect do + delete v3_api("/runners/#{shared_runner.id}", admin) + + expect(response).to have_http_status(200) + end.to change{ Ci::Runner.shared.count }.by(-1) + end + end + + context 'when runner is not shared' do + it 'deletes unused runner' do + expect do + delete v3_api("/runners/#{unused_specific_runner.id}", admin) + + expect(response).to have_http_status(200) + end.to change{ Ci::Runner.specific.count }.by(-1) + end + + it 'deletes used runner' do + expect do + delete v3_api("/runners/#{specific_runner.id}", admin) + + expect(response).to have_http_status(200) + end.to change{ Ci::Runner.specific.count }.by(-1) + end + end + + it 'returns 404 if runner does not exists' do + delete v3_api('/runners/9999', admin) + + expect(response).to have_http_status(404) + end + end + + context 'authorized user' do + context 'when runner is shared' do + it 'does not delete runner' do + delete v3_api("/runners/#{shared_runner.id}", user) + expect(response).to have_http_status(403) + end + end + + context 'when runner is not shared' do + it 'does not delete runner without access to it' do + delete v3_api("/runners/#{specific_runner.id}", user2) + expect(response).to have_http_status(403) + end + + it 'does not delete runner with more than one associated project' do + delete v3_api("/runners/#{two_projects_runner.id}", user) + expect(response).to have_http_status(403) + end + + it 'deletes runner for one owned project' do + expect do + delete v3_api("/runners/#{specific_runner.id}", user) + + expect(response).to have_http_status(200) + end.to change{ Ci::Runner.specific.count }.by(-1) + end + end + end + + context 'unauthorized user' do + it 'does not delete runner' do + delete v3_api("/runners/#{specific_runner.id}") + + expect(response).to have_http_status(401) + end + end + end + + describe 'DELETE /projects/:id/runners/:runner_id' do + context 'authorized user' do + context 'when runner have more than one associated projects' do + it "disables project's runner" do + expect do + delete v3_api("/projects/#{project.id}/runners/#{two_projects_runner.id}", user) + + expect(response).to have_http_status(200) + end.to change{ project.runners.count }.by(-1) + end + end + + context 'when runner have one associated projects' do + it "does not disable project's runner" do + expect do + delete v3_api("/projects/#{project.id}/runners/#{specific_runner.id}", user) + end.to change{ project.runners.count }.by(0) + expect(response).to have_http_status(403) + end + end + + it 'returns 404 is runner is not found' do + delete v3_api("/projects/#{project.id}/runners/9999", user) + + expect(response).to have_http_status(404) + end + end + + context 'authorized user without permissions' do + it "does not disable project's runner" do + delete v3_api("/projects/#{project.id}/runners/#{specific_runner.id}", user2) + + expect(response).to have_http_status(403) + end + end + + context 'unauthorized user' do + it "does not disable project's runner" do + delete v3_api("/projects/#{project.id}/runners/#{specific_runner.id}") + + expect(response).to have_http_status(401) + end + end + end +end diff --git a/spec/requests/api/v3/services_spec.rb b/spec/requests/api/v3/services_spec.rb new file mode 100644 index 00000000000..7e8c8753d02 --- /dev/null +++ b/spec/requests/api/v3/services_spec.rb @@ -0,0 +1,22 @@ +require "spec_helper" + +describe API::V3::Services, api: true do + include ApiHelpers + + let(:user) { create(:user) } + let(:project) { create(:empty_project, creator_id: user.id, namespace: user.namespace) } + + Service.available_services_names.each do |service| + describe "DELETE /projects/:id/services/#{service.dasherize}" do + include_context service + + it "deletes #{service}" do + delete v3_api("/projects/#{project.id}/services/#{dashed_service}", user) + + expect(response).to have_http_status(200) + project.send(service_method).reload + expect(project.send(service_method).activated?).to be_falsey + end + end + end +end diff --git a/spec/requests/api/v3/system_hooks_spec.rb b/spec/requests/api/v3/system_hooks_spec.rb index da58efb6ebf..91038977c82 100644 --- a/spec/requests/api/v3/system_hooks_spec.rb +++ b/spec/requests/api/v3/system_hooks_spec.rb @@ -38,4 +38,20 @@ describe API::V3::SystemHooks, api: true do end end end + + describe "DELETE /hooks/:id" do + it "deletes a hook" do + expect do + delete v3_api("/hooks/#{hook.id}", admin) + + expect(response).to have_http_status(200) + end.to change { SystemHook.count }.by(-1) + end + + it 'returns 404 if the system hook does not exist' do + delete v3_api('/hooks/12345', admin) + + expect(response).to have_http_status(404) + end + end end diff --git a/spec/requests/api/v3/tags_spec.rb b/spec/requests/api/v3/tags_spec.rb index 6722789d928..6870cfd2668 100644 --- a/spec/requests/api/v3/tags_spec.rb +++ b/spec/requests/api/v3/tags_spec.rb @@ -64,4 +64,26 @@ describe API::V3::Tags, api: true do end end end + + describe 'DELETE /projects/:id/repository/tags/:tag_name' do + let(:tag_name) { project.repository.tag_names.sort.reverse.first } + + before do + allow_any_instance_of(Repository).to receive(:rm_tag).and_return(true) + end + + context 'delete tag' do + it 'deletes an existing tag' do + delete v3_api("/projects/#{project.id}/repository/tags/#{tag_name}", user) + + expect(response).to have_http_status(200) + expect(json_response['tag_name']).to eq(tag_name) + end + + it 'raises 404 if the tag does not exist' do + delete v3_api("/projects/#{project.id}/repository/tags/foobar", user) + expect(response).to have_http_status(404) + end + end + end end diff --git a/spec/requests/api/v3/triggers_spec.rb b/spec/requests/api/v3/triggers_spec.rb new file mode 100644 index 00000000000..721ce4a361b --- /dev/null +++ b/spec/requests/api/v3/triggers_spec.rb @@ -0,0 +1,47 @@ +require 'spec_helper' + +describe API::V3::Triggers do + include ApiHelpers + + let(:user) { create(:user) } + let(:user2) { create(:user) } + let!(:trigger_token) { 'secure_token' } + let!(:project) { create(:project, :repository, creator: user) } + let!(:master) { create(:project_member, :master, user: user, project: project) } + let!(:developer) { create(:project_member, :developer, user: user2, project: project) } + let!(:trigger) { create(:ci_trigger, project: project, token: trigger_token) } + + describe 'DELETE /projects/:id/triggers/:token' do + context 'authenticated user with valid permissions' do + it 'deletes trigger' do + expect do + delete v3_api("/projects/#{project.id}/triggers/#{trigger.token}", user) + + expect(response).to have_http_status(200) + end.to change{project.triggers.count}.by(-1) + end + + it 'responds with 404 Not Found if requesting non-existing trigger' do + delete v3_api("/projects/#{project.id}/triggers/abcdef012345", user) + + expect(response).to have_http_status(404) + end + end + + context 'authenticated user with invalid permissions' do + it 'does not delete trigger' do + delete v3_api("/projects/#{project.id}/triggers/#{trigger.token}", user2) + + expect(response).to have_http_status(403) + end + end + + context 'unauthenticated user' do + it 'does not delete trigger' do + delete v3_api("/projects/#{project.id}/triggers/#{trigger.token}") + + expect(response).to have_http_status(401) + end + end + end +end diff --git a/spec/requests/api/variables_spec.rb b/spec/requests/api/variables_spec.rb index 769f04c5057..0c1413119e0 100644 --- a/spec/requests/api/variables_spec.rb +++ b/spec/requests/api/variables_spec.rb @@ -152,8 +152,9 @@ describe API::Variables, api: true do it 'deletes variable' do expect do delete api("/projects/#{project.id}/variables/#{variable.key}", user) + + expect(response).to have_http_status(204) end.to change{project.variables.count}.by(-1) - expect(response).to have_http_status(200) end it 'responds with 404 Not Found if requesting non-existing variable' do diff --git a/spec/requests/ci/api/builds_spec.rb b/spec/requests/ci/api/builds_spec.rb index 444258e312d..9948d1a9ea0 100644 --- a/spec/requests/ci/api/builds_spec.rb +++ b/spec/requests/ci/api/builds_spec.rb @@ -630,6 +630,7 @@ describe Ci::API::Builds do context 'with an expire date' do let!(:artifacts) { file_upload } + let(:default_artifacts_expire_in) {} let(:post_data) do { 'file.path' => artifacts.path, @@ -638,6 +639,9 @@ describe Ci::API::Builds do end before do + stub_application_setting( + default_artifacts_expire_in: default_artifacts_expire_in) + post(post_url, post_data, headers_with_token) end @@ -648,7 +652,8 @@ describe Ci::API::Builds do build.reload expect(response).to have_http_status(201) expect(json_response['artifacts_expire_at']).not_to be_empty - expect(build.artifacts_expire_at).to be_within(5.minutes).of(Time.now + 7.days) + expect(build.artifacts_expire_at). + to be_within(5.minutes).of(7.days.from_now) end end @@ -661,6 +666,32 @@ describe Ci::API::Builds do expect(json_response['artifacts_expire_at']).to be_nil expect(build.artifacts_expire_at).to be_nil end + + context 'with application default' do + context 'default to 5 days' do + let(:default_artifacts_expire_in) { '5 days' } + + it 'sets to application default' do + build.reload + expect(response).to have_http_status(201) + expect(json_response['artifacts_expire_at']) + .not_to be_empty + expect(build.artifacts_expire_at) + .to be_within(5.minutes).of(5.days.from_now) + end + end + + context 'default to 0' do + let(:default_artifacts_expire_in) { '0' } + + it 'does not set expire_in' do + build.reload + expect(response).to have_http_status(201) + expect(json_response['artifacts_expire_at']).to be_nil + expect(build.artifacts_expire_at).to be_nil + end + end + end end end diff --git a/spec/rubocop/cop/custom_error_class_spec.rb b/spec/rubocop/cop/custom_error_class_spec.rb new file mode 100644 index 00000000000..381d7871a40 --- /dev/null +++ b/spec/rubocop/cop/custom_error_class_spec.rb @@ -0,0 +1,111 @@ +require 'spec_helper' + +require 'rubocop' +require 'rubocop/rspec/support' + +require_relative '../../../rubocop/cop/custom_error_class' + +describe RuboCop::Cop::CustomErrorClass do + include CopHelper + + subject(:cop) { described_class.new } + + context 'when a class has a body' do + it 'does nothing' do + inspect_source(cop, 'class CustomError < StandardError; def foo; end; end') + + expect(cop.offenses).to be_empty + end + end + + context 'when a class has no explicit superclass' do + it 'does nothing' do + inspect_source(cop, 'class CustomError; end') + + expect(cop.offenses).to be_empty + end + end + + context 'when a class has a superclass that does not end in Error' do + it 'does nothing' do + inspect_source(cop, 'class CustomError < BasicObject; end') + + expect(cop.offenses).to be_empty + end + end + + context 'when a class is empty and inherits from a class ending in Error' do + context 'when the class is on a single line' do + let(:source) do + <<-SOURCE + module Foo + class CustomError < Bar::Baz::BaseError; end + end + SOURCE + end + + let(:expected) do + <<-EXPECTED + module Foo + CustomError = Class.new(Bar::Baz::BaseError) + end + EXPECTED + end + + it 'registers an offense' do + expected_highlights = source.split("\n")[1].strip + + inspect_source(cop, source) + + aggregate_failures do + expect(cop.offenses.size).to eq(1) + expect(cop.offenses.map(&:line)).to eq([2]) + expect(cop.highlights).to contain_exactly(expected_highlights) + end + end + + it 'autocorrects to the right version' do + autocorrected = autocorrect_source(cop, source, 'foo/custom_error.rb') + + expect(autocorrected).to eq(expected) + end + end + + context 'when the class is on multiple lines' do + let(:source) do + <<-SOURCE + module Foo + class CustomError < Bar::Baz::BaseError + end + end + SOURCE + end + + let(:expected) do + <<-EXPECTED + module Foo + CustomError = Class.new(Bar::Baz::BaseError) + end + EXPECTED + end + + it 'registers an offense' do + expected_highlights = source.split("\n")[1..2].join("\n").strip + + inspect_source(cop, source) + + aggregate_failures do + expect(cop.offenses.size).to eq(1) + expect(cop.offenses.map(&:line)).to eq([2]) + expect(cop.highlights).to contain_exactly(expected_highlights) + end + end + + it 'autocorrects to the right version' do + autocorrected = autocorrect_source(cop, source, 'foo/custom_error.rb') + + expect(autocorrected).to eq(expected) + end + end + end +end diff --git a/spec/services/ci/process_pipeline_service_spec.rb b/spec/services/ci/process_pipeline_service_spec.rb index b818dfdd50c..de68fb64726 100644 --- a/spec/services/ci/process_pipeline_service_spec.rb +++ b/spec/services/ci/process_pipeline_service_spec.rb @@ -341,7 +341,7 @@ describe Ci::ProcessPipelineService, :services do expect(builds.pending.count).to eq(1) expect(all_builds.count).to eq(4) - # When pending build succeeds in stage test, we enqueue deploy stage. + # When pending merge_when_pipeline_succeeds in stage test, we enqueue deploy stage. # succeed_pending process_pipeline diff --git a/spec/services/ci/register_build_service_spec.rb b/spec/services/ci/register_build_service_spec.rb index d9f774a1095..cd7dd53025c 100644 --- a/spec/services/ci/register_build_service_spec.rb +++ b/spec/services/ci/register_build_service_spec.rb @@ -170,6 +170,51 @@ module Ci end end + context 'when first build is stalled' do + before do + pending_build.lock_version = 10 + end + + subject { described_class.new(specific_runner).execute } + + context 'with multiple builds are in queue' do + let!(:other_build) { create :ci_build, pipeline: pipeline } + + before do + allow_any_instance_of(Ci::RegisterBuildService).to receive(:builds_for_specific_runner) + .and_return([pending_build, other_build]) + end + + it "receives second build from the queue" do + expect(subject).to be_valid + expect(subject.build).to eq(other_build) + end + end + + context 'when single build is in queue' do + before do + allow_any_instance_of(Ci::RegisterBuildService).to receive(:builds_for_specific_runner) + .and_return([pending_build]) + end + + it "does not receive any valid result" do + expect(subject).not_to be_valid + end + end + + context 'when there is no build in queue' do + before do + allow_any_instance_of(Ci::RegisterBuildService).to receive(:builds_for_specific_runner) + .and_return([]) + end + + it "does not receive builds but result is valid" do + expect(subject).to be_valid + expect(subject.build).to be_nil + end + end + end + def execute(runner) described_class.new(runner).execute.build end diff --git a/spec/services/groups/destroy_service_spec.rb b/spec/services/groups/destroy_service_spec.rb index 32c2ed8cae7..98c560ffb26 100644 --- a/spec/services/groups/destroy_service_spec.rb +++ b/spec/services/groups/destroy_service_spec.rb @@ -5,6 +5,7 @@ describe Groups::DestroyService, services: true do let!(:user) { create(:user) } let!(:group) { create(:group) } + let!(:nested_group) { create(:group, parent: group) } let!(:project) { create(:project, namespace: group) } let!(:gitlab_shell) { Gitlab::Shell.new } let!(:remove_path) { group.path + "+#{group.id}+deleted" } @@ -20,6 +21,7 @@ describe Groups::DestroyService, services: true do end it { expect(Group.unscoped.all).not_to include(group) } + it { expect(Group.unscoped.all).not_to include(nested_group) } it { expect(Project.unscoped.all).not_to include(project) } end diff --git a/spec/services/merge_requests/merge_when_pipeline_succeeds_service_spec.rb b/spec/services/merge_requests/merge_when_pipeline_succeeds_service_spec.rb index f92978a33a3..c2f205c389d 100644 --- a/spec/services/merge_requests/merge_when_pipeline_succeeds_service_spec.rb +++ b/spec/services/merge_requests/merge_when_pipeline_succeeds_service_spec.rb @@ -5,7 +5,7 @@ describe MergeRequests::MergeWhenPipelineSucceedsService do let(:project) { create(:project) } let(:mr_merge_if_green_enabled) do - create(:merge_request, merge_when_build_succeeds: true, merge_user: user, + create(:merge_request, merge_when_pipeline_succeeds: true, merge_user: user, source_branch: "master", target_branch: 'feature', source_project: project, target_project: project, state: "opened") end @@ -36,7 +36,7 @@ describe MergeRequests::MergeWhenPipelineSucceedsService do it 'sets the params, merge_user, and flag' do expect(merge_request).to be_valid - expect(merge_request.merge_when_build_succeeds).to be_truthy + expect(merge_request.merge_when_pipeline_succeeds).to be_truthy expect(merge_request.merge_params).to eq commit_message: 'Awesome message' expect(merge_request.merge_user).to be user end @@ -62,7 +62,7 @@ describe MergeRequests::MergeWhenPipelineSucceedsService do end it 'updates the merge params' do - expect(SystemNoteService).not_to receive(:merge_when_build_succeeds) + expect(SystemNoteService).not_to receive(:merge_when_pipeline_succeeds) service.execute(mr_merge_if_green_enabled) expect(mr_merge_if_green_enabled.merge_params).to have_key(:new_key) @@ -82,7 +82,7 @@ describe MergeRequests::MergeWhenPipelineSucceedsService do sha: merge_request_head, status: 'success') end - it "merges all merge requests with merge when build succeeds enabled" do + it "merges all merge requests with merge when the pipeline succeeds enabled" do expect(MergeWorker).to receive(:perform_async) service.trigger(triggering_pipeline) end @@ -111,6 +111,31 @@ describe MergeRequests::MergeWhenPipelineSucceedsService do service.trigger(unrelated_pipeline) end end + + context 'when the merge request is not mergeable' do + let(:mr_conflict) do + create(:merge_request, merge_when_pipeline_succeeds: true, merge_user: user, + source_branch: 'master', target_branch: 'feature-conflict', + source_project: project, target_project: project) + end + + let(:conflict_pipeline) do + create(:ci_pipeline, project: project, ref: mr_conflict.source_branch, + sha: mr_conflict.diff_head_sha, status: 'success') + end + + it 'does not merge the merge request' do + expect(MergeWorker).not_to receive(:perform_async) + + service.trigger(conflict_pipeline) + end + + it 'creates todos for unmergeability' do + expect_any_instance_of(TodoService).to receive(:merge_request_became_unmergeable).with(mr_conflict) + + service.trigger(conflict_pipeline) + end + end end describe "#cancel" do @@ -118,8 +143,8 @@ describe MergeRequests::MergeWhenPipelineSucceedsService 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 + it "resets all the pipeline succeeds params" do + expect(mr_merge_if_green_enabled.merge_when_pipeline_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 diff --git a/spec/services/merge_requests/refresh_service_spec.rb b/spec/services/merge_requests/refresh_service_spec.rb index 983dac6efdb..ff367f54d2a 100644 --- a/spec/services/merge_requests/refresh_service_spec.rb +++ b/spec/services/merge_requests/refresh_service_spec.rb @@ -18,7 +18,7 @@ describe MergeRequests::RefreshService, services: true do source_branch: 'master', target_branch: 'feature', target_project: @project, - merge_when_build_succeeds: true, + merge_when_pipeline_succeeds: true, merge_user: @user) @fork_merge_request = create(:merge_request, @@ -62,7 +62,7 @@ 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_pipeline_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 } diff --git a/spec/services/merge_requests/resolve_service_spec.rb b/spec/services/merge_requests/resolve_service_spec.rb index c3b468ac47f..d33535d22af 100644 --- a/spec/services/merge_requests/resolve_service_spec.rb +++ b/spec/services/merge_requests/resolve_service_spec.rb @@ -66,13 +66,12 @@ describe MergeRequests::ResolveService do context 'when the source project is a fork and does not contain the HEAD of the target branch' do let!(:target_head) do - project.repository.commit_file( + project.repository.create_file( user, 'new-file-in-target', '', message: 'Add new file in target', - branch_name: 'conflict-start', - update: false) + branch_name: 'conflict-start') end before do diff --git a/spec/services/notes/create_service_spec.rb b/spec/services/notes/create_service_spec.rb index 9c92a5080c6..152c6d20daa 100644 --- a/spec/services/notes/create_service_spec.rb +++ b/spec/services/notes/create_service_spec.rb @@ -102,47 +102,19 @@ describe Notes::CreateService, services: true do expect(subject.note).to eq(params[:note]) end end - end - - describe "award emoji" do - before do - project.team << [user, :master] - end - - it "creates an award emoji" do - opts = { - note: ':smile: ', - noteable_type: 'Issue', - noteable_id: issue.id - } - note = described_class.new(project, user, opts).execute - - expect(note).to be_valid - expect(note.name).to eq('smile') - end - it "creates regular note if emoji name is invalid" do - opts = { - note: ':smile: moretext:', - noteable_type: 'Issue', - noteable_id: issue.id - } - note = described_class.new(project, user, opts).execute - - expect(note).to be_valid - expect(note.note).to eq(opts[:note]) - end - - it "normalizes the emoji name" do - opts = { - note: ':+1:', - noteable_type: 'Issue', - noteable_id: issue.id - } - - expect_any_instance_of(TodoService).to receive(:new_award_emoji).with(issue, user) + describe 'note with emoji only' do + it 'creates regular note' do + opts = { + note: ':smile: ', + noteable_type: 'Issue', + noteable_id: issue.id + } + note = described_class.new(project, user, opts).execute - described_class.new(project, user, opts).execute + expect(note).to be_valid + expect(note.note).to eq(':smile:') + end end end end diff --git a/spec/services/notification_service_spec.rb b/spec/services/notification_service_spec.rb index 839250b7d84..ebbaea4e59a 100644 --- a/spec/services/notification_service_spec.rb +++ b/spec/services/notification_service_spec.rb @@ -1050,22 +1050,22 @@ describe NotificationService, services: true do should_not_email(@u_lazy_participant) end - it "notifies the merger when merge_when_build_succeeds is true" do - merge_request.merge_when_build_succeeds = true + it "notifies the merger when the pipeline succeeds is true" do + merge_request.merge_when_pipeline_succeeds = true notification.merge_mr(merge_request, @u_watcher) should_email(@u_watcher) end - it "does not notify the merger when merge_when_build_succeeds is false" do - merge_request.merge_when_build_succeeds = false + it "does not notify the merger when the pipeline succeeds is false" do + merge_request.merge_when_pipeline_succeeds = false notification.merge_mr(merge_request, @u_watcher) should_not_email(@u_watcher) end - it "notifies the merger when merge_when_build_succeeds is false but they've opted into notifications about their activity" do - merge_request.merge_when_build_succeeds = false + it "notifies the merger when the pipeline succeeds is false but they've opted into notifications about their activity" do + merge_request.merge_when_pipeline_succeeds = false @u_watcher.notified_of_own_activity = true notification.merge_mr(merge_request, @u_watcher) diff --git a/spec/services/slash_commands/interpret_service_spec.rb b/spec/services/slash_commands/interpret_service_spec.rb index 0b0925983eb..52e8678cb9d 100644 --- a/spec/services/slash_commands/interpret_service_spec.rb +++ b/spec/services/slash_commands/interpret_service_spec.rb @@ -267,6 +267,14 @@ describe SlashCommands::InterpretService, services: true do end end + shared_examples 'award command' do + it 'toggle award 100 emoji if content containts /award :100:' do + _, updates = service.execute(content, issuable) + + expect(updates).to eq(emoji_award: "100") + end + end + it_behaves_like 'reopen command' do let(:content) { '/reopen' } let(:issuable) { issue } @@ -654,6 +662,37 @@ describe SlashCommands::InterpretService, services: true do end end + context '/award command' do + it_behaves_like 'award command' do + let(:content) { '/award :100:' } + let(:issuable) { issue } + end + + it_behaves_like 'award command' do + let(:content) { '/award :100:' } + let(:issuable) { merge_request } + end + + context 'ignores command with no argument' do + it_behaves_like 'empty command' do + let(:content) { '/award' } + let(:issuable) { issue } + end + end + + context 'ignores non-existing / invalid emojis' do + it_behaves_like 'empty command' do + let(:content) { '/award noop' } + let(:issuable) { issue } + end + + it_behaves_like 'empty command' do + let(:content) { '/award :lorem_ipsum:' } + let(:issuable) { issue } + end + end + end + context '/target_branch command' do let(:non_empty_project) { create(:project) } let(:another_merge_request) { create(:merge_request, author: developer, source_project: non_empty_project) } diff --git a/spec/services/system_note_service_spec.rb b/spec/services/system_note_service_spec.rb index eca5a418f2a..1f2ec9eacf0 100644 --- a/spec/services/system_note_service_spec.rb +++ b/spec/services/system_note_service_spec.rb @@ -215,13 +215,13 @@ describe SystemNoteService, services: true do end end - describe '.merge_when_build_succeeds' do + describe '.merge_when_pipeline_succeeds' do let(:pipeline) { build(:ci_pipeline_without_jobs )} let(:noteable) do create(:merge_request, source_project: project, target_project: project) end - subject { described_class.merge_when_build_succeeds(noteable, project, author, noteable.diff_head_commit) } + subject { described_class.merge_when_pipeline_succeeds(noteable, project, author, noteable.diff_head_commit) } it_behaves_like 'a system note' @@ -230,12 +230,12 @@ describe SystemNoteService, services: true do end end - describe '.cancel_merge_when_build_succeeds' do + describe '.cancel_merge_when_pipeline_succeeds' do let(:noteable) do create(:merge_request, source_project: project, target_project: project) end - subject { described_class.cancel_merge_when_build_succeeds(noteable, project, author) } + subject { described_class.cancel_merge_when_pipeline_succeeds(noteable, project, author) } it_behaves_like 'a system note' diff --git a/spec/services/todo_service_spec.rb b/spec/services/todo_service_spec.rb index 9f24cc0f3f2..fb9a8462f84 100644 --- a/spec/services/todo_service_spec.rb +++ b/spec/services/todo_service_spec.rb @@ -680,7 +680,7 @@ describe TodoService, services: true do end it 'creates a pending todo for merge_user' do - mr_unassigned.update(merge_when_build_succeeds: true, merge_user: admin) + mr_unassigned.update(merge_when_pipeline_succeeds: true, merge_user: admin) service.merge_request_build_failed(mr_unassigned) should_create_todo(user: admin, author: admin, target: mr_unassigned, action: Todo::BUILD_FAILED) @@ -700,7 +700,7 @@ describe TodoService, services: true do describe '#merge_request_became_unmergeable' do it 'creates a pending todo for a merge_user' do - mr_unassigned.update(merge_when_build_succeeds: true, merge_user: admin) + mr_unassigned.update(merge_when_pipeline_succeeds: true, merge_user: admin) service.merge_request_became_unmergeable(mr_unassigned) should_create_todo(user: admin, author: admin, target: mr_unassigned, action: Todo::UNMERGEABLE) diff --git a/spec/services/users/destroy_spec.rb b/spec/services/users/destroy_spec.rb index c0bf27c698c..922e82445d0 100644 --- a/spec/services/users/destroy_spec.rb +++ b/spec/services/users/destroy_spec.rb @@ -24,6 +24,54 @@ describe Users::DestroyService, services: true do end end + context "a deleted user's issues" do + let(:project) { create :project } + + before do + project.add_developer(user) + end + + context "for an issue the user has created" do + let!(:issue) { create(:issue, project: project, author: user) } + + before do + service.execute(user) + end + + it 'does not delete the issue' do + expect(Issue.find_by_id(issue.id)).to be_present + end + + it 'migrates the issue so that the "Ghost User" is the issue owner' do + migrated_issue = Issue.find_by_id(issue.id) + + expect(migrated_issue.author).to eq(User.ghost) + end + + it 'blocks the user before migrating issues to the "Ghost User' do + expect(user).to be_blocked + end + end + + context "for an issue the user was assigned to" do + let!(:issue) { create(:issue, project: project, assignee: user) } + + before do + service.execute(user) + end + + it 'does not delete issues the user is assigned to' do + expect(Issue.find_by_id(issue.id)).to be_present + end + + it 'migrates the issue so that it is "Unassigned"' do + migrated_issue = Issue.find_by_id(issue.id) + + expect(migrated_issue.assignee).to be_nil + end + end + end + context "solo owned groups present" do let(:solo_owned) { create(:group) } let(:member) { create(:group_member) } diff --git a/spec/services/users/refresh_authorized_projects_service_spec.rb b/spec/services/users/refresh_authorized_projects_service_spec.rb index 690fe979492..08733d6dcf1 100644 --- a/spec/services/users/refresh_authorized_projects_service_spec.rb +++ b/spec/services/users/refresh_authorized_projects_service_spec.rb @@ -131,6 +131,80 @@ describe Users::RefreshAuthorizedProjectsService do it 'sets the values to the access levels' do expect(hash.values).to eq([Gitlab::Access::MASTER]) end + + context 'personal projects' do + it 'includes the project with the right access level' do + expect(hash[project.id]).to eq(Gitlab::Access::MASTER) + end + end + + context 'projects the user is a member of' do + let!(:other_project) { create(:empty_project) } + + before do + other_project.team.add_reporter(user) + end + + it 'includes the project with the right access level' do + expect(hash[other_project.id]).to eq(Gitlab::Access::REPORTER) + end + end + + context 'projects of groups the user is a member of' do + let(:group) { create(:group) } + let!(:other_project) { create(:project, group: group) } + + before do + group.add_owner(user) + end + + it 'includes the project with the right access level' do + expect(hash[other_project.id]).to eq(Gitlab::Access::OWNER) + end + end + + context 'projects of subgroups of groups the user is a member of' do + let(:group) { create(:group) } + let(:nested_group) { create(:group, parent: group) } + let!(:other_project) { create(:project, group: nested_group) } + + before do + group.add_master(user) + end + + it 'includes the project with the right access level' do + expect(hash[other_project.id]).to eq(Gitlab::Access::MASTER) + end + end + + context 'projects shared with groups the user is a member of' do + let(:group) { create(:group) } + let(:other_project) { create(:empty_project) } + let!(:project_group_link) { create(:project_group_link, project: other_project, group: group, group_access: Gitlab::Access::GUEST) } + + before do + group.add_master(user) + end + + it 'includes the project with the right access level' do + expect(hash[other_project.id]).to eq(Gitlab::Access::GUEST) + end + end + + context 'projects shared with subgroups of groups the user is a member of' do + let(:group) { create(:group) } + let(:nested_group) { create(:group, parent: group) } + let(:other_project) { create(:empty_project) } + let!(:project_group_link) { create(:project_group_link, project: other_project, group: nested_group, group_access: Gitlab::Access::DEVELOPER) } + + before do + group.add_master(user) + end + + it 'includes the project with the right access level' do + expect(hash[other_project.id]).to eq(Gitlab::Access::DEVELOPER) + end + end end describe '#current_authorizations_per_project' do diff --git a/spec/support/cycle_analytics_helpers.rb b/spec/support/cycle_analytics_helpers.rb index 6ed55289ed9..c864a705ca4 100644 --- a/spec/support/cycle_analytics_helpers.rb +++ b/spec/support/cycle_analytics_helpers.rb @@ -9,14 +9,7 @@ module CycleAnalyticsHelpers commit_shas = Array.new(count) do |index| filename = random_git_name - options = { - committer: project.repository.user_to_committer(user), - author: project.repository.user_to_committer(user), - commit: { message: message, branch: branch_name, update_ref: true }, - file: { content: "content", path: filename, update: false } - } - - commit_sha = Gitlab::Git::Blob.commit(project.repository, options) + commit_sha = project.repository.create_file(user, filename, "content", message: message, branch_name: branch_name) project.repository.commit(commit_sha) commit_sha @@ -35,13 +28,12 @@ module CycleAnalyticsHelpers project.repository.add_branch(user, source_branch, 'master') end - sha = project.repository.commit_file( + sha = project.repository.create_file( user, random_git_name, 'content', message: 'commit message', - branch_name: source_branch, - update: false) + branch_name: source_branch) project.repository.commit(sha) opts = { diff --git a/spec/support/dropzone_helper.rb b/spec/support/dropzone_helper.rb new file mode 100644 index 00000000000..984ec7d2741 --- /dev/null +++ b/spec/support/dropzone_helper.rb @@ -0,0 +1,37 @@ +module DropzoneHelper + # Provides a way to perform `attach_file` for a Dropzone-based file input + # + # This is accomplished by creating a standard HTML file input on the page, + # performing `attach_file` on that field, and then triggering the appropriate + # Dropzone events to perform the actual upload. + # + # This method waits for the upload to complete before returning. + def dropzone_file(file_path) + # Generate a fake file input that Capybara can attach to + page.execute_script <<-JS.strip_heredoc + var fakeFileInput = window.$('<input/>').attr( + {id: 'fakeFileInput', type: 'file'} + ).appendTo('body'); + + window._dropzoneComplete = false; + JS + + # Attach the file to the fake input selector with Capybara + attach_file('fakeFileInput', file_path) + + # Manually trigger a Dropzone "drop" event with the fake input's file list + page.execute_script <<-JS.strip_heredoc + var fileList = [$('#fakeFileInput')[0].files[0]]; + var e = jQuery.Event('drop', { dataTransfer : { files : fileList } }); + + var dropzone = $('.div-dropzone')[0].dropzone; + dropzone.on('queuecomplete', function() { + window._dropzoneComplete = true; + }); + dropzone.listeners[0].events.drop(e); + JS + + # Wait until Dropzone's fired `queuecomplete` + loop until page.evaluate_script('window._dropzoneComplete === true') + end +end diff --git a/spec/support/issuables_list_metadata_shared_examples.rb b/spec/support/issuables_list_metadata_shared_examples.rb index 4644c7a6b86..4c0f556e736 100644 --- a/spec/support/issuables_list_metadata_shared_examples.rb +++ b/spec/support/issuables_list_metadata_shared_examples.rb @@ -22,7 +22,7 @@ shared_examples 'issuables list meta-data' do |issuable_type, action = nil| if action get action else - get :index, namespace_id: project.namespace.path, project_id: project.path + get :index, namespace_id: project.namespace, project_id: project end meta_data = assigns(:issuable_meta_data) diff --git a/spec/support/markdown_feature.rb b/spec/support/markdown_feature.rb index a79386b5db9..dea0015f105 100644 --- a/spec/support/markdown_feature.rb +++ b/spec/support/markdown_feature.rb @@ -79,8 +79,8 @@ class MarkdownFeature def xproject @xproject ||= begin - namespace = create(:namespace, name: 'cross-reference') - create(:project, namespace: namespace) do |project| + group = create(:group, :nested) + create(:project, namespace: group) do |project| project.team << [user, :developer] end end diff --git a/spec/support/matchers/gitaly_matchers.rb b/spec/support/matchers/gitaly_matchers.rb new file mode 100644 index 00000000000..d7a53820684 --- /dev/null +++ b/spec/support/matchers/gitaly_matchers.rb @@ -0,0 +1,3 @@ +RSpec::Matchers.define :post_receive_request_with_repo_path do |path| + match { |actual| actual.repository.path == path } +end diff --git a/spec/support/test_env.rb b/spec/support/test_env.rb index 4e63a4cd537..c3aa3ef44c2 100644 --- a/spec/support/test_env.rb +++ b/spec/support/test_env.rb @@ -135,7 +135,7 @@ module TestEnv def copy_repo(project) base_repo_path = File.expand_path(factory_repo_path_bare) - target_repo_path = File.expand_path(project.repository_storage_path + "/#{project.namespace.path}/#{project.path}.git") + target_repo_path = File.expand_path(project.repository_storage_path + "/#{project.full_path}.git") FileUtils.mkdir_p(target_repo_path) FileUtils.cp_r("#{base_repo_path}/.", target_repo_path) FileUtils.chmod_R 0755, target_repo_path @@ -152,7 +152,7 @@ module TestEnv def copy_forked_repo_with_submodules(project) base_repo_path = File.expand_path(forked_repo_path_bare) - target_repo_path = File.expand_path(project.repository_storage_path + "/#{project.namespace.path}/#{project.path}.git") + target_repo_path = File.expand_path(project.repository_storage_path + "/#{project.full_path}.git") FileUtils.mkdir_p(target_repo_path) FileUtils.cp_r("#{base_repo_path}/.", target_repo_path) FileUtils.chmod_R 0755, target_repo_path diff --git a/spec/support/update_invalid_issuable.rb b/spec/support/update_invalid_issuable.rb new file mode 100644 index 00000000000..365c34448ac --- /dev/null +++ b/spec/support/update_invalid_issuable.rb @@ -0,0 +1,57 @@ +shared_examples 'update invalid issuable' do |klass| + let(:params) do + { + namespace_id: project.namespace.path, + project_id: project.path, + id: issuable.iid + } + end + + let(:issuable) do + klass == Issue ? issue : merge_request + end + + before do + if klass == Issue + params.merge!(issue: { title: "any" }) + else + params.merge!(merge_request: { title: "any" }) + end + end + + context 'when updating causes conflicts' do + before do + allow_any_instance_of(issuable.class).to receive(:save). + and_raise(ActiveRecord::StaleObjectError.new(issuable, :save)) + end + + it 'renders edit when format is html' do + put :update, params + + expect(response).to render_template(:edit) + expect(assigns[:conflict]).to be_truthy + end + + it 'renders json error message when format is json' do + params[:format] = "json" + + put :update, params + + expect(response.status).to eq(409) + expect(JSON.parse(response.body)).to have_key('errors') + end + end + + context 'when updating an invalid issuable' do + before do + key = klass == Issue ? :issue : :merge_request + params[key][:title] = "" + end + + it 'renders edit when merge request is invalid' do + put :update, params + + expect(response).to render_template(:edit) + end + end +end diff --git a/spec/uploaders/attachment_uploader_spec.rb b/spec/uploaders/attachment_uploader_spec.rb index 6098be5cd45..ea714fb08f0 100644 --- a/spec/uploaders/attachment_uploader_spec.rb +++ b/spec/uploaders/attachment_uploader_spec.rb @@ -1,18 +1,17 @@ require 'spec_helper' describe AttachmentUploader do - let(:issue) { build(:issue) } - subject { described_class.new(issue) } + let(:uploader) { described_class.new(build_stubbed(:user)) } describe '#move_to_cache' do it 'is true' do - expect(subject.move_to_cache).to eq(true) + expect(uploader.move_to_cache).to eq(true) end end describe '#move_to_store' do it 'is true' do - expect(subject.move_to_store).to eq(true) + expect(uploader.move_to_store).to eq(true) end end end diff --git a/spec/uploaders/avatar_uploader_spec.rb b/spec/uploaders/avatar_uploader_spec.rb index 76f5a4b42ed..c4d558805ab 100644 --- a/spec/uploaders/avatar_uploader_spec.rb +++ b/spec/uploaders/avatar_uploader_spec.rb @@ -1,18 +1,17 @@ require 'spec_helper' describe AvatarUploader do - let(:user) { build(:user) } - subject { described_class.new(user) } + let(:uploader) { described_class.new(build_stubbed(:user)) } describe '#move_to_cache' do it 'is false' do - expect(subject.move_to_cache).to eq(false) + expect(uploader.move_to_cache).to eq(false) end end describe '#move_to_store' do it 'is false' do - expect(subject.move_to_store).to eq(false) + expect(uploader.move_to_store).to eq(false) end end end diff --git a/spec/uploaders/file_uploader_spec.rb b/spec/uploaders/file_uploader_spec.rb index 6a712e33c96..b0f5be55c33 100644 --- a/spec/uploaders/file_uploader_spec.rb +++ b/spec/uploaders/file_uploader_spec.rb @@ -1,57 +1,35 @@ require 'spec_helper' describe FileUploader do - let(:project) { create(:project) } + let(:uploader) { described_class.new(build_stubbed(:project)) } - before do - @previous_enable_processing = FileUploader.enable_processing - FileUploader.enable_processing = false - @uploader = FileUploader.new(project) - end - - after do - FileUploader.enable_processing = @previous_enable_processing - @uploader.remove! - end + describe 'initialize' do + it 'generates a secret if none is provided' do + expect(SecureRandom).to receive(:hex).and_return('secret') - describe '#image_or_video?' do - context 'given an image file' do - before do - @uploader.store!(fixture_file_upload(Rails.root.join('spec', 'fixtures', 'rails_sample.jpg'))) - end + uploader = described_class.new(double) - it 'detects an image based on file extension' do - expect(@uploader.image_or_video?).to be true - end + expect(uploader.secret).to eq 'secret' end - context 'given an video file' do - before do - video_file = fixture_file_upload(Rails.root.join('spec', 'fixtures', 'video_sample.mp4')) - @uploader.store!(video_file) - end - - it 'detects a video based on file extension' do - expect(@uploader.image_or_video?).to be true - end - end + it 'accepts a secret parameter' do + expect(SecureRandom).not_to receive(:hex) - it 'does not return image_or_video? for other types' do - @uploader.store!(fixture_file_upload(Rails.root.join('spec', 'fixtures', 'doc_sample.txt'))) + uploader = described_class.new(double, 'secret') - expect(@uploader.image_or_video?).to be false + expect(uploader.secret).to eq 'secret' end end describe '#move_to_cache' do it 'is true' do - expect(@uploader.move_to_cache).to eq(true) + expect(uploader.move_to_cache).to eq(true) end end describe '#move_to_store' do it 'is true' do - expect(@uploader.move_to_store).to eq(true) + expect(uploader.move_to_store).to eq(true) end end end diff --git a/spec/uploaders/uploader_helper_spec.rb b/spec/uploaders/uploader_helper_spec.rb new file mode 100644 index 00000000000..e9efd13b9aa --- /dev/null +++ b/spec/uploaders/uploader_helper_spec.rb @@ -0,0 +1,35 @@ +require 'rails_helper' + +describe UploaderHelper do + class ExampleUploader < CarrierWave::Uploader::Base + include UploaderHelper + + storage :file + end + + def upload_fixture(filename) + fixture_file_upload(Rails.root.join('spec', 'fixtures', filename)) + end + + describe '#image_or_video?' do + let(:uploader) { ExampleUploader.new } + + it 'returns true for an image file' do + uploader.store!(upload_fixture('dk.png')) + + expect(uploader).to be_image_or_video + end + + it 'it returns true for a video file' do + uploader.store!(upload_fixture('video_sample.mp4')) + + expect(uploader).to be_image_or_video + end + + it 'returns false for other extensions' do + uploader.store!(upload_fixture('doc_sample.txt')) + + expect(uploader).not_to be_image_or_video + end + end +end diff --git a/spec/views/ci/status/_badge.html.haml_spec.rb b/spec/views/ci/status/_badge.html.haml_spec.rb new file mode 100644 index 00000000000..c62450fb8e2 --- /dev/null +++ b/spec/views/ci/status/_badge.html.haml_spec.rb @@ -0,0 +1,89 @@ +require 'spec_helper' + +describe 'ci/status/_badge', :view do + let(:user) { create(:user) } + let(:project) { create(:empty_project, :private) } + let(:pipeline) { create(:ci_pipeline, project: project) } + + context 'when rendering status for build' do + let(:build) do + create(:ci_build, :success, pipeline: pipeline) + end + + context 'when user has ability to see details' do + before do + project.add_developer(user) + end + + it 'has link to build details page' do + details_path = namespace_project_build_path( + project.namespace, project, build) + + render_status(build) + + expect(rendered).to have_link 'passed', href: details_path + end + end + + context 'when user do not have ability to see build details' do + before do + render_status(build) + end + + it 'contains build status text' do + expect(rendered).to have_content 'passed' + end + + it 'does not contain links' do + expect(rendered).not_to have_link 'passed' + end + end + end + + context 'when rendering status for external job' do + context 'when user has ability to see commit status details' do + before do + project.add_developer(user) + end + + context 'status has external target url' do + before do + external_job = create(:generic_commit_status, + status: :running, + pipeline: pipeline, + target_url: 'http://gitlab.com') + + render_status(external_job) + end + + it 'contains valid commit status text' do + expect(rendered).to have_content 'running' + end + + it 'has link to external status page' do + expect(rendered).to have_link 'running', href: 'http://gitlab.com' + end + end + + context 'status do not have external target url' do + before do + external_job = create(:generic_commit_status, status: :canceled) + + render_status(external_job) + end + + it 'contains valid commit status text' do + expect(rendered).to have_content 'canceled' + end + + it 'has link to external status page' do + expect(rendered).not_to have_link 'canceled' + end + end + end + end + + def render_status(resource) + render 'ci/status/badge', status: resource.detailed_status(user) + end +end diff --git a/spec/views/projects/builds/show.html.haml_spec.rb b/spec/views/projects/builds/show.html.haml_spec.rb index b6f6e7b7a2b..ec78ac30593 100644 --- a/spec/views/projects/builds/show.html.haml_spec.rb +++ b/spec/views/projects/builds/show.html.haml_spec.rb @@ -209,6 +209,10 @@ describe 'projects/builds/show', :view do it 'does not show retry button' do expect(rendered).not_to have_link('Retry') end + + it 'does not show New issue button' do + expect(rendered).not_to have_link('New issue') + end end context 'when job is not running' do @@ -220,6 +224,23 @@ describe 'projects/builds/show', :view do it 'shows retry button' do expect(rendered).to have_link('Retry') end + + context 'if build passed' do + it 'does not show New issue button' do + expect(rendered).not_to have_link('New issue') + end + end + + context 'if build failed' do + before do + build.status = 'failed' + render + end + + it 'shows New issue button' do + expect(rendered).to have_link('New issue') + end + end end describe 'commit title in sidebar' do @@ -248,4 +269,25 @@ describe 'projects/builds/show', :view do expect(rendered).to have_css('.js-build-value', visible: false, text: 'TRIGGER_VALUE_2') end end + + describe 'New issue button' do + before do + build.status = 'failed' + render + end + + it 'links to issues/new with the title and description filled in' do + title = "Build Failed ##{build.id}" + build_url = namespace_project_build_url(project.namespace, project, build) + href = new_namespace_project_issue_path( + project.namespace, + project, + issue: { + title: title, + description: build_url + } + ) + expect(rendered).to have_link('New issue', href: href) + end + end end diff --git a/spec/workers/repository_fork_worker_spec.rb b/spec/workers/repository_fork_worker_spec.rb index 60605460adb..87521ae408e 100644 --- a/spec/workers/repository_fork_worker_spec.rb +++ b/spec/workers/repository_fork_worker_spec.rb @@ -15,24 +15,24 @@ describe RepositoryForkWorker do it "creates a new repository from a fork" do expect(shell).to receive(:fork_repository).with( '/test/path', - project.path_with_namespace, + project.full_path, project.repository_storage_path, - fork_project.namespace.path + fork_project.namespace.full_path ).and_return(true) subject.perform( project.id, '/test/path', - project.path_with_namespace, - fork_project.namespace.path) + project.full_path, + fork_project.namespace.full_path) end it 'flushes various caches' do expect(shell).to receive(:fork_repository).with( '/test/path', - project.path_with_namespace, + project.full_path, project.repository_storage_path, - fork_project.namespace.path + fork_project.namespace.full_path ).and_return(true) expect_any_instance_of(Repository).to receive(:expire_emptiness_caches). @@ -41,8 +41,8 @@ describe RepositoryForkWorker do expect_any_instance_of(Repository).to receive(:expire_exists_cache). and_call_original - subject.perform(project.id, '/test/path', project.path_with_namespace, - fork_project.namespace.path) + subject.perform(project.id, '/test/path', project.full_path, + fork_project.namespace.full_path) end it "handles bad fork" do @@ -53,8 +53,8 @@ describe RepositoryForkWorker do subject.perform( project.id, '/test/path', - project.path_with_namespace, - fork_project.namespace.path) + project.full_path, + fork_project.namespace.full_path) end end end |