diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2020-05-20 14:34:42 +0000 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2020-05-20 14:34:42 +0000 |
commit | 9f46488805e86b1bc341ea1620b866016c2ce5ed (patch) | |
tree | f9748c7e287041e37d6da49e0a29c9511dc34768 /spec/controllers/projects | |
parent | dfc92d081ea0332d69c8aca2f0e745cb48ae5e6d (diff) | |
download | gitlab-ce-9f46488805e86b1bc341ea1620b866016c2ce5ed.tar.gz |
Add latest changes from gitlab-org/gitlab@13-0-stable-ee
Diffstat (limited to 'spec/controllers/projects')
28 files changed, 1543 insertions, 332 deletions
diff --git a/spec/controllers/projects/alert_management_controller_spec.rb b/spec/controllers/projects/alert_management_controller_spec.rb new file mode 100644 index 00000000000..b84376db33d --- /dev/null +++ b/spec/controllers/projects/alert_management_controller_spec.rb @@ -0,0 +1,59 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe Projects::AlertManagementController do + let_it_be(:project) { create(:project) } + let_it_be(:role) { :developer } + let_it_be(:user) { create(:user) } + let_it_be(:id) { 1 } + + before do + project.add_role(user, role) + sign_in(user) + end + + describe 'GET #index' do + it 'shows the page' do + get :index, params: { namespace_id: project.namespace, project_id: project } + + expect(response).to have_gitlab_http_status(:ok) + end + + context 'when user is unauthorized' do + let(:role) { :reporter } + + it 'shows 404' do + get :index, params: { namespace_id: project.namespace, project_id: project } + + expect(response).to have_gitlab_http_status(:not_found) + end + end + end + + describe 'GET #details' do + it 'shows the page' do + get :details, params: { namespace_id: project.namespace, project_id: project, id: id } + + expect(response).to have_gitlab_http_status(:ok) + end + + context 'when user is unauthorized' do + let(:role) { :reporter } + + it 'shows 404' do + get :index, params: { namespace_id: project.namespace, project_id: project } + + expect(response).to have_gitlab_http_status(:not_found) + end + end + end + + describe 'set_alert_id' do + it 'sets alert id from the route' do + get :details, params: { namespace_id: project.namespace, project_id: project, id: id } + + expect(assigns(:alert_id)).to eq(id.to_s) + end + end +end diff --git a/spec/controllers/projects/artifacts_controller_spec.rb b/spec/controllers/projects/artifacts_controller_spec.rb index c59983d5138..be616b566dd 100644 --- a/spec/controllers/projects/artifacts_controller_spec.rb +++ b/spec/controllers/projects/artifacts_controller_spec.rb @@ -308,10 +308,13 @@ describe Projects::ArtifactsController do end describe 'GET raw' do - subject { get(:raw, params: { namespace_id: project.namespace, project_id: project, job_id: job, path: path }) } + let(:query_params) { { namespace_id: project.namespace, project_id: project, job_id: job, path: path } } + + subject { get(:raw, params: query_params) } context 'when the file exists' do let(:path) { 'ci_artifacts.txt' } + let(:archive_matcher) { /build_artifacts.zip(\?[^?]+)?$/ } shared_examples 'a valid file' do it 'serves the file using workhorse' do @@ -323,8 +326,8 @@ describe Projects::ArtifactsController do expect(params.keys).to eq(%w(Archive Entry)) expect(params['Archive']).to start_with(archive_path) # On object storage, the URL can end with a query string - expect(params['Archive']).to match(/build_artifacts.zip(\?[^?]+)?$/) - expect(params['Entry']).to eq(Base64.encode64('ci_artifacts.txt')) + expect(params['Archive']).to match(archive_matcher) + expect(params['Entry']).to eq(Base64.encode64(path)) end def send_data @@ -334,7 +337,7 @@ describe Projects::ArtifactsController do def params @params ||= begin base64_params = send_data.sub(/\Aartifacts\-entry:/, '') - JSON.parse(Base64.urlsafe_decode64(base64_params)) + Gitlab::Json.parse(Base64.urlsafe_decode64(base64_params)) end end end @@ -359,6 +362,37 @@ describe Projects::ArtifactsController do let(:archive_path) { 'https://' } end end + + context 'fetching an artifact of different type' do + before do + job.job_artifacts.each(&:destroy) + end + + context 'when the artifact is zip' do + let!(:artifact) { create(:ci_job_artifact, :lsif, job: job, file_path: Rails.root.join("spec/fixtures/#{file_name}")) } + let(:path) { 'lsif/main.go.json' } + let(:file_name) { 'lsif.json.zip' } + let(:archive_matcher) { file_name } + let(:query_params) { super().merge(file_type: :lsif, path: path) } + + it_behaves_like 'a valid file' do + let(:store) { ObjectStorage::Store::LOCAL } + let(:archive_path) { JobArtifactUploader.root } + end + end + + context 'when the artifact is not zip' do + let(:query_params) { super().merge(file_type: :junit, path: '') } + + it 'responds with not found' do + create(:ci_job_artifact, :junit, job: job) + + subject + + expect(response).to have_gitlab_http_status(:not_found) + end + end + end end end diff --git a/spec/controllers/projects/branches_controller_spec.rb b/spec/controllers/projects/branches_controller_spec.rb index 85d3044993e..174d8904481 100644 --- a/spec/controllers/projects/branches_controller_spec.rb +++ b/spec/controllers/projects/branches_controller_spec.rb @@ -124,57 +124,39 @@ describe Projects::BranchesController do ) end - context 'create_confidential_merge_request feature is enabled' do + context 'user cannot update issue' do + let(:issue) { create(:issue, project: confidential_issue_project) } + + it 'does not post a system note' do + expect(SystemNoteService).not_to receive(:new_issue_branch) + + create_branch_with_confidential_issue_project + end + end + + context 'user can update issue' do before do - stub_feature_flags(create_confidential_merge_request: true) + confidential_issue_project.add_reporter(user) end - context 'user cannot update issue' do + context 'issue is under the specified project' do let(:issue) { create(:issue, project: confidential_issue_project) } - it 'does not post a system note' do - expect(SystemNoteService).not_to receive(:new_issue_branch) + it 'posts a system note' do + expect(SystemNoteService).to receive(:new_issue_branch).with(issue, confidential_issue_project, user, "1-feature-branch", branch_project: project) create_branch_with_confidential_issue_project end end - context 'user can update issue' do - before do - confidential_issue_project.add_reporter(user) - end - - context 'issue is under the specified project' do - let(:issue) { create(:issue, project: confidential_issue_project) } - - it 'posts a system note' do - expect(SystemNoteService).to receive(:new_issue_branch).with(issue, confidential_issue_project, user, "1-feature-branch", branch_project: project) - - create_branch_with_confidential_issue_project - end - end - - context 'issue is not under the specified project' do - it 'does not post a system note' do - expect(SystemNoteService).not_to receive(:new_issue_branch) + context 'issue is not under the specified project' do + it 'does not post a system note' do + expect(SystemNoteService).not_to receive(:new_issue_branch) - create_branch_with_confidential_issue_project - end + create_branch_with_confidential_issue_project end end end - - context 'create_confidential_merge_request feature is disabled' do - before do - stub_feature_flags(create_confidential_merge_request: false) - end - - it 'posts a system note on project' do - expect(SystemNoteService).to receive(:new_issue_branch).with(issue, project, user, "1-feature-branch", branch_project: project) - - create_branch_with_confidential_issue_project - end - end end context 'repository-less project' do diff --git a/spec/controllers/projects/ci/daily_build_group_report_results_controller_spec.rb b/spec/controllers/projects/ci/daily_build_group_report_results_controller_spec.rb new file mode 100644 index 00000000000..ac31045678f --- /dev/null +++ b/spec/controllers/projects/ci/daily_build_group_report_results_controller_spec.rb @@ -0,0 +1,80 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe Projects::Ci::DailyBuildGroupReportResultsController do + describe 'GET index' do + let(:project) { create(:project, :public, :repository) } + let(:ref_path) { 'refs/heads/master' } + let(:param_type) { 'coverage' } + let(:start_date) { '2019-12-10' } + let(:end_date) { '2020-03-09' } + + def create_daily_coverage(group_name, coverage, date) + create( + :ci_daily_build_group_report_result, + project: project, + ref_path: ref_path, + group_name: group_name, + data: { 'coverage' => coverage }, + date: date + ) + end + + def csv_response + CSV.parse(response.body) + end + + before do + create_daily_coverage('rspec', 79.0, '2020-03-09') + create_daily_coverage('karma', 81.0, '2019-12-10') + create_daily_coverage('rspec', 67.0, '2019-12-09') + create_daily_coverage('karma', 71.0, '2019-12-09') + + get :index, params: { + namespace_id: project.namespace, + project_id: project, + ref_path: ref_path, + param_type: param_type, + start_date: start_date, + end_date: end_date, + format: :csv + } + end + + it 'serves the results in CSV' do + expect(response).to have_gitlab_http_status(:ok) + expect(response.headers['Content-Type']).to eq('text/csv; charset=utf-8') + + expect(csv_response).to eq([ + %w[date group_name coverage], + ['2020-03-09', 'rspec', '79.0'], + ['2019-12-10', 'karma', '81.0'] + ]) + end + + context 'when given date range spans more than 90 days' do + let(:start_date) { '2019-12-09' } + let(:end_date) { '2020-03-09' } + + it 'limits the result to 90 days from the given start_date' do + expect(response).to have_gitlab_http_status(:ok) + expect(response.headers['Content-Type']).to eq('text/csv; charset=utf-8') + + expect(csv_response).to eq([ + %w[date group_name coverage], + ['2020-03-09', 'rspec', '79.0'], + ['2019-12-10', 'karma', '81.0'] + ]) + end + end + + context 'when given param_type is invalid' do + let(:param_type) { 'something_else' } + + it 'responds with 422 error' do + expect(response).to have_gitlab_http_status(:unprocessable_entity) + end + end + end +end diff --git a/spec/controllers/projects/clusters_controller_spec.rb b/spec/controllers/projects/clusters_controller_spec.rb index 07733ec30d9..698a3773d59 100644 --- a/spec/controllers/projects/clusters_controller_spec.rb +++ b/spec/controllers/projects/clusters_controller_spec.rb @@ -26,7 +26,7 @@ describe Projects::ClustersController do let!(:enabled_cluster) { create(:cluster, :provided_by_gcp, projects: [project]) } let!(:disabled_cluster) { create(:cluster, :disabled, :provided_by_gcp, :production_environment, projects: [project]) } - it 'lists available clusters' do + it 'lists available clusters and renders html' do go expect(response).to have_gitlab_http_status(:ok) @@ -34,20 +34,39 @@ describe Projects::ClustersController do expect(assigns(:clusters)).to match_array([enabled_cluster, disabled_cluster]) end + it 'lists available clusters with json serializer' do + go(format: :json) + + expect(response).to have_gitlab_http_status(:ok) + expect(response).to match_response_schema('cluster_list') + end + context 'when page is specified' do let(:last_page) { project.clusters.page.total_pages } + let(:total_count) { project.clusters.page.total_count } before do - allow(Clusters::Cluster).to receive(:paginates_per).and_return(1) - create_list(:cluster, 2, :provided_by_gcp, :production_environment, projects: [project]) + create_list(:cluster, 30, :provided_by_gcp, :production_environment, projects: [project]) end it 'redirects to the page' do + expect(last_page).to be > 1 + go(page: last_page) expect(response).to have_gitlab_http_status(:ok) expect(assigns(:clusters).current_page).to eq(last_page) end + + it 'displays cluster list for associated page' do + expect(last_page).to be > 1 + + go(page: last_page, format: :json) + + expect(response).to have_gitlab_http_status(:ok) + expect(response.headers['X-Page'].to_i).to eq(last_page) + expect(response.headers['X-Total'].to_i).to eq(total_count) + end end end @@ -68,9 +87,11 @@ describe Projects::ClustersController do it 'is allowed for admin when admin mode enabled', :enable_admin_mode do expect { go }.to be_allowed_for(:admin) end + it 'is disabled for admin when admin mode disabled' do expect { go }.to be_denied_for(:admin) end + it { expect { go }.to be_allowed_for(:owner).of(project) } it { expect { go }.to be_allowed_for(:maintainer).of(project) } it { expect { go }.to be_denied_for(:developer).of(project) } diff --git a/spec/controllers/projects/cycle_analytics/events_controller_spec.rb b/spec/controllers/projects/cycle_analytics/events_controller_spec.rb index b828c678d0c..942e095d669 100644 --- a/spec/controllers/projects/cycle_analytics/events_controller_spec.rb +++ b/spec/controllers/projects/cycle_analytics/events_controller_spec.rb @@ -17,7 +17,7 @@ describe Projects::CycleAnalytics::EventsController do get_issue expect(response).to be_successful - expect(JSON.parse(response.body)['events']).to be_empty + expect(Gitlab::Json.parse(response.body)['events']).to be_empty end end @@ -38,7 +38,7 @@ describe Projects::CycleAnalytics::EventsController do it 'contains event detais' do get_issue - events = JSON.parse(response.body)['events'] + events = Gitlab::Json.parse(response.body)['events'] expect(events).not_to be_empty expect(events.first).to include('title', 'author', 'iid', 'total_time', 'created_at', 'url') @@ -51,7 +51,7 @@ describe Projects::CycleAnalytics::EventsController do expect(response).to be_successful - expect(JSON.parse(response.body)['events']).to be_empty + expect(Gitlab::Json.parse(response.body)['events']).to be_empty end end end 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 new file mode 100644 index 00000000000..30d2b79a92f --- /dev/null +++ b/spec/controllers/projects/design_management/designs/raw_images_controller_spec.rb @@ -0,0 +1,153 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe Projects::DesignManagement::Designs::RawImagesController do + include DesignManagementTestHelpers + + let_it_be(:project) { create(:project, :private) } + let_it_be(:issue) { create(:issue, project: project) } + let_it_be(:viewer) { issue.author } + let(:design_id) { design.id } + let(:sha) { design.versions.first.sha } + let(:filename) { design.filename } + + before do + enable_design_management + end + + describe 'GET #show' do + subject do + get(:show, + params: { + namespace_id: project.namespace, + project_id: project, + design_id: design_id, + sha: sha + }) + end + + before do + sign_in(viewer) + end + + context 'when the design is not an LFS file' do + let_it_be(:design) { create(:design, :with_file, issue: issue, versions_count: 2) } + + # For security, .svg images should only ever be served with Content-Disposition: attachment. + # If this specs ever fails we must assess whether we should be serving svg images. + # See https://gitlab.com/gitlab-org/gitlab/issues/12771 + it 'serves files with `Content-Disposition: attachment`' do + subject + + expect(response.header['Content-Disposition']).to eq('attachment') + expect(response).to have_gitlab_http_status(:ok) + end + + it 'serves files with Workhorse' do + subject + + expect(response.header[Gitlab::Workhorse::DETECT_HEADER]).to eq "true" + expect(response.header[Gitlab::Workhorse::SEND_DATA_HEADER]).to start_with('git-blob:') + expect(response).to have_gitlab_http_status(:ok) + end + + it_behaves_like 'project cache control headers' + + context 'when the user does not have permission' do + let_it_be(:viewer) { create(:user) } + + specify do + subject + + expect(response).to have_gitlab_http_status(:not_found) + end + end + + context 'when design does not exist' do + let(:design_id) { 'foo' } + + specify do + subject + + expect(response).to have_gitlab_http_status(:not_found) + end + end + + describe 'sha param' do + let(:newest_version) { design.versions.ordered.first } + let(:oldest_version) { design.versions.ordered.last } + + shared_examples 'a successful request for sha' do + it do + expect_next_instance_of(DesignManagement::Repository) do |repository| + expect(repository).to receive(:blob_at).with(expected_ref, design.full_path).and_call_original + end + + subject + + expect(response).to have_gitlab_http_status(:ok) + end + end + + specify { expect(newest_version.sha).not_to eq(oldest_version.sha) } + + context 'when sha is the newest version sha' do + let(:sha) { newest_version.sha } + let(:expected_ref) { sha } + + it_behaves_like 'a successful request for sha' + end + + context 'when sha is the oldest version sha' do + let(:sha) { oldest_version.sha } + let(:expected_ref) { sha } + + it_behaves_like 'a successful request for sha' + end + + context 'when sha is nil' do + let(:sha) { nil } + let(:expected_ref) { 'master' } + + it_behaves_like 'a successful request for sha' + end + end + end + + context 'when the design is an LFS file' do + let_it_be(:design) { create(:design, :with_lfs_file, issue: issue) } + + # For security, .svg images should only ever be served with Content-Disposition: attachment. + # If this specs ever fails we must assess whether we should be serving svg images. + # See https://gitlab.com/gitlab-org/gitlab/issues/12771 + it 'serves files with `Content-Disposition: attachment`' do + subject + + expect(response.header['Content-Disposition']).to eq(%Q(attachment; filename=\"#{filename}\"; filename*=UTF-8''#{filename})) + end + + it 'sets appropriate caching headers' do + subject + + expect(response.header['ETag']).to be_present + expect(response.header['Cache-Control']).to eq("max-age=60, private") + end + end + + # Pass `skip_lfs_disabled_tests: true` to this shared example to disable + # the test scenarios for when LFS is disabled globally. + # + # When LFS is disabled then the design management feature also becomes disabled. + # When the feature is disabled, the `authorize :read_design` check within the + # controller will never authorize the user. Therefore #show will return a 403 and + # we cannot test the data that it serves. + it_behaves_like 'a controller that can serve LFS files', skip_lfs_disabled_tests: true do + let(:file) { fixture_file_upload('spec/fixtures/dk.png', '`/png') } + let(:lfs_pointer) { Gitlab::Git::LfsPointerFile.new(file.read) } + let(:design) { create(:design, :with_lfs_file, file: lfs_pointer.pointer, issue: issue) } + let(:lfs_oid) { project.design_repository.blob_at('HEAD', design.full_path).lfs_oid } + let(:filepath) { design.full_path } + end + end +end diff --git a/spec/controllers/projects/design_management/designs/resized_image_controller_spec.rb b/spec/controllers/projects/design_management/designs/resized_image_controller_spec.rb new file mode 100644 index 00000000000..6bfec1b314e --- /dev/null +++ b/spec/controllers/projects/design_management/designs/resized_image_controller_spec.rb @@ -0,0 +1,148 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe Projects::DesignManagement::Designs::ResizedImageController do + include DesignManagementTestHelpers + + let_it_be(:project) { create(:project, :private) } + let_it_be(:issue) { create(:issue, project: project) } + let_it_be(:viewer) { issue.author } + let_it_be(:size) { :v432x230 } + let(:design) { create(:design, :with_smaller_image_versions, issue: issue, versions_count: 2) } + let(:design_id) { design.id } + let(:sha) { design.versions.first.sha } + + before do + enable_design_management + end + + describe 'GET #show' do + subject do + get(:show, + params: { + namespace_id: project.namespace, + project_id: project, + design_id: design_id, + sha: sha, + id: size + }) + end + + before do + sign_in(viewer) + subject + end + + context 'when the user does not have permission' do + let_it_be(:viewer) { create(:user) } + + specify do + expect(response).to have_gitlab_http_status(:not_found) + end + end + + describe 'Response headers' do + it 'completes the request successfully' do + expect(response).to have_gitlab_http_status(:ok) + end + + it 'sets Content-Disposition as attachment' do + filename = design.filename + + expect(response.header['Content-Disposition']).to eq(%Q(attachment; filename=\"#{filename}\"; filename*=UTF-8''#{filename})) + end + + it 'serves files with Workhorse' do + expect(response.header[Gitlab::Workhorse::DETECT_HEADER]).to eq 'true' + end + + it 'sets appropriate caching headers' do + expect(response.header['Cache-Control']).to eq('private') + expect(response.header['ETag']).to be_present + end + end + + context 'when design does not exist' do + let(:design_id) { 'foo' } + + specify do + subject + + expect(response).to have_gitlab_http_status(:not_found) + end + end + + context 'when size is invalid' do + let_it_be(:size) { :foo } + + it 'returns a 404' do + expect(response).to have_gitlab_http_status(:not_found) + end + end + + describe 'sha param' do + let(:newest_version) { design.versions.ordered.first } + let(:oldest_version) { design.versions.ordered.last } + + # The design images generated by Factorybot are identical, so + # refer to the `ETag` header, which is uniquely generated from the Action + # (the record that represents the design at a specific version), to + # verify that the correct file is being returned. + def etag(action) + ActionDispatch::TestResponse.new.send(:generate_weak_etag, [action.cache_key, '']) + end + + specify { expect(newest_version.sha).not_to eq(oldest_version.sha) } + + context 'when sha is the newest version sha' do + let(:sha) { newest_version.sha } + + it 'serves the newest image' do + action = newest_version.actions.first + + expect(response.header['ETag']).to eq(etag(action)) + expect(response).to have_gitlab_http_status(:ok) + end + end + + context 'when sha is the oldest version sha' do + let(:sha) { oldest_version.sha } + + it 'serves the oldest image' do + action = oldest_version.actions.first + + expect(response.header['ETag']).to eq(etag(action)) + expect(response).to have_gitlab_http_status(:ok) + end + end + + context 'when sha is nil' do + let(:sha) { nil } + + it 'serves the newest image' do + action = newest_version.actions.first + + expect(response.header['ETag']).to eq(etag(action)) + expect(response).to have_gitlab_http_status(:ok) + end + end + + context 'when sha is not a valid version sha' do + let(:sha) { '570e7b2abdd848b95f2f578043fc23bd6f6fd24d' } + + it 'returns a 404' do + expect(response).to have_gitlab_http_status(:not_found) + end + end + end + + context 'when design does not have a smaller image size available' do + let(:design) { create(:design, :with_file, issue: issue) } + + it 'returns a 404' do + expect(response).to have_gitlab_http_status(:not_found) + end + end + end +end diff --git a/spec/controllers/projects/environments/prometheus_api_controller_spec.rb b/spec/controllers/projects/environments/prometheus_api_controller_spec.rb index 793c10f0b21..64f90e44bb6 100644 --- a/spec/controllers/projects/environments/prometheus_api_controller_spec.rb +++ b/spec/controllers/projects/environments/prometheus_api_controller_spec.rb @@ -38,7 +38,7 @@ describe Projects::Environments::PrometheusApiController do context 'with success result' do let(:service_result) { { status: :success, body: prometheus_body } } let(:prometheus_body) { '{"status":"success"}' } - let(:prometheus_json_body) { JSON.parse(prometheus_body) } + let(:prometheus_json_body) { Gitlab::Json.parse(prometheus_body) } it 'returns prometheus response' do get :proxy, params: environment_params @@ -55,7 +55,7 @@ describe Projects::Environments::PrometheusApiController do end it 'replaces variables with values' do - get :proxy, params: environment_params.merge(query: 'up{environment="%{ci_environment_slug}"}') + get :proxy, params: environment_params.merge(query: 'up{environment="{{ci_environment_slug}}"}') expect(Prometheus::ProxyService).to have_received(:new) .with(environment, 'GET', 'query', expected_params) diff --git a/spec/controllers/projects/environments_controller_spec.rb b/spec/controllers/projects/environments_controller_spec.rb index 3b035eea7d5..56fff2771ec 100644 --- a/spec/controllers/projects/environments_controller_spec.rb +++ b/spec/controllers/projects/environments_controller_spec.rb @@ -410,6 +410,18 @@ describe Projects::EnvironmentsController do expect(json_response['last_update']).to eq(42) end end + + context 'permissions' do + before do + allow(controller).to receive(:can?).and_return true + end + + it 'checks :metrics_dashboard ability' do + expect(controller).to receive(:can?).with(anything, :metrics_dashboard, anything) + + get :metrics, params: environment_params + end + end end describe 'GET #additional_metrics' do @@ -473,6 +485,18 @@ describe Projects::EnvironmentsController do .to raise_error(ActionController::ParameterMissing) end end + + context 'permissions' do + before do + allow(controller).to receive(:can?).and_return true + end + + it 'checks :metrics_dashboard ability' do + expect(controller).to receive(:can?).with(anything, :metrics_dashboard, anything) + + get :metrics, params: environment_params + end + end end describe 'GET #metrics_dashboard' do @@ -648,6 +672,18 @@ describe Projects::EnvironmentsController do it_behaves_like 'the default dashboard' it_behaves_like 'dashboard can be specified' it_behaves_like 'dashboard can be embedded' + + context 'permissions' do + before do + allow(controller).to receive(:can?).and_return true + end + + it 'checks :metrics_dashboard ability' do + expect(controller).to receive(:can?).with(anything, :metrics_dashboard, anything) + + get :metrics, params: environment_params + end + end end describe 'GET #search' do diff --git a/spec/controllers/projects/grafana_api_controller_spec.rb b/spec/controllers/projects/grafana_api_controller_spec.rb index c62baa30fde..8502bd1ab0a 100644 --- a/spec/controllers/projects/grafana_api_controller_spec.rb +++ b/spec/controllers/projects/grafana_api_controller_spec.rb @@ -131,10 +131,11 @@ describe Projects::GrafanaApiController do get :metrics_dashboard, params: params expect(response).to have_gitlab_http_status(:ok) - expect(json_response).to eq({ + expect(json_response).to include({ 'dashboard' => '{}', 'status' => 'success' }) + expect(json_response).to include('metrics_data') end end diff --git a/spec/controllers/projects/graphs_controller_spec.rb b/spec/controllers/projects/graphs_controller_spec.rb index b5248c7f0c8..e589815c45d 100644 --- a/spec/controllers/projects/graphs_controller_spec.rb +++ b/spec/controllers/projects/graphs_controller_spec.rb @@ -41,6 +41,26 @@ describe Projects::GraphsController do expect(response).to have_gitlab_http_status(:ok) expect(response).to render_template(:charts) end + + it 'sets the daily coverage options' do + Timecop.freeze do + get(:charts, params: { namespace_id: project.namespace.path, project_id: project.path, id: 'master' }) + + expect(assigns[:daily_coverage_options]).to eq( + base_params: { + start_date: Time.current.to_date - 90.days, + end_date: Time.current.to_date, + ref_path: project.repository.expand_ref('master'), + param_type: 'coverage' + }, + download_path: namespace_project_ci_daily_build_group_report_results_path( + namespace_id: project.namespace, + project_id: project, + format: :csv + ) + ) + end + end end context 'when languages were previously detected' do diff --git a/spec/controllers/projects/import/jira_controller_spec.rb b/spec/controllers/projects/import/jira_controller_spec.rb index 4629aab65dd..d1b0a086576 100644 --- a/spec/controllers/projects/import/jira_controller_spec.rb +++ b/spec/controllers/projects/import/jira_controller_spec.rb @@ -3,6 +3,8 @@ require 'spec_helper' describe Projects::Import::JiraController do + include JiraServiceHelper + let_it_be(:user) { create(:user) } let_it_be(:project) { create(:project) } let_it_be(:jira_project_key) { 'Test' } @@ -61,9 +63,10 @@ describe Projects::Import::JiraController do before do stub_feature_flags(jira_issue_import: true) stub_feature_flags(jira_issue_import_vue: false) + stub_jira_service_test end - context 'when jira service is enabled for the project' do + context 'when Jira service is enabled for the project' do let_it_be(:jira_service) { create(:jira_service, project: project) } context 'when user is developer' do @@ -79,7 +82,7 @@ describe Projects::Import::JiraController do get :show, params: { namespace_id: project.namespace.to_param, project_id: project } end - it 'does not query jira service' do + it 'does not query Jira service' do expect(project).not_to receive(:jira_service) end @@ -118,7 +121,7 @@ describe Projects::Import::JiraController do end end - context 'when running jira import first time' do + context 'when running Jira import first time' do context 'get show' do before do allow(JIRA::Resource::Project).to receive(:all).and_return(jira_projects) @@ -147,12 +150,12 @@ describe Projects::Import::JiraController do end context 'post import' do - context 'when jira project key is empty' do + context 'when Jira project key is empty' do it 'redirects back to show with an error' do post :import, params: { namespace_id: project.namespace, project_id: project, jira_project_key: '' } expect(response).to redirect_to(project_import_jira_path(project)) - expect(flash[:alert]).to eq('No jira project key has been provided.') + expect(flash[:alert]).to eq('No Jira project key has been provided.') end end @@ -197,7 +200,7 @@ describe Projects::Import::JiraController do end end - context 'when jira import ran before' do + context 'when Jira import ran before' do let_it_be(:jira_import_state) { create(:jira_import_state, :finished, project: project, jira_project_key: jira_project_key) } context 'get show' do diff --git a/spec/controllers/projects/issues_controller_spec.rb b/spec/controllers/projects/issues_controller_spec.rb index 862a4bd3559..96f11f11dc4 100644 --- a/spec/controllers/projects/issues_controller_spec.rb +++ b/spec/controllers/projects/issues_controller_spec.rb @@ -4,6 +4,7 @@ require 'spec_helper' describe Projects::IssuesController do include ProjectForksHelper + include_context 'includes Spam constants' let(:project) { create(:project) } let(:user) { create(:user) } @@ -186,6 +187,33 @@ describe Projects::IssuesController do expect(assigns(:issue)).to be_a_new(Issue) end + where(:conf_value, :conf_result) do + [ + [true, true], + ['true', true], + ['TRUE', true], + [false, false], + ['false', false], + ['FALSE', false] + ] + end + + with_them do + it 'sets the confidential flag to the expected value' do + get :new, params: { + namespace_id: project.namespace, + project_id: project, + issue: { + confidential: conf_value + } + } + + assigned_issue = assigns(:issue) + expect(assigned_issue).to be_a_new(Issue) + expect(assigned_issue.confidential).to eq conf_result + end + end + it 'fills in an issue for a merge request' do project_with_repository = create(:project, :repository) project_with_repository.add_developer(user) @@ -242,6 +270,91 @@ describe Projects::IssuesController do end end + describe '#related_branches' do + subject { get :related_branches, params: params, format: :json } + + before do + sign_in(user) + project.add_developer(developer) + end + + let(:developer) { user } + let(:params) do + { + namespace_id: project.namespace, + project_id: project, + id: issue.iid + } + end + + context 'the current user cannot download code' do + it 'prevents access' do + allow(controller).to receive(:can?).with(any_args).and_return(true) + allow(controller).to receive(:can?).with(user, :download_code, project).and_return(false) + + subject + + expect(response).to have_gitlab_http_status(:not_found) + end + end + + context 'there are no related branches' do + it 'assigns empty arrays', :aggregate_failures do + subject + + expect(response).to have_gitlab_http_status(:ok) + expect(assigns(:related_branches)).to be_empty + expect(response).to render_template('projects/issues/_related_branches') + expect(json_response).to eq('html' => '') + end + end + + context 'there are related branches' do + let(:missing_branch) { "#{issue.to_branch_name}-missing" } + let(:unreadable_branch) { "#{issue.to_branch_name}-unreadable" } + let(:pipeline) { build(:ci_pipeline, :success, project: project) } + let(:master_branch) { 'master' } + + let(:related_branches) do + [ + branch_info(issue.to_branch_name, pipeline.detailed_status(user)), + branch_info(missing_branch, nil), + branch_info(unreadable_branch, nil) + ] + end + + def branch_info(name, status) + { + name: name, + link: controller.project_compare_path(project, from: master_branch, to: name), + pipeline_status: status + } + end + + before do + allow(controller).to receive(:find_routable!) + .with(Project, project.full_path, any_args).and_return(project) + allow(project).to receive(:default_branch).and_return(master_branch) + allow_next_instance_of(Issues::RelatedBranchesService) do |service| + allow(service).to receive(:execute).and_return(related_branches) + end + end + + it 'finds and assigns the appropriate branch information', :aggregate_failures do + subject + + expect(response).to have_gitlab_http_status(:ok) + expect(assigns(:related_branches)).to contain_exactly( + branch_info(issue.to_branch_name, an_instance_of(Gitlab::Ci::Status::Success)), + branch_info(missing_branch, be_nil), + branch_info(unreadable_branch, be_nil) + ) + expect(response).to render_template('projects/issues/_related_branches') + expect(json_response).to match('html' => String) + end + end + end + # This spec runs as a request-style spec in order to invoke the # Rails router. A controller-style spec matches the wrong route, and # session['user_return_to'] becomes incorrect. @@ -419,11 +532,11 @@ describe Projects::IssuesController do expect(issue.reload.title).to eq('New title') end - context 'when Akismet is enabled and the issue is identified as spam' do + context 'when the SpamVerdictService disallows' do before do stub_application_setting(recaptcha_enabled: true) - expect_next_instance_of(Spam::AkismetService) do |akismet_service| - expect(akismet_service).to receive_messages(spam?: true) + expect_next_instance_of(Spam::SpamVerdictService) do |verdict_service| + expect(verdict_service).to receive(:execute).and_return(REQUIRE_RECAPTCHA) end end @@ -496,7 +609,7 @@ describe Projects::IssuesController do before do project.add_developer(user) - issue.update!(last_edited_by: deleted_user, last_edited_at: Time.now) + issue.update!(last_edited_by: deleted_user, last_edited_at: Time.current) deleted_user.destroy sign_in(user) @@ -712,20 +825,20 @@ describe Projects::IssuesController do update_issue(issue_params: { assignee_ids: [assignee.id] }) expect(json_response['assignees'].first.keys) - .to match_array(%w(id name username avatar_url state web_url)) + .to include(*%w(id name username avatar_url state web_url)) end end - context 'Akismet is enabled' do + context 'Recaptcha is enabled' do before do project.update!(visibility_level: Gitlab::VisibilityLevel::PUBLIC) stub_application_setting(recaptcha_enabled: true) end - context 'when an issue is not identified as spam' do + context 'when SpamVerdictService allows the issue' do before do - expect_next_instance_of(Spam::AkismetService) do |akismet_service| - expect(akismet_service).to receive_messages(spam?: false) + expect_next_instance_of(Spam::SpamVerdictService) do |verdict_service| + expect(verdict_service).to receive(:execute).and_return(ALLOW) end end @@ -735,10 +848,10 @@ describe Projects::IssuesController do end context 'when an issue is identified as spam' do - context 'when captcha is not verified' do + context 'when recaptcha is not verified' do before do - expect_next_instance_of(Spam::AkismetService) do |akismet_service| - expect(akismet_service).to receive_messages(spam?: true) + expect_next_instance_of(Spam::SpamVerdictService) do |verdict_service| + expect(verdict_service).to receive(:execute).and_return(REQUIRE_RECAPTCHA) end end @@ -751,7 +864,7 @@ describe Projects::IssuesController do expect { update_issue }.not_to change { issue.reload.title } end - it 'rejects an issue recognized as a spam when recaptcha disabled' do + it 'rejects an issue recognized as a spam when reCAPTCHA disabled' do stub_application_setting(recaptcha_enabled: false) expect { update_issue }.not_to change { issue.reload.title } @@ -796,7 +909,7 @@ describe Projects::IssuesController do end end - context 'when captcha is verified' do + context 'when recaptcha is verified' do let(:spammy_title) { 'Whatever' } let!(:spam_logs) { create_list(:spam_log, 2, user: user, title: spammy_title) } @@ -810,7 +923,7 @@ describe Projects::IssuesController do expect(response).to have_gitlab_http_status(:ok) end - it 'accepts an issue after recaptcha is verified' do + it 'accepts an issue after reCAPTCHA is verified' do expect { update_verified_issue }.to change { issue.reload.title }.to(spammy_title) end @@ -967,17 +1080,17 @@ describe Projects::IssuesController do end end - context 'Akismet is enabled' do + context 'Recaptcha is enabled' do before do stub_application_setting(recaptcha_enabled: true) end - context 'when an issue is not identified as spam' do + context 'when SpamVerdictService allows the issue' do before do stub_feature_flags(allow_possible_spam: false) - expect_next_instance_of(Spam::AkismetService) do |akismet_service| - expect(akismet_service).to receive_messages(spam?: false) + expect_next_instance_of(Spam::SpamVerdictService) do |verdict_service| + expect(verdict_service).to receive(:execute).and_return(ALLOW) end end @@ -986,18 +1099,18 @@ describe Projects::IssuesController do end end - context 'when an issue is identified as spam' do + context 'when SpamVerdictService requires recaptcha' do context 'when captcha is not verified' do - def post_spam_issue - post_new_issue(title: 'Spam Title', description: 'Spam lives here') - end - before do - expect_next_instance_of(Spam::AkismetService) do |akismet_service| - expect(akismet_service).to receive_messages(spam?: true) + expect_next_instance_of(Spam::SpamVerdictService) do |verdict_service| + expect(verdict_service).to receive(:execute).and_return(REQUIRE_RECAPTCHA) end end + def post_spam_issue + post_new_issue(title: 'Spam Title', description: 'Spam lives here') + end + context 'when allow_possible_spam feature flag is false' do before do stub_feature_flags(allow_possible_spam: false) @@ -1016,7 +1129,7 @@ describe Projects::IssuesController do expect { post_new_issue(title: '') }.not_to change(Issue, :count) end - it 'does not create an issue when recaptcha is not enabled' do + it 'does not create an issue when reCAPTCHA is not enabled' do stub_application_setting(recaptcha_enabled: false) expect { post_spam_issue }.not_to change(Issue, :count) @@ -1039,30 +1152,31 @@ describe Projects::IssuesController do end end - context 'when captcha is verified' do + context 'when Recaptcha is verified' do let!(:spam_logs) { create_list(:spam_log, 2, user: user, title: 'Title') } + let!(:last_spam_log) { spam_logs.last } def post_verified_issue - post_new_issue({}, { spam_log_id: spam_logs.last.id, recaptcha_verification: true } ) + post_new_issue({}, { spam_log_id: last_spam_log.id, recaptcha_verification: true } ) end before do expect(controller).to receive_messages(verify_recaptcha: true) end - it 'accepts an issue after recaptcha is verified' do + it 'accepts an issue after reCAPTCHA is verified' do expect { post_verified_issue }.to change(Issue, :count) end it 'marks spam log as recaptcha_verified' do - expect { post_verified_issue }.to change { SpamLog.last.recaptcha_verified }.from(false).to(true) + expect { post_verified_issue }.to change { last_spam_log.reload.recaptcha_verified }.from(false).to(true) end it 'does not mark spam log as recaptcha_verified when it does not belong to current_user' do spam_log = create(:spam_log) expect { post_new_issue({}, { spam_log_id: spam_log.id, recaptcha_verification: true } ) } - .not_to change { SpamLog.last.recaptcha_verified } + .not_to change { last_spam_log.recaptcha_verified } end end end @@ -1294,6 +1408,7 @@ describe Projects::IssuesController do it 'render merge request as json' do create_merge_request + expect(response).to have_gitlab_http_status(:ok) expect(response).to match_response_schema('merge_request') end @@ -1337,24 +1452,8 @@ describe Projects::IssuesController do let(:target_project) { fork_project(project, user, repository: true) } let(:target_project_id) { target_project.id } - context 'create_confidential_merge_request feature is enabled' do - before do - stub_feature_flags(create_confidential_merge_request: true) - end - - it 'creates a new merge request', :sidekiq_might_not_need_inline do - expect { create_merge_request }.to change(target_project.merge_requests, :count).by(1) - end - end - - context 'create_confidential_merge_request feature is disabled' do - before do - stub_feature_flags(create_confidential_merge_request: false) - end - - it 'creates a new merge request' do - expect { create_merge_request }.to change(project.merge_requests, :count).by(1) - end + it 'creates a new merge request', :sidekiq_might_not_need_inline do + expect { create_merge_request }.to change(target_project.merge_requests, :count).by(1) end end @@ -1513,61 +1612,6 @@ describe Projects::IssuesController do expect(note_json['author']['status_tooltip_html']).to be_present end - context 'is_gitlab_employee attribute' do - subject { get :discussions, params: { namespace_id: project.namespace, project_id: project, id: issue.iid } } - - before do - allow(Gitlab).to receive(:com?).and_return(true) - note_user = discussion.author - note_user.update(email: email) - note_user.confirm - end - - shared_examples 'non inclusion of gitlab employee badge' do - it 'does not render the is_gitlab_employee attribute' do - subject - - note_json = json_response.first['notes'].first - - expect(note_json['author']['is_gitlab_employee']).to be nil - end - end - - context 'when user is a gitlab employee' do - let(:email) { 'test@gitlab.com' } - - it 'renders the is_gitlab_employee attribute' do - subject - - note_json = json_response.first['notes'].first - - expect(note_json['author']['is_gitlab_employee']).to be true - end - - context 'when feature flag is disabled' do - before do - stub_feature_flags(gitlab_employee_badge: false) - end - - it_behaves_like 'non inclusion of gitlab employee badge' - end - end - - context 'when user is not a gitlab employee' do - let(:email) { 'test@example.com' } - - it_behaves_like 'non inclusion of gitlab employee badge' - - context 'when feature flag is disabled' do - before do - stub_feature_flags(gitlab_employee_badge: false) - end - - it_behaves_like 'non inclusion of gitlab employee badge' - end - end - end - it 'does not cause an extra query for the status' do control = ActiveRecord::QueryRecorder.new do get :discussions, params: { namespace_id: project.namespace, project_id: project, id: issue.iid } @@ -1660,6 +1704,33 @@ describe Projects::IssuesController do end end + describe 'GET #designs' do + context 'when project has moved' do + let(:new_project) { create(:project) } + let(:issue) { create(:issue, project: new_project) } + + before do + sign_in(user) + + project.route.destroy + new_project.redirect_routes.create!(path: project.full_path) + new_project.add_developer(user) + end + + it 'redirects from an old issue/designs correctly' do + get :designs, + params: { + namespace_id: project.namespace, + project_id: project, + id: issue + } + + expect(response).to redirect_to(designs_project_issue_path(new_project, issue)) + expect(response).to have_gitlab_http_status(:found) + end + end + end + context 'private project with token authentication' do let(:private_project) { create(:project, :private) } diff --git a/spec/controllers/projects/logs_controller_spec.rb b/spec/controllers/projects/logs_controller_spec.rb index ea71dbe45aa..e86a42b03c8 100644 --- a/spec/controllers/projects/logs_controller_spec.rb +++ b/spec/controllers/projects/logs_controller_spec.rb @@ -16,16 +16,23 @@ describe Projects::LogsController do let(:container) { 'container-1' } before do - project.add_maintainer(user) - sign_in(user) end describe 'GET #index' do let(:empty_project) { create(:project) } + it 'returns 404 with developer access' do + project.add_developer(user) + + get :index, params: environment_params + + expect(response).to have_gitlab_http_status(:not_found) + end + it 'renders empty logs page if no environment exists' do empty_project.add_maintainer(user) + get :index, params: { namespace_id: empty_project.namespace, project_id: empty_project } expect(response).to be_ok @@ -33,6 +40,8 @@ describe Projects::LogsController do end it 'renders index template' do + project.add_maintainer(user) + get :index, params: environment_params expect(response).to be_ok @@ -50,7 +59,7 @@ describe Projects::LogsController do container_name: container } end - let(:service_result_json) { JSON.parse(service_result.to_json) } + let(:service_result_json) { Gitlab::Json.parse(service_result.to_json) } let_it_be(:cluster) { create(:cluster, :provided_by_gcp, environment_scope: '*', projects: [project]) } @@ -60,70 +69,84 @@ describe Projects::LogsController do end end - it 'returns the service result' do + it 'returns 404 with developer access' do + project.add_developer(user) + get endpoint, params: environment_params(pod_name: pod_name, format: :json) - expect(response).to have_gitlab_http_status(:success) - expect(json_response).to eq(service_result_json) + expect(response).to have_gitlab_http_status(:not_found) end - it 'registers a usage of the endpoint' do - expect(::Gitlab::UsageCounters::PodLogs).to receive(:increment).with(project.id) + context 'with maintainer access' do + before do + project.add_maintainer(user) + end - get endpoint, params: environment_params(pod_name: pod_name, format: :json) + it 'returns the service result' do + get endpoint, params: environment_params(pod_name: pod_name, format: :json) - expect(response).to have_gitlab_http_status(:success) - end + expect(response).to have_gitlab_http_status(:success) + expect(json_response).to eq(service_result_json) + end - it 'sets the polling header' do - get endpoint, params: environment_params(pod_name: pod_name, format: :json) + it 'registers a usage of the endpoint' do + expect(::Gitlab::UsageCounters::PodLogs).to receive(:increment).with(project.id) - expect(response).to have_gitlab_http_status(:success) - expect(response.headers['Poll-Interval']).to eq('3000') - end + get endpoint, params: environment_params(pod_name: pod_name, format: :json) - context 'when service is processing' do - let(:service_result) { nil } + expect(response).to have_gitlab_http_status(:success) + end - it 'returns a 202' do + it 'sets the polling header' do get endpoint, params: environment_params(pod_name: pod_name, format: :json) - expect(response).to have_gitlab_http_status(:accepted) + expect(response).to have_gitlab_http_status(:success) + expect(response.headers['Poll-Interval']).to eq('3000') end - end - shared_examples 'unsuccessful execution response' do |message| - let(:service_result) do - { - status: :error, - message: message - } - end + context 'when service is processing' do + let(:service_result) { nil } - it 'returns the error' do - get endpoint, params: environment_params(pod_name: pod_name, format: :json) + it 'returns a 202' do + get endpoint, params: environment_params(pod_name: pod_name, format: :json) - expect(response).to have_gitlab_http_status(:bad_request) - expect(json_response).to eq(service_result_json) + expect(response).to have_gitlab_http_status(:accepted) + end end - end - context 'when service is failing' do - it_behaves_like 'unsuccessful execution response', 'some error' - end + shared_examples 'unsuccessful execution response' do |message| + let(:service_result) do + { + status: :error, + message: message + } + end - context 'when cluster is nil' do - let!(:cluster) { nil } + it 'returns the error' do + get endpoint, params: environment_params(pod_name: pod_name, format: :json) - it_behaves_like 'unsuccessful execution response', 'Environment does not have deployments' - end + expect(response).to have_gitlab_http_status(:bad_request) + expect(json_response).to eq(service_result_json) + end + end - context 'when namespace is empty' do - before do - allow(environment).to receive(:deployment_namespace).and_return('') + context 'when service is failing' do + it_behaves_like 'unsuccessful execution response', 'some error' + end + + context 'when cluster is nil' do + let!(:cluster) { nil } + + it_behaves_like 'unsuccessful execution response', 'Environment does not have deployments' end - it_behaves_like 'unsuccessful execution response', 'Environment does not have deployments' + context 'when namespace is empty' do + before do + allow(environment).to receive(:deployment_namespace).and_return('') + end + + it_behaves_like 'unsuccessful execution response', 'Environment does not have deployments' + end end end diff --git a/spec/controllers/projects/merge_requests_controller_spec.rb b/spec/controllers/projects/merge_requests_controller_spec.rb index aaeaf53d100..7d9e42fcc2d 100644 --- a/spec/controllers/projects/merge_requests_controller_spec.rb +++ b/spec/controllers/projects/merge_requests_controller_spec.rb @@ -935,34 +935,6 @@ describe Projects::MergeRequestsController do }]) end end - - context 'when feature flag :ci_expose_arbitrary_artifacts_in_mr is disabled' do - let(:job_options) do - { - artifacts: { - paths: ['ci_artifacts.txt'], - expose_as: 'Exposed artifact' - } - } - end - let(:report) { double } - - before do - stub_feature_flags(ci_expose_arbitrary_artifacts_in_mr: false) - end - - it 'does not send polling interval' do - expect(Gitlab::PollingInterval).not_to receive(:set_header) - - subject - end - - it 'returns 204 HTTP status' do - subject - - expect(response).to have_gitlab_http_status(:no_content) - end - end end context 'when pipeline does not have jobs with exposed artifacts' do @@ -1114,6 +1086,150 @@ describe Projects::MergeRequestsController do end end + describe 'GET terraform_reports' do + let(:merge_request) do + create(:merge_request, + :with_merge_request_pipeline, + target_project: project, + source_project: project) + end + + let(:pipeline) do + create(:ci_pipeline, + :success, + :with_terraform_reports, + project: merge_request.source_project, + ref: merge_request.source_branch, + sha: merge_request.diff_head_sha) + end + + before do + allow_any_instance_of(MergeRequest) + .to receive(:find_terraform_reports) + .and_return(report) + + allow_any_instance_of(MergeRequest) + .to receive(:actual_head_pipeline) + .and_return(pipeline) + end + + subject do + get :terraform_reports, params: { + namespace_id: project.namespace.to_param, + project_id: project, + id: merge_request.iid + }, + format: :json + end + + describe 'permissions on a public project with private CI/CD' do + let(:project) { create :project, :repository, :public, :builds_private } + let(:report) { { status: :parsed, data: [] } } + + context 'while signed out' do + before do + sign_out(user) + end + + it 'responds with a 404' do + subject + + expect(response).to have_gitlab_http_status(:not_found) + expect(response.body).to be_blank + end + end + + context 'while signed in as an unrelated user' do + before do + sign_in(create(:user)) + end + + it 'responds with a 404' do + subject + + expect(response).to have_gitlab_http_status(:not_found) + expect(response.body).to be_blank + end + end + end + + context 'when pipeline has jobs with terraform reports' do + before do + allow_next_instance_of(MergeRequest) do |merge_request| + allow(merge_request).to receive(:has_terraform_reports?).and_return(true) + end + end + + context 'when processing terraform reports is in progress' do + let(:report) { { status: :parsing } } + + it 'sends polling interval' do + expect(Gitlab::PollingInterval).to receive(:set_header) + + subject + end + + it 'returns 204 HTTP status' do + subject + + expect(response).to have_gitlab_http_status(:no_content) + end + end + + context 'when processing terraform reports is completed' do + let(:report) { { status: :parsed, data: pipeline.terraform_reports.plans } } + + it 'returns terraform reports' do + subject + + expect(response).to have_gitlab_http_status(:ok) + expect(json_response).to match( + a_hash_including( + 'tfplan.json' => hash_including( + 'create' => 0, + 'delete' => 0, + 'update' => 1 + ) + ) + ) + end + end + + context 'when user created corrupted terraform reports' do + let(:report) { { status: :error, status_reason: 'Failed to parse terraform reports' } } + + it 'does not send polling interval' do + expect(Gitlab::PollingInterval).not_to receive(:set_header) + + subject + end + + it 'returns 400 HTTP status' do + subject + + expect(response).to have_gitlab_http_status(:bad_request) + expect(json_response).to eq({ 'status_reason' => 'Failed to parse terraform reports' }) + end + end + end + + context 'when pipeline does not have jobs with terraform reports' do + before do + allow_next_instance_of(MergeRequest) do |merge_request| + allow(merge_request).to receive(:has_terraform_reports?).and_return(false) + end + end + + let(:report) { { status: :error } } + + it 'returns error' do + subject + + expect(response).to have_gitlab_http_status(:bad_request) + end + end + end + describe 'GET test_reports' do let(:merge_request) do create(:merge_request, @@ -1225,6 +1341,141 @@ describe Projects::MergeRequestsController do end end + describe 'GET accessibility_reports' do + let(:merge_request) do + create(:merge_request, + :with_diffs, + :with_merge_request_pipeline, + target_project: project, + source_project: project + ) + end + + let(:pipeline) do + create(:ci_pipeline, + :success, + project: merge_request.source_project, + ref: merge_request.source_branch, + sha: merge_request.diff_head_sha) + end + + before do + allow_any_instance_of(MergeRequest) + .to receive(:compare_accessibility_reports) + .and_return(accessibility_comparison) + + allow_any_instance_of(MergeRequest) + .to receive(:actual_head_pipeline) + .and_return(pipeline) + end + + subject do + get :accessibility_reports, params: { + namespace_id: project.namespace.to_param, + project_id: project, + id: merge_request.iid + }, + format: :json + end + + context 'permissions on a public project with private CI/CD' do + let(:project) { create(:project, :repository, :public, :builds_private) } + let(:accessibility_comparison) { { status: :parsed, data: { summary: 1 } } } + + context 'while signed out' do + before do + sign_out(user) + end + + it 'responds with a 404' do + subject + + expect(response).to have_gitlab_http_status(:not_found) + expect(response.body).to be_blank + end + end + + context 'while signed in as an unrelated user' do + before do + sign_in(create(:user)) + end + + it 'responds with a 404' do + subject + + expect(response).to have_gitlab_http_status(:not_found) + expect(response.body).to be_blank + end + end + end + + context 'when feature flag is disabled' do + let(:accessibility_comparison) { { status: :parsed, data: { summary: 1 } } } + + before do + stub_feature_flags(accessibility_report_view: false) + end + + it 'returns 204 HTTP status' do + subject + + expect(response).to have_gitlab_http_status(:no_content) + end + end + + context 'when pipeline has jobs with accessibility reports' do + before do + allow_any_instance_of(MergeRequest) + .to receive(:has_accessibility_reports?) + .and_return(true) + end + + context 'when processing accessibility reports is in progress' do + let(:accessibility_comparison) { { status: :parsing } } + + it 'sends polling interval' do + expect(Gitlab::PollingInterval).to receive(:set_header) + + subject + end + + it 'returns 204 HTTP status' do + subject + + expect(response).to have_gitlab_http_status(:no_content) + end + end + + context 'when processing accessibility reports is completed' do + let(:accessibility_comparison) { { status: :parsed, data: { summary: 1 } } } + + it 'returns accessibility reports' do + subject + + expect(response).to have_gitlab_http_status(:ok) + expect(json_response).to eq({ 'summary' => 1 }) + end + end + + context 'when user created corrupted accessibility reports' do + let(:accessibility_comparison) { { status: :error, status_reason: 'This merge request does not have accessibility reports' } } + + it 'does not send polling interval' do + expect(Gitlab::PollingInterval).not_to receive(:set_header) + + subject + end + + it 'returns 400 HTTP status' do + subject + + expect(response).to have_gitlab_http_status(:bad_request) + expect(json_response).to eq({ 'status_reason' => 'This merge request does not have accessibility reports' }) + end + end + end + end + describe 'POST remove_wip' do before do merge_request.title = merge_request.wip_title diff --git a/spec/controllers/projects/mirrors_controller_spec.rb b/spec/controllers/projects/mirrors_controller_spec.rb index faeade0d737..8cd940978c0 100644 --- a/spec/controllers/projects/mirrors_controller_spec.rb +++ b/spec/controllers/projects/mirrors_controller_spec.rb @@ -189,7 +189,7 @@ describe Projects::MirrorsController do context 'no data in cache' do it 'requests the cache to be filled and returns a 204 response' do - expect(ReactiveCachingWorker).to receive(:perform_async).with(cache.class, cache.id).at_least(:once) + expect(ExternalServiceReactiveCachingWorker).to receive(:perform_async).with(cache.class, cache.id).at_least(:once) do_get(project) diff --git a/spec/controllers/projects/pipelines_controller_spec.rb b/spec/controllers/projects/pipelines_controller_spec.rb index 9d243bf5a7f..b3d8fb94fb3 100644 --- a/spec/controllers/projects/pipelines_controller_spec.rb +++ b/spec/controllers/projects/pipelines_controller_spec.rb @@ -145,11 +145,81 @@ describe Projects::PipelinesController do end end - def get_pipelines_index_json + context 'filter by scope' do + it 'returns matched pipelines' do + get_pipelines_index_json(scope: 'running') + + check_pipeline_response(returned: 2, all: 6, running: 2, pending: 1, finished: 3) + end + + context 'scope is branches or tags' do + before do + create(:ci_pipeline, :failed, project: project, ref: 'v1.0.0', tag: true) + end + + context 'when scope is branches' do + it 'returns matched pipelines' do + get_pipelines_index_json(scope: 'branches') + + check_pipeline_response(returned: 1, all: 7, running: 2, pending: 1, finished: 4) + end + end + + context 'when scope is tags' do + it 'returns matched pipelines' do + get_pipelines_index_json(scope: 'tags') + + check_pipeline_response(returned: 1, all: 7, running: 2, pending: 1, finished: 4) + end + end + end + end + + context 'filter by username' do + let!(:pipeline) { create(:ci_pipeline, :running, project: project, user: user) } + + context 'when username exists' do + it 'returns matched pipelines' do + get_pipelines_index_json(username: user.username) + + check_pipeline_response(returned: 1, all: 1, running: 1, pending: 0, finished: 0) + end + end + + context 'when username does not exist' do + it 'returns empty' do + get_pipelines_index_json(username: 'invalid-username') + + check_pipeline_response(returned: 0, all: 0, running: 0, pending: 0, finished: 0) + end + end + end + + context 'filter by ref' do + let!(:pipeline) { create(:ci_pipeline, :running, project: project, ref: 'branch-1') } + + context 'when pipelines with the ref exists' do + it 'returns matched pipelines' do + get_pipelines_index_json(ref: 'branch-1') + + check_pipeline_response(returned: 1, all: 1, running: 1, pending: 0, finished: 0) + end + end + + context 'when no pipeline with the ref exists' do + it 'returns empty list' do + get_pipelines_index_json(ref: 'invalid-ref') + + check_pipeline_response(returned: 0, all: 0, running: 0, pending: 0, finished: 0) + end + end + end + + def get_pipelines_index_json(params = {}) get :index, params: { namespace_id: project.namespace, project_id: project - }, + }.merge(params), format: :json end @@ -199,6 +269,18 @@ describe Projects::PipelinesController do user: user ) end + + def check_pipeline_response(returned:, all:, running:, pending:, finished:) + aggregate_failures do + expect(response).to match_response_schema('pipeline') + + expect(json_response['pipelines'].count).to eq returned + expect(json_response['count']['all'].to_i).to eq all + expect(json_response['count']['running'].to_i).to eq running + expect(json_response['count']['pending'].to_i).to eq pending + expect(json_response['count']['finished'].to_i).to eq finished + end + end end describe 'GET show.json' do @@ -748,12 +830,10 @@ describe Projects::PipelinesController do context 'when feature is enabled' do before do - stub_feature_flags(junit_pipeline_view: true) + stub_feature_flags(junit_pipeline_view: project) end context 'when pipeline does not have a test report' do - let(:pipeline) { create(:ci_pipeline, project: project) } - it 'renders an empty test report' do get_test_report_json @@ -763,7 +843,11 @@ describe Projects::PipelinesController do end context 'when pipeline has a test report' do - let(:pipeline) { create(:ci_pipeline, :with_test_reports, project: project) } + before do + create(:ci_build, name: 'rspec', pipeline: pipeline).tap do |build| + create(:ci_job_artifact, :junit, job: build) + end + end it 'renders the test report' do get_test_report_json @@ -773,25 +857,28 @@ describe Projects::PipelinesController do end end - context 'when pipeline has corrupt test reports' do - let(:pipeline) { create(:ci_pipeline, project: project) } - + context 'when pipeline has a corrupt test report artifact' do before do - job = create(:ci_build, pipeline: pipeline) - create(:ci_job_artifact, :junit_with_corrupted_data, job: job, project: project) - end + create(:ci_build, name: 'rspec', pipeline: pipeline).tap do |build| + create(:ci_job_artifact, :junit_with_corrupted_data, job: build) + end - it 'renders the test reports' do get_test_report_json + end + it 'renders the test reports' do expect(response).to have_gitlab_http_status(:ok) - expect(json_response['status']).to eq('error_parsing_report') + expect(json_response['test_suites'].count).to eq(1) + end + + it 'returns a suite_error on the suite with corrupted XML' do + expect(json_response['test_suites'].first['suite_error']).to eq('JUnit XML parsing failed: 1:1: FATAL: Document is empty') end end context 'when junit_pipeline_screenshots_view is enabled' do before do - stub_feature_flags(junit_pipeline_screenshots_view: { enabled: true, thing: project }) + stub_feature_flags(junit_pipeline_screenshots_view: project) end context 'when test_report contains attachment and scope is with_attachment as a URL param' do @@ -820,7 +907,7 @@ describe Projects::PipelinesController do context 'when junit_pipeline_screenshots_view is disabled' do before do - stub_feature_flags(junit_pipeline_screenshots_view: { enabled: false, thing: project }) + stub_feature_flags(junit_pipeline_screenshots_view: false) end context 'when test_report contains attachment and scope is with_attachment as a URL param' do diff --git a/spec/controllers/projects/prometheus/alerts_controller_spec.rb b/spec/controllers/projects/prometheus/alerts_controller_spec.rb index 451834e0962..e936cb5916e 100644 --- a/spec/controllers/projects/prometheus/alerts_controller_spec.rb +++ b/spec/controllers/projects/prometheus/alerts_controller_spec.rb @@ -352,7 +352,7 @@ describe Projects::Prometheus::AlertsController do get :metrics_dashboard, params: request_params(id: metric.id, environment_id: alert.environment.id), format: :json expect(response).to have_gitlab_http_status(:ok) - expect(json_response.keys).to contain_exactly('dashboard', 'status') + expect(json_response.keys).to contain_exactly('dashboard', 'status', 'metrics_data') end it 'is the correct embed' do diff --git a/spec/controllers/projects/refs_controller_spec.rb b/spec/controllers/projects/refs_controller_spec.rb index 646c7a7db7c..b043e7f2538 100644 --- a/spec/controllers/projects/refs_controller_spec.rb +++ b/spec/controllers/projects/refs_controller_spec.rb @@ -12,25 +12,27 @@ describe Projects::RefsController do end describe 'GET #logs_tree' do + let(:path) { 'foo/bar/baz.html' } + def default_get(format = :html) get :logs_tree, params: { namespace_id: project.namespace.to_param, project_id: project, id: 'master', - path: 'foo/bar/baz.html' + path: path }, format: format end - def xhr_get(format = :html) + def xhr_get(format = :html, params = {}) get :logs_tree, params: { namespace_id: project.namespace.to_param, project_id: project, id: 'master', - path: 'foo/bar/baz.html', + path: path, format: format - }, xhr: true + }.merge(params), xhr: true end it 'never throws MissingTemplate' do @@ -52,13 +54,27 @@ describe Projects::RefsController do expect(response).to be_successful end - it 'renders JSON' do - expect(::Gitlab::GitalyClient).to receive(:allow_ref_name_caching).and_call_original + context 'when json is requested' do + it 'renders JSON' do + expect(::Gitlab::GitalyClient).to receive(:allow_ref_name_caching).and_call_original - xhr_get(:json) + xhr_get(:json) - expect(response).to be_successful - expect(json_response).to be_kind_of(Array) + expect(response).to be_successful + expect(json_response).to be_kind_of(Array) + end + + it 'caches tree summary data', :use_clean_rails_memory_store_caching do + expect_next_instance_of(::Gitlab::TreeSummary) do |instance| + expect(instance).to receive_messages(summarize: ['logs'], next_offset: 50, more?: true) + end + + xhr_get(:json, offset: 25) + + cache_key = "projects/#{project.id}/logs/#{project.commit.id}/#{path}/25" + expect(Rails.cache.fetch(cache_key)).to eq(['logs', 50]) + expect(response.headers['More-Logs-Offset']).to eq(50) + end end end end diff --git a/spec/controllers/projects/registry/repositories_controller_spec.rb b/spec/controllers/projects/registry/repositories_controller_spec.rb index c641a45a216..badb84f9b50 100644 --- a/spec/controllers/projects/registry/repositories_controller_spec.rb +++ b/spec/controllers/projects/registry/repositories_controller_spec.rb @@ -3,8 +3,8 @@ require 'spec_helper' describe Projects::Registry::RepositoriesController do - let(:user) { create(:user) } - let(:project) { create(:project, :private) } + let_it_be(:user) { create(:user) } + let_it_be(:project) { create(:project, :private) } before do sign_in(user) @@ -16,6 +16,22 @@ describe Projects::Registry::RepositoriesController do project.add_developer(user) end + shared_examples 'with name parameter' do + let_it_be(:repo) { create(:container_repository, project: project, name: 'my_searched_image') } + let_it_be(:another_repo) { create(:container_repository, project: project, name: 'bar') } + + it 'returns the searched repo' do + go_to_index(format: :json, params: { name: 'my_searched_image' }) + + expect(response).to have_gitlab_http_status(:ok) + expect(json_response.length).to eq 1 + expect(json_response.first).to include( + 'id' => repo.id, + 'name' => repo.name + ) + end + end + shared_examples 'renders a list of repositories' do context 'when root container repository exists' do before do @@ -60,6 +76,8 @@ describe Projects::Registry::RepositoriesController do expect(response).to match_response_schema('registry/repositories') expect(response).to include_pagination_headers end + + it_behaves_like 'with name parameter' end context 'when there are no tags for this repository' do @@ -138,11 +156,11 @@ describe Projects::Registry::RepositoriesController do end end - def go_to_index(format: :html) - get :index, params: { + def go_to_index(format: :html, params: {} ) + get :index, params: params.merge({ namespace_id: project.namespace, project_id: project - }, + }), format: format end diff --git a/spec/controllers/projects/service_hook_logs_controller_spec.rb b/spec/controllers/projects/service_hook_logs_controller_spec.rb index ca57b0579a8..a5130cd6e32 100644 --- a/spec/controllers/projects/service_hook_logs_controller_spec.rb +++ b/spec/controllers/projects/service_hook_logs_controller_spec.rb @@ -24,7 +24,7 @@ describe Projects::ServiceHookLogsController do describe 'GET #show' do subject { get :show, params: log_params } - it do + specify do expect(response).to be_successful end end diff --git a/spec/controllers/projects/settings/access_tokens_controller_spec.rb b/spec/controllers/projects/settings/access_tokens_controller_spec.rb new file mode 100644 index 00000000000..884a5bc2836 --- /dev/null +++ b/spec/controllers/projects/settings/access_tokens_controller_spec.rb @@ -0,0 +1,190 @@ +# frozen_string_literal: true + +require('spec_helper') + +describe Projects::Settings::AccessTokensController do + let_it_be(:user) { create(:user) } + let_it_be(:project) { create(:project) } + + before_all do + project.add_maintainer(user) + end + + before do + sign_in(user) + end + + shared_examples 'feature unavailability' do + context 'when flag is disabled' do + before do + stub_feature_flags(resource_access_token: false) + end + + it { is_expected.to have_gitlab_http_status(:not_found) } + end + + context 'when environment is Gitlab.com' do + before do + allow(Gitlab).to receive(:com?).and_return(true) + end + + it { is_expected.to have_gitlab_http_status(:not_found) } + end + end + + describe '#index' do + subject { get :index, params: { namespace_id: project.namespace, project_id: project } } + + it_behaves_like 'feature unavailability' + + context 'when feature is available' do + let_it_be(:bot_user) { create(:user, :project_bot) } + let_it_be(:active_project_access_token) { create(:personal_access_token, user: bot_user) } + let_it_be(:inactive_project_access_token) { create(:personal_access_token, :revoked, user: bot_user) } + + before_all do + project.add_maintainer(bot_user) + end + + before do + enable_feature + end + + it 'retrieves active project access tokens' do + subject + + expect(assigns(:active_project_access_tokens)).to contain_exactly(active_project_access_token) + end + + it 'retrieves inactive project access tokens' do + subject + + expect(assigns(:inactive_project_access_tokens)).to contain_exactly(inactive_project_access_token) + end + + it 'lists all available scopes' do + subject + + expect(assigns(:scopes)).to eq(Gitlab::Auth.resource_bot_scopes) + end + + it 'retrieves newly created personal access token value' do + token_value = 'random-value' + allow(PersonalAccessToken).to receive(:redis_getdel).with("#{user.id}:#{project.id}").and_return(token_value) + + subject + + expect(assigns(:new_project_access_token)).to eq(token_value) + end + end + end + + describe '#create', :clean_gitlab_redis_shared_state do + subject { post :create, params: { namespace_id: project.namespace, project_id: project }.merge(project_access_token: access_token_params) } + + let_it_be(:access_token_params) { {} } + + it_behaves_like 'feature unavailability' + + context 'when feature is available' do + let_it_be(:access_token_params) { { name: 'Nerd bot', scopes: ["api"], expires_at: 1.month.since.to_date } } + + before do + enable_feature + end + + def created_token + PersonalAccessToken.order(:created_at).last + end + + it 'returns success message' do + subject + + expect(response.flash[:notice]).to match(/\AYour new project access token has been created./i) + end + + it 'creates project access token' do + subject + + expect(created_token.name).to eq(access_token_params[:name]) + expect(created_token.scopes).to eq(access_token_params[:scopes]) + expect(created_token.expires_at).to eq(access_token_params[:expires_at]) + end + + it 'creates project bot user' do + subject + + expect(created_token.user).to be_project_bot + end + + it 'stores newly created token redis store' do + expect(PersonalAccessToken).to receive(:redis_store!) + + subject + end + + it { expect { subject }.to change { User.count }.by(1) } + it { expect { subject }.to change { PersonalAccessToken.count }.by(1) } + + context 'when unsuccessful' do + before do + allow_next_instance_of(ResourceAccessTokens::CreateService) do |service| + allow(service).to receive(:execute).and_return ServiceResponse.error(message: 'Failed!') + end + end + + it { expect(subject).to render_template(:index) } + end + end + end + + describe '#revoke' do + subject { put :revoke, params: { namespace_id: project.namespace, project_id: project, id: project_access_token } } + + let_it_be(:bot_user) { create(:user, :project_bot) } + let_it_be(:project_access_token) { create(:personal_access_token, user: bot_user) } + + before_all do + project.add_maintainer(bot_user) + end + + it_behaves_like 'feature unavailability' + + context 'when feature is available' do + before do + enable_feature + end + + it 'revokes token access' do + subject + + expect(project_access_token.reload.revoked?).to be true + end + + it 'removed membership of bot user' do + subject + + expect(project.reload.bots).not_to include(bot_user) + end + + it 'blocks project bot user' do + subject + + expect(bot_user.reload.blocked?).to be true + end + + it 'converts issuables of the bot user to ghost user' do + issue = create(:issue, author: bot_user) + + subject + + expect(issue.reload.author.ghost?).to be true + end + end + end + + def enable_feature + allow(Gitlab).to receive(:com?).and_return(false) + stub_feature_flags(resource_access_token: true) + end +end diff --git a/spec/controllers/projects/settings/repository_controller_spec.rb b/spec/controllers/projects/settings/repository_controller_spec.rb index 847c80e8917..fb9cdd860dc 100644 --- a/spec/controllers/projects/settings/repository_controller_spec.rb +++ b/spec/controllers/projects/settings/repository_controller_spec.rb @@ -36,7 +36,7 @@ describe Projects::Settings::RepositoryController do describe 'POST create_deploy_token' do context 'when ajax_new_deploy_token feature flag is disabled for the project' do before do - stub_feature_flags(ajax_new_deploy_token: { enabled: false, thing: project }) + stub_feature_flags(ajax_new_deploy_token: false) end it_behaves_like 'a created deploy token' do @@ -73,7 +73,7 @@ describe Projects::Settings::RepositoryController do 'id' => be_a(Integer), 'name' => deploy_token_params[:name], 'username' => deploy_token_params[:username], - 'expires_at' => Time.parse(deploy_token_params[:expires_at]), + 'expires_at' => Time.zone.parse(deploy_token_params[:expires_at]), 'token' => be_a(String), 'scopes' => deploy_token_params.inject([]) do |scopes, kv| key, value = kv diff --git a/spec/controllers/projects/snippets_controller_spec.rb b/spec/controllers/projects/snippets_controller_spec.rb index 284789305e2..b5f4929d8ce 100644 --- a/spec/controllers/projects/snippets_controller_spec.rb +++ b/spec/controllers/projects/snippets_controller_spec.rb @@ -127,7 +127,7 @@ describe Projects::SnippetsController do .to log_spam(title: 'Title', user_id: user.id, noteable_type: 'ProjectSnippet') end - it 'renders :new with recaptcha disabled' do + it 'renders :new with reCAPTCHA disabled' do stub_application_setting(recaptcha_enabled: false) create_snippet(project, visibility_level: Snippet::PUBLIC) @@ -135,18 +135,18 @@ describe Projects::SnippetsController do expect(response).to render_template(:new) end - context 'recaptcha enabled' do + context 'reCAPTCHA enabled' do before do stub_application_setting(recaptcha_enabled: true) end - it 'renders :verify with recaptcha enabled' do + it 'renders :verify with reCAPTCHA enabled' do create_snippet(project, visibility_level: Snippet::PUBLIC) expect(response).to render_template(:verify) end - it 'renders snippet page when recaptcha verified' do + it 'renders snippet page when reCAPTCHA verified' do spammy_title = 'Whatever' spam_logs = create_list(:spam_log, 2, user: user, title: spammy_title) @@ -223,7 +223,7 @@ describe Projects::SnippetsController do .to log_spam(title: 'Foo', user_id: user.id, noteable_type: 'ProjectSnippet') end - it 'renders :edit with recaptcha disabled' do + it 'renders :edit with reCAPTCHA disabled' do stub_application_setting(recaptcha_enabled: false) update_snippet(title: 'Foo') @@ -231,18 +231,18 @@ describe Projects::SnippetsController do expect(response).to render_template(:edit) end - context 'recaptcha enabled' do + context 'reCAPTCHA enabled' do before do stub_application_setting(recaptcha_enabled: true) end - it 'renders :verify with recaptcha enabled' do + it 'renders :verify with reCAPTCHA enabled' do update_snippet(title: 'Foo') expect(response).to render_template(:verify) end - it 'renders snippet page when recaptcha verified' do + it 'renders snippet page when reCAPTCHA verified' do spammy_title = 'Whatever' spam_logs = create_list(:spam_log, 2, user: user, title: spammy_title) @@ -268,7 +268,7 @@ describe Projects::SnippetsController do .to log_spam(title: 'Foo', user_id: user.id, noteable_type: 'ProjectSnippet') end - it 'renders :edit with recaptcha disabled' do + it 'renders :edit with reCAPTCHA disabled' do stub_application_setting(recaptcha_enabled: false) update_snippet(title: 'Foo', visibility_level: Snippet::PUBLIC) @@ -276,18 +276,18 @@ describe Projects::SnippetsController do expect(response).to render_template(:edit) end - context 'recaptcha enabled' do + context 'reCAPTCHA enabled' do before do stub_application_setting(recaptcha_enabled: true) end - it 'renders :verify with recaptcha enabled' do + it 'renders :verify' do update_snippet(title: 'Foo', visibility_level: Snippet::PUBLIC) expect(response).to render_template(:verify) end - it 'renders snippet page when recaptcha verified' do + it 'renders snippet page' do spammy_title = 'Whatever' spam_logs = create_list(:spam_log, 2, user: user, title: spammy_title) @@ -346,20 +346,6 @@ describe Projects::SnippetsController do expect(assigns(:blob)).to eq(project_snippet.blobs.first) end - - context 'when feature flag version_snippets is disabled' do - before do - stub_feature_flags(version_snippets: false) - end - - it 'returns the snippet database content' do - subject - - blob = assigns(:blob) - - expect(blob.data).to eq(project_snippet.content) - end - end end %w[show raw].each do |action| diff --git a/spec/controllers/projects/static_site_editor_controller_spec.rb b/spec/controllers/projects/static_site_editor_controller_spec.rb index f7c8848b8cf..7b470254de1 100644 --- a/spec/controllers/projects/static_site_editor_controller_spec.rb +++ b/spec/controllers/projects/static_site_editor_controller_spec.rb @@ -3,7 +3,8 @@ require 'spec_helper' describe Projects::StaticSiteEditorController do - let(:project) { create(:project, :public, :repository) } + let_it_be(:project) { create(:project, :public, :repository) } + let_it_be(:user) { create(:user) } describe 'GET show' do let(:default_params) do @@ -27,8 +28,6 @@ describe Projects::StaticSiteEditorController do end context 'as guest' do - let(:user) { create(:user) } - before do project.add_guest(user) sign_in(user) @@ -42,10 +41,11 @@ describe Projects::StaticSiteEditorController do %w[developer maintainer].each do |role| context "as #{role}" do - let(:user) { create(:user) } + before_all do + project.add_role(user, role) + end before do - project.add_role(user, role) sign_in(user) get :show, params: default_params end @@ -54,8 +54,10 @@ describe Projects::StaticSiteEditorController do expect(response).to render_template(:show) end - it 'assigns a config variable' do + it 'assigns a required variables' do expect(assigns(:config)).to be_a(Gitlab::StaticSiteEditor::Config) + expect(assigns(:ref)).to eq('master') + expect(assigns(:path)).to eq('README.md') end context 'when combination of ref and file path is incorrect' do diff --git a/spec/controllers/projects/usage_ping_controller_spec.rb b/spec/controllers/projects/usage_ping_controller_spec.rb index 284db93d7a8..a68967c228f 100644 --- a/spec/controllers/projects/usage_ping_controller_spec.rb +++ b/spec/controllers/projects/usage_ping_controller_spec.rb @@ -6,45 +6,52 @@ describe Projects::UsagePingController do let_it_be(:project) { create(:project) } let_it_be(:user) { create(:user) } - describe 'POST #web_ide_clientside_preview' do - subject { post :web_ide_clientside_preview, params: { namespace_id: project.namespace, project_id: project } } + before do + sign_in(user) if user + end - before do - sign_in(user) if user - end + shared_examples 'counter is not increased' do + context 'when the user is not authenticated' do + let(:user) { nil } - context 'when web ide clientside preview is enabled' do - before do - stub_application_setting(web_ide_clientside_preview_enabled: true) - end + it 'returns 302' do + subject - context 'when the user is not authenticated' do - let(:user) { nil } + expect(response).to have_gitlab_http_status(:found) + end + end - it 'returns 302' do - subject + context 'when the user does not have access to the project' do + it 'returns 404' do + subject - expect(response).to have_gitlab_http_status(:found) - end + expect(response).to have_gitlab_http_status(:not_found) end + end + end - context 'when the user does not have access to the project' do - it 'returns 404' do - subject + shared_examples 'counter is increased' do |counter| + context 'when the authenticated user has access to the project' do + let(:user) { project.owner } - expect(response).to have_gitlab_http_status(:not_found) - end + it 'increments the usage counter' do + expect do + subject + end.to change { Gitlab::UsageDataCounters::WebIdeCounter.total_count(counter) }.by(1) end + end + end - context 'when the user has access to the project' do - let(:user) { project.owner } + describe 'POST #web_ide_clientside_preview' do + subject { post :web_ide_clientside_preview, params: { namespace_id: project.namespace, project_id: project } } - it 'increments the counter' do - expect do - subject - end.to change { Gitlab::UsageDataCounters::WebIdeCounter.total_previews_count }.by(1) - end + context 'when web ide clientside preview is enabled' do + before do + stub_application_setting(web_ide_clientside_preview_enabled: true) end + + it_behaves_like 'counter is not increased' + it_behaves_like 'counter is increased', 'WEB_IDE_PREVIEWS_COUNT' end context 'when web ide clientside preview is not enabled' do @@ -61,4 +68,11 @@ describe Projects::UsagePingController do end end end + + describe 'POST #web_ide_pipelines_count' do + subject { post :web_ide_pipelines_count, params: { namespace_id: project.namespace, project_id: project } } + + it_behaves_like 'counter is not increased' + it_behaves_like 'counter is increased', 'WEB_IDE_PIPELINES_COUNT' + end end diff --git a/spec/controllers/projects/wikis_controller_spec.rb b/spec/controllers/projects/wikis_controller_spec.rb index 99d14298cd1..b4bbf76ce18 100644 --- a/spec/controllers/projects/wikis_controller_spec.rb +++ b/spec/controllers/projects/wikis_controller_spec.rb @@ -98,13 +98,12 @@ describe Projects::WikisController do let(:id) { wiki_title } it 'limits the retrieved pages for the sidebar' do - expect(controller).to receive(:load_wiki).and_return(project_wiki) - expect(project_wiki).to receive(:list_pages).with(limit: 15).and_call_original - subject expect(response).to have_gitlab_http_status(:ok) expect(assigns(:page).title).to eq(wiki_title) + expect(assigns(:sidebar_wiki_entries)).to contain_exactly(an_instance_of(WikiPage)) + expect(assigns(:sidebar_limited)).to be(false) end context 'when page content encoding is invalid' do @@ -200,7 +199,20 @@ describe Projects::WikisController do subject - expect(response).to redirect_to(project_wiki_path(project, project_wiki.list_pages.first)) + expect(response).to redirect_to_wiki(project, project_wiki.list_pages.first) + end + end + + context 'when the page has nil content' do + let(:page) { create(:wiki_page) } + + it 'redirects to show' do + allow(page).to receive(:content).and_return(nil) + allow(controller).to receive(:find_page).and_return(page) + + subject + + expect(response).to redirect_to_wiki(project, page) end end @@ -235,7 +247,7 @@ describe Projects::WikisController do allow(controller).to receive(:valid_encoding?).and_return(false) subject - expect(response).to redirect_to(project_wiki_path(project, project_wiki.list_pages.first)) + expect(response).to redirect_to_wiki(project, project_wiki.list_pages.first) end end @@ -265,4 +277,8 @@ describe Projects::WikisController do page = wiki.page(title: title, dir: dir) project_wiki.delete_page(page, "test commit") end + + def redirect_to_wiki(project, page) + redirect_to(controller.project_wiki_path(project, page)) + end end |