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:
Diffstat (limited to 'spec/requests')
-rw-r--r--spec/requests/api/admin/plan_limits_spec.rb12
-rw-r--r--spec/requests/api/api_spec.rb2
-rw-r--r--spec/requests/api/award_emoji_spec.rb1
-rw-r--r--spec/requests/api/branches_spec.rb14
-rw-r--r--spec/requests/api/bulk_imports_spec.rb67
-rw-r--r--spec/requests/api/ci/pipelines_spec.rb1
-rw-r--r--spec/requests/api/ci/runner/jobs_request_post_spec.rb23
-rw-r--r--spec/requests/api/ci/runner/jobs_trace_spec.rb16
-rw-r--r--spec/requests/api/ci/runner/runners_post_spec.rb56
-rw-r--r--spec/requests/api/composer_packages_spec.rb1
-rw-r--r--spec/requests/api/debian_group_packages_spec.rb10
-rw-r--r--spec/requests/api/debian_project_packages_spec.rb10
-rw-r--r--spec/requests/api/deploy_tokens_spec.rb1
-rw-r--r--spec/requests/api/deployments_spec.rb1
-rw-r--r--spec/requests/api/error_tracking_collector_spec.rb77
-rw-r--r--spec/requests/api/error_tracking_spec.rb1
-rw-r--r--spec/requests/api/feature_flags_spec.rb1
-rw-r--r--spec/requests/api/freeze_periods_spec.rb1
-rw-r--r--spec/requests/api/geo_spec.rb30
-rw-r--r--spec/requests/api/graphql/boards/board_lists_query_spec.rb1
-rw-r--r--spec/requests/api/graphql/ci/jobs_spec.rb6
-rw-r--r--spec/requests/api/graphql/ci/pipelines_spec.rb1
-rw-r--r--spec/requests/api/graphql/ci/runner_spec.rb111
-rw-r--r--spec/requests/api/graphql/current_user_todos_spec.rb1
-rw-r--r--spec/requests/api/graphql/issue_status_counts_spec.rb1
-rw-r--r--spec/requests/api/graphql/metrics/dashboard_query_spec.rb1
-rw-r--r--spec/requests/api/graphql/mutations/admin/sidekiq_queues/delete_jobs_spec.rb1
-rw-r--r--spec/requests/api/graphql/mutations/alert_management/alerts/set_assignees_spec.rb1
-rw-r--r--spec/requests/api/graphql/mutations/alert_management/alerts/todo/create_spec.rb1
-rw-r--r--spec/requests/api/graphql/mutations/alert_management/alerts/update_alert_status_spec.rb1
-rw-r--r--spec/requests/api/graphql/mutations/alert_management/http_integration/create_spec.rb1
-rw-r--r--spec/requests/api/graphql/mutations/alert_management/prometheus_integration/create_spec.rb3
-rw-r--r--spec/requests/api/graphql/mutations/alert_management/prometheus_integration/reset_token_spec.rb2
-rw-r--r--spec/requests/api/graphql/mutations/alert_management/prometheus_integration/update_spec.rb2
-rw-r--r--spec/requests/api/graphql/mutations/award_emojis/add_spec.rb1
-rw-r--r--spec/requests/api/graphql/mutations/award_emojis/toggle_spec.rb1
-rw-r--r--spec/requests/api/graphql/mutations/boards/create_spec.rb1
-rw-r--r--spec/requests/api/graphql/mutations/branches/create_spec.rb4
-rw-r--r--spec/requests/api/graphql/mutations/ci/ci_cd_settings_update_spec.rb5
-rw-r--r--spec/requests/api/graphql/mutations/ci/job_token_scope/add_project_spec.rb78
-rw-r--r--spec/requests/api/graphql/mutations/ci/job_token_scope/remove_project_spec.rb84
-rw-r--r--spec/requests/api/graphql/mutations/commits/create_spec.rb1
-rw-r--r--spec/requests/api/graphql/mutations/container_expiration_policy/update_spec.rb1
-rw-r--r--spec/requests/api/graphql/mutations/discussions/toggle_resolve_spec.rb1
-rw-r--r--spec/requests/api/graphql/mutations/environments/canary_ingress/update_spec.rb1
-rw-r--r--spec/requests/api/graphql/mutations/issues/set_locked_spec.rb1
-rw-r--r--spec/requests/api/graphql/mutations/issues/set_severity_spec.rb1
-rw-r--r--spec/requests/api/graphql/mutations/issues/update_spec.rb1
-rw-r--r--spec/requests/api/graphql/mutations/jira_import/import_users_spec.rb1
-rw-r--r--spec/requests/api/graphql/mutations/jira_import/start_spec.rb9
-rw-r--r--spec/requests/api/graphql/mutations/labels/create_spec.rb2
-rw-r--r--spec/requests/api/graphql/mutations/merge_requests/accept_spec.rb1
-rw-r--r--spec/requests/api/graphql/mutations/merge_requests/create_spec.rb1
-rw-r--r--spec/requests/api/graphql/mutations/merge_requests/set_assignees_spec.rb10
-rw-r--r--spec/requests/api/graphql/mutations/metrics/dashboard/annotations/create_spec.rb1
-rw-r--r--spec/requests/api/graphql/mutations/namespace/package_settings/update_spec.rb1
-rw-r--r--spec/requests/api/graphql/mutations/notes/create/diff_note_spec.rb1
-rw-r--r--spec/requests/api/graphql/mutations/notes/create/image_diff_note_spec.rb1
-rw-r--r--spec/requests/api/graphql/mutations/notes/create/note_spec.rb1
-rw-r--r--spec/requests/api/graphql/mutations/notes/reposition_image_diff_note_spec.rb1
-rw-r--r--spec/requests/api/graphql/mutations/notes/update/image_diff_note_spec.rb1
-rw-r--r--spec/requests/api/graphql/mutations/packages/destroy_spec.rb93
-rw-r--r--spec/requests/api/graphql/mutations/releases/delete_spec.rb8
-rw-r--r--spec/requests/api/graphql/mutations/snippets/create_spec.rb33
-rw-r--r--spec/requests/api/graphql/mutations/snippets/mark_as_spam_spec.rb1
-rw-r--r--spec/requests/api/graphql/mutations/snippets/update_spec.rb29
-rw-r--r--spec/requests/api/graphql/mutations/user_callouts/create_spec.rb1
-rw-r--r--spec/requests/api/graphql/namespace/package_settings_spec.rb1
-rw-r--r--spec/requests/api/graphql/project/alert_management/alert/issue_spec.rb1
-rw-r--r--spec/requests/api/graphql/project/alert_management/alert_status_counts_spec.rb1
-rw-r--r--spec/requests/api/graphql/project/alert_management/integrations_spec.rb24
-rw-r--r--spec/requests/api/graphql/project/base_service_spec.rb4
-rw-r--r--spec/requests/api/graphql/project/error_tracking/sentry_detailed_error_request_spec.rb1
-rw-r--r--spec/requests/api/graphql/project/error_tracking/sentry_errors_request_spec.rb2
-rw-r--r--spec/requests/api/graphql/project/issue/designs/designs_spec.rb3
-rw-r--r--spec/requests/api/graphql/project/jira_service_spec.rb2
-rw-r--r--spec/requests/api/graphql/project/pipeline_spec.rb81
-rw-r--r--spec/requests/api/graphql/project/project_pipeline_statistics_spec.rb1
-rw-r--r--spec/requests/api/graphql/project_query_spec.rb1
-rw-r--r--spec/requests/api/graphql/query_spec.rb2
-rw-r--r--spec/requests/api/graphql/user/starred_projects_query_spec.rb1
-rw-r--r--spec/requests/api/graphql/user_query_spec.rb2
-rw-r--r--spec/requests/api/graphql_spec.rb2
-rw-r--r--spec/requests/api/group_avatar_spec.rb36
-rw-r--r--spec/requests/api/group_import_spec.rb1
-rw-r--r--spec/requests/api/group_labels_spec.rb26
-rw-r--r--spec/requests/api/group_milestones_spec.rb1
-rw-r--r--spec/requests/api/group_packages_spec.rb2
-rw-r--r--spec/requests/api/groups_spec.rb62
-rw-r--r--spec/requests/api/helm_packages_spec.rb176
-rw-r--r--spec/requests/api/helpers_spec.rb1
-rw-r--r--spec/requests/api/import_bitbucket_server_spec.rb5
-rw-r--r--spec/requests/api/internal/base_spec.rb129
-rw-r--r--spec/requests/api/internal/kubernetes_spec.rb60
-rw-r--r--spec/requests/api/labels_spec.rb30
-rw-r--r--spec/requests/api/lint_spec.rb2
-rw-r--r--spec/requests/api/markdown_spec.rb1
-rw-r--r--spec/requests/api/merge_requests_spec.rb18
-rw-r--r--spec/requests/api/metrics/dashboard/annotations_spec.rb1
-rw-r--r--spec/requests/api/metrics/user_starred_dashboards_spec.rb1
-rw-r--r--spec/requests/api/nuget_project_packages_spec.rb127
-rw-r--r--spec/requests/api/project_attributes.yml1
-rw-r--r--spec/requests/api/project_clusters_spec.rb1
-rw-r--r--spec/requests/api/project_container_repositories_spec.rb1
-rw-r--r--spec/requests/api/project_milestones_spec.rb1
-rw-r--r--spec/requests/api/project_snippets_spec.rb2
-rw-r--r--spec/requests/api/projects_spec.rb103
-rw-r--r--spec/requests/api/pypi_packages_spec.rb2
-rw-r--r--spec/requests/api/release/links_spec.rb68
-rw-r--r--spec/requests/api/releases_spec.rb82
-rw-r--r--spec/requests/api/repositories_spec.rb11
-rw-r--r--spec/requests/api/resource_access_tokens_spec.rb20
-rw-r--r--spec/requests/api/rubygem_packages_spec.rb2
-rw-r--r--spec/requests/api/services_spec.rb186
-rw-r--r--spec/requests/api/settings_spec.rb13
-rw-r--r--spec/requests/api/snippets_spec.rb2
-rw-r--r--spec/requests/api/system_hooks_spec.rb5
-rw-r--r--spec/requests/api/unleash_spec.rb1
-rw-r--r--spec/requests/api/users_spec.rb2
-rw-r--r--spec/requests/api/wikis_spec.rb3
-rw-r--r--spec/requests/git_http_spec.rb24
-rw-r--r--spec/requests/import/gitlab_groups_controller_spec.rb1
-rw-r--r--spec/requests/invite_registration_spec.rb68
-rw-r--r--spec/requests/jwt_controller_spec.rb1
-rw-r--r--spec/requests/lfs_http_spec.rb16
-rw-r--r--spec/requests/product_analytics/collector_app_spec.rb1
-rw-r--r--spec/requests/projects/merge_requests/diffs_spec.rb126
-rw-r--r--spec/requests/projects/merge_requests_discussions_spec.rb139
-rw-r--r--spec/requests/rack_attack_global_spec.rb1
129 files changed, 1886 insertions, 641 deletions
diff --git a/spec/requests/api/admin/plan_limits_spec.rb b/spec/requests/api/admin/plan_limits_spec.rb
index 6bc133f67c0..f497227789a 100644
--- a/spec/requests/api/admin/plan_limits_spec.rb
+++ b/spec/requests/api/admin/plan_limits_spec.rb
@@ -29,6 +29,7 @@ RSpec.describe API::Admin::PlanLimits, 'PlanLimits' do
expect(json_response['npm_max_file_size']).to eq(Plan.default.actual_limits.npm_max_file_size)
expect(json_response['nuget_max_file_size']).to eq(Plan.default.actual_limits.nuget_max_file_size)
expect(json_response['pypi_max_file_size']).to eq(Plan.default.actual_limits.pypi_max_file_size)
+ expect(json_response['terraform_module_max_file_size']).to eq(Plan.default.actual_limits.terraform_module_max_file_size)
end
end
@@ -48,6 +49,7 @@ RSpec.describe API::Admin::PlanLimits, 'PlanLimits' do
expect(json_response['npm_max_file_size']).to eq(Plan.default.actual_limits.npm_max_file_size)
expect(json_response['nuget_max_file_size']).to eq(Plan.default.actual_limits.nuget_max_file_size)
expect(json_response['pypi_max_file_size']).to eq(Plan.default.actual_limits.pypi_max_file_size)
+ expect(json_response['terraform_module_max_file_size']).to eq(Plan.default.actual_limits.terraform_module_max_file_size)
end
end
@@ -85,7 +87,8 @@ RSpec.describe API::Admin::PlanLimits, 'PlanLimits' do
'maven_max_file_size': 30,
'npm_max_file_size': 40,
'nuget_max_file_size': 50,
- 'pypi_max_file_size': 60
+ 'pypi_max_file_size': 60,
+ 'terraform_module_max_file_size': 70
}
expect(response).to have_gitlab_http_status(:ok)
@@ -96,6 +99,7 @@ RSpec.describe API::Admin::PlanLimits, 'PlanLimits' do
expect(json_response['npm_max_file_size']).to eq(40)
expect(json_response['nuget_max_file_size']).to eq(50)
expect(json_response['pypi_max_file_size']).to eq(60)
+ expect(json_response['terraform_module_max_file_size']).to eq(70)
end
it 'updates single plan limits' do
@@ -128,7 +132,8 @@ RSpec.describe API::Admin::PlanLimits, 'PlanLimits' do
'maven_max_file_size': 'c',
'npm_max_file_size': 'd',
'nuget_max_file_size': 'e',
- 'pypi_max_file_size': 'f'
+ 'pypi_max_file_size': 'f',
+ 'terraform_module_max_file_size': 'g'
}
expect(response).to have_gitlab_http_status(:bad_request)
@@ -139,7 +144,8 @@ RSpec.describe API::Admin::PlanLimits, 'PlanLimits' do
'generic_packages_max_file_size is invalid',
'npm_max_file_size is invalid',
'nuget_max_file_size is invalid',
- 'pypi_max_file_size is invalid'
+ 'pypi_max_file_size is invalid',
+ 'terraform_module_max_file_size is invalid'
)
end
end
diff --git a/spec/requests/api/api_spec.rb b/spec/requests/api/api_spec.rb
index 46430e55ff2..81620fce448 100644
--- a/spec/requests/api/api_spec.rb
+++ b/spec/requests/api/api_spec.rb
@@ -81,6 +81,7 @@ RSpec.describe API::API do
let_it_be(:maven_metadatum) { package.maven_metadatum }
let_it_be(:package_file) { package.package_files.first }
let_it_be(:deploy_token) { create(:deploy_token) }
+
let(:headers_with_deploy_token) do
{
Gitlab::Auth::AuthFinders::DEPLOY_TOKEN_HEADER => deploy_token.token
@@ -138,6 +139,7 @@ RSpec.describe API::API do
describe 'Marginalia comments' do
context 'GET /user/:id' do
let_it_be(:user) { create(:user) }
+
let(:component_map) do
{
"application" => "test",
diff --git a/spec/requests/api/award_emoji_spec.rb b/spec/requests/api/award_emoji_spec.rb
index 1c825949ae8..07a9f7dfd74 100644
--- a/spec/requests/api/award_emoji_spec.rb
+++ b/spec/requests/api/award_emoji_spec.rb
@@ -8,6 +8,7 @@ RSpec.describe API::AwardEmoji do
let_it_be(:issue) { create(:issue, project: project) }
let_it_be(:award_emoji) { create(:award_emoji, awardable: issue, user: user) }
let_it_be(:note) { create(:note, project: project, noteable: issue) }
+
let!(:merge_request) { create(:merge_request, source_project: project, target_project: project) }
let!(:downvote) { create(:award_emoji, :downvote, awardable: merge_request, user: user) }
diff --git a/spec/requests/api/branches_spec.rb b/spec/requests/api/branches_spec.rb
index 36fbe86ac76..ad517a05533 100644
--- a/spec/requests/api/branches_spec.rb
+++ b/spec/requests/api/branches_spec.rb
@@ -4,6 +4,7 @@ require 'spec_helper'
RSpec.describe API::Branches do
let_it_be(:user) { create(:user) }
+
let(:project) { create(:project, :repository, creator: user, path: 'my.project') }
let(:guest) { create(:user).tap { |u| project.add_guest(u) } }
let(:branch_name) { 'feature' }
@@ -20,7 +21,7 @@ RSpec.describe API::Branches do
stub_feature_flags(branch_list_keyset_pagination: false)
end
- describe "GET /projects/:id/repository/branches", :use_clean_rails_redis_caching do
+ describe "GET /projects/:id/repository/branches", :use_clean_rails_redis_caching, :clean_gitlab_redis_shared_state do
let(:route) { "/projects/#{project_id}/repository/branches" }
shared_examples_for 'repository branches' do
@@ -74,6 +75,14 @@ RSpec.describe API::Branches do
check_merge_status(json_response)
end
+
+ it 'recovers pagination headers from cache between consecutive requests' do
+ 2.times do
+ get api(route, current_user), params: base_params
+
+ expect(response.headers).to include('X-Page')
+ end
+ end
end
context 'with gitaly pagination params' do
@@ -718,10 +727,11 @@ RSpec.describe API::Branches do
end
it 'returns 400 if ref name is invalid' do
+ error_message = 'Failed to create branch \'new_design3\': invalid reference name \'foo\''
post api(route, user), params: { branch: 'new_design3', ref: 'foo' }
expect(response).to have_gitlab_http_status(:bad_request)
- expect(json_response['message']).to eq('Invalid reference name: foo')
+ expect(json_response['message']).to eq(error_message)
end
end
diff --git a/spec/requests/api/bulk_imports_spec.rb b/spec/requests/api/bulk_imports_spec.rb
new file mode 100644
index 00000000000..f0edfa6f227
--- /dev/null
+++ b/spec/requests/api/bulk_imports_spec.rb
@@ -0,0 +1,67 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe API::BulkImports do
+ let_it_be(:user) { create(:user) }
+ let_it_be(:import_1) { create(:bulk_import, user: user) }
+ let_it_be(:import_2) { create(:bulk_import, user: user) }
+ let_it_be(:entity_1) { create(:bulk_import_entity, bulk_import: import_1) }
+ let_it_be(:entity_2) { create(:bulk_import_entity, bulk_import: import_1) }
+ let_it_be(:entity_3) { create(:bulk_import_entity, bulk_import: import_2) }
+ let_it_be(:failure_3) { create(:bulk_import_failure, entity: entity_3) }
+
+ describe 'GET /bulk_imports' do
+ it 'returns a list of bulk imports authored by the user' do
+ get api('/bulk_imports', user)
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(json_response.pluck('id')).to contain_exactly(import_1.id, import_2.id)
+ end
+ end
+
+ describe 'GET /bulk_imports/entities' do
+ it 'returns a list of all import entities authored by the user' do
+ get api('/bulk_imports/entities', user)
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(json_response.pluck('id')).to contain_exactly(entity_1.id, entity_2.id, entity_3.id)
+ end
+ end
+
+ describe 'GET /bulk_imports/:id' do
+ it 'returns specified bulk import' do
+ get api("/bulk_imports/#{import_1.id}", user)
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(json_response['id']).to eq(import_1.id)
+ end
+ end
+
+ describe 'GET /bulk_imports/:id/entities' do
+ it 'returns specified bulk import entities with failures' do
+ get api("/bulk_imports/#{import_2.id}/entities", user)
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(json_response.pluck('id')).to contain_exactly(entity_3.id)
+ expect(json_response.first['failures'].first['exception_class']).to eq(failure_3.exception_class)
+ end
+ end
+
+ describe 'GET /bulk_imports/:id/entities/:entity_id' do
+ it 'returns specified bulk import entity' do
+ get api("/bulk_imports/#{import_1.id}/entities/#{entity_2.id}", user)
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(json_response['id']).to eq(entity_2.id)
+ end
+ end
+
+ context 'when user is unauthenticated' do
+ it 'returns 401' do
+ get api('/bulk_imports', nil)
+
+ expect(response).to have_gitlab_http_status(:unauthorized)
+ end
+ end
+end
diff --git a/spec/requests/api/ci/pipelines_spec.rb b/spec/requests/api/ci/pipelines_spec.rb
index 092cd00630e..eb6c0861844 100644
--- a/spec/requests/api/ci/pipelines_spec.rb
+++ b/spec/requests/api/ci/pipelines_spec.rb
@@ -491,6 +491,7 @@ RSpec.describe API::Ci::Pipelines do
describe 'GET /projects/:id/pipelines/:pipeline_id/bridges' do
let_it_be(:bridge) { create(:ci_bridge, pipeline: pipeline) }
+
let(:downstream_pipeline) { create(:ci_pipeline) }
let!(:pipeline_source) do
diff --git a/spec/requests/api/ci/runner/jobs_request_post_spec.rb b/spec/requests/api/ci/runner/jobs_request_post_spec.rb
index 8896bd44077..00c3a0a31af 100644
--- a/spec/requests/api/ci/runner/jobs_request_post_spec.rb
+++ b/spec/requests/api/ci/runner/jobs_request_post_spec.rb
@@ -297,7 +297,13 @@ RSpec.describe API::Ci::Runner, :clean_gitlab_redis_shared_state do
end
context 'when job filtered by job_age' do
- let!(:job) { create(:ci_build, :pending, :queued, :tag, pipeline: pipeline, name: 'spinach', stage: 'test', stage_idx: 0, queued_at: 60.seconds.ago) }
+ let!(:job) do
+ create(:ci_build, :pending, :queued, :tag, pipeline: pipeline, name: 'spinach', stage: 'test', stage_idx: 0, queued_at: 60.seconds.ago)
+ end
+
+ before do
+ job.queuing_entry&.update!(created_at: 60.seconds.ago)
+ end
context 'job is queued less than job_age parameter' do
let(:job_age) { 120 }
@@ -797,29 +803,16 @@ RSpec.describe API::Ci::Runner, :clean_gitlab_redis_shared_state do
end
context 'when a runner supports this feature' do
- it 'exposes excluded paths when the feature is enabled' do
- stub_feature_flags(ci_artifacts_exclude: true)
-
+ it 'exposes excluded paths' do
request_job info: { features: { artifacts_exclude: true } }
expect(response).to have_gitlab_http_status(:created)
expect(json_response.dig('artifacts').first).to include('exclude' => ['cde'])
end
-
- it 'does not expose excluded paths when the feature is disabled' do
- stub_feature_flags(ci_artifacts_exclude: false)
-
- request_job info: { features: { artifacts_exclude: true } }
-
- expect(response).to have_gitlab_http_status(:created)
- expect(json_response.dig('artifacts').first).not_to have_key('exclude')
- end
end
context 'when a runner does not support this feature' do
it 'does not expose the build at all' do
- stub_feature_flags(ci_artifacts_exclude: true)
-
request_job
expect(response).to have_gitlab_http_status(:no_content)
diff --git a/spec/requests/api/ci/runner/jobs_trace_spec.rb b/spec/requests/api/ci/runner/jobs_trace_spec.rb
index e077a174b08..e20c7e36096 100644
--- a/spec/requests/api/ci/runner/jobs_trace_spec.rb
+++ b/spec/requests/api/ci/runner/jobs_trace_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe API::Ci::Runner, :clean_gitlab_redis_shared_state do
+RSpec.describe API::Ci::Runner, :clean_gitlab_redis_trace_chunks do
include StubGitlabCalls
include RedisHelpers
include WorkhorseHelpers
@@ -142,7 +142,7 @@ RSpec.describe API::Ci::Runner, :clean_gitlab_redis_shared_state do
context 'when redis data are flushed' do
before do
- redis_shared_state_cleanup!
+ redis_trace_chunks_cleanup!
end
it 'has empty trace' do
@@ -272,6 +272,18 @@ RSpec.describe API::Ci::Runner, :clean_gitlab_redis_shared_state do
it { expect(response).to have_gitlab_http_status(:forbidden) }
end
+ context 'when the job trace is too big' do
+ before do
+ project.actual_limits.update!(ci_jobs_trace_size_limit: 1)
+ end
+
+ it 'returns 403 Forbidden' do
+ patch_the_trace(' appended', headers.merge({ 'Content-Range' => "#{1.megabyte}-#{1.megabyte + 9}" }))
+
+ expect(response).to have_gitlab_http_status(:forbidden)
+ end
+ end
+
def patch_the_trace(content = ' appended', request_headers = nil, job_id: job.id)
unless request_headers
job.trace.read do |stream|
diff --git a/spec/requests/api/ci/runner/runners_post_spec.rb b/spec/requests/api/ci/runner/runners_post_spec.rb
index 1696fe63d5d..6d222046998 100644
--- a/spec/requests/api/ci/runner/runners_post_spec.rb
+++ b/spec/requests/api/ci/runner/runners_post_spec.rb
@@ -11,8 +11,10 @@ RSpec.describe API::Ci::Runner, :clean_gitlab_redis_shared_state do
before do
stub_feature_flags(ci_enable_live_trace: true)
+ stub_feature_flags(runner_registration_control: false)
stub_gitlab_calls
stub_application_setting(runners_registration_token: registration_token)
+ stub_application_setting(valid_runner_registrars: ApplicationSetting::VALID_RUNNER_REGISTRAR_TYPES)
allow_any_instance_of(::Ci::Runner).to receive(:cache_attributes)
end
@@ -122,6 +124,33 @@ RSpec.describe API::Ci::Runner, :clean_gitlab_redis_shared_state do
expect(project.runners.recent.size).to eq(1)
end
end
+
+ context 'when valid runner registrars do not include project' do
+ before do
+ stub_application_setting(valid_runner_registrars: ['group'])
+ end
+
+ context 'when feature flag is enabled' do
+ before do
+ stub_feature_flags(runner_registration_control: true)
+ end
+
+ it 'returns 403 error' do
+ request
+
+ expect(response).to have_gitlab_http_status(:forbidden)
+ end
+ end
+
+ context 'when feature flag is disabled' do
+ it 'registers the runner' do
+ request
+
+ expect(response).to have_gitlab_http_status(:created)
+ expect(::Ci::Runner.first.active).to be true
+ end
+ end
+ end
end
context 'when group token is used' do
@@ -180,6 +209,33 @@ RSpec.describe API::Ci::Runner, :clean_gitlab_redis_shared_state do
expect(group.runners.recent.size).to eq(1)
end
end
+
+ context 'when valid runner registrars do not include group' do
+ before do
+ stub_application_setting(valid_runner_registrars: ['project'])
+ end
+
+ context 'when feature flag is enabled' do
+ before do
+ stub_feature_flags(runner_registration_control: true)
+ end
+
+ it 'returns 403 error' do
+ request
+
+ expect(response).to have_gitlab_http_status(:forbidden)
+ end
+ end
+
+ context 'when feature flag is disabled' do
+ it 'registers the runner' do
+ request
+
+ expect(response).to have_gitlab_http_status(:created)
+ expect(::Ci::Runner.first.active).to be true
+ end
+ end
+ end
end
end
diff --git a/spec/requests/api/composer_packages_spec.rb b/spec/requests/api/composer_packages_spec.rb
index 4120edabea3..e75725cacba 100644
--- a/spec/requests/api/composer_packages_spec.rb
+++ b/spec/requests/api/composer_packages_spec.rb
@@ -9,6 +9,7 @@ RSpec.describe API::ComposerPackages do
let_it_be(:personal_access_token) { create(:personal_access_token, user: user) }
let_it_be(:package_name) { 'package-name' }
let_it_be(:project, reload: true) { create(:project, :custom_repo, files: { 'composer.json' => { name: package_name }.to_json }, group: group) }
+
let(:snowplow_gitlab_standard_context) { { project: project, namespace: project.namespace, user: user } }
let(:headers) { {} }
diff --git a/spec/requests/api/debian_group_packages_spec.rb b/spec/requests/api/debian_group_packages_spec.rb
index c3abb06c5c1..931eaf41891 100644
--- a/spec/requests/api/debian_group_packages_spec.rb
+++ b/spec/requests/api/debian_group_packages_spec.rb
@@ -15,23 +15,23 @@ RSpec.describe API::DebianGroupPackages do
describe 'GET groups/:id/-/packages/debian/dists/*distribution/Release' do
let(:url) { "/groups/#{container.id}/-/packages/debian/dists/#{distribution.codename}/Release" }
- it_behaves_like 'Debian repository read endpoint', 'GET request', :success, /^TODO Release$/
+ it_behaves_like 'Debian repository read endpoint', 'GET request', :success, /^Codename: fixture-distribution\n$/
end
describe 'GET groups/:id/-/packages/debian/dists/*distribution/InRelease' do
let(:url) { "/groups/#{container.id}/-/packages/debian/dists/#{distribution.codename}/InRelease" }
- it_behaves_like 'Debian repository read endpoint', 'GET request', :not_found
+ it_behaves_like 'Debian repository read endpoint', 'GET request', :success, /^Codename: fixture-distribution\n$/
end
describe 'GET groups/:id/-/packages/debian/dists/*distribution/:component/binary-:architecture/Packages' do
- let(:url) { "/groups/#{container.id}/-/packages/debian/dists/#{distribution.codename}/#{component}/binary-#{architecture}/Packages" }
+ let(:url) { "/groups/#{container.id}/-/packages/debian/dists/#{distribution.codename}/#{component.name}/binary-#{architecture.name}/Packages" }
- it_behaves_like 'Debian repository read endpoint', 'GET request', :success, /^TODO Packages$/
+ it_behaves_like 'Debian repository read endpoint', 'GET request', :success, /Description: This is an incomplete Packages file/
end
describe 'GET groups/:id/-/packages/debian/pool/:component/:letter/:source_package/:file_name' do
- let(:url) { "/groups/#{container.id}/-/packages/debian/pool/#{component}/#{letter}/#{source_package}/#{package_name}_#{package_version}_#{architecture}.deb" }
+ let(:url) { "/groups/#{container.id}/-/packages/debian/pool/#{component.name}/#{letter}/#{source_package}/#{package_name}_#{package_version}_#{architecture.name}.deb" }
it_behaves_like 'Debian repository read endpoint', 'GET request', :success, /^TODO File$/
end
diff --git a/spec/requests/api/debian_project_packages_spec.rb b/spec/requests/api/debian_project_packages_spec.rb
index c11c4ecc12a..fb7da467322 100644
--- a/spec/requests/api/debian_project_packages_spec.rb
+++ b/spec/requests/api/debian_project_packages_spec.rb
@@ -15,23 +15,23 @@ RSpec.describe API::DebianProjectPackages do
describe 'GET projects/:id/packages/debian/dists/*distribution/Release' do
let(:url) { "/projects/#{container.id}/packages/debian/dists/#{distribution.codename}/Release" }
- it_behaves_like 'Debian repository read endpoint', 'GET request', :success, /^TODO Release$/
+ it_behaves_like 'Debian repository read endpoint', 'GET request', :success, /^Codename: fixture-distribution\n$/
end
describe 'GET projects/:id/packages/debian/dists/*distribution/InRelease' do
let(:url) { "/projects/#{container.id}/packages/debian/dists/#{distribution.codename}/InRelease" }
- it_behaves_like 'Debian repository read endpoint', 'GET request', :not_found
+ it_behaves_like 'Debian repository read endpoint', 'GET request', :success, /^Codename: fixture-distribution\n$/
end
describe 'GET projects/:id/packages/debian/dists/*distribution/:component/binary-:architecture/Packages' do
- let(:url) { "/projects/#{container.id}/packages/debian/dists/#{distribution.codename}/#{component}/binary-#{architecture}/Packages" }
+ let(:url) { "/projects/#{container.id}/packages/debian/dists/#{distribution.codename}/#{component.name}/binary-#{architecture.name}/Packages" }
- it_behaves_like 'Debian repository read endpoint', 'GET request', :success, /^TODO Packages$/
+ it_behaves_like 'Debian repository read endpoint', 'GET request', :success, /Description: This is an incomplete Packages file/
end
describe 'GET projects/:id/packages/debian/pool/:component/:letter/:source_package/:file_name' do
- let(:url) { "/projects/#{container.id}/packages/debian/pool/#{component}/#{letter}/#{source_package}/#{package_name}_#{package_version}_#{architecture}.deb" }
+ let(:url) { "/projects/#{container.id}/packages/debian/pool/#{component.name}/#{letter}/#{source_package}/#{package_name}_#{package_version}_#{architecture.name}.deb" }
it_behaves_like 'Debian repository read endpoint', 'GET request', :success, /^TODO File$/
end
diff --git a/spec/requests/api/deploy_tokens_spec.rb b/spec/requests/api/deploy_tokens_spec.rb
index e8426270622..38380fa4460 100644
--- a/spec/requests/api/deploy_tokens_spec.rb
+++ b/spec/requests/api/deploy_tokens_spec.rb
@@ -7,6 +7,7 @@ RSpec.describe API::DeployTokens do
let_it_be(:creator) { create(:user) }
let_it_be(:project) { create(:project, creator_id: creator.id) }
let_it_be(:group) { create(:group) }
+
let!(:deploy_token) { create(:deploy_token, projects: [project]) }
let!(:revoked_deploy_token) { create(:deploy_token, projects: [project], revoked: true) }
let!(:expired_deploy_token) { create(:deploy_token, projects: [project], expires_at: '1988-01-11T04:33:04-0600') }
diff --git a/spec/requests/api/deployments_spec.rb b/spec/requests/api/deployments_spec.rb
index bbfe37cb70b..38c96cd37af 100644
--- a/spec/requests/api/deployments_spec.rb
+++ b/spec/requests/api/deployments_spec.rb
@@ -456,6 +456,7 @@ RSpec.describe API::Deployments do
context 'when a user member of the deployment project' do
let_it_be(:project2) { create(:project) }
+
let!(:merge_request1) { create(:merge_request, source_project: project, target_project: project) }
let!(:merge_request2) { create(:merge_request, source_project: project, target_project: project, state: 'closed') }
let!(:merge_request3) { create(:merge_request, source_project: project2, target_project: project2) }
diff --git a/spec/requests/api/error_tracking_collector_spec.rb b/spec/requests/api/error_tracking_collector_spec.rb
new file mode 100644
index 00000000000..52d63410e7a
--- /dev/null
+++ b/spec/requests/api/error_tracking_collector_spec.rb
@@ -0,0 +1,77 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe API::ErrorTrackingCollector do
+ let_it_be(:project) { create(:project, :private) }
+ let_it_be(:setting) { create(:project_error_tracking_setting, project: project) }
+
+ describe "POST /error_tracking/collector/api/:id/envelope" do
+ let_it_be(:raw_event) { fixture_file('error_tracking/event.txt') }
+ let_it_be(:url) { "/error_tracking/collector/api/#{project.id}/envelope" }
+
+ let(:params) { raw_event }
+
+ subject { post api(url), params: params }
+
+ RSpec.shared_examples 'not found' do
+ it 'reponds with 404' do
+ subject
+
+ expect(response).to have_gitlab_http_status(:not_found)
+ end
+ end
+
+ RSpec.shared_examples 'bad request' do
+ it 'responds with 400' do
+ subject
+
+ expect(response).to have_gitlab_http_status(:bad_request)
+ end
+ end
+
+ context 'error tracking feature is disabled' do
+ before do
+ setting.update!(enabled: false)
+ end
+
+ it_behaves_like 'not found'
+ end
+
+ context 'feature flag is disabled' do
+ before do
+ stub_feature_flags(integrated_error_tracking: false)
+ end
+
+ it_behaves_like 'not found'
+ end
+
+ context 'empty body' do
+ let(:params) { '' }
+
+ it_behaves_like 'bad request'
+ end
+
+ context 'unknown request type' do
+ let(:params) { fixture_file('error_tracking/unknown.txt') }
+
+ it_behaves_like 'bad request'
+ end
+
+ context 'transaction request type' do
+ let(:params) { fixture_file('error_tracking/transaction.txt') }
+
+ it 'does nothing and returns no content' do
+ expect { subject }.not_to change { ErrorTracking::ErrorEvent.count }
+
+ expect(response).to have_gitlab_http_status(:no_content)
+ end
+ end
+
+ it 'writes to the database and returns no content' do
+ expect { subject }.to change { ErrorTracking::ErrorEvent.count }.by(1)
+
+ expect(response).to have_gitlab_http_status(:no_content)
+ end
+ end
+end
diff --git a/spec/requests/api/error_tracking_spec.rb b/spec/requests/api/error_tracking_spec.rb
index 8c9ca1b6a9d..39121af7bc3 100644
--- a/spec/requests/api/error_tracking_spec.rb
+++ b/spec/requests/api/error_tracking_spec.rb
@@ -4,6 +4,7 @@ require 'spec_helper'
RSpec.describe API::ErrorTracking do
let_it_be(:user) { create(:user) }
+
let(:setting) { create(:project_error_tracking_setting) }
let(:project) { setting.project }
diff --git a/spec/requests/api/feature_flags_spec.rb b/spec/requests/api/feature_flags_spec.rb
index 2cd52c0a5e5..8edf8825fb2 100644
--- a/spec/requests/api/feature_flags_spec.rb
+++ b/spec/requests/api/feature_flags_spec.rb
@@ -8,6 +8,7 @@ RSpec.describe API::FeatureFlags do
let_it_be(:developer) { create(:user) }
let_it_be(:reporter) { create(:user) }
let_it_be(:non_project_member) { create(:user) }
+
let(:user) { developer }
before_all do
diff --git a/spec/requests/api/freeze_periods_spec.rb b/spec/requests/api/freeze_periods_spec.rb
index 5589d4d543d..3da992301d5 100644
--- a/spec/requests/api/freeze_periods_spec.rb
+++ b/spec/requests/api/freeze_periods_spec.rb
@@ -6,6 +6,7 @@ RSpec.describe API::FreezePeriods do
let_it_be(:project) { create(:project, :repository, :private) }
let_it_be(:user) { create(:user) }
let_it_be(:admin) { create(:admin) }
+
let(:api_user) { user }
let(:invalid_cron) { '0 0 0 * *' }
let(:last_freeze_period) { project.freeze_periods.last }
diff --git a/spec/requests/api/geo_spec.rb b/spec/requests/api/geo_spec.rb
new file mode 100644
index 00000000000..edbca5eb1c6
--- /dev/null
+++ b/spec/requests/api/geo_spec.rb
@@ -0,0 +1,30 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe API::Geo do
+ include WorkhorseHelpers
+
+ describe 'GET /geo/proxy' do
+ subject { get api('/geo/proxy'), headers: workhorse_headers }
+
+ include_context 'workhorse headers'
+
+ context 'with valid auth' do
+ it 'returns empty data' do
+ subject
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(json_response).to be_empty
+ end
+ end
+
+ it 'rejects requests that bypassed gitlab-workhorse' do
+ workhorse_headers.delete(Gitlab::Workhorse::INTERNAL_API_REQUEST_HEADER)
+
+ subject
+
+ expect(response).to have_gitlab_http_status(:forbidden)
+ end
+ end
+end
diff --git a/spec/requests/api/graphql/boards/board_lists_query_spec.rb b/spec/requests/api/graphql/boards/board_lists_query_spec.rb
index cd94ce91071..2d52cddcacc 100644
--- a/spec/requests/api/graphql/boards/board_lists_query_spec.rb
+++ b/spec/requests/api/graphql/boards/board_lists_query_spec.rb
@@ -66,6 +66,7 @@ RSpec.describe 'get board lists' do
describe 'sorting and pagination' do
let_it_be(:current_user) { user }
+
let(:data_path) { [board_parent_type, :boards, :nodes, 0, :lists] }
def pagination_query(params)
diff --git a/spec/requests/api/graphql/ci/jobs_spec.rb b/spec/requests/api/graphql/ci/jobs_spec.rb
index 3fb89d6e815..10f05efa1b8 100644
--- a/spec/requests/api/graphql/ci/jobs_spec.rb
+++ b/spec/requests/api/graphql/ci/jobs_spec.rb
@@ -38,9 +38,15 @@ RSpec.describe 'Query.project.pipeline' do
name
groups {
nodes {
+ detailedStatus {
+ id
+ }
name
jobs {
nodes {
+ detailedStatus {
+ id
+ }
name
needs {
nodes { #{all_graphql_fields_for('CiBuildNeed')} }
diff --git a/spec/requests/api/graphql/ci/pipelines_spec.rb b/spec/requests/api/graphql/ci/pipelines_spec.rb
index f207636283f..6587061094d 100644
--- a/spec/requests/api/graphql/ci/pipelines_spec.rb
+++ b/spec/requests/api/graphql/ci/pipelines_spec.rb
@@ -229,6 +229,7 @@ RSpec.describe 'Query.project(fullPath).pipelines' do
let_it_be(:pipeline) { create(:ci_pipeline, project: project, user: user) }
let_it_be(:upstream_project) { create(:project, :repository, :public) }
let_it_be(:upstream_pipeline) { create(:ci_pipeline, project: upstream_project, user: user) }
+
let(:upstream_pipelines_graphql_data) { graphql_data.dig(*%w[project pipelines nodes]).first['upstream'] }
let(:query) do
diff --git a/spec/requests/api/graphql/ci/runner_spec.rb b/spec/requests/api/graphql/ci/runner_spec.rb
index e1f84d23209..cdd46ca4ecc 100644
--- a/spec/requests/api/graphql/ci/runner_spec.rb
+++ b/spec/requests/api/graphql/ci/runner_spec.rb
@@ -5,25 +5,25 @@ require 'spec_helper'
RSpec.describe 'Query.runner(id)' do
include GraphqlHelpers
- let_it_be(:user) { create_default(:user, :admin) }
+ let_it_be(:user) { create(:user, :admin) }
- let_it_be(:active_runner) do
+ let_it_be(:active_instance_runner) do
create(:ci_runner, :instance, description: 'Runner 1', contacted_at: 2.hours.ago,
active: true, version: 'adfe156', revision: 'a', locked: true, ip_address: '127.0.0.1', maximum_timeout: 600,
access_level: 0, tag_list: %w[tag1 tag2], run_untagged: true)
end
- let_it_be(:inactive_runner) do
+ let_it_be(:inactive_instance_runner) do
create(:ci_runner, :instance, description: 'Runner 2', contacted_at: 1.day.ago, active: false,
version: 'adfe157', revision: 'b', ip_address: '10.10.10.10', access_level: 1, run_untagged: true)
end
def get_runner(id)
case id
- when :active_runner
- active_runner
- when :inactive_runner
- inactive_runner
+ when :active_instance_runner
+ active_instance_runner
+ when :inactive_instance_runner
+ inactive_instance_runner
end
end
@@ -59,7 +59,9 @@ RSpec.describe 'Query.runner(id)' do
'accessLevel' => runner.access_level.to_s.upcase,
'runUntagged' => runner.run_untagged,
'ipAddress' => runner.ip_address,
- 'runnerType' => 'INSTANCE_TYPE'
+ 'runnerType' => 'INSTANCE_TYPE',
+ 'jobCount' => 0,
+ 'projectCount' => nil
)
expect(runner_data['tagList']).to match_array runner.tag_list
end
@@ -84,38 +86,113 @@ RSpec.describe 'Query.runner(id)' do
end
describe 'for active runner' do
- it_behaves_like 'runner details fetch', :active_runner
+ it_behaves_like 'runner details fetch', :active_instance_runner
+
+ context 'when tagList is not requested' do
+ let(:query) do
+ wrap_fields(query_graphql_path(query_path, 'id'))
+ end
+
+ let(:query_path) do
+ [
+ [:runner, { id: active_instance_runner.to_global_id.to_s }]
+ ]
+ end
+
+ it 'does not retrieve tagList' do
+ post_graphql(query, current_user: user)
+
+ runner_data = graphql_data_at(:runner)
+ expect(runner_data).not_to be_nil
+ expect(runner_data).not_to include('tagList')
+ end
+ end
end
describe 'for inactive runner' do
- it_behaves_like 'runner details fetch', :inactive_runner
+ it_behaves_like 'runner details fetch', :inactive_instance_runner
+ end
+
+ describe 'for multiple runners' do
+ let_it_be(:project1) { create(:project, :test_repo) }
+ let_it_be(:project2) { create(:project, :test_repo) }
+ let_it_be(:project_runner1) { create(:ci_runner, :project, projects: [project1, project2], description: 'Runner 1') }
+ let_it_be(:project_runner2) { create(:ci_runner, :project, projects: [], description: 'Runner 2') }
+
+ let!(:job) { create(:ci_build, runner: project_runner1) }
+
+ context 'requesting project and job counts' do
+ let(:query) do
+ %(
+ query {
+ projectRunner1: runner(id: "#{project_runner1.to_global_id}") {
+ projectCount
+ jobCount
+ }
+ projectRunner2: runner(id: "#{project_runner2.to_global_id}") {
+ projectCount
+ jobCount
+ }
+ activeInstanceRunner: runner(id: "#{active_instance_runner.to_global_id}") {
+ projectCount
+ jobCount
+ }
+ }
+ )
+ end
+
+ before do
+ project_runner2.projects.clear
+
+ post_graphql(query, current_user: user)
+ end
+
+ it 'retrieves expected fields' do
+ runner1_data = graphql_data_at(:project_runner1)
+ runner2_data = graphql_data_at(:project_runner2)
+ runner3_data = graphql_data_at(:active_instance_runner)
+
+ expect(runner1_data).to match a_hash_including(
+ 'jobCount' => 1,
+ 'projectCount' => 2)
+ expect(runner2_data).to match a_hash_including(
+ 'jobCount' => 0,
+ 'projectCount' => 0)
+ expect(runner3_data).to match a_hash_including(
+ 'jobCount' => 0,
+ 'projectCount' => nil)
+ end
+ end
end
describe 'by regular user' do
- let(:user) { create_default(:user) }
+ let(:user) { create(:user) }
- it_behaves_like 'retrieval by unauthorized user', :active_runner
+ it_behaves_like 'retrieval by unauthorized user', :active_instance_runner
end
describe 'by unauthenticated user' do
let(:user) { nil }
- it_behaves_like 'retrieval by unauthorized user', :active_runner
+ it_behaves_like 'retrieval by unauthorized user', :active_instance_runner
end
describe 'Query limits' do
def runner_query(runner)
<<~SINGLE
runner(id: "#{runner.to_global_id}") {
- #{all_graphql_fields_for('CiRunner')}
+ #{all_graphql_fields_for('CiRunner', excluded: excluded_fields)}
}
SINGLE
end
+ # Currently excluding a known N+1 issue, see https://gitlab.com/gitlab-org/gitlab/-/issues/334759
+ let(:excluded_fields) { %w[jobCount] }
+
let(:single_query) do
<<~QUERY
{
- active: #{runner_query(active_runner)}
+ active: #{runner_query(active_instance_runner)}
}
QUERY
end
@@ -123,8 +200,8 @@ RSpec.describe 'Query.runner(id)' do
let(:double_query) do
<<~QUERY
{
- active: #{runner_query(active_runner)}
- inactive: #{runner_query(inactive_runner)}
+ active: #{runner_query(active_instance_runner)}
+ inactive: #{runner_query(inactive_instance_runner)}
}
QUERY
end
diff --git a/spec/requests/api/graphql/current_user_todos_spec.rb b/spec/requests/api/graphql/current_user_todos_spec.rb
index b657f15d0e9..7f37abba74a 100644
--- a/spec/requests/api/graphql/current_user_todos_spec.rb
+++ b/spec/requests/api/graphql/current_user_todos_spec.rb
@@ -10,6 +10,7 @@ RSpec.describe 'A Todoable that implements the CurrentUserTodos interface' do
let_it_be(:todoable) { create(:issue, project: project) }
let_it_be(:done_todo) { create(:todo, state: :done, target: todoable, user: current_user) }
let_it_be(:pending_todo) { create(:todo, state: :pending, target: todoable, user: current_user) }
+
let(:state) { 'null' }
let(:todoable_response) do
diff --git a/spec/requests/api/graphql/issue_status_counts_spec.rb b/spec/requests/api/graphql/issue_status_counts_spec.rb
index 3d8817c3bc5..89ecbf44b10 100644
--- a/spec/requests/api/graphql/issue_status_counts_spec.rb
+++ b/spec/requests/api/graphql/issue_status_counts_spec.rb
@@ -9,6 +9,7 @@ RSpec.describe 'getting Issue counts by status' do
let_it_be(:issue_opened) { create(:issue, project: project) }
let_it_be(:issue_closed) { create(:issue, :closed, project: project) }
let_it_be(:other_project_issue) { create(:issue) }
+
let(:params) { {} }
let(:fields) do
diff --git a/spec/requests/api/graphql/metrics/dashboard_query_spec.rb b/spec/requests/api/graphql/metrics/dashboard_query_spec.rb
index e01f59ee6a0..1b84acff0e2 100644
--- a/spec/requests/api/graphql/metrics/dashboard_query_spec.rb
+++ b/spec/requests/api/graphql/metrics/dashboard_query_spec.rb
@@ -6,6 +6,7 @@ RSpec.describe 'Getting Metrics Dashboard' do
include GraphqlHelpers
let_it_be(:current_user) { create(:user) }
+
let(:project) { create(:project) }
let(:environment) { create(:environment, project: project) }
diff --git a/spec/requests/api/graphql/mutations/admin/sidekiq_queues/delete_jobs_spec.rb b/spec/requests/api/graphql/mutations/admin/sidekiq_queues/delete_jobs_spec.rb
index b8cde32877b..1692cfbcf84 100644
--- a/spec/requests/api/graphql/mutations/admin/sidekiq_queues/delete_jobs_spec.rb
+++ b/spec/requests/api/graphql/mutations/admin/sidekiq_queues/delete_jobs_spec.rb
@@ -6,6 +6,7 @@ RSpec.describe 'Deleting Sidekiq jobs', :clean_gitlab_redis_queues do
include GraphqlHelpers
let_it_be(:admin) { create(:admin) }
+
let(:queue) { 'authorized_projects' }
let(:variables) { { user: admin.username, queue_name: queue } }
diff --git a/spec/requests/api/graphql/mutations/alert_management/alerts/set_assignees_spec.rb b/spec/requests/api/graphql/mutations/alert_management/alerts/set_assignees_spec.rb
index cd5cefa0a9a..fcef7b4e3ec 100644
--- a/spec/requests/api/graphql/mutations/alert_management/alerts/set_assignees_spec.rb
+++ b/spec/requests/api/graphql/mutations/alert_management/alerts/set_assignees_spec.rb
@@ -8,6 +8,7 @@ RSpec.describe 'Setting assignees of an alert' do
let_it_be(:project) { create(:project) }
let_it_be(:current_user) { create(:user) }
let_it_be(:alert) { create(:alert_management_alert, project: project) }
+
let(:input) { { assignee_usernames: [current_user.username] } }
let(:mutation) do
diff --git a/spec/requests/api/graphql/mutations/alert_management/alerts/todo/create_spec.rb b/spec/requests/api/graphql/mutations/alert_management/alerts/todo/create_spec.rb
index cd423d7764a..48307964345 100644
--- a/spec/requests/api/graphql/mutations/alert_management/alerts/todo/create_spec.rb
+++ b/spec/requests/api/graphql/mutations/alert_management/alerts/todo/create_spec.rb
@@ -7,6 +7,7 @@ RSpec.describe 'Creating a todo for the alert' do
let_it_be(:user) { create(:user) }
let_it_be(:project) { create(:project) }
+
let(:alert) { create(:alert_management_alert, project: project) }
let(:mutation) do
diff --git a/spec/requests/api/graphql/mutations/alert_management/alerts/update_alert_status_spec.rb b/spec/requests/api/graphql/mutations/alert_management/alerts/update_alert_status_spec.rb
index ff55656a2ae..802d8d6c5a1 100644
--- a/spec/requests/api/graphql/mutations/alert_management/alerts/update_alert_status_spec.rb
+++ b/spec/requests/api/graphql/mutations/alert_management/alerts/update_alert_status_spec.rb
@@ -7,6 +7,7 @@ RSpec.describe 'Setting the status of an alert' do
let_it_be(:user) { create(:user) }
let_it_be(:project) { create(:project) }
+
let(:alert) { create(:alert_management_alert, project: project) }
let(:input) { { status: 'ACKNOWLEDGED' } }
diff --git a/spec/requests/api/graphql/mutations/alert_management/http_integration/create_spec.rb b/spec/requests/api/graphql/mutations/alert_management/http_integration/create_spec.rb
index e594d67aab4..ff93da2153f 100644
--- a/spec/requests/api/graphql/mutations/alert_management/http_integration/create_spec.rb
+++ b/spec/requests/api/graphql/mutations/alert_management/http_integration/create_spec.rb
@@ -7,6 +7,7 @@ RSpec.describe 'Creating a new HTTP Integration' do
let_it_be(:current_user) { create(:user) }
let_it_be(:project) { create(:project) }
+
let(:variables) do
{
project_path: project.full_path,
diff --git a/spec/requests/api/graphql/mutations/alert_management/prometheus_integration/create_spec.rb b/spec/requests/api/graphql/mutations/alert_management/prometheus_integration/create_spec.rb
index 0ef61ae0d5b..4c359d9b357 100644
--- a/spec/requests/api/graphql/mutations/alert_management/prometheus_integration/create_spec.rb
+++ b/spec/requests/api/graphql/mutations/alert_management/prometheus_integration/create_spec.rb
@@ -7,6 +7,7 @@ RSpec.describe 'Creating a new Prometheus Integration' do
let_it_be(:current_user) { create(:user) }
let_it_be(:project) { create(:project) }
+
let(:variables) do
{
project_path: project.full_path,
@@ -42,7 +43,7 @@ RSpec.describe 'Creating a new Prometheus Integration' do
it 'creates a new integration' do
post_graphql_mutation(mutation, current_user: current_user)
- new_integration = ::PrometheusService.last!
+ new_integration = ::Integrations::Prometheus.last!
integration_response = mutation_response['integration']
expect(response).to have_gitlab_http_status(:success)
diff --git a/spec/requests/api/graphql/mutations/alert_management/prometheus_integration/reset_token_spec.rb b/spec/requests/api/graphql/mutations/alert_management/prometheus_integration/reset_token_spec.rb
index d8d0ace5981..31053c50cac 100644
--- a/spec/requests/api/graphql/mutations/alert_management/prometheus_integration/reset_token_spec.rb
+++ b/spec/requests/api/graphql/mutations/alert_management/prometheus_integration/reset_token_spec.rb
@@ -7,7 +7,7 @@ RSpec.describe 'Resetting a token on an existing Prometheus Integration' do
let_it_be(:user) { create(:user) }
let_it_be(:project) { create(:project) }
- let_it_be(:integration) { create(:prometheus_service, project: project) }
+ let_it_be(:integration) { create(:prometheus_integration, project: project) }
let(:mutation) do
variables = {
diff --git a/spec/requests/api/graphql/mutations/alert_management/prometheus_integration/update_spec.rb b/spec/requests/api/graphql/mutations/alert_management/prometheus_integration/update_spec.rb
index 6c4a647a353..ad26ec118d7 100644
--- a/spec/requests/api/graphql/mutations/alert_management/prometheus_integration/update_spec.rb
+++ b/spec/requests/api/graphql/mutations/alert_management/prometheus_integration/update_spec.rb
@@ -7,7 +7,7 @@ RSpec.describe 'Updating an existing Prometheus Integration' do
let_it_be(:user) { create(:user) }
let_it_be(:project) { create(:project) }
- let_it_be(:integration) { create(:prometheus_service, project: project) }
+ let_it_be(:integration) { create(:prometheus_integration, project: project) }
let(:mutation) do
variables = {
diff --git a/spec/requests/api/graphql/mutations/award_emojis/add_spec.rb b/spec/requests/api/graphql/mutations/award_emojis/add_spec.rb
index b39062f2e71..fdf5503a3a2 100644
--- a/spec/requests/api/graphql/mutations/award_emojis/add_spec.rb
+++ b/spec/requests/api/graphql/mutations/award_emojis/add_spec.rb
@@ -8,6 +8,7 @@ RSpec.describe 'Adding an AwardEmoji' do
let_it_be(:current_user) { create(:user) }
let_it_be(:project) { create(:project) }
let_it_be(:awardable) { create(:note, project: project) }
+
let(:emoji_name) { 'thumbsup' }
let(:mutation) do
variables = {
diff --git a/spec/requests/api/graphql/mutations/award_emojis/toggle_spec.rb b/spec/requests/api/graphql/mutations/award_emojis/toggle_spec.rb
index 170e7ff3b44..6b26e37e30c 100644
--- a/spec/requests/api/graphql/mutations/award_emojis/toggle_spec.rb
+++ b/spec/requests/api/graphql/mutations/award_emojis/toggle_spec.rb
@@ -8,6 +8,7 @@ RSpec.describe 'Toggling an AwardEmoji' do
let_it_be(:current_user) { create(:user) }
let_it_be(:project, reload: true) { create(:project) }
let_it_be(:awardable) { create(:note, project: project) }
+
let(:emoji_name) { 'thumbsup' }
let(:mutation) do
variables = {
diff --git a/spec/requests/api/graphql/mutations/boards/create_spec.rb b/spec/requests/api/graphql/mutations/boards/create_spec.rb
index c5f981262ea..22d05f36f0f 100644
--- a/spec/requests/api/graphql/mutations/boards/create_spec.rb
+++ b/spec/requests/api/graphql/mutations/boards/create_spec.rb
@@ -4,6 +4,7 @@ require 'spec_helper'
RSpec.describe Mutations::Boards::Create do
let_it_be(:parent) { create(:project) }
+
let(:project_path) { parent.full_path }
let(:params) do
{
diff --git a/spec/requests/api/graphql/mutations/branches/create_spec.rb b/spec/requests/api/graphql/mutations/branches/create_spec.rb
index fc09f57a389..6a098002963 100644
--- a/spec/requests/api/graphql/mutations/branches/create_spec.rb
+++ b/spec/requests/api/graphql/mutations/branches/create_spec.rb
@@ -7,6 +7,7 @@ RSpec.describe 'Creation of a new branch' do
let_it_be(:current_user) { create(:user) }
let_it_be(:project) { create(:project, :public, :empty_repo) }
+
let(:input) { { project_path: project.full_path, name: new_branch, ref: ref } }
let(:new_branch) { 'new_branch' }
let(:ref) { 'master' }
@@ -34,11 +35,12 @@ RSpec.describe 'Creation of a new branch' do
end
context 'when ref is not correct' do
+ err_msg = 'Failed to create branch \'another_branch\': invalid reference name \'unknown\''
let(:new_branch) { 'another_branch' }
let(:ref) { 'unknown' }
it_behaves_like 'a mutation that returns errors in the response',
- errors: ['Invalid reference name: unknown']
+ errors: [err_msg]
end
end
end
diff --git a/spec/requests/api/graphql/mutations/ci/ci_cd_settings_update_spec.rb b/spec/requests/api/graphql/mutations/ci/ci_cd_settings_update_spec.rb
index 0d7571d91ca..05f6804a208 100644
--- a/spec/requests/api/graphql/mutations/ci/ci_cd_settings_update_spec.rb
+++ b/spec/requests/api/graphql/mutations/ci/ci_cd_settings_update_spec.rb
@@ -5,7 +5,10 @@ require 'spec_helper'
RSpec.describe 'CiCdSettingsUpdate' do
include GraphqlHelpers
- let_it_be(:project) { create(:project, keep_latest_artifact: true, ci_job_token_scope_enabled: true) }
+ let_it_be(:project) do
+ create(:project, keep_latest_artifact: true, ci_job_token_scope_enabled: true)
+ .tap(&:save!)
+ end
let(:variables) do
{
diff --git a/spec/requests/api/graphql/mutations/ci/job_token_scope/add_project_spec.rb b/spec/requests/api/graphql/mutations/ci/job_token_scope/add_project_spec.rb
new file mode 100644
index 00000000000..b53a7ddde32
--- /dev/null
+++ b/spec/requests/api/graphql/mutations/ci/job_token_scope/add_project_spec.rb
@@ -0,0 +1,78 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe 'CiJobTokenScopeAddProject' do
+ include GraphqlHelpers
+
+ let_it_be(:project) { create(:project, ci_job_token_scope_enabled: true).tap(&:save!) }
+ let_it_be(:target_project) { create(:project) }
+
+ let(:variables) do
+ {
+ project_path: project.full_path,
+ target_project_path: target_project.full_path
+ }
+ end
+
+ let(:mutation) do
+ graphql_mutation(:ci_job_token_scope_add_project, variables) do
+ <<~QL
+ errors
+ ciJobTokenScope {
+ projects {
+ nodes {
+ path
+ }
+ }
+ }
+ QL
+ end
+ end
+
+ let(:mutation_response) { graphql_mutation_response(:ci_job_token_scope_add_project) }
+
+ context 'when unauthorized' do
+ let(:current_user) { create(:user) }
+
+ context 'when not a maintainer' do
+ before do
+ project.add_developer(current_user)
+ end
+
+ it 'has graphql errors' do
+ post_graphql_mutation(mutation, current_user: current_user)
+
+ expect(graphql_errors).not_to be_empty
+ end
+ end
+ end
+
+ context 'when authorized' do
+ let_it_be(:current_user) { project.owner }
+
+ before do
+ target_project.add_developer(current_user)
+ end
+
+ it 'adds the target project to the job token scope' do
+ expect do
+ post_graphql_mutation(mutation, current_user: current_user)
+ expect(response).to have_gitlab_http_status(:success)
+ expect(mutation_response.dig('ciJobTokenScope', 'projects', 'nodes')).not_to be_empty
+ end.to change { Ci::JobToken::Scope.new(project).includes?(target_project) }.from(false).to(true)
+ end
+
+ context 'when invalid target project is provided' do
+ before do
+ variables[:target_project_path] = 'unknown/project'
+ end
+
+ it 'has mutation errors' do
+ post_graphql_mutation(mutation, current_user: current_user)
+
+ expect(mutation_response['errors']).to contain_exactly(Ci::JobTokenScope::EditScopeValidations::TARGET_PROJECT_UNAUTHORIZED_OR_UNFOUND)
+ end
+ end
+ end
+end
diff --git a/spec/requests/api/graphql/mutations/ci/job_token_scope/remove_project_spec.rb b/spec/requests/api/graphql/mutations/ci/job_token_scope/remove_project_spec.rb
new file mode 100644
index 00000000000..f1f42b00ada
--- /dev/null
+++ b/spec/requests/api/graphql/mutations/ci/job_token_scope/remove_project_spec.rb
@@ -0,0 +1,84 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe 'CiJobTokenScopeRemoveProject' do
+ include GraphqlHelpers
+
+ let_it_be(:project) { create(:project, ci_job_token_scope_enabled: true).tap(&:save!) }
+ let_it_be(:target_project) { create(:project) }
+
+ let_it_be(:link) do
+ create(:ci_job_token_project_scope_link,
+ source_project: project,
+ target_project: target_project)
+ end
+
+ let(:variables) do
+ {
+ project_path: project.full_path,
+ target_project_path: target_project.full_path
+ }
+ end
+
+ let(:mutation) do
+ graphql_mutation(:ci_job_token_scope_remove_project, variables) do
+ <<~QL
+ errors
+ ciJobTokenScope {
+ projects {
+ nodes {
+ path
+ }
+ }
+ }
+ QL
+ end
+ end
+
+ let(:mutation_response) { graphql_mutation_response(:ci_job_token_scope_remove_project) }
+
+ context 'when unauthorized' do
+ let(:current_user) { create(:user) }
+
+ context 'when not a maintainer' do
+ before do
+ project.add_developer(current_user)
+ end
+
+ it 'has graphql errors' do
+ post_graphql_mutation(mutation, current_user: current_user)
+
+ expect(graphql_errors).not_to be_empty
+ end
+ end
+ end
+
+ context 'when authorized' do
+ let_it_be(:current_user) { project.owner }
+
+ before do
+ target_project.add_guest(current_user)
+ end
+
+ it 'removes the target project from the job token scope' do
+ expect do
+ post_graphql_mutation(mutation, current_user: current_user)
+ expect(response).to have_gitlab_http_status(:success)
+ expect(mutation_response.dig('ciJobTokenScope', 'projects', 'nodes')).not_to be_empty
+ end.to change { Ci::JobToken::Scope.new(project).includes?(target_project) }.from(true).to(false)
+ end
+
+ context 'when invalid target project is provided' do
+ before do
+ variables[:target_project_path] = 'unknown/project'
+ end
+
+ it 'has mutation errors' do
+ post_graphql_mutation(mutation, current_user: current_user)
+
+ expect(mutation_response['errors']).to contain_exactly(Ci::JobTokenScope::EditScopeValidations::TARGET_PROJECT_UNAUTHORIZED_OR_UNFOUND)
+ end
+ end
+ end
+end
diff --git a/spec/requests/api/graphql/mutations/commits/create_spec.rb b/spec/requests/api/graphql/mutations/commits/create_spec.rb
index 375d4f10b40..619cba99c4e 100644
--- a/spec/requests/api/graphql/mutations/commits/create_spec.rb
+++ b/spec/requests/api/graphql/mutations/commits/create_spec.rb
@@ -7,6 +7,7 @@ RSpec.describe 'Creation of a new commit' do
let_it_be(:current_user) { create(:user) }
let_it_be(:project) { create(:project, :public, :repository) }
+
let(:input) { { project_path: project.full_path, branch: branch, message: message, actions: actions } }
let(:branch) { 'master' }
let(:message) { 'Commit message' }
diff --git a/spec/requests/api/graphql/mutations/container_expiration_policy/update_spec.rb b/spec/requests/api/graphql/mutations/container_expiration_policy/update_spec.rb
index 23e8e366483..0156142dc6f 100644
--- a/spec/requests/api/graphql/mutations/container_expiration_policy/update_spec.rb
+++ b/spec/requests/api/graphql/mutations/container_expiration_policy/update_spec.rb
@@ -53,6 +53,7 @@ RSpec.describe 'Updating the container expiration policy' do
RSpec.shared_examples 'rejecting invalid regex for' do |field_name|
context "for field #{field_name}" do
let_it_be(:invalid_regex) { '*production' }
+
let(:params) do
{
:project_path => project.full_path,
diff --git a/spec/requests/api/graphql/mutations/discussions/toggle_resolve_spec.rb b/spec/requests/api/graphql/mutations/discussions/toggle_resolve_spec.rb
index 450996bf76b..632a934cd95 100644
--- a/spec/requests/api/graphql/mutations/discussions/toggle_resolve_spec.rb
+++ b/spec/requests/api/graphql/mutations/discussions/toggle_resolve_spec.rb
@@ -7,6 +7,7 @@ RSpec.describe 'Toggling the resolve status of a discussion' do
let_it_be(:project) { create(:project, :public, :repository) }
let_it_be(:noteable) { create(:merge_request, source_project: project) }
+
let(:discussion) do
create(:diff_note_on_merge_request, noteable: noteable, project: project).to_discussion
end
diff --git a/spec/requests/api/graphql/mutations/environments/canary_ingress/update_spec.rb b/spec/requests/api/graphql/mutations/environments/canary_ingress/update_spec.rb
index f25a49291a6..3771ae0746e 100644
--- a/spec/requests/api/graphql/mutations/environments/canary_ingress/update_spec.rb
+++ b/spec/requests/api/graphql/mutations/environments/canary_ingress/update_spec.rb
@@ -13,6 +13,7 @@ RSpec.describe 'Update Environment Canary Ingress', :clean_gitlab_redis_cache do
let_it_be(:deployment) { create(:deployment, :success, environment: environment, project: project) }
let_it_be(:maintainer) { create(:user) }
let_it_be(:developer) { create(:user) }
+
let(:environment_id) { environment.to_global_id.to_s }
let(:weight) { 25 }
let(:actor) { developer }
diff --git a/spec/requests/api/graphql/mutations/issues/set_locked_spec.rb b/spec/requests/api/graphql/mutations/issues/set_locked_spec.rb
index 4989d096925..435ed0f9eb2 100644
--- a/spec/requests/api/graphql/mutations/issues/set_locked_spec.rb
+++ b/spec/requests/api/graphql/mutations/issues/set_locked_spec.rb
@@ -8,6 +8,7 @@ RSpec.describe 'Setting an issue as locked' do
let_it_be(:current_user) { create(:user) }
let_it_be(:issue) { create(:issue) }
let_it_be(:project) { issue.project }
+
let(:input) { { locked: true } }
let(:mutation) do
diff --git a/spec/requests/api/graphql/mutations/issues/set_severity_spec.rb b/spec/requests/api/graphql/mutations/issues/set_severity_spec.rb
index 96fd2368765..41997f151a2 100644
--- a/spec/requests/api/graphql/mutations/issues/set_severity_spec.rb
+++ b/spec/requests/api/graphql/mutations/issues/set_severity_spec.rb
@@ -6,6 +6,7 @@ RSpec.describe 'Setting severity level of an incident' do
include GraphqlHelpers
let_it_be(:user) { create(:user) }
+
let(:incident) { create(:incident) }
let(:project) { incident.project }
let(:input) { { severity: 'CRITICAL' } }
diff --git a/spec/requests/api/graphql/mutations/issues/update_spec.rb b/spec/requests/api/graphql/mutations/issues/update_spec.rb
index adfa2a2bc08..b3e1ab62e54 100644
--- a/spec/requests/api/graphql/mutations/issues/update_spec.rb
+++ b/spec/requests/api/graphql/mutations/issues/update_spec.rb
@@ -8,6 +8,7 @@ RSpec.describe 'Update of an existing issue' do
let_it_be(:current_user) { create(:user) }
let_it_be(:project) { create(:project, :public) }
let_it_be(:issue) { create(:issue, project: project) }
+
let(:input) do
{
'iid' => issue.iid.to_s,
diff --git a/spec/requests/api/graphql/mutations/jira_import/import_users_spec.rb b/spec/requests/api/graphql/mutations/jira_import/import_users_spec.rb
index 00b93984f98..45cc70f09fd 100644
--- a/spec/requests/api/graphql/mutations/jira_import/import_users_spec.rb
+++ b/spec/requests/api/graphql/mutations/jira_import/import_users_spec.rb
@@ -8,6 +8,7 @@ RSpec.describe 'Importing Jira Users' do
let_it_be(:user) { create(:user) }
let_it_be(:project) { create(:project) }
+
let(:importer) { instance_double(JiraImport::UsersImporter) }
let(:project_path) { project.full_path }
let(:start_at) { 7 }
diff --git a/spec/requests/api/graphql/mutations/jira_import/start_spec.rb b/spec/requests/api/graphql/mutations/jira_import/start_spec.rb
index e7124512ef1..b14305281af 100644
--- a/spec/requests/api/graphql/mutations/jira_import/start_spec.rb
+++ b/spec/requests/api/graphql/mutations/jira_import/start_spec.rb
@@ -8,6 +8,7 @@ RSpec.describe 'Starting a Jira Import' do
let_it_be(:user) { create(:user) }
let_it_be(:project, reload: true) { create(:project) }
+
let(:jira_project_key) { 'AA' }
let(:project_path) { project.full_path }
@@ -80,17 +81,17 @@ RSpec.describe 'Starting a Jira Import' do
end
end
- context 'when project has no Jira service' do
+ context 'when project has no Jira integration' do
it_behaves_like 'a mutation that returns errors in the response', errors: ['Jira integration not configured.']
end
- context 'when when project has Jira service' do
- let!(:service) { create(:jira_service, project: project) }
+ context 'when when project has Jira integration' do
+ let!(:service) { create(:jira_integration, project: project) }
before do
project.reload
- stub_jira_service_test
+ stub_jira_integration_test
end
context 'when issues feature are disabled' do
diff --git a/spec/requests/api/graphql/mutations/labels/create_spec.rb b/spec/requests/api/graphql/mutations/labels/create_spec.rb
index 28284408306..d19411f6c1d 100644
--- a/spec/requests/api/graphql/mutations/labels/create_spec.rb
+++ b/spec/requests/api/graphql/mutations/labels/create_spec.rb
@@ -61,6 +61,7 @@ RSpec.describe Mutations::Labels::Create do
context 'when creating a project label' do
let_it_be(:parent) { create(:project) }
+
let(:extra_params) { { project_path: parent.full_path } }
it_behaves_like 'labels create mutation'
@@ -68,6 +69,7 @@ RSpec.describe Mutations::Labels::Create do
context 'when creating a group label' do
let_it_be(:parent) { create(:group) }
+
let(:extra_params) { { group_path: parent.full_path } }
it_behaves_like 'labels create mutation'
diff --git a/spec/requests/api/graphql/mutations/merge_requests/accept_spec.rb b/spec/requests/api/graphql/mutations/merge_requests/accept_spec.rb
index 2725b33d528..19a7c72ba80 100644
--- a/spec/requests/api/graphql/mutations/merge_requests/accept_spec.rb
+++ b/spec/requests/api/graphql/mutations/merge_requests/accept_spec.rb
@@ -7,6 +7,7 @@ RSpec.describe 'accepting a merge request', :request_store do
let_it_be(:current_user) { create(:user) }
let_it_be(:project) { create(:project, :public, :repository) }
+
let!(:merge_request) { create(:merge_request, source_project: project) }
let(:input) do
{
diff --git a/spec/requests/api/graphql/mutations/merge_requests/create_spec.rb b/spec/requests/api/graphql/mutations/merge_requests/create_spec.rb
index bf759521dc0..3a4508489a1 100644
--- a/spec/requests/api/graphql/mutations/merge_requests/create_spec.rb
+++ b/spec/requests/api/graphql/mutations/merge_requests/create_spec.rb
@@ -6,6 +6,7 @@ RSpec.describe 'Creation of a new merge request' do
include GraphqlHelpers
let_it_be(:current_user) { create(:user) }
+
let(:project) { create(:project, :public, :repository) }
let(:input) do
{
diff --git a/spec/requests/api/graphql/mutations/merge_requests/set_assignees_spec.rb b/spec/requests/api/graphql/mutations/merge_requests/set_assignees_spec.rb
index a63116e2b94..dec9afd1310 100644
--- a/spec/requests/api/graphql/mutations/merge_requests/set_assignees_spec.rb
+++ b/spec/requests/api/graphql/mutations/merge_requests/set_assignees_spec.rb
@@ -68,7 +68,7 @@ RSpec.describe 'Setting assignees of a merge request', :assume_throttled do
context 'when the current user does not have permission to add assignees' do
let(:current_user) { create(:user) }
- let(:db_query_limit) { 28 }
+ let(:db_query_limit) { 27 }
it 'does not change the assignees' do
project.add_guest(current_user)
@@ -80,7 +80,7 @@ RSpec.describe 'Setting assignees of a merge request', :assume_throttled do
end
context 'with assignees already assigned' do
- let(:db_query_limit) { 46 }
+ let(:db_query_limit) { 39 }
before do
merge_request.assignees = [assignee2]
@@ -96,7 +96,7 @@ RSpec.describe 'Setting assignees of a merge request', :assume_throttled do
end
context 'when passing an empty list of assignees' do
- let(:db_query_limit) { 32 }
+ let(:db_query_limit) { 31 }
let(:input) { { assignee_usernames: [] } }
before do
@@ -115,7 +115,7 @@ RSpec.describe 'Setting assignees of a merge request', :assume_throttled do
context 'when passing append as true' do
let(:mode) { Types::MutationOperationModeEnum.enum[:append] }
let(:input) { { assignee_usernames: [assignee2.username], operation_mode: mode } }
- let(:db_query_limit) { 22 }
+ let(:db_query_limit) { 21 }
before do
# In CE, APPEND is a NOOP as you can't have multiple assignees
@@ -135,7 +135,7 @@ RSpec.describe 'Setting assignees of a merge request', :assume_throttled do
end
context 'when passing remove as true' do
- let(:db_query_limit) { 32 }
+ let(:db_query_limit) { 31 }
let(:mode) { Types::MutationOperationModeEnum.enum[:remove] }
let(:input) { { assignee_usernames: [assignee.username], operation_mode: mode } }
let(:expected_result) { [] }
diff --git a/spec/requests/api/graphql/mutations/metrics/dashboard/annotations/create_spec.rb b/spec/requests/api/graphql/mutations/metrics/dashboard/annotations/create_spec.rb
index 2a39757e103..5bc3c68cf26 100644
--- a/spec/requests/api/graphql/mutations/metrics/dashboard/annotations/create_spec.rb
+++ b/spec/requests/api/graphql/mutations/metrics/dashboard/annotations/create_spec.rb
@@ -9,6 +9,7 @@ RSpec.describe Mutations::Metrics::Dashboard::Annotations::Create do
let_it_be(:project) { create(:project, :private, :repository) }
let_it_be(:environment) { create(:environment, project: project) }
let_it_be(:cluster) { create(:cluster, projects: [project]) }
+
let(:dashboard_path) { 'config/prometheus/common_metrics.yml' }
let(:starting_at) { Time.current.iso8601 }
let(:ending_at) { 1.hour.from_now.iso8601 }
diff --git a/spec/requests/api/graphql/mutations/namespace/package_settings/update_spec.rb b/spec/requests/api/graphql/mutations/namespace/package_settings/update_spec.rb
index 202e7e7c333..d335642d321 100644
--- a/spec/requests/api/graphql/mutations/namespace/package_settings/update_spec.rb
+++ b/spec/requests/api/graphql/mutations/namespace/package_settings/update_spec.rb
@@ -126,6 +126,7 @@ RSpec.describe 'Updating the package settings' do
context 'without existing package settings' do
let_it_be(:namespace, reload: true) { create(:group) }
+
let(:package_settings) { namespace.package_settings }
where(:user_role, :shared_examples_name) do
diff --git a/spec/requests/api/graphql/mutations/notes/create/diff_note_spec.rb b/spec/requests/api/graphql/mutations/notes/create/diff_note_spec.rb
index b5aaf304812..8f3ae9f26f6 100644
--- a/spec/requests/api/graphql/mutations/notes/create/diff_note_spec.rb
+++ b/spec/requests/api/graphql/mutations/notes/create/diff_note_spec.rb
@@ -6,6 +6,7 @@ RSpec.describe 'Adding a DiffNote' do
include GraphqlHelpers
let_it_be(:current_user) { create(:user) }
+
let(:noteable) { create(:merge_request, source_project: project, target_project: project) }
let(:project) { create(:project, :repository) }
let(:diff_refs) { noteable.diff_refs }
diff --git a/spec/requests/api/graphql/mutations/notes/create/image_diff_note_spec.rb b/spec/requests/api/graphql/mutations/notes/create/image_diff_note_spec.rb
index 0e5744fb64f..8f2438cb741 100644
--- a/spec/requests/api/graphql/mutations/notes/create/image_diff_note_spec.rb
+++ b/spec/requests/api/graphql/mutations/notes/create/image_diff_note_spec.rb
@@ -6,6 +6,7 @@ RSpec.describe 'Adding an image DiffNote' do
include GraphqlHelpers
let_it_be(:current_user) { create(:user) }
+
let(:noteable) { create(:merge_request, source_project: project, target_project: project) }
let(:project) { create(:project, :repository) }
let(:diff_refs) { noteable.diff_refs }
diff --git a/spec/requests/api/graphql/mutations/notes/create/note_spec.rb b/spec/requests/api/graphql/mutations/notes/create/note_spec.rb
index 8dd8ed361ba..87c752393ea 100644
--- a/spec/requests/api/graphql/mutations/notes/create/note_spec.rb
+++ b/spec/requests/api/graphql/mutations/notes/create/note_spec.rb
@@ -6,6 +6,7 @@ RSpec.describe 'Adding a Note' do
include GraphqlHelpers
let_it_be(:current_user) { create(:user) }
+
let(:noteable) { create(:merge_request, source_project: project, target_project: project) }
let(:project) { create(:project) }
let(:discussion) { nil }
diff --git a/spec/requests/api/graphql/mutations/notes/reposition_image_diff_note_spec.rb b/spec/requests/api/graphql/mutations/notes/reposition_image_diff_note_spec.rb
index 4efa7f9d509..89e3a71280f 100644
--- a/spec/requests/api/graphql/mutations/notes/reposition_image_diff_note_spec.rb
+++ b/spec/requests/api/graphql/mutations/notes/reposition_image_diff_note_spec.rb
@@ -7,6 +7,7 @@ RSpec.describe 'Repositioning an ImageDiffNote' do
let_it_be(:noteable) { create(:merge_request) }
let_it_be(:project) { noteable.project }
+
let(:note) { create(:image_diff_note_on_merge_request, noteable: noteable, project: project) }
let(:new_position) { { x: 10 } }
let(:current_user) { project.creator }
diff --git a/spec/requests/api/graphql/mutations/notes/update/image_diff_note_spec.rb b/spec/requests/api/graphql/mutations/notes/update/image_diff_note_spec.rb
index 1ce09881fde..cfd0b34b815 100644
--- a/spec/requests/api/graphql/mutations/notes/update/image_diff_note_spec.rb
+++ b/spec/requests/api/graphql/mutations/notes/update/image_diff_note_spec.rb
@@ -26,6 +26,7 @@ RSpec.describe 'Updating an image DiffNote' do
let_it_be(:updated_height) { 100 }
let_it_be(:updated_x) { 5 }
let_it_be(:updated_y) { 10 }
+
let(:updated_position) do
{
width: updated_width,
diff --git a/spec/requests/api/graphql/mutations/packages/destroy_spec.rb b/spec/requests/api/graphql/mutations/packages/destroy_spec.rb
new file mode 100644
index 00000000000..e5ced419ecf
--- /dev/null
+++ b/spec/requests/api/graphql/mutations/packages/destroy_spec.rb
@@ -0,0 +1,93 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe 'Destroying a package' do
+ using RSpec::Parameterized::TableSyntax
+
+ include GraphqlHelpers
+
+ let_it_be_with_reload(:package) { create(:package) }
+ let_it_be(:user) { create(:user) }
+
+ let(:project) { package.project }
+ let(:id) { package.to_global_id.to_s }
+
+ let(:query) do
+ <<~GQL
+ errors
+ GQL
+ end
+
+ let(:params) { { id: id } }
+ let(:mutation) { graphql_mutation(:destroy_package, params, query) }
+ let(:mutation_response) { graphql_mutation_response(:destroyPackage) }
+
+ shared_examples 'destroying the package' do
+ it 'destroy the package' do
+ expect(::Packages::DestroyPackageService)
+ .to receive(:new).with(container: package, current_user: user).and_call_original
+
+ expect { mutation_request }.to change { ::Packages::Package.count }.by(-1)
+ end
+
+ it_behaves_like 'returning response status', :success
+ end
+
+ shared_examples 'denying the mutation request' do
+ it 'does not destroy the package' do
+ expect(::Packages::DestroyPackageService)
+ .not_to receive(:new).with(container: package, current_user: user)
+
+ expect { mutation_request }.not_to change { ::Packages::Package.count }
+
+ expect(mutation_response).to be_nil
+ end
+
+ it_behaves_like 'returning response status', :success
+ end
+
+ describe 'post graphql mutation' do
+ subject(:mutation_request) { post_graphql_mutation(mutation, current_user: user) }
+
+ context 'with valid id' do
+ where(:user_role, :shared_examples_name) do
+ :maintainer | 'destroying the package'
+ :developer | 'denying the mutation request'
+ :reporter | 'denying the mutation request'
+ :guest | 'denying the mutation request'
+ :anonymous | 'denying the mutation request'
+ end
+
+ with_them do
+ before do
+ project.send("add_#{user_role}", user) unless user_role == :anonymous
+ end
+
+ it_behaves_like params[:shared_examples_name]
+ end
+ end
+
+ context 'with invalid id' do
+ let(:params) { { id: 'gid://gitlab/Packages::Package/5555' } }
+
+ it_behaves_like 'denying the mutation request'
+ end
+
+ context 'when an error occures' do
+ before do
+ project.add_maintainer(user)
+ end
+
+ it 'returns the errors in the response' do
+ allow_next_found_instance_of(::Packages::Package) do |package|
+ allow(package).to receive(:destroy!).and_raise(StandardError)
+ end
+
+ mutation_request
+
+ expect(mutation_response['errors']).to eq(['Failed to remove the package'])
+ end
+ end
+ end
+end
diff --git a/spec/requests/api/graphql/mutations/releases/delete_spec.rb b/spec/requests/api/graphql/mutations/releases/delete_spec.rb
index 3710f118bf4..40063156609 100644
--- a/spec/requests/api/graphql/mutations/releases/delete_spec.rb
+++ b/spec/requests/api/graphql/mutations/releases/delete_spec.rb
@@ -55,7 +55,7 @@ RSpec.describe 'Deleting a release' do
end
context 'when the current user has access to update releases' do
- let(:current_user) { maintainer }
+ let(:current_user) { developer }
it 'deletes the release' do
expect { delete_release }.to change { Release.count }.by(-1)
@@ -105,12 +105,6 @@ RSpec.describe 'Deleting a release' do
end
context "when the current user doesn't have access to update releases" do
- context 'when the current user is a Developer' do
- let(:current_user) { developer }
-
- it_behaves_like 'unauthorized or not found error'
- end
-
context 'when the current user is a Reporter' do
let(:current_user) { reporter }
diff --git a/spec/requests/api/graphql/mutations/snippets/create_spec.rb b/spec/requests/api/graphql/mutations/snippets/create_spec.rb
index 214c804c519..9a3cea3ca14 100644
--- a/spec/requests/api/graphql/mutations/snippets/create_spec.rb
+++ b/spec/requests/api/graphql/mutations/snippets/create_spec.rb
@@ -17,7 +17,6 @@ RSpec.describe 'Creating a Snippet' do
let(:actions) { [{ action: action }.merge(file_1), { action: action }.merge(file_2)] }
let(:project_path) { nil }
let(:uploaded_files) { nil }
- let(:spam_mutation_vars) { {} }
let(:mutation_vars) do
{
description: description,
@@ -26,7 +25,7 @@ RSpec.describe 'Creating a Snippet' do
project_path: project_path,
uploaded_files: uploaded_files,
blob_actions: actions
- }.merge(spam_mutation_vars)
+ }
end
let(:mutation) do
@@ -77,21 +76,6 @@ RSpec.describe 'Creating a Snippet' do
expect(mutation_response['snippet']).to be_nil
end
-
- context 'when snippet_spam flag is disabled' do
- before do
- stub_feature_flags(snippet_spam: false)
- end
-
- it 'passes disable_spam_action_service param to service' do
- expect(::Snippets::CreateService)
- .to receive(:new)
- .with(project: anything, current_user: anything, params: hash_including(disable_spam_action_service: true))
- .and_call_original
-
- subject
- end
- end
end
shared_examples 'creates snippet' do
@@ -101,8 +85,8 @@ RSpec.describe 'Creating a Snippet' do
end.to change { Snippet.count }.by(1)
snippet = Snippet.last
- created_file_1 = snippet.repository.blob_at('HEAD', file_1[:filePath])
- created_file_2 = snippet.repository.blob_at('HEAD', file_2[:filePath])
+ created_file_1 = snippet.repository.blob_at(snippet.default_branch, file_1[:filePath])
+ created_file_2 = snippet.repository.blob_at(snippet.default_branch, file_2[:filePath])
expect(created_file_1.data).to match(file_1[:content])
expect(created_file_2.data).to match(file_2[:content])
@@ -121,15 +105,6 @@ RSpec.describe 'Creating a Snippet' do
it_behaves_like 'snippet edit usage data counters'
it_behaves_like 'a mutation which can mutate a spammable' do
- let(:captcha_response) { 'abc123' }
- let(:spam_log_id) { 1234 }
- let(:spam_mutation_vars) do
- {
- captcha_response: captcha_response,
- spam_log_id: spam_log_id
- }
- end
-
let(:service) { Snippets::CreateService }
end
end
@@ -190,7 +165,7 @@ RSpec.describe 'Creating a Snippet' do
it do
expect(::Snippets::CreateService).to receive(:new)
- .with(project: nil, current_user: user, params: hash_including(files: expected_value))
+ .with(project: nil, current_user: user, params: hash_including(files: expected_value), spam_params: instance_of(::Spam::SpamParams))
.and_return(double(execute: creation_response))
subject
diff --git a/spec/requests/api/graphql/mutations/snippets/mark_as_spam_spec.rb b/spec/requests/api/graphql/mutations/snippets/mark_as_spam_spec.rb
index 4d499310591..43d846cb297 100644
--- a/spec/requests/api/graphql/mutations/snippets/mark_as_spam_spec.rb
+++ b/spec/requests/api/graphql/mutations/snippets/mark_as_spam_spec.rb
@@ -10,6 +10,7 @@ RSpec.describe 'Mark snippet as spam' do
let_it_be(:other_user) { create(:user) }
let_it_be(:snippet) { create(:personal_snippet) }
let_it_be(:user_agent_detail) { create(:user_agent_detail, subject: snippet) }
+
let(:current_user) { snippet.author }
let(:snippet_gid) { snippet.to_global_id.to_s }
diff --git a/spec/requests/api/graphql/mutations/snippets/update_spec.rb b/spec/requests/api/graphql/mutations/snippets/update_spec.rb
index 77efb786dcb..eb7e6f840fe 100644
--- a/spec/requests/api/graphql/mutations/snippets/update_spec.rb
+++ b/spec/requests/api/graphql/mutations/snippets/update_spec.rb
@@ -9,6 +9,7 @@ RSpec.describe 'Updating a Snippet' do
let_it_be(:original_description) { 'Initial description' }
let_it_be(:original_title) { 'Initial title' }
let_it_be(:original_file_name) { 'Initial file_name' }
+
let(:updated_content) { 'Updated content' }
let(:updated_description) { 'Updated description' }
let(:updated_title) { 'Updated_title' }
@@ -16,7 +17,6 @@ RSpec.describe 'Updating a Snippet' do
let(:updated_file) { 'CHANGELOG' }
let(:deleted_file) { 'README' }
let(:snippet_gid) { GitlabSchema.id_from_object(snippet).to_s }
- let(:spam_mutation_vars) { {} }
let(:mutation_vars) do
{
id: snippet_gid,
@@ -27,7 +27,7 @@ RSpec.describe 'Updating a Snippet' do
{ action: :update, filePath: updated_file, content: updated_content },
{ action: :delete, filePath: deleted_file }
]
- }.merge(spam_mutation_vars)
+ }
end
let(:mutation) do
@@ -82,21 +82,6 @@ RSpec.describe 'Updating a Snippet' do
end
end
- context 'when snippet_spam flag is disabled' do
- before do
- stub_feature_flags(snippet_spam: false)
- end
-
- it 'passes disable_spam_action_service param to service' do
- expect(::Snippets::UpdateService)
- .to receive(:new)
- .with(project: anything, current_user: anything, params: hash_including(disable_spam_action_service: true))
- .and_call_original
-
- subject
- end
- end
-
context 'when there are ActiveRecord validation errors' do
let(:updated_title) { '' }
@@ -125,15 +110,6 @@ RSpec.describe 'Updating a Snippet' do
end
it_behaves_like 'a mutation which can mutate a spammable' do
- let(:captcha_response) { 'abc123' }
- let(:spam_log_id) { 1234 }
- let(:spam_mutation_vars) do
- {
- captcha_response: captcha_response,
- spam_log_id: spam_log_id
- }
- end
-
let(:service) { Snippets::UpdateService }
end
@@ -164,6 +140,7 @@ RSpec.describe 'Updating a Snippet' do
describe 'ProjectSnippet' do
let_it_be(:project) { create(:project, :private) }
+
let(:snippet) do
create(:project_snippet,
:private,
diff --git a/spec/requests/api/graphql/mutations/user_callouts/create_spec.rb b/spec/requests/api/graphql/mutations/user_callouts/create_spec.rb
index cb67a60ebe4..716983f01d2 100644
--- a/spec/requests/api/graphql/mutations/user_callouts/create_spec.rb
+++ b/spec/requests/api/graphql/mutations/user_callouts/create_spec.rb
@@ -6,6 +6,7 @@ RSpec.describe 'Create a user callout' do
include GraphqlHelpers
let_it_be(:current_user) { create(:user) }
+
let(:feature_name) { ::UserCallout.feature_names.each_key.first }
let(:input) do
diff --git a/spec/requests/api/graphql/namespace/package_settings_spec.rb b/spec/requests/api/graphql/namespace/package_settings_spec.rb
index 6af098e902f..42fd07dbdc7 100644
--- a/spec/requests/api/graphql/namespace/package_settings_spec.rb
+++ b/spec/requests/api/graphql/namespace/package_settings_spec.rb
@@ -8,6 +8,7 @@ RSpec.describe 'getting namespace package settings in a namespace' do
let_it_be(:package_settings) { create(:namespace_package_setting) }
let_it_be(:namespace) { package_settings.namespace }
let_it_be(:current_user) { namespace.owner }
+
let(:package_settings_response) { graphql_data.dig('namespace', 'packageSettings') }
let(:fields) { all_graphql_fields_for('PackageSettings') }
diff --git a/spec/requests/api/graphql/project/alert_management/alert/issue_spec.rb b/spec/requests/api/graphql/project/alert_management/alert/issue_spec.rb
index 9724de4fedb..05a98a9dd9c 100644
--- a/spec/requests/api/graphql/project/alert_management/alert/issue_spec.rb
+++ b/spec/requests/api/graphql/project/alert_management/alert/issue_spec.rb
@@ -7,6 +7,7 @@ RSpec.describe 'getting Alert Management Alert Issue' do
let_it_be(:project) { create(:project) }
let_it_be(:current_user) { create(:user) }
+
let(:payload) { {} }
let(:query) { 'avg(metric) > 1.0' }
diff --git a/spec/requests/api/graphql/project/alert_management/alert_status_counts_spec.rb b/spec/requests/api/graphql/project/alert_management/alert_status_counts_spec.rb
index 9fbf5aaa41f..ecd93d169d3 100644
--- a/spec/requests/api/graphql/project/alert_management/alert_status_counts_spec.rb
+++ b/spec/requests/api/graphql/project/alert_management/alert_status_counts_spec.rb
@@ -9,6 +9,7 @@ RSpec.describe 'getting Alert Management Alert counts by status' do
let_it_be(:alert_resolved) { create(:alert_management_alert, :resolved, project: project) }
let_it_be(:alert_triggered) { create(:alert_management_alert, project: project) }
let_it_be(:other_project_alert) { create(:alert_management_alert) }
+
let(:params) { {} }
let(:fields) do
diff --git a/spec/requests/api/graphql/project/alert_management/integrations_spec.rb b/spec/requests/api/graphql/project/alert_management/integrations_spec.rb
index 0e029aee9e8..1793d4961eb 100644
--- a/spec/requests/api/graphql/project/alert_management/integrations_spec.rb
+++ b/spec/requests/api/graphql/project/alert_management/integrations_spec.rb
@@ -7,7 +7,7 @@ RSpec.describe 'getting Alert Management Integrations' do
let_it_be(:project) { create(:project, :repository) }
let_it_be(:current_user) { create(:user) }
- let_it_be(:prometheus_service) { create(:prometheus_service, project: project) }
+ let_it_be(:prometheus_integration) { create(:prometheus_integration, project: project) }
let_it_be(:project_alerting_setting) { create(:project_alerting_setting, project: project) }
let_it_be(:active_http_integration) { create(:alert_management_http_integration, project: project) }
let_it_be(:inactive_http_integration) { create(:alert_management_http_integration, :inactive, project: project) }
@@ -53,15 +53,15 @@ RSpec.describe 'getting Alert Management Integrations' do
end
context 'when no extra params given' do
- let(:http_integration) { integrations.first }
- let(:prometheus_integration) { integrations.second }
+ let(:http_integration_response) { integrations.first }
+ let(:prometheus_integration_response) { integrations.second }
it_behaves_like 'a working graphql query'
it { expect(integrations.size).to eq(2) }
it 'returns the correct properties of the integrations' do
- expect(http_integration).to include(
+ expect(http_integration_response).to include(
'id' => global_id_of(active_http_integration),
'type' => 'HTTP',
'name' => active_http_integration.name,
@@ -71,14 +71,14 @@ RSpec.describe 'getting Alert Management Integrations' do
'apiUrl' => nil
)
- expect(prometheus_integration).to include(
- 'id' => global_id_of(prometheus_service),
+ expect(prometheus_integration_response).to include(
+ 'id' => global_id_of(prometheus_integration),
'type' => 'PROMETHEUS',
'name' => 'Prometheus',
- 'active' => prometheus_service.manual_configuration?,
+ 'active' => prometheus_integration.manual_configuration?,
'token' => project_alerting_setting.token,
'url' => "http://localhost/#{project.full_path}/prometheus/alerts/notify.json",
- 'apiUrl' => prometheus_service.api_url
+ 'apiUrl' => prometheus_integration.api_url
)
end
end
@@ -104,7 +104,7 @@ RSpec.describe 'getting Alert Management Integrations' do
end
context 'when Prometheus Integration ID is given' do
- let(:params) { { id: global_id_of(prometheus_service) } }
+ let(:params) { { id: global_id_of(prometheus_integration) } }
it_behaves_like 'a working graphql query'
@@ -112,13 +112,13 @@ RSpec.describe 'getting Alert Management Integrations' do
it 'returns the correct properties of the Prometheus Integration' do
expect(integrations.first).to include(
- 'id' => global_id_of(prometheus_service),
+ 'id' => global_id_of(prometheus_integration),
'type' => 'PROMETHEUS',
'name' => 'Prometheus',
- 'active' => prometheus_service.manual_configuration?,
+ 'active' => prometheus_integration.manual_configuration?,
'token' => project_alerting_setting.token,
'url' => "http://localhost/#{project.full_path}/prometheus/alerts/notify.json",
- 'apiUrl' => prometheus_service.api_url
+ 'apiUrl' => prometheus_integration.api_url
)
end
end
diff --git a/spec/requests/api/graphql/project/base_service_spec.rb b/spec/requests/api/graphql/project/base_service_spec.rb
index af462c4a639..5dc0f55db88 100644
--- a/spec/requests/api/graphql/project/base_service_spec.rb
+++ b/spec/requests/api/graphql/project/base_service_spec.rb
@@ -7,9 +7,9 @@ RSpec.describe 'query Jira service' do
let_it_be(:current_user) { create(:user) }
let_it_be(:project) { create(:project) }
- let_it_be(:jira_service) { create(:jira_service, project: project) }
+ let_it_be(:jira_integration) { create(:jira_integration, project: project) }
let_it_be(:bugzilla_integration) { create(:bugzilla_integration, project: project) }
- let_it_be(:redmine_service) { create(:redmine_service, project: project) }
+ let_it_be(:redmine_integration) { create(:redmine_integration, project: project) }
let(:query) do
%(
diff --git a/spec/requests/api/graphql/project/error_tracking/sentry_detailed_error_request_spec.rb b/spec/requests/api/graphql/project/error_tracking/sentry_detailed_error_request_spec.rb
index b2b42137acf..14fabaaf032 100644
--- a/spec/requests/api/graphql/project/error_tracking/sentry_detailed_error_request_spec.rb
+++ b/spec/requests/api/graphql/project/error_tracking/sentry_detailed_error_request_spec.rb
@@ -8,6 +8,7 @@ RSpec.describe 'getting a detailed sentry error' do
let_it_be(:project_setting) { create(:project_error_tracking_setting, project: project) }
let_it_be(:current_user) { project.owner }
let_it_be(:sentry_detailed_error) { build(:detailed_error_tracking_error) }
+
let(:sentry_gid) { sentry_detailed_error.to_global_id.to_s }
let(:fields) do
<<~QUERY
diff --git a/spec/requests/api/graphql/project/error_tracking/sentry_errors_request_spec.rb b/spec/requests/api/graphql/project/error_tracking/sentry_errors_request_spec.rb
index c7d327a62af..e71e5a48ddc 100644
--- a/spec/requests/api/graphql/project/error_tracking/sentry_errors_request_spec.rb
+++ b/spec/requests/api/graphql/project/error_tracking/sentry_errors_request_spec.rb
@@ -17,6 +17,7 @@ RSpec.describe 'sentry errors requests' do
describe 'getting a detailed sentry error' do
let_it_be(:sentry_detailed_error) { build(:detailed_error_tracking_error) }
+
let(:sentry_gid) { sentry_detailed_error.to_global_id.to_s }
let(:detailed_fields) do
@@ -193,6 +194,7 @@ RSpec.describe 'sentry errors requests' do
describe 'getting a stack trace' do
let_it_be(:sentry_stack_trace) { build(:error_tracking_error_event) }
+
let(:sentry_gid) { global_id_of(Gitlab::ErrorTracking::DetailedError.new(id: 1)) }
let(:stack_trace_fields) do
diff --git a/spec/requests/api/graphql/project/issue/designs/designs_spec.rb b/spec/requests/api/graphql/project/issue/designs/designs_spec.rb
index decab900a43..def41efddde 100644
--- a/spec/requests/api/graphql/project/issue/designs/designs_spec.rb
+++ b/spec/requests/api/graphql/project/issue/designs/designs_spec.rb
@@ -8,6 +8,7 @@ RSpec.describe 'Getting designs related to an issue' do
let_it_be(:design) { create(:design, :with_smaller_image_versions, versions_count: 1) }
let_it_be(:current_user) { design.project.owner }
+
let(:design_query) do
<<~NODE
designs {
@@ -124,6 +125,7 @@ RSpec.describe 'Getting designs related to an issue' do
context 'with versions' do
let_it_be(:version) { design.versions.take }
+
let(:design_query) do
<<~NODE
designs {
@@ -165,6 +167,7 @@ RSpec.describe 'Getting designs related to an issue' do
let_it_be(:issue) { design.issue }
let_it_be(:second_design, reload: true) { create(:design, :with_smaller_image_versions, issue: issue, versions_count: 1) }
let_it_be(:deleted_design) { create(:design, :with_versions, issue: issue, deleted: true, versions_count: 1) }
+
let(:all_versions) { issue.design_versions.ordered.reverse }
let(:design_query) do
<<~NODE
diff --git a/spec/requests/api/graphql/project/jira_service_spec.rb b/spec/requests/api/graphql/project/jira_service_spec.rb
index 905a669bf0d..64e9e04ae44 100644
--- a/spec/requests/api/graphql/project/jira_service_spec.rb
+++ b/spec/requests/api/graphql/project/jira_service_spec.rb
@@ -7,7 +7,7 @@ RSpec.describe 'query Jira service' do
let_it_be(:current_user) { create(:user) }
let_it_be(:project) { create(:project) }
- let_it_be(:jira_service) { create(:jira_service, project: project) }
+ let_it_be(:jira_integration) { create(:jira_integration, project: project) }
let(:query) do
%(
diff --git a/spec/requests/api/graphql/project/pipeline_spec.rb b/spec/requests/api/graphql/project/pipeline_spec.rb
index 0a5bcc7a965..cb6755640a9 100644
--- a/spec/requests/api/graphql/project/pipeline_spec.rb
+++ b/spec/requests/api/graphql/project/pipeline_spec.rb
@@ -8,9 +8,9 @@ RSpec.describe 'getting pipeline information nested in a project' do
let_it_be(:project) { create(:project, :repository, :public) }
let_it_be(:pipeline) { create(:ci_pipeline, project: project) }
let_it_be(:current_user) { create(:user) }
- let_it_be(:build_job) { create(:ci_build, :trace_with_sections, name: 'build-a', pipeline: pipeline) }
- let_it_be(:failed_build) { create(:ci_build, :failed, name: 'failed-build', pipeline: pipeline) }
- let_it_be(:bridge) { create(:ci_bridge, name: 'ci-bridge-example', pipeline: pipeline) }
+ let_it_be(:build_job) { create(:ci_build, :trace_with_sections, name: 'build-a', pipeline: pipeline, stage_idx: 0, stage: 'build') }
+ let_it_be(:failed_build) { create(:ci_build, :failed, name: 'failed-build', pipeline: pipeline, stage_idx: 0, stage: 'build') }
+ let_it_be(:bridge) { create(:ci_bridge, name: 'ci-bridge-example', pipeline: pipeline, stage_idx: 0, stage: 'build') }
let(:path) { %i[project pipeline] }
let(:pipeline_graphql_data) { graphql_data_at(*path) }
@@ -79,16 +79,6 @@ RSpec.describe 'getting pipeline information nested in a project' do
end
end
- private
-
- def build_query_to_find_pipeline_shas(*pipelines)
- pipeline_fields = pipelines.map.each_with_index do |pipeline, idx|
- "pipeline#{idx}: pipeline(iid: \"#{pipeline.iid}\") { sha }"
- end.join(' ')
-
- graphql_query_for('project', { 'fullPath' => project.full_path }, pipeline_fields)
- end
-
context 'when enough data is requested' do
let(:fields) do
query_graphql_field(:jobs, nil,
@@ -282,4 +272,69 @@ RSpec.describe 'getting pipeline information nested in a project' do
end
end
end
+
+ context 'N+1 queries on stages jobs' do
+ let(:depth) { 5 }
+ let(:fields) do
+ <<~FIELDS
+ stages {
+ nodes {
+ name
+ groups {
+ nodes {
+ name
+ jobs {
+ nodes {
+ name
+ needs {
+ nodes {
+ name
+ }
+ }
+ status: detailedStatus {
+ tooltip
+ hasDetails
+ detailsPath
+ action {
+ buttonTitle
+ path
+ title
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ FIELDS
+ end
+
+ it 'does not generate N+1 queries', :request_store, :use_sql_query_cache do
+ # warm up
+ post_graphql(query, current_user: current_user)
+
+ control = ActiveRecord::QueryRecorder.new(skip_cached: false) do
+ post_graphql(query, current_user: current_user)
+ end
+
+ create(:ci_build, name: 'test-a', pipeline: pipeline, stage_idx: 1, stage: 'test')
+ create(:ci_build, name: 'test-b', pipeline: pipeline, stage_idx: 1, stage: 'test')
+ create(:ci_build, name: 'deploy-a', pipeline: pipeline, stage_idx: 2, stage: 'deploy')
+
+ expect do
+ post_graphql(query, current_user: current_user)
+ end.not_to exceed_all_query_limit(control)
+ end
+ end
+
+ private
+
+ def build_query_to_find_pipeline_shas(*pipelines)
+ pipeline_fields = pipelines.map.each_with_index do |pipeline, idx|
+ "pipeline#{idx}: pipeline(iid: \"#{pipeline.iid}\") { sha }"
+ end.join(' ')
+
+ graphql_query_for('project', { 'fullPath' => project.full_path }, pipeline_fields)
+ end
end
diff --git a/spec/requests/api/graphql/project/project_pipeline_statistics_spec.rb b/spec/requests/api/graphql/project/project_pipeline_statistics_spec.rb
index 7d157563f5f..39a68d98d84 100644
--- a/spec/requests/api/graphql/project/project_pipeline_statistics_spec.rb
+++ b/spec/requests/api/graphql/project/project_pipeline_statistics_spec.rb
@@ -6,6 +6,7 @@ RSpec.describe 'rendering project pipeline statistics' do
include GraphqlHelpers
let_it_be(:project) { create(:project) }
+
let(:user) { create(:user) }
let(:fields) do
diff --git a/spec/requests/api/graphql/project_query_spec.rb b/spec/requests/api/graphql/project_query_spec.rb
index 54375d4de1d..e44a7efb354 100644
--- a/spec/requests/api/graphql/project_query_spec.rb
+++ b/spec/requests/api/graphql/project_query_spec.rb
@@ -8,6 +8,7 @@ RSpec.describe 'getting project information' do
let_it_be(:group) { create(:group) }
let_it_be(:project, reload: true) { create(:project, :repository, group: group) }
let_it_be(:current_user) { create(:user) }
+
let(:project_fields) { all_graphql_fields_for('project'.to_s.classify, max_depth: 1) }
let(:query) do
diff --git a/spec/requests/api/graphql/query_spec.rb b/spec/requests/api/graphql/query_spec.rb
index 6bd0703c121..ecc7fffaef7 100644
--- a/spec/requests/api/graphql/query_spec.rb
+++ b/spec/requests/api/graphql/query_spec.rb
@@ -8,6 +8,7 @@ RSpec.describe 'Query' do
let_it_be(:project) { create(:project) }
let_it_be(:issue) { create(:issue, project: project) }
let_it_be(:developer) { create(:user) }
+
let(:current_user) { developer }
describe '.designManagement' do
@@ -15,6 +16,7 @@ RSpec.describe 'Query' do
let_it_be(:version) { create(:design_version, issue: issue) }
let_it_be(:design) { version.designs.first }
+
let(:query_result) { graphql_data.dig(*path) }
let(:query) { graphql_query_for(:design_management, nil, dm_fields) }
diff --git a/spec/requests/api/graphql/user/starred_projects_query_spec.rb b/spec/requests/api/graphql/user/starred_projects_query_spec.rb
index 6cb02068f2a..a8c087d1fbf 100644
--- a/spec/requests/api/graphql/user/starred_projects_query_spec.rb
+++ b/spec/requests/api/graphql/user/starred_projects_query_spec.rb
@@ -60,6 +60,7 @@ RSpec.describe 'Getting starredProjects of the user' do
context 'the current user is a member of a private project the user starred' do
let_it_be(:other_user) { create(:user) }
+
let(:current_user) { other_user }
before do
diff --git a/spec/requests/api/graphql/user_query_spec.rb b/spec/requests/api/graphql/user_query_spec.rb
index 60520906e87..59b805bb25b 100644
--- a/spec/requests/api/graphql/user_query_spec.rb
+++ b/spec/requests/api/graphql/user_query_spec.rb
@@ -402,6 +402,7 @@ RSpec.describe 'getting user information' do
context 'we request the groupMemberships' do
let_it_be(:membership_a) { create(:group_member, user: user) }
+
let(:group_memberships) { graphql_data_at(:user, :group_memberships, :nodes) }
let(:user_fields) { 'groupMemberships { nodes { id } }' }
@@ -424,6 +425,7 @@ RSpec.describe 'getting user information' do
context 'we request the projectMemberships' do
let_it_be(:membership_a) { create(:project_member, user: user) }
+
let(:project_memberships) { graphql_data_at(:user, :project_memberships, :nodes) }
let(:user_fields) { 'projectMemberships { nodes { id } }' }
diff --git a/spec/requests/api/graphql_spec.rb b/spec/requests/api/graphql_spec.rb
index 463fca43cb5..7b081bb7568 100644
--- a/spec/requests/api/graphql_spec.rb
+++ b/spec/requests/api/graphql_spec.rb
@@ -315,6 +315,7 @@ RSpec.describe 'GraphQL' do
describe 'resolver complexity' do
let_it_be(:project) { create(:project, :public) }
+
let(:query) do
graphql_query_for(
'project',
@@ -350,6 +351,7 @@ RSpec.describe 'GraphQL' do
describe 'complexity limits' do
let_it_be(:project) { create(:project, :public) }
+
let!(:user) { create(:user) }
let(:query_fields) do
diff --git a/spec/requests/api/group_avatar_spec.rb b/spec/requests/api/group_avatar_spec.rb
index be5cfbc234c..50379d29b09 100644
--- a/spec/requests/api/group_avatar_spec.rb
+++ b/spec/requests/api/group_avatar_spec.rb
@@ -4,17 +4,35 @@ require 'spec_helper'
RSpec.describe API::GroupAvatar do
def avatar_path(group)
- "/groups/#{group.id}/avatar"
+ "/groups/#{ERB::Util.url_encode(group.full_path)}/avatar"
end
describe 'GET /groups/:id/avatar' do
context 'when the group is public' do
- it 'retrieves the avatar successfully' do
- group = create(:group, :public, :with_avatar)
+ let(:group) { create(:group, :public, :with_avatar) }
+ it 'retrieves the avatar successfully' do
get api(avatar_path(group))
expect(response).to have_gitlab_http_status(:ok)
+ expect(response.headers['Content-Disposition'])
+ .to eq(%(attachment; filename="dk.png"; filename*=UTF-8''dk.png))
+ end
+
+ context 'when the avatar is in the object storage' do
+ before do
+ stub_uploads_object_storage(AvatarUploader)
+
+ group.avatar.migrate!(ObjectStorage::Store::REMOTE)
+ end
+
+ it 'redirects to the file in the object storage' do
+ get api(avatar_path(group))
+
+ expect(response).to have_gitlab_http_status(:found)
+ expect(response.headers['Content-Disposition'])
+ .to eq(%(attachment; filename="dk.png"; filename*=UTF-8''dk.png))
+ end
end
context 'when the group does not have avatar' do
@@ -24,6 +42,18 @@ RSpec.describe API::GroupAvatar do
get api(avatar_path(group))
expect(response).to have_gitlab_http_status(:not_found)
+ expect(response.body)
+ .to eq(%({"message":"404 Avatar Not Found"}))
+ end
+ end
+
+ context 'when the group is a subgroup' do
+ it 'returns :ok' do
+ group = create(:group, :nested, :public, :with_avatar, name: 'g1.1')
+
+ get api(avatar_path(group))
+
+ expect(response).to have_gitlab_http_status(:ok)
end
end
end
diff --git a/spec/requests/api/group_import_spec.rb b/spec/requests/api/group_import_spec.rb
index f632e49bf3a..efad6334518 100644
--- a/spec/requests/api/group_import_spec.rb
+++ b/spec/requests/api/group_import_spec.rb
@@ -9,6 +9,7 @@ RSpec.describe API::GroupImport do
let_it_be(:user) { create(:user) }
let_it_be(:group) { create(:group) }
+
let(:path) { '/groups/import' }
let(:file) { File.join('spec', 'fixtures', 'group_export.tar.gz') }
let(:export_path) { "#{Dir.tmpdir}/group_export_spec" }
diff --git a/spec/requests/api/group_labels_spec.rb b/spec/requests/api/group_labels_spec.rb
index c677e68b285..11738e3cba8 100644
--- a/spec/requests/api/group_labels_spec.rb
+++ b/spec/requests/api/group_labels_spec.rb
@@ -29,6 +29,32 @@ RSpec.describe API::GroupLabels do
let(:expected_labels) { [group_label1.name] }
it_behaves_like 'fetches labels'
+
+ context 'and is subscribed' do
+ before do
+ group_label1.subscribe(user)
+ end
+
+ it 'returns true' do
+ get api("/groups/#{group.id}/labels?search=#{group_label1.name}", user)
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(json_response[0]['subscribed']).to be true
+ end
+ end
+
+ context 'and is unsubscribed' do
+ before do
+ group_label1.unsubscribe(user)
+ end
+
+ it 'returns false' do
+ get api("/groups/#{group.id}/labels?search=#{group_label1.name}", user)
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(json_response[0]['subscribed']).to be false
+ end
+ end
end
context 'when the with_counts parameter is set' do
diff --git a/spec/requests/api/group_milestones_spec.rb b/spec/requests/api/group_milestones_spec.rb
index e3e0164e5a7..2312d35c815 100644
--- a/spec/requests/api/group_milestones_spec.rb
+++ b/spec/requests/api/group_milestones_spec.rb
@@ -9,6 +9,7 @@ RSpec.describe API::GroupMilestones do
let_it_be(:group_member) { create(:group_member, group: group, user: user) }
let_it_be(:closed_milestone) { create(:closed_milestone, group: group, title: 'version1', description: 'closed milestone') }
let_it_be(:milestone) { create(:milestone, group: group, title: 'version2', description: 'open milestone') }
+
let(:route) { "/groups/#{group.id}/milestones" }
it_behaves_like 'group and project milestones', "/groups/:id/milestones"
diff --git a/spec/requests/api/group_packages_spec.rb b/spec/requests/api/group_packages_spec.rb
index 792aa2c1f20..a2b0b35c76a 100644
--- a/spec/requests/api/group_packages_spec.rb
+++ b/spec/requests/api/group_packages_spec.rb
@@ -6,6 +6,7 @@ RSpec.describe API::GroupPackages do
let_it_be(:group) { create(:group, :public) }
let_it_be(:project) { create(:project, :public, namespace: group, name: 'project A') }
let_it_be(:user) { create(:user) }
+
let(:params) { {} }
subject { get api(url), params: params }
@@ -17,6 +18,7 @@ RSpec.describe API::GroupPackages do
context 'with sorting' do
let_it_be(:package1) { create(:npm_package, project: project, version: '3.1.0', name: "@#{project.root_namespace.path}/foo1") }
let_it_be(:package2) { create(:nuget_package, project: project, version: '2.0.4') }
+
let(:package3) { create(:maven_package, project: project, version: '1.1.1', name: 'zzz') }
before do
diff --git a/spec/requests/api/groups_spec.rb b/spec/requests/api/groups_spec.rb
index 0a47b93773b..ad7a2e3b1fb 100644
--- a/spec/requests/api/groups_spec.rb
+++ b/spec/requests/api/groups_spec.rb
@@ -17,7 +17,7 @@ RSpec.describe API::Groups do
let_it_be(:project3) { create(:project, namespace: group1, path: 'test', visibility_level: Gitlab::VisibilityLevel::PRIVATE) }
let_it_be(:archived_project) { create(:project, namespace: group1, archived: true) }
- before do
+ before_all do
group1.add_owner(user1)
group2.add_owner(user2)
end
@@ -255,13 +255,14 @@ RSpec.describe API::Groups do
end
context "when using sorting" do
- let(:group3) { create(:group, name: "a#{group1.name}", path: "z#{group1.path}") }
- let(:group4) { create(:group, name: "same-name", path: "y#{group1.path}") }
- let(:group5) { create(:group, name: "same-name") }
+ let_it_be(:group3) { create(:group, name: "a#{group1.name}", path: "z#{group1.path}") }
+ let_it_be(:group4) { create(:group, name: "same-name", path: "y#{group1.path}") }
+ let_it_be(:group5) { create(:group, name: "same-name") }
+
let(:response_groups) { json_response.map { |group| group['name'] } }
let(:response_groups_ids) { json_response.map { |group| group['id'] } }
- before do
+ before_all do
group3.add_owner(user1)
group4.add_owner(user1)
group5.add_owner(user1)
@@ -330,6 +331,44 @@ RSpec.describe API::Groups do
expect(response_groups_ids).to eq(Group.select { |group| group['name'] == 'same-name' }.map { |group| group['id'] }.sort)
end
+ context 'when searching with similarity ordering', :aggregate_failures do
+ let_it_be(:group6) { create(:group, name: 'same-name subgroup', parent: group4) }
+ let_it_be(:group7) { create(:group, name: 'same-name parent') }
+
+ let(:params) { { order_by: 'similarity', search: 'same-name' } }
+
+ before_all do
+ group6.add_owner(user1)
+ group7.add_owner(user1)
+ end
+
+ subject { get api('/groups', user1), params: params }
+
+ it 'sorts top level groups before subgroups with exact matches first' do
+ subject
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(response).to include_pagination_headers
+ expect(json_response.length).to eq(4)
+
+ expect(response_groups).to eq(['same-name', 'same-name parent', 'same-name subgroup', 'same-name'])
+ end
+
+ context 'when `search` parameter is not given' do
+ let(:params) { { order_by: 'similarity' } }
+
+ it 'sorts items ordered by name' do
+ subject
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(response).to include_pagination_headers
+ expect(json_response.length).to eq(6)
+
+ expect(response_groups).to eq(groups_visible_to_user(user1).order(:name).pluck(:name))
+ end
+ end
+ end
+
def groups_visible_to_user(user)
Group.where(id: user.authorized_groups.select(:id).reorder(nil))
end
@@ -451,6 +490,7 @@ RSpec.describe API::Groups do
expect(json_response['visibility']).to eq(Gitlab::VisibilityLevel.string_level(group1.visibility_level))
expect(json_response['avatar_url']).to eq(group1.avatar_url(only_path: false))
expect(json_response['share_with_group_lock']).to eq(group1.share_with_group_lock)
+ expect(json_response['prevent_sharing_groups_outside_hierarchy']).to eq(group2.namespace_settings.prevent_sharing_groups_outside_hierarchy)
expect(json_response['require_two_factor_authentication']).to eq(group1.require_two_factor_authentication)
expect(json_response['two_factor_grace_period']).to eq(group1.two_factor_grace_period)
expect(json_response['auto_devops_enabled']).to eq(group1.auto_devops_enabled)
@@ -661,6 +701,7 @@ RSpec.describe API::Groups do
project_creation_level: "noone",
subgroup_creation_level: "maintainer",
default_branch_protection: ::Gitlab::Access::MAINTAINER_PROJECT_ACCESS,
+ prevent_sharing_groups_outside_hierarchy: true,
avatar: fixture_file_upload(file_path)
}
@@ -685,6 +726,7 @@ RSpec.describe API::Groups do
expect(json_response['shared_projects'].length).to eq(0)
expect(json_response['default_branch_protection']).to eq(::Gitlab::Access::MAINTAINER_PROJECT_ACCESS)
expect(json_response['avatar_url']).to end_with('dk.png')
+ expect(json_response['prevent_sharing_groups_outside_hierarchy']).to eq(true)
end
context 'updating the `default_branch_protection` attribute' do
@@ -755,6 +797,15 @@ RSpec.describe API::Groups do
expect(response).to have_gitlab_http_status(:bad_request)
expect(json_response['message']['visibility_level']).to contain_exactly('private is not allowed since there are sub-groups with higher visibility.')
end
+
+ it 'does not update prevent_sharing_groups_outside_hierarchy' do
+ put api("/groups/#{subgroup.id}", user3), params: { description: 'it works', prevent_sharing_groups_outside_hierarchy: true }
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(json_response.keys).not_to include('prevent_sharing_groups_outside_hierarchy')
+ expect(subgroup.reload.prevent_sharing_groups_outside_hierarchy).to eq(false)
+ expect(json_response['description']).to eq('it works')
+ end
end
end
@@ -1381,6 +1432,7 @@ RSpec.describe API::Groups do
let_it_be(:sub_child_group1) { create(:group, parent: child_group1) }
let_it_be(:child_group2) { create(:group, :private, parent: group2) }
let_it_be(:sub_child_group2) { create(:group, :private, parent: child_group2) }
+
let(:response_groups) { json_response.map { |group| group['name'] } }
context 'when unauthenticated' do
diff --git a/spec/requests/api/helm_packages_spec.rb b/spec/requests/api/helm_packages_spec.rb
index 5871c0a5d5b..08b4489a6e3 100644
--- a/spec/requests/api/helm_packages_spec.rb
+++ b/spec/requests/api/helm_packages_spec.rb
@@ -9,55 +9,171 @@ RSpec.describe API::HelmPackages do
let_it_be_with_reload(:project) { create(:project, :public) }
let_it_be(:deploy_token) { create(:deploy_token, read_package_registry: true, write_package_registry: true) }
let_it_be(:project_deploy_token) { create(:project_deploy_token, deploy_token: deploy_token, project: project) }
+ let_it_be(:package) { create(:helm_package, project: project) }
- describe 'GET /api/v4/projects/:id/packages/helm/:channel/charts/:file_name.tgz' do
- let_it_be(:package) { create(:helm_package, project: project) }
-
- let(:channel) { package.package_files.first.helm_channel }
+ describe 'GET /api/v4/projects/:id/packages/helm/:channel/index.yaml' do
+ it_behaves_like 'handling helm chart index requests' do
+ let(:url) { "/projects/#{project.id}/packages/helm/#{package.package_files.first.helm_channel}/index.yaml" }
+ end
+ end
- let(:url) { "/projects/#{project.id}/packages/helm/#{channel}/charts/#{package.name}-#{package.version}.tgz" }
+ describe 'GET /api/v4/projects/:id/packages/helm/:channel/charts/:file_name.tgz' do
+ let(:url) { "/projects/#{project.id}/packages/helm/#{package.package_files.first.helm_channel}/charts/#{package.name}-#{package.version}.tgz" }
- subject { get api(url) }
+ subject { get api(url), headers: headers }
context 'with valid project' do
- where(:visibility, :user_role, :member, :user_token, :shared_examples_name, :expected_status) do
- :public | :developer | true | true | 'process helm download content request' | :success
- :public | :guest | true | true | 'process helm download content request' | :success
- :public | :developer | true | false | 'rejects helm packages access' | :unauthorized
- :public | :guest | true | false | 'rejects helm packages access' | :unauthorized
- :public | :developer | false | true | 'process helm download content request' | :success
- :public | :guest | false | true | 'process helm download content request' | :success
- :public | :developer | false | false | 'rejects helm packages access' | :unauthorized
- :public | :guest | false | false | 'rejects helm packages access' | :unauthorized
- :public | :anonymous | false | true | 'process helm download content request' | :success
- :private | :developer | true | true | 'process helm download content request' | :success
- :private | :guest | true | true | 'rejects helm packages access' | :forbidden
- :private | :developer | true | false | 'rejects helm packages access' | :unauthorized
- :private | :guest | true | false | 'rejects helm packages access' | :unauthorized
- :private | :developer | false | true | 'rejects helm packages access' | :not_found
- :private | :guest | false | true | 'rejects helm packages access' | :not_found
- :private | :developer | false | false | 'rejects helm packages access' | :unauthorized
- :private | :guest | false | false | 'rejects helm packages access' | :unauthorized
- :private | :anonymous | false | true | 'rejects helm packages access' | :unauthorized
+ where(:visibility, :user_role, :shared_examples_name, :expected_status) do
+ :public | :guest | 'process helm download content request' | :success
+ :public | :not_a_member | 'process helm download content request' | :success
+ :public | :anonymous | 'process helm download content request' | :success
+ :private | :reporter | 'process helm download content request' | :success
+ :private | :guest | 'rejects helm packages access' | :forbidden
+ :private | :not_a_member | 'rejects helm packages access' | :not_found
+ :private | :anonymous | 'rejects helm packages access' | :unauthorized
end
with_them do
- let(:token) { user_token ? personal_access_token.token : 'wrong' }
- let(:headers) { user_role == :anonymous ? {} : basic_auth_header(user.username, token) }
+ let(:headers) { user_role == :anonymous ? {} : basic_auth_header(user.username, personal_access_token.token) }
let(:snowplow_gitlab_standard_context) { { project: project, namespace: project.namespace } }
- subject { get api(url), headers: headers }
-
before do
project.update!(visibility: visibility.to_s)
end
- it_behaves_like params[:shared_examples_name], params[:user_role], params[:expected_status], params[:member]
+ it_behaves_like params[:shared_examples_name], params[:user_role], params[:expected_status]
end
end
+ context 'when an invalid token is passed' do
+ let(:headers) { basic_auth_header(user.username, 'wrong') }
+
+ it_behaves_like 'returning response status', :unauthorized
+ end
+
it_behaves_like 'deploy token for package GET requests'
+ end
+
+ describe 'POST /api/v4/projects/:id/packages/helm/api/:channel/charts/authorize' do
+ include_context 'workhorse headers'
+
+ let(:channel) { 'stable' }
+ let(:url) { "/projects/#{project.id}/packages/helm/api/#{channel}/charts/authorize" }
+ let(:headers) { {} }
+
+ subject { post api(url), headers: headers }
+
+ context 'with valid project' do
+ where(:visibility_level, :user_role, :shared_examples_name, :expected_status) do
+ :public | :developer | 'process helm workhorse authorization' | :success
+ :public | :reporter | 'rejects helm packages access' | :forbidden
+ :public | :not_a_member | 'rejects helm packages access' | :forbidden
+ :public | :anonymous | 'rejects helm packages access' | :unauthorized
+ :private | :developer | 'process helm workhorse authorization' | :success
+ :private | :reporter | 'rejects helm packages access' | :forbidden
+ :private | :not_a_member | 'rejects helm packages access' | :not_found
+ :private | :anonymous | 'rejects helm packages access' | :unauthorized
+ end
+
+ with_them do
+ let(:user_headers) { user_role == :anonymous ? {} : basic_auth_header(user.username, personal_access_token.token) }
+ let(:headers) { user_headers.merge(workhorse_headers) }
+
+ before do
+ project.update_column(:visibility_level, Gitlab::VisibilityLevel.level_value(visibility_level.to_s))
+ end
+
+ it_behaves_like params[:shared_examples_name], params[:user_role], params[:expected_status]
+ end
+ end
+
+ context 'when an invalid token is passed' do
+ let(:headers) { basic_auth_header(user.username, 'wrong') }
+
+ it_behaves_like 'returning response status', :unauthorized
+ end
+
+ it_behaves_like 'deploy token for package uploads'
+
+ it_behaves_like 'job token for package uploads', authorize_endpoint: true, accept_invalid_username: true do
+ let_it_be(:job) { create(:ci_build, :running, user: user, project: project) }
+ end
it_behaves_like 'rejects helm access with unknown project id'
end
+
+ describe 'POST /api/v4/projects/:id/packages/helm/api/:channel/charts' do
+ include_context 'workhorse headers'
+
+ let_it_be(:file_name) { 'package.tgz' }
+
+ let(:channel) { 'stable' }
+ let(:url) { "/projects/#{project.id}/packages/helm/api/#{channel}/charts" }
+ let(:headers) { {} }
+ let(:params) { { chart: temp_file(file_name) } }
+ let(:file_key) { :chart }
+ let(:send_rewritten_field) { true }
+ let(:snowplow_gitlab_standard_context) { { project: project, namespace: project.namespace } }
+
+ subject do
+ workhorse_finalize(
+ api(url),
+ method: :post,
+ file_key: file_key,
+ params: params,
+ headers: headers,
+ send_rewritten_field: send_rewritten_field
+ )
+ end
+
+ context 'with valid project' do
+ where(:visibility_level, :user_role, :shared_examples_name, :expected_status) do
+ :public | :developer | 'process helm upload' | :created
+ :public | :reporter | 'rejects helm packages access' | :forbidden
+ :public | :not_a_member | 'rejects helm packages access' | :forbidden
+ :public | :anonymous | 'rejects helm packages access' | :unauthorized
+ :private | :developer | 'process helm upload' | :created
+ :private | :guest | 'rejects helm packages access' | :forbidden
+ :private | :not_a_member | 'rejects helm packages access' | :not_found
+ :private | :anonymous | 'rejects helm packages access' | :unauthorized
+ end
+
+ with_them do
+ let(:user_headers) { user_role == :anonymous ? {} : basic_auth_header(user.username, personal_access_token.token) }
+ let(:headers) { user_headers.merge(workhorse_headers) }
+
+ before do
+ project.update_column(:visibility_level, Gitlab::VisibilityLevel.level_value(visibility_level.to_s))
+ end
+
+ it_behaves_like params[:shared_examples_name], params[:user_role], params[:expected_status]
+ end
+ end
+
+ context 'when an invalid token is passed' do
+ let(:headers) { basic_auth_header(user.username, 'wrong') }
+
+ it_behaves_like 'returning response status', :unauthorized
+ end
+
+ it_behaves_like 'deploy token for package uploads'
+
+ it_behaves_like 'job token for package uploads', accept_invalid_username: true do
+ let_it_be(:job) { create(:ci_build, :running, user: user, project: project) }
+ end
+
+ it_behaves_like 'rejects helm access with unknown project id'
+
+ context 'file size above maximum limit' do
+ let(:headers) { basic_auth_header(deploy_token.username, deploy_token.token).merge(workhorse_headers) }
+
+ before do
+ allow_next_instance_of(UploadedFile) do |uploaded_file|
+ allow(uploaded_file).to receive(:size).and_return(project.actual_limits.helm_max_file_size + 1)
+ end
+ end
+
+ it_behaves_like 'returning response status', :bad_request
+ end
+ end
end
diff --git a/spec/requests/api/helpers_spec.rb b/spec/requests/api/helpers_spec.rb
index ce0018d6d0d..8961f3177b6 100644
--- a/spec/requests/api/helpers_spec.rb
+++ b/spec/requests/api/helpers_spec.rb
@@ -10,6 +10,7 @@ RSpec.describe API::Helpers do
include TermsHelper
let_it_be(:user, reload: true) { create(:user) }
+
let(:admin) { create(:admin) }
let(:key) { create(:key, user: user) }
diff --git a/spec/requests/api/import_bitbucket_server_spec.rb b/spec/requests/api/import_bitbucket_server_spec.rb
index 972b21ad2e0..2225f737f36 100644
--- a/spec/requests/api/import_bitbucket_server_spec.rb
+++ b/spec/requests/api/import_bitbucket_server_spec.rb
@@ -4,7 +4,7 @@ require 'spec_helper'
RSpec.describe API::ImportBitbucketServer do
let(:base_uri) { "https://test:7990" }
- let(:user) { create(:user, bio: 'test') }
+ let(:user) { create(:user) }
let(:token) { "asdasd12345" }
let(:secret) { "sekrettt" }
let(:project_key) { 'TES' }
@@ -14,6 +14,7 @@ RSpec.describe API::ImportBitbucketServer do
describe "POST /import/bitbucket_server" do
context 'with no optional parameters' do
let_it_be(:project) { create(:project) }
+
let(:client) { double(BitbucketServer::Client) }
before do
@@ -48,6 +49,7 @@ RSpec.describe API::ImportBitbucketServer do
context 'with a new project name' do
let_it_be(:project) { create(:project, name: 'new-name') }
+
let(:client) { instance_double(BitbucketServer::Client) }
before do
@@ -83,6 +85,7 @@ RSpec.describe API::ImportBitbucketServer do
context 'with an invalid URL' do
let_it_be(:project) { create(:project, name: 'new-name') }
+
let(:client) { instance_double(BitbucketServer::Client) }
before do
diff --git a/spec/requests/api/internal/base_spec.rb b/spec/requests/api/internal/base_spec.rb
index 631698554f9..49756df61c6 100644
--- a/spec/requests/api/internal/base_spec.rb
+++ b/spec/requests/api/internal/base_spec.rb
@@ -9,6 +9,7 @@ RSpec.describe API::Internal::Base do
let_it_be(:project, reload: true) { create(:project, :repository, :wiki_repo) }
let_it_be(:personal_snippet) { create(:personal_snippet, :repository, author: user) }
let_it_be(:project_snippet) { create(:project_snippet, :repository, author: user, project: project) }
+
let(:key) { create(:key, user: user) }
let(:secret_token) { Gitlab::Shell.secret_token }
let(:gl_repository) { "project-#{project.id}" }
@@ -1176,59 +1177,68 @@ RSpec.describe API::Internal::Base do
allow_any_instance_of(Gitlab::Identifier).to receive(:identify).and_return(user)
end
- context 'with Project' do
- it 'executes PostReceiveService' do
- message = <<~MESSAGE.strip
- To create a merge request for #{branch_name}, visit:
- http://#{Gitlab.config.gitlab.host}/#{project.full_path}/-/merge_requests/new?merge_request%5Bsource_branch%5D=#{branch_name}
- MESSAGE
+ shared_examples 'runs post-receive hooks' do
+ let(:gl_repository) { container.repository.gl_repository }
+ let(:messages) { [] }
+ it 'executes PostReceiveService' do
subject
+ expect(response).to have_gitlab_http_status(:ok)
expect(json_response).to eq({
- 'messages' => [{ 'message' => message, 'type' => 'basic' }],
+ 'messages' => messages,
'reference_counter_decreased' => true
})
end
+ it 'tries to notify that the container has moved' do
+ expect(Gitlab::Checks::ContainerMoved).to receive(:fetch_message).with(user, container.repository)
+
+ subject
+ end
+
it_behaves_like 'storing arguments in the application context' do
- let(:expected_params) { { user: user.username, project: project.full_path } }
+ let(:expected_params) { expected_context }
end
end
- context 'with PersonalSnippet' do
- let(:gl_repository) { "snippet-#{personal_snippet.id}" }
-
- it 'executes PostReceiveService' do
- subject
+ context 'with Project' do
+ it_behaves_like 'runs post-receive hooks' do
+ let(:container) { project }
+ let(:expected_context) { { user: user.username, project: project.full_path } }
- expect(json_response).to eq({
- 'messages' => [],
- 'reference_counter_decreased' => true
- })
+ let(:messages) do
+ [
+ {
+ 'message' => <<~MESSAGE.strip,
+ To create a merge request for #{branch_name}, visit:
+ http://#{Gitlab.config.gitlab.host}/#{project.full_path}/-/merge_requests/new?merge_request%5Bsource_branch%5D=#{branch_name}
+ MESSAGE
+ 'type' => 'basic'
+ }
+ ]
+ end
end
+ end
- it_behaves_like 'storing arguments in the application context' do
- let(:expected_params) { { user: key.user.username } }
- let(:gl_repository) { "snippet-#{personal_snippet.id}" }
+ context 'with PersonalSnippet' do
+ it_behaves_like 'runs post-receive hooks' do
+ let(:container) { personal_snippet }
+ let(:expected_context) { { user: key.user.username } }
end
end
context 'with ProjectSnippet' do
- let(:gl_repository) { "snippet-#{project_snippet.id}" }
-
- it 'executes PostReceiveService' do
- subject
-
- expect(json_response).to eq({
- 'messages' => [],
- 'reference_counter_decreased' => true
- })
+ it_behaves_like 'runs post-receive hooks' do
+ let(:container) { project_snippet }
+ let(:expected_context) { { user: key.user.username, project: project_snippet.project.full_path } }
end
+ end
- it_behaves_like 'storing arguments in the application context' do
- let(:expected_params) { { user: key.user.username, project: project_snippet.project.full_path } }
- let(:gl_repository) { "snippet-#{project_snippet.id}" }
+ context 'with ProjectWiki' do
+ it_behaves_like 'runs post-receive hooks' do
+ let(:container) { project.wiki }
+ let(:expected_context) { { user: key.user.username, project: project.full_path } }
end
end
@@ -1236,7 +1246,7 @@ RSpec.describe API::Internal::Base do
it 'does not try to notify that project moved' do
allow_any_instance_of(Gitlab::Identifier).to receive(:identify).and_return(nil)
- expect(Gitlab::Checks::ProjectMoved).not_to receive(:fetch_message)
+ expect(Gitlab::Checks::ContainerMoved).not_to receive(:fetch_message)
subject
@@ -1244,33 +1254,17 @@ RSpec.describe API::Internal::Base do
end
end
- context 'when project is nil' do
- context 'with Project' do
- let(:gl_repository) { 'project-foo' }
-
- it 'does not try to notify that project moved' do
- allow(Gitlab::GlRepository).to receive(:parse).and_return([nil, nil, Gitlab::GlRepository::PROJECT])
-
- expect(Gitlab::Checks::ProjectMoved).not_to receive(:fetch_message)
-
- subject
-
- expect(response).to have_gitlab_http_status(:ok)
- end
- end
-
- context 'with PersonalSnippet' do
- let(:gl_repository) { "snippet-#{personal_snippet.id}" }
+ context 'when container is nil' do
+ let(:gl_repository) { 'project-foo' }
- it 'does not try to notify that project moved' do
- allow(Gitlab::GlRepository).to receive(:parse).and_return([personal_snippet, nil, Gitlab::GlRepository::SNIPPET])
+ it 'does not try to notify that project moved' do
+ allow(Gitlab::GlRepository).to receive(:parse).and_return([nil, nil, Gitlab::GlRepository::PROJECT])
- expect(Gitlab::Checks::ProjectMoved).not_to receive(:fetch_message)
+ expect(Gitlab::Checks::ContainerMoved).not_to receive(:fetch_message)
- subject
+ subject
- expect(response).to have_gitlab_http_status(:ok)
- end
+ expect(response).to have_gitlab_http_status(:ok)
end
end
end
@@ -1378,29 +1372,6 @@ RSpec.describe API::Internal::Base do
end
end
- describe 'GET /internal/geo_proxy' do
- subject { get api('/internal/geo_proxy'), params: { secret_token: secret_token } }
-
- context 'with valid auth' do
- it 'returns empty data' do
- subject
-
- expect(response).to have_gitlab_http_status(:ok)
- expect(json_response).to be_empty
- end
- end
-
- context 'with invalid auth' do
- let(:secret_token) { 'invalid_token' }
-
- it 'returns unauthorized' do
- subject
-
- expect(response).to have_gitlab_http_status(:unauthorized)
- end
- end
- end
-
def lfs_auth_project(project)
post(
api("/internal/lfs_authenticate"),
diff --git a/spec/requests/api/internal/kubernetes_spec.rb b/spec/requests/api/internal/kubernetes_spec.rb
index 7a2cec974b9..2acf6951d50 100644
--- a/spec/requests/api/internal/kubernetes_spec.rb
+++ b/spec/requests/api/internal/kubernetes_spec.rb
@@ -133,36 +133,6 @@ RSpec.describe API::Internal::Kubernetes do
)
)
end
-
- context 'on GitLab.com' do
- before do
- allow(::Gitlab).to receive(:com?).and_return(true)
- end
-
- context 'kubernetes_agent_on_gitlab_com feature flag disabled' do
- before do
- stub_feature_flags(kubernetes_agent_on_gitlab_com: false)
- end
-
- it 'returns 403' do
- send_request(headers: { 'Authorization' => "Bearer #{agent_token.token}" })
-
- expect(response).to have_gitlab_http_status(:forbidden)
- end
- end
-
- context 'kubernetes_agent_on_gitlab_com feature flag enabled' do
- before do
- stub_feature_flags(kubernetes_agent_on_gitlab_com: agent_token.agent.project)
- end
-
- it 'returns success' do
- send_request(headers: { 'Authorization' => "Bearer #{agent_token.token}" })
-
- expect(response).to have_gitlab_http_status(:success)
- end
- end
- end
end
end
@@ -214,36 +184,6 @@ RSpec.describe API::Internal::Kubernetes do
expect(response).to have_gitlab_http_status(:not_found)
end
end
-
- context 'on GitLab.com' do
- before do
- allow(::Gitlab).to receive(:com?).and_return(true)
- end
-
- context 'kubernetes_agent_on_gitlab_com feature flag disabled' do
- before do
- stub_feature_flags(kubernetes_agent_on_gitlab_com: false)
- end
-
- it 'returns 403' do
- send_request(params: { id: project.id }, headers: { 'Authorization' => "Bearer #{agent_token.token}" })
-
- expect(response).to have_gitlab_http_status(:forbidden)
- end
- end
-
- context 'kubernetes_agent_on_gitlab_com feature flag enabled' do
- before do
- stub_feature_flags(kubernetes_agent_on_gitlab_com: agent_token.agent.project)
- end
-
- it 'returns success' do
- send_request(params: { id: project.id }, headers: { 'Authorization' => "Bearer #{agent_token.token}" })
-
- expect(response).to have_gitlab_http_status(:success)
- end
- end
- end
end
context 'project is private' do
diff --git a/spec/requests/api/labels_spec.rb b/spec/requests/api/labels_spec.rb
index 26377c40b73..4b6868f42bc 100644
--- a/spec/requests/api/labels_spec.rb
+++ b/spec/requests/api/labels_spec.rb
@@ -200,6 +200,36 @@ RSpec.describe API::Labels do
expect(json_response.map { |l| l['name'] }).to match_array([group_label.name, priority_label.name, label1.name])
end
+ context 'when search param is provided' do
+ context 'and user is subscribed' do
+ before do
+ priority_label.subscribe(user)
+ end
+
+ it 'returns subscribed true' do
+ get api("/projects/#{project.id}/labels?search=#{priority_label.name}", user)
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(json_response[0]['name']).to eq(priority_label.name)
+ expect(json_response[0]['subscribed']).to be true
+ end
+ end
+
+ context 'and user is not subscribed' do
+ before do
+ priority_label.unsubscribe(user)
+ end
+
+ it 'returns subscribed false' do
+ get api("/projects/#{project.id}/labels?search=#{priority_label.name}", user)
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(json_response[0]['name']).to eq(priority_label.name)
+ expect(json_response[0]['subscribed']).to be false
+ end
+ end
+ end
+
context 'when the with_counts parameter is set' do
before do
create(:labeled_issue, project: project, labels: [group_label], author: user)
diff --git a/spec/requests/api/lint_spec.rb b/spec/requests/api/lint_spec.rb
index 57aa0f36192..7fe516d3daa 100644
--- a/spec/requests/api/lint_spec.rb
+++ b/spec/requests/api/lint_spec.rb
@@ -19,6 +19,7 @@ RSpec.describe API::Lint do
context 'when authenticated' do
let_it_be(:api_user) { create(:user) }
+
it 'returns authorized' do
post api('/ci/lint', api_user), params: { content: 'content' }
@@ -43,6 +44,7 @@ RSpec.describe API::Lint do
context 'when authenticated' do
let_it_be(:api_user) { create(:user) }
+
it 'returns authentication success' do
post api('/ci/lint', api_user), params: { content: 'content' }
diff --git a/spec/requests/api/markdown_spec.rb b/spec/requests/api/markdown_spec.rb
index 35d91963ac9..faf671d350f 100644
--- a/spec/requests/api/markdown_spec.rb
+++ b/spec/requests/api/markdown_spec.rb
@@ -52,6 +52,7 @@ RSpec.describe API::Markdown do
context "when arguments are valid" do
let_it_be(:project) { create(:project) }
let_it_be(:issue) { create(:issue, project: project) }
+
let(:issue_url) { "http://#{Gitlab.config.gitlab.host}/#{issue.project.namespace.path}/#{issue.project.path}/-/issues/#{issue.iid}" }
let(:text) { ":tada: Hello world! :100: #{issue.to_reference}" }
diff --git a/spec/requests/api/merge_requests_spec.rb b/spec/requests/api/merge_requests_spec.rb
index 038c3bc552a..4b5fc57571b 100644
--- a/spec/requests/api/merge_requests_spec.rb
+++ b/spec/requests/api/merge_requests_spec.rb
@@ -1188,16 +1188,14 @@ RSpec.describe API::MergeRequests do
expect(json_response['target_project_id']).to eq(merge_request.target_project.id)
expect(json_response['draft']).to be false
expect(json_response['work_in_progress']).to be false
- expect(json_response['merge_when_pipeline_succeeds']).to be_falsy
+ expect(json_response['merge_when_pipeline_succeeds']).to be false
expect(json_response['merge_status']).to eq('can_be_merged')
- expect(json_response['should_close_merge_request']).to be_falsy
- expect(json_response['force_close_merge_request']).to be_falsy
expect(json_response['changes_count']).to eq(merge_request.merge_request_diff.real_size)
expect(json_response['merge_error']).to eq(merge_request.merge_error)
expect(json_response['user']['can_merge']).to be_truthy
expect(json_response).not_to include('rebase_in_progress')
- expect(json_response['first_contribution']).to be_falsy
- expect(json_response['has_conflicts']).to be_falsy
+ expect(json_response['first_contribution']).to be false
+ expect(json_response['has_conflicts']).to be false
expect(json_response['blocking_discussions_resolved']).to be_truthy
expect(json_response['references']['short']).to eq("!#{merge_request.iid}")
expect(json_response['references']['relative']).to eq("!#{merge_request.iid}")
@@ -1396,7 +1394,7 @@ RSpec.describe API::MergeRequests do
get api("/projects/#{project.id}/merge_requests/#{merge_request.iid}", user2)
- expect(json_response['user']['can_merge']).to be_falsy
+ expect(json_response['user']['can_merge']).to be false
end
it 'returns `checking` as its merge_status instead of `cannot_be_merged_rechecking`' do
@@ -2009,6 +2007,7 @@ RSpec.describe API::MergeRequests do
context 'forked projects', :sidekiq_might_not_need_inline do
let_it_be(:user2) { create(:user) }
+
let(:project) { create(:project, :public, :repository) }
let!(:forked_project) { fork_project(project, user2, repository: true) }
let!(:unrelated_project) { create(:project, namespace: create(:user).namespace, creator_id: user2.id) }
@@ -2664,7 +2663,7 @@ RSpec.describe API::MergeRequests do
)
expect(response).to have_gitlab_http_status(:ok)
- expect(source_repository.branch_exists?(source_branch)).to be_falsy
+ expect(source_repository.branch_exists?(source_branch)).to be false
end
end
@@ -2682,7 +2681,7 @@ RSpec.describe API::MergeRequests do
)
expect(response).to have_gitlab_http_status(:ok)
- expect(source_repository.branch_exists?(source_branch)).to be_falsy
+ expect(source_repository.branch_exists?(source_branch)).to be false
end
it 'does not remove the source branch' do
@@ -2804,7 +2803,7 @@ RSpec.describe API::MergeRequests do
it 'sets to true' do
merge_request.update!(merge_params: { 'force_remove_source_branch' => false } )
- expect(merge_request.force_remove_source_branch?).to be_falsey
+ expect(merge_request.force_remove_source_branch?).to be false
put api("/projects/#{project.id}/merge_requests/#{merge_request.iid}", user), params: { state_event: "close", remove_source_branch: true }
@@ -2889,6 +2888,7 @@ RSpec.describe API::MergeRequests do
context "forked projects" do
let_it_be(:user2) { create(:user) }
+
let(:project) { create(:project, :public, :repository) }
let!(:forked_project) { fork_project(project, user2, repository: true) }
let(:merge_request) do
diff --git a/spec/requests/api/metrics/dashboard/annotations_spec.rb b/spec/requests/api/metrics/dashboard/annotations_spec.rb
index 07de2925ee2..79a38702354 100644
--- a/spec/requests/api/metrics/dashboard/annotations_spec.rb
+++ b/spec/requests/api/metrics/dashboard/annotations_spec.rb
@@ -6,6 +6,7 @@ RSpec.describe API::Metrics::Dashboard::Annotations do
let_it_be(:user) { create(:user) }
let_it_be(:project) { create(:project, :private, :repository, namespace: user.namespace) }
let_it_be(:environment) { create(:environment, project: project) }
+
let(:dashboard) { 'config/prometheus/common_metrics.yml' }
let(:starting_at) { Time.now.iso8601 }
let(:ending_at) { 1.hour.from_now.iso8601 }
diff --git a/spec/requests/api/metrics/user_starred_dashboards_spec.rb b/spec/requests/api/metrics/user_starred_dashboards_spec.rb
index 533dff05f27..7f019e1226a 100644
--- a/spec/requests/api/metrics/user_starred_dashboards_spec.rb
+++ b/spec/requests/api/metrics/user_starred_dashboards_spec.rb
@@ -7,6 +7,7 @@ RSpec.describe API::Metrics::UserStarredDashboards do
let_it_be(:dashboard_yml) { fixture_file('lib/gitlab/metrics/dashboard/sample_dashboard.yml') }
let_it_be(:dashboard) { '.gitlab/dashboards/find&seek.yml' }
let_it_be(:project) { create(:project, :private, :repository, :custom_repo, namespace: user.namespace, files: { dashboard => dashboard_yml }) }
+
let(:url) { "/projects/#{project.id}/metrics/user_starred_dashboards" }
let(:params) do
{
diff --git a/spec/requests/api/nuget_project_packages_spec.rb b/spec/requests/api/nuget_project_packages_spec.rb
index 572736cfc86..f608f296295 100644
--- a/spec/requests/api/nuget_project_packages_spec.rb
+++ b/spec/requests/api/nuget_project_packages_spec.rb
@@ -92,9 +92,10 @@ RSpec.describe API::NugetProjectPackages do
describe 'GET /api/v4/projects/:id/packages/nuget/download/*package_name/*package_version/*package_filename' do
let_it_be(:package_name) { 'Dummy.Package' }
- let_it_be(:package) { create(:nuget_package, project: project, name: package_name) }
+ let_it_be(:package) { create(:nuget_package, :with_symbol_package, project: project, name: package_name) }
- let(:url) { "/projects/#{target.id}/packages/nuget/download/#{package.name}/#{package.version}/#{package.name}.#{package.version}.nupkg" }
+ let(:format) { 'nupkg' }
+ let(:url) { "/projects/#{target.id}/packages/nuget/download/#{package.name}/#{package.version}/#{package.name}.#{package.version}.#{format}" }
subject { get api(url) }
@@ -154,56 +155,14 @@ RSpec.describe API::NugetProjectPackages do
subject { put api(url), headers: headers }
- context 'with valid project' do
- where(:visibility_level, :user_role, :member, :user_token, :shared_examples_name, :expected_status) do
- 'PUBLIC' | :developer | true | true | 'process nuget workhorse authorization' | :success
- 'PUBLIC' | :guest | true | true | 'rejects nuget packages access' | :forbidden
- 'PUBLIC' | :developer | true | false | 'rejects nuget packages access' | :unauthorized
- 'PUBLIC' | :guest | true | false | 'rejects nuget packages access' | :unauthorized
- 'PUBLIC' | :developer | false | true | 'rejects nuget packages access' | :forbidden
- 'PUBLIC' | :guest | false | true | 'rejects nuget packages access' | :forbidden
- 'PUBLIC' | :developer | false | false | 'rejects nuget packages access' | :unauthorized
- 'PUBLIC' | :guest | false | false | 'rejects nuget packages access' | :unauthorized
- 'PUBLIC' | :anonymous | false | true | 'rejects nuget packages access' | :unauthorized
- 'PRIVATE' | :developer | true | true | 'process nuget workhorse authorization' | :success
- 'PRIVATE' | :guest | true | true | 'rejects nuget packages access' | :forbidden
- 'PRIVATE' | :developer | true | false | 'rejects nuget packages access' | :unauthorized
- 'PRIVATE' | :guest | true | false | 'rejects nuget packages access' | :unauthorized
- 'PRIVATE' | :developer | false | true | 'rejects nuget packages access' | :not_found
- 'PRIVATE' | :guest | false | true | 'rejects nuget packages access' | :not_found
- 'PRIVATE' | :developer | false | false | 'rejects nuget packages access' | :unauthorized
- 'PRIVATE' | :guest | false | false | 'rejects nuget packages access' | :unauthorized
- 'PRIVATE' | :anonymous | false | true | 'rejects nuget packages access' | :unauthorized
- end
-
- with_them do
- let(:token) { user_token ? personal_access_token.token : 'wrong' }
- let(:user_headers) { user_role == :anonymous ? {} : basic_auth_header(user.username, token) }
- let(:headers) { user_headers.merge(workhorse_headers) }
-
- before do
- update_visibility_to(Gitlab::VisibilityLevel.const_get(visibility_level, false))
- end
-
- it_behaves_like params[:shared_examples_name], params[:user_role], params[:expected_status], params[:member]
- end
- end
-
- it_behaves_like 'deploy token for package uploads'
-
- it_behaves_like 'job token for package uploads', authorize_endpoint: true do
- let_it_be(:job) { create(:ci_build, :running, user: user, project: project) }
- end
-
- it_behaves_like 'rejects nuget access with unknown target id'
-
- it_behaves_like 'rejects nuget access with invalid target id'
+ it_behaves_like 'nuget authorize upload endpoint'
end
describe 'PUT /api/v4/projects/:id/packages/nuget' do
include_context 'workhorse headers'
let_it_be(:file_name) { 'package.nupkg' }
+
let(:url) { "/projects/#{target.id}/packages/nuget" }
let(:headers) { {} }
let(:params) { { package: temp_file(file_name) } }
@@ -221,63 +180,43 @@ RSpec.describe API::NugetProjectPackages do
)
end
- context 'with valid project' do
- where(:visibility_level, :user_role, :member, :user_token, :shared_examples_name, :expected_status) do
- 'PUBLIC' | :developer | true | true | 'process nuget upload' | :created
- 'PUBLIC' | :guest | true | true | 'rejects nuget packages access' | :forbidden
- 'PUBLIC' | :developer | true | false | 'rejects nuget packages access' | :unauthorized
- 'PUBLIC' | :guest | true | false | 'rejects nuget packages access' | :unauthorized
- 'PUBLIC' | :developer | false | true | 'rejects nuget packages access' | :forbidden
- 'PUBLIC' | :guest | false | true | 'rejects nuget packages access' | :forbidden
- 'PUBLIC' | :developer | false | false | 'rejects nuget packages access' | :unauthorized
- 'PUBLIC' | :guest | false | false | 'rejects nuget packages access' | :unauthorized
- 'PUBLIC' | :anonymous | false | true | 'rejects nuget packages access' | :unauthorized
- 'PRIVATE' | :developer | true | true | 'process nuget upload' | :created
- 'PRIVATE' | :guest | true | true | 'rejects nuget packages access' | :forbidden
- 'PRIVATE' | :developer | true | false | 'rejects nuget packages access' | :unauthorized
- 'PRIVATE' | :guest | true | false | 'rejects nuget packages access' | :unauthorized
- 'PRIVATE' | :developer | false | true | 'rejects nuget packages access' | :not_found
- 'PRIVATE' | :guest | false | true | 'rejects nuget packages access' | :not_found
- 'PRIVATE' | :developer | false | false | 'rejects nuget packages access' | :unauthorized
- 'PRIVATE' | :guest | false | false | 'rejects nuget packages access' | :unauthorized
- 'PRIVATE' | :anonymous | false | true | 'rejects nuget packages access' | :unauthorized
- end
-
- with_them do
- let(:token) { user_token ? personal_access_token.token : 'wrong' }
- let(:user_headers) { user_role == :anonymous ? {} : basic_auth_header(user.username, token) }
- let(:headers) { user_headers.merge(workhorse_headers) }
- let(:snowplow_gitlab_standard_context) { { project: project, user: user, namespace: project.namespace } }
-
- before do
- update_visibility_to(Gitlab::VisibilityLevel.const_get(visibility_level, false))
- end
+ it_behaves_like 'nuget upload endpoint'
+ end
- it_behaves_like params[:shared_examples_name], params[:user_role], params[:expected_status], params[:member]
- end
- end
+ describe 'PUT /api/v4/projects/:id/packages/nuget/symbolpackage/authorize' do
+ include_context 'workhorse headers'
- it_behaves_like 'deploy token for package uploads'
+ let(:url) { "/projects/#{target.id}/packages/nuget/symbolpackage/authorize" }
+ let(:headers) { {} }
- it_behaves_like 'job token for package uploads' do
- let_it_be(:job) { create(:ci_build, :running, user: user, project: project) }
- end
+ subject { put api(url), headers: headers }
- it_behaves_like 'rejects nuget access with unknown target id'
+ it_behaves_like 'nuget authorize upload endpoint'
+ end
- it_behaves_like 'rejects nuget access with invalid target id'
+ describe 'PUT /api/v4/projects/:id/packages/nuget/symbolpackage' do
+ include_context 'workhorse headers'
- context 'file size above maximum limit' do
- let(:headers) { basic_auth_header(deploy_token.username, deploy_token.token).merge(workhorse_headers) }
+ let_it_be(:file_name) { 'package.snupkg' }
- before do
- allow_next_instance_of(UploadedFile) do |uploaded_file|
- allow(uploaded_file).to receive(:size).and_return(project.actual_limits.nuget_max_file_size + 1)
- end
- end
+ let(:url) { "/projects/#{target.id}/packages/nuget/symbolpackage" }
+ let(:headers) { {} }
+ let(:params) { { package: temp_file(file_name) } }
+ let(:file_key) { :package }
+ let(:send_rewritten_field) { true }
- it_behaves_like 'returning response status', :bad_request
+ subject do
+ workhorse_finalize(
+ api(url),
+ method: :put,
+ file_key: file_key,
+ params: params,
+ headers: headers,
+ send_rewritten_field: send_rewritten_field
+ )
end
+
+ it_behaves_like 'nuget upload endpoint', symbol_package: true
end
def update_visibility_to(visibility)
diff --git a/spec/requests/api/project_attributes.yml b/spec/requests/api/project_attributes.yml
index 2932447f663..8341fac3191 100644
--- a/spec/requests/api/project_attributes.yml
+++ b/spec/requests/api/project_attributes.yml
@@ -137,6 +137,7 @@ project_setting:
- has_confluence
- has_vulnerabilities
- prevent_merge_without_jira_issue
+ - previous_default_branch
- project_id
- push_rule_id
- show_default_award_emojis
diff --git a/spec/requests/api/project_clusters_spec.rb b/spec/requests/api/project_clusters_spec.rb
index f784f677c25..253b61e5865 100644
--- a/spec/requests/api/project_clusters_spec.rb
+++ b/spec/requests/api/project_clusters_spec.rb
@@ -335,6 +335,7 @@ RSpec.describe API::ProjectClusters do
let(:namespace) { 'new-namespace' }
let(:platform_kubernetes_attributes) { { namespace: namespace } }
let_it_be(:management_project) { create(:project, namespace: project.namespace) }
+
let(:management_project_id) { management_project.id }
let(:update_params) do
diff --git a/spec/requests/api/project_container_repositories_spec.rb b/spec/requests/api/project_container_repositories_spec.rb
index 695d2c3fe2c..1170a9ba6cb 100644
--- a/spec/requests/api/project_container_repositories_spec.rb
+++ b/spec/requests/api/project_container_repositories_spec.rb
@@ -11,6 +11,7 @@ RSpec.describe API::ProjectContainerRepositories do
let_it_be(:developer) { create(:user) }
let_it_be(:reporter) { create(:user) }
let_it_be(:guest) { create(:user) }
+
let(:root_repository) { create(:container_repository, :root, project: project) }
let(:test_repository) { create(:container_repository, project: project) }
let(:root_repository2) { create(:container_repository, :root, project: project2) }
diff --git a/spec/requests/api/project_milestones_spec.rb b/spec/requests/api/project_milestones_spec.rb
index 71535e66353..606279ec20a 100644
--- a/spec/requests/api/project_milestones_spec.rb
+++ b/spec/requests/api/project_milestones_spec.rb
@@ -21,6 +21,7 @@ RSpec.describe API::ProjectMilestones do
let_it_be(:group) { create(:group, :private, parent: ancestor_group) }
let_it_be(:ancestor_group_milestone) { create(:milestone, group: ancestor_group) }
let_it_be(:group_milestone) { create(:milestone, group: group) }
+
let(:params) { { include_parent_milestones: true } }
shared_examples 'listing all milestones' do
diff --git a/spec/requests/api/project_snippets_spec.rb b/spec/requests/api/project_snippets_spec.rb
index 6a9cf6e16e2..8cd1f15a88d 100644
--- a/spec/requests/api/project_snippets_spec.rb
+++ b/spec/requests/api/project_snippets_spec.rb
@@ -138,7 +138,7 @@ RSpec.describe API::ProjectSnippets do
aggregate_failures do
expect(snippet.repository.exists?).to be_truthy
- blob = snippet.repository.blob_at('master', file_path)
+ blob = snippet.repository.blob_at(snippet.default_branch, file_path)
expect(blob.data).to eq file_content
end
diff --git a/spec/requests/api/projects_spec.rb b/spec/requests/api/projects_spec.rb
index 529a75af122..a869866c698 100644
--- a/spec/requests/api/projects_spec.rb
+++ b/spec/requests/api/projects_spec.rb
@@ -164,24 +164,21 @@ RSpec.describe API::Projects do
end
end
- shared_examples_for 'projects response without N + 1 queries' do
+ shared_examples_for 'projects response without N + 1 queries' do |threshold|
+ let(:additional_project) { create(:project, :public) }
+
it 'avoids N + 1 queries' do
+ get api('/projects', current_user)
+
control = ActiveRecord::QueryRecorder.new do
get api('/projects', current_user)
end
- if defined?(additional_project)
- additional_project
- else
- create(:project, :public)
- end
+ additional_project
- # TODO: We're currently querying to detect if a project is a fork
- # in 2 ways. Lower this back to 8 when `ForkedProjectLink` relation is
- # removed
expect do
get api('/projects', current_user)
- end.not_to exceed_query_limit(control).with_threshold(9)
+ end.not_to exceed_query_limit(control).with_threshold(threshold)
end
end
@@ -194,7 +191,7 @@ RSpec.describe API::Projects do
let(:projects) { [project] }
end
- it_behaves_like 'projects response without N + 1 queries' do
+ it_behaves_like 'projects response without N + 1 queries', 1 do
let(:current_user) { nil }
end
end
@@ -206,7 +203,7 @@ RSpec.describe API::Projects do
let(:projects) { user_projects }
end
- it_behaves_like 'projects response without N + 1 queries' do
+ it_behaves_like 'projects response without N + 1 queries', 0 do
let(:current_user) { user }
end
@@ -215,7 +212,7 @@ RSpec.describe API::Projects do
create(:project, :public, group: create(:group))
end
- it_behaves_like 'projects response without N + 1 queries' do
+ it_behaves_like 'projects response without N + 1 queries', 0 do
let(:current_user) { user }
let(:additional_project) { create(:project, :public, group: create(:group)) }
end
@@ -233,20 +230,6 @@ RSpec.describe API::Projects do
expect(project_response['container_registry_enabled']).to eq(false)
end
- it 'reads projects.container_registry_enabled when read_container_registry_access_level is disabled' do
- stub_feature_flags(read_container_registry_access_level: false)
-
- project.project_feature.update!(container_registry_access_level: ProjectFeature::DISABLED)
- project.update_column(:container_registry_enabled, true)
-
- get api('/projects', user)
- project_response = json_response.find { |p| p['id'] == project.id }
-
- expect(response).to have_gitlab_http_status(:ok)
- expect(json_response).to be_an Array
- expect(project_response['container_registry_enabled']).to eq(true)
- end
-
it 'includes project topics' do
get api('/projects', user)
@@ -386,7 +369,7 @@ RSpec.describe API::Projects do
end
context 'when external issue tracker is enabled' do
- let!(:jira_service) { create(:jira_service, project: project) }
+ let!(:jira_integration) { create(:jira_integration, project: project) }
it 'includes open_issues_count' do
get api('/projects', user)
@@ -880,7 +863,7 @@ RSpec.describe API::Projects do
get api(url, current_user), params: params
link = response.header['Link']
- url = link&.match(/<[^>]+(\/projects\?[^>]+)>; rel="next"/) do |match|
+ url = link&.match(%r{<[^>]+(/projects\?[^>]+)>; rel="next"}) do |match|
match[1]
end
@@ -1016,7 +999,8 @@ RSpec.describe API::Projects do
request_access_enabled: true,
only_allow_merge_if_all_discussions_are_resolved: false,
ci_config_path: 'a/custom/path',
- merge_method: 'ff'
+ merge_method: 'ff',
+ squash_option: 'always'
}).tap do |attrs|
attrs[:operations_access_level] = 'disabled'
attrs[:analytics_access_level] = 'disabled'
@@ -2464,6 +2448,14 @@ RSpec.describe API::Projects do
describe 'GET /projects/:id/users' do
shared_examples_for 'project users response' do
+ let(:reporter_1) { create(:user) }
+ let(:reporter_2) { create(:user) }
+
+ before do
+ project.add_reporter(reporter_1)
+ project.add_reporter(reporter_2)
+ end
+
it 'returns the project users' do
get api("/projects/#{project.id}/users", current_user)
@@ -2472,12 +2464,15 @@ RSpec.describe API::Projects do
expect(response).to have_gitlab_http_status(:ok)
expect(response).to include_pagination_headers
expect(json_response).to be_an Array
- expect(json_response.size).to eq(1)
+ expect(json_response.size).to eq(3)
first_user = json_response.first
expect(first_user['username']).to eq(user.username)
expect(first_user['name']).to eq(user.name)
expect(first_user.keys).to include(*%w[name username id state avatar_url web_url])
+
+ ids = json_response.map { |raw_user| raw_user['id'] }
+ expect(ids).to eq([user.id, reporter_1.id, reporter_2.id])
end
end
@@ -2490,9 +2485,26 @@ RSpec.describe API::Projects do
context 'when authenticated' do
context 'valid request' do
- it_behaves_like 'project users response' do
- let(:project) { project4 }
- let(:current_user) { user4 }
+ context 'when sort_by_project_authorizations_user_id FF is off' do
+ before do
+ stub_feature_flags(sort_by_project_users_by_project_authorizations_user_id: false)
+ end
+
+ it_behaves_like 'project users response' do
+ let(:project) { project4 }
+ let(:current_user) { user4 }
+ end
+ end
+
+ context 'when sort_by_project_authorizations_user_id FF is on' do
+ before do
+ stub_feature_flags(sort_by_project_users_by_project_authorizations_user_id: true)
+ end
+
+ it_behaves_like 'project users response' do
+ let(:project) { project4 }
+ let(:current_user) { user4 }
+ end
end
end
@@ -3125,6 +3137,29 @@ RSpec.describe API::Projects do
expect(json_response['topics']).to eq(%w[topic2])
end
+
+ it 'updates squash_option' do
+ project3.update!(squash_option: 'always')
+
+ project_param = { squash_option: "default_on" }
+
+ expect { put api("/projects/#{project3.id}", user), params: project_param }
+ .to change { project3.reload.squash_option }
+ .from('always')
+ .to('default_on')
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(json_response['squash_option']).to eq("default_on")
+ end
+
+ it 'does not update an invalid squash_option' do
+ project_param = { squash_option: "jawn" }
+
+ expect { put api("/projects/#{project3.id}", user), params: project_param }
+ .not_to change { project3.reload.squash_option }
+
+ expect(response).to have_gitlab_http_status(:bad_request)
+ end
end
context 'when authenticated as project maintainer' do
diff --git a/spec/requests/api/pypi_packages_spec.rb b/spec/requests/api/pypi_packages_spec.rb
index 86925e6a0ba..e66326db2a2 100644
--- a/spec/requests/api/pypi_packages_spec.rb
+++ b/spec/requests/api/pypi_packages_spec.rb
@@ -14,6 +14,7 @@ RSpec.describe API::PypiPackages do
let_it_be(:deploy_token) { create(:deploy_token, read_package_registry: true, write_package_registry: true) }
let_it_be(:project_deploy_token) { create(:project_deploy_token, deploy_token: deploy_token, project: project) }
let_it_be(:job) { create(:ci_build, :running, user: user, project: project) }
+
let(:headers) { {} }
context 'simple API endpoint' do
@@ -117,6 +118,7 @@ RSpec.describe API::PypiPackages do
include_context 'workhorse headers'
let_it_be(:file_name) { 'package.whl' }
+
let(:url) { "/projects/#{project.id}/packages/pypi" }
let(:headers) { {} }
let(:requires_python) { '>=3.7' }
diff --git a/spec/requests/api/release/links_spec.rb b/spec/requests/api/release/links_spec.rb
index c03dd0331cf..00326426af5 100644
--- a/spec/requests/api/release/links_spec.rb
+++ b/spec/requests/api/release/links_spec.rb
@@ -5,6 +5,7 @@ require 'spec_helper'
RSpec.describe API::Release::Links do
let(:project) { create(:project, :repository, :private) }
let(:maintainer) { create(:user) }
+ let(:developer) { create(:user) }
let(:reporter) { create(:user) }
let(:non_project_member) { create(:user) }
let(:commit) { create(:commit, project: project) }
@@ -18,6 +19,7 @@ RSpec.describe API::Release::Links do
before do
project.add_maintainer(maintainer)
+ project.add_developer(developer)
project.add_reporter(reporter)
project.repository.add_tag(maintainer, 'v0.1', commit.id)
@@ -196,6 +198,28 @@ RSpec.describe API::Release::Links do
expect(response).to match_response_schema('release/link')
end
+ context 'with protected tag' do
+ context 'when user has access to the protected tag' do
+ let!(:protected_tag) { create(:protected_tag, :developers_can_create, name: '*', project: project) }
+
+ it 'accepts the request' do
+ post api("/projects/#{project.id}/releases/v0.1/assets/links", developer), params: params
+
+ expect(response).to have_gitlab_http_status(:created)
+ end
+ end
+
+ context 'when user does not have access to the protected tag' do
+ let!(:protected_tag) { create(:protected_tag, :maintainers_can_create, name: '*', project: project) }
+
+ it 'forbids the request' do
+ post api("/projects/#{project.id}/releases/v0.1/assets/links", developer), params: params
+
+ expect(response).to have_gitlab_http_status(:forbidden)
+ end
+ end
+ end
+
context 'when name is empty' do
let(:params) do
{
@@ -290,6 +314,28 @@ RSpec.describe API::Release::Links do
expect(response).to match_response_schema('release/link')
end
+ context 'with protected tag' do
+ context 'when user has access to the protected tag' do
+ let!(:protected_tag) { create(:protected_tag, :developers_can_create, name: '*', project: project) }
+
+ it 'accepts the request' do
+ put api("/projects/#{project.id}/releases/v0.1/assets/links/#{release_link.id}", developer), params: params
+
+ expect(response).to have_gitlab_http_status(:ok)
+ end
+ end
+
+ context 'when user does not have access to the protected tag' do
+ let!(:protected_tag) { create(:protected_tag, :maintainers_can_create, name: '*', project: project) }
+
+ it 'forbids the request' do
+ put api("/projects/#{project.id}/releases/v0.1/assets/links/#{release_link.id}", developer), params: params
+
+ expect(response).to have_gitlab_http_status(:forbidden)
+ end
+ end
+ end
+
context 'when params is empty' do
let(:params) { {} }
@@ -365,6 +411,28 @@ RSpec.describe API::Release::Links do
expect(response).to match_response_schema('release/link')
end
+ context 'with protected tag' do
+ context 'when user has access to the protected tag' do
+ let!(:protected_tag) { create(:protected_tag, :developers_can_create, name: '*', project: project) }
+
+ it 'accepts the request' do
+ delete api("/projects/#{project.id}/releases/v0.1/assets/links/#{release_link.id}", developer)
+
+ expect(response).to have_gitlab_http_status(:ok)
+ end
+ end
+
+ context 'when user does not have access to the protected tag' do
+ let!(:protected_tag) { create(:protected_tag, :maintainers_can_create, name: '*', project: project) }
+
+ it 'forbids the request' do
+ delete api("/projects/#{project.id}/releases/v0.1/assets/links/#{release_link.id}", developer)
+
+ expect(response).to have_gitlab_http_status(:forbidden)
+ end
+ end
+ end
+
context 'when there are no corresponding release link' do
let!(:release_link) { }
diff --git a/spec/requests/api/releases_spec.rb b/spec/requests/api/releases_spec.rb
index 81a4fcdbcac..03e0954e5ab 100644
--- a/spec/requests/api/releases_spec.rb
+++ b/spec/requests/api/releases_spec.rb
@@ -463,9 +463,23 @@ RSpec.describe API::Releases do
end
context 'when specified tag is not found in the project' do
- it 'cannot find the release entry' do
+ it 'returns 404 for maintater' do
get api("/projects/#{project.id}/releases/non_exist_tag", maintainer)
+ expect(response).to have_gitlab_http_status(:not_found)
+ expect(json_response['message']).to eq('404 Not Found')
+ end
+
+ it 'returns project not found for no user' do
+ get api("/projects/#{project.id}/releases/non_exist_tag", nil)
+
+ expect(response).to have_gitlab_http_status(:not_found)
+ expect(json_response['message']).to eq('404 Project Not Found')
+ end
+
+ it 'returns forbidden for guest' do
+ get api("/projects/#{project.id}/releases/non_existing_tag", guest)
+
expect(response).to have_gitlab_http_status(:forbidden)
end
end
@@ -662,6 +676,28 @@ RSpec.describe API::Releases do
end.not_to change { Project.find_by_id(project.id).repository.tag_count }
end
+ context 'with protected tag' do
+ context 'when user has access to the protected tag' do
+ let!(:protected_tag) { create(:protected_tag, :developers_can_create, name: '*', project: project) }
+
+ it 'accepts the request' do
+ post api("/projects/#{project.id}/releases", developer), params: params
+
+ expect(response).to have_gitlab_http_status(:created)
+ end
+ end
+
+ context 'when user does not have access to the protected tag' do
+ let!(:protected_tag) { create(:protected_tag, :maintainers_can_create, name: '*', project: project) }
+
+ it 'forbids the request' do
+ post api("/projects/#{project.id}/releases", developer), params: params
+
+ expect(response).to have_gitlab_http_status(:forbidden)
+ end
+ end
+ end
+
context 'when user is a reporter' do
it 'forbids the request' do
post api("/projects/#{project.id}/releases", reporter), params: params
@@ -1000,6 +1036,28 @@ RSpec.describe API::Releases do
expect(project.releases.last.released_at).to eq('2015-10-10T05:00:00Z')
end
+ context 'with protected tag' do
+ context 'when user has access to the protected tag' do
+ let!(:protected_tag) { create(:protected_tag, :developers_can_create, name: '*', project: project) }
+
+ it 'accepts the request' do
+ put api("/projects/#{project.id}/releases/v0.1", developer), params: params
+
+ expect(response).to have_gitlab_http_status(:ok)
+ end
+ end
+
+ context 'when user does not have access to the protected tag' do
+ let!(:protected_tag) { create(:protected_tag, :maintainers_can_create, name: '*', project: project) }
+
+ it 'forbids the request' do
+ put api("/projects/#{project.id}/releases/v0.1", developer), params: params
+
+ expect(response).to have_gitlab_http_status(:forbidden)
+ end
+ end
+ end
+
context 'when user tries to update sha' do
let(:params) { { sha: 'xxx' } }
@@ -1180,6 +1238,28 @@ RSpec.describe API::Releases do
expect(response).to match_response_schema('public_api/v4/release')
end
+ context 'with protected tag' do
+ context 'when user has access to the protected tag' do
+ let!(:protected_tag) { create(:protected_tag, :developers_can_create, name: '*', project: project) }
+
+ it 'accepts the request' do
+ delete api("/projects/#{project.id}/releases/v0.1", developer)
+
+ expect(response).to have_gitlab_http_status(:ok)
+ end
+ end
+
+ context 'when user does not have access to the protected tag' do
+ let!(:protected_tag) { create(:protected_tag, :maintainers_can_create, name: '*', project: project) }
+
+ it 'forbids the request' do
+ delete api("/projects/#{project.id}/releases/v0.1", developer)
+
+ expect(response).to have_gitlab_http_status(:forbidden)
+ end
+ end
+ end
+
context 'when there are no corresponding releases' do
let!(:release) { }
diff --git a/spec/requests/api/repositories_spec.rb b/spec/requests/api/repositories_spec.rb
index 1b96efeca22..d019e89e0b4 100644
--- a/spec/requests/api/repositories_spec.rb
+++ b/spec/requests/api/repositories_spec.rb
@@ -477,6 +477,17 @@ RSpec.describe API::Repositories do
let(:request) { get api(route, guest) }
end
end
+
+ context 'api_caching_rate_limit_repository_compare is disabled' do
+ before do
+ stub_feature_flags(api_caching_rate_limit_repository_compare: false)
+ end
+
+ it_behaves_like 'repository compare' do
+ let(:project) { create(:project, :public, :repository) }
+ let(:current_user) { nil }
+ end
+ end
end
describe 'GET /projects/:id/repository/contributors' do
diff --git a/spec/requests/api/resource_access_tokens_spec.rb b/spec/requests/api/resource_access_tokens_spec.rb
index 1a3c805fe9f..23061ab4bf0 100644
--- a/spec/requests/api/resource_access_tokens_spec.rb
+++ b/spec/requests/api/resource_access_tokens_spec.rb
@@ -38,6 +38,7 @@ RSpec.describe API::ResourceAccessTokens do
expect(api_get_token["name"]).to eq(token.name)
expect(api_get_token["scopes"]).to eq(token.scopes)
+ expect(api_get_token["access_level"]).to eq(project.team.max_member_access(token.user.id))
expect(api_get_token["expires_at"]).to eq(token.expires_at.to_date.iso8601)
expect(api_get_token).not_to have_key('token')
end
@@ -211,8 +212,9 @@ RSpec.describe API::ResourceAccessTokens do
end
describe "POST projects/:id/access_tokens" do
- let(:params) { { name: "test", scopes: ["api"], expires_at: expires_at } }
+ let(:params) { { name: "test", scopes: ["api"], expires_at: expires_at, access_level: access_level } }
let(:expires_at) { 1.month.from_now }
+ let(:access_level) { 20 }
subject(:create_token) { post api("/projects/#{project_id}/access_tokens", user), params: params }
@@ -231,6 +233,7 @@ RSpec.describe API::ResourceAccessTokens do
expect(response).to have_gitlab_http_status(:created)
expect(json_response["name"]).to eq("test")
expect(json_response["scopes"]).to eq(["api"])
+ expect(json_response["access_level"]).to eq(20)
expect(json_response["expires_at"]).to eq(expires_at.to_date.iso8601)
expect(json_response["token"]).to be_present
end
@@ -248,6 +251,21 @@ RSpec.describe API::ResourceAccessTokens do
expect(json_response["expires_at"]).to eq(nil)
end
end
+
+ context "when 'access_level' is not set" do
+ let(:access_level) { nil }
+
+ it 'creates a project access token with the default access level', :aggregate_failures do
+ create_token
+
+ expect(response).to have_gitlab_http_status(:created)
+ expect(json_response["name"]).to eq("test")
+ expect(json_response["scopes"]).to eq(["api"])
+ expect(json_response["access_level"]).to eq(40)
+ expect(json_response["expires_at"]).to eq(expires_at.to_date.iso8601)
+ expect(json_response["token"]).to be_present
+ end
+ end
end
context "with invalid params" do
diff --git a/spec/requests/api/rubygem_packages_spec.rb b/spec/requests/api/rubygem_packages_spec.rb
index 7d863b55bbe..9b104520b52 100644
--- a/spec/requests/api/rubygem_packages_spec.rb
+++ b/spec/requests/api/rubygem_packages_spec.rb
@@ -14,6 +14,7 @@ RSpec.describe API::RubygemPackages do
let_it_be(:deploy_token) { create(:deploy_token, read_package_registry: true, write_package_registry: true) }
let_it_be(:project_deploy_token) { create(:project_deploy_token, deploy_token: deploy_token, project: project) }
let_it_be(:headers) { {} }
+
let(:snowplow_gitlab_standard_context) { { project: project, namespace: project.namespace, user: user } }
let(:tokens) do
@@ -244,6 +245,7 @@ RSpec.describe API::RubygemPackages do
let(:url) { "/projects/#{project.id}/packages/rubygems/api/v1/gems" }
let_it_be(:file_name) { 'package.gem' }
+
let(:headers) { {} }
let(:params) { { file: temp_file(file_name) } }
let(:file_key) { :file }
diff --git a/spec/requests/api/services_spec.rb b/spec/requests/api/services_spec.rb
index f7394fa0cb4..e550132e776 100644
--- a/spec/requests/api/services_spec.rb
+++ b/spec/requests/api/services_spec.rb
@@ -24,14 +24,14 @@ RSpec.describe API::Services do
expect(response).to have_gitlab_http_status(:forbidden)
end
- context 'project with services' do
+ context 'with integrations' do
let!(:active_integration) { create(:emails_on_push_integration, project: project, active: true) }
let!(:integration) { create(:custom_issue_tracker_integration, project: project, active: false) }
- it "returns a list of all active services" do
+ it "returns a list of all active integrations" do
get api("/projects/#{project.id}/services", user)
- aggregate_failures 'expect successful response with all active services' do
+ aggregate_failures 'expect successful response with all active integrations' do
expect(response).to have_gitlab_http_status(:ok)
expect(json_response).to be_an Array
expect(json_response.count).to eq(1)
@@ -42,41 +42,39 @@ RSpec.describe API::Services do
end
end
- Integration.available_services_names.each do |service|
- describe "PUT /projects/:id/services/#{service.dasherize}" do
- include_context service
+ Integration.available_integration_names.each do |integration|
+ describe "PUT /projects/:id/services/#{integration.dasherize}" do
+ include_context integration
- it "updates #{service} settings" do
- put api("/projects/#{project.id}/services/#{dashed_service}", user), params: service_attrs
+ it "updates #{integration} settings" do
+ put api("/projects/#{project.id}/services/#{dashed_integration}", user), params: integration_attrs
expect(response).to have_gitlab_http_status(:ok)
- current_service = project.integrations.first
- events = current_service.event_names.empty? ? ["foo"].freeze : current_service.event_names
+ current_integration = project.integrations.first
+ events = current_integration.event_names.empty? ? ["foo"].freeze : current_integration.event_names
query_strings = []
events.each do |event|
- query_strings << "#{event}=#{!current_service[event]}"
+ query_strings << "#{event}=#{!current_integration[event]}"
end
query_strings = query_strings.join('&')
- put api("/projects/#{project.id}/services/#{dashed_service}?#{query_strings}", user), params: service_attrs
+ put api("/projects/#{project.id}/services/#{dashed_integration}?#{query_strings}", user), params: integration_attrs
expect(response).to have_gitlab_http_status(:ok)
- expect(json_response['slug']).to eq(dashed_service)
+ expect(json_response['slug']).to eq(dashed_integration)
events.each do |event|
next if event == "foo"
- expect(project.integrations.first[event]).not_to eq(current_service[event]),
- "expected #{!current_service[event]} for event #{event} for service #{current_service.title}, got #{current_service[event]}"
+ expect(project.integrations.first[event]).not_to eq(current_integration[event]),
+ "expected #{!current_integration[event]} for event #{event} for service #{current_integration.title}, got #{current_integration[event]}"
end
end
it "returns if required fields missing" do
- attrs = service_attrs
-
- required_attributes = service_attrs_list.select do |attr|
- service_klass.validators_on(attr).any? do |v|
- v.class == ActiveRecord::Validations::PresenceValidator &&
+ required_attributes = integration_attrs_list.select do |attr|
+ integration_klass.validators_on(attr).any? do |v|
+ v.instance_of?(ActiveRecord::Validations::PresenceValidator) &&
# exclude presence validators with conditional since those are not really required
![:if, :unless].any? { |cond| v.options.include?(cond) }
end
@@ -85,85 +83,85 @@ RSpec.describe API::Services do
if required_attributes.empty?
expected_code = :ok
else
- attrs.delete(required_attributes.sample)
+ integration_attrs.delete(required_attributes.sample)
expected_code = :bad_request
end
- put api("/projects/#{project.id}/services/#{dashed_service}", user), params: attrs
+ put api("/projects/#{project.id}/services/#{dashed_integration}", user), params: integration_attrs
expect(response).to have_gitlab_http_status(expected_code)
end
end
- describe "DELETE /projects/:id/services/#{service.dasherize}" do
- include_context service
+ describe "DELETE /projects/:id/services/#{integration.dasherize}" do
+ include_context integration
before do
- initialize_service(service)
+ initialize_integration(integration)
end
- it "deletes #{service}" do
- delete api("/projects/#{project.id}/services/#{dashed_service}", user)
+ it "deletes #{integration}" do
+ delete api("/projects/#{project.id}/services/#{dashed_integration}", user)
expect(response).to have_gitlab_http_status(:no_content)
- project.send(service_method).reload
- expect(project.send(service_method).activated?).to be_falsey
+ project.send(integration_method).reload
+ expect(project.send(integration_method).activated?).to be_falsey
end
end
- describe "GET /projects/:id/services/#{service.dasherize}" do
- include_context service
+ describe "GET /projects/:id/services/#{integration.dasherize}" do
+ include_context integration
- let!(:initialized_service) { initialize_service(service, active: true) }
+ let!(:initialized_integration) { initialize_integration(integration, active: true) }
let_it_be(:project2) do
create(:project, creator_id: user.id, namespace: user.namespace)
end
- def deactive_service!
- return initialized_service.update!(active: false) unless initialized_service.is_a?(PrometheusService)
+ def deactive_integration!
+ return initialized_integration.update!(active: false) unless initialized_integration.is_a?(::Integrations::Prometheus)
- # PrometheusService sets `#active` itself within a `before_save`:
- initialized_service.manual_configuration = false
- initialized_service.save!
+ # Integrations::Prometheus sets `#active` itself within a `before_save`:
+ initialized_integration.manual_configuration = false
+ initialized_integration.save!
end
it 'returns authentication error when unauthenticated' do
- get api("/projects/#{project.id}/services/#{dashed_service}")
+ get api("/projects/#{project.id}/services/#{dashed_integration}")
expect(response).to have_gitlab_http_status(:unauthorized)
end
- it "returns all properties of active service #{service}" do
- get api("/projects/#{project.id}/services/#{dashed_service}", user)
+ it "returns all properties of active service #{integration}" do
+ get api("/projects/#{project.id}/services/#{dashed_integration}", user)
- expect(initialized_service).to be_active
+ expect(initialized_integration).to be_active
expect(response).to have_gitlab_http_status(:ok)
- expect(json_response['properties'].keys).to match_array(service_instance.api_field_names)
+ expect(json_response['properties'].keys).to match_array(integration_instance.api_field_names)
end
- it "returns all properties of inactive service #{service}" do
- deactive_service!
+ it "returns all properties of inactive integration #{integration}" do
+ deactive_integration!
- get api("/projects/#{project.id}/services/#{dashed_service}", user)
+ get api("/projects/#{project.id}/services/#{dashed_integration}", user)
- expect(initialized_service).not_to be_active
+ expect(initialized_integration).not_to be_active
expect(response).to have_gitlab_http_status(:ok)
- expect(json_response['properties'].keys).to match_array(service_instance.api_field_names)
+ expect(json_response['properties'].keys).to match_array(integration_instance.api_field_names)
end
- it "returns not found if service does not exist" do
- get api("/projects/#{project2.id}/services/#{dashed_service}", user)
+ it "returns not found if integration does not exist" do
+ get api("/projects/#{project2.id}/services/#{dashed_integration}", user)
expect(response).to have_gitlab_http_status(:not_found)
expect(json_response['message']).to eq('404 Service Not Found')
end
- it "returns not found if service exists but is in `Project#disabled_services`" do
+ it "returns not found if service exists but is in `Project#disabled_integrations`" do
expect_next_found_instance_of(Project) do |project|
- expect(project).to receive(:disabled_services).at_least(:once).and_return([service])
+ expect(project).to receive(:disabled_integrations).at_least(:once).and_return([integration])
end
- get api("/projects/#{project.id}/services/#{dashed_service}", user)
+ get api("/projects/#{project.id}/services/#{dashed_integration}", user)
expect(response).to have_gitlab_http_status(:not_found)
expect(json_response['message']).to eq('404 Service Not Found')
@@ -171,7 +169,7 @@ RSpec.describe API::Services do
it "returns error when authenticated but not a project owner" do
project.add_developer(user2)
- get api("/projects/#{project.id}/services/#{dashed_service}", user2)
+ get api("/projects/#{project.id}/services/#{dashed_integration}", user2)
expect(response).to have_gitlab_http_status(:forbidden)
end
@@ -179,10 +177,10 @@ RSpec.describe API::Services do
end
describe 'POST /projects/:id/services/:slug/trigger' do
- describe 'Mattermost Service' do
- let(:service_name) { 'mattermost_slash_commands' }
+ describe 'Mattermost integration' do
+ let(:integration_name) { 'mattermost_slash_commands' }
- context 'no service is available' do
+ context 'when no integration is available' do
it 'returns a not found message' do
post api("/projects/#{project.id}/services/idonotexist/trigger")
@@ -191,34 +189,34 @@ RSpec.describe API::Services do
end
end
- context 'the service exists' do
+ context 'when the integration exists' do
let(:params) { { token: 'token' } }
- context 'the service is not active' do
+ context 'when the integration is not active' do
before do
- project.create_mattermost_slash_commands_service(
+ project.create_mattermost_slash_commands_integration(
active: false,
properties: params
)
end
- it 'when the service is inactive' do
- post api("/projects/#{project.id}/services/#{service_name}/trigger"), params: params
+ it 'when the integration is inactive' do
+ post api("/projects/#{project.id}/services/#{integration_name}/trigger"), params: params
expect(response).to have_gitlab_http_status(:not_found)
end
end
- context 'the service is active' do
+ context 'when the integration is active' do
before do
- project.create_mattermost_slash_commands_service(
+ project.create_mattermost_slash_commands_integration(
active: true,
properties: params
)
end
it 'returns status 200' do
- post api("/projects/#{project.id}/services/#{service_name}/trigger"), params: params
+ post api("/projects/#{project.id}/services/#{integration_name}/trigger"), params: params
expect(response).to have_gitlab_http_status(:ok)
end
@@ -226,7 +224,7 @@ RSpec.describe API::Services do
context 'when the project can not be found' do
it 'returns a generic 404' do
- post api("/projects/404/services/#{service_name}/trigger"), params: params
+ post api("/projects/404/services/#{integration_name}/trigger"), params: params
expect(response).to have_gitlab_http_status(:not_found)
expect(json_response["message"]).to eq("404 Service Not Found")
@@ -235,18 +233,18 @@ RSpec.describe API::Services do
end
end
- describe 'Slack Service' do
- let(:service_name) { 'slack_slash_commands' }
+ describe 'Slack Integration' do
+ let(:integration_name) { 'slack_slash_commands' }
before do
- project.create_slack_slash_commands_service(
+ project.create_slack_slash_commands_integration(
active: true,
properties: { token: 'token' }
)
end
it 'returns status 200' do
- post api("/projects/#{project.id}/services/#{service_name}/trigger"), params: { token: 'token', text: 'help' }
+ post api("/projects/#{project.id}/services/#{integration_name}/trigger"), params: { token: 'token', text: 'help' }
expect(response).to have_gitlab_http_status(:ok)
expect(json_response['response_type']).to eq("ephemeral")
@@ -254,29 +252,29 @@ RSpec.describe API::Services do
end
end
- describe 'Mattermost service' do
- let(:service_name) { 'mattermost' }
+ describe 'Mattermost integration' do
+ let(:integration_name) { 'mattermost' }
let(:params) do
{ webhook: 'https://hook.example.com', username: 'username' }
end
before do
- project.create_mattermost_service(
+ project.create_mattermost_integration(
active: true,
properties: params
)
end
it 'accepts a username for update' do
- put api("/projects/#{project.id}/services/#{service_name}", user), params: params.merge(username: 'new_username')
+ put api("/projects/#{project.id}/services/#{integration_name}", user), params: params.merge(username: 'new_username')
expect(response).to have_gitlab_http_status(:ok)
expect(json_response['properties']['username']).to eq('new_username')
end
end
- describe 'Microsoft Teams service' do
- let(:service_name) { 'microsoft-teams' }
+ describe 'Microsoft Teams integration' do
+ let(:integration_name) { 'microsoft-teams' }
let(:params) do
{
webhook: 'https://hook.example.com',
@@ -286,29 +284,31 @@ RSpec.describe API::Services do
end
before do
- project.create_microsoft_teams_service(
+ project.create_microsoft_teams_integration(
active: true,
properties: params
)
end
it 'accepts branches_to_be_notified for update' do
- put api("/projects/#{project.id}/services/#{service_name}", user), params: params.merge(branches_to_be_notified: 'all')
+ put api("/projects/#{project.id}/services/#{integration_name}", user),
+ params: params.merge(branches_to_be_notified: 'all')
expect(response).to have_gitlab_http_status(:ok)
expect(json_response['properties']['branches_to_be_notified']).to eq('all')
end
it 'accepts notify_only_broken_pipelines for update' do
- put api("/projects/#{project.id}/services/#{service_name}", user), params: params.merge(notify_only_broken_pipelines: true)
+ put api("/projects/#{project.id}/services/#{integration_name}", user),
+ params: params.merge(notify_only_broken_pipelines: true)
expect(response).to have_gitlab_http_status(:ok)
expect(json_response['properties']['notify_only_broken_pipelines']).to eq(true)
end
end
- describe 'Hangouts Chat service' do
- let(:service_name) { 'hangouts-chat' }
+ describe 'Hangouts Chat integration' do
+ let(:integration_name) { 'hangouts-chat' }
let(:params) do
{
webhook: 'https://hook.example.com',
@@ -324,16 +324,38 @@ RSpec.describe API::Services do
end
it 'accepts branches_to_be_notified for update', :aggregate_failures do
- put api("/projects/#{project.id}/services/#{service_name}", user), params: params.merge(branches_to_be_notified: 'all')
+ put api("/projects/#{project.id}/services/#{integration_name}", user), params: params.merge(branches_to_be_notified: 'all')
expect(response).to have_gitlab_http_status(:ok)
expect(json_response['properties']['branches_to_be_notified']).to eq('all')
end
it 'only requires the webhook param' do
- put api("/projects/#{project.id}/services/#{service_name}", user), params: { webhook: 'https://hook.example.com' }
+ put api("/projects/#{project.id}/services/#{integration_name}", user), params: { webhook: 'https://hook.example.com' }
expect(response).to have_gitlab_http_status(:ok)
end
end
+
+ describe 'Pipelines Email Integration' do
+ let(:integration_name) { 'pipelines-email' }
+
+ context 'notify_only_broken_pipelines property was saved as a string' do
+ before do
+ project.create_pipelines_email_integration(
+ active: false,
+ properties: {
+ "notify_only_broken_pipelines": "true",
+ "branches_to_be_notified": "default"
+ }
+ )
+ end
+
+ it 'returns boolean values for notify_only_broken_pipelines' do
+ get api("/projects/#{project.id}/services/#{integration_name}", user)
+
+ expect(json_response['properties']['notify_only_broken_pipelines']).to eq(true)
+ end
+ end
+ end
end
diff --git a/spec/requests/api/settings_spec.rb b/spec/requests/api/settings_spec.rb
index 4a4aeaea714..4008b57a1cf 100644
--- a/spec/requests/api/settings_spec.rb
+++ b/spec/requests/api/settings_spec.rb
@@ -127,6 +127,8 @@ RSpec.describe API::Settings, 'Settings', :do_not_mock_admin_mode_setting do
spam_check_endpoint_enabled: true,
spam_check_endpoint_url: 'grpc://example.com/spam_check',
spam_check_api_key: 'SPAM_CHECK_API_KEY',
+ mailgun_events_enabled: true,
+ mailgun_signing_key: 'MAILGUN_SIGNING_KEY',
disabled_oauth_sign_in_sources: 'unknown',
import_sources: 'github,bitbucket',
wiki_page_max_content_bytes: 12345,
@@ -175,6 +177,8 @@ RSpec.describe API::Settings, 'Settings', :do_not_mock_admin_mode_setting do
expect(json_response['spam_check_endpoint_enabled']).to be_truthy
expect(json_response['spam_check_endpoint_url']).to eq('grpc://example.com/spam_check')
expect(json_response['spam_check_api_key']).to eq('SPAM_CHECK_API_KEY')
+ expect(json_response['mailgun_events_enabled']).to be(true)
+ expect(json_response['mailgun_signing_key']).to eq('MAILGUN_SIGNING_KEY')
expect(json_response['disabled_oauth_sign_in_sources']).to eq([])
expect(json_response['import_sources']).to match_array(%w(github bitbucket))
expect(json_response['wiki_page_max_content_bytes']).to eq(12345)
@@ -493,6 +497,15 @@ RSpec.describe API::Settings, 'Settings', :do_not_mock_admin_mode_setting do
end
end
+ context "missing mailgun_signing_key value when mailgun_events_enabled is true" do
+ it "returns a blank parameter error message" do
+ put api("/application/settings", admin), params: { mailgun_events_enabled: true }
+
+ expect(response).to have_gitlab_http_status(:bad_request)
+ expect(json_response['error']).to eq('mailgun_signing_key is missing')
+ end
+ end
+
context "personal access token prefix settings" do
context "handles validation errors" do
it "fails to update the settings with too long prefix" do
diff --git a/spec/requests/api/snippets_spec.rb b/spec/requests/api/snippets_spec.rb
index 227c53f8fb9..f4d15d0525e 100644
--- a/spec/requests/api/snippets_spec.rb
+++ b/spec/requests/api/snippets_spec.rb
@@ -223,7 +223,7 @@ RSpec.describe API::Snippets, factory_default: :keep do
it 'commit the files to the repository' do
subject
- blob = snippet.repository.blob_at('master', file_path)
+ blob = snippet.repository.blob_at(snippet.default_branch, file_path)
expect(blob.data).to eq file_content
end
diff --git a/spec/requests/api/system_hooks_spec.rb b/spec/requests/api/system_hooks_spec.rb
index 3cea1af686e..1511872d183 100644
--- a/spec/requests/api/system_hooks_spec.rb
+++ b/spec/requests/api/system_hooks_spec.rb
@@ -81,6 +81,7 @@ RSpec.describe API::SystemHooks do
expect(json_response['push_events']).to be false
expect(json_response['tag_push_events']).to be false
expect(json_response['merge_requests_events']).to be false
+ expect(json_response['repository_update_events']).to be true
end
it 'sets explicit values for events' do
@@ -92,7 +93,8 @@ RSpec.describe API::SystemHooks do
enable_ssl_verification: false,
push_events: true,
tag_push_events: true,
- merge_requests_events: true
+ merge_requests_events: true,
+ repository_update_events: false
}
expect(response).to have_gitlab_http_status(:created)
@@ -100,6 +102,7 @@ RSpec.describe API::SystemHooks do
expect(json_response['push_events']).to be true
expect(json_response['tag_push_events']).to be true
expect(json_response['merge_requests_events']).to be true
+ expect(json_response['repository_update_events']).to be false
end
end
diff --git a/spec/requests/api/unleash_spec.rb b/spec/requests/api/unleash_spec.rb
index 9989f8d28bd..0718710f15c 100644
--- a/spec/requests/api/unleash_spec.rb
+++ b/spec/requests/api/unleash_spec.rb
@@ -6,6 +6,7 @@ RSpec.describe API::Unleash do
include FeatureFlagHelpers
let_it_be(:project, refind: true) { create(:project) }
+
let(:project_id) { project.id }
let(:params) { }
let(:headers) { }
diff --git a/spec/requests/api/users_spec.rb b/spec/requests/api/users_spec.rb
index d724cb9612c..383940ce34a 100644
--- a/spec/requests/api/users_spec.rb
+++ b/spec/requests/api/users_spec.rb
@@ -8,6 +8,7 @@ RSpec.describe API::Users do
let_it_be(:key) { create(:key, user: user) }
let_it_be(:gpg_key) { create(:gpg_key, user: user) }
let_it_be(:email) { create(:email, user: user) }
+
let(:omniauth_user) { create(:omniauth_user) }
let(:ldap_blocked_user) { create(:omniauth_user, provider: 'ldapmain', state: 'ldap_blocked') }
let(:private_user) { create(:user, private_profile: true) }
@@ -2967,6 +2968,7 @@ RSpec.describe API::Users do
let_it_be(:user) { create(:user) }
let_it_be(:project) { create(:project) }
let_it_be(:group) { create(:group) }
+
let(:requesting_user) { create(:user) }
before_all do
diff --git a/spec/requests/api/wikis_spec.rb b/spec/requests/api/wikis_spec.rb
index 64fde3db19f..ec34dc7e7a1 100644
--- a/spec/requests/api/wikis_spec.rb
+++ b/spec/requests/api/wikis_spec.rb
@@ -611,11 +611,12 @@ RSpec.describe API::Wikis do
let(:payload) { { file: fixture_file_upload('spec/fixtures/dk.png') } }
let(:url) { "/projects/#{project.id}/wikis/attachments" }
let(:file_path) { "#{Wikis::CreateAttachmentService::ATTACHMENT_PATH}/fixed_hex/dk.png" }
+ let(:branch) { wiki.default_branch }
let(:result_hash) do
{
file_name: 'dk.png',
file_path: file_path,
- branch: 'master',
+ branch: branch,
link: {
url: file_path,
markdown: "![dk](#{file_path})"
diff --git a/spec/requests/git_http_spec.rb b/spec/requests/git_http_spec.rb
index 40005596c3e..3fb683ea0fa 100644
--- a/spec/requests/git_http_spec.rb
+++ b/spec/requests/git_http_spec.rb
@@ -61,7 +61,7 @@ RSpec.describe 'Git HTTP requests' do
shared_examples 'operations are not allowed with expired password' do
context "when password is expired" do
it "responds to downloads with status 401 Unauthorized" do
- user.update!(password_expires_at: 2.days.ago)
+ user.update!(password_expires_at: 2.days.ago, password_automatically_set: true)
download(path, user: user.username, password: user.password) do |response|
expect(response).to have_gitlab_http_status(:unauthorized)
@@ -69,7 +69,7 @@ RSpec.describe 'Git HTTP requests' do
end
it "responds to uploads with status 401 Unauthorized" do
- user.update!(password_expires_at: 2.days.ago)
+ user.update!(password_expires_at: 2.days.ago, password_automatically_set: true)
upload(path, user: user.username, password: user.password) do |response|
expect(response).to have_gitlab_http_status(:unauthorized)
@@ -614,7 +614,7 @@ RSpec.describe 'Git HTTP requests' do
context "when password is expired" do
it "responds to downloads with status 401 unauthorized" do
- user.update!(password_expires_at: 2.days.ago)
+ user.update!(password_expires_at: 2.days.ago, password_automatically_set: true)
download(path, **env) do |response|
expect(response).to have_gitlab_http_status(:unauthorized)
@@ -697,7 +697,7 @@ RSpec.describe 'Git HTTP requests' do
context "when password is expired" do
it "responds to uploads with status 401 unauthorized" do
- user.update!(password_expires_at: 2.days.ago)
+ user.update!(password_expires_at: 2.days.ago, password_automatically_set: true)
write_access_token = create(:personal_access_token, user: user, scopes: [:write_repository])
@@ -889,10 +889,10 @@ RSpec.describe 'Git HTTP requests' do
context 'when admin mode is enabled', :enable_admin_mode do
it_behaves_like 'can download code only'
- it 'downloads from other project get status 404' do
+ it 'downloads from other project get status 403' do
clone_get "#{other_project.full_path}.git", user: 'gitlab-ci-token', password: build.token
- expect(response).to have_gitlab_http_status(:not_found)
+ expect(response).to have_gitlab_http_status(:forbidden)
end
end
@@ -920,7 +920,7 @@ RSpec.describe 'Git HTTP requests' do
context 'when users password is expired' do
it 'rejects pulls with 401 unauthorized' do
- user.update!(password_expires_at: 2.days.ago)
+ user.update!(password_expires_at: 2.days.ago, password_automatically_set: true)
download(path, user: 'gitlab-ci-token', password: build.token) do |response|
expect(response).to have_gitlab_http_status(:unauthorized)
@@ -1215,7 +1215,7 @@ RSpec.describe 'Git HTTP requests' do
context "when password is expired" do
it "responds to downloads with status 401 unauthorized" do
- user.update!(password_expires_at: 2.days.ago)
+ user.update!(password_expires_at: 2.days.ago, password_automatically_set: true)
download(path, **env) do |response|
expect(response).to have_gitlab_http_status(:unauthorized)
@@ -1298,7 +1298,7 @@ RSpec.describe 'Git HTTP requests' do
context "when password is expired" do
it "responds to uploads with status 401 unauthorized" do
- user.update!(password_expires_at: 2.days.ago)
+ user.update!(password_expires_at: 2.days.ago, password_automatically_set: true)
write_access_token = create(:personal_access_token, user: user, scopes: [:write_repository])
@@ -1490,10 +1490,10 @@ RSpec.describe 'Git HTTP requests' do
context 'when admin mode is enabled', :enable_admin_mode do
it_behaves_like 'can download code only'
- it 'downloads from other project get status 404' do
+ it 'downloads from other project get status 403' do
clone_get "#{other_project.full_path}.git", user: 'gitlab-ci-token', password: build.token
- expect(response).to have_gitlab_http_status(:not_found)
+ expect(response).to have_gitlab_http_status(:forbidden)
end
end
@@ -1521,7 +1521,7 @@ RSpec.describe 'Git HTTP requests' do
context 'when users password is expired' do
it 'rejects pulls with 401 unauthorized' do
- user.update!(password_expires_at: 2.days.ago)
+ user.update!(password_expires_at: 2.days.ago, password_automatically_set: true)
download(path, user: 'gitlab-ci-token', password: build.token) do |response|
expect(response).to have_gitlab_http_status(:unauthorized)
diff --git a/spec/requests/import/gitlab_groups_controller_spec.rb b/spec/requests/import/gitlab_groups_controller_spec.rb
index c65caf2ebf0..1f6487986a3 100644
--- a/spec/requests/import/gitlab_groups_controller_spec.rb
+++ b/spec/requests/import/gitlab_groups_controller_spec.rb
@@ -8,6 +8,7 @@ RSpec.describe Import::GitlabGroupsController do
include_context 'workhorse headers'
let_it_be(:user) { create(:user) }
+
let(:import_path) { "#{Dir.tmpdir}/gitlab_groups_controller_spec" }
before do
diff --git a/spec/requests/invite_registration_spec.rb b/spec/requests/invite_registration_spec.rb
deleted file mode 100644
index 167cf4b1de7..00000000000
--- a/spec/requests/invite_registration_spec.rb
+++ /dev/null
@@ -1,68 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-RSpec.describe 'Registering from an invite' do
- let(:com) { true }
-
- before do
- allow(Gitlab).to receive(:dev_env_or_com?).and_return(com)
- end
-
- describe 'GET /users/sign_up/invites/new' do
- subject(:request) { get '/users/sign_up/invites/new' }
-
- context 'when on .com' do
- it 'renders the template with expected text', :aggregate_failures do
- request
-
- expect(response).to render_template('layouts/simple_registration')
- expect(response).to render_template(:new)
- expect(response.body).to include('Join your team')
- end
- end
-
- context 'when not on .com' do
- let(:com) { false }
-
- it 'returns not found' do
- request
-
- expect(response).to have_gitlab_http_status(:not_found)
- end
- end
- end
-
- describe 'POST /users/sign_up/invites' do
- subject(:request) do
- post '/users/sign_up/invites',
- params: {
- user: {
- first_name: 'first',
- last_name: 'last',
- username: 'new_username',
- email: 'new@user.com',
- password: 'Any_password'
- }
- }
- end
-
- context 'when on .com' do
- it 'creates a user' do
- expect { request }.to change(User, :count).by(1)
-
- expect(response).to have_gitlab_http_status(:found)
- end
- end
-
- context 'when not on .com' do
- let(:com) { false }
-
- it 'returns not found' do
- request
-
- expect(response).to have_gitlab_http_status(:not_found)
- end
- end
- end
-end
diff --git a/spec/requests/jwt_controller_spec.rb b/spec/requests/jwt_controller_spec.rb
index 5b5658da97e..55577a5dc65 100644
--- a/spec/requests/jwt_controller_spec.rb
+++ b/spec/requests/jwt_controller_spec.rb
@@ -227,6 +227,7 @@ RSpec.describe JwtController do
let_it_be(:group_deploy_token) { create(:deploy_token, :group, groups: [group]) }
let_it_be(:project_deploy_token) { create(:deploy_token, :project, projects: [project]) }
let_it_be(:service_name) { 'dependency_proxy' }
+
let(:headers) { { authorization: credentials(credential_user, credential_password) } }
let(:params) { { account: credential_user, client_id: 'docker', offline_token: true, service: service_name } }
diff --git a/spec/requests/lfs_http_spec.rb b/spec/requests/lfs_http_spec.rb
index fda8b2ecec6..02eb4262690 100644
--- a/spec/requests/lfs_http_spec.rb
+++ b/spec/requests/lfs_http_spec.rb
@@ -105,6 +105,7 @@ RSpec.describe 'Git LFS API and storage' do
context 'when deploy key is authorized' do
let_it_be(:key) { create(:deploy_key) }
+
let(:authorization) { authorize_deploy_key }
before do
@@ -125,7 +126,7 @@ RSpec.describe 'Git LFS API and storage' do
it_behaves_like 'LFS http 200 blob response'
context 'when user password is expired' do
- let_it_be(:user) { create(:user, password_expires_at: 1.minute.ago)}
+ let_it_be(:user) { create(:user, password_expires_at: 1.minute.ago, password_automatically_set: true)}
it_behaves_like 'LFS http 401 response'
end
@@ -343,7 +344,8 @@ RSpec.describe 'Git LFS API and storage' do
end
context 'when user password is expired' do
- let_it_be(:user) { create(:user, password_expires_at: 1.minute.ago)}
+ let_it_be(:user) { create(:user, password_expires_at: 1.minute.ago, password_automatically_set: true)}
+
let(:role) { :reporter}
it_behaves_like 'LFS http 401 response'
@@ -351,6 +353,7 @@ RSpec.describe 'Git LFS API and storage' do
context 'when user is blocked' do
let_it_be(:user) { create(:user, :blocked)}
+
let(:role) { :reporter}
it_behaves_like 'LFS http 401 response'
@@ -405,6 +408,7 @@ RSpec.describe 'Git LFS API and storage' do
context 'administrator', :enable_admin_mode do
let_it_be(:user) { create(:admin) }
+
let(:build) { create(:ci_build, :running, pipeline: pipeline, user: user) }
it_behaves_like 'can download LFS only from own projects', renew_authorization: true
@@ -458,6 +462,7 @@ RSpec.describe 'Git LFS API and storage' do
describe 'upload' do
let_it_be(:project) { create(:project, :public) }
+
let(:body) { upload_body(sample_object) }
shared_examples 'pushes new LFS objects' do |renew_authorization:|
@@ -569,7 +574,7 @@ RSpec.describe 'Git LFS API and storage' do
let(:pipeline) { create(:ci_empty_pipeline, project: other_project) }
# I'm not sure what this tests that is different from the previous test
- it_behaves_like 'LFS http 404 response'
+ it_behaves_like 'LFS http 403 response'
end
end
@@ -953,7 +958,7 @@ RSpec.describe 'Git LFS API and storage' do
it_behaves_like 'LFS http 200 workhorse response'
context 'when user password is expired' do
- let_it_be(:user) { create(:user, password_expires_at: 1.minute.ago)}
+ let_it_be(:user) { create(:user, password_expires_at: 1.minute.ago, password_automatically_set: true) }
it_behaves_like 'LFS http 401 response'
end
@@ -984,6 +989,7 @@ RSpec.describe 'Git LFS API and storage' do
describe 'to a forked project' do
let_it_be(:upstream_project) { create(:project, :public) }
let_it_be(:project_owner) { create(:user) }
+
let(:project) { fork_project(upstream_project, project_owner) }
describe 'when user is authenticated' do
@@ -1043,7 +1049,7 @@ RSpec.describe 'Git LFS API and storage' do
let(:pipeline) { create(:ci_empty_pipeline, project: other_project) }
# I'm not sure what this tests that is different from the previous test
- it_behaves_like 'LFS http 404 response'
+ it_behaves_like 'LFS http 403 response'
end
end
diff --git a/spec/requests/product_analytics/collector_app_spec.rb b/spec/requests/product_analytics/collector_app_spec.rb
index b87610841e7..0d55d167a6f 100644
--- a/spec/requests/product_analytics/collector_app_spec.rb
+++ b/spec/requests/product_analytics/collector_app_spec.rb
@@ -4,6 +4,7 @@ require 'spec_helper'
RSpec.describe 'ProductAnalytics::CollectorApp' do
let_it_be(:project) { create(:project) }
+
let(:params) { {} }
let(:raw_event) { Gitlab::Json.parse(fixture_file('product_analytics/event.json')) }
diff --git a/spec/requests/projects/merge_requests/diffs_spec.rb b/spec/requests/projects/merge_requests/diffs_spec.rb
new file mode 100644
index 00000000000..3a64c88acc1
--- /dev/null
+++ b/spec/requests/projects/merge_requests/diffs_spec.rb
@@ -0,0 +1,126 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe 'Merge Requests Diffs' do
+ let_it_be(:project) { create(:project, :repository) }
+ let_it_be(:user) { create(:user) }
+ let_it_be(:merge_request) { create(:merge_request_with_diffs, target_project: project, source_project: project) }
+
+ before do
+ project.add_maintainer(user)
+ sign_in(user)
+ end
+
+ describe 'GET diffs_batch' do
+ let(:headers) { {} }
+
+ shared_examples_for 'serializes diffs with expected arguments' do
+ it 'serializes paginated merge request diff collection' do
+ expect_next_instance_of(PaginatedDiffSerializer) do |instance|
+ expect(instance).to receive(:represent)
+ .with(an_instance_of(collection), expected_options)
+ .and_call_original
+ end
+
+ subject
+ end
+ end
+
+ def collection_arguments(pagination_data = {})
+ {
+ environment: nil,
+ merge_request: merge_request,
+ diff_view: :inline,
+ merge_ref_head_diff: nil,
+ pagination_data: {
+ total_pages: nil
+ }.merge(pagination_data)
+ }
+ end
+
+ def go(extra_params = {})
+ params = {
+ namespace_id: project.namespace.to_param,
+ project_id: project,
+ id: merge_request.iid,
+ page: 0,
+ per_page: 20,
+ format: 'json'
+ }
+
+ get diffs_batch_namespace_project_json_merge_request_path(params.merge(extra_params)), headers: headers
+ end
+
+ context 'with caching', :use_clean_rails_memory_store_caching do
+ subject { go(page: 0, per_page: 5) }
+
+ context 'when the request has not been cached' do
+ it_behaves_like 'serializes diffs with expected arguments' do
+ let(:collection) { Gitlab::Diff::FileCollection::MergeRequestDiffBatch }
+ let(:expected_options) { collection_arguments(total_pages: 20) }
+ end
+ end
+
+ context 'when the request has already been cached' do
+ before do
+ go(page: 0, per_page: 5)
+ end
+
+ it 'does not serialize diffs' do
+ expect_next_instance_of(PaginatedDiffSerializer) do |instance|
+ expect(instance).not_to receive(:represent)
+ end
+
+ subject
+ end
+
+ context 'with the different pagination option' do
+ subject { go(page: 5, per_page: 5) }
+
+ it_behaves_like 'serializes diffs with expected arguments' do
+ let(:collection) { Gitlab::Diff::FileCollection::MergeRequestDiffBatch }
+ let(:expected_options) { collection_arguments(total_pages: 20) }
+ end
+ end
+
+ context 'with the different diff_view' do
+ subject { go(page: 0, per_page: 5, view: :parallel) }
+
+ it_behaves_like 'serializes diffs with expected arguments' do
+ let(:collection) { Gitlab::Diff::FileCollection::MergeRequestDiffBatch }
+ let(:expected_options) { collection_arguments(total_pages: 20).merge(diff_view: :parallel) }
+ end
+ end
+
+ context 'with the different expanded option' do
+ subject { go(page: 0, per_page: 5, expanded: true ) }
+
+ it_behaves_like 'serializes diffs with expected arguments' do
+ let(:collection) { Gitlab::Diff::FileCollection::MergeRequestDiffBatch }
+ let(:expected_options) { collection_arguments(total_pages: 20) }
+ end
+ end
+
+ context 'with the different ignore_whitespace_change option' do
+ subject { go(page: 0, per_page: 5, w: 1) }
+
+ it_behaves_like 'serializes diffs with expected arguments' do
+ let(:collection) { Gitlab::Diff::FileCollection::Compare }
+ let(:expected_options) { collection_arguments(total_pages: 20) }
+ end
+ end
+ end
+
+ context 'when the paths is given' do
+ subject { go(page: 0, per_page: 5, paths: %w[README CHANGELOG]) }
+
+ it 'does not use cache' do
+ expect(Rails.cache).not_to receive(:fetch).with(/cache:gitlab:PaginatedDiffSerializer/).and_call_original
+
+ subject
+ end
+ end
+ end
+ end
+end
diff --git a/spec/requests/projects/merge_requests_discussions_spec.rb b/spec/requests/projects/merge_requests_discussions_spec.rb
index eb8cf9f797d..595222a9eb2 100644
--- a/spec/requests/projects/merge_requests_discussions_spec.rb
+++ b/spec/requests/projects/merge_requests_discussions_spec.rb
@@ -52,5 +52,144 @@ RSpec.describe 'merge requests discussions' do
expect { send_request }
.to change { Gitlab::GitalyClient.get_request_count }.by_at_most(4)
end
+
+ context 'caching', :use_clean_rails_memory_store_caching do
+ let!(:first_note) { create(:diff_note_on_merge_request, noteable: merge_request, project: project) }
+ let!(:second_note) { create(:diff_note_on_merge_request, in_reply_to: first_note, noteable: merge_request, project: project) }
+ let!(:award_emoji) { create(:award_emoji, awardable: first_note) }
+
+ before do
+ # Make a request to cache the discussions
+ send_request
+ end
+
+ shared_examples 'cache miss' do
+ it 'does not hit a warm cache' do
+ expect_next_instance_of(DiscussionSerializer) do |serializer|
+ expect(serializer).to receive(:represent) do |arg|
+ expect(arg.notes).to contain_exactly(*changed_notes)
+ end.and_call_original
+ end
+
+ send_request
+ end
+ end
+
+ it 'gets cached on subsequent requests' do
+ expect_next_instance_of(DiscussionSerializer) do |serializer|
+ expect(serializer).not_to receive(:represent)
+ end
+
+ send_request
+ end
+
+ context 'when a note in a discussion got updated' do
+ before do
+ first_note.update!(updated_at: 1.minute.from_now)
+ end
+
+ it_behaves_like 'cache miss' do
+ let(:changed_notes) { [first_note, second_note] }
+ end
+ end
+
+ context 'when a note in a discussion got resolved' do
+ before do
+ travel_to(1.minute.from_now) do
+ first_note.resolve!(user)
+ end
+ end
+
+ it_behaves_like 'cache miss' do
+ let(:changed_notes) { [first_note, second_note] }
+ end
+ end
+
+ context 'when a note is added to a discussion' do
+ let!(:third_note) { create(:diff_note_on_merge_request, in_reply_to: first_note, noteable: merge_request, project: project) }
+
+ it_behaves_like 'cache miss' do
+ let(:changed_notes) { [first_note, second_note, third_note] }
+ end
+ end
+
+ context 'when a note is removed from a discussion' do
+ before do
+ second_note.destroy!
+ end
+
+ it_behaves_like 'cache miss' do
+ let(:changed_notes) { [first_note] }
+ end
+ end
+
+ context 'when an emoji is awarded to a note in discussion' do
+ before do
+ travel_to(1.minute.from_now) do
+ create(:award_emoji, awardable: first_note)
+ end
+ end
+
+ it_behaves_like 'cache miss' do
+ let(:changed_notes) { [first_note, second_note] }
+ end
+ end
+
+ context 'when an award emoji is removed from a note in discussion' do
+ before do
+ travel_to(1.minute.from_now) do
+ award_emoji.destroy!
+ end
+ end
+
+ it_behaves_like 'cache miss' do
+ let(:changed_notes) { [first_note, second_note] }
+ end
+ end
+
+ context 'when cached markdown version gets bump' do
+ before do
+ settings = Gitlab::CurrentSettings.current_application_settings
+ settings.update!(local_markdown_version: settings.local_markdown_version + 1)
+ end
+
+ it_behaves_like 'cache miss' do
+ let(:changed_notes) { [first_note, second_note] }
+ end
+ end
+
+ context 'when the diff note position changes' do
+ before do
+ # This replicates a position change wherein timestamps aren't updated
+ # which is why `Gitlab::Timeless.timeless` is utilized. This is the
+ # same approach being used in Discussions::UpdateDiffPositionService
+ # which is responsible for updating the positions of diff discussions
+ # when MR updates.
+ first_note.position = Gitlab::Diff::Position.new(
+ old_path: first_note.position.old_path,
+ new_path: first_note.position.new_path,
+ old_line: first_note.position.old_line,
+ new_line: first_note.position.new_line + 1,
+ diff_refs: first_note.position.diff_refs
+ )
+
+ Gitlab::Timeless.timeless(first_note, &:save)
+ end
+
+ it_behaves_like 'cache miss' do
+ let(:changed_notes) { [first_note, second_note] }
+ end
+ end
+
+ context 'when merge_request_discussion_cache is disabled' do
+ before do
+ stub_feature_flags(merge_request_discussion_cache: false)
+ end
+
+ it_behaves_like 'cache miss' do
+ let(:changed_notes) { [first_note, second_note] }
+ end
+ end
+ end
end
end
diff --git a/spec/requests/rack_attack_global_spec.rb b/spec/requests/rack_attack_global_spec.rb
index f24f815e9c6..f7b1b4726f6 100644
--- a/spec/requests/rack_attack_global_spec.rb
+++ b/spec/requests/rack_attack_global_spec.rb
@@ -221,6 +221,7 @@ RSpec.describe 'Rack Attack global throttles', :use_clean_rails_memory_store_cac
let_it_be(:token) { create(:personal_access_token, user: user) }
let_it_be(:other_user) { create(:user) }
let_it_be(:other_user_token) { create(:personal_access_token, user: other_user) }
+
let(:throttle_setting_prefix) { 'throttle_authenticated_api' }
let(:api_partial_url) { '/todos' }