diff options
Diffstat (limited to 'spec/controllers/projects')
16 files changed, 491 insertions, 158 deletions
diff --git a/spec/controllers/projects/artifacts_controller_spec.rb b/spec/controllers/projects/artifacts_controller_spec.rb index 263f488ddbf..808e67eff3d 100644 --- a/spec/controllers/projects/artifacts_controller_spec.rb +++ b/spec/controllers/projects/artifacts_controller_spec.rb @@ -229,7 +229,7 @@ RSpec.describe Projects::ArtifactsController do expect(response.body).to include( 'You must have developer or higher permissions in the associated project to view job logs when debug trace is enabled. ' \ 'To disable debug trace, set the 'CI_DEBUG_TRACE' variable to 'false' in your pipeline configuration or CI/CD settings. ' \ - 'If you need to view this job log, a project maintainer must add you to the project with developer permissions or higher.' + 'If you need to view this job log, a project maintainer or owner must add you to the project with developer permissions or higher.' ) end end diff --git a/spec/controllers/projects/autocomplete_sources_controller_spec.rb b/spec/controllers/projects/autocomplete_sources_controller_spec.rb index a5274b6543e..7077aae6b45 100644 --- a/spec/controllers/projects/autocomplete_sources_controller_spec.rb +++ b/spec/controllers/projects/autocomplete_sources_controller_spec.rb @@ -5,37 +5,133 @@ require 'spec_helper' RSpec.describe Projects::AutocompleteSourcesController do let_it_be(:group, reload: true) { create(:group) } let_it_be(:project) { create(:project, namespace: group) } - let_it_be(:issue) { create(:issue, project: project) } + let_it_be(:public_project) { create(:project, :public, group: group) } + let_it_be(:development) { create(:label, project: project, name: 'Development') } + let_it_be(:issue) { create(:labeled_issue, project: project, labels: [development]) } let_it_be(:user) { create(:user) } def members_by_username(username) json_response.find { |member| member['username'] == username } end - describe 'GET members' do + describe 'GET commands' do + before do + group.add_owner(user) + end + + context 'with a public project' do + shared_examples 'issuable commands' do + it 'returns empty array when no user logged in' do + get :commands, format: :json, params: { namespace_id: group.path, project_id: public_project.path, type: issuable_type, type_id: issuable_iid } + + expect(response).to have_gitlab_http_status(:ok) + expect(json_response).to eq([]) + end + + it 'raises an error when no target type specified' do + sign_in(user) + + expect { get :commands, format: :json, params: { namespace_id: group.path, project_id: project.path } } + .to raise_error(ActionController::ParameterMissing) + end + + it 'returns an array of commands' do + sign_in(user) + + get :commands, format: :json, params: { namespace_id: group.path, project_id: public_project.path, type: issuable_type, type_id: issuable_iid } + + expect(response).to have_gitlab_http_status(:ok) + expect(json_response).to be_present + end + end + + context 'with an issue' do + let(:issuable_type) { issue.class.name } + let(:issuable_iid) { issue.iid } + + it_behaves_like 'issuable commands' + end + + context 'with merge request' do + let(:merge_request) { create(:merge_request, target_project: public_project, source_project: public_project) } + let(:issuable_type) { merge_request.class.name } + let(:issuable_iid) { merge_request.iid } + + it_behaves_like 'issuable commands' + end + end + end + + describe 'GET labels' do before do group.add_owner(user) sign_in(user) end - it 'returns an array of member object' do - get :members, format: :json, params: { namespace_id: group.path, project_id: project.path, type: issue.class.name, type_id: issue.id } + it 'raises an error when no target type specified' do + expect { get :labels, format: :json, params: { namespace_id: group.path, project_id: project.path } } + .to raise_error(ActionController::ParameterMissing) + end + + it 'returns an array of labels' do + get :labels, format: :json, params: { namespace_id: group.path, project_id: project.path, type: issue.class.name, type_id: issue.id } + + expect(json_response).to be_a(Array) + expect(json_response.count).to eq(1) + expect(json_response[0]['title']).to eq('Development') + end + end + + describe 'GET members' do + context 'when logged in' do + before do + group.add_owner(user) + sign_in(user) + end + + it 'returns 400 when no target type specified' do + expect { get :members, format: :json, params: { namespace_id: group.path, project_id: project.path } } + .to raise_error(ActionController::ParameterMissing) + end + + it 'returns an array of member object' do + get :members, format: :json, params: { namespace_id: group.path, project_id: project.path, type: issue.class.name, type_id: issue.id } + + expect(members_by_username('all').symbolize_keys).to include( + username: 'all', + name: 'All Project and Group Members', + count: 1) + + expect(members_by_username(group.full_path).symbolize_keys).to include( + type: group.class.name, + name: group.full_name, + avatar_url: group.avatar_url, + count: 1) + + expect(members_by_username(user.username).symbolize_keys).to include( + type: user.class.name, + name: user.name, + avatar_url: user.avatar_url) + end + end + + context 'when anonymous' do + it 'redirects to login page' do + get :members, format: :json, params: { namespace_id: group.path, project_id: project.path, type: issue.class.name, type_id: issue.id } - expect(members_by_username('all').symbolize_keys).to include( - username: 'all', - name: 'All Project and Group Members', - count: 1) + expect(response).to redirect_to new_user_session_path + end - expect(members_by_username(group.full_path).symbolize_keys).to include( - type: group.class.name, - name: group.full_name, - avatar_url: group.avatar_url, - count: 1) + context 'with public project' do + it 'returns no members' do + get :members, format: :json, params: { namespace_id: group.path, project_id: public_project.path, type: issue.class.name, type_id: issue.id } - expect(members_by_username(user.username).symbolize_keys).to include( - type: user.class.name, - name: user.name, - avatar_url: user.avatar_url) + expect(response).to have_gitlab_http_status(:ok) + expect(json_response).to be_a(Array) + expect(json_response.count).to eq(1) + expect(json_response.first['count']).to eq(0) + end + end end end @@ -88,7 +184,7 @@ RSpec.describe Projects::AutocompleteSourcesController do it 'lists contacts' do group.add_developer(user) - get :contacts, format: :json, params: { namespace_id: group.path, project_id: project.path } + get :contacts, format: :json, params: { namespace_id: group.path, project_id: project.path, type: issue.class.name, type_id: issue.id } emails = json_response.map { |contact_data| contact_data["email"] } expect(emails).to match_array([contact_1.email, contact_2.email]) @@ -97,7 +193,7 @@ RSpec.describe Projects::AutocompleteSourcesController do context 'when a user can not read contacts' do it 'renders 404' do - get :contacts, format: :json, params: { namespace_id: group.path, project_id: project.path } + get :contacts, format: :json, params: { namespace_id: group.path, project_id: project.path, type: issue.class.name, type_id: issue.id } expect(response).to have_gitlab_http_status(:not_found) end @@ -108,7 +204,7 @@ RSpec.describe Projects::AutocompleteSourcesController do it 'renders 404' do group.add_developer(user) - get :contacts, format: :json, params: { namespace_id: group.path, project_id: project.path } + get :contacts, format: :json, params: { namespace_id: group.path, project_id: project.path, type: issue.class.name, type_id: issue.id } expect(response).to have_gitlab_http_status(:not_found) end diff --git a/spec/controllers/projects/boards_controller_spec.rb b/spec/controllers/projects/boards_controller_spec.rb index cde3a8d4761..89d0669f47b 100644 --- a/spec/controllers/projects/boards_controller_spec.rb +++ b/spec/controllers/projects/boards_controller_spec.rb @@ -3,11 +3,14 @@ require 'spec_helper' RSpec.describe Projects::BoardsController do - let(:project) { create(:project) } - let(:user) { create(:user) } + let_it_be(:project) { create(:project) } + let_it_be(:user) { create(:user) } - before do + before_all do project.add_maintainer(user) + end + + before do sign_in(user) end @@ -16,77 +19,63 @@ RSpec.describe Projects::BoardsController do expect { list_boards }.to change(project.boards, :count).by(1) end - it 'sets boards_endpoint instance variable to a boards path' do + it 'renders template' do list_boards - expect(assigns(:boards_endpoint)).to eq project_boards_path(project) + expect(response).to render_template :index + expect(response.media_type).to eq 'text/html' end - context 'when format is HTML' do - it 'renders template' do - list_boards + context 'when there are recently visited boards' do + let_it_be(:boards) { create_list(:board, 3, resource_parent: project) } - expect(response).to render_template :index - expect(response.media_type).to eq 'text/html' + before_all do + visit_board(boards[2], Time.current + 1.minute) + visit_board(boards[0], Time.current + 2.minutes) + visit_board(boards[1], Time.current + 5.minutes) end - context 'with unauthorized user' do - before do - expect(Ability).to receive(:allowed?).with(user, :log_in, :global).and_call_original - allow(Ability).to receive(:allowed?).with(user, :read_project, project).and_return(true) - allow(Ability).to receive(:allowed?).with(user, :read_issue_board, project).and_return(false) - end - - it 'returns a not found 404 response' do - list_boards + it 'redirects to latest visited board' do + list_boards - expect(response).to have_gitlab_http_status(:not_found) - expect(response.media_type).to eq 'text/html' - end + expect(response).to redirect_to( + namespace_project_board_path(namespace_id: project.namespace, project_id: project, id: boards[1].id) + ) end - context 'when user is signed out' do - let(:project) { create(:project, :public) } - - it 'renders template' do - sign_out(user) + def visit_board(board, time) + create(:board_project_recent_visit, project: project, board: board, user: user, updated_at: time) + end + end - board = create(:board, project: project) - create(:board_project_recent_visit, project: board.project, board: board, user: user) + context 'with unauthorized user' do + before do + expect(Ability).to receive(:allowed?).with(user, :log_in, :global).and_call_original + allow(Ability).to receive(:allowed?).with(user, :read_project, project).and_return(true) + allow(Ability).to receive(:allowed?).with(user, :read_issue_board, project).and_return(false) + end - list_boards + it 'returns a not found 404 response' do + list_boards - expect(response).to render_template :index - expect(response.media_type).to eq 'text/html' - end + expect(response).to have_gitlab_http_status(:not_found) + expect(response.media_type).to eq 'text/html' end end - context 'when format is JSON' do - it 'returns a list of project boards' do - create_list(:board, 2, project: project) - - expect(Boards::VisitsFinder).not_to receive(:new) - - list_boards format: :json + context 'when user is signed out' do + let(:project) { create(:project, :public) } - expect(response).to match_response_schema('boards') - expect(json_response.length).to eq 2 - end + it 'renders template' do + sign_out(user) - context 'with unauthorized user' do - before do - expect(Ability).to receive(:allowed?).with(user, :log_in, :global).and_call_original - allow(Ability).to receive(:allowed?).with(user, :read_project, project).and_return(true) - allow(Ability).to receive(:allowed?).with(user, :read_issue_board, project).and_return(false) - end + board = create(:board, project: project) + create(:board_project_recent_visit, project: board.project, board: board, user: user) - it 'returns a not found 404 response' do - list_boards format: :json + list_boards - expect(response).to have_gitlab_http_status(:not_found) - expect(response.media_type).to eq 'application/json' - end + expect(response).to render_template :index + expect(response.media_type).to eq 'text/html' end end @@ -104,23 +93,16 @@ RSpec.describe Projects::BoardsController do subject { list_boards } end - def list_boards(format: :html) + def list_boards get :index, params: { namespace_id: project.namespace, project_id: project - }, - format: format + } end end describe 'GET show' do - let!(:board) { create(:board, project: project) } - - it 'sets boards_endpoint instance variable to a boards path' do - read_board board: board - - expect(assigns(:boards_endpoint)).to eq project_boards_path(project) - end + let_it_be(:board) { create(:board, project: project) } context 'when format is HTML' do it 'renders template' do @@ -146,12 +128,12 @@ RSpec.describe Projects::BoardsController do end context 'when user is signed out' do - let(:project) { create(:project, :public) } + let(:public_board) { create(:board, project: create(:project, :public)) } it 'does not save visit' do sign_out(user) - expect { read_board board: board }.to change(BoardProjectRecentVisit, :count).by(0) + expect { read_board board: public_board }.to change(BoardProjectRecentVisit, :count).by(0) expect(response).to render_template :show expect(response.media_type).to eq 'text/html' @@ -159,48 +141,18 @@ RSpec.describe Projects::BoardsController do end end - context 'when format is JSON' do - it 'returns project board' do - expect(Boards::Visits::CreateService).not_to receive(:new) - - read_board board: board, format: :json - - expect(response).to match_response_schema('board') - end - - context 'with unauthorized user' do - before do - expect(Ability).to receive(:allowed?).with(user, :log_in, :global).and_call_original - allow(Ability).to receive(:allowed?).with(user, :read_project, project).and_return(true) - allow(Ability).to receive(:allowed?).with(user, :read_issue_board, project).and_return(false) - end - - it 'returns a not found 404 response' do - read_board board: board, format: :json - - expect(response).to have_gitlab_http_status(:not_found) - expect(response.media_type).to eq 'application/json' - end - end - end - context 'when board does not belong to project' do it 'returns a not found 404 response' do another_board = create(:board) - read_board board: another_board + get :show, params: { namespace_id: project.namespace, project_id: project, id: another_board.to_param } expect(response).to have_gitlab_http_status(:not_found) end end - def read_board(board:, format: :html) - get :show, params: { - namespace_id: project.namespace, - project_id: project, - id: board.to_param - }, - format: format + def read_board(board:) + get :show, params: { namespace_id: board.project.namespace, project_id: board.project, id: board.to_param } end end end diff --git a/spec/controllers/projects/compare_controller_spec.rb b/spec/controllers/projects/compare_controller_spec.rb index 6ed6f7017e3..3751b89951c 100644 --- a/spec/controllers/projects/compare_controller_spec.rb +++ b/spec/controllers/projects/compare_controller_spec.rb @@ -67,11 +67,13 @@ RSpec.describe Projects::CompareController do from: from_ref, to: to_ref, w: whitespace, - page: page + page: page, + straight: straight } end let(:whitespace) { nil } + let(:straight) { nil } let(:page) { nil } context 'when the refs exist in the same project' do @@ -142,6 +144,58 @@ RSpec.describe Projects::CompareController do end end + context 'when comparing missing commits between source and target' do + let(:from_project_id) { nil } + let(:from_ref) { '5937ac0a7beb003549fc5fd26fc247adbce4a52e' } + let(:to_ref) { '6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9' } + let(:page) { 1 } + + context 'when comparing them in the other direction' do + let(:straight) { "false" } + let(:from_ref) { '6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9' } + let(:to_ref) { '5937ac0a7beb003549fc5fd26fc247adbce4a52e' } + + it 'the commits are there' do + show_request + + expect(response).to be_successful + expect(assigns(:commits).length).to be >= 2 + expect(assigns(:diffs).raw_diff_files.size).to be >= 2 + expect(assigns(:diffs).diff_files.first).to be_present + end + end + + context 'with straight mode true' do + let(:from_ref) { '5937ac0a7beb003549fc5fd26fc247adbce4a52e' } + let(:to_ref) { '6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9' } + + let(:straight) { "true" } + + it 'the commits are empty, but the removed lines are visible as diffs' do + show_request + + expect(response).to be_successful + expect(assigns(:commits).length).to be == 0 + expect(assigns(:diffs).diff_files.size).to be >= 4 + end + end + + context 'with straight mode false' do + let(:from_ref) { '5937ac0a7beb003549fc5fd26fc247adbce4a52e' } + let(:to_ref) { '6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9' } + + let(:straight) { "false" } + + it 'the additional commits are not visible in diffs and commits' do + show_request + + expect(response).to be_successful + expect(assigns(:commits).length).to be == 0 + expect(assigns(:diffs).diff_files.size).to be == 0 + end + end + end + context 'when the refs exist in different projects but the user cannot see' do let(:from_project_id) { private_fork.id } let(:from_ref) { 'improve%2Fmore-awesome' } @@ -450,10 +504,13 @@ RSpec.describe Projects::CompareController do project_id: project, from: from_ref, to: to_ref, + straight: straight, format: :json } end + let(:straight) { nil } + context 'when the source and target refs exist' do let(:from_ref) { 'improve%2Fawesome' } let(:to_ref) { 'feature' } @@ -469,10 +526,43 @@ RSpec.describe Projects::CompareController do escaped_to_ref = Addressable::URI.unescape(to_ref) compare_service = CompareService.new(project, escaped_to_ref) + compare = compare_service.execute(project, escaped_from_ref, straight: false) + + expect(CompareService).to receive(:new).with(project, escaped_to_ref).and_return(compare_service) + expect(compare_service).to receive(:execute).with(project, escaped_from_ref, straight: false).and_return(compare) + + expect(compare).to receive(:commits).and_return(CommitCollection.new(project, [signature_commit, non_signature_commit])) + expect(non_signature_commit).to receive(:has_signature?).and_return(false) + end + + it 'returns only the commit with a signature' do + signatures_request + + expect(response).to have_gitlab_http_status(:ok) + signatures = json_response['signatures'] + + expect(signatures.size).to eq(1) + expect(signatures.first['commit_sha']).to eq(signature_commit.sha) + expect(signatures.first['html']).to be_present + end + end + + context 'when the user has access to the project with straight compare' do + render_views + + let(:signature_commit) { project.commit_by(oid: '0b4bc9a49b562e85de7cc9e834518ea6828729b9') } + let(:non_signature_commit) { build(:commit, project: project, safe_message: "message", sha: 'non_signature_commit') } + let(:straight) { "true" } + + before do + escaped_from_ref = Addressable::URI.unescape(from_ref) + escaped_to_ref = Addressable::URI.unescape(to_ref) + + compare_service = CompareService.new(project, escaped_to_ref) compare = compare_service.execute(project, escaped_from_ref) expect(CompareService).to receive(:new).with(project, escaped_to_ref).and_return(compare_service) - expect(compare_service).to receive(:execute).with(project, escaped_from_ref).and_return(compare) + expect(compare_service).to receive(:execute).with(project, escaped_from_ref, straight: true).and_return(compare) expect(compare).to receive(:commits).and_return(CommitCollection.new(project, [signature_commit, non_signature_commit])) expect(non_signature_commit).to receive(:has_signature?).and_return(false) diff --git a/spec/controllers/projects/cycle_analytics_controller_spec.rb b/spec/controllers/projects/cycle_analytics_controller_spec.rb index f5dd8abd67b..034e6104f99 100644 --- a/spec/controllers/projects/cycle_analytics_controller_spec.rb +++ b/spec/controllers/projects/cycle_analytics_controller_spec.rb @@ -31,7 +31,7 @@ RSpec.describe Projects::CycleAnalyticsController do let(:target_id) { 'p_analytics_valuestream' } end - it_behaves_like 'Snowplow event tracking' do + it_behaves_like 'Snowplow event tracking with RedisHLL context' do subject { get :show, params: request_params, format: :html } let(:request_params) { { namespace_id: project.namespace, project_id: project } } diff --git a/spec/controllers/projects/deploy_keys_controller_spec.rb b/spec/controllers/projects/deploy_keys_controller_spec.rb index 308146ce792..fd844808d81 100644 --- a/spec/controllers/projects/deploy_keys_controller_spec.rb +++ b/spec/controllers/projects/deploy_keys_controller_spec.rb @@ -72,13 +72,15 @@ RSpec.describe Projects::DeployKeysController do end describe 'POST create' do + let(:deploy_key_content) { attributes_for(:deploy_key)[:key] } + def create_params(title = 'my-key') { namespace_id: project.namespace.path, project_id: project.path, deploy_key: { title: title, - key: attributes_for(:deploy_key)[:key], + key: deploy_key_content, deploy_keys_projects_attributes: { '0' => { can_push: '1' } } } } @@ -96,13 +98,38 @@ RSpec.describe Projects::DeployKeysController do expect(response).to redirect_to(project_settings_repository_path(project, anchor: 'js-deploy-keys-settings')) end - context 'when the deploy key is invalid' do + context 'when the deploy key has an invalid title' do it 'shows an alert with the validations errors' do post :create, params: create_params(nil) expect(flash[:alert]).to eq("Title can't be blank, Deploy keys projects deploy key title can't be blank") end end + + context 'when the deploy key is not supported SSH public key' do + let(:deploy_key_content) { 'bogus ssh public key' } + + it 'shows an alert with a help link' do + post :create, params: create_params + + expect(assigns(:key).errors.count).to be > 1 + expect(flash[:alert]).to eq('Deploy Key must be a <a target="_blank" rel="noopener noreferrer" ' \ + 'href="/help/user/ssh#supported-ssh-key-types">supported SSH public key.</a>') + end + end + + context 'when the deploy key already exists' do + before do + create(:deploy_key, title: 'my-key', key: deploy_key_content, projects: [project]) + end + + it 'shows an alert with the validations errors' do + post :create, params: create_params + + expect(flash[:alert]).to eq("Fingerprint sha256 has already been taken, " \ + "Deploy keys projects deploy key fingerprint sha256 has already been taken") + end + end end describe '/enable/:id' do diff --git a/spec/controllers/projects/design_management/designs/raw_images_controller_spec.rb b/spec/controllers/projects/design_management/designs/raw_images_controller_spec.rb index 55ab0f0eefa..2d39e0e5317 100644 --- a/spec/controllers/projects/design_management/designs/raw_images_controller_spec.rb +++ b/spec/controllers/projects/design_management/designs/raw_images_controller_spec.rb @@ -132,7 +132,7 @@ RSpec.describe Projects::DesignManagement::Designs::RawImagesController do subject expect(response.header['ETag']).to be_present - expect(response.header['Cache-Control']).to eq("max-age=60, private") + expect(response.header['Cache-Control']).to eq("max-age=60, private, must-revalidate, stale-while-revalidate=60, stale-if-error=300, s-maxage=60") end end diff --git a/spec/controllers/projects/graphs_controller_spec.rb b/spec/controllers/projects/graphs_controller_spec.rb index 9227c7dd70a..3dfc22927cf 100644 --- a/spec/controllers/projects/graphs_controller_spec.rb +++ b/spec/controllers/projects/graphs_controller_spec.rb @@ -90,7 +90,7 @@ RSpec.describe Projects::GraphsController do let(:target_id) { 'p_analytics_repo' } end - it_behaves_like 'Snowplow event tracking' do + it_behaves_like 'Snowplow event tracking with RedisHLL context' do subject do sign_in(user) get :charts, params: request_params, format: :html diff --git a/spec/controllers/projects/issues_controller_spec.rb b/spec/controllers/projects/issues_controller_spec.rb index c48be8efb1b..0c3795540e0 100644 --- a/spec/controllers/projects/issues_controller_spec.rb +++ b/spec/controllers/projects/issues_controller_spec.rb @@ -1107,6 +1107,46 @@ RSpec.describe Projects::IssuesController do end end + context 'when create service return an unrecoverable error with http_status' do + let(:http_status) { 403 } + + before do + allow_next_instance_of(::Issues::CreateService) do |create_service| + allow(create_service).to receive(:execute).and_return( + ServiceResponse.error(message: 'unrecoverable error', http_status: http_status) + ) + end + end + + it 'renders 403 and logs the error' do + expect(Gitlab::AppLogger).to receive(:warn).with( + message: 'Cannot create issue', + errors: ['unrecoverable error'], + http_status: http_status + ) + + post_new_issue + + expect(response).to have_gitlab_http_status :forbidden + end + + context 'when no render method is found for the returned http_status' do + let(:http_status) { nil } + + it 'renders 404 and logs the error' do + expect(Gitlab::AppLogger).to receive(:warn).with( + message: 'Cannot create issue', + errors: ['unrecoverable error'], + http_status: http_status + ) + + post_new_issue + + expect(response).to have_gitlab_http_status :not_found + end + end + end + it 'creates the issue successfully', :aggregate_failures do issue = post_new_issue @@ -1661,13 +1701,27 @@ RSpec.describe Projects::IssuesController do end it 'allows CSV export' do - expect(IssuableExportCsvWorker).to receive(:perform_async).with(:issue, viewer.id, project.id, anything) + expect(IssuableExportCsvWorker).to receive(:perform_async) + .with(:issue, viewer.id, project.id, hash_including('issue_types' => Issue::TYPES_FOR_LIST)) request_csv expect(response).to redirect_to(project_issues_path(project)) expect(controller).to set_flash[:notice].to match(/\AYour CSV export has started/i) end + + context 'when work_items is disabled' do + before do + stub_feature_flags(work_items: false) + end + + it 'does not include tasks in CSV export' do + expect(IssuableExportCsvWorker).to receive(:perform_async) + .with(:issue, viewer.id, project.id, hash_including('issue_types' => Issue::TYPES_FOR_LIST.excluding('task'))) + + request_csv + end + end end context 'when not logged in' do diff --git a/spec/controllers/projects/merge_requests_controller_spec.rb b/spec/controllers/projects/merge_requests_controller_spec.rb index 9c4baeae836..a41abd8c16d 100644 --- a/spec/controllers/projects/merge_requests_controller_spec.rb +++ b/spec/controllers/projects/merge_requests_controller_spec.rb @@ -77,7 +77,8 @@ RSpec.describe Projects::MergeRequestsController do merge_request, 'json', diff_head: true, - view: 'inline')) + view: 'inline', + w: '0')) end context 'when diff files were cleaned' do @@ -498,7 +499,7 @@ RSpec.describe Projects::MergeRequestsController do context 'when a squash commit message is passed' do let(:message) { 'My custom squash commit message' } - it 'passes the same message to SquashService', :sidekiq_might_not_need_inline do + it 'passes the same message to SquashService', :sidekiq_inline do params = { squash: '1', squash_commit_message: message, sha: merge_request.diff_head_sha } @@ -790,7 +791,7 @@ RSpec.describe Projects::MergeRequestsController do context 'with private builds' do context 'for the target project member' do - it 'does not respond with serialized pipelines', :sidekiq_might_not_need_inline do + it 'does not respond with serialized pipelines' do expect(json_response['pipelines']).to be_empty expect(json_response['count']['all']).to eq(0) expect(response).to include_pagination_headers @@ -800,7 +801,7 @@ RSpec.describe Projects::MergeRequestsController do context 'for the source project member' do let(:user) { fork_user } - it 'responds with serialized pipelines', :sidekiq_might_not_need_inline do + it 'responds with serialized pipelines' do expect(json_response['pipelines']).to be_present expect(json_response['count']['all']).to eq(1) expect(response).to include_pagination_headers @@ -816,7 +817,7 @@ RSpec.describe Projects::MergeRequestsController do end context 'for the target project member' do - it 'does not respond with serialized pipelines', :sidekiq_might_not_need_inline do + it 'does not respond with serialized pipelines' do expect(json_response['pipelines']).to be_present expect(json_response['count']['all']).to eq(1) expect(response).to include_pagination_headers @@ -826,7 +827,7 @@ RSpec.describe Projects::MergeRequestsController do context 'for the source project member' do let(:user) { fork_user } - it 'responds with serialized pipelines', :sidekiq_might_not_need_inline do + it 'responds with serialized pipelines' do expect(json_response['pipelines']).to be_present expect(json_response['count']['all']).to eq(1) expect(response).to include_pagination_headers @@ -1855,13 +1856,13 @@ RSpec.describe Projects::MergeRequestsController do create(:merge_request, source_project: forked, target_project: project, target_branch: 'master', head_pipeline: pipeline) end - it 'links to the environment on that project', :sidekiq_might_not_need_inline do + it 'links to the environment on that project' do get_ci_environments_status expect(json_response.first['url']).to match(/#{forked.full_path}/) end - context "when environment_target is 'merge_commit'", :sidekiq_might_not_need_inline do + context "when environment_target is 'merge_commit'" do it 'returns nothing' do get_ci_environments_status(environment_target: 'merge_commit') @@ -1891,13 +1892,13 @@ RSpec.describe Projects::MergeRequestsController do # we're trying to reduce the overall number of queries for this method. # set a hard limit for now. https://gitlab.com/gitlab-org/gitlab-foss/issues/52287 - it 'keeps queries in check', :sidekiq_might_not_need_inline do + it 'keeps queries in check' do control_count = ActiveRecord::QueryRecorder.new { get_ci_environments_status }.count expect(control_count).to be <= 137 end - it 'has no N+1 SQL issues for environments', :request_store, :sidekiq_might_not_need_inline, retry: 0 do + it 'has no N+1 SQL issues for environments', :request_store, retry: 0 do # First run to insert test data from lets, which does take up some 30 queries get_ci_environments_status @@ -2144,7 +2145,7 @@ RSpec.describe Projects::MergeRequestsController do sign_in(fork_owner) end - it 'returns 200', :sidekiq_might_not_need_inline do + it 'returns 200' do expect_rebase_worker_for(fork_owner) post_rebase diff --git a/spec/controllers/projects/milestones_controller_spec.rb b/spec/controllers/projects/milestones_controller_spec.rb index b62353784b3..28da7eff8fc 100644 --- a/spec/controllers/projects/milestones_controller_spec.rb +++ b/spec/controllers/projects/milestones_controller_spec.rb @@ -44,6 +44,26 @@ RSpec.describe Projects::MilestonesController do end end + describe "#create" do + it 'does not redirect without redirect_path' do + post :create, params: { namespace_id: project.namespace.id, project_id: project.id, milestone: { title: 'test' } } + + expect(response).to redirect_to(project_milestone_path(project, project.milestones.last)) + end + + it 'redirects when given a redirect_path' do + post :create, params: { namespace_id: project.namespace.id, project_id: project.id, redirect_path: 'new_release', milestone: { title: 'test' } } + + expect(response).to redirect_to(new_project_release_path(project)) + end + + it 'will not redirect when given a redirect_path with an error' do + post :create, params: { namespace_id: project.namespace.id, project_id: project.id, redirect_path: 'new_release', milestone: { title: nil } } + + expect(response).to have_gitlab_http_status(:ok) + end + end + describe "#index" do context "as html" do def render_index(project:, page:, search_title: '') diff --git a/spec/controllers/projects/pages_domains_controller_spec.rb b/spec/controllers/projects/pages_domains_controller_spec.rb index 691508d1e14..b29bbef0c40 100644 --- a/spec/controllers/projects/pages_domains_controller_spec.rb +++ b/spec/controllers/projects/pages_domains_controller_spec.rb @@ -63,9 +63,15 @@ RSpec.describe Projects::PagesDomainsController do describe 'POST create' do it "creates a new pages domain" do - expect do - post(:create, params: request_params.merge(pages_domain: pages_domain_params)) - end.to change { PagesDomain.count }.by(1) + expect { post(:create, params: request_params.merge(pages_domain: pages_domain_params)) } + .to change { PagesDomain.count }.by(1) + .and publish_event(PagesDomains::PagesDomainCreatedEvent) + .with( + project_id: project.id, + namespace_id: project.namespace.id, + root_namespace_id: project.root_namespace.id, + domain: pages_domain_params[:domain] + ) created_domain = PagesDomain.reorder(:id).last @@ -106,6 +112,17 @@ RSpec.describe Projects::PagesDomainsController do end.to change { pages_domain.reload.certificate }.to(pages_domain_params[:user_provided_certificate]) end + it 'publishes PagesDomainUpdatedEvent event' do + expect { patch(:update, params: params) } + .to publish_event(PagesDomains::PagesDomainUpdatedEvent) + .with( + project_id: project.id, + namespace_id: project.namespace.id, + root_namespace_id: project.root_namespace.id, + domain: pages_domain.domain + ) + end + it 'redirects to the project page' do patch(:update, params: params) @@ -134,6 +151,11 @@ RSpec.describe Projects::PagesDomainsController do expect(response).to render_template('show') end + + it 'does not publish PagesDomainUpdatedEvent event' do + expect { patch(:update, params: params) } + .to not_publish_event(PagesDomains::PagesDomainUpdatedEvent) + end end context 'when parameters include the domain' do @@ -197,9 +219,15 @@ RSpec.describe Projects::PagesDomainsController do describe 'DELETE destroy' do it "deletes the pages domain" do - expect do - delete(:destroy, params: request_params.merge(id: pages_domain.domain)) - end.to change { PagesDomain.count }.by(-1) + expect { delete(:destroy, params: request_params.merge(id: pages_domain.domain)) } + .to change(PagesDomain, :count).by(-1) + .and publish_event(PagesDomains::PagesDomainDeletedEvent) + .with( + project_id: project.id, + namespace_id: project.namespace.id, + root_namespace_id: project.root_namespace.id, + domain: pages_domain.domain + ) expect(response).to redirect_to(project_pages_path(project)) end @@ -216,6 +244,17 @@ RSpec.describe Projects::PagesDomainsController do expect(response).to redirect_to(project_pages_domain_path(project, pages_domain)) end + it 'publishes PagesDomainUpdatedEvent event' do + expect { subject } + .to publish_event(PagesDomains::PagesDomainUpdatedEvent) + .with( + project_id: project.id, + namespace_id: project.namespace.id, + root_namespace_id: project.root_namespace.id, + domain: pages_domain.domain + ) + end + it 'removes certificate' do expect do subject @@ -245,6 +284,11 @@ RSpec.describe Projects::PagesDomainsController do expect(pages_domain.key).to be_present end + it 'does not publish PagesDomainUpdatedEvent event' do + expect { subject } + .to not_publish_event(PagesDomains::PagesDomainUpdatedEvent) + end + it 'redirects to show page with a flash message' do subject diff --git a/spec/controllers/projects/pipelines_controller_spec.rb b/spec/controllers/projects/pipelines_controller_spec.rb index b9acaf65892..6e2de0c4d57 100644 --- a/spec/controllers/projects/pipelines_controller_spec.rb +++ b/spec/controllers/projects/pipelines_controller_spec.rb @@ -859,7 +859,7 @@ RSpec.describe Projects::PipelinesController do let(:target_id) { ['p_analytics_pipelines', tab[:event]] } end - it_behaves_like 'Snowplow event tracking' do + it_behaves_like 'Snowplow event tracking with RedisHLL context' do subject { get :charts, params: request_params, format: :html } let(:request_params) { { namespace_id: project.namespace, project_id: project, id: pipeline.id, chart: tab[:chart_param] } } diff --git a/spec/controllers/projects/prometheus/metrics_controller_spec.rb b/spec/controllers/projects/prometheus/metrics_controller_spec.rb index cd195b95100..327651b2058 100644 --- a/spec/controllers/projects/prometheus/metrics_controller_spec.rb +++ b/spec/controllers/projects/prometheus/metrics_controller_spec.rb @@ -4,7 +4,7 @@ require 'spec_helper' RSpec.describe Projects::Prometheus::MetricsController do let_it_be(:user) { create(:user) } - let_it_be(:project) { create(:prometheus_project) } + let_it_be(:project) { create(:project, :with_prometheus_integration) } let(:prometheus_adapter) { double('prometheus_adapter', can_query?: true) } diff --git a/spec/controllers/projects/protected_branches_controller_spec.rb b/spec/controllers/projects/protected_branches_controller_spec.rb index 4996bd90005..14728618633 100644 --- a/spec/controllers/projects/protected_branches_controller_spec.rb +++ b/spec/controllers/projects/protected_branches_controller_spec.rb @@ -4,26 +4,23 @@ require('spec_helper') RSpec.describe Projects::ProtectedBranchesController do let_it_be_with_reload(:project) { create(:project, :repository) } - let_it_be(:maintainer) { create(:user) } + let_it_be_with_reload(:empty_project) { create(:project, :empty_repo) } + let_it_be(:maintainer) { create(:user, maintainer_projects: [project, empty_project]) } let(:protected_branch) { create(:protected_branch, project: project) } let(:project_params) { { namespace_id: project.namespace.to_param, project_id: project } } let(:base_params) { project_params.merge(id: protected_branch.id) } let(:user) { maintainer } - before_all do - project.add_maintainer(maintainer) - end - before do sign_in(user) end describe "GET #index" do - let(:project) { create(:project_empty_repo, :public) } + it 'redirects to repository settings' do + get(:index, params: { namespace_id: empty_project.namespace.to_param, project_id: empty_project }) - it "redirects empty repo to projects page" do - get(:index, params: { namespace_id: project.namespace.to_param, project_id: project }) + expect(response).to redirect_to(project_settings_repository_path(empty_project)) end end @@ -42,6 +39,18 @@ RSpec.describe Projects::ProtectedBranchesController do end.to change(ProtectedBranch, :count).by(1) end + context 'when repository is empty' do + let(:project) { empty_project } + + it 'creates the protected branch rule' do + expect do + post(:create, params: project_params.merge(protected_branch: create_params)) + end.to change(ProtectedBranch, :count).by(1) + + expect(response).to have_gitlab_http_status(:found) + end + end + context 'when a policy restricts rule creation' do it "prevents creation of the protected branch rule" do disallow(:create_protected_branch, an_instance_of(ProtectedBranch)) @@ -63,6 +72,17 @@ RSpec.describe Projects::ProtectedBranchesController do expect(json_response["name"]).to eq('new_name') end + context 'when repository is empty' do + let(:project) { empty_project } + + it 'updates the protected branch rule' do + put(:update, params: base_params.merge(protected_branch: update_params)) + + expect(protected_branch.reload.name).to eq('new_name') + expect(json_response["name"]).to eq('new_name') + end + end + context 'when a policy restricts rule update' do it "prevents update of the protected branch rule" do disallow(:update_protected_branch, protected_branch) @@ -83,6 +103,16 @@ RSpec.describe Projects::ProtectedBranchesController do expect { ProtectedBranch.find(protected_branch.id) }.to raise_error(ActiveRecord::RecordNotFound) end + context 'when repository is empty' do + let(:project) { empty_project } + + it 'deletes the protected branch rule' do + delete(:destroy, params: base_params) + + expect { ProtectedBranch.find(protected_branch.id) }.to raise_error(ActiveRecord::RecordNotFound) + end + end + context 'when a policy restricts rule deletion' do it "prevents deletion of the protected branch rule" do disallow(:destroy_protected_branch, protected_branch) diff --git a/spec/controllers/projects/raw_controller_spec.rb b/spec/controllers/projects/raw_controller_spec.rb index e0d88fa799f..1c9aafacbd9 100644 --- a/spec/controllers/projects/raw_controller_spec.rb +++ b/spec/controllers/projects/raw_controller_spec.rb @@ -247,9 +247,11 @@ RSpec.describe Projects::RawController do sign_in create(:user) request_file - expect(response.cache_control[:public]).to eq(true) - expect(response.cache_control[:max_age]).to eq(60) + expect(response.headers['ETag']).to eq("\"bdd5aa537c1e1f6d1b66de4bac8a6132\"") expect(response.cache_control[:no_store]).to be_nil + expect(response.header['Cache-Control']).to eq( + 'max-age=60, public, must-revalidate, stale-while-revalidate=60, stale-if-error=300, s-maxage=60' + ) end context 'when a public project has private repo' do @@ -260,7 +262,9 @@ RSpec.describe Projects::RawController do sign_in user request_file - expect(response.header['Cache-Control']).to include('max-age=60, private') + expect(response.header['Cache-Control']).to eq( + 'max-age=60, private, must-revalidate, stale-while-revalidate=60, stale-if-error=300, s-maxage=60' + ) end end @@ -274,6 +278,21 @@ RSpec.describe Projects::RawController do expect(response).to have_gitlab_http_status(:not_modified) end end + + context 'when improve_blobs_cache_headers disabled' do + before do + stub_feature_flags(improve_blobs_cache_headers: false) + end + + it 'uses weak etags with a restricted set of headers' do + sign_in create(:user) + request_file + + expect(response.headers['ETag']).to eq("W/\"bdd5aa537c1e1f6d1b66de4bac8a6132\"") + expect(response.cache_control[:no_store]).to be_nil + expect(response.header['Cache-Control']).to eq('max-age=60, public') + end + end end end end |