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/support/shared_examples')
-rw-r--r--spec/support/shared_examples/controllers/uploads_actions_shared_examples.rb52
-rw-r--r--spec/support/shared_examples/features/comments_on_merge_request_files_shared_examples.rb2
-rw-r--r--spec/support/shared_examples/features/creatable_merge_request_shared_examples.rb2
-rw-r--r--spec/support/shared_examples/features/sidebar/sidebar_labels_shared_examples.rb5
-rw-r--r--spec/support/shared_examples/features/variable_list_shared_examples.rb2
-rw-r--r--spec/support/shared_examples/features/wiki/user_previews_wiki_changes_shared_examples.rb4
-rw-r--r--spec/support/shared_examples/graphql/boards_shared_examples.rb58
-rw-r--r--spec/support/shared_examples/graphql/mutations/can_mutate_spammable_examples.rb13
-rw-r--r--spec/support/shared_examples/graphql/mutations/security/ci_configuration_shared_examples.rb2
-rw-r--r--spec/support/shared_examples/integrations/integration_settings_form.rb47
-rw-r--r--spec/support/shared_examples/lib/gitlab/experimentation_shared_examples.rb8
-rw-r--r--spec/support/shared_examples/lib/gitlab/usage_data_counters/code_review_extension_request_examples.rb47
-rw-r--r--spec/support/shared_examples/lib/sidebars/projects/menus/zentao_menu_shared_examples.rb2
-rw-r--r--spec/support/shared_examples/loose_foreign_keys/have_loose_foreign_key.rb10
-rw-r--r--spec/support/shared_examples/models/concerns/analytics/cycle_analytics/stage_event_model_examples.rb18
-rw-r--r--spec/support/shared_examples/models/member_shared_examples.rb80
-rw-r--r--spec/support/shared_examples/models/note_access_check_shared_examples.rb4
-rw-r--r--spec/support/shared_examples/models/packages/debian/distribution_shared_examples.rb12
-rw-r--r--spec/support/shared_examples/models/update_project_statistics_shared_examples.rb4
-rw-r--r--spec/support/shared_examples/namespaces/traversal_scope_examples.rb47
-rw-r--r--spec/support/shared_examples/path_extraction_shared_examples.rb5
-rw-r--r--spec/support/shared_examples/policies/clusterable_shared_examples.rb14
-rw-r--r--spec/support/shared_examples/quick_actions/issuable/time_tracking_quick_action_shared_examples.rb8
-rw-r--r--spec/support/shared_examples/quick_actions/merge_request/rebase_quick_action_shared_examples.rb10
-rw-r--r--spec/support/shared_examples/requests/api/graphql/mutations/snippets_shared_examples.rb11
-rw-r--r--spec/support/shared_examples/requests/api/graphql/packages/group_and_project_packages_list_shared_examples.rb56
-rw-r--r--spec/support/shared_examples/requests/api/graphql/packages/package_details_shared_examples.rb12
-rw-r--r--spec/support/shared_examples/requests/api/notes_shared_examples.rb2
-rw-r--r--spec/support/shared_examples/requests/rack_attack_shared_examples.rb85
-rw-r--r--spec/support/shared_examples/services/boards/issues_move_service_shared_examples.rb13
-rw-r--r--spec/support/shared_examples/services/container_registry_auth_service_shared_examples.rb93
-rw-r--r--spec/support/shared_examples/services/incident_shared_examples.rb13
-rw-r--r--spec/support/shared_examples/views/registration_features_prompt_shared_examples.rb27
-rw-r--r--spec/support/shared_examples/workers/background_migration_worker_shared_examples.rb16
-rw-r--r--spec/support/shared_examples/workers/project_export_shared_examples.rb16
35 files changed, 657 insertions, 143 deletions
diff --git a/spec/support/shared_examples/controllers/uploads_actions_shared_examples.rb b/spec/support/shared_examples/controllers/uploads_actions_shared_examples.rb
index 62b35923bcd..5ed8dc7ce98 100644
--- a/spec/support/shared_examples/controllers/uploads_actions_shared_examples.rb
+++ b/spec/support/shared_examples/controllers/uploads_actions_shared_examples.rb
@@ -205,10 +205,30 @@ RSpec.shared_examples 'handle uploads' do
allow_any_instance_of(FileUploader).to receive(:image?).and_return(true)
end
- it "responds with status 200" do
- show_upload
+ context "enforce_auth_checks_on_uploads feature flag" do
+ context "with flag enabled" do
+ before do
+ stub_feature_flags(enforce_auth_checks_on_uploads: true)
+ end
- expect(response).to have_gitlab_http_status(:ok)
+ it "responds with status 302" do
+ show_upload
+
+ expect(response).to have_gitlab_http_status(:redirect)
+ end
+ end
+
+ context "with flag disabled" do
+ before do
+ stub_feature_flags(enforce_auth_checks_on_uploads: false)
+ end
+
+ it "responds with status 200" do
+ show_upload
+
+ expect(response).to have_gitlab_http_status(:ok)
+ end
+ end
end
end
@@ -276,10 +296,30 @@ RSpec.shared_examples 'handle uploads' do
allow_any_instance_of(FileUploader).to receive(:image?).and_return(true)
end
- it "responds with status 200" do
- show_upload
+ context "enforce_auth_checks_on_uploads feature flag" do
+ context "with flag enabled" do
+ before do
+ stub_feature_flags(enforce_auth_checks_on_uploads: true)
+ end
+
+ it "responds with status 404" do
+ show_upload
+
+ expect(response).to have_gitlab_http_status(:not_found)
+ end
+ end
+
+ context "with flag disabled" do
+ before do
+ stub_feature_flags(enforce_auth_checks_on_uploads: false)
+ end
+
+ it "responds with status 200" do
+ show_upload
- expect(response).to have_gitlab_http_status(:ok)
+ expect(response).to have_gitlab_http_status(:ok)
+ end
+ end
end
end
diff --git a/spec/support/shared_examples/features/comments_on_merge_request_files_shared_examples.rb b/spec/support/shared_examples/features/comments_on_merge_request_files_shared_examples.rb
index e0a032b1a43..8a07e52019c 100644
--- a/spec/support/shared_examples/features/comments_on_merge_request_files_shared_examples.rb
+++ b/spec/support/shared_examples/features/comments_on_merge_request_files_shared_examples.rb
@@ -2,7 +2,7 @@
RSpec.shared_examples 'comment on merge request file' do
it 'adds a comment' do
- click_diff_line(find("[id='#{sample_commit.line_code}']"))
+ click_diff_line(find_by_scrolling("[id='#{sample_commit.line_code}']"))
page.within('.js-discussion-note-form') do
fill_in(:note_note, with: 'Line is wrong')
diff --git a/spec/support/shared_examples/features/creatable_merge_request_shared_examples.rb b/spec/support/shared_examples/features/creatable_merge_request_shared_examples.rb
index 1c816ee4b0a..456175e7113 100644
--- a/spec/support/shared_examples/features/creatable_merge_request_shared_examples.rb
+++ b/spec/support/shared_examples/features/creatable_merge_request_shared_examples.rb
@@ -62,7 +62,7 @@ RSpec.shared_examples 'a creatable merge request' do
end
it 'updates the branches when selecting a new target project', :js do
- target_project_member = target_project.owner
+ target_project_member = target_project.first_owner
::Branches::CreateService.new(target_project, target_project_member)
.execute('a-brand-new-branch-to-test', 'master')
diff --git a/spec/support/shared_examples/features/sidebar/sidebar_labels_shared_examples.rb b/spec/support/shared_examples/features/sidebar/sidebar_labels_shared_examples.rb
index a9dac7a391f..281a70e46c4 100644
--- a/spec/support/shared_examples/features/sidebar/sidebar_labels_shared_examples.rb
+++ b/spec/support/shared_examples/features/sidebar/sidebar_labels_shared_examples.rb
@@ -54,7 +54,10 @@ RSpec.shared_examples 'labels sidebar widget' do
end
fill_in 'Search', with: 'Devel'
- sleep 1
+ expect(page).to have_css('.labels-fetch-loading')
+ wait_for_all_requests
+
+ expect(page).to have_css('[data-testid="dropdown-content"] .gl-new-dropdown-item')
expect(page.all(:css, '[data-testid="dropdown-content"] .gl-new-dropdown-item').length).to eq(1)
find_field('Search').native.send_keys(:enter)
diff --git a/spec/support/shared_examples/features/variable_list_shared_examples.rb b/spec/support/shared_examples/features/variable_list_shared_examples.rb
index 52451839281..c63faace6b2 100644
--- a/spec/support/shared_examples/features/variable_list_shared_examples.rb
+++ b/spec/support/shared_examples/features/variable_list_shared_examples.rb
@@ -166,7 +166,7 @@ RSpec.shared_examples 'variable list' do
wait_for_requests
expect(find('.flash-container')).to be_present
- expect(find('.flash-text').text).to have_content('Variables key (key) has already been taken')
+ expect(find('[data-testid="alert-danger"]').text).to have_content('Variables key (key) has already been taken')
end
it 'prevents a variable to be added if no values are provided when a variable is set to masked' do
diff --git a/spec/support/shared_examples/features/wiki/user_previews_wiki_changes_shared_examples.rb b/spec/support/shared_examples/features/wiki/user_previews_wiki_changes_shared_examples.rb
index 1a981f42086..2285d9a17e2 100644
--- a/spec/support/shared_examples/features/wiki/user_previews_wiki_changes_shared_examples.rb
+++ b/spec/support/shared_examples/features/wiki/user_previews_wiki_changes_shared_examples.rb
@@ -85,7 +85,9 @@ RSpec.shared_examples 'User previews wiki changes' do
end
it 'renders content with CommonMark' do
- fill_in :wiki_content, with: "1. one\n - sublist\n"
+ # using two `\n` ensures we're sublist to it's own line due
+ # to list auto-continue
+ fill_in :wiki_content, with: "1. one\n\n - sublist\n"
click_on "Preview"
# the above generates two separate lists (not embedded) in CommonMark
diff --git a/spec/support/shared_examples/graphql/boards_shared_examples.rb b/spec/support/shared_examples/graphql/boards_shared_examples.rb
new file mode 100644
index 00000000000..e8a4c17fb92
--- /dev/null
+++ b/spec/support/shared_examples/graphql/boards_shared_examples.rb
@@ -0,0 +1,58 @@
+# frozen_string_literal: true
+
+RSpec.shared_examples 'querying a GraphQL type recent boards' do
+ describe 'Get list of recently visited boards' do
+ let(:boards_data) { graphql_data[board_type]['recentIssueBoards']['nodes'] }
+
+ context 'when the request is correct' do
+ before do
+ visit_board
+ parent.add_reporter(user)
+ post_graphql(query, current_user: user)
+ end
+
+ it_behaves_like 'a working graphql query'
+
+ it 'returns recent boards for user successfully' do
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(graphql_errors).to be_nil
+ expect(boards_data.size).to eq(1)
+ expect(boards_data[0]['name']).to eq(board.name)
+ end
+ end
+
+ context 'when requests has errors' do
+ context 'when there are no recently visited boards' do
+ it 'returns empty result' do
+ post_graphql(query, current_user: user)
+
+ expect(response).to have_gitlab_http_status(:success)
+ expect(graphql_errors).to be_nil
+ expect(boards_data).to be_empty
+ end
+ end
+ end
+ end
+
+ def query(query_params: {}, full_path: parent.full_path)
+ board_nodes = <<~NODE
+ nodes {
+ name
+ }
+ NODE
+
+ graphql_query_for(
+ board_type.to_sym,
+ { full_path: full_path },
+ query_graphql_field(:recent_issue_boards, query_params, board_nodes)
+ )
+ end
+
+ def visit_board
+ if board_type == 'group'
+ create(:board_group_recent_visit, group: parent, board: board, user: user)
+ else
+ create(:board_project_recent_visit, project: parent, board: board, user: user)
+ end
+ end
+end
diff --git a/spec/support/shared_examples/graphql/mutations/can_mutate_spammable_examples.rb b/spec/support/shared_examples/graphql/mutations/can_mutate_spammable_examples.rb
index 011a2157f24..b17e59f0797 100644
--- a/spec/support/shared_examples/graphql/mutations/can_mutate_spammable_examples.rb
+++ b/spec/support/shared_examples/graphql/mutations/can_mutate_spammable_examples.rb
@@ -16,17 +16,4 @@ RSpec.shared_examples 'a mutation which can mutate a spammable' do
subject
end
end
-
- describe "#spam_action_response_fields" do
- it 'resolves with spam action fields' do
- subject
-
- # NOTE: We do not need to assert on the specific values of spam action fields here, we only need
- # to verify that #spam_action_response_fields was invoked and that the fields are present in the
- # response. The specific behavior of #spam_action_response_fields is covered in the
- # HasSpamActionResponseFields unit tests.
- expect(mutation_response.keys)
- .to include('spam', 'spamLogId', 'needsCaptchaResponse', 'captchaSiteKey')
- end
- end
end
diff --git a/spec/support/shared_examples/graphql/mutations/security/ci_configuration_shared_examples.rb b/spec/support/shared_examples/graphql/mutations/security/ci_configuration_shared_examples.rb
index 2bb3d807aa7..14b2663a72c 100644
--- a/spec/support/shared_examples/graphql/mutations/security/ci_configuration_shared_examples.rb
+++ b/spec/support/shared_examples/graphql/mutations/security/ci_configuration_shared_examples.rb
@@ -18,7 +18,7 @@ RSpec.shared_examples_for 'graphql mutations security ci configuration' do
ServiceResponse.success(payload: { branch: branch, success_path: success_path })
end
- let(:error) { "An error occured!" }
+ let(:error) { "An error occurred!" }
let(:service_error_response) do
ServiceResponse.error(message: error)
diff --git a/spec/support/shared_examples/integrations/integration_settings_form.rb b/spec/support/shared_examples/integrations/integration_settings_form.rb
new file mode 100644
index 00000000000..d0bb40e43ee
--- /dev/null
+++ b/spec/support/shared_examples/integrations/integration_settings_form.rb
@@ -0,0 +1,47 @@
+# frozen_string_literal: true
+
+RSpec.shared_examples 'integration settings form' do
+ include IntegrationsHelper
+ # Note: these specs don't validate channel fields
+ # which are present on a few integrations
+ it 'displays all the integrations' do
+ aggregate_failures do
+ integrations.each do |integration|
+ navigate_to_integration(integration)
+
+ page.within('form.integration-settings-form') do
+ expect(page).to have_field('Active', type: 'checkbox', wait: 0),
+ "#{integration.title} active field not present"
+
+ fields = parse_json(fields_for_integration(integration))
+ fields.each do |field|
+ field_name = field[:name]
+ expect(page).to have_field(field[:title], wait: 0),
+ "#{integration.title} field #{field_name} not present"
+ end
+
+ events = parse_json(trigger_events_for_integration(integration))
+ events.each do |trigger|
+ # normalizing the title because capybara location is case sensitive
+ title = normalize_title trigger[:title], integration
+
+ expect(page).to have_field(title, type: 'checkbox', wait: 0),
+ "#{integration.title} field #{title} checkbox not present"
+ end
+ end
+ end
+ end
+ end
+
+ private
+
+ def normalize_title(title, integration)
+ return 'Merge request' if integration.is_a?(Integrations::Jira) && title == 'merge_request'
+
+ title.titlecase
+ end
+
+ def parse_json(json)
+ Gitlab::Json.parse(json, symbolize_names: true)
+ end
+end
diff --git a/spec/support/shared_examples/lib/gitlab/experimentation_shared_examples.rb b/spec/support/shared_examples/lib/gitlab/experimentation_shared_examples.rb
index 5baa6478225..fdca326dbea 100644
--- a/spec/support/shared_examples/lib/gitlab/experimentation_shared_examples.rb
+++ b/spec/support/shared_examples/lib/gitlab/experimentation_shared_examples.rb
@@ -1,6 +1,10 @@
# frozen_string_literal: true
RSpec.shared_examples 'tracks assignment and records the subject' do |experiment, subject_type|
+ before do
+ stub_experiments(experiment => true)
+ end
+
it 'tracks the assignment', :experiment do
expect(experiment(experiment))
.to track(:assignment)
@@ -11,9 +15,7 @@ RSpec.shared_examples 'tracks assignment and records the subject' do |experiment
end
it 'records the subject' do
- stub_experiments(experiment => :candidate)
-
- expect(Experiment).to receive(:add_subject).with(experiment.to_s, variant: :experimental, subject: subject)
+ expect(Experiment).to receive(:add_subject).with(experiment.to_s, variant: anything, subject: subject)
action
end
diff --git a/spec/support/shared_examples/lib/gitlab/usage_data_counters/code_review_extension_request_examples.rb b/spec/support/shared_examples/lib/gitlab/usage_data_counters/code_review_extension_request_examples.rb
new file mode 100644
index 00000000000..6221366ab51
--- /dev/null
+++ b/spec/support/shared_examples/lib/gitlab/usage_data_counters/code_review_extension_request_examples.rb
@@ -0,0 +1,47 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.shared_examples 'a request from an extension' do |event|
+ before do
+ stub_application_setting(usage_ping_enabled: true)
+ end
+
+ def count_unique(date_from:, date_to:)
+ Gitlab::UsageDataCounters::HLLRedisCounter.unique_events(event_names: action, start_date: date_from, end_date: date_to)
+ end
+
+ def track_action(params)
+ described_class.track_api_request_when_trackable(**params)
+ end
+
+ it 'tracks when the user agent is matching' do
+ aggregate_failures do
+ expect(track_action(user: user1, **user_agent)).to be_truthy
+ expect(track_action(user: user1, **user_agent)).to be_truthy
+ expect(track_action(user: user2, **user_agent)).to be_truthy
+
+ expect(count_unique(date_from: time - 1.week, date_to: time + 1.week)).to eq(2)
+ end
+ end
+
+ it 'does not track when the user agent is not matching' do
+ aggregate_failures do
+ user_agent = { user_agent: 'normal_user_agent' }
+
+ expect(track_action(user: user1, **user_agent)).to be_falsey
+ expect(track_action(user: user1, **user_agent)).to be_falsey
+ expect(track_action(user: user2, **user_agent)).to be_falsey
+
+ expect(count_unique(date_from: time - 1.week, date_to: time + 1.week)).to eq(0)
+ end
+ end
+
+ it 'does not track if user agent is not present' do
+ expect(track_action(user: nil, user_agent: nil)).to be_nil
+ end
+
+ it 'does not track if user is not present' do
+ expect(track_action(user: nil, **user_agent)).to be_nil
+ end
+end
diff --git a/spec/support/shared_examples/lib/sidebars/projects/menus/zentao_menu_shared_examples.rb b/spec/support/shared_examples/lib/sidebars/projects/menus/zentao_menu_shared_examples.rb
index d3fd28727b5..b4c438771ce 100644
--- a/spec/support/shared_examples/lib/sidebars/projects/menus/zentao_menu_shared_examples.rb
+++ b/spec/support/shared_examples/lib/sidebars/projects/menus/zentao_menu_shared_examples.rb
@@ -4,7 +4,7 @@ require 'spec_helper'
RSpec.shared_examples 'ZenTao menu with CE version' do
let(:project) { create(:project, has_external_issue_tracker: true) }
- let(:user) { project.owner }
+ let(:user) { project.first_owner }
let(:context) { Sidebars::Projects::Context.new(current_user: user, container: project) }
let(:zentao_integration) { create(:zentao_integration, project: project) }
diff --git a/spec/support/shared_examples/loose_foreign_keys/have_loose_foreign_key.rb b/spec/support/shared_examples/loose_foreign_keys/have_loose_foreign_key.rb
index 42eec74e64f..5f59d43ad19 100644
--- a/spec/support/shared_examples/loose_foreign_keys/have_loose_foreign_key.rb
+++ b/spec/support/shared_examples/loose_foreign_keys/have_loose_foreign_key.rb
@@ -7,6 +7,12 @@ RSpec.shared_examples 'it has loose foreign keys' do
let(:fully_qualified_table_name) { "#{connection.current_schema}.#{table_name}" }
let(:deleted_records) { LooseForeignKeys::DeletedRecord.where(fully_qualified_table_name: fully_qualified_table_name) }
+ around do |example|
+ LooseForeignKeys::DeletedRecord.using_connection(connection) do
+ example.run
+ end
+ end
+
it 'has at least one loose foreign key definition' do
definitions = Gitlab::Database::LooseForeignKeys.definitions_by_table[table_name]
expect(definitions.size).to be > 0
@@ -69,7 +75,9 @@ RSpec.shared_examples 'cleanup by a loose foreign key' do
expect(find_model).to be_present
- LooseForeignKeys::ProcessDeletedRecordsService.new(connection: model.connection).execute
+ LooseForeignKeys::DeletedRecord.using_connection(parent.connection) do
+ LooseForeignKeys::ProcessDeletedRecordsService.new(connection: parent.connection).execute
+ end
if foreign_key_definition.on_delete.eql?(:async_delete)
expect(find_model).not_to be_present
diff --git a/spec/support/shared_examples/models/concerns/analytics/cycle_analytics/stage_event_model_examples.rb b/spec/support/shared_examples/models/concerns/analytics/cycle_analytics/stage_event_model_examples.rb
index d823e7ac221..8ff30021d6e 100644
--- a/spec/support/shared_examples/models/concerns/analytics/cycle_analytics/stage_event_model_examples.rb
+++ b/spec/support/shared_examples/models/concerns/analytics/cycle_analytics/stage_event_model_examples.rb
@@ -178,4 +178,22 @@ RSpec.shared_examples 'StageEventModel' do
end
end
end
+
+ describe '#total_time' do
+ it 'calcualtes total time from the start_event_timestamp and end_event_timestamp columns' do
+ model = described_class.new(start_event_timestamp: Time.new(2022, 1, 1, 12, 5, 0), end_event_timestamp: Time.new(2022, 1, 1, 12, 6, 30))
+
+ expect(model.total_time).to eq(90)
+ end
+
+ context 'when total time is calculated in SQL as an extra column' do
+ it 'returns the SQL calculated time' do
+ create(stage_event_factory) # rubocop:disable Rails/SaveBang
+
+ model = described_class.select('*, 5 AS total_time').first
+
+ expect(model.total_time).to eq(5)
+ end
+ end
+ end
end
diff --git a/spec/support/shared_examples/models/member_shared_examples.rb b/spec/support/shared_examples/models/member_shared_examples.rb
index 5b4b8c8fcc1..f7e09cfca62 100644
--- a/spec/support/shared_examples/models/member_shared_examples.rb
+++ b/spec/support/shared_examples/models/member_shared_examples.rb
@@ -301,8 +301,9 @@ RSpec.shared_examples_for "member creation" do
end
context 'when `tasks_to_be_done` and `tasks_project_id` are passed' do
+ let(:task_project) { source.is_a?(Group) ? create(:project, group: source) : source }
+
it 'creates a member_task with the correct attributes', :aggregate_failures do
- task_project = source.is_a?(Group) ? create(:project, group: source) : source
described_class.new(source, user, :developer, tasks_to_be_done: %w(ci code), tasks_project_id: task_project.id).execute
member = source.members.last
@@ -310,6 +311,43 @@ RSpec.shared_examples_for "member creation" do
expect(member.tasks_to_be_done).to match_array([:ci, :code])
expect(member.member_task.project).to eq(task_project)
end
+
+ context 'with an already existing member' do
+ before do
+ source.add_user(user, :developer)
+ end
+
+ it 'does not update tasks to be done if tasks already exist', :aggregate_failures do
+ member = source.members.find_by(user_id: user.id)
+ create(:member_task, member: member, project: task_project, tasks_to_be_done: %w(code ci))
+
+ expect do
+ described_class.new(source,
+ user,
+ :developer,
+ tasks_to_be_done: %w(issues),
+ tasks_project_id: task_project.id).execute
+ end.not_to change(MemberTask, :count)
+
+ member.reset
+ expect(member.tasks_to_be_done).to match_array([:code, :ci])
+ expect(member.member_task.project).to eq(task_project)
+ end
+
+ it 'adds tasks to be done if they do not exist', :aggregate_failures do
+ expect do
+ described_class.new(source,
+ user,
+ :developer,
+ tasks_to_be_done: %w(issues),
+ tasks_project_id: task_project.id).execute
+ end.to change(MemberTask, :count).by(1)
+
+ member = source.members.find_by(user_id: user.id)
+ expect(member.tasks_to_be_done).to match_array([:issues])
+ expect(member.member_task.project).to eq(task_project)
+ end
+ end
end
end
end
@@ -393,14 +431,52 @@ RSpec.shared_examples_for "bulk member creation" do
end
context 'when `tasks_to_be_done` and `tasks_project_id` are passed' do
+ let(:task_project) { source.is_a?(Group) ? create(:project, group: source) : source }
+
it 'creates a member_task with the correct attributes', :aggregate_failures do
- task_project = source.is_a?(Group) ? create(:project, group: source) : source
members = described_class.add_users(source, [user1], :developer, tasks_to_be_done: %w(ci code), tasks_project_id: task_project.id)
member = members.last
expect(member.tasks_to_be_done).to match_array([:ci, :code])
expect(member.member_task.project).to eq(task_project)
end
+
+ context 'with an already existing member' do
+ before do
+ source.add_user(user1, :developer)
+ end
+
+ it 'does not update tasks to be done if tasks already exist', :aggregate_failures do
+ member = source.members.find_by(user_id: user1.id)
+ create(:member_task, member: member, project: task_project, tasks_to_be_done: %w(code ci))
+
+ expect do
+ described_class.add_users(source,
+ [user1.id],
+ :developer,
+ tasks_to_be_done: %w(issues),
+ tasks_project_id: task_project.id)
+ end.not_to change(MemberTask, :count)
+
+ member.reset
+ expect(member.tasks_to_be_done).to match_array([:code, :ci])
+ expect(member.member_task.project).to eq(task_project)
+ end
+
+ it 'adds tasks to be done if they do not exist', :aggregate_failures do
+ expect do
+ described_class.add_users(source,
+ [user1.id],
+ :developer,
+ tasks_to_be_done: %w(issues),
+ tasks_project_id: task_project.id)
+ end.to change(MemberTask, :count).by(1)
+
+ member = source.members.find_by(user_id: user1.id)
+ expect(member.tasks_to_be_done).to match_array([:issues])
+ expect(member.member_task.project).to eq(task_project)
+ end
+ end
end
end
end
diff --git a/spec/support/shared_examples/models/note_access_check_shared_examples.rb b/spec/support/shared_examples/models/note_access_check_shared_examples.rb
index 44edafe9091..0c9992b832f 100644
--- a/spec/support/shared_examples/models/note_access_check_shared_examples.rb
+++ b/spec/support/shared_examples/models/note_access_check_shared_examples.rb
@@ -3,7 +3,7 @@
RSpec.shared_examples 'users with note access' do
it 'returns true' do
users.each do |user|
- expect(note.system_note_with_references_visible_for?(user)).to be_truthy
+ expect(note.system_note_visible_for?(user)).to be_truthy
expect(note.readable_by?(user)).to be_truthy
end
end
@@ -12,7 +12,7 @@ end
RSpec.shared_examples 'users without note access' do
it 'returns false' do
users.each do |user|
- expect(note.system_note_with_references_visible_for?(user)).to be_falsy
+ expect(note.system_note_visible_for?(user)).to be_falsy
expect(note.readable_by?(user)).to be_falsy
end
end
diff --git a/spec/support/shared_examples/models/packages/debian/distribution_shared_examples.rb b/spec/support/shared_examples/models/packages/debian/distribution_shared_examples.rb
index 3f8c3b8960b..6b0ae589efb 100644
--- a/spec/support/shared_examples/models/packages/debian/distribution_shared_examples.rb
+++ b/spec/support/shared_examples/models/packages/debian/distribution_shared_examples.rb
@@ -235,18 +235,6 @@ RSpec.shared_examples 'Debian Distribution' do |factory, container, can_freeze|
it 'does not return them' do
expect(subject.to_a).not_to include(package_file_pending_destruction)
end
-
- context 'with packages_installable_package_files disabled' do
- before do
- stub_feature_flags(packages_installable_package_files: false)
- end
-
- it 'returns them' do
- subject
-
- expect(subject.to_a).to include(package_file_pending_destruction)
- end
- end
end
end
end
diff --git a/spec/support/shared_examples/models/update_project_statistics_shared_examples.rb b/spec/support/shared_examples/models/update_project_statistics_shared_examples.rb
index 06326ffac97..ad0bbc0aeff 100644
--- a/spec/support/shared_examples/models/update_project_statistics_shared_examples.rb
+++ b/spec/support/shared_examples/models/update_project_statistics_shared_examples.rb
@@ -115,14 +115,14 @@ RSpec.shared_examples 'UpdateProjectStatistics' do |with_counter_attribute|
expect(ProjectStatistics)
.not_to receive(:increment_statistic)
- expect(Projects::DestroyService.new(project, project.owner).execute).to eq(true)
+ expect(Projects::DestroyService.new(project, project.first_owner).execute).to eq(true)
end
it 'does not schedule a namespace statistics worker' do
expect(Namespaces::ScheduleAggregationWorker)
.not_to receive(:perform_async)
- expect(Projects::DestroyService.new(project, project.owner).execute).to eq(true)
+ expect(Projects::DestroyService.new(project, project.first_owner).execute).to eq(true)
end
end
end
diff --git a/spec/support/shared_examples/namespaces/traversal_scope_examples.rb b/spec/support/shared_examples/namespaces/traversal_scope_examples.rb
index b43b7946e69..bcb5464ed5b 100644
--- a/spec/support/shared_examples/namespaces/traversal_scope_examples.rb
+++ b/spec/support/shared_examples/namespaces/traversal_scope_examples.rb
@@ -299,4 +299,51 @@ RSpec.shared_examples 'namespace traversal scopes' do
include_examples '.self_and_descendant_ids'
end
end
+
+ shared_examples '.self_and_hierarchy' do
+ let(:base_scope) { Group.where(id: base_groups) }
+
+ subject { base_scope.self_and_hierarchy }
+
+ context 'with ancestors only' do
+ let(:base_groups) { [group_1, group_2] }
+
+ it { is_expected.to match_array(groups) }
+ end
+
+ context 'with descendants only' do
+ let(:base_groups) { [deep_nested_group_1, deep_nested_group_2] }
+
+ it { is_expected.to match_array(groups) }
+ end
+
+ context 'nodes with both ancestors and descendants' do
+ let(:base_groups) { [nested_group_1, nested_group_2] }
+
+ it { is_expected.to match_array(groups) }
+ end
+
+ context 'with duplicate base groups' do
+ let(:base_groups) { [nested_group_1, nested_group_1] }
+
+ it { is_expected.to contain_exactly(group_1, nested_group_1, deep_nested_group_1) }
+ end
+ end
+
+ describe '.self_and_hierarchy' do
+ it_behaves_like '.self_and_hierarchy'
+
+ context "use_traversal_ids_for_self_and_hierarchy_scopes feature flag is false" do
+ before do
+ stub_feature_flags(use_traversal_ids_for_self_and_hierarchy_scopes: false)
+ end
+
+ it_behaves_like '.self_and_hierarchy'
+
+ it 'make recursive queries' do
+ base_groups = Group.where(id: nested_group_1)
+ expect { base_groups.self_and_hierarchy.load }.to make_queries_matching(/WITH RECURSIVE/)
+ end
+ end
+ end
end
diff --git a/spec/support/shared_examples/path_extraction_shared_examples.rb b/spec/support/shared_examples/path_extraction_shared_examples.rb
index 39c7c1f2a94..d76348aa26a 100644
--- a/spec/support/shared_examples/path_extraction_shared_examples.rb
+++ b/spec/support/shared_examples/path_extraction_shared_examples.rb
@@ -40,12 +40,13 @@ RSpec.shared_examples 'assigns ref vars' do
end
context 'path contains space' do
- let(:params) { { path: 'with space', ref: '38008cb17ce1466d8fec2dfa6f6ab8dcfe5cf49e' } }
+ let(:ref) { '38008cb17ce1466d8fec2dfa6f6ab8dcfe5cf49e' }
+ let(:path) { 'with space' }
it 'is not converted to %20 in @path' do
assign_ref_vars
- expect(@path).to eq(params[:path])
+ expect(@path).to eq(path)
end
end
diff --git a/spec/support/shared_examples/policies/clusterable_shared_examples.rb b/spec/support/shared_examples/policies/clusterable_shared_examples.rb
index b96aa71acbe..faf283f9059 100644
--- a/spec/support/shared_examples/policies/clusterable_shared_examples.rb
+++ b/spec/support/shared_examples/policies/clusterable_shared_examples.rb
@@ -6,12 +6,24 @@ RSpec.shared_examples 'clusterable policies' do
subject { described_class.new(current_user, clusterable) }
+ context 'with a reporter' do
+ before do
+ clusterable.add_reporter(current_user)
+ end
+
+ it { expect_disallowed(:read_cluster) }
+ it { expect_disallowed(:add_cluster) }
+ it { expect_disallowed(:create_cluster) }
+ it { expect_disallowed(:update_cluster) }
+ it { expect_disallowed(:admin_cluster) }
+ end
+
context 'with a developer' do
before do
clusterable.add_developer(current_user)
end
- it { expect_disallowed(:read_cluster) }
+ it { expect_allowed(:read_cluster) }
it { expect_disallowed(:add_cluster) }
it { expect_disallowed(:create_cluster) }
it { expect_disallowed(:update_cluster) }
diff --git a/spec/support/shared_examples/quick_actions/issuable/time_tracking_quick_action_shared_examples.rb b/spec/support/shared_examples/quick_actions/issuable/time_tracking_quick_action_shared_examples.rb
index 052fd0622d0..f414500f202 100644
--- a/spec/support/shared_examples/quick_actions/issuable/time_tracking_quick_action_shared_examples.rb
+++ b/spec/support/shared_examples/quick_actions/issuable/time_tracking_quick_action_shared_examples.rb
@@ -66,7 +66,7 @@ RSpec.shared_examples 'issuable time tracker' do |issuable_type|
it 'shows the help state when icon is clicked' do
page.within '.time-tracking-component-wrap' do
- find('.help-button').click
+ find('[data-testid="helpButton"]').click
expect(page).to have_content 'Track time with quick actions'
expect(page).to have_content 'Learn more'
end
@@ -92,8 +92,8 @@ RSpec.shared_examples 'issuable time tracker' do |issuable_type|
it 'hides the help state when close icon is clicked' do
page.within '.time-tracking-component-wrap' do
- find('.help-button').click
- find('.close-help-button').click
+ find('[data-testid="helpButton"]').click
+ find('[data-testid="closeHelpButton"]').click
expect(page).not_to have_content 'Track time with quick actions'
expect(page).not_to have_content 'Learn more'
@@ -102,7 +102,7 @@ RSpec.shared_examples 'issuable time tracker' do |issuable_type|
it 'displays the correct help url' do
page.within '.time-tracking-component-wrap' do
- find('.help-button').click
+ find('[data-testid="helpButton"]').click
expect(find_link('Learn more')[:href]).to have_content('/help/user/project/time_tracking.md')
end
diff --git a/spec/support/shared_examples/quick_actions/merge_request/rebase_quick_action_shared_examples.rb b/spec/support/shared_examples/quick_actions/merge_request/rebase_quick_action_shared_examples.rb
index 28decb4011d..2258bdd2c79 100644
--- a/spec/support/shared_examples/quick_actions/merge_request/rebase_quick_action_shared_examples.rb
+++ b/spec/support/shared_examples/quick_actions/merge_request/rebase_quick_action_shared_examples.rb
@@ -73,6 +73,16 @@ RSpec.shared_examples 'rebase quick action' do
expect(page).to have_content 'This merge request cannot be rebased while there are conflicts.'
end
end
+
+ context 'when the merge request branch is protected from force push' do
+ let!(:protected_branch) { create(:protected_branch, project: project, name: merge_request.source_branch, allow_force_push: false) }
+
+ it 'does not rebase the MR' do
+ add_note("/rebase")
+
+ expect(page).to have_content 'This merge request branch is protected from force push.'
+ end
+ end
end
context 'when the current user cannot rebase the MR' do
diff --git a/spec/support/shared_examples/requests/api/graphql/mutations/snippets_shared_examples.rb b/spec/support/shared_examples/requests/api/graphql/mutations/snippets_shared_examples.rb
index 8bffd1f71e9..a42a1fda62e 100644
--- a/spec/support/shared_examples/requests/api/graphql/mutations/snippets_shared_examples.rb
+++ b/spec/support/shared_examples/requests/api/graphql/mutations/snippets_shared_examples.rb
@@ -10,6 +10,8 @@ RSpec.shared_examples 'when the snippet is not found' do
end
RSpec.shared_examples 'snippet edit usage data counters' do
+ include SessionHelpers
+
context 'when user is sessionless' do
it 'does not track usage data actions' do
expect(::Gitlab::UsageDataCounters::EditorUniqueCounter).not_to receive(:track_snippet_editor_edit_action)
@@ -20,14 +22,7 @@ RSpec.shared_examples 'snippet edit usage data counters' do
context 'when user is not sessionless', :clean_gitlab_redis_sessions do
before do
- session_id = Rack::Session::SessionId.new('6919a6f1bb119dd7396fadc38fd18d0d')
- session_hash = { 'warden.user.user.key' => [[current_user.id], current_user.encrypted_password[0, 29]] }
-
- Gitlab::Redis::Sessions.with do |redis|
- redis.set("session:gitlab:#{session_id.private_id}", Marshal.dump(session_hash))
- end
-
- cookies[Gitlab::Application.config.session_options[:key]] = session_id.public_id
+ stub_session('warden.user.user.key' => [[current_user.id], current_user.encrypted_password[0, 29]])
end
it 'tracks usage data actions', :clean_gitlab_redis_sessions do
diff --git a/spec/support/shared_examples/requests/api/graphql/packages/group_and_project_packages_list_shared_examples.rb b/spec/support/shared_examples/requests/api/graphql/packages/group_and_project_packages_list_shared_examples.rb
index 882c79cb03f..127b1a6d4c4 100644
--- a/spec/support/shared_examples/requests/api/graphql/packages/group_and_project_packages_list_shared_examples.rb
+++ b/spec/support/shared_examples/requests/api/graphql/packages/group_and_project_packages_list_shared_examples.rb
@@ -3,11 +3,11 @@
RSpec.shared_examples 'group and project packages query' do
include GraphqlHelpers
- let_it_be(:versionaless_package) { create(:maven_package, project: project1, version: nil) }
- let_it_be(:maven_package) { create(:maven_package, project: project1, name: 'tab', version: '4.0.0', created_at: 5.days.ago) }
- let_it_be(:package) { create(:npm_package, project: project1, name: 'uab', version: '5.0.0', created_at: 4.days.ago) }
- let_it_be(:composer_package) { create(:composer_package, project: project2, name: 'vab', version: '6.0.0', created_at: 3.days.ago) }
- let_it_be(:debian_package) { create(:debian_package, project: project2, name: 'zab', version: '7.0.0', created_at: 2.days.ago) }
+ let_it_be(:versionless_package) { create(:maven_package, project: project1, version: nil) }
+ let_it_be(:maven_package) { create(:maven_package, project: project1, name: 'bab', version: '6.0.0', created_at: 1.day.ago) }
+ let_it_be(:npm_package) { create(:npm_package, project: project1, name: 'cab', version: '7.0.0', created_at: 4.days.ago) }
+ let_it_be(:composer_package) { create(:composer_package, project: project2, name: 'dab', version: '4.0.0', created_at: 3.days.ago) }
+ let_it_be(:debian_package) { create(:debian_package, project: project2, name: 'aab', version: '5.0.0', created_at: 2.days.ago) }
let_it_be(:composer_metadatum) do
create(:composer_metadatum, package: composer_package,
target_sha: 'afdeh',
@@ -21,11 +21,11 @@ RSpec.shared_examples 'group and project packages query' do
let(:fields) do
<<~QUERY
- count
- nodes {
- #{all_graphql_fields_for('packages'.classify, excluded: ['project'])}
- metadata { #{query_graphql_fragment('ComposerMetadata')} }
- }
+ count
+ nodes {
+ #{all_graphql_fields_for('packages'.classify, excluded: ['project'])}
+ metadata { #{query_graphql_fragment('ComposerMetadata')} }
+ }
QUERY
end
@@ -47,7 +47,7 @@ RSpec.shared_examples 'group and project packages query' do
it 'returns packages successfully' do
expect(package_names).to contain_exactly(
- package.name,
+ npm_package.name,
maven_package.name,
debian_package.name,
composer_package.name
@@ -88,7 +88,23 @@ RSpec.shared_examples 'group and project packages query' do
end
describe 'sorting and pagination' do
- let_it_be(:ascending_packages) { [maven_package, package, composer_package, debian_package].map { |package| global_id_of(package)} }
+ let_it_be(:packages_order_map) do
+ {
+ TYPE_ASC: [maven_package, npm_package, composer_package, debian_package],
+ TYPE_DESC: [debian_package, composer_package, npm_package, maven_package],
+
+ NAME_ASC: [debian_package, maven_package, npm_package, composer_package],
+ NAME_DESC: [composer_package, npm_package, maven_package, debian_package],
+
+ VERSION_ASC: [composer_package, debian_package, maven_package, npm_package],
+ VERSION_DESC: [npm_package, maven_package, debian_package, composer_package],
+
+ CREATED_ASC: [npm_package, composer_package, debian_package, maven_package],
+ CREATED_DESC: [maven_package, debian_package, composer_package, npm_package]
+ }
+ end
+
+ let(:expected_packages) { sorted_packages.map { |package| global_id_of(package) } }
let(:data_path) { [resource_type, :packages] }
@@ -96,22 +112,14 @@ RSpec.shared_examples 'group and project packages query' do
resource.add_reporter(current_user)
end
- [:CREATED_ASC, :NAME_ASC, :VERSION_ASC, :TYPE_ASC].each do |order|
+ [:CREATED_ASC, :NAME_ASC, :VERSION_ASC, :TYPE_ASC, :CREATED_DESC, :NAME_DESC, :VERSION_DESC, :TYPE_DESC].each do |order|
context "#{order}" do
- it_behaves_like 'sorted paginated query' do
- let(:sort_param) { order }
- let(:first_param) { 4 }
- let(:all_records) { ascending_packages }
- end
- end
- end
+ let(:sorted_packages) { packages_order_map.fetch(order) }
- [:CREATED_DESC, :NAME_DESC, :VERSION_DESC, :TYPE_DESC].each do |order|
- context "#{order}" do
it_behaves_like 'sorted paginated query' do
let(:sort_param) { order }
let(:first_param) { 4 }
- let(:all_records) { ascending_packages.reverse }
+ let(:all_records) { expected_packages }
end
end
end
@@ -180,7 +188,7 @@ RSpec.shared_examples 'group and project packages query' do
context 'include_versionless' do
let(:params) { { include_versionless: true } }
- it { is_expected.to include({ "name" => versionaless_package.name }) }
+ it { is_expected.to include({ "name" => versionless_package.name }) }
end
end
end
diff --git a/spec/support/shared_examples/requests/api/graphql/packages/package_details_shared_examples.rb b/spec/support/shared_examples/requests/api/graphql/packages/package_details_shared_examples.rb
index 9385706d991..ab93f54111b 100644
--- a/spec/support/shared_examples/requests/api/graphql/packages/package_details_shared_examples.rb
+++ b/spec/support/shared_examples/requests/api/graphql/packages/package_details_shared_examples.rb
@@ -49,17 +49,5 @@ RSpec.shared_examples 'a package with files' do
expect(response_package_file_ids).not_to include(package_file_pending_destruction.to_global_id.to_s)
end
-
- context 'with packages_installable_package_files disabled' do
- before(:context) do
- stub_feature_flags(packages_installable_package_files: false)
- end
-
- it 'returns them' do
- expect(package.reload.package_files).to include(package_file_pending_destruction)
-
- expect(response_package_file_ids).to include(package_file_pending_destruction.to_global_id.to_s)
- end
- end
end
end
diff --git a/spec/support/shared_examples/requests/api/notes_shared_examples.rb b/spec/support/shared_examples/requests/api/notes_shared_examples.rb
index 0434d0beb7e..2a157f6e855 100644
--- a/spec/support/shared_examples/requests/api/notes_shared_examples.rb
+++ b/spec/support/shared_examples/requests/api/notes_shared_examples.rb
@@ -190,7 +190,7 @@ RSpec.shared_examples 'noteable API' do |parent_type, noteable_type, id_name|
if parent_type == 'projects'
context 'by a project owner' do
- let(:user) { project.owner }
+ let(:user) { project.first_owner }
it 'sets the creation time on the new note' do
post api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/notes", user), params: params
diff --git a/spec/support/shared_examples/requests/rack_attack_shared_examples.rb b/spec/support/shared_examples/requests/rack_attack_shared_examples.rb
index b294467d482..c6c6c44dce8 100644
--- a/spec/support/shared_examples/requests/rack_attack_shared_examples.rb
+++ b/spec/support/shared_examples/requests/rack_attack_shared_examples.rb
@@ -580,3 +580,88 @@ RSpec.shared_examples 'rate-limited unauthenticated requests' do
end
end
end
+
+# Requires let variables:
+# * throttle_setting_prefix: "throttle_authenticated", "throttle_unauthenticated"
+RSpec.shared_examples 'rate-limited frontend API requests' do
+ let(:requests_per_period) { 1 }
+ let(:csrf_token) { SecureRandom.base64(ActionController::RequestForgeryProtection::AUTHENTICITY_TOKEN_LENGTH) }
+ let(:csrf_session) { { _csrf_token: csrf_token } }
+ let(:personal_access_token) { nil }
+
+ let(:api_path) { '/projects' }
+
+ # These don't actually exist, so a 404 is the expected response.
+ let(:files_api_path) { '/projects/1/repository/files/ref/path' }
+ let(:packages_api_path) { '/projects/1/packages/foo' }
+ let(:deprecated_api_path) { '/groups/1?with_projects=true' }
+
+ def get_api(path: api_path, csrf: false)
+ headers = csrf ? { 'X-CSRF-Token' => csrf_token } : nil
+ get api(path, personal_access_token: personal_access_token), headers: headers
+ end
+
+ def expect_not_found(&block)
+ yield
+
+ expect(response).to have_gitlab_http_status(:not_found)
+ end
+
+ before do
+ stub_application_setting(
+ "#{throttle_setting_prefix}_enabled" => true,
+ "#{throttle_setting_prefix}_requests_per_period" => requests_per_period,
+ "#{throttle_setting_prefix}_api_enabled" => true,
+ "#{throttle_setting_prefix}_api_requests_per_period" => requests_per_period,
+ "#{throttle_setting_prefix}_web_enabled" => true,
+ "#{throttle_setting_prefix}_web_requests_per_period" => requests_per_period,
+ "#{throttle_setting_prefix}_files_api_enabled" => true,
+ "#{throttle_setting_prefix}_packages_api_enabled" => true,
+ "#{throttle_setting_prefix}_deprecated_api_enabled" => true
+ )
+
+ stub_session(csrf_session)
+ end
+
+ context 'with a CSRF token' do
+ it 'uses the rate limit for web requests' do
+ requests_per_period.times { get_api csrf: true }
+
+ expect_rejection("#{throttle_setting_prefix}_web") { get_api csrf: true }
+ expect_rejection("#{throttle_setting_prefix}_web") { get_api csrf: true, path: files_api_path }
+ expect_rejection("#{throttle_setting_prefix}_web") { get_api csrf: true, path: packages_api_path }
+ expect_rejection("#{throttle_setting_prefix}_web") { get_api csrf: true, path: deprecated_api_path }
+
+ # API rate limit is not triggered yet
+ expect_ok { get_api }
+ expect_not_found { get_api path: files_api_path }
+ expect_not_found { get_api path: packages_api_path }
+ expect_not_found { get_api path: deprecated_api_path }
+ end
+
+ context 'without a CSRF session' do
+ let(:csrf_session) { nil }
+
+ it 'always uses the rate limit for API requests' do
+ requests_per_period.times { get_api csrf: true }
+
+ expect_rejection("#{throttle_setting_prefix}_api") { get_api csrf: true }
+ expect_rejection("#{throttle_setting_prefix}_api") { get_api }
+ end
+ end
+ end
+
+ context 'without a CSRF token' do
+ it 'uses the rate limit for API requests' do
+ requests_per_period.times { get_api }
+
+ expect_rejection("#{throttle_setting_prefix}_api") { get_api }
+
+ # Web and custom API rate limits are not triggered yet
+ expect_ok { get_api csrf: true }
+ expect_not_found { get_api path: files_api_path }
+ expect_not_found { get_api path: packages_api_path }
+ expect_not_found { get_api path: deprecated_api_path }
+ end
+ end
+end
diff --git a/spec/support/shared_examples/services/boards/issues_move_service_shared_examples.rb b/spec/support/shared_examples/services/boards/issues_move_service_shared_examples.rb
index d9b837258ce..a46c2f0ac5c 100644
--- a/spec/support/shared_examples/services/boards/issues_move_service_shared_examples.rb
+++ b/spec/support/shared_examples/services/boards/issues_move_service_shared_examples.rb
@@ -140,19 +140,6 @@ RSpec.shared_examples 'issues move service' do |group|
expect(issue2.reload.updated_at.change(usec: 0)).to eq updated_at2.change(usec: 0)
end
- if group
- context 'when on a group board' do
- it 'sends the board_group_id parameter' do
- params.merge!(move_after_id: issue1.id, move_before_id: issue2.id)
-
- match_params = { move_between_ids: [issue1.id, issue2.id], board_group_id: parent.id }
- expect(Issues::UpdateService).to receive(:new).with(project: issue.project, current_user: user, params: match_params).and_return(double(execute: build(:issue)))
-
- described_class.new(parent, user, params).execute(issue)
- end
- end
- end
-
def reorder_issues(params, issues: [])
issues.each do |issue|
issue.move_to_end && issue.save!
diff --git a/spec/support/shared_examples/services/container_registry_auth_service_shared_examples.rb b/spec/support/shared_examples/services/container_registry_auth_service_shared_examples.rb
index 87bf134eeb8..c808b9a5318 100644
--- a/spec/support/shared_examples/services/container_registry_auth_service_shared_examples.rb
+++ b/spec/support/shared_examples/services/container_registry_auth_service_shared_examples.rb
@@ -71,7 +71,6 @@ end
RSpec.shared_examples 'an accessible' do
before do
stub_feature_flags(container_registry_migration_phase1: false)
- stub_feature_flags(container_registry_cdn_redirect: false)
end
let(:access) do
@@ -164,10 +163,9 @@ RSpec.shared_examples 'a container registry auth service' do
before do
stub_feature_flags(container_registry_migration_phase1: false)
- stub_feature_flags(container_registry_cdn_redirect: false)
end
- describe '#full_access_token' do
+ describe '.full_access_token' do
let_it_be(:project) { create(:project) }
let(:token) { described_class.full_access_token(project.full_path) }
@@ -181,7 +179,26 @@ RSpec.shared_examples 'a container registry auth service' do
it_behaves_like 'not a container repository factory'
end
- describe '#pull_access_token' do
+ describe '.import_access_token' do
+ let(:access) do
+ [{ 'type' => 'registry',
+ 'name' => 'import',
+ 'actions' => ['*'] }]
+ end
+
+ let(:token) { described_class.import_access_token }
+
+ subject { { token: token } }
+
+ it_behaves_like 'a valid token'
+ it_behaves_like 'not a container repository factory'
+
+ it 'has the correct scope' do
+ expect(payload).to include('access' => access)
+ end
+ end
+
+ describe '.pull_access_token' do
let_it_be(:project) { create(:project) }
let(:token) { described_class.pull_access_token(project.full_path) }
@@ -1126,4 +1143,72 @@ RSpec.shared_examples 'a container registry auth service' do
end
end
end
+
+ context 'when importing' do
+ let_it_be(:container_repository) { create(:container_repository, :root, :importing) }
+ let_it_be(:current_project) { container_repository.project }
+ let_it_be(:current_user) { create(:user) }
+
+ before do
+ current_project.add_developer(current_user)
+ end
+
+ shared_examples 'containing the import error' do
+ it 'includes a helpful error message' do
+ expect(subject[:errors].first).to include(message: /Your repository is currently being migrated/)
+ end
+ end
+
+ context 'push request' do
+ let(:current_params) do
+ { scopes: ["repository:#{container_repository.path}:push"] }
+ end
+
+ it_behaves_like 'a forbidden' do
+ it_behaves_like 'containing the import error'
+ end
+ end
+
+ context 'delete request' do
+ let(:current_params) do
+ { scopes: ["repository:#{container_repository.path}:delete"] }
+ end
+
+ it_behaves_like 'a forbidden' do
+ it_behaves_like 'containing the import error'
+ end
+ end
+
+ context '* request' do
+ let(:current_params) do
+ { scopes: ["repository:#{container_repository.path}:*"] }
+ end
+
+ it_behaves_like 'a forbidden' do
+ it_behaves_like 'containing the import error'
+ end
+ end
+
+ context 'pull request' do
+ let(:current_params) do
+ { scopes: ["repository:#{container_repository.path}:pull"] }
+ end
+
+ let(:project) { current_project }
+
+ it_behaves_like 'a pullable'
+ end
+
+ context 'mixed request' do
+ let(:current_params) do
+ { scopes: ["repository:#{container_repository.path}:pull,push"] }
+ end
+
+ let(:project) { current_project }
+
+ it_behaves_like 'a forbidden' do
+ it_behaves_like 'containing the import error'
+ end
+ end
+ end
end
diff --git a/spec/support/shared_examples/services/incident_shared_examples.rb b/spec/support/shared_examples/services/incident_shared_examples.rb
index 36b0acf5a51..cc26cf87322 100644
--- a/spec/support/shared_examples/services/incident_shared_examples.rb
+++ b/spec/support/shared_examples/services/incident_shared_examples.rb
@@ -28,28 +28,15 @@ end
#
# include_examples 'not an incident issue'
RSpec.shared_examples 'not an incident issue' do
- let(:label_properties) { attributes_for(:label, :incident) }
-
it 'has not incident as issue type' do
expect(issue.issue_type).not_to eq('incident')
expect(issue.work_item_type.base_type).not_to eq('incident')
end
-
- it_behaves_like 'does not have incident label'
-end
-
-RSpec.shared_examples 'does not have incident label' do
- let(:label_properties) { attributes_for(:label, :incident) }
-
- it 'has not an incident label' do
- expect(issue.labels).not_to include(have_attributes(label_properties))
- end
end
# This shared example is to test the execution of incident management label services
# For example:
# - IncidentManagement::CreateIncidentSlaExceededLabelService
-# - IncidentManagement::CreateIncidentLabelService
# It doesn't require any defined variables
diff --git a/spec/support/shared_examples/views/registration_features_prompt_shared_examples.rb b/spec/support/shared_examples/views/registration_features_prompt_shared_examples.rb
new file mode 100644
index 00000000000..661a96266f1
--- /dev/null
+++ b/spec/support/shared_examples/views/registration_features_prompt_shared_examples.rb
@@ -0,0 +1,27 @@
+# frozen_string_literal: true
+
+RSpec.shared_examples 'renders registration features prompt' do |disabled_field|
+ it 'renders a placeholder input with registration features message', :aggregate_failures do
+ render
+
+ if disabled_field
+ expect(rendered).to have_field(disabled_field, disabled: true)
+ end
+
+ expect(rendered).to have_content(s_("RegistrationFeatures|Want to %{feature_title} for free?") % { feature_title: s_('RegistrationFeatures|use this feature') })
+ expect(rendered).to have_link(s_('RegistrationFeatures|Registration Features Program'))
+ end
+end
+
+RSpec.shared_examples 'does not render registration features prompt' do |disabled_field|
+ it 'does not render a placeholder input with registration features message', :aggregate_failures do
+ render
+
+ if disabled_field
+ expect(rendered).not_to have_field(disabled_field, disabled: true)
+ end
+
+ expect(rendered).not_to have_content(s_("RegistrationFeatures|Want to %{feature_title} for free?") % { feature_title: s_('RegistrationFeatures|use this feature') })
+ expect(rendered).not_to have_link(s_('RegistrationFeatures|Registration Features Program'))
+ end
+end
diff --git a/spec/support/shared_examples/workers/background_migration_worker_shared_examples.rb b/spec/support/shared_examples/workers/background_migration_worker_shared_examples.rb
index 0d3e158d358..7fdf049a823 100644
--- a/spec/support/shared_examples/workers/background_migration_worker_shared_examples.rb
+++ b/spec/support/shared_examples/workers/background_migration_worker_shared_examples.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-RSpec.shared_examples 'it runs background migration jobs' do |tracking_database, metric_name|
+RSpec.shared_examples 'it runs background migration jobs' do |tracking_database|
describe 'defining the job attributes' do
it 'defines the data_consistency as always' do
expect(described_class.get_data_consistency).to eq(:always)
@@ -33,16 +33,6 @@ RSpec.shared_examples 'it runs background migration jobs' do |tracking_database,
end
end
- describe '.unhealthy_metric_name' do
- it 'does not raise an error' do
- expect { described_class.unhealthy_metric_name }.not_to raise_error
- end
-
- it 'overrides the method to return the unhealthy metric name' do
- expect(described_class.unhealthy_metric_name).to eq(metric_name)
- end
- end
-
describe '.minimum_interval' do
it 'returns 2 minutes' do
expect(described_class.minimum_interval).to eq(2.minutes.to_i)
@@ -189,11 +179,11 @@ RSpec.shared_examples 'it runs background migration jobs' do |tracking_database,
end
it 'increments the unhealthy counter' do
- counter = Gitlab::Metrics.counter(metric_name, 'msg')
+ counter = Gitlab::Metrics.counter(:background_migration_database_health_reschedules, 'msg')
expect(described_class).to receive(:perform_in)
- expect { worker.perform('Foo', [10, 20]) }.to change { counter.get }.by(1)
+ expect { worker.perform('Foo', [10, 20]) }.to change { counter.get(db_config_name: tracking_database) }.by(1)
end
context 'when lease_attempts is 0' do
diff --git a/spec/support/shared_examples/workers/project_export_shared_examples.rb b/spec/support/shared_examples/workers/project_export_shared_examples.rb
index a9bcc3f4f7c..175ef9bd012 100644
--- a/spec/support/shared_examples/workers/project_export_shared_examples.rb
+++ b/spec/support/shared_examples/workers/project_export_shared_examples.rb
@@ -53,6 +53,10 @@ RSpec.shared_examples 'export worker' do
it 'does not raise an exception when strategy is invalid' do
expect(::Projects::ImportExport::ExportService).not_to receive(:new)
+ expect_next_instance_of(ProjectExportJob) do |job|
+ expect(job).to receive(:finish)
+ end
+
expect { subject.perform(user.id, project.id, { 'klass' => 'Whatever' }) }.not_to raise_error
end
@@ -63,6 +67,18 @@ RSpec.shared_examples 'export worker' do
it 'does not raise error when user cannot be found' do
expect { subject.perform(non_existing_record_id, project.id, {}) }.not_to raise_error
end
+
+ it 'fails the export job status' do
+ expect_next_instance_of(::Projects::ImportExport::ExportService) do |service|
+ expect(service).to receive(:execute).and_raise(Gitlab::ImportExport::Error)
+ end
+
+ expect_next_instance_of(ProjectExportJob) do |job|
+ expect(job).to receive(:fail_op)
+ end
+
+ expect { subject.perform(user.id, project.id, {}) }.to raise_error(Gitlab::ImportExport::Error)
+ end
end
end