Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2020-05-20 17:34:42 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2020-05-20 17:34:42 +0300
commit9f46488805e86b1bc341ea1620b866016c2ce5ed (patch)
treef9748c7e287041e37d6da49e0a29c9511dc34768 /spec/controllers/projects
parentdfc92d081ea0332d69c8aca2f0e745cb48ae5e6d (diff)
Add latest changes from gitlab-org/gitlab@13-0-stable-ee
Diffstat (limited to 'spec/controllers/projects')
-rw-r--r--spec/controllers/projects/alert_management_controller_spec.rb59
-rw-r--r--spec/controllers/projects/artifacts_controller_spec.rb42
-rw-r--r--spec/controllers/projects/branches_controller_spec.rb56
-rw-r--r--spec/controllers/projects/ci/daily_build_group_report_results_controller_spec.rb80
-rw-r--r--spec/controllers/projects/clusters_controller_spec.rb27
-rw-r--r--spec/controllers/projects/cycle_analytics/events_controller_spec.rb6
-rw-r--r--spec/controllers/projects/design_management/designs/raw_images_controller_spec.rb153
-rw-r--r--spec/controllers/projects/design_management/designs/resized_image_controller_spec.rb148
-rw-r--r--spec/controllers/projects/environments/prometheus_api_controller_spec.rb4
-rw-r--r--spec/controllers/projects/environments_controller_spec.rb36
-rw-r--r--spec/controllers/projects/grafana_api_controller_spec.rb3
-rw-r--r--spec/controllers/projects/graphs_controller_spec.rb20
-rw-r--r--spec/controllers/projects/import/jira_controller_spec.rb15
-rw-r--r--spec/controllers/projects/issues_controller_spec.rb281
-rw-r--r--spec/controllers/projects/logs_controller_spec.rb111
-rw-r--r--spec/controllers/projects/merge_requests_controller_spec.rb307
-rw-r--r--spec/controllers/projects/mirrors_controller_spec.rb2
-rw-r--r--spec/controllers/projects/pipelines_controller_spec.rb119
-rw-r--r--spec/controllers/projects/prometheus/alerts_controller_spec.rb2
-rw-r--r--spec/controllers/projects/refs_controller_spec.rb34
-rw-r--r--spec/controllers/projects/registry/repositories_controller_spec.rb28
-rw-r--r--spec/controllers/projects/service_hook_logs_controller_spec.rb2
-rw-r--r--spec/controllers/projects/settings/access_tokens_controller_spec.rb190
-rw-r--r--spec/controllers/projects/settings/repository_controller_spec.rb4
-rw-r--r--spec/controllers/projects/snippets_controller_spec.rb38
-rw-r--r--spec/controllers/projects/static_site_editor_controller_spec.rb14
-rw-r--r--spec/controllers/projects/usage_ping_controller_spec.rb68
-rw-r--r--spec/controllers/projects/wikis_controller_spec.rb26
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