summaryrefslogtreecommitdiff
path: root/spec/support
diff options
context:
space:
mode:
Diffstat (limited to 'spec/support')
-rw-r--r--spec/support/api/boards_shared_examples.rb2
-rw-r--r--spec/support/api/issues_resolving_discussions_shared_examples.rb2
-rw-r--r--spec/support/api/members_shared_examples.rb2
-rw-r--r--spec/support/api/milestones_shared_examples.rb2
-rw-r--r--spec/support/api/repositories_shared_context.rb2
-rw-r--r--spec/support/api/schema_matcher.rb2
-rw-r--r--spec/support/api/scopes/read_user_shared_examples.rb2
-rw-r--r--spec/support/api/time_tracking_shared_examples.rb2
-rw-r--r--spec/support/banzai/reference_filter_shared_examples.rb2
-rw-r--r--spec/support/batch_loader.rb2
-rw-r--r--spec/support/capybara.rb6
-rw-r--r--spec/support/carrierwave.rb2
-rw-r--r--spec/support/chunked_io/chunked_io_helpers.rb2
-rw-r--r--spec/support/commit_trailers_spec_helper.rb2
-rw-r--r--spec/support/controllers/githubish_import_controller_shared_context.rb2
-rw-r--r--spec/support/controllers/githubish_import_controller_shared_examples.rb8
-rw-r--r--spec/support/controllers/ldap_omniauth_callbacks_controller_shared_context.rb2
-rw-r--r--spec/support/controllers/sessionless_auth_controller_shared_examples.rb2
-rw-r--r--spec/support/cycle_analytics_helpers/test_generation.rb14
-rw-r--r--spec/support/database_cleaner.rb27
-rw-r--r--spec/support/db_cleaner.rb6
-rw-r--r--spec/support/external_authorization_service_helpers.rb2
-rw-r--r--spec/support/features/discussion_comments_shared_example.rb2
-rw-r--r--spec/support/features/reportable_note_shared_examples.rb2
-rw-r--r--spec/support/features/resolving_discussions_in_issues_shared_examples.rb2
-rw-r--r--spec/support/features/rss_shared_examples.rb2
-rw-r--r--spec/support/features/variable_list_shared_examples.rb2
-rw-r--r--spec/support/forgery_protection.rb2
-rw-r--r--spec/support/google_api/cloud_platform_helpers.rb2
-rw-r--r--spec/support/helpers/api_helpers.rb11
-rw-r--r--spec/support/helpers/assets_helpers.rb2
-rw-r--r--spec/support/helpers/bare_repo_operations.rb2
-rw-r--r--spec/support/helpers/board_helpers.rb2
-rw-r--r--spec/support/helpers/capybara_helpers.rb2
-rw-r--r--spec/support/helpers/ci_artifact_metadata_generator.rb2
-rw-r--r--spec/support/helpers/cookie_helper.rb2
-rw-r--r--spec/support/helpers/cycle_analytics_helpers.rb2
-rw-r--r--spec/support/helpers/database_connection_helpers.rb2
-rw-r--r--spec/support/helpers/devise_helpers.rb2
-rw-r--r--spec/support/helpers/drag_to_helper.rb21
-rw-r--r--spec/support/helpers/dropzone_helper.rb2
-rw-r--r--spec/support/helpers/email_helpers.rb6
-rw-r--r--spec/support/helpers/exclusive_lease_helpers.rb2
-rw-r--r--spec/support/helpers/expect_next_instance_of.rb2
-rw-r--r--spec/support/helpers/expect_offense.rb2
-rw-r--r--spec/support/helpers/expect_request_with_status.rb11
-rw-r--r--spec/support/helpers/fake_blob_helpers.rb2
-rw-r--r--spec/support/helpers/fake_migration_classes.rb2
-rw-r--r--spec/support/helpers/fake_u2f_device.rb2
-rw-r--r--spec/support/helpers/features/branches_helpers.rb2
-rw-r--r--spec/support/helpers/features/notes_helpers.rb10
-rw-r--r--spec/support/helpers/features/sorting_helpers.rb2
-rw-r--r--spec/support/helpers/filter_spec_helper.rb2
-rw-r--r--spec/support/helpers/filtered_search_helpers.rb2
-rw-r--r--spec/support/helpers/fixture_helpers.rb2
-rw-r--r--spec/support/helpers/git_http_helpers.rb2
-rw-r--r--spec/support/helpers/gitlab_verify_helpers.rb2
-rw-r--r--spec/support/helpers/graphql_helpers.rb10
-rw-r--r--spec/support/helpers/import_spec_helper.rb2
-rw-r--r--spec/support/helpers/input_helper.rb2
-rw-r--r--spec/support/helpers/inspect_requests.rb2
-rw-r--r--spec/support/helpers/issue_helpers.rb2
-rw-r--r--spec/support/helpers/javascript_fixtures_helpers.rb4
-rw-r--r--spec/support/helpers/jira_service_helper.rb2
-rw-r--r--spec/support/helpers/key_generator_helper.rb4
-rw-r--r--spec/support/helpers/kubernetes_helpers.rb7
-rw-r--r--spec/support/helpers/ldap_helpers.rb2
-rw-r--r--spec/support/helpers/live_debugger.rb2
-rw-r--r--spec/support/helpers/login_helpers.rb2
-rw-r--r--spec/support/helpers/markdown_feature.rb2
-rw-r--r--spec/support/helpers/memory_usage_helper.rb37
-rw-r--r--spec/support/helpers/merge_request_diff_helpers.rb2
-rw-r--r--spec/support/helpers/merge_request_helpers.rb2
-rw-r--r--spec/support/helpers/metrics_dashboard_helpers.rb8
-rw-r--r--spec/support/helpers/migrations_helpers.rb15
-rw-r--r--spec/support/helpers/mobile_helpers.rb2
-rw-r--r--spec/support/helpers/note_interaction_helpers.rb2
-rw-r--r--spec/support/helpers/notification_helpers.rb2
-rw-r--r--spec/support/helpers/project_forks_helper.rb2
-rw-r--r--spec/support/helpers/prometheus_helpers.rb10
-rw-r--r--spec/support/helpers/query_recorder.rb2
-rw-r--r--spec/support/helpers/quick_actions_helpers.rb2
-rw-r--r--spec/support/helpers/rake_helpers.rb2
-rw-r--r--spec/support/helpers/reactive_caching_helpers.rb2
-rw-r--r--spec/support/helpers/redis_without_keys.rb2
-rw-r--r--spec/support/helpers/reference_parser_helpers.rb2
-rw-r--r--spec/support/helpers/repo_helpers.rb2
-rw-r--r--spec/support/helpers/routes_helpers.rb2
-rw-r--r--spec/support/helpers/search_helpers.rb2
-rw-r--r--spec/support/helpers/seed_repo.rb2
-rw-r--r--spec/support/helpers/select2_helper.rb2
-rw-r--r--spec/support/helpers/selection_helper.rb2
-rw-r--r--spec/support/helpers/smime_helper.rb55
-rw-r--r--spec/support/helpers/sorting_helper.rb2
-rw-r--r--spec/support/helpers/stub_configuration.rb10
-rw-r--r--spec/support/helpers/stub_env.rb2
-rw-r--r--spec/support/helpers/stub_feature_flags.rb2
-rw-r--r--spec/support/helpers/stub_gitlab_calls.rb6
-rw-r--r--spec/support/helpers/stub_gitlab_data.rb2
-rw-r--r--spec/support/helpers/stub_metrics.rb2
-rw-r--r--spec/support/helpers/stub_object_storage.rb2
-rw-r--r--spec/support/helpers/stub_requests.rb15
-rw-r--r--spec/support/helpers/stub_worker.rb2
-rw-r--r--spec/support/helpers/terms_helper.rb2
-rw-r--r--spec/support/helpers/test_env.rb40
-rw-r--r--spec/support/helpers/upload_helpers.rb2
-rw-r--r--spec/support/helpers/wait_for_requests.rb2
-rw-r--r--spec/support/helpers/wait_helpers.rb2
-rw-r--r--spec/support/helpers/wiki_helpers.rb2
-rw-r--r--spec/support/helpers/workhorse_helpers.rb2
-rw-r--r--spec/support/http_io/http_io_helpers.rb2
-rw-r--r--spec/support/import_export/common_util.rb2
-rw-r--r--spec/support/import_export/configuration_helper.rb2
-rw-r--r--spec/support/import_export/export_file_helper.rb2
-rw-r--r--spec/support/inspect_squelch.rb2
-rw-r--r--spec/support/issuables_requiring_filter_shared_examples.rb2
-rw-r--r--spec/support/json_response.rb4
-rw-r--r--spec/support/matchers/abort_matcher.rb48
-rw-r--r--spec/support/matchers/access_matchers.rb2
-rw-r--r--spec/support/matchers/access_matchers_for_controller.rb2
-rw-r--r--spec/support/matchers/background_migrations_matchers.rb2
-rw-r--r--spec/support/matchers/be_a_binary_string.rb2
-rw-r--r--spec/support/matchers/be_like_time.rb2
-rw-r--r--spec/support/matchers/be_url.rb6
-rw-r--r--spec/support/matchers/be_utf8.rb2
-rw-r--r--spec/support/matchers/be_valid_commit.rb2
-rw-r--r--spec/support/matchers/disallow_request_matchers.rb2
-rw-r--r--spec/support/matchers/exceed_query_limit.rb2
-rw-r--r--spec/support/matchers/execute_check.rb2
-rw-r--r--spec/support/matchers/gitaly_matchers.rb2
-rw-r--r--spec/support/matchers/gitlab_git_matchers.rb2
-rw-r--r--spec/support/matchers/graphql_matchers.rb2
-rw-r--r--spec/support/matchers/have_emoji.rb2
-rw-r--r--spec/support/matchers/have_gitlab_http_status.rb2
-rw-r--r--spec/support/matchers/have_issuable_counts.rb2
-rw-r--r--spec/support/matchers/include_module.rb2
-rw-r--r--spec/support/matchers/issuable_matchers.rb2
-rw-r--r--spec/support/matchers/markdown_matchers.rb2
-rw-r--r--spec/support/matchers/match_file.rb2
-rw-r--r--spec/support/matchers/match_ids.rb2
-rw-r--r--spec/support/matchers/metric_counter_matcher.rb2
-rw-r--r--spec/support/matchers/navigation_matcher.rb2
-rw-r--r--spec/support/matchers/pagination_matcher.rb2
-rw-r--r--spec/support/matchers/query_matcher.rb2
-rw-r--r--spec/support/matchers/satisfy_matchers.rb2
-rw-r--r--spec/support/matchers/security_header_matcher.rb2
-rw-r--r--spec/support/migrations_helpers/track_untracked_uploads_helpers.rb2
-rw-r--r--spec/support/omni_auth.rb2
-rw-r--r--spec/support/prometheus/additional_metrics_shared_examples.rb4
-rw-r--r--spec/support/prometheus/metric_builders.rb2
-rw-r--r--spec/support/protected_tags/access_control_ce_shared_examples.rb2
-rw-r--r--spec/support/redis/redis_helpers.rb2
-rw-r--r--spec/support/redis/redis_shared_examples.rb2
-rw-r--r--spec/support/rspec.rb2
-rw-r--r--spec/support/seed.rb2
-rw-r--r--spec/support/services/clusters/create_service_shared.rb69
-rw-r--r--spec/support/services/issuable_create_service_slash_commands_shared_examples.rb2
-rw-r--r--spec/support/services/issuable_update_service_shared_examples.rb2
-rw-r--r--spec/support/services/migrate_to_ghost_user_service_shared_examples.rb2
-rw-r--r--spec/support/setup_builds_storage.rb2
-rw-r--r--spec/support/shared_contexts/email_shared_context.rb2
-rw-r--r--spec/support/shared_contexts/finders/group_projects_finder_shared_contexts.rb2
-rw-r--r--spec/support/shared_contexts/finders/issues_finder_shared_contexts.rb2
-rw-r--r--spec/support/shared_contexts/finders/merge_requests_finder_shared_contexts.rb2
-rw-r--r--spec/support/shared_contexts/finders/users_finder_shared_contexts.rb2
-rw-r--r--spec/support/shared_contexts/json_response_shared_context.rb2
-rw-r--r--spec/support/shared_contexts/merge_requests_allowing_collaboration.rb2
-rw-r--r--spec/support/shared_contexts/policies/group_policy_shared_context.rb7
-rw-r--r--spec/support/shared_contexts/services_shared_context.rb2
-rw-r--r--spec/support/shared_contexts/url_shared_context.rb2
-rw-r--r--spec/support/shared_examples/application_setting_examples.rb164
-rw-r--r--spec/support/shared_examples/award_emoji_todo_shared_examples.rb59
-rw-r--r--spec/support/shared_examples/boards/multiple_issue_boards_shared_examples.rb144
-rw-r--r--spec/support/shared_examples/chat_slash_commands_shared_examples.rb15
-rw-r--r--spec/support/shared_examples/ci_trace_shared_examples.rb58
-rw-r--r--spec/support/shared_examples/common_system_notes_examples.rb2
-rw-r--r--spec/support/shared_examples/container_repositories_shared_examples.rb58
-rw-r--r--spec/support/shared_examples/controllers/external_authorization_service_shared_examples.rb4
-rw-r--r--spec/support/shared_examples/controllers/issuable_notes_filter_shared_examples.rb16
-rw-r--r--spec/support/shared_examples/controllers/set_sort_order_from_user_preference_shared_examples.rb8
-rw-r--r--spec/support/shared_examples/controllers/todos_shared_examples.rb2
-rw-r--r--spec/support/shared_examples/controllers/uploads_actions_shared_examples.rb12
-rw-r--r--spec/support/shared_examples/controllers/variables_shared_examples.rb2
-rw-r--r--spec/support/shared_examples/cycle_analytics_stage_examples.rb74
-rw-r--r--spec/support/shared_examples/dirty_submit_form_shared_examples.rb2
-rw-r--r--spec/support/shared_examples/discussions_provider_shared_examples.rb15
-rw-r--r--spec/support/shared_examples/email_format_shared_examples.rb2
-rw-r--r--spec/support/shared_examples/fast_destroy_all.rb2
-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/editable_merge_request_shared_examples.rb2
-rw-r--r--spec/support/shared_examples/features/issuable_sidebar_shared_examples.rb2
-rw-r--r--spec/support/shared_examples/features/issuables_user_dropdown_behaviors_shared_examples.rb2
-rw-r--r--spec/support/shared_examples/features/master_manages_access_requests_shared_example.rb2
-rw-r--r--spec/support/shared_examples/features/project_features_apply_to_issuables_shared_examples.rb2
-rw-r--r--spec/support/shared_examples/features/protected_branches_access_control_ce.rb14
-rw-r--r--spec/support/shared_examples/features/search_shared_examples.rb2
-rw-r--r--spec/support/shared_examples/file_finder.rb2
-rw-r--r--spec/support/shared_examples/finders/finder_with_external_authorization_enabled.rb2
-rw-r--r--spec/support/shared_examples/gitlab_verify.rb2
-rw-r--r--spec/support/shared_examples/graphql/issuable_state_shared_examples.rb2
-rw-r--r--spec/support/shared_examples/group_members_shared_example.rb2
-rw-r--r--spec/support/shared_examples/helm_generated_script.rb2
-rw-r--r--spec/support/shared_examples/issuable_shared_examples.rb2
-rw-r--r--spec/support/shared_examples/issuables_list_metadata_shared_examples.rb2
-rw-r--r--spec/support/shared_examples/issue_tracker_service_shared_example.rb2
-rw-r--r--spec/support/shared_examples/ldap_shared_examples.rb2
-rw-r--r--spec/support/shared_examples/legacy_path_redirect_shared_examples.rb2
-rw-r--r--spec/support/shared_examples/lib/gitlab/background_migration/backfill_project_repositories_examples.rb2
-rw-r--r--spec/support/shared_examples/lib/gitlab/usage_data_counters/a_redis_counter.rb57
-rw-r--r--spec/support/shared_examples/malicious_regexp_shared_examples.rb2
-rw-r--r--spec/support/shared_examples/mentionable_shared_examples.rb53
-rw-r--r--spec/support/shared_examples/milestone_tabs_examples.rb2
-rw-r--r--spec/support/shared_examples/models/atomic_internal_id_shared_examples.rb2
-rw-r--r--spec/support/shared_examples/models/chat_service_shared_examples.rb5
-rw-r--r--spec/support/shared_examples/models/cluster_application_core_shared_examples.rb2
-rw-r--r--spec/support/shared_examples/models/cluster_application_helm_cert_examples.rb2
-rw-r--r--spec/support/shared_examples/models/cluster_application_status_shared_examples.rb2
-rw-r--r--spec/support/shared_examples/models/diff_positionable_note_shared_examples.rb52
-rw-r--r--spec/support/shared_examples/models/issuable_hook_data_shared_examples.rb2
-rw-r--r--spec/support/shared_examples/models/members_notifications_shared_example.rb2
-rw-r--r--spec/support/shared_examples/models/project_hook_data_shared_examples.rb2
-rw-r--r--spec/support/shared_examples/models/update_project_statistics_shared_examples.rb40
-rw-r--r--spec/support/shared_examples/models/with_uploads_shared_examples.rb2
-rw-r--r--spec/support/shared_examples/notify_shared_examples.rb35
-rw-r--r--spec/support/shared_examples/policies/clusterable_shared_examples.rb16
-rw-r--r--spec/support/shared_examples/position_formatters.rb2
-rw-r--r--spec/support/shared_examples/project_latest_successful_build_for_examples.rb63
-rw-r--r--spec/support/shared_examples/quick_actions/commit/tag_quick_action_shared_examples.rb2
-rw-r--r--spec/support/shared_examples/quick_actions/issuable/close_quick_action_shared_examples.rb2
-rw-r--r--spec/support/shared_examples/quick_actions/issue/create_merge_request_quick_action_shared_examples.rb22
-rw-r--r--spec/support/shared_examples/quick_actions/issue/duplicate_quick_action_shared_examples.rb2
-rw-r--r--spec/support/shared_examples/quick_actions/issue/move_quick_action_shared_examples.rb57
-rw-r--r--spec/support/shared_examples/quick_actions/merge_request/merge_quick_action_shared_examples.rb2
-rw-r--r--spec/support/shared_examples/reference_parser_shared_examples.rb2
-rw-r--r--spec/support/shared_examples/relative_positioning_shared_examples.rb283
-rw-r--r--spec/support/shared_examples/requests/api/custom_attributes_shared_examples.rb2
-rw-r--r--spec/support/shared_examples/requests/api/diff_discussions.rb2
-rw-r--r--spec/support/shared_examples/requests/api/discussions.rb56
-rw-r--r--spec/support/shared_examples/requests/api/issuable_participants_examples.rb2
-rw-r--r--spec/support/shared_examples/requests/api/issues/merge_requests_count_shared_examples.rb2
-rw-r--r--spec/support/shared_examples/requests/api/notes.rb2
-rw-r--r--spec/support/shared_examples/requests/api/pipelines/visibility_table_examples.rb235
-rw-r--r--spec/support/shared_examples/requests/api/resolvable_discussions.rb2
-rw-r--r--spec/support/shared_examples/requests/api/status_shared_examples.rb2
-rw-r--r--spec/support/shared_examples/requests/graphql_shared_examples.rb2
-rw-r--r--spec/support/shared_examples/resource_label_events_api.rb44
-rw-r--r--spec/support/shared_examples/serializers/note_entity_examples.rb2
-rw-r--r--spec/support/shared_examples/services/boards/boards_create_service.rb2
-rw-r--r--spec/support/shared_examples/services/boards/boards_list_service.rb2
-rw-r--r--spec/support/shared_examples/services/boards/issues_list_service.rb2
-rw-r--r--spec/support/shared_examples/services/boards/issues_move_service.rb2
-rw-r--r--spec/support/shared_examples/services/boards/lists_destroy_service.rb2
-rw-r--r--spec/support/shared_examples/services/boards/lists_list_service.rb2
-rw-r--r--spec/support/shared_examples/services/boards/lists_move_service.rb2
-rw-r--r--spec/support/shared_examples/services/check_ingress_ip_address_service_shared_examples.rb2
-rw-r--r--spec/support/shared_examples/services/gitlab_projects_import_service_shared_examples.rb2
-rw-r--r--spec/support/shared_examples/services/notification_service_shared_examples.rb54
-rw-r--r--spec/support/shared_examples/slack_mattermost_notifications_shared_examples.rb6
-rw-r--r--spec/support/shared_examples/snippet_visibility_shared_examples.rb2
-rw-r--r--spec/support/shared_examples/snippets_shared_examples.rb2
-rw-r--r--spec/support/shared_examples/taskable_shared_examples.rb23
-rw-r--r--spec/support/shared_examples/throttled_touch.rb2
-rw-r--r--spec/support/shared_examples/unique_ip_check_shared_examples.rb2
-rw-r--r--spec/support/shared_examples/update_invalid_issuable.rb4
-rw-r--r--spec/support/shared_examples/updating_mentions_shared_examples.rb2
-rw-r--r--spec/support/shared_examples/uploaders/gitlab_uploader_shared_examples.rb2
-rw-r--r--spec/support/shared_examples/uploaders/object_storage_shared_examples.rb2
-rw-r--r--spec/support/shared_examples/url_validator_examples.rb59
-rw-r--r--spec/support/sidekiq.rb2
-rw-r--r--spec/support/stored_repositories.rb2
-rw-r--r--spec/support/test_reports/test_reports_helper.rb2
-rw-r--r--spec/support/trace/trace_helpers.rb2
-rw-r--r--spec/support/webmock.rb2
274 files changed, 2478 insertions, 232 deletions
diff --git a/spec/support/api/boards_shared_examples.rb b/spec/support/api/boards_shared_examples.rb
index 3abb5096a7a..b7aff32460d 100644
--- a/spec/support/api/boards_shared_examples.rb
+++ b/spec/support/api/boards_shared_examples.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
shared_examples_for 'group and project boards' do |route_definition, ee = false|
let(:root_url) { route_definition.gsub(":id", board_parent.id.to_s) }
diff --git a/spec/support/api/issues_resolving_discussions_shared_examples.rb b/spec/support/api/issues_resolving_discussions_shared_examples.rb
index d2d6260dfa8..4c44f1bd103 100644
--- a/spec/support/api/issues_resolving_discussions_shared_examples.rb
+++ b/spec/support/api/issues_resolving_discussions_shared_examples.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
shared_examples 'creating an issue resolving discussions through the API' do
it 'creates a new project issue' do
expect(response).to have_gitlab_http_status(:created)
diff --git a/spec/support/api/members_shared_examples.rb b/spec/support/api/members_shared_examples.rb
index 8d910e52eda..603efd4fc75 100644
--- a/spec/support/api/members_shared_examples.rb
+++ b/spec/support/api/members_shared_examples.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
shared_examples 'a 404 response when source is private' do
before do
source.update_column(:visibility_level, Gitlab::VisibilityLevel::PRIVATE)
diff --git a/spec/support/api/milestones_shared_examples.rb b/spec/support/api/milestones_shared_examples.rb
index 63b719be03e..d6439f77408 100644
--- a/spec/support/api/milestones_shared_examples.rb
+++ b/spec/support/api/milestones_shared_examples.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
shared_examples_for 'group and project milestones' do |route_definition|
let(:resource_route) { "#{route}/#{milestone.id}" }
let(:label_1) { create(:label, title: 'label_1', project: project, priority: 1) }
diff --git a/spec/support/api/repositories_shared_context.rb b/spec/support/api/repositories_shared_context.rb
index f1341804e56..346015106e3 100644
--- a/spec/support/api/repositories_shared_context.rb
+++ b/spec/support/api/repositories_shared_context.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
shared_context 'disabled repository' do
before do
project.project_feature.update!(
diff --git a/spec/support/api/schema_matcher.rb b/spec/support/api/schema_matcher.rb
index 4cf34d43117..ebbd57c8115 100644
--- a/spec/support/api/schema_matcher.rb
+++ b/spec/support/api/schema_matcher.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module SchemaPath
def self.expand(schema, dir = nil)
if Gitlab.ee? && dir.nil?
diff --git a/spec/support/api/scopes/read_user_shared_examples.rb b/spec/support/api/scopes/read_user_shared_examples.rb
index 683234264a8..3786a8012f9 100644
--- a/spec/support/api/scopes/read_user_shared_examples.rb
+++ b/spec/support/api/scopes/read_user_shared_examples.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
shared_examples_for 'allows the "read_user" scope' do |api_version|
let(:version) { api_version || 'v4' }
diff --git a/spec/support/api/time_tracking_shared_examples.rb b/spec/support/api/time_tracking_shared_examples.rb
index 15037222630..3bd1b145433 100644
--- a/spec/support/api/time_tracking_shared_examples.rb
+++ b/spec/support/api/time_tracking_shared_examples.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
shared_examples 'an unauthorized API user' do
it { is_expected.to eq(403) }
end
diff --git a/spec/support/banzai/reference_filter_shared_examples.rb b/spec/support/banzai/reference_filter_shared_examples.rb
index 476d80f3a93..27765652f28 100644
--- a/spec/support/banzai/reference_filter_shared_examples.rb
+++ b/spec/support/banzai/reference_filter_shared_examples.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
# Specs for reference links containing HTML.
#
# Requires a reference:
diff --git a/spec/support/batch_loader.rb b/spec/support/batch_loader.rb
index bb790e660a6..0eb8f279d29 100644
--- a/spec/support/batch_loader.rb
+++ b/spec/support/batch_loader.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
RSpec.configure do |config|
config.after do
BatchLoader::Executor.clear_current
diff --git a/spec/support/capybara.rb b/spec/support/capybara.rb
index 56ac208a025..4c688094352 100644
--- a/spec/support/capybara.rb
+++ b/spec/support/capybara.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
# rubocop:disable Style/GlobalVars
require 'capybara/rails'
require 'capybara/rspec'
@@ -45,6 +47,9 @@ Capybara.register_driver :chrome do |app|
# Explicitly set user-data-dir to prevent crashes. See https://gitlab.com/gitlab-org/gitlab-ce/issues/58882#note_179811508
options.add_argument("user-data-dir=/tmp/chrome") if ENV['CI'] || ENV['CI_SERVER']
+ # Chrome 75 defaults to W3C mode which doesn't allow console log access
+ options.add_option(:w3c, false)
+
Capybara::Selenium::Driver.new(
app,
browser: :chrome,
@@ -58,6 +63,7 @@ Capybara.javascript_driver = :chrome
Capybara.default_max_wait_time = timeout
Capybara.ignore_hidden_elements = true
Capybara.default_normalize_ws = true
+Capybara.enable_aria_label = true
# Keep only the screenshots generated from the last failing test suite
Capybara::Screenshot.prune_strategy = :keep_last_run
diff --git a/spec/support/carrierwave.rb b/spec/support/carrierwave.rb
index b376822d530..8da55514c78 100644
--- a/spec/support/carrierwave.rb
+++ b/spec/support/carrierwave.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
CarrierWave.root = File.expand_path('tmp/tests/public', Rails.root)
RSpec.configure do |config|
diff --git a/spec/support/chunked_io/chunked_io_helpers.rb b/spec/support/chunked_io/chunked_io_helpers.rb
index fec1f951563..278f577f3cb 100644
--- a/spec/support/chunked_io/chunked_io_helpers.rb
+++ b/spec/support/chunked_io/chunked_io_helpers.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module ChunkedIOHelpers
def sample_trace_raw
@sample_trace_raw ||= File.read(expand_fixture_path('trace/sample_trace'))
diff --git a/spec/support/commit_trailers_spec_helper.rb b/spec/support/commit_trailers_spec_helper.rb
index efa317fd2f9..a958e259368 100644
--- a/spec/support/commit_trailers_spec_helper.rb
+++ b/spec/support/commit_trailers_spec_helper.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module CommitTrailersSpecHelper
extend ActiveSupport::Concern
diff --git a/spec/support/controllers/githubish_import_controller_shared_context.rb b/spec/support/controllers/githubish_import_controller_shared_context.rb
index e71994edec6..3706178ee34 100644
--- a/spec/support/controllers/githubish_import_controller_shared_context.rb
+++ b/spec/support/controllers/githubish_import_controller_shared_context.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
shared_context 'a GitHub-ish import controller' do
let(:user) { create(:user) }
let(:token) { "asdasd12345" }
diff --git a/spec/support/controllers/githubish_import_controller_shared_examples.rb b/spec/support/controllers/githubish_import_controller_shared_examples.rb
index 5bb1269a19d..718d9857b18 100644
--- a/spec/support/controllers/githubish_import_controller_shared_examples.rb
+++ b/spec/support/controllers/githubish_import_controller_shared_examples.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
# Specifications for behavior common to all objects with an email attribute.
# Takes a list of email-format attributes and requires:
# - subject { "the object with a attribute= setter" }
@@ -321,7 +323,7 @@ shared_examples 'a GitHub-ish import controller: POST create' do
end
end
- context 'user has chosen an existing nested namespace and name for the project', :postgresql do
+ context 'user has chosen an existing nested namespace and name for the project' do
let(:parent_namespace) { create(:group, name: 'foo') }
let(:nested_namespace) { create(:group, name: 'bar', parent: parent_namespace) }
let(:test_name) { 'test_name' }
@@ -340,7 +342,7 @@ shared_examples 'a GitHub-ish import controller: POST create' do
end
end
- context 'user has chosen a non-existent nested namespaces and name for the project', :postgresql do
+ context 'user has chosen a non-existent nested namespaces and name for the project' do
let(:test_name) { 'test_name' }
it 'takes the selected namespace and name' do
@@ -371,7 +373,7 @@ shared_examples 'a GitHub-ish import controller: POST create' do
end
end
- context 'user has chosen existent and non-existent nested namespaces and name for the project', :postgresql do
+ context 'user has chosen existent and non-existent nested namespaces and name for the project' do
let(:test_name) { 'test_name' }
let!(:parent_namespace) { create(:group, name: 'foo') }
diff --git a/spec/support/controllers/ldap_omniauth_callbacks_controller_shared_context.rb b/spec/support/controllers/ldap_omniauth_callbacks_controller_shared_context.rb
index a0c77eecb61..d636c1cf6cd 100644
--- a/spec/support/controllers/ldap_omniauth_callbacks_controller_shared_context.rb
+++ b/spec/support/controllers/ldap_omniauth_callbacks_controller_shared_context.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
shared_context 'Ldap::OmniauthCallbacksController' do
diff --git a/spec/support/controllers/sessionless_auth_controller_shared_examples.rb b/spec/support/controllers/sessionless_auth_controller_shared_examples.rb
index 355555d9d19..b5149a0fcb1 100644
--- a/spec/support/controllers/sessionless_auth_controller_shared_examples.rb
+++ b/spec/support/controllers/sessionless_auth_controller_shared_examples.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
shared_examples 'authenticates sessionless user' do |path, format, params|
params ||= {}
diff --git a/spec/support/cycle_analytics_helpers/test_generation.rb b/spec/support/cycle_analytics_helpers/test_generation.rb
index 19b32c84d81..c57abbd96c6 100644
--- a/spec/support/cycle_analytics_helpers/test_generation.rb
+++ b/spec/support/cycle_analytics_helpers/test_generation.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
# rubocop:disable Metrics/AbcSize
# Note: The ABC size is large here because we have a method generating test cases with
@@ -50,7 +52,7 @@ module CycleAnalyticsHelpers
end
median_time_difference = time_differences.sort[2]
- expect(subject[phase].median).to be_within(5).of(median_time_difference)
+ expect(subject[phase].project_median).to be_within(5).of(median_time_difference)
end
context "when the data belongs to another project" do
@@ -80,7 +82,7 @@ module CycleAnalyticsHelpers
# Turn off the stub before checking assertions
allow(self).to receive(:project).and_call_original
- expect(subject[phase].median).to be_nil
+ expect(subject[phase].project_median).to be_nil
end
end
@@ -103,7 +105,7 @@ module CycleAnalyticsHelpers
Timecop.freeze(end_time + 1.day) { post_fn[self, data] } if post_fn
- expect(subject[phase].median).to be_nil
+ expect(subject[phase].project_median).to be_nil
end
end
end
@@ -121,7 +123,7 @@ module CycleAnalyticsHelpers
Timecop.freeze(end_time + 1.day) { post_fn[self, data] } if post_fn
- expect(subject[phase].median).to be_nil
+ expect(subject[phase].project_median).to be_nil
end
end
end
@@ -138,7 +140,7 @@ module CycleAnalyticsHelpers
post_fn[self, data] if post_fn
- expect(subject[phase].median).to be_nil
+ expect(subject[phase].project_median).to be_nil
end
end
end
@@ -146,7 +148,7 @@ module CycleAnalyticsHelpers
context "when none of the start / end conditions are matched" do
it "returns nil" do
- expect(subject[phase].median).to be_nil
+ expect(subject[phase].project_median).to be_nil
end
end
end
diff --git a/spec/support/database_cleaner.rb b/spec/support/database_cleaner.rb
index edd7de94203..f0dd6c52b74 100644
--- a/spec/support/database_cleaner.rb
+++ b/spec/support/database_cleaner.rb
@@ -26,31 +26,22 @@ RSpec.configure do |config|
end
config.append_after(:context) do
- DatabaseCleaner.clean_with(:deletion, cache_tables: false)
+ delete_from_all_tables!
end
- config.before do
- setup_database_cleaner
- DatabaseCleaner.strategy = :transaction
- end
+ config.around(:each, :delete) do |example|
+ self.class.use_transactional_tests = false
- config.before(:each, :js) do
- DatabaseCleaner.strategy = :deletion, { except: deletion_except_tables, cache_tables: false }
- end
+ example.run
- config.before(:each, :delete) do
- DatabaseCleaner.strategy = :deletion, { except: deletion_except_tables, cache_tables: false }
+ delete_from_all_tables!(except: deletion_except_tables)
end
- config.before(:each, :migration) do
- DatabaseCleaner.strategy = :deletion, { cache_tables: false }
- end
+ config.around(:each, :migration) do |example|
+ self.class.use_transactional_tests = false
- config.before do
- DatabaseCleaner.start
- end
+ example.run
- config.append_after do
- DatabaseCleaner.clean
+ delete_from_all_tables!
end
end
diff --git a/spec/support/db_cleaner.rb b/spec/support/db_cleaner.rb
index c69fa322073..041ffa25535 100644
--- a/spec/support/db_cleaner.rb
+++ b/spec/support/db_cleaner.rb
@@ -1,4 +1,10 @@
+# frozen_string_literal: true
+
module DbCleaner
+ def delete_from_all_tables!(except: nil)
+ DatabaseCleaner.clean_with(:deletion, cache_tables: false, except: except)
+ end
+
def deletion_except_tables
[]
end
diff --git a/spec/support/external_authorization_service_helpers.rb b/spec/support/external_authorization_service_helpers.rb
index 79dd9a3d58e..f4214d800cf 100644
--- a/spec/support/external_authorization_service_helpers.rb
+++ b/spec/support/external_authorization_service_helpers.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module ExternalAuthorizationServiceHelpers
def enable_external_authorization_service_check
stub_application_setting(external_authorization_service_enabled: true)
diff --git a/spec/support/features/discussion_comments_shared_example.rb b/spec/support/features/discussion_comments_shared_example.rb
index 7c8e57702ae..5590bf0fb7e 100644
--- a/spec/support/features/discussion_comments_shared_example.rb
+++ b/spec/support/features/discussion_comments_shared_example.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
shared_examples 'thread comments' do |resource_name|
let(:form_selector) { '.js-main-target-form' }
let(:dropdown_selector) { "#{form_selector} .comment-type-dropdown" }
diff --git a/spec/support/features/reportable_note_shared_examples.rb b/spec/support/features/reportable_note_shared_examples.rb
index 5d5a0a7b5d2..2f9208e6ed5 100644
--- a/spec/support/features/reportable_note_shared_examples.rb
+++ b/spec/support/features/reportable_note_shared_examples.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
shared_examples 'reportable note' do |type|
diff --git a/spec/support/features/resolving_discussions_in_issues_shared_examples.rb b/spec/support/features/resolving_discussions_in_issues_shared_examples.rb
index 8d0e03134d0..d4f8a87d0d8 100644
--- a/spec/support/features/resolving_discussions_in_issues_shared_examples.rb
+++ b/spec/support/features/resolving_discussions_in_issues_shared_examples.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
shared_examples 'creating an issue for a thread' do
it 'shows an issue with the title filled in' do
title_field = page.find_field('issue[title]')
diff --git a/spec/support/features/rss_shared_examples.rb b/spec/support/features/rss_shared_examples.rb
index 0de92aedba5..c97eeba87db 100644
--- a/spec/support/features/rss_shared_examples.rb
+++ b/spec/support/features/rss_shared_examples.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
shared_examples "an autodiscoverable RSS feed with current_user's feed token" do
it "has an RSS autodiscovery link tag with current_user's feed token" do
expect(page).to have_css("link[type*='atom+xml'][href*='feed_token=#{user.feed_token}']", visible: false)
diff --git a/spec/support/features/variable_list_shared_examples.rb b/spec/support/features/variable_list_shared_examples.rb
index 01531864c1f..0f8ad2c6536 100644
--- a/spec/support/features/variable_list_shared_examples.rb
+++ b/spec/support/features/variable_list_shared_examples.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
shared_examples 'variable list' do
it 'shows list of variables' do
page.within('.js-ci-variable-list-section') do
diff --git a/spec/support/forgery_protection.rb b/spec/support/forgery_protection.rb
index fa87d5fa881..1d6ea013292 100644
--- a/spec/support/forgery_protection.rb
+++ b/spec/support/forgery_protection.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module ForgeryProtection
def with_forgery_protection
ActionController::Base.allow_forgery_protection = true
diff --git a/spec/support/google_api/cloud_platform_helpers.rb b/spec/support/google_api/cloud_platform_helpers.rb
index 2fdbddd40c2..a1328ef0d13 100644
--- a/spec/support/google_api/cloud_platform_helpers.rb
+++ b/spec/support/google_api/cloud_platform_helpers.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module GoogleApi
module CloudPlatformHelpers
def stub_google_api_validate_token
diff --git a/spec/support/helpers/api_helpers.rb b/spec/support/helpers/api_helpers.rb
index 4a9ce9beb78..aff0f87b6e4 100644
--- a/spec/support/helpers/api_helpers.rb
+++ b/spec/support/helpers/api_helpers.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module ApiHelpers
# Public: Prepend a request path with the path to the API
#
@@ -30,11 +32,12 @@ module ApiHelpers
end
if query_string
- full_path << (path.index('?') ? '&' : '?')
- full_path << query_string
- end
+ separator = path.index('?') ? '&' : '?'
- full_path
+ full_path + separator + query_string
+ else
+ full_path
+ end
end
def expect_paginated_array_response(items)
diff --git a/spec/support/helpers/assets_helpers.rb b/spec/support/helpers/assets_helpers.rb
index 09bbf451671..fa24ad9ad2a 100644
--- a/spec/support/helpers/assets_helpers.rb
+++ b/spec/support/helpers/assets_helpers.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module AssetsHelpers
# In a CI environment the assets are not compiled, as there is a CI job
# `compile-assets` that compiles them in the prepare stage for all following
diff --git a/spec/support/helpers/bare_repo_operations.rb b/spec/support/helpers/bare_repo_operations.rb
index 3f4a4243cb6..099610f087d 100644
--- a/spec/support/helpers/bare_repo_operations.rb
+++ b/spec/support/helpers/bare_repo_operations.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'zlib'
class BareRepoOperations
diff --git a/spec/support/helpers/board_helpers.rb b/spec/support/helpers/board_helpers.rb
index b85fde222ea..683ee3e4bf2 100644
--- a/spec/support/helpers/board_helpers.rb
+++ b/spec/support/helpers/board_helpers.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module BoardHelpers
def click_card(card)
within card do
diff --git a/spec/support/helpers/capybara_helpers.rb b/spec/support/helpers/capybara_helpers.rb
index bcc2df44708..5abbc1e2951 100644
--- a/spec/support/helpers/capybara_helpers.rb
+++ b/spec/support/helpers/capybara_helpers.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module CapybaraHelpers
# Execute a block a certain number of times before considering it a failure
#
diff --git a/spec/support/helpers/ci_artifact_metadata_generator.rb b/spec/support/helpers/ci_artifact_metadata_generator.rb
index ef638d59d2d..e02501565a9 100644
--- a/spec/support/helpers/ci_artifact_metadata_generator.rb
+++ b/spec/support/helpers/ci_artifact_metadata_generator.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
# frozen_sting_literal: true
# This generates fake CI metadata .gz for testing
diff --git a/spec/support/helpers/cookie_helper.rb b/spec/support/helpers/cookie_helper.rb
index 5ff7b0b68c9..ea4be12355b 100644
--- a/spec/support/helpers/cookie_helper.rb
+++ b/spec/support/helpers/cookie_helper.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
# Helper for setting cookies in Selenium/WebDriver
#
module CookieHelper
diff --git a/spec/support/helpers/cycle_analytics_helpers.rb b/spec/support/helpers/cycle_analytics_helpers.rb
index 100e439ef44..575b2e779c5 100644
--- a/spec/support/helpers/cycle_analytics_helpers.rb
+++ b/spec/support/helpers/cycle_analytics_helpers.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module CycleAnalyticsHelpers
include GitHelpers
diff --git a/spec/support/helpers/database_connection_helpers.rb b/spec/support/helpers/database_connection_helpers.rb
index 763329499f0..10ea7b5de91 100644
--- a/spec/support/helpers/database_connection_helpers.rb
+++ b/spec/support/helpers/database_connection_helpers.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module DatabaseConnectionHelpers
def run_with_new_database_connection
pool = ActiveRecord::Base.connection_pool
diff --git a/spec/support/helpers/devise_helpers.rb b/spec/support/helpers/devise_helpers.rb
index fb2a110422a..70fc6a48414 100644
--- a/spec/support/helpers/devise_helpers.rb
+++ b/spec/support/helpers/devise_helpers.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module DeviseHelpers
# explicitly tells Devise which mapping to use
# this is needed when we are testing a Devise controller bypassing the router
diff --git a/spec/support/helpers/drag_to_helper.rb b/spec/support/helpers/drag_to_helper.rb
index 6d53ad0b602..2e9932f2e8a 100644
--- a/spec/support/helpers/drag_to_helper.rb
+++ b/spec/support/helpers/drag_to_helper.rb
@@ -1,6 +1,23 @@
+# frozen_string_literal: true
+
module DragTo
- def drag_to(list_from_index: 0, from_index: 0, to_index: 0, list_to_index: 0, selector: '', scrollable: 'body', duration: 1000)
- evaluate_script("simulateDrag({scrollable: $('#{scrollable}').get(0), duration: #{duration}, from: {el: $('#{selector}').eq(#{list_from_index}).get(0), index: #{from_index}}, to: {el: $('#{selector}').eq(#{list_to_index}).get(0), index: #{to_index}}});")
+ def drag_to(list_from_index: 0, from_index: 0, to_index: 0, list_to_index: 0, selector: '', scrollable: 'body', duration: 1000, perform_drop: true)
+ js = <<~JS
+ simulateDrag({
+ scrollable: document.querySelector('#{scrollable}'),
+ duration: #{duration},
+ from: {
+ el: document.querySelectorAll('#{selector}')[#{list_from_index}],
+ index: #{from_index}
+ },
+ to: {
+ el: document.querySelectorAll('#{selector}')[#{list_to_index}],
+ index: #{to_index}
+ },
+ performDrop: #{perform_drop}
+ });
+ JS
+ evaluate_script(js)
Timeout.timeout(Capybara.default_max_wait_time) do
loop while drag_active?
diff --git a/spec/support/helpers/dropzone_helper.rb b/spec/support/helpers/dropzone_helper.rb
index fe72d320fcf..a0f261b312e 100644
--- a/spec/support/helpers/dropzone_helper.rb
+++ b/spec/support/helpers/dropzone_helper.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module DropzoneHelper
# Provides a way to perform `attach_file` for a Dropzone-based file input
#
diff --git a/spec/support/helpers/email_helpers.rb b/spec/support/helpers/email_helpers.rb
index ed049daba80..024340310a1 100644
--- a/spec/support/helpers/email_helpers.rb
+++ b/spec/support/helpers/email_helpers.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module EmailHelpers
def sent_to_user(user, recipients: email_recipients)
recipients.count { |to| to == user.notification_email }
@@ -29,6 +31,10 @@ module EmailHelpers
expect(ActionMailer::Base.deliveries).to be_empty
end
+ def should_email_anyone
+ expect(ActionMailer::Base.deliveries).not_to be_empty
+ end
+
def email_recipients(kind: :to)
ActionMailer::Base.deliveries.flat_map(&kind)
end
diff --git a/spec/support/helpers/exclusive_lease_helpers.rb b/spec/support/helpers/exclusive_lease_helpers.rb
index 383cc7dee81..77703e20602 100644
--- a/spec/support/helpers/exclusive_lease_helpers.rb
+++ b/spec/support/helpers/exclusive_lease_helpers.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module ExclusiveLeaseHelpers
def stub_exclusive_lease(key = nil, uuid = 'uuid', renew: false, timeout: nil)
key ||= instance_of(String)
diff --git a/spec/support/helpers/expect_next_instance_of.rb b/spec/support/helpers/expect_next_instance_of.rb
index b95046b2b42..749d2cb2a56 100644
--- a/spec/support/helpers/expect_next_instance_of.rb
+++ b/spec/support/helpers/expect_next_instance_of.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module ExpectNextInstanceOf
def expect_next_instance_of(klass, *new_args)
receive_new = receive(:new)
diff --git a/spec/support/helpers/expect_offense.rb b/spec/support/helpers/expect_offense.rb
index 35718ba90c5..76301fe19ff 100644
--- a/spec/support/helpers/expect_offense.rb
+++ b/spec/support/helpers/expect_offense.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'rubocop/rspec/support'
# https://github.com/backus/rubocop-rspec/blob/master/spec/support/expect_offense.rb
diff --git a/spec/support/helpers/expect_request_with_status.rb b/spec/support/helpers/expect_request_with_status.rb
new file mode 100644
index 00000000000..0469a94e336
--- /dev/null
+++ b/spec/support/helpers/expect_request_with_status.rb
@@ -0,0 +1,11 @@
+# frozen_string_literal: true
+
+module ExpectRequestWithStatus
+ def expect_request_with_status(status)
+ expect do
+ yield
+
+ expect(response).to have_gitlab_http_status(status)
+ end
+ end
+end
diff --git a/spec/support/helpers/fake_blob_helpers.rb b/spec/support/helpers/fake_blob_helpers.rb
index 801ca8b7412..ef4740638ff 100644
--- a/spec/support/helpers/fake_blob_helpers.rb
+++ b/spec/support/helpers/fake_blob_helpers.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module FakeBlobHelpers
class FakeBlob
include BlobLike
diff --git a/spec/support/helpers/fake_migration_classes.rb b/spec/support/helpers/fake_migration_classes.rb
index c7766df7a52..6c066b3b199 100644
--- a/spec/support/helpers/fake_migration_classes.rb
+++ b/spec/support/helpers/fake_migration_classes.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
class FakeRenameReservedPathMigrationV1 < ActiveRecord::Migration[4.2]
include Gitlab::Database::RenameReservedPathsMigration::V1
diff --git a/spec/support/helpers/fake_u2f_device.rb b/spec/support/helpers/fake_u2f_device.rb
index 22cd8152d77..f765b277175 100644
--- a/spec/support/helpers/fake_u2f_device.rb
+++ b/spec/support/helpers/fake_u2f_device.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
class FakeU2fDevice
attr_reader :name
diff --git a/spec/support/helpers/features/branches_helpers.rb b/spec/support/helpers/features/branches_helpers.rb
index df88fd425c9..2a50b41cb4e 100644
--- a/spec/support/helpers/features/branches_helpers.rb
+++ b/spec/support/helpers/features/branches_helpers.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
# These helpers allow you to manipulate with sorting features.
#
# Usage:
diff --git a/spec/support/helpers/features/notes_helpers.rb b/spec/support/helpers/features/notes_helpers.rb
index 8a139fafac2..8c27f81930d 100644
--- a/spec/support/helpers/features/notes_helpers.rb
+++ b/spec/support/helpers/features/notes_helpers.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
# These helpers allow you to manipulate with notes.
#
# Usage:
@@ -21,6 +23,14 @@ module Spec
end
end
+ def edit_note(note_text_to_edit, new_note_text)
+ page.within('#notes-list li.note', text: note_text_to_edit) do
+ find('.js-note-edit').click
+ fill_in('note[note]', with: new_note_text)
+ find('.js-comment-button').click
+ end
+ end
+
def preview_note(text)
page.within('.js-main-target-form') do
filled_text = fill_in('note[note]', with: text)
diff --git a/spec/support/helpers/features/sorting_helpers.rb b/spec/support/helpers/features/sorting_helpers.rb
index 003ecb251fe..a6428bf8573 100644
--- a/spec/support/helpers/features/sorting_helpers.rb
+++ b/spec/support/helpers/features/sorting_helpers.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
# These helpers allow you to manipulate with sorting features.
#
# Usage:
diff --git a/spec/support/helpers/filter_spec_helper.rb b/spec/support/helpers/filter_spec_helper.rb
index 721d359c2ee..95c24d76dcd 100644
--- a/spec/support/helpers/filter_spec_helper.rb
+++ b/spec/support/helpers/filter_spec_helper.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
# Helper methods for Banzai filter specs
#
# Must be included into specs manually
diff --git a/spec/support/helpers/filtered_search_helpers.rb b/spec/support/helpers/filtered_search_helpers.rb
index 34ef185ea27..39c818b1763 100644
--- a/spec/support/helpers/filtered_search_helpers.rb
+++ b/spec/support/helpers/filtered_search_helpers.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module FilteredSearchHelpers
def filtered_search
page.find('.filtered-search')
diff --git a/spec/support/helpers/fixture_helpers.rb b/spec/support/helpers/fixture_helpers.rb
index 611d19f36a0..7b3b8ae5f7a 100644
--- a/spec/support/helpers/fixture_helpers.rb
+++ b/spec/support/helpers/fixture_helpers.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module FixtureHelpers
def fixture_file(filename, dir: '')
return '' if filename.blank?
diff --git a/spec/support/helpers/git_http_helpers.rb b/spec/support/helpers/git_http_helpers.rb
index c83860d7b51..de8bb9ac8e3 100644
--- a/spec/support/helpers/git_http_helpers.rb
+++ b/spec/support/helpers/git_http_helpers.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require_relative 'workhorse_helpers'
module GitHttpHelpers
diff --git a/spec/support/helpers/gitlab_verify_helpers.rb b/spec/support/helpers/gitlab_verify_helpers.rb
index 5df4bf24ec2..9901ce374ed 100644
--- a/spec/support/helpers/gitlab_verify_helpers.rb
+++ b/spec/support/helpers/gitlab_verify_helpers.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module GitlabVerifyHelpers
def collect_ranges(args = {})
verifier = described_class.new(args.merge(batch_size: 1))
diff --git a/spec/support/helpers/graphql_helpers.rb b/spec/support/helpers/graphql_helpers.rb
index ec3c460cd37..d86371d70b9 100644
--- a/spec/support/helpers/graphql_helpers.rb
+++ b/spec/support/helpers/graphql_helpers.rb
@@ -1,6 +1,10 @@
+# frozen_string_literal: true
+
module GraphqlHelpers
MutationDefinition = Struct.new(:query, :variables)
+ NoData = Class.new(StandardError)
+
# makes an underscored string look like a fieldname
# "merge_request" => "mergeRequest"
def self.fieldnamerize(underscored_field_name)
@@ -156,8 +160,9 @@ module GraphqlHelpers
post_graphql(mutation.query, current_user: current_user, variables: mutation.variables)
end
+ # Raises an error if no data is found
def graphql_data
- json_response['data']
+ json_response['data'] || (raise NoData, graphql_errors)
end
def graphql_errors
@@ -171,8 +176,9 @@ module GraphqlHelpers
end
end
+ # Raises an error if no response is found
def graphql_mutation_response(mutation_name)
- graphql_data[GraphqlHelpers.fieldnamerize(mutation_name)]
+ graphql_data.fetch(GraphqlHelpers.fieldnamerize(mutation_name))
end
def nested_fields?(field)
diff --git a/spec/support/helpers/import_spec_helper.rb b/spec/support/helpers/import_spec_helper.rb
index d4eced724fa..d8fb2ba08af 100644
--- a/spec/support/helpers/import_spec_helper.rb
+++ b/spec/support/helpers/import_spec_helper.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'ostruct'
# Helper methods for controller specs in the Import namespace
diff --git a/spec/support/helpers/input_helper.rb b/spec/support/helpers/input_helper.rb
index acbb42274ec..5136f8e9cb8 100644
--- a/spec/support/helpers/input_helper.rb
+++ b/spec/support/helpers/input_helper.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
# see app/assets/javascripts/test_utils/simulate_input.js
module InputHelper
diff --git a/spec/support/helpers/inspect_requests.rb b/spec/support/helpers/inspect_requests.rb
index 88ddc5c7f6c..4a1d9cb8539 100644
--- a/spec/support/helpers/inspect_requests.rb
+++ b/spec/support/helpers/inspect_requests.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require_relative './wait_for_requests'
module InspectRequests
diff --git a/spec/support/helpers/issue_helpers.rb b/spec/support/helpers/issue_helpers.rb
index ffd72515f37..82b954a92e2 100644
--- a/spec/support/helpers/issue_helpers.rb
+++ b/spec/support/helpers/issue_helpers.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module IssueHelpers
def visit_issues(project, opts = {})
visit project_issues_path project, opts
diff --git a/spec/support/helpers/javascript_fixtures_helpers.rb b/spec/support/helpers/javascript_fixtures_helpers.rb
index cdd7724cc13..7ec65318ec5 100644
--- a/spec/support/helpers/javascript_fixtures_helpers.rb
+++ b/spec/support/helpers/javascript_fixtures_helpers.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'action_dispatch/testing/test_request'
require 'fileutils'
@@ -19,7 +21,7 @@ module JavaScriptFixturesHelpers
end
def fixture_root_path
- (Gitlab.ee? ? 'ee/' : '') + 'spec/javascripts/fixtures'
+ 'tmp/tests/frontend/fixtures' + (Gitlab.ee? ? '-ee' : '')
end
# Public: Removes all fixture files from given directory
diff --git a/spec/support/helpers/jira_service_helper.rb b/spec/support/helpers/jira_service_helper.rb
index 7e955f3d593..57c33c81ea3 100644
--- a/spec/support/helpers/jira_service_helper.rb
+++ b/spec/support/helpers/jira_service_helper.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module JiraServiceHelper
JIRA_URL = "http://jira.example.net".freeze
JIRA_API = JIRA_URL + "/rest/api/2"
diff --git a/spec/support/helpers/key_generator_helper.rb b/spec/support/helpers/key_generator_helper.rb
index d55d8312c65..59c8eeb3692 100644
--- a/spec/support/helpers/key_generator_helper.rb
+++ b/spec/support/helpers/key_generator_helper.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Spec
module Support
module Helpers
@@ -33,7 +35,7 @@ module Spec
# Packs string components into an openssh-encoded pubkey.
def pack_pubkey_components(strings)
- (strings.map { |s| [s.length].pack('N') }).zip(strings).flatten.join
+ (strings.flat_map { |s| [s.length].pack('N') }).zip(strings).join
end
end
end
diff --git a/spec/support/helpers/kubernetes_helpers.rb b/spec/support/helpers/kubernetes_helpers.rb
index 3c7bcba2b42..538a5b8ef3c 100644
--- a/spec/support/helpers/kubernetes_helpers.rb
+++ b/spec/support/helpers/kubernetes_helpers.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module KubernetesHelpers
include Gitlab::Kubernetes
@@ -199,6 +201,11 @@ module KubernetesHelpers
.to_return(kube_response({}))
end
+ def stub_kubeclient_put_role(api_url, name, namespace: 'default')
+ WebMock.stub_request(:put, api_url + "/apis/rbac.authorization.k8s.io/v1/namespaces/#{namespace}/roles/#{name}")
+ .to_return(kube_response({}))
+ end
+
def kube_v1_secret_body(**options)
{
"kind" => "SecretList",
diff --git a/spec/support/helpers/ldap_helpers.rb b/spec/support/helpers/ldap_helpers.rb
index 66ca5d7f0a3..dce8a3803f5 100644
--- a/spec/support/helpers/ldap_helpers.rb
+++ b/spec/support/helpers/ldap_helpers.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module LdapHelpers
def ldap_adapter(provider = 'ldapmain', ldap = double(:ldap))
::Gitlab::Auth::LDAP::Adapter.new(provider, ldap)
diff --git a/spec/support/helpers/live_debugger.rb b/spec/support/helpers/live_debugger.rb
index 911eb48a8ca..d6091035b59 100644
--- a/spec/support/helpers/live_debugger.rb
+++ b/spec/support/helpers/live_debugger.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'io/console'
module LiveDebugger
diff --git a/spec/support/helpers/login_helpers.rb b/spec/support/helpers/login_helpers.rb
index 0cb99b4e087..2b508ee6f2c 100644
--- a/spec/support/helpers/login_helpers.rb
+++ b/spec/support/helpers/login_helpers.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require_relative 'devise_helpers'
module LoginHelpers
diff --git a/spec/support/helpers/markdown_feature.rb b/spec/support/helpers/markdown_feature.rb
index 96401379cf0..eea03fb9325 100644
--- a/spec/support/helpers/markdown_feature.rb
+++ b/spec/support/helpers/markdown_feature.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
# This is a helper class used by the GitLab Markdown feature spec
#
# Because the feature spec only cares about the output of the Markdown, and the
diff --git a/spec/support/helpers/memory_usage_helper.rb b/spec/support/helpers/memory_usage_helper.rb
new file mode 100644
index 00000000000..984ea8cc571
--- /dev/null
+++ b/spec/support/helpers/memory_usage_helper.rb
@@ -0,0 +1,37 @@
+# frozen_string_literal: true
+
+module MemoryUsageHelper
+ extend ActiveSupport::Concern
+
+ def gather_memory_data(csv_path)
+ write_csv_entry(csv_path,
+ {
+ example_group_path: TestEnv.topmost_example_group[:location],
+ example_group_description: TestEnv.topmost_example_group[:description],
+ time: Time.current,
+ job_name: ENV['CI_JOB_NAME']
+ }.merge(get_memory_usage))
+ end
+
+ def write_csv_entry(path, entry)
+ CSV.open(path, "a", headers: entry.keys, write_headers: !File.exist?(path)) do |file|
+ file << entry.values
+ end
+ end
+
+ def get_memory_usage
+ output, status = Gitlab::Popen.popen(%w(free -m))
+ abort "`free -m` return code is #{status}: #{output}" unless status.zero?
+
+ result = output.split("\n")[1].split(" ")[1..-1]
+ attrs = %i(m_total m_used m_free m_shared m_buffers_cache m_available).freeze
+
+ attrs.zip(result).to_h
+ end
+
+ included do |config|
+ config.after(:all) do
+ gather_memory_data(ENV['MEMORY_TEST_PATH']) if ENV['MEMORY_TEST_PATH']
+ end
+ end
+end
diff --git a/spec/support/helpers/merge_request_diff_helpers.rb b/spec/support/helpers/merge_request_diff_helpers.rb
index 3b49d0b3319..49beecc6d4b 100644
--- a/spec/support/helpers/merge_request_diff_helpers.rb
+++ b/spec/support/helpers/merge_request_diff_helpers.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module MergeRequestDiffHelpers
def click_diff_line(line_holder, diff_side = nil)
line = get_line_components(line_holder, diff_side)
diff --git a/spec/support/helpers/merge_request_helpers.rb b/spec/support/helpers/merge_request_helpers.rb
index 772adff4626..3c359bc9353 100644
--- a/spec/support/helpers/merge_request_helpers.rb
+++ b/spec/support/helpers/merge_request_helpers.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module MergeRequestHelpers
def visit_merge_requests(project, opts = {})
visit project_merge_requests_path project, opts
diff --git a/spec/support/helpers/metrics_dashboard_helpers.rb b/spec/support/helpers/metrics_dashboard_helpers.rb
index 1511a2f6b49..0e86b6dfda7 100644
--- a/spec/support/helpers/metrics_dashboard_helpers.rb
+++ b/spec/support/helpers/metrics_dashboard_helpers.rb
@@ -18,6 +18,14 @@ module MetricsDashboardHelpers
project.repository.refresh_method_caches([:metrics_dashboard])
end
+ def system_dashboard_path
+ Metrics::Dashboard::SystemDashboardService::SYSTEM_DASHBOARD_PATH
+ end
+
+ def business_metric_title
+ PrometheusMetricEnums.group_details[:business][:group_title]
+ end
+
shared_examples_for 'misconfigured dashboard service response' do |status_code|
it 'returns an appropriate message and status code' do
result = service_call
diff --git a/spec/support/helpers/migrations_helpers.rb b/spec/support/helpers/migrations_helpers.rb
index cc1a28cb264..2727ab7fb1e 100644
--- a/spec/support/helpers/migrations_helpers.rb
+++ b/spec/support/helpers/migrations_helpers.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module MigrationsHelpers
def active_record_base
ActiveRecord::Base
@@ -18,8 +20,12 @@ module MigrationsHelpers
ActiveRecord::Migrator.migrations_paths
end
+ def migration_context
+ ActiveRecord::MigrationContext.new(migrations_paths)
+ end
+
def migrations
- ActiveRecord::Migrator.migrations(migrations_paths)
+ migration_context.migrations
end
def clear_schema_cache!
@@ -96,8 +102,7 @@ module MigrationsHelpers
def schema_migrate_down!
disable_migrations_output do
- ActiveRecord::Migrator.migrate(migrations_paths,
- migration_schema_version)
+ migration_context.down(migration_schema_version)
end
reset_column_in_all_models
@@ -107,7 +112,7 @@ module MigrationsHelpers
reset_column_in_all_models
disable_migrations_output do
- ActiveRecord::Migrator.migrate(migrations_paths)
+ migration_context.up
end
reset_column_in_all_models
@@ -123,7 +128,7 @@ module MigrationsHelpers
end
def migrate!
- ActiveRecord::Migrator.up(migrations_paths) do |migration|
+ migration_context.up do |migration|
migration.name == described_class.name
end
end
diff --git a/spec/support/helpers/mobile_helpers.rb b/spec/support/helpers/mobile_helpers.rb
index 4230d315d9b..94dbd2fb1b7 100644
--- a/spec/support/helpers/mobile_helpers.rb
+++ b/spec/support/helpers/mobile_helpers.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module MobileHelpers
def resize_screen_xs
resize_window(575, 768)
diff --git a/spec/support/helpers/note_interaction_helpers.rb b/spec/support/helpers/note_interaction_helpers.rb
index 79a0aa174b1..a4322618cd3 100644
--- a/spec/support/helpers/note_interaction_helpers.rb
+++ b/spec/support/helpers/note_interaction_helpers.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module NoteInteractionHelpers
def open_more_actions_dropdown(note)
note_element = find("#note_#{note.id}")
diff --git a/spec/support/helpers/notification_helpers.rb b/spec/support/helpers/notification_helpers.rb
index 44c2051598c..16ecb338f6e 100644
--- a/spec/support/helpers/notification_helpers.rb
+++ b/spec/support/helpers/notification_helpers.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module NotificationHelpers
extend self
diff --git a/spec/support/helpers/project_forks_helper.rb b/spec/support/helpers/project_forks_helper.rb
index bcb11a09b36..b2d22853e4c 100644
--- a/spec/support/helpers/project_forks_helper.rb
+++ b/spec/support/helpers/project_forks_helper.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module ProjectForksHelper
def fork_project(project, user = nil, params = {})
Gitlab::GitalyClient.allow_n_plus_1_calls do
diff --git a/spec/support/helpers/prometheus_helpers.rb b/spec/support/helpers/prometheus_helpers.rb
index db662836013..7c03746a395 100644
--- a/spec/support/helpers/prometheus_helpers.rb
+++ b/spec/support/helpers/prometheus_helpers.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module PrometheusHelpers
def prometheus_memory_query(environment_slug)
%{avg(container_memory_usage_bytes{container_name!="POD",environment="#{environment_slug}"}) / 2^20}
@@ -74,6 +76,14 @@ module PrometheusHelpers
WebMock.stub_request(:any, /prometheus.example.com/)
end
+ def stub_any_prometheus_request_with_response(status: 200, headers: {}, body: nil)
+ stub_any_prometheus_request.to_return({
+ status: status,
+ headers: { 'Content-Type' => 'application/json' }.merge(headers),
+ body: body || prometheus_values_body.to_json
+ })
+ end
+
def stub_all_prometheus_requests(environment_slug, body: nil, status: 200)
stub_prometheus_request(
prometheus_query_with_time_url(prometheus_memory_query(environment_slug), Time.now.utc),
diff --git a/spec/support/helpers/query_recorder.rb b/spec/support/helpers/query_recorder.rb
index f77b43391dd..d936dc6de41 100644
--- a/spec/support/helpers/query_recorder.rb
+++ b/spec/support/helpers/query_recorder.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module ActiveRecord
class QueryRecorder
attr_reader :log, :skip_cached, :cached
diff --git a/spec/support/helpers/quick_actions_helpers.rb b/spec/support/helpers/quick_actions_helpers.rb
index 361190aa352..cb853f5363f 100644
--- a/spec/support/helpers/quick_actions_helpers.rb
+++ b/spec/support/helpers/quick_actions_helpers.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module QuickActionsHelpers
def write_note(text)
Sidekiq::Testing.fake! do
diff --git a/spec/support/helpers/rake_helpers.rb b/spec/support/helpers/rake_helpers.rb
index 7d8d7750bf3..d8f354a69da 100644
--- a/spec/support/helpers/rake_helpers.rb
+++ b/spec/support/helpers/rake_helpers.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module RakeHelpers
def run_rake_task(task_name, *args)
Rake::Task[task_name].reenable
diff --git a/spec/support/helpers/reactive_caching_helpers.rb b/spec/support/helpers/reactive_caching_helpers.rb
index 528da37e8cf..aa9d3b3a199 100644
--- a/spec/support/helpers/reactive_caching_helpers.rb
+++ b/spec/support/helpers/reactive_caching_helpers.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module ReactiveCachingHelpers
def reactive_cache_key(subject, *qualifiers)
([subject.class.reactive_cache_key.call(subject)].flatten + qualifiers).join(':')
diff --git a/spec/support/helpers/redis_without_keys.rb b/spec/support/helpers/redis_without_keys.rb
index 6220167dee6..e030f1028f7 100644
--- a/spec/support/helpers/redis_without_keys.rb
+++ b/spec/support/helpers/redis_without_keys.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
class Redis
ForbiddenCommand = Class.new(StandardError)
diff --git a/spec/support/helpers/reference_parser_helpers.rb b/spec/support/helpers/reference_parser_helpers.rb
index 9f27502aa52..f96a01d15b5 100644
--- a/spec/support/helpers/reference_parser_helpers.rb
+++ b/spec/support/helpers/reference_parser_helpers.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module ReferenceParserHelpers
def empty_html_link
Nokogiri::HTML.fragment('<a></a>').children[0]
diff --git a/spec/support/helpers/repo_helpers.rb b/spec/support/helpers/repo_helpers.rb
index 44d95a029af..ca4d2acbf2c 100644
--- a/spec/support/helpers/repo_helpers.rb
+++ b/spec/support/helpers/repo_helpers.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module RepoHelpers
extend self
diff --git a/spec/support/helpers/routes_helpers.rb b/spec/support/helpers/routes_helpers.rb
index c4129606418..2a7cd81cbe3 100644
--- a/spec/support/helpers/routes_helpers.rb
+++ b/spec/support/helpers/routes_helpers.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module RoutesHelpers
def fake_routes(&block)
@routes = @routes.dup
diff --git a/spec/support/helpers/search_helpers.rb b/spec/support/helpers/search_helpers.rb
index abbbb636d66..815337f8615 100644
--- a/spec/support/helpers/search_helpers.rb
+++ b/spec/support/helpers/search_helpers.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module SearchHelpers
def select_filter(name)
find(:xpath, "//ul[contains(@class, 'search-filter')]//a[contains(.,'#{name}')]").click
diff --git a/spec/support/helpers/seed_repo.rb b/spec/support/helpers/seed_repo.rb
index 71f1a86b0c1..20738b45129 100644
--- a/spec/support/helpers/seed_repo.rb
+++ b/spec/support/helpers/seed_repo.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
# This file is generated by generate-seed-repo-rb. Do not edit this file manually.
#
# Seed repo:
diff --git a/spec/support/helpers/select2_helper.rb b/spec/support/helpers/select2_helper.rb
index 87672c8896d..9c42c2b0d8b 100644
--- a/spec/support/helpers/select2_helper.rb
+++ b/spec/support/helpers/select2_helper.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require_relative 'wait_for_requests'
# Select2 ajax programmatic helper
diff --git a/spec/support/helpers/selection_helper.rb b/spec/support/helpers/selection_helper.rb
index b4725b137b2..a5f9ca76f6e 100644
--- a/spec/support/helpers/selection_helper.rb
+++ b/spec/support/helpers/selection_helper.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module SelectionHelper
def select_element(selector)
find(selector)
diff --git a/spec/support/helpers/smime_helper.rb b/spec/support/helpers/smime_helper.rb
new file mode 100644
index 00000000000..656b3e196ba
--- /dev/null
+++ b/spec/support/helpers/smime_helper.rb
@@ -0,0 +1,55 @@
+module SmimeHelper
+ include OpenSSL
+
+ INFINITE_EXPIRY = 1000.years
+ SHORT_EXPIRY = 30.minutes
+
+ def generate_root
+ issue(signed_by: nil, expires_in: INFINITE_EXPIRY, certificate_authority: true)
+ end
+
+ def generate_cert(root_ca:, expires_in: SHORT_EXPIRY)
+ issue(signed_by: root_ca, expires_in: expires_in, certificate_authority: false)
+ end
+
+ # returns a hash { key:, cert: } containing a generated key, cert pair
+ def issue(email_address: 'test@example.com', signed_by:, expires_in:, certificate_authority:)
+ key = OpenSSL::PKey::RSA.new(4096)
+ public_key = key.public_key
+
+ subject = if certificate_authority
+ X509::Name.parse("/CN=EU")
+ else
+ X509::Name.parse("/CN=#{email_address}")
+ end
+
+ cert = X509::Certificate.new
+ cert.subject = subject
+
+ cert.issuer = signed_by&.fetch(:cert, nil)&.subject || subject
+
+ cert.not_before = Time.now
+ cert.not_after = expires_in.from_now
+ cert.public_key = public_key
+ cert.serial = 0x0
+ cert.version = 2
+
+ extension_factory = X509::ExtensionFactory.new
+ if certificate_authority
+ extension_factory.subject_certificate = cert
+ extension_factory.issuer_certificate = cert
+ cert.add_extension(extension_factory.create_extension('subjectKeyIdentifier', 'hash'))
+ cert.add_extension(extension_factory.create_extension('basicConstraints', 'CA:TRUE', true))
+ cert.add_extension(extension_factory.create_extension('keyUsage', 'cRLSign,keyCertSign', true))
+ else
+ cert.add_extension(extension_factory.create_extension('subjectAltName', "email:#{email_address}", false))
+ cert.add_extension(extension_factory.create_extension('basicConstraints', 'CA:FALSE', true))
+ cert.add_extension(extension_factory.create_extension('keyUsage', 'digitalSignature,keyEncipherment', true))
+ cert.add_extension(extension_factory.create_extension('extendedKeyUsage', 'clientAuth,emailProtection', false))
+ end
+
+ cert.sign(signed_by&.fetch(:key, nil) || key, Digest::SHA256.new)
+
+ { key: key, cert: cert }
+ end
+end
diff --git a/spec/support/helpers/sorting_helper.rb b/spec/support/helpers/sorting_helper.rb
index e505a6b7258..3801d25fb63 100644
--- a/spec/support/helpers/sorting_helper.rb
+++ b/spec/support/helpers/sorting_helper.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
# Helper allows you to sort items
#
# Params
diff --git a/spec/support/helpers/stub_configuration.rb b/spec/support/helpers/stub_configuration.rb
index c372a3f0e49..dec7898d8d2 100644
--- a/spec/support/helpers/stub_configuration.rb
+++ b/spec/support/helpers/stub_configuration.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'active_support/core_ext/hash/transform_values'
require 'active_support/hash_with_indifferent_access'
require 'active_support/dependencies'
@@ -28,6 +30,10 @@ module StubConfiguration
allow(Gitlab.config.gitlab).to receive_messages(to_settings(messages))
end
+ def stub_config(messages)
+ allow(Gitlab.config).to receive_messages(to_settings(messages))
+ end
+
def stub_default_url_options(host: "localhost", protocol: "http")
url_options = { host: host, protocol: protocol }
allow(Rails.application.routes).to receive(:default_url_options).and_return(url_options)
@@ -65,6 +71,10 @@ module StubConfiguration
allow(Gitlab.config.artifacts).to receive_messages(to_settings(messages))
end
+ def stub_pages_setting(messages)
+ allow(Gitlab.config.pages).to receive_messages(to_settings(messages))
+ end
+
def stub_storage_settings(messages)
messages.deep_stringify_keys!
diff --git a/spec/support/helpers/stub_env.rb b/spec/support/helpers/stub_env.rb
index 1c2f474a015..8107ffc939f 100644
--- a/spec/support/helpers/stub_env.rb
+++ b/spec/support/helpers/stub_env.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
# Inspired by https://github.com/ljkbennett/stub_env/blob/master/lib/stub_env/helpers.rb
module StubENV
def stub_env(key_or_hash, value = nil)
diff --git a/spec/support/helpers/stub_feature_flags.rb b/spec/support/helpers/stub_feature_flags.rb
index 48258692304..6c3efff7262 100644
--- a/spec/support/helpers/stub_feature_flags.rb
+++ b/spec/support/helpers/stub_feature_flags.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module StubFeatureFlags
# Stub Feature flags with `flag_name: true/false`
#
diff --git a/spec/support/helpers/stub_gitlab_calls.rb b/spec/support/helpers/stub_gitlab_calls.rb
index 4cb3b18df85..7d10cffe920 100644
--- a/spec/support/helpers/stub_gitlab_calls.rb
+++ b/spec/support/helpers/stub_gitlab_calls.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module StubGitlabCalls
def stub_gitlab_calls
stub_user
@@ -20,6 +22,10 @@ module StubGitlabCalls
allow_any_instance_of(Ci::Pipeline).to receive(:ci_yaml_file) { ci_yaml }
end
+ def stub_pipeline_modified_paths(pipeline, modified_paths)
+ allow(pipeline).to receive(:modified_paths).and_return(modified_paths)
+ end
+
def stub_repository_ci_yaml_file(sha:, path: '.gitlab-ci.yml')
allow_any_instance_of(Repository)
.to receive(:gitlab_ci_yml_for).with(sha, path)
diff --git a/spec/support/helpers/stub_gitlab_data.rb b/spec/support/helpers/stub_gitlab_data.rb
index fa402f35b95..ed518393c03 100644
--- a/spec/support/helpers/stub_gitlab_data.rb
+++ b/spec/support/helpers/stub_gitlab_data.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module StubGitlabData
def gitlab_ci_yaml
File.read(Rails.root.join('spec/support/gitlab_stubs/gitlab_ci.yml'))
diff --git a/spec/support/helpers/stub_metrics.rb b/spec/support/helpers/stub_metrics.rb
index 64983fdf222..e347955efbb 100644
--- a/spec/support/helpers/stub_metrics.rb
+++ b/spec/support/helpers/stub_metrics.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module StubMetrics
def authentication_metrics
Gitlab::Auth::Activity
diff --git a/spec/support/helpers/stub_object_storage.rb b/spec/support/helpers/stub_object_storage.rb
index d31f9908714..e5b8bb712bb 100644
--- a/spec/support/helpers/stub_object_storage.rb
+++ b/spec/support/helpers/stub_object_storage.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module StubObjectStorage
def stub_object_storage_uploader(
config:,
diff --git a/spec/support/helpers/stub_requests.rb b/spec/support/helpers/stub_requests.rb
index 5cad35282c0..473f07dd413 100644
--- a/spec/support/helpers/stub_requests.rb
+++ b/spec/support/helpers/stub_requests.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module StubRequests
IP_ADDRESS_STUB = '8.8.8.9'.freeze
@@ -26,6 +28,19 @@ module StubRequests
.and_return([addr])
end
+ def stub_all_dns(url, ip_address:)
+ url = URI(url)
+ port = 80 # arbitarily chosen, does not matter as we are not going to connect
+ socket = Socket.sockaddr_in(port, ip_address)
+ addr = Addrinfo.new(socket)
+
+ # See Gitlab::UrlBlocker
+ allow(Addrinfo).to receive(:getaddrinfo).and_call_original
+ allow(Addrinfo).to receive(:getaddrinfo)
+ .with(url.hostname, anything, nil, :STREAM)
+ .and_return([addr])
+ end
+
def stubbed_hostname(url, hostname: IP_ADDRESS_STUB)
url = parse_url(url)
url.hostname = hostname
diff --git a/spec/support/helpers/stub_worker.rb b/spec/support/helpers/stub_worker.rb
index 58b7ee93dff..cac839ed5fe 100644
--- a/spec/support/helpers/stub_worker.rb
+++ b/spec/support/helpers/stub_worker.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
# Inspired by https://github.com/ljkbennett/stub_env/blob/master/lib/stub_env/helpers.rb
module StubWorker
def stub_worker(queue:)
diff --git a/spec/support/helpers/terms_helper.rb b/spec/support/helpers/terms_helper.rb
index a00ec14138b..a61bae18f9a 100644
--- a/spec/support/helpers/terms_helper.rb
+++ b/spec/support/helpers/terms_helper.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module TermsHelper
def enforce_terms
stub_env('IN_MEMORY_APPLICATION_SETTINGS', 'false')
diff --git a/spec/support/helpers/test_env.rb b/spec/support/helpers/test_env.rb
index e63099d89b7..a4acf76e1a3 100644
--- a/spec/support/helpers/test_env.rb
+++ b/spec/support/helpers/test_env.rb
@@ -1,7 +1,10 @@
+# frozen_string_literal: true
+
require 'rspec/mocks'
require 'toml-rb'
module TestEnv
+ extend ActiveSupport::Concern
extend self
ComponentFailedToInstallError = Class.new(StandardError)
@@ -108,6 +111,12 @@ module TestEnv
setup_forked_repo
end
+ included do |config|
+ config.append_before do
+ set_current_example_group
+ end
+ end
+
def disable_mailer
allow_any_instance_of(NotificationService).to receive(:mailer)
.and_return(double.as_null_object)
@@ -123,7 +132,7 @@ module TestEnv
# Keeps gitlab-shell and gitlab-test
def clean_test_path
Dir[TMP_TEST_PATH].each do |entry|
- unless File.basename(entry) =~ /\A(gitaly|gitlab-(shell|test|test_bare|test-fork|test-fork_bare))\z/
+ unless test_dirs.include?(File.basename(entry))
FileUtils.rm_rf(entry)
end
end
@@ -134,14 +143,6 @@ module TestEnv
FileUtils.mkdir_p(artifacts_path)
end
- def clean_gitlab_test_path
- Dir[TMP_TEST_PATH].each do |entry|
- unless test_dirs.include?(File.basename(entry))
- FileUtils.rm_rf(entry)
- end
- end
- end
-
def setup_gitlab_shell
component_timed_setup('GitLab Shell',
install_dir: Gitlab.config.gitlab_shell.path,
@@ -297,11 +298,27 @@ module TestEnv
FileUtils.rm_rf(path)
end
+ def current_example_group
+ Thread.current[:current_example_group]
+ end
+
+ # looking for a top-level `describe`
+ def topmost_example_group
+ example_group = current_example_group
+ example_group = example_group[:parent_example_group] until example_group[:parent_example_group].nil?
+ example_group
+ end
+
private
+ def set_current_example_group
+ Thread.current[:current_example_group] = ::RSpec.current_example.metadata[:example_group]
+ end
+
# These are directories that should be preserved at cleanup time
def test_dirs
@test_dirs ||= %w[
+ frontend
gitaly
gitlab-shell
gitlab-test
@@ -346,10 +363,7 @@ module TestEnv
# Try to reset without fetching to avoid using the network.
unless reset.call
raise 'Could not fetch test seed repository.' unless system(*%W(#{Gitlab.config.git.bin_path} -C #{repo_path} fetch origin))
-
- # Before we used Git clone's --mirror option, bare repos could end up
- # with missing refs, clearing them and retrying should fix the issue.
- clean_gitlab_test_path && init unless reset.call
+ raise "Could not update test seed repository, please delete #{repo_path} and try again" unless reset.call
end
end
diff --git a/spec/support/helpers/upload_helpers.rb b/spec/support/helpers/upload_helpers.rb
index 5eead80c935..60e14a8673b 100644
--- a/spec/support/helpers/upload_helpers.rb
+++ b/spec/support/helpers/upload_helpers.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'fileutils'
module UploadHelpers
diff --git a/spec/support/helpers/wait_for_requests.rb b/spec/support/helpers/wait_for_requests.rb
index 45b9faa0fea..3bb2f7c5b51 100644
--- a/spec/support/helpers/wait_for_requests.rb
+++ b/spec/support/helpers/wait_for_requests.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module WaitForRequests
extend self
diff --git a/spec/support/helpers/wait_helpers.rb b/spec/support/helpers/wait_helpers.rb
index 7e8e25798e8..a8c4408db59 100644
--- a/spec/support/helpers/wait_helpers.rb
+++ b/spec/support/helpers/wait_helpers.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module WaitHelpers
extend self
diff --git a/spec/support/helpers/wiki_helpers.rb b/spec/support/helpers/wiki_helpers.rb
index 8165403cb60..06cea728b42 100644
--- a/spec/support/helpers/wiki_helpers.rb
+++ b/spec/support/helpers/wiki_helpers.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module WikiHelpers
extend self
diff --git a/spec/support/helpers/workhorse_helpers.rb b/spec/support/helpers/workhorse_helpers.rb
index ef1f9f68671..4488e5f227e 100644
--- a/spec/support/helpers/workhorse_helpers.rb
+++ b/spec/support/helpers/workhorse_helpers.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module WorkhorseHelpers
extend self
diff --git a/spec/support/http_io/http_io_helpers.rb b/spec/support/http_io/http_io_helpers.rb
index 42144870eb5..0193db81fa9 100644
--- a/spec/support/http_io/http_io_helpers.rb
+++ b/spec/support/http_io/http_io_helpers.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module HttpIOHelpers
def stub_remote_url_206(url, file_path)
WebMock.stub_request(:get, url)
diff --git a/spec/support/import_export/common_util.rb b/spec/support/import_export/common_util.rb
index 2542a59bb00..ac6840dbcfc 100644
--- a/spec/support/import_export/common_util.rb
+++ b/spec/support/import_export/common_util.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module ImportExport
module CommonUtil
def setup_symlink(tmpdir, symlink_name)
diff --git a/spec/support/import_export/configuration_helper.rb b/spec/support/import_export/configuration_helper.rb
index b4164cff922..122df7f27f0 100644
--- a/spec/support/import_export/configuration_helper.rb
+++ b/spec/support/import_export/configuration_helper.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module ConfigurationHelper
# Returns a list of models from hashes/arrays contained in +project_tree+
def names_from_tree(project_tree)
diff --git a/spec/support/import_export/export_file_helper.rb b/spec/support/import_export/export_file_helper.rb
index 388b88f0331..f862a9bc1a4 100644
--- a/spec/support/import_export/export_file_helper.rb
+++ b/spec/support/import_export/export_file_helper.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require './spec/support/import_export/configuration_helper'
module ExportFileHelper
diff --git a/spec/support/inspect_squelch.rb b/spec/support/inspect_squelch.rb
index 8ee6732370b..90475204889 100644
--- a/spec/support/inspect_squelch.rb
+++ b/spec/support/inspect_squelch.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
# This class can generate a lot of output if it fails,
# so squelch the instance variable output.
class ActiveSupport::Cache::NullStore
diff --git a/spec/support/issuables_requiring_filter_shared_examples.rb b/spec/support/issuables_requiring_filter_shared_examples.rb
index 71bcc82ee58..ee25df00dfb 100644
--- a/spec/support/issuables_requiring_filter_shared_examples.rb
+++ b/spec/support/issuables_requiring_filter_shared_examples.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
shared_examples 'issuables requiring filter' do |action|
it "doesn't load any issuables if no filter is set" do
expect_any_instance_of(described_class).not_to receive(:issuables_collection)
diff --git a/spec/support/json_response.rb b/spec/support/json_response.rb
index 210b0e6d867..55bdce0cfe9 100644
--- a/spec/support/json_response.rb
+++ b/spec/support/json_response.rb
@@ -1,5 +1,7 @@
+# frozen_string_literal: true
+
RSpec.configure do |config|
- config.include_context 'JSON response'
+ config.include_context 'JSON response', type: :controller
config.include_context 'JSON response', type: :request
config.include_context 'JSON response', :api
end
diff --git a/spec/support/matchers/abort_matcher.rb b/spec/support/matchers/abort_matcher.rb
new file mode 100644
index 00000000000..64fed2ca069
--- /dev/null
+++ b/spec/support/matchers/abort_matcher.rb
@@ -0,0 +1,48 @@
+# frozen_string_literal: true
+
+RSpec::Matchers.define :abort_execution do
+ match do |code_block|
+ @captured_stderr = StringIO.new
+ original_stderr = $stderr
+ $stderr = @captured_stderr
+
+ code_block.call
+
+ false
+ rescue SystemExit => e
+ captured = @captured_stderr.string.chomp
+ @actual_exit_code = e.status
+ break false unless e.status == 1
+
+ if @message
+ if @message.is_a? String
+ @message == captured
+ elsif @message.is_a? Regexp
+ @message.match?(captured)
+ else
+ raise ArgumentError, 'with_message must be either a String or a Regular Expression'
+ end
+ end
+
+ ensure
+ $stderr = original_stderr
+ end
+
+ chain :with_message do |message|
+ @message = message
+ end
+
+ failure_message do |block|
+ unless @actual_exit_code
+ break "expected #{block} to abort with '#{@message}' but didnt call abort."
+ end
+
+ if @actual_exit_code != 1
+ break "expected #{block} to abort with: '#{@message}' but exited with success instead."
+ end
+
+ "expected #{block} to abort with: '#{@message}' \n but received: '#{@captured_stderr.string.chomp}' instead."
+ end
+
+ supports_block_expectations
+end
diff --git a/spec/support/matchers/access_matchers.rb b/spec/support/matchers/access_matchers.rb
index e6899e2d23c..c9ff777f604 100644
--- a/spec/support/matchers/access_matchers.rb
+++ b/spec/support/matchers/access_matchers.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
# AccessMatchers
#
# The custom matchers contained in this module are used to test a user's access
diff --git a/spec/support/matchers/access_matchers_for_controller.rb b/spec/support/matchers/access_matchers_for_controller.rb
index 429401a5da8..401bf6c196e 100644
--- a/spec/support/matchers/access_matchers_for_controller.rb
+++ b/spec/support/matchers/access_matchers_for_controller.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
# AccessMatchersForController
#
# For testing authorize_xxx in controller.
diff --git a/spec/support/matchers/background_migrations_matchers.rb b/spec/support/matchers/background_migrations_matchers.rb
index f4127efc6ae..c38aa7ad6a6 100644
--- a/spec/support/matchers/background_migrations_matchers.rb
+++ b/spec/support/matchers/background_migrations_matchers.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
RSpec::Matchers.define :be_scheduled_delayed_migration do |delay, *expected|
match do |migration|
BackgroundMigrationWorker.jobs.any? do |job|
diff --git a/spec/support/matchers/be_a_binary_string.rb b/spec/support/matchers/be_a_binary_string.rb
index f041ae76167..6195c6c7554 100644
--- a/spec/support/matchers/be_a_binary_string.rb
+++ b/spec/support/matchers/be_a_binary_string.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
RSpec::Matchers.define :be_a_binary_string do |_|
match do |actual|
actual.is_a?(String) && actual.encoding == Encoding.find('ASCII-8BIT')
diff --git a/spec/support/matchers/be_like_time.rb b/spec/support/matchers/be_like_time.rb
index 1f27390eab7..b449f7a7ffb 100644
--- a/spec/support/matchers/be_like_time.rb
+++ b/spec/support/matchers/be_like_time.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
RSpec::Matchers.define :be_like_time do |expected|
match do |actual|
expect(actual).to be_within(1.second).of(expected)
diff --git a/spec/support/matchers/be_url.rb b/spec/support/matchers/be_url.rb
index f8096af1b22..69171f53891 100644
--- a/spec/support/matchers/be_url.rb
+++ b/spec/support/matchers/be_url.rb
@@ -1,5 +1,11 @@
+# frozen_string_literal: true
+
RSpec::Matchers.define :be_url do |_|
match do |actual|
URI.parse(actual) rescue false
end
end
+
+# looks better when used like:
+# expect(thing).to receive(:method).with(a_valid_url)
+RSpec::Matchers.alias_matcher :a_valid_url, :be_url
diff --git a/spec/support/matchers/be_utf8.rb b/spec/support/matchers/be_utf8.rb
index ea806352422..4fa55539a49 100644
--- a/spec/support/matchers/be_utf8.rb
+++ b/spec/support/matchers/be_utf8.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
RSpec::Matchers.define :be_utf8 do |_|
match do |actual|
actual.is_a?(String) && actual.encoding == Encoding.find('UTF-8')
diff --git a/spec/support/matchers/be_valid_commit.rb b/spec/support/matchers/be_valid_commit.rb
index 3696e4d5f03..b59339de622 100644
--- a/spec/support/matchers/be_valid_commit.rb
+++ b/spec/support/matchers/be_valid_commit.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
RSpec::Matchers.define :be_valid_commit do
match do |actual|
actual &&
diff --git a/spec/support/matchers/disallow_request_matchers.rb b/spec/support/matchers/disallow_request_matchers.rb
index db4d90e4fd0..a161e3660cd 100644
--- a/spec/support/matchers/disallow_request_matchers.rb
+++ b/spec/support/matchers/disallow_request_matchers.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
RSpec::Matchers.define :disallow_request do
match do |middleware|
alert = middleware.env['rack.session'].to_hash
diff --git a/spec/support/matchers/exceed_query_limit.rb b/spec/support/matchers/exceed_query_limit.rb
index cd042401f3a..40cf85eb8e5 100644
--- a/spec/support/matchers/exceed_query_limit.rb
+++ b/spec/support/matchers/exceed_query_limit.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module ExceedQueryLimitHelpers
def with_threshold(threshold)
@threshold = threshold
diff --git a/spec/support/matchers/execute_check.rb b/spec/support/matchers/execute_check.rb
index 7232fad52fb..d3c0751f0dc 100644
--- a/spec/support/matchers/execute_check.rb
+++ b/spec/support/matchers/execute_check.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
RSpec::Matchers.define :execute_check do |expected|
match do |actual|
expect(actual).to eq(SystemCheck)
diff --git a/spec/support/matchers/gitaly_matchers.rb b/spec/support/matchers/gitaly_matchers.rb
index 933ed22b5d0..c2b3ebe3422 100644
--- a/spec/support/matchers/gitaly_matchers.rb
+++ b/spec/support/matchers/gitaly_matchers.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
RSpec::Matchers.define :gitaly_request_with_path do |storage_name, relative_path|
match do |actual|
repository = actual.repository
diff --git a/spec/support/matchers/gitlab_git_matchers.rb b/spec/support/matchers/gitlab_git_matchers.rb
index c840cd4bf2d..aea1603db05 100644
--- a/spec/support/matchers/gitlab_git_matchers.rb
+++ b/spec/support/matchers/gitlab_git_matchers.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
RSpec::Matchers.define :gitlab_git_repository_with do |values|
match do |actual|
actual.is_a?(Gitlab::Git::Repository) &&
diff --git a/spec/support/matchers/graphql_matchers.rb b/spec/support/matchers/graphql_matchers.rb
index 7894484f590..4d48b4b5389 100644
--- a/spec/support/matchers/graphql_matchers.rb
+++ b/spec/support/matchers/graphql_matchers.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
RSpec::Matchers.define :require_graphql_authorizations do |*expected|
match do |field|
expect(field.metadata[:authorize]).to eq(*expected)
diff --git a/spec/support/matchers/have_emoji.rb b/spec/support/matchers/have_emoji.rb
index 23fb8e9c1c4..273bd0b7f40 100644
--- a/spec/support/matchers/have_emoji.rb
+++ b/spec/support/matchers/have_emoji.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
RSpec::Matchers.define :have_emoji do |emoji_name|
match do |actual|
expect(actual).to have_selector("gl-emoji[data-name='#{emoji_name}']")
diff --git a/spec/support/matchers/have_gitlab_http_status.rb b/spec/support/matchers/have_gitlab_http_status.rb
index e7e418cdde4..13a64a58218 100644
--- a/spec/support/matchers/have_gitlab_http_status.rb
+++ b/spec/support/matchers/have_gitlab_http_status.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
RSpec::Matchers.define :have_gitlab_http_status do |expected|
match do |actual|
expect(actual).to have_http_status(expected)
diff --git a/spec/support/matchers/have_issuable_counts.rb b/spec/support/matchers/have_issuable_counts.rb
index 92cf3de5448..049cfc022fb 100644
--- a/spec/support/matchers/have_issuable_counts.rb
+++ b/spec/support/matchers/have_issuable_counts.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
RSpec::Matchers.define :have_issuable_counts do |opts|
expected_counts = opts.map do |state, count|
"#{state.to_s.humanize} #{count}"
diff --git a/spec/support/matchers/include_module.rb b/spec/support/matchers/include_module.rb
index 0a78af1e90e..9b6970cf061 100644
--- a/spec/support/matchers/include_module.rb
+++ b/spec/support/matchers/include_module.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
RSpec::Matchers.define :include_module do |expected|
match do
described_class.included_modules.include?(expected)
diff --git a/spec/support/matchers/issuable_matchers.rb b/spec/support/matchers/issuable_matchers.rb
index 62f510b0fbd..743f0b8c932 100644
--- a/spec/support/matchers/issuable_matchers.rb
+++ b/spec/support/matchers/issuable_matchers.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
RSpec::Matchers.define :have_header_with_correct_id_and_link do |level, text, id, parent = ".md"|
match do |actual|
node = find("#{parent} h#{level} a#user-content-#{id}")
diff --git a/spec/support/matchers/markdown_matchers.rb b/spec/support/matchers/markdown_matchers.rb
index ec4ec6f4038..12e8fa83a60 100644
--- a/spec/support/matchers/markdown_matchers.rb
+++ b/spec/support/matchers/markdown_matchers.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
# MarkdownMatchers
#
# Custom matchers for our custom HTML::Pipeline filters. These are used to test
diff --git a/spec/support/matchers/match_file.rb b/spec/support/matchers/match_file.rb
index d1888b3376a..4e522b52912 100644
--- a/spec/support/matchers/match_file.rb
+++ b/spec/support/matchers/match_file.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
RSpec::Matchers.define :match_file do |expected|
match do |actual|
expect(Digest::MD5.hexdigest(actual)).to eq(Digest::MD5.hexdigest(File.read(expected)))
diff --git a/spec/support/matchers/match_ids.rb b/spec/support/matchers/match_ids.rb
index 1cb6b74acac..7bc41949937 100644
--- a/spec/support/matchers/match_ids.rb
+++ b/spec/support/matchers/match_ids.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
RSpec::Matchers.define :match_ids do |*expected|
match do |actual|
actual_ids = map_ids(actual)
diff --git a/spec/support/matchers/metric_counter_matcher.rb b/spec/support/matchers/metric_counter_matcher.rb
index 22d5cd17e3f..f0d52b9b149 100644
--- a/spec/support/matchers/metric_counter_matcher.rb
+++ b/spec/support/matchers/metric_counter_matcher.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
RSpec::Matchers.define :increment do |counter|
match do |adapter|
expect(adapter.send(counter))
diff --git a/spec/support/matchers/navigation_matcher.rb b/spec/support/matchers/navigation_matcher.rb
index 63f59b9654c..ad73c96031e 100644
--- a/spec/support/matchers/navigation_matcher.rb
+++ b/spec/support/matchers/navigation_matcher.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
RSpec::Matchers.define :have_active_navigation do |expected|
match do |page|
expect(page).to have_selector('.sidebar-top-level-items > li.active', count: 1)
diff --git a/spec/support/matchers/pagination_matcher.rb b/spec/support/matchers/pagination_matcher.rb
index 9a7697e2bfc..a3e9c3b8474 100644
--- a/spec/support/matchers/pagination_matcher.rb
+++ b/spec/support/matchers/pagination_matcher.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
RSpec::Matchers.define :include_pagination_headers do |expected|
match do |actual|
expect(actual.headers).to include('X-Total', 'X-Total-Pages', 'X-Per-Page', 'X-Page', 'X-Next-Page', 'X-Prev-Page', 'Link')
diff --git a/spec/support/matchers/query_matcher.rb b/spec/support/matchers/query_matcher.rb
index bb0feca7c43..3e47fe241bc 100644
--- a/spec/support/matchers/query_matcher.rb
+++ b/spec/support/matchers/query_matcher.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
RSpec::Matchers.define :make_queries_matching do |matcher, expected_count = nil|
supports_block_expectations
diff --git a/spec/support/matchers/satisfy_matchers.rb b/spec/support/matchers/satisfy_matchers.rb
index 585915bac93..dd1920ee2b2 100644
--- a/spec/support/matchers/satisfy_matchers.rb
+++ b/spec/support/matchers/satisfy_matchers.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
# These matchers are a syntactic hack to provide more readable expectations for
# an Enumerable object.
#
diff --git a/spec/support/matchers/security_header_matcher.rb b/spec/support/matchers/security_header_matcher.rb
index f8518d13ebb..760b1fddd06 100644
--- a/spec/support/matchers/security_header_matcher.rb
+++ b/spec/support/matchers/security_header_matcher.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
RSpec::Matchers.define :include_security_headers do |expected|
match do |actual|
expect(actual.headers).to include('X-Content-Type-Options')
diff --git a/spec/support/migrations_helpers/track_untracked_uploads_helpers.rb b/spec/support/migrations_helpers/track_untracked_uploads_helpers.rb
index 016bcfa9b1b..656be3b6d4d 100644
--- a/spec/support/migrations_helpers/track_untracked_uploads_helpers.rb
+++ b/spec/support/migrations_helpers/track_untracked_uploads_helpers.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module MigrationsHelpers
module TrackUntrackedUploadsHelpers
PUBLIC_DIR = File.join(Rails.root, 'tmp', 'tests', 'public')
diff --git a/spec/support/omni_auth.rb b/spec/support/omni_auth.rb
index 0b1af4052ff..64aa3855a6f 100644
--- a/spec/support/omni_auth.rb
+++ b/spec/support/omni_auth.rb
@@ -1 +1,3 @@
+# frozen_string_literal: true
+
OmniAuth.config.test_mode = true
diff --git a/spec/support/prometheus/additional_metrics_shared_examples.rb b/spec/support/prometheus/additional_metrics_shared_examples.rb
index de21e808932..4e006edb7da 100644
--- a/spec/support/prometheus/additional_metrics_shared_examples.rb
+++ b/spec/support/prometheus/additional_metrics_shared_examples.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
RSpec.shared_examples 'additional metrics query' do
include Prometheus::MetricBuilders
@@ -48,7 +50,7 @@ RSpec.shared_examples 'additional metrics query' do
let!(:cluster) { create(:cluster, :project, :provided_by_gcp) }
let(:project) { cluster.project }
let(:environment) { create(:environment, slug: 'environment-slug', project: project) }
- let(:kube_namespace) { project.deployment_platform.kubernetes_namespace_for(project) }
+ let(:kube_namespace) { environment.deployment_namespace }
it_behaves_like 'query context containing environment slug and filter'
diff --git a/spec/support/prometheus/metric_builders.rb b/spec/support/prometheus/metric_builders.rb
index c8d056d3fc8..512e32a44d0 100644
--- a/spec/support/prometheus/metric_builders.rb
+++ b/spec/support/prometheus/metric_builders.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Prometheus
module MetricBuilders
def simple_query(suffix = 'a', **opts)
diff --git a/spec/support/protected_tags/access_control_ce_shared_examples.rb b/spec/support/protected_tags/access_control_ce_shared_examples.rb
index 71eec9f3217..8666c19481c 100644
--- a/spec/support/protected_tags/access_control_ce_shared_examples.rb
+++ b/spec/support/protected_tags/access_control_ce_shared_examples.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
RSpec.shared_examples "protected tags > access control > CE" do
ProtectedRefAccess::HUMAN_ACCESS_LEVELS.each do |(access_type_id, access_type_name)|
it "allows creating protected tags that #{access_type_name} can create" do
diff --git a/spec/support/redis/redis_helpers.rb b/spec/support/redis/redis_helpers.rb
index 0457e8487d8..7c571738a01 100644
--- a/spec/support/redis/redis_helpers.rb
+++ b/spec/support/redis/redis_helpers.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module RedisHelpers
# config/README.md
diff --git a/spec/support/redis/redis_shared_examples.rb b/spec/support/redis/redis_shared_examples.rb
index 6aa59960092..7e47cdae866 100644
--- a/spec/support/redis/redis_shared_examples.rb
+++ b/spec/support/redis/redis_shared_examples.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
RSpec.shared_examples "redis_shared_examples" do
include StubENV
diff --git a/spec/support/rspec.rb b/spec/support/rspec.rb
index b38c5dfe60b..1c9f9e5161e 100644
--- a/spec/support/rspec.rb
+++ b/spec/support/rspec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require_relative "helpers/stub_configuration"
require_relative "helpers/stub_metrics"
require_relative "helpers/stub_object_storage"
diff --git a/spec/support/seed.rb b/spec/support/seed.rb
index bea2e9c3044..36cb819763b 100644
--- a/spec/support/seed.rb
+++ b/spec/support/seed.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
RSpec.configure do |config|
config.include SeedHelper, :seed_helper
diff --git a/spec/support/services/clusters/create_service_shared.rb b/spec/support/services/clusters/create_service_shared.rb
index b0bf942aa09..27f6d0570b6 100644
--- a/spec/support/services/clusters/create_service_shared.rb
+++ b/spec/support/services/clusters/create_service_shared.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
shared_context 'valid cluster create params' do
let(:params) do
{
@@ -30,23 +32,56 @@ shared_context 'invalid cluster create params' do
end
shared_examples 'create cluster service success' do
- it 'creates a cluster object and performs a worker' do
- expect(ClusterProvisionWorker).to receive(:perform_async)
-
- expect { subject }
- .to change { Clusters::Cluster.count }.by(1)
- .and change { Clusters::Providers::Gcp.count }.by(1)
-
- expect(subject.name).to eq('test-cluster')
- expect(subject.user).to eq(user)
- expect(subject.project).to eq(project)
- expect(subject.provider.gcp_project_id).to eq('gcp-project')
- expect(subject.provider.zone).to eq('us-central1-a')
- expect(subject.provider.num_nodes).to eq(1)
- expect(subject.provider.machine_type).to eq('machine_type-a')
- expect(subject.provider.access_token).to eq(access_token)
- expect(subject.provider).to be_legacy_abac
- expect(subject.platform).to be_nil
+ context 'namespace per environment feature is enabled' do
+ before do
+ stub_feature_flags(kubernetes_namespace_per_environment: true)
+ end
+
+ it 'creates a cluster object and performs a worker' do
+ expect(ClusterProvisionWorker).to receive(:perform_async)
+
+ expect { subject }
+ .to change { Clusters::Cluster.count }.by(1)
+ .and change { Clusters::Providers::Gcp.count }.by(1)
+
+ expect(subject.name).to eq('test-cluster')
+ expect(subject.user).to eq(user)
+ expect(subject.project).to eq(project)
+ expect(subject.provider.gcp_project_id).to eq('gcp-project')
+ expect(subject.provider.zone).to eq('us-central1-a')
+ expect(subject.provider.num_nodes).to eq(1)
+ expect(subject.provider.machine_type).to eq('machine_type-a')
+ expect(subject.provider.access_token).to eq(access_token)
+ expect(subject.provider).to be_legacy_abac
+ expect(subject.platform).to be_nil
+ expect(subject.namespace_per_environment).to eq true
+ end
+ end
+
+ context 'namespace per environment feature is disabled' do
+ before do
+ stub_feature_flags(kubernetes_namespace_per_environment: false)
+ end
+
+ it 'creates a cluster object and performs a worker' do
+ expect(ClusterProvisionWorker).to receive(:perform_async)
+
+ expect { subject }
+ .to change { Clusters::Cluster.count }.by(1)
+ .and change { Clusters::Providers::Gcp.count }.by(1)
+
+ expect(subject.name).to eq('test-cluster')
+ expect(subject.user).to eq(user)
+ expect(subject.project).to eq(project)
+ expect(subject.provider.gcp_project_id).to eq('gcp-project')
+ expect(subject.provider.zone).to eq('us-central1-a')
+ expect(subject.provider.num_nodes).to eq(1)
+ expect(subject.provider.machine_type).to eq('machine_type-a')
+ expect(subject.provider.access_token).to eq(access_token)
+ expect(subject.provider).to be_legacy_abac
+ expect(subject.platform).to be_nil
+ expect(subject.namespace_per_environment).to eq false
+ end
end
end
diff --git a/spec/support/services/issuable_create_service_slash_commands_shared_examples.rb b/spec/support/services/issuable_create_service_slash_commands_shared_examples.rb
index 8b4cffaac19..4c3644e6724 100644
--- a/spec/support/services/issuable_create_service_slash_commands_shared_examples.rb
+++ b/spec/support/services/issuable_create_service_slash_commands_shared_examples.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
# Specifications for behavior common to all objects with executable attributes.
# It can take a `default_params`.
diff --git a/spec/support/services/issuable_update_service_shared_examples.rb b/spec/support/services/issuable_update_service_shared_examples.rb
index ffbce6c42bf..5e5acd0e40a 100644
--- a/spec/support/services/issuable_update_service_shared_examples.rb
+++ b/spec/support/services/issuable_update_service_shared_examples.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
shared_examples 'issuable update service' do
def update_issuable(opts)
described_class.new(project, user, opts).execute(open_issuable)
diff --git a/spec/support/services/migrate_to_ghost_user_service_shared_examples.rb b/spec/support/services/migrate_to_ghost_user_service_shared_examples.rb
index 1284415da1f..65236f13e27 100644
--- a/spec/support/services/migrate_to_ghost_user_service_shared_examples.rb
+++ b/spec/support/services/migrate_to_ghost_user_service_shared_examples.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require "spec_helper"
shared_examples "migrating a deleted user's associated records to the ghost user" do |record_class, fields|
diff --git a/spec/support/setup_builds_storage.rb b/spec/support/setup_builds_storage.rb
index 1d2a4856724..bbe442f07b0 100644
--- a/spec/support/setup_builds_storage.rb
+++ b/spec/support/setup_builds_storage.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
RSpec.configure do |config|
def builds_path
Rails.root.join('tmp/tests/builds')
diff --git a/spec/support/shared_contexts/email_shared_context.rb b/spec/support/shared_contexts/email_shared_context.rb
index 9d806fc524d..b4d061a8215 100644
--- a/spec/support/shared_contexts/email_shared_context.rb
+++ b/spec/support/shared_contexts/email_shared_context.rb
@@ -1,4 +1,4 @@
-require 'gitlab/email/receiver'
+# frozen_string_literal: true
shared_context :email_shared_context do
let(:mail_key) { "59d8df8370b7e95c5a49fbf86aeb2c93" }
diff --git a/spec/support/shared_contexts/finders/group_projects_finder_shared_contexts.rb b/spec/support/shared_contexts/finders/group_projects_finder_shared_contexts.rb
index a0d994c4d8d..38f6011646e 100644
--- a/spec/support/shared_contexts/finders/group_projects_finder_shared_contexts.rb
+++ b/spec/support/shared_contexts/finders/group_projects_finder_shared_contexts.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
RSpec.shared_context 'GroupProjectsFinder context' do
diff --git a/spec/support/shared_contexts/finders/issues_finder_shared_contexts.rb b/spec/support/shared_contexts/finders/issues_finder_shared_contexts.rb
index b8a9554f55f..26ab6fbd400 100644
--- a/spec/support/shared_contexts/finders/issues_finder_shared_contexts.rb
+++ b/spec/support/shared_contexts/finders/issues_finder_shared_contexts.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
RSpec.shared_context 'IssuesFinder context' do
diff --git a/spec/support/shared_contexts/finders/merge_requests_finder_shared_contexts.rb b/spec/support/shared_contexts/finders/merge_requests_finder_shared_contexts.rb
index ab6687f1d07..ef1e65d2577 100644
--- a/spec/support/shared_contexts/finders/merge_requests_finder_shared_contexts.rb
+++ b/spec/support/shared_contexts/finders/merge_requests_finder_shared_contexts.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
RSpec.shared_context 'MergeRequestsFinder multiple projects with merge requests context' do
diff --git a/spec/support/shared_contexts/finders/users_finder_shared_contexts.rb b/spec/support/shared_contexts/finders/users_finder_shared_contexts.rb
index 9e1f89ee0ed..d6404b2ee4b 100644
--- a/spec/support/shared_contexts/finders/users_finder_shared_contexts.rb
+++ b/spec/support/shared_contexts/finders/users_finder_shared_contexts.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
RSpec.shared_context 'UsersFinder#execute filter by project context' do
diff --git a/spec/support/shared_contexts/json_response_shared_context.rb b/spec/support/shared_contexts/json_response_shared_context.rb
index df5fc288089..bd37c97ed35 100644
--- a/spec/support/shared_contexts/json_response_shared_context.rb
+++ b/spec/support/shared_contexts/json_response_shared_context.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
shared_context 'JSON response' do
let(:json_response) { JSON.parse(response.body) }
end
diff --git a/spec/support/shared_contexts/merge_requests_allowing_collaboration.rb b/spec/support/shared_contexts/merge_requests_allowing_collaboration.rb
index 05424d08b9d..276ebf973c8 100644
--- a/spec/support/shared_contexts/merge_requests_allowing_collaboration.rb
+++ b/spec/support/shared_contexts/merge_requests_allowing_collaboration.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
shared_context 'merge request allowing collaboration' do
include ProjectForksHelper
diff --git a/spec/support/shared_contexts/policies/group_policy_shared_context.rb b/spec/support/shared_contexts/policies/group_policy_shared_context.rb
index b4808ac0068..b89723b1e1a 100644
--- a/spec/support/shared_contexts/policies/group_policy_shared_context.rb
+++ b/spec/support/shared_contexts/policies/group_policy_shared_context.rb
@@ -7,7 +7,7 @@ RSpec.shared_context 'GroupPolicy context' do
let(:maintainer) { create(:user) }
let(:owner) { create(:user) }
let(:admin) { create(:admin) }
- let(:group) { create(:group, :private) }
+ let(:group) { create(:group, :private, :owner_subgroup_creation_only) }
let(:guest_permissions) do
%i[
@@ -16,7 +16,7 @@ RSpec.shared_context 'GroupPolicy context' do
read_group_merge_requests
]
end
- let(:reporter_permissions) { [:admin_label] }
+ let(:reporter_permissions) { %i[admin_label read_container_image] }
let(:developer_permissions) { [:admin_milestone] }
let(:maintainer_permissions) do
%i[
@@ -31,7 +31,8 @@ RSpec.shared_context 'GroupPolicy context' do
:admin_group_member,
:change_visibility_level,
:set_note_created_at,
- (Gitlab::Database.postgresql? ? :create_subgroup : nil)
+ :create_subgroup,
+ :read_statistics
].compact
end
diff --git a/spec/support/shared_contexts/services_shared_context.rb b/spec/support/shared_contexts/services_shared_context.rb
index 0c3a24d206f..4d176ab5fca 100644
--- a/spec/support/shared_contexts/services_shared_context.rb
+++ b/spec/support/shared_contexts/services_shared_context.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
Service.available_services_names.each do |service|
shared_context service do
let(:dashed_service) { service.dasherize }
diff --git a/spec/support/shared_contexts/url_shared_context.rb b/spec/support/shared_contexts/url_shared_context.rb
index 1b1f67daac3..560cd500ecd 100644
--- a/spec/support/shared_contexts/url_shared_context.rb
+++ b/spec/support/shared_contexts/url_shared_context.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
shared_context 'invalid urls' do
let(:urls_with_CRLF) do
["http://127.0.0.1:333/pa\rth",
diff --git a/spec/support/shared_examples/application_setting_examples.rb b/spec/support/shared_examples/application_setting_examples.rb
index e7ec24c5b7e..a43d2a75082 100644
--- a/spec/support/shared_examples/application_setting_examples.rb
+++ b/spec/support/shared_examples/application_setting_examples.rb
@@ -1,62 +1,150 @@
# frozen_string_literal: true
+RSpec.shared_examples 'string of domains' do |attribute|
+ it 'sets single domain' do
+ setting.method("#{attribute}_raw=").call('example.com')
+ expect(setting.method(attribute).call).to eq(['example.com'])
+ end
+
+ it 'sets multiple domains with spaces' do
+ setting.method("#{attribute}_raw=").call('example.com *.example.com')
+ expect(setting.method(attribute).call).to eq(['example.com', '*.example.com'])
+ end
+
+ it 'sets multiple domains with newlines and a space' do
+ setting.method("#{attribute}_raw=").call("example.com\n *.example.com")
+ expect(setting.method(attribute).call).to eq(['example.com', '*.example.com'])
+ end
+
+ it 'sets multiple domains with commas' do
+ setting.method("#{attribute}_raw=").call("example.com, *.example.com")
+ expect(setting.method(attribute).call).to eq(['example.com', '*.example.com'])
+ end
+
+ it 'sets multiple domains with semicolon' do
+ setting.method("#{attribute}_raw=").call("example.com; *.example.com")
+ expect(setting.method(attribute).call).to contain_exactly('example.com', '*.example.com')
+ end
+
+ it 'sets multiple domains with mixture of everything' do
+ setting.method("#{attribute}_raw=").call("example.com; *.example.com\n test.com\sblock.com yes.com")
+ expect(setting.method(attribute).call).to contain_exactly('example.com', '*.example.com', 'test.com', 'block.com', 'yes.com')
+ end
+
+ it 'removes duplicates' do
+ setting.method("#{attribute}_raw=").call("example.com; example.com; 127.0.0.1; 127.0.0.1")
+ expect(setting.method(attribute).call).to contain_exactly('example.com', '127.0.0.1')
+ end
+
+ it 'does not fail with garbage values' do
+ setting.method("#{attribute}_raw=").call("example;34543:garbage:fdh5654;")
+ expect(setting.method(attribute).call).to contain_exactly('example', '34543:garbage:fdh5654')
+ end
+
+ it 'does not raise error with nil' do
+ setting.method("#{attribute}_raw=").call(nil)
+ expect(setting.method(attribute).call).to eq([])
+ end
+end
+
RSpec.shared_examples 'application settings examples' do
context 'restricted signup domains' do
- it 'sets single domain' do
- setting.domain_whitelist_raw = 'example.com'
- expect(setting.domain_whitelist).to eq(['example.com'])
- end
+ it_behaves_like 'string of domains', :domain_whitelist
+ end
- it 'sets multiple domains with spaces' do
- setting.domain_whitelist_raw = 'example.com *.example.com'
- expect(setting.domain_whitelist).to eq(['example.com', '*.example.com'])
- end
+ context 'blacklisted signup domains' do
+ it_behaves_like 'string of domains', :domain_blacklist
- it 'sets multiple domains with newlines and a space' do
- setting.domain_whitelist_raw = "example.com\n *.example.com"
- expect(setting.domain_whitelist).to eq(['example.com', '*.example.com'])
+ it 'sets multiple domain with file' do
+ setting.domain_blacklist_file = File.open(Rails.root.join('spec/fixtures/', 'domain_blacklist.txt'))
+ expect(setting.domain_blacklist).to contain_exactly('example.com', 'test.com', 'foo.bar')
end
+ end
+
+ context 'outbound_local_requests_whitelist' do
+ it_behaves_like 'string of domains', :outbound_local_requests_whitelist
- it 'sets multiple domains with commas' do
- setting.domain_whitelist_raw = "example.com, *.example.com"
- expect(setting.domain_whitelist).to eq(['example.com', '*.example.com'])
+ it 'clears outbound_local_requests_whitelist_arrays memoization' do
+ setting.outbound_local_requests_whitelist_raw = 'example.com'
+
+ expect(setting.outbound_local_requests_whitelist_arrays).to contain_exactly(
+ [], ['example.com']
+ )
+
+ setting.outbound_local_requests_whitelist_raw = 'gitlab.com'
+ expect(setting.outbound_local_requests_whitelist_arrays).to contain_exactly(
+ [], ['gitlab.com']
+ )
end
end
- context 'blacklisted signup domains' do
- it 'sets single domain' do
- setting.domain_blacklist_raw = 'example.com'
- expect(setting.domain_blacklist).to contain_exactly('example.com')
+ context 'outbound_local_requests_whitelist_arrays' do
+ it 'separates the IPs and domains' do
+ setting.outbound_local_requests_whitelist = [
+ '192.168.1.1', '127.0.0.0/28', 'www.example.com', 'example.com',
+ '::ffff:a00:2', '1:0:0:0:0:0:0:0/124', 'subdomain.example.com'
+ ]
+
+ ip_whitelist = [
+ IPAddr.new('192.168.1.1'), IPAddr.new('127.0.0.0/8'),
+ IPAddr.new('::ffff:a00:2'), IPAddr.new('1:0:0:0:0:0:0:0/124')
+ ]
+ domain_whitelist = ['www.example.com', 'example.com', 'subdomain.example.com']
+
+ expect(setting.outbound_local_requests_whitelist_arrays).to contain_exactly(
+ ip_whitelist, domain_whitelist
+ )
end
+ end
- it 'sets multiple domains with spaces' do
- setting.domain_blacklist_raw = 'example.com *.example.com'
- expect(setting.domain_blacklist).to contain_exactly('example.com', '*.example.com')
- end
+ context 'add_to_outbound_local_requests_whitelist' do
+ it 'adds entry to outbound_local_requests_whitelist' do
+ setting.outbound_local_requests_whitelist = ['example.com']
- it 'sets multiple domains with newlines and a space' do
- setting.domain_blacklist_raw = "example.com\n *.example.com"
- expect(setting.domain_blacklist).to contain_exactly('example.com', '*.example.com')
- end
+ setting.add_to_outbound_local_requests_whitelist(
+ ['example.com', '127.0.0.1', 'gitlab.com']
+ )
- it 'sets multiple domains with commas' do
- setting.domain_blacklist_raw = "example.com, *.example.com"
- expect(setting.domain_blacklist).to contain_exactly('example.com', '*.example.com')
+ expect(setting.outbound_local_requests_whitelist).to contain_exactly(
+ 'example.com',
+ '127.0.0.1',
+ 'gitlab.com'
+ )
end
- it 'sets multiple domains with semicolon' do
- setting.domain_blacklist_raw = "example.com; *.example.com"
- expect(setting.domain_blacklist).to contain_exactly('example.com', '*.example.com')
+ it 'clears outbound_local_requests_whitelist_arrays memoization' do
+ setting.outbound_local_requests_whitelist = ['example.com']
+
+ expect(setting.outbound_local_requests_whitelist_arrays).to contain_exactly(
+ [],
+ ['example.com']
+ )
+
+ setting.add_to_outbound_local_requests_whitelist(
+ ['example.com', 'gitlab.com']
+ )
+
+ expect(setting.outbound_local_requests_whitelist_arrays).to contain_exactly(
+ [],
+ ['example.com', 'gitlab.com']
+ )
end
- it 'sets multiple domains with mixture of everything' do
- setting.domain_blacklist_raw = "example.com; *.example.com\n test.com\sblock.com yes.com"
- expect(setting.domain_blacklist).to contain_exactly('example.com', '*.example.com', 'test.com', 'block.com', 'yes.com')
+ it 'does not raise error with nil' do
+ setting.outbound_local_requests_whitelist = nil
+
+ setting.add_to_outbound_local_requests_whitelist(['gitlab.com'])
+
+ expect(setting.outbound_local_requests_whitelist).to contain_exactly('gitlab.com')
+ expect(setting.outbound_local_requests_whitelist_arrays).to contain_exactly(
+ [], ['gitlab.com']
+ )
end
- it 'sets multiple domain with file' do
- setting.domain_blacklist_file = File.open(Rails.root.join('spec/fixtures/', 'domain_blacklist.txt'))
- expect(setting.domain_blacklist).to contain_exactly('example.com', 'test.com', 'foo.bar')
+ it 'does not raise error with nil' do
+ setting.outbound_local_requests_whitelist = nil
+
+ expect(setting.outbound_local_requests_whitelist_arrays).to contain_exactly([], [])
end
end
diff --git a/spec/support/shared_examples/award_emoji_todo_shared_examples.rb b/spec/support/shared_examples/award_emoji_todo_shared_examples.rb
new file mode 100644
index 00000000000..88ad37d232f
--- /dev/null
+++ b/spec/support/shared_examples/award_emoji_todo_shared_examples.rb
@@ -0,0 +1,59 @@
+# frozen_string_literal: true
+
+# Shared examples to that test code that creates AwardEmoji also mark Todos
+# as done.
+#
+# The examples expect these to be defined in the calling spec:
+# - `subject` the callable code that executes the creation of an AwardEmoji
+# - `user`
+# - `project`
+RSpec.shared_examples 'creating award emojis marks Todos as done' do
+ using RSpec::Parameterized::TableSyntax
+
+ before do
+ project.add_developer(user)
+ end
+
+ where(:type, :expectation) do
+ :issue | true
+ :merge_request | true
+ :project_snippet | false
+ end
+
+ with_them do
+ let(:project) { awardable.project }
+ let(:awardable) { create(type) }
+ let!(:todo) { create(:todo, target: awardable, project: project, user: user) }
+
+ it do
+ subject
+
+ expect(todo.reload.done?).to eq(expectation)
+ end
+ end
+
+ # Notes have more complicated rules than other Todoables
+ describe 'for notes' do
+ let!(:todo) { create(:todo, target: awardable.noteable, project: project, user: user) }
+
+ context 'regular Notes' do
+ let(:awardable) { create(:note, project: project) }
+
+ it 'marks the Todo as done' do
+ subject
+
+ expect(todo.reload.done?).to eq(true)
+ end
+ end
+
+ context 'PersonalSnippet Notes' do
+ let(:awardable) { create(:note, noteable: create(:personal_snippet, author: user)) }
+
+ it 'does not mark the Todo as done' do
+ subject
+
+ expect(todo.reload.done?).to eq(false)
+ end
+ end
+ end
+end
diff --git a/spec/support/shared_examples/boards/multiple_issue_boards_shared_examples.rb b/spec/support/shared_examples/boards/multiple_issue_boards_shared_examples.rb
new file mode 100644
index 00000000000..76d82649c5f
--- /dev/null
+++ b/spec/support/shared_examples/boards/multiple_issue_boards_shared_examples.rb
@@ -0,0 +1,144 @@
+# frozen_string_literal: true
+
+shared_examples_for 'multiple issue boards' do
+ dropdown_selector = '.js-boards-selector .dropdown-menu'
+
+ context 'authorized user' do
+ before do
+ parent.add_maintainer(user)
+
+ login_as(user)
+
+ visit boards_path
+ wait_for_requests
+ end
+
+ it 'shows current board name' do
+ page.within('.boards-switcher') do
+ expect(page).to have_content(board.name)
+ end
+ end
+
+ it 'shows a list of boards' do
+ click_button board.name
+
+ page.within(dropdown_selector) do
+ expect(page).to have_content(board.name)
+ expect(page).to have_content(board2.name)
+ end
+ end
+
+ it 'switches current board' do
+ click_button board.name
+
+ page.within(dropdown_selector) do
+ click_link board2.name
+ end
+
+ wait_for_requests
+
+ page.within('.boards-switcher') do
+ expect(page).to have_content(board2.name)
+ end
+ end
+
+ it 'creates new board without detailed configuration' do
+ click_button board.name
+
+ page.within(dropdown_selector) do
+ click_button 'Create new board'
+ end
+
+ fill_in 'board-new-name', with: 'This is a new board'
+ click_button 'Create board'
+ wait_for_requests
+
+ expect(page).to have_button('This is a new board')
+ end
+
+ it 'deletes board' do
+ click_button board.name
+
+ wait_for_requests
+
+ page.within(dropdown_selector) do
+ click_button 'Delete board'
+ end
+
+ expect(page).to have_content('Are you sure you want to delete this board?')
+ click_button 'Delete'
+
+ click_button board2.name
+ page.within(dropdown_selector) do
+ expect(page).not_to have_content(board.name)
+ expect(page).to have_content(board2.name)
+ end
+ end
+
+ it 'adds a list to the none default board' do
+ click_button board.name
+
+ page.within(dropdown_selector) do
+ click_link board2.name
+ end
+
+ wait_for_requests
+
+ page.within('.boards-switcher') do
+ expect(page).to have_content(board2.name)
+ end
+
+ click_button 'Add list'
+
+ wait_for_requests
+
+ page.within '.dropdown-menu-issues-board-new' do
+ click_link planning.title
+ end
+
+ wait_for_requests
+
+ expect(page).to have_selector('.board', count: 3)
+
+ click_button board2.name
+
+ page.within(dropdown_selector) do
+ click_link board.name
+ end
+
+ wait_for_requests
+
+ expect(page).to have_selector('.board', count: 2)
+ end
+
+ it 'maintains sidebar state over board switch' do
+ assert_boards_nav_active
+
+ find('.boards-switcher').click
+ wait_for_requests
+ click_link board2.name
+
+ assert_boards_nav_active
+ end
+ end
+
+ context 'unauthorized user' do
+ before do
+ visit boards_path
+ wait_for_requests
+ end
+
+ it 'does not show action links' do
+ click_button board.name
+
+ page.within(dropdown_selector) do
+ expect(page).not_to have_content('Create new board')
+ expect(page).not_to have_content('Delete board')
+ end
+ end
+ end
+
+ def assert_boards_nav_active
+ expect(find('.nav-sidebar .active .active')).to have_selector('a', text: 'Boards')
+ end
+end
diff --git a/spec/support/shared_examples/chat_slash_commands_shared_examples.rb b/spec/support/shared_examples/chat_slash_commands_shared_examples.rb
index dc97a39f051..dcc92dda950 100644
--- a/spec/support/shared_examples/chat_slash_commands_shared_examples.rb
+++ b/spec/support/shared_examples/chat_slash_commands_shared_examples.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
RSpec.shared_examples 'chat slash commands service' do
describe "Associations" do
it { is_expected.to respond_to :token }
@@ -91,6 +93,19 @@ RSpec.shared_examples 'chat slash commands service' do
subject.trigger(params)
end
+
+ context 'when user is blocked' do
+ before do
+ chat_name.user.block
+ end
+
+ it 'blocks command execution' do
+ expect_any_instance_of(Gitlab::SlashCommands::Command).not_to receive(:execute)
+
+ result = subject.trigger(params)
+ expect(result).to include(text: /^Whoops! This action is not allowed/)
+ end
+ end
end
end
end
diff --git a/spec/support/shared_examples/ci_trace_shared_examples.rb b/spec/support/shared_examples/ci_trace_shared_examples.rb
index ab0550e2613..e2b4b50d41d 100644
--- a/spec/support/shared_examples/ci_trace_shared_examples.rb
+++ b/spec/support/shared_examples/ci_trace_shared_examples.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
shared_examples_for 'common trace features' do
describe '#html' do
before do
@@ -5,11 +7,11 @@ shared_examples_for 'common trace features' do
end
it "returns formatted html" do
- expect(trace.html).to eq("<span class=\"\">12<br/><span class=\"\">34</span></span>")
+ expect(trace.html).to eq("<span>12<br/>34</span>")
end
it "returns last line of formatted html" do
- expect(trace.html(last_lines: 1)).to eq("<span class=\"\">34</span>")
+ expect(trace.html(last_lines: 1)).to eq("<span>34</span>")
end
end
@@ -720,6 +722,58 @@ shared_examples_for 'trace with enabled live trace feature' do
end
end
+ describe '#archived_trace_exist?' do
+ subject { trace.archived_trace_exist? }
+
+ context 'when trace does not exist' do
+ it { is_expected.to be_falsy }
+ end
+
+ context 'when archived trace exists' do
+ before do
+ create(:ci_job_artifact, :trace, job: build)
+ end
+
+ it { is_expected.to be_truthy }
+ end
+
+ context 'when live trace exists' do
+ before do
+ Gitlab::Ci::Trace::ChunkedIO.new(build) do |stream|
+ stream.write('abc')
+ end
+ end
+
+ it { is_expected.to be_falsy }
+ end
+ end
+
+ describe '#live_trace_exist?' do
+ subject { trace.live_trace_exist? }
+
+ context 'when trace does not exist' do
+ it { is_expected.to be_falsy }
+ end
+
+ context 'when archived trace exists' do
+ before do
+ create(:ci_job_artifact, :trace, job: build)
+ end
+
+ it { is_expected.to be_falsy }
+ end
+
+ context 'when live trace exists' do
+ before do
+ Gitlab::Ci::Trace::ChunkedIO.new(build) do |stream|
+ stream.write('abc')
+ end
+ end
+
+ it { is_expected.to be_truthy }
+ end
+ end
+
describe '#archive!' do
subject { trace.archive! }
diff --git a/spec/support/shared_examples/common_system_notes_examples.rb b/spec/support/shared_examples/common_system_notes_examples.rb
index da5a4f3e319..75f93a32d78 100644
--- a/spec/support/shared_examples/common_system_notes_examples.rb
+++ b/spec/support/shared_examples/common_system_notes_examples.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
shared_examples 'system note creation' do |update_params, note_text|
subject { described_class.new(project, user).execute(issuable, old_labels: []) }
diff --git a/spec/support/shared_examples/container_repositories_shared_examples.rb b/spec/support/shared_examples/container_repositories_shared_examples.rb
new file mode 100644
index 00000000000..946b130fca2
--- /dev/null
+++ b/spec/support/shared_examples/container_repositories_shared_examples.rb
@@ -0,0 +1,58 @@
+# frozen_string_literal: true
+
+shared_examples 'rejected container repository access' do |user_type, status|
+ context "for #{user_type}" do
+ let(:api_user) { users[user_type] }
+
+ it "returns #{status}" do
+ subject
+
+ expect(response).to have_gitlab_http_status(status)
+ end
+ end
+end
+
+shared_examples 'returns repositories for allowed users' do |user_type, scope|
+ context "for #{user_type}" do
+ it 'returns a list of repositories' do
+ subject
+
+ expect(json_response.length).to eq(2)
+ expect(json_response.map { |repository| repository['id'] }).to contain_exactly(
+ root_repository.id, test_repository.id)
+ expect(response.body).not_to include('tags')
+ end
+
+ it 'returns a matching schema' do
+ subject
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(response).to match_response_schema('registry/repositories')
+ end
+
+ context 'with tags param' do
+ let(:url) { "/#{scope}s/#{object.id}/registry/repositories?tags=true" }
+
+ before do
+ stub_container_registry_tags(repository: root_repository.path, tags: %w(rootA latest), with_manifest: true)
+ stub_container_registry_tags(repository: test_repository.path, tags: %w(rootA latest), with_manifest: true)
+ end
+
+ it 'returns a list of repositories and their tags' do
+ subject
+
+ expect(json_response.length).to eq(2)
+ expect(json_response.map { |repository| repository['id'] }).to contain_exactly(
+ root_repository.id, test_repository.id)
+ expect(response.body).to include('tags')
+ end
+
+ it 'returns a matching schema' do
+ subject
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(response).to match_response_schema('registry/repositories')
+ end
+ end
+ end
+end
diff --git a/spec/support/shared_examples/controllers/external_authorization_service_shared_examples.rb b/spec/support/shared_examples/controllers/external_authorization_service_shared_examples.rb
index 8dd78fd0a25..d8a1ae83f61 100644
--- a/spec/support/shared_examples/controllers/external_authorization_service_shared_examples.rb
+++ b/spec/support/shared_examples/controllers/external_authorization_service_shared_examples.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
shared_examples 'disabled when using an external authorization service' do
@@ -6,7 +8,7 @@ shared_examples 'disabled when using an external authorization service' do
it 'works when the feature is not enabled' do
subject
- expect(response).to be_success
+ expect(response).to be_successful
end
it 'renders a 404 with a message when the feature is enabled' do
diff --git a/spec/support/shared_examples/controllers/issuable_notes_filter_shared_examples.rb b/spec/support/shared_examples/controllers/issuable_notes_filter_shared_examples.rb
index 0acc9e2a836..26ed86bfe26 100644
--- a/spec/support/shared_examples/controllers/issuable_notes_filter_shared_examples.rb
+++ b/spec/support/shared_examples/controllers/issuable_notes_filter_shared_examples.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
shared_examples 'issuable notes filter' do
let(:params) do
if issuable_parent.is_a?(Project)
@@ -39,14 +41,22 @@ shared_examples 'issuable notes filter' do
get :discussions, params: params.merge(notes_filter: notes_filter)
- expect(user.reload.notes_filter_for(issuable)).to eq(0)
+ expect(user.reload.notes_filter_for(issuable)).to eq(UserPreference::NOTES_FILTERS[:all_notes])
+ end
+
+ it 'does not set notes filter when persist_filter param is false' do
+ notes_filter = UserPreference::NOTES_FILTERS[:only_comments]
+
+ get :discussions, params: params.merge(notes_filter: notes_filter, persist_filter: false)
+
+ expect(user.reload.notes_filter_for(issuable)).to eq(UserPreference::NOTES_FILTERS[:all_notes])
end
it 'returns only user comments' do
user.set_notes_filter(UserPreference::NOTES_FILTERS[:only_comments], issuable)
get :discussions, params: params
- discussions = JSON.parse(response.body)
+ discussions = json_response
expect(discussions.count).to eq(1)
expect(discussions.first["notes"].first["system"]).to be(false)
@@ -56,7 +66,7 @@ shared_examples 'issuable notes filter' do
user.set_notes_filter(UserPreference::NOTES_FILTERS[:only_activity], issuable)
get :discussions, params: params
- discussions = JSON.parse(response.body)
+ discussions = json_response
expect(discussions.count).to eq(1)
expect(discussions.first["notes"].first["system"]).to be(true)
diff --git a/spec/support/shared_examples/controllers/set_sort_order_from_user_preference_shared_examples.rb b/spec/support/shared_examples/controllers/set_sort_order_from_user_preference_shared_examples.rb
index eb051166a69..d89eded6e69 100644
--- a/spec/support/shared_examples/controllers/set_sort_order_from_user_preference_shared_examples.rb
+++ b/spec/support/shared_examples/controllers/set_sort_order_from_user_preference_shared_examples.rb
@@ -1,13 +1,15 @@
+# frozen_string_literal: true
+
shared_examples 'set sort order from user preference' do
describe '#set_sort_order_from_user_preference' do
- # There is no issuable_sorting_field defined in any CE controllers yet,
+ # There is no sorting_field defined in any CE controllers yet,
# however any other field present in user_preferences table can be used for testing.
context 'when database is in read-only mode' do
it 'does not update user preference' do
allow(Gitlab::Database).to receive(:read_only?).and_return(true)
- expect_any_instance_of(UserPreference).not_to receive(:update).with({ controller.send(:issuable_sorting_field) => sorting_param })
+ expect_any_instance_of(UserPreference).not_to receive(:update).with({ controller.send(:sorting_field) => sorting_param })
get :index, params: { namespace_id: project.namespace, project_id: project, sort: sorting_param }
end
@@ -17,7 +19,7 @@ shared_examples 'set sort order from user preference' do
it 'updates user preference' do
allow(Gitlab::Database).to receive(:read_only?).and_return(false)
- expect_any_instance_of(UserPreference).to receive(:update).with({ controller.send(:issuable_sorting_field) => sorting_param })
+ expect_any_instance_of(UserPreference).to receive(:update).with({ controller.send(:sorting_field) => sorting_param })
get :index, params: { namespace_id: project.namespace, project_id: project, sort: sorting_param }
end
diff --git a/spec/support/shared_examples/controllers/todos_shared_examples.rb b/spec/support/shared_examples/controllers/todos_shared_examples.rb
index bafd9bac8d0..f3f9abb7da2 100644
--- a/spec/support/shared_examples/controllers/todos_shared_examples.rb
+++ b/spec/support/shared_examples/controllers/todos_shared_examples.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
shared_examples 'todos actions' do
context 'when authorized' do
before do
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 59708173716..39d13cccb13 100644
--- a/spec/support/shared_examples/controllers/uploads_actions_shared_examples.rb
+++ b/spec/support/shared_examples/controllers/uploads_actions_shared_examples.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
shared_examples 'handle uploads' do
let(:user) { create(:user) }
let(:jpg) { fixture_file_upload('spec/fixtures/rails_sample.jpg', 'image/jpg') }
@@ -74,6 +76,16 @@ shared_examples 'handle uploads' do
UploadService.new(model, jpg, uploader_class).execute
end
+ context 'when accessing a specific upload via different model' do
+ it 'responds with status 404' do
+ params.merge!(other_params)
+
+ show_upload
+
+ expect(response).to have_gitlab_http_status(404)
+ end
+ end
+
context "when the model is public" do
before do
model.update_attribute(:visibility_level, Gitlab::VisibilityLevel::PUBLIC)
diff --git a/spec/support/shared_examples/controllers/variables_shared_examples.rb b/spec/support/shared_examples/controllers/variables_shared_examples.rb
index e80722857ec..78666e677ef 100644
--- a/spec/support/shared_examples/controllers/variables_shared_examples.rb
+++ b/spec/support/shared_examples/controllers/variables_shared_examples.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
shared_examples 'GET #show lists all variables' do
it 'renders the variables as json' do
subject
diff --git a/spec/support/shared_examples/cycle_analytics_stage_examples.rb b/spec/support/shared_examples/cycle_analytics_stage_examples.rb
new file mode 100644
index 00000000000..151f5325e84
--- /dev/null
+++ b/spec/support/shared_examples/cycle_analytics_stage_examples.rb
@@ -0,0 +1,74 @@
+# frozen_string_literal: true
+
+shared_examples_for 'cycle analytics stage' do
+ let(:valid_params) do
+ {
+ name: 'My Stage',
+ parent: parent,
+ start_event_identifier: :merge_request_created,
+ end_event_identifier: :merge_request_merged
+ }
+ end
+
+ describe 'validation' do
+ it 'is valid' do
+ expect(described_class.new(valid_params)).to be_valid
+ end
+
+ it 'validates presence of parent' do
+ stage = described_class.new(valid_params.except(:parent))
+
+ expect(stage).not_to be_valid
+ expect(stage.errors.details[parent_name]).to eq([{ error: :blank }])
+ end
+
+ it 'validates presence of start_event_identifier' do
+ stage = described_class.new(valid_params.except(:start_event_identifier))
+
+ expect(stage).not_to be_valid
+ expect(stage.errors.details[:start_event_identifier]).to eq([{ error: :blank }])
+ end
+
+ it 'validates presence of end_event_identifier' do
+ stage = described_class.new(valid_params.except(:end_event_identifier))
+
+ expect(stage).not_to be_valid
+ expect(stage.errors.details[:end_event_identifier]).to eq([{ error: :blank }])
+ end
+
+ it 'is invalid when end_event is not allowed for the given start_event' do
+ invalid_params = valid_params.merge(
+ start_event_identifier: :merge_request_merged,
+ end_event_identifier: :merge_request_created
+ )
+ stage = described_class.new(invalid_params)
+
+ expect(stage).not_to be_valid
+ expect(stage.errors.details[:end_event]).to eq([{ error: :not_allowed_for_the_given_start_event }])
+ end
+ end
+
+ describe '#subject_model' do
+ it 'infers the model from the start event' do
+ stage = described_class.new(valid_params)
+
+ expect(stage.subject_model).to eq(MergeRequest)
+ end
+ end
+
+ describe '#start_event' do
+ it 'builds start_event object based on start_event_identifier' do
+ stage = described_class.new(start_event_identifier: 'merge_request_created')
+
+ expect(stage.start_event).to be_a_kind_of(Gitlab::Analytics::CycleAnalytics::StageEvents::MergeRequestCreated)
+ end
+ end
+
+ describe '#end_event' do
+ it 'builds end_event object based on end_event_identifier' do
+ stage = described_class.new(end_event_identifier: 'merge_request_merged')
+
+ expect(stage.end_event).to be_a_kind_of(Gitlab::Analytics::CycleAnalytics::StageEvents::MergeRequestMerged)
+ end
+ end
+end
diff --git a/spec/support/shared_examples/dirty_submit_form_shared_examples.rb b/spec/support/shared_examples/dirty_submit_form_shared_examples.rb
index 4e45e2921e7..60c8899d349 100644
--- a/spec/support/shared_examples/dirty_submit_form_shared_examples.rb
+++ b/spec/support/shared_examples/dirty_submit_form_shared_examples.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
shared_examples 'dirty submit form' do |selector_args|
selectors = selector_args.is_a?(Array) ? selector_args : [selector_args]
diff --git a/spec/support/shared_examples/discussions_provider_shared_examples.rb b/spec/support/shared_examples/discussions_provider_shared_examples.rb
new file mode 100644
index 00000000000..77cf1ac3f51
--- /dev/null
+++ b/spec/support/shared_examples/discussions_provider_shared_examples.rb
@@ -0,0 +1,15 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+shared_examples 'discussions provider' do
+ it 'returns the expected discussions' do
+ get :discussions, params: { namespace_id: project.namespace, project_id: project, id: requested_iid }
+
+ expect(response).to have_gitlab_http_status(200)
+ expect(response).to match_response_schema('entities/discussions')
+
+ expect(json_response.size).to eq(expected_discussion_count)
+ expect(json_response.pluck('id')).to eq(expected_discussion_ids)
+ end
+end
diff --git a/spec/support/shared_examples/email_format_shared_examples.rb b/spec/support/shared_examples/email_format_shared_examples.rb
index b924a208e71..22d6c2b38e3 100644
--- a/spec/support/shared_examples/email_format_shared_examples.rb
+++ b/spec/support/shared_examples/email_format_shared_examples.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
# Specifications for behavior common to all objects with an email attribute.
# Takes a list of email-format attributes and requires:
# - subject { "the object with a attribute= setter" }
diff --git a/spec/support/shared_examples/fast_destroy_all.rb b/spec/support/shared_examples/fast_destroy_all.rb
index a8079b6d864..a64259c03f2 100644
--- a/spec/support/shared_examples/fast_destroy_all.rb
+++ b/spec/support/shared_examples/fast_destroy_all.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
shared_examples_for 'fast destroyable' do
describe 'Forbid #destroy and #destroy_all' do
it 'does not delete database rows and associted external data' do
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 2b36955a3c4..f24e47f4638 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
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
shared_examples 'comment on merge request file' do
it 'adds a comment' do
click_diff_line(find("[id='#{sample_commit.line_code}']"))
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 ec1b1754cf0..c0db4cdde72 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
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
RSpec.shared_examples 'a creatable merge request' do
include WaitForRequests
diff --git a/spec/support/shared_examples/features/editable_merge_request_shared_examples.rb b/spec/support/shared_examples/features/editable_merge_request_shared_examples.rb
index a6121fcc50a..964c80007b0 100644
--- a/spec/support/shared_examples/features/editable_merge_request_shared_examples.rb
+++ b/spec/support/shared_examples/features/editable_merge_request_shared_examples.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
RSpec.shared_examples 'an editable merge request' do
it 'updates merge request', :js do
find('.js-assignee-search').click
diff --git a/spec/support/shared_examples/features/issuable_sidebar_shared_examples.rb b/spec/support/shared_examples/features/issuable_sidebar_shared_examples.rb
index 96c821b26f7..09a48533ee3 100644
--- a/spec/support/shared_examples/features/issuable_sidebar_shared_examples.rb
+++ b/spec/support/shared_examples/features/issuable_sidebar_shared_examples.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
shared_examples 'issue sidebar stays collapsed on mobile' do
before do
resize_screen_xs
diff --git a/spec/support/shared_examples/features/issuables_user_dropdown_behaviors_shared_examples.rb b/spec/support/shared_examples/features/issuables_user_dropdown_behaviors_shared_examples.rb
index c92c7f603d6..63ed37cde03 100644
--- a/spec/support/shared_examples/features/issuables_user_dropdown_behaviors_shared_examples.rb
+++ b/spec/support/shared_examples/features/issuables_user_dropdown_behaviors_shared_examples.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
shared_examples 'issuable user dropdown behaviors' do
include FilteredSearchHelpers
diff --git a/spec/support/shared_examples/features/master_manages_access_requests_shared_example.rb b/spec/support/shared_examples/features/master_manages_access_requests_shared_example.rb
index d87e5fcaa88..8e1d24c4be2 100644
--- a/spec/support/shared_examples/features/master_manages_access_requests_shared_example.rb
+++ b/spec/support/shared_examples/features/master_manages_access_requests_shared_example.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
RSpec.shared_examples 'Maintainer manages access requests' do
let(:user) { create(:user) }
let(:maintainer) { create(:user) }
diff --git a/spec/support/shared_examples/features/project_features_apply_to_issuables_shared_examples.rb b/spec/support/shared_examples/features/project_features_apply_to_issuables_shared_examples.rb
index 64c3b80136d..51559c0b110 100644
--- a/spec/support/shared_examples/features/project_features_apply_to_issuables_shared_examples.rb
+++ b/spec/support/shared_examples/features/project_features_apply_to_issuables_shared_examples.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
shared_examples 'project features apply to issuables' do |klass|
let(:described_class) { klass }
diff --git a/spec/support/shared_examples/features/protected_branches_access_control_ce.rb b/spec/support/shared_examples/features/protected_branches_access_control_ce.rb
index a8f2c2e7a5a..db83d6f0793 100644
--- a/spec/support/shared_examples/features/protected_branches_access_control_ce.rb
+++ b/spec/support/shared_examples/features/protected_branches_access_control_ce.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
shared_examples "protected branches > access control > CE" do
ProtectedRefAccess::HUMAN_ACCESS_LEVELS.each do |(access_type_id, access_type_name)|
it "allows creating protected branches that #{access_type_name} can push to" do
@@ -6,7 +8,7 @@ shared_examples "protected branches > access control > CE" do
set_protected_branch_name('master')
find(".js-allowed-to-merge").click
- within('.qa-allowed-to-merge-dropdown') do
+ within('.rspec-allowed-to-merge-dropdown') do
expect(first("li")).to have_content("Roles")
find(:link, 'No one').click
end
@@ -32,13 +34,13 @@ shared_examples "protected branches > access control > CE" do
set_protected_branch_name('master')
find(".js-allowed-to-merge").click
- within('.qa-allowed-to-merge-dropdown') do
+ within('.rspec-allowed-to-merge-dropdown') do
expect(first("li")).to have_content("Roles")
find(:link, 'No one').click
end
find(".js-allowed-to-push").click
- within('.qa-allowed-to-push-dropdown') do
+ within('.rspec-allowed-to-push-dropdown') do
expect(first("li")).to have_content("Roles")
find(:link, 'No one').click
end
@@ -78,7 +80,7 @@ shared_examples "protected branches > access control > CE" do
end
find(".js-allowed-to-push").click
- within('.qa-allowed-to-push-dropdown') do
+ within('.rspec-allowed-to-push-dropdown') do
expect(first("li")).to have_content("Roles")
find(:link, 'No one').click
end
@@ -95,13 +97,13 @@ shared_examples "protected branches > access control > CE" do
set_protected_branch_name('master')
find(".js-allowed-to-merge").click
- within('.qa-allowed-to-merge-dropdown') do
+ within('.rspec-allowed-to-merge-dropdown') do
expect(first("li")).to have_content("Roles")
find(:link, 'No one').click
end
find(".js-allowed-to-push").click
- within('.qa-allowed-to-push-dropdown') do
+ within('.rspec-allowed-to-push-dropdown') do
expect(first("li")).to have_content("Roles")
find(:link, 'No one').click
end
diff --git a/spec/support/shared_examples/features/search_shared_examples.rb b/spec/support/shared_examples/features/search_shared_examples.rb
index 25ebbf011d5..e27d6700cbf 100644
--- a/spec/support/shared_examples/features/search_shared_examples.rb
+++ b/spec/support/shared_examples/features/search_shared_examples.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
shared_examples 'top right search form' do
it 'does not show top right search form' do
expect(page).not_to have_selector('.search')
diff --git a/spec/support/shared_examples/file_finder.rb b/spec/support/shared_examples/file_finder.rb
index 0dc351b5149..984a06ccd1a 100644
--- a/spec/support/shared_examples/file_finder.rb
+++ b/spec/support/shared_examples/file_finder.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
shared_examples 'file finder' do
let(:query) { 'files' }
let(:search_results) { subject.find(query) }
diff --git a/spec/support/shared_examples/finders/finder_with_external_authorization_enabled.rb b/spec/support/shared_examples/finders/finder_with_external_authorization_enabled.rb
index d7e17cc0b70..b8b0079e36d 100644
--- a/spec/support/shared_examples/finders/finder_with_external_authorization_enabled.rb
+++ b/spec/support/shared_examples/finders/finder_with_external_authorization_enabled.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
shared_examples 'a finder with external authorization service' do
diff --git a/spec/support/shared_examples/gitlab_verify.rb b/spec/support/shared_examples/gitlab_verify.rb
index 560913ca92f..721ea3b4c88 100644
--- a/spec/support/shared_examples/gitlab_verify.rb
+++ b/spec/support/shared_examples/gitlab_verify.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
RSpec.shared_examples 'Gitlab::Verify::BatchVerifier subclass' do
describe 'batching' do
let(:first_batch) { objects[0].id..objects[0].id }
diff --git a/spec/support/shared_examples/graphql/issuable_state_shared_examples.rb b/spec/support/shared_examples/graphql/issuable_state_shared_examples.rb
index 713f0a879c1..145c476c7f7 100644
--- a/spec/support/shared_examples/graphql/issuable_state_shared_examples.rb
+++ b/spec/support/shared_examples/graphql/issuable_state_shared_examples.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
RSpec.shared_examples 'issuable state' do
it 'exposes all the existing issuable states' do
expect(described_class.values.keys).to include(*%w[opened closed locked])
diff --git a/spec/support/shared_examples/group_members_shared_example.rb b/spec/support/shared_examples/group_members_shared_example.rb
index 547c83c7955..4f7d496741d 100644
--- a/spec/support/shared_examples/group_members_shared_example.rb
+++ b/spec/support/shared_examples/group_members_shared_example.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
RSpec.shared_examples 'members and requesters associations' do
describe '#members_and_requesters' do
it 'includes members and requesters' do
diff --git a/spec/support/shared_examples/helm_generated_script.rb b/spec/support/shared_examples/helm_generated_script.rb
index 01bee603274..17f495ebe46 100644
--- a/spec/support/shared_examples/helm_generated_script.rb
+++ b/spec/support/shared_examples/helm_generated_script.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
shared_examples 'helm commands' do
describe '#generate_script' do
let(:helm_setup) do
diff --git a/spec/support/shared_examples/issuable_shared_examples.rb b/spec/support/shared_examples/issuable_shared_examples.rb
index d97b21f71cd..3460a8ba297 100644
--- a/spec/support/shared_examples/issuable_shared_examples.rb
+++ b/spec/support/shared_examples/issuable_shared_examples.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
shared_examples 'cache counters invalidator' do
it 'invalidates counter cache for assignees' do
expect_any_instance_of(User).to receive(:invalidate_merge_request_cache_counts)
diff --git a/spec/support/shared_examples/issuables_list_metadata_shared_examples.rb b/spec/support/shared_examples/issuables_list_metadata_shared_examples.rb
index 244f4766a84..52d90b5f183 100644
--- a/spec/support/shared_examples/issuables_list_metadata_shared_examples.rb
+++ b/spec/support/shared_examples/issuables_list_metadata_shared_examples.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
shared_examples 'issuables list meta-data' do |issuable_type, action = nil|
include ProjectForksHelper
diff --git a/spec/support/shared_examples/issue_tracker_service_shared_example.rb b/spec/support/shared_examples/issue_tracker_service_shared_example.rb
index a6ab03cb808..0a483fd30ba 100644
--- a/spec/support/shared_examples/issue_tracker_service_shared_example.rb
+++ b/spec/support/shared_examples/issue_tracker_service_shared_example.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
RSpec.shared_examples 'issue tracker service URL attribute' do |url_attr|
it { is_expected.to allow_value('https://example.com').for(url_attr) }
diff --git a/spec/support/shared_examples/ldap_shared_examples.rb b/spec/support/shared_examples/ldap_shared_examples.rb
index 52c34e78965..0a70ce7ea0c 100644
--- a/spec/support/shared_examples/ldap_shared_examples.rb
+++ b/spec/support/shared_examples/ldap_shared_examples.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
shared_examples_for 'normalizes a DN' do
using RSpec::Parameterized::TableSyntax
diff --git a/spec/support/shared_examples/legacy_path_redirect_shared_examples.rb b/spec/support/shared_examples/legacy_path_redirect_shared_examples.rb
index f326e502092..22e5698825d 100644
--- a/spec/support/shared_examples/legacy_path_redirect_shared_examples.rb
+++ b/spec/support/shared_examples/legacy_path_redirect_shared_examples.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
shared_examples 'redirecting a legacy path' do |source, target|
include RSpec::Rails::RequestExampleGroup
diff --git a/spec/support/shared_examples/lib/gitlab/background_migration/backfill_project_repositories_examples.rb b/spec/support/shared_examples/lib/gitlab/background_migration/backfill_project_repositories_examples.rb
index dcf7c1a90c2..2cbc0c2bdf2 100644
--- a/spec/support/shared_examples/lib/gitlab/background_migration/backfill_project_repositories_examples.rb
+++ b/spec/support/shared_examples/lib/gitlab/background_migration/backfill_project_repositories_examples.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
shared_examples 'backfill migration for project repositories' do |storage|
describe '#perform' do
let(:storage_versions) { storage == :legacy ? [nil, 0] : [1, 2] }
diff --git a/spec/support/shared_examples/lib/gitlab/usage_data_counters/a_redis_counter.rb b/spec/support/shared_examples/lib/gitlab/usage_data_counters/a_redis_counter.rb
new file mode 100644
index 00000000000..91bf804978d
--- /dev/null
+++ b/spec/support/shared_examples/lib/gitlab/usage_data_counters/a_redis_counter.rb
@@ -0,0 +1,57 @@
+# frozen_string_literal: true
+
+shared_examples 'a redis usage counter' do |thing, event|
+ describe ".count(#{event})", :clean_gitlab_redis_shared_state do
+ it "increments the #{thing} #{event} counter by 1" do
+ expect do
+ described_class.count(event)
+ end.to change { described_class.read(event) }.by 1
+ end
+ end
+
+ describe ".read(#{event})", :clean_gitlab_redis_shared_state do
+ event_count = 5
+
+ it "returns the total number of #{event} events" do
+ event_count.times do
+ described_class.count(event)
+ end
+
+ expect(described_class.read(event)).to eq(event_count)
+ end
+ end
+end
+
+shared_examples 'a redis usage counter with totals' do |prefix, events|
+ describe 'totals', :clean_gitlab_redis_shared_state do
+ before do
+ events.each do |k, n|
+ n.times do
+ described_class.count(k)
+ end
+ end
+ end
+
+ let(:expected_totals) do
+ events.transform_keys { |k| "#{prefix}_#{k}".to_sym }
+ end
+
+ it 'can report all totals' do
+ expect(described_class.totals).to include(expected_totals)
+ end
+ end
+
+ # Override these let-bindings to adjust the unknown events tests
+ let(:unknown_event) { described_class::UnknownEvent }
+ let(:bad_event) { :wibble }
+
+ describe 'unknown events' do
+ it 'cannot increment' do
+ expect { described_class.count(bad_event) }.to raise_error unknown_event
+ end
+
+ it 'cannot read' do
+ expect { described_class.read(bad_event) }.to raise_error unknown_event
+ end
+ end
+end
diff --git a/spec/support/shared_examples/malicious_regexp_shared_examples.rb b/spec/support/shared_examples/malicious_regexp_shared_examples.rb
index a86050e2cf2..96c02260d53 100644
--- a/spec/support/shared_examples/malicious_regexp_shared_examples.rb
+++ b/spec/support/shared_examples/malicious_regexp_shared_examples.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'timeout'
shared_examples 'malicious regexp' do
diff --git a/spec/support/shared_examples/mentionable_shared_examples.rb b/spec/support/shared_examples/mentionable_shared_examples.rb
index 1226841f24c..93a8c4709a6 100644
--- a/spec/support/shared_examples/mentionable_shared_examples.rb
+++ b/spec/support/shared_examples/mentionable_shared_examples.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
# Specifications for behavior common to all Mentionable implementations.
# Requires a shared context containing:
# - subject { "the mentionable implementation" }
@@ -76,6 +78,30 @@ shared_examples 'a mentionable' do
expect(refs).to include(ext_commit)
end
+ context 'when there are cached markdown fields' do
+ before do
+ if subject.is_a?(CacheMarkdownField)
+ subject.refresh_markdown_cache
+ end
+ end
+
+ it 'sends in cached markdown fields when appropriate' do
+ if subject.is_a?(CacheMarkdownField)
+ expect_next_instance_of(Gitlab::ReferenceExtractor) do |ext|
+ attrs = subject.class.mentionable_attrs.collect(&:first) & subject.cached_markdown_fields.markdown_fields
+ attrs.each do |field|
+ expect(ext).to receive(:analyze).with(subject.send(field), hash_including(rendered: anything))
+ end
+ end
+
+ expect(subject).not_to receive(:refresh_markdown_cache)
+ expect(subject).to receive(:cached_markdown_fields).at_least(:once).and_call_original
+
+ subject.all_references(author)
+ end
+ end
+ end
+
it 'creates cross-reference notes' do
mentioned_objects = [mentioned_issue, mentioned_mr, mentioned_commit,
ext_issue, ext_mr, ext_commit]
@@ -98,6 +124,33 @@ shared_examples 'an editable mentionable' do
[create(:issue, project: project), create(:issue, project: ext_proj)]
end
+ context 'when there are cached markdown fields' do
+ before do
+ if subject.is_a?(CacheMarkdownField)
+ subject.refresh_markdown_cache
+ end
+ end
+
+ it 'refreshes markdown cache if necessary' do
+ subject.save!
+
+ set_mentionable_text.call('This is a text')
+
+ if subject.is_a?(CacheMarkdownField)
+ expect_next_instance_of(Gitlab::ReferenceExtractor) do |ext|
+ subject.cached_markdown_fields.markdown_fields.each do |field|
+ expect(ext).to receive(:analyze).with(subject.send(field), hash_including(rendered: anything))
+ end
+ end
+
+ expect(subject).to receive(:refresh_markdown_cache)
+ expect(subject).to receive(:cached_markdown_fields).at_least(:once).and_call_original
+
+ subject.all_references(author)
+ end
+ end
+ end
+
it 'creates new cross-reference notes when the mentionable text is edited' do
subject.save
subject.create_cross_references!
diff --git a/spec/support/shared_examples/milestone_tabs_examples.rb b/spec/support/shared_examples/milestone_tabs_examples.rb
index 8b757586941..bda4b978737 100644
--- a/spec/support/shared_examples/milestone_tabs_examples.rb
+++ b/spec/support/shared_examples/milestone_tabs_examples.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
shared_examples 'milestone tabs' do
def go(path, extra_params = {})
params =
diff --git a/spec/support/shared_examples/models/atomic_internal_id_shared_examples.rb b/spec/support/shared_examples/models/atomic_internal_id_shared_examples.rb
index a248f60d23e..b837ca87256 100644
--- a/spec/support/shared_examples/models/atomic_internal_id_shared_examples.rb
+++ b/spec/support/shared_examples/models/atomic_internal_id_shared_examples.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
shared_examples_for 'AtomicInternalId' do |validate_presence: true|
diff --git a/spec/support/shared_examples/models/chat_service_shared_examples.rb b/spec/support/shared_examples/models/chat_service_shared_examples.rb
index 0a302e7d030..b6a3d50d14a 100644
--- a/spec/support/shared_examples/models/chat_service_shared_examples.rb
+++ b/spec/support/shared_examples/models/chat_service_shared_examples.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require "spec_helper"
shared_examples_for "chat service" do |service_name|
@@ -220,7 +222,8 @@ shared_examples_for "chat service" do |service_name|
context "with not default branch" do
let(:pipeline) do
- create(:ci_pipeline, project: project, status: "failed", ref: "not-the-default-branch")
+ create(:ci_pipeline, :failed, project: project,
+ sha: project.commit.sha, ref: "not-the-default-branch")
end
context "when notify_only_default_branch enabled" do
diff --git a/spec/support/shared_examples/models/cluster_application_core_shared_examples.rb b/spec/support/shared_examples/models/cluster_application_core_shared_examples.rb
index d6490a808ce..8e58cc7ba22 100644
--- a/spec/support/shared_examples/models/cluster_application_core_shared_examples.rb
+++ b/spec/support/shared_examples/models/cluster_application_core_shared_examples.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
shared_examples 'cluster application core specs' do |application_name|
it { is_expected.to belong_to(:cluster) }
it { is_expected.to validate_presence_of(:cluster) }
diff --git a/spec/support/shared_examples/models/cluster_application_helm_cert_examples.rb b/spec/support/shared_examples/models/cluster_application_helm_cert_examples.rb
index bd3661471f8..7ddb3b11c85 100644
--- a/spec/support/shared_examples/models/cluster_application_helm_cert_examples.rb
+++ b/spec/support/shared_examples/models/cluster_application_helm_cert_examples.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
shared_examples 'cluster application helm specs' do |application_name|
let(:application) { create(application_name) }
diff --git a/spec/support/shared_examples/models/cluster_application_status_shared_examples.rb b/spec/support/shared_examples/models/cluster_application_status_shared_examples.rb
index 4525c03837f..5341aacb445 100644
--- a/spec/support/shared_examples/models/cluster_application_status_shared_examples.rb
+++ b/spec/support/shared_examples/models/cluster_application_status_shared_examples.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
shared_examples 'cluster application status specs' do |application_name|
describe '#status' do
let(:cluster) { create(:cluster, :provided_by_gcp) }
diff --git a/spec/support/shared_examples/models/diff_positionable_note_shared_examples.rb b/spec/support/shared_examples/models/diff_positionable_note_shared_examples.rb
new file mode 100644
index 00000000000..8b298c5c974
--- /dev/null
+++ b/spec/support/shared_examples/models/diff_positionable_note_shared_examples.rb
@@ -0,0 +1,52 @@
+# frozen_string_literal: true
+
+shared_examples_for 'a valid diff positionable note' do |factory_on_commit|
+ context 'for commit' do
+ let(:project) { create(:project, :repository) }
+ let(:commit) { project.commit(sample_commit.id) }
+ let(:commit_id) { commit.id }
+ let(:diff_refs) { commit.diff_refs }
+
+ let(:position) do
+ Gitlab::Diff::Position.new(
+ old_path: "files/ruby/popen.rb",
+ new_path: "files/ruby/popen.rb",
+ old_line: nil,
+ new_line: 14,
+ diff_refs: diff_refs
+ )
+ end
+
+ subject { build(factory_on_commit, commit_id: commit_id, position: position) }
+
+ context 'position diff refs matches commit diff refs' do
+ it 'is valid' do
+ expect(subject).to be_valid
+ expect(subject.errors).not_to have_key(:commit_id)
+ end
+ end
+
+ context 'position diff refs does not match commit diff refs' do
+ let(:diff_refs) do
+ Gitlab::Diff::DiffRefs.new(
+ base_sha: "not_existing_sha",
+ head_sha: "existing_sha"
+ )
+ end
+
+ it 'is invalid' do
+ expect(subject).to be_invalid
+ expect(subject.errors).to have_key(:commit_id)
+ end
+ end
+
+ context 'commit does not exist' do
+ let(:commit_id) { 'non-existing' }
+
+ it 'is invalid' do
+ expect(subject).to be_invalid
+ expect(subject.errors).to have_key(:commit_id)
+ end
+ end
+ end
+end
diff --git a/spec/support/shared_examples/models/issuable_hook_data_shared_examples.rb b/spec/support/shared_examples/models/issuable_hook_data_shared_examples.rb
index a4762b68858..7ea2bb265cc 100644
--- a/spec/support/shared_examples/models/issuable_hook_data_shared_examples.rb
+++ b/spec/support/shared_examples/models/issuable_hook_data_shared_examples.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
# This shared example requires a `builder` and `user` variable
shared_examples 'issuable hook data' do |kind|
let(:data) { builder.build(user: user) }
diff --git a/spec/support/shared_examples/models/members_notifications_shared_example.rb b/spec/support/shared_examples/models/members_notifications_shared_example.rb
index ef5cea3f2a5..050d710f1de 100644
--- a/spec/support/shared_examples/models/members_notifications_shared_example.rb
+++ b/spec/support/shared_examples/models/members_notifications_shared_example.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
RSpec.shared_examples 'members notifications' do |entity_type|
let(:notification_service) { double('NotificationService').as_null_object }
diff --git a/spec/support/shared_examples/models/project_hook_data_shared_examples.rb b/spec/support/shared_examples/models/project_hook_data_shared_examples.rb
index f0264878811..03d10c10e3c 100644
--- a/spec/support/shared_examples/models/project_hook_data_shared_examples.rb
+++ b/spec/support/shared_examples/models/project_hook_data_shared_examples.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
shared_examples 'project hook data with deprecateds' do |project_key: :project|
it 'contains project data' do
expect(data[project_key][:name]).to eq(project.name)
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 aad63982e7a..e03435cafe8 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
@@ -32,19 +32,6 @@ shared_examples_for 'UpdateProjectStatistics' do
subject.save!
end
-
- context 'when feature flag is disabled for the namespace' do
- it 'does not schedules a namespace statistics worker' do
- namespace = subject.project.root_ancestor
-
- stub_feature_flags(update_statistics_namespace: false, namespace: namespace)
-
- expect(Namespaces::ScheduleAggregationWorker)
- .not_to receive(:perform_async)
-
- subject.save!
- end
- end
end
context 'when updating' do
@@ -87,20 +74,6 @@ shared_examples_for 'UpdateProjectStatistics' do
subject.save!
end.not_to exceed_query_limit(control_count)
end
-
- context 'when the feature flag is disabled for the namespace' do
- it 'does not schedule a namespace statistics worker' do
- namespace = subject.project.root_ancestor
-
- stub_feature_flags(update_statistics_namespace: false, namespace: namespace)
-
- expect(Namespaces::ScheduleAggregationWorker)
- .not_to receive(:perform_async)
-
- subject.write_attribute(statistic_attribute, read_attribute + delta)
- subject.save!
- end
- end
end
context 'when destroying' do
@@ -144,18 +117,5 @@ shared_examples_for 'UpdateProjectStatistics' do
project.destroy!
end
end
-
- context 'when feature flag is disabled for the namespace' do
- it 'does not schedule a namespace statistics worker' do
- namespace = subject.project.root_ancestor
-
- stub_feature_flags(update_statistics_namespace: false, namespace: namespace)
-
- expect(Namespaces::ScheduleAggregationWorker)
- .not_to receive(:perform_async)
-
- subject.destroy!
- end
- end
end
end
diff --git a/spec/support/shared_examples/models/with_uploads_shared_examples.rb b/spec/support/shared_examples/models/with_uploads_shared_examples.rb
index 43033a2d256..eb1ade03017 100644
--- a/spec/support/shared_examples/models/with_uploads_shared_examples.rb
+++ b/spec/support/shared_examples/models/with_uploads_shared_examples.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
shared_examples_for 'model with uploads' do |supports_fileuploads|
diff --git a/spec/support/shared_examples/notify_shared_examples.rb b/spec/support/shared_examples/notify_shared_examples.rb
index e64c7e37a0c..ca031df000e 100644
--- a/spec/support/shared_examples/notify_shared_examples.rb
+++ b/spec/support/shared_examples/notify_shared_examples.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
shared_context 'gitlab email notification' do
set(:group) { create(:group) }
set(:subgroup) { create(:group, parent: group) }
@@ -42,42 +44,17 @@ shared_examples 'an email sent from GitLab' do
end
shared_examples 'an email sent to a user' do
- let(:group_notification_email) { 'user+group@example.com' }
-
it 'is sent to user\'s global notification email address' do
expect(subject).to deliver_to(recipient.notification_email)
end
- context 'that is part of a project\'s group' do
- it 'is sent to user\'s group notification email address when set' do
- create(:notification_setting, user: recipient, source: project.group, notification_email: group_notification_email)
- expect(subject).to deliver_to(group_notification_email)
- end
-
- it 'is sent to user\'s global notification email address when no group email set' do
- create(:notification_setting, user: recipient, source: project.group, notification_email: '')
- expect(subject).to deliver_to(recipient.notification_email)
- end
- end
+ context 'with group notification email' do
+ it 'is sent to user\'s group notification email' do
+ group_notification_email = 'user+group@example.com'
- context 'when project is in a sub-group', :nested_groups do
- before do
- project.update!(group: subgroup)
- end
-
- it 'is sent to user\'s subgroup notification email address when set' do
- # Set top-level group notification email address to make sure it doesn't get selected
create(:notification_setting, user: recipient, source: group, notification_email: group_notification_email)
- subgroup_notification_email = 'user+subgroup@example.com'
- create(:notification_setting, user: recipient, source: subgroup, notification_email: subgroup_notification_email)
-
- expect(subject).to deliver_to(subgroup_notification_email)
- end
-
- it 'is sent to user\'s group notification email address when set and subgroup email address not set' do
- create(:notification_setting, user: recipient, source: subgroup, notification_email: '')
- expect(subject).to deliver_to(recipient.notification_email)
+ expect(subject).to deliver_to(group_notification_email)
end
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 d99f94c76c3..0b427c23256 100644
--- a/spec/support/shared_examples/policies/clusterable_shared_examples.rb
+++ b/spec/support/shared_examples/policies/clusterable_shared_examples.rb
@@ -13,7 +13,11 @@ shared_examples 'clusterable policies' do
clusterable.add_developer(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 maintainer' do
@@ -22,15 +26,11 @@ shared_examples 'clusterable policies' do
end
context 'with no clusters' do
+ it { expect_allowed(:read_cluster) }
it { expect_allowed(:add_cluster) }
- end
-
- context 'with an existing cluster' do
- before do
- cluster
- end
-
- it { expect_disallowed(:add_cluster) }
+ it { expect_allowed(:create_cluster) }
+ it { expect_allowed(:update_cluster) }
+ it { expect_allowed(:admin_cluster) }
end
end
end
diff --git a/spec/support/shared_examples/position_formatters.rb b/spec/support/shared_examples/position_formatters.rb
index ffc9456dbc7..30b6b8d24f0 100644
--- a/spec/support/shared_examples/position_formatters.rb
+++ b/spec/support/shared_examples/position_formatters.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
shared_examples_for "position formatter" do
let(:formatter) { described_class.new(attrs) }
diff --git a/spec/support/shared_examples/project_latest_successful_build_for_examples.rb b/spec/support/shared_examples/project_latest_successful_build_for_examples.rb
new file mode 100644
index 00000000000..a9bd23e9fc9
--- /dev/null
+++ b/spec/support/shared_examples/project_latest_successful_build_for_examples.rb
@@ -0,0 +1,63 @@
+# frozen_string_literal: true
+
+shared_examples 'latest successful build for sha or ref' do
+ context 'with many builds' do
+ let(:other_pipeline) { create_pipeline(project) }
+ let(:other_build) { create_build(other_pipeline, 'test') }
+ let(:build_name) { other_build.name }
+
+ before do
+ pipeline1 = create_pipeline(project)
+ pipeline2 = create_pipeline(project)
+ create_build(pipeline1, 'test')
+ create_build(pipeline1, 'test2')
+ create_build(pipeline2, 'test2')
+ end
+
+ it 'gives the latest builds from latest pipeline' do
+ expect(subject).to eq(other_build)
+ end
+ end
+
+ context 'with succeeded pipeline' do
+ let!(:build) { create_build }
+ let(:build_name) { build.name }
+
+ context 'standalone pipeline' do
+ it 'returns builds for ref for default_branch' do
+ expect(subject).to eq(build)
+ end
+
+ context 'with nonexistent build' do
+ let(:build_name) { 'TAIL' }
+
+ it 'returns empty relation if the build cannot be found' do
+ expect(subject).to be_nil
+ end
+ end
+ end
+
+ context 'with some pending pipeline' do
+ before do
+ create_build(create_pipeline(project, 'pending'))
+ end
+
+ it 'gives the latest build from latest pipeline' do
+ expect(subject).to eq(build)
+ end
+ end
+ end
+
+ context 'with pending pipeline' do
+ let!(:pending_build) { create_build(pipeline) }
+ let(:build_name) { pending_build.name }
+
+ before do
+ pipeline.update(status: 'pending')
+ end
+
+ it 'returns empty relation' do
+ expect(subject).to be_nil
+ end
+ end
+end
diff --git a/spec/support/shared_examples/quick_actions/commit/tag_quick_action_shared_examples.rb b/spec/support/shared_examples/quick_actions/commit/tag_quick_action_shared_examples.rb
index b337a1c18d8..f5a86e4dc2c 100644
--- a/spec/support/shared_examples/quick_actions/commit/tag_quick_action_shared_examples.rb
+++ b/spec/support/shared_examples/quick_actions/commit/tag_quick_action_shared_examples.rb
@@ -5,7 +5,7 @@ shared_examples 'tag quick action' do
it 'tags this commit' do
add_note("/tag #{tag_name} #{tag_message}")
- expect(page).to have_content 'Commands applied'
+ expect(page).to have_content %{Tagged this commit to #{tag_name} with "#{tag_message}".}
expect(page).to have_content "tagged commit #{truncated_commit_sha}"
expect(page).to have_content tag_name
diff --git a/spec/support/shared_examples/quick_actions/issuable/close_quick_action_shared_examples.rb b/spec/support/shared_examples/quick_actions/issuable/close_quick_action_shared_examples.rb
index a79a61bc708..6e7eb78261a 100644
--- a/spec/support/shared_examples/quick_actions/issuable/close_quick_action_shared_examples.rb
+++ b/spec/support/shared_examples/quick_actions/issuable/close_quick_action_shared_examples.rb
@@ -68,7 +68,7 @@ shared_examples 'close quick action' do |issuable_type|
it "does not close the #{issuable_type}" do
add_note('/close')
- expect(page).not_to have_content 'Commands applied'
+ expect(page).not_to have_content "Closed this #{issuable.to_ability_name.humanize(capitalize: false)}."
expect(issuable).to be_open
end
end
diff --git a/spec/support/shared_examples/quick_actions/issue/create_merge_request_quick_action_shared_examples.rb b/spec/support/shared_examples/quick_actions/issue/create_merge_request_quick_action_shared_examples.rb
index 34dba5dbc31..3e9ee9a633f 100644
--- a/spec/support/shared_examples/quick_actions/issue/create_merge_request_quick_action_shared_examples.rb
+++ b/spec/support/shared_examples/quick_actions/issue/create_merge_request_quick_action_shared_examples.rb
@@ -2,8 +2,14 @@
shared_examples 'create_merge_request quick action' do
context 'create a merge request starting from an issue' do
- def expect_mr_quickaction(success)
- expect(page).to have_content 'Commands applied'
+ def expect_mr_quickaction(success, branch_name = nil)
+ command_message = if branch_name
+ "Created branch '#{branch_name}' and a merge request to resolve this issue"
+ else
+ "Created a branch and a merge request to resolve this issue"
+ end
+
+ expect(page).to have_content command_message
if success
expect(page).to have_content 'created merge request'
@@ -13,19 +19,21 @@ shared_examples 'create_merge_request quick action' do
end
it "doesn't create a merge request when the branch name is invalid" do
- add_note("/create_merge_request invalid branch name")
+ branch_name = 'invalid branch name'
+ add_note("/create_merge_request #{branch_name}")
wait_for_requests
- expect_mr_quickaction(false)
+ expect_mr_quickaction(false, branch_name)
end
it "doesn't create a merge request when a branch with that name already exists" do
- add_note("/create_merge_request feature")
+ branch_name = 'feature'
+ add_note("/create_merge_request #{branch_name}")
wait_for_requests
- expect_mr_quickaction(false)
+ expect_mr_quickaction(false, branch_name)
end
it 'creates a new merge request using issue iid and title as branch name when the branch name is empty' do
@@ -46,7 +54,7 @@ shared_examples 'create_merge_request quick action' do
branch_name = '1-feature'
add_note("/create_merge_request #{branch_name}")
- expect_mr_quickaction(true)
+ expect_mr_quickaction(true, branch_name)
created_mr = project.merge_requests.last
expect(created_mr.source_branch).to eq(branch_name)
diff --git a/spec/support/shared_examples/quick_actions/issue/duplicate_quick_action_shared_examples.rb b/spec/support/shared_examples/quick_actions/issue/duplicate_quick_action_shared_examples.rb
index 633c7135fbc..3834b8b2b87 100644
--- a/spec/support/shared_examples/quick_actions/issue/duplicate_quick_action_shared_examples.rb
+++ b/spec/support/shared_examples/quick_actions/issue/duplicate_quick_action_shared_examples.rb
@@ -9,7 +9,6 @@ shared_examples 'duplicate quick action' do
add_note("/duplicate ##{original_issue.to_reference}")
expect(page).not_to have_content "/duplicate #{original_issue.to_reference}"
- expect(page).to have_content 'Commands applied'
expect(page).to have_content "marked this issue as a duplicate of #{original_issue.to_reference}"
expect(issue.reload).to be_closed
@@ -28,7 +27,6 @@ shared_examples 'duplicate quick action' do
it 'does not create a note, and does not mark the issue as a duplicate' do
add_note("/duplicate ##{original_issue.to_reference}")
- expect(page).not_to have_content 'Commands applied'
expect(page).not_to have_content "marked this issue as a duplicate of #{original_issue.to_reference}"
expect(issue.reload).to be_open
diff --git a/spec/support/shared_examples/quick_actions/issue/move_quick_action_shared_examples.rb b/spec/support/shared_examples/quick_actions/issue/move_quick_action_shared_examples.rb
index a0b0d888769..bebc8509d53 100644
--- a/spec/support/shared_examples/quick_actions/issue/move_quick_action_shared_examples.rb
+++ b/spec/support/shared_examples/quick_actions/issue/move_quick_action_shared_examples.rb
@@ -12,7 +12,7 @@ shared_examples 'move quick action' do
it 'moves the issue' do
add_note("/move #{target_project.full_path}")
- expect(page).to have_content 'Commands applied'
+ expect(page).to have_content "Moved this issue to #{target_project.full_path}."
expect(issue.reload).to be_closed
visit project_issue_path(target_project, issue)
@@ -29,7 +29,7 @@ shared_examples 'move quick action' do
wait_for_requests
- expect(page).to have_content 'Commands applied'
+ expect(page).to have_content "Moved this issue to #{project_unauthorized.full_path}."
expect(issue.reload).to be_open
end
end
@@ -40,7 +40,7 @@ shared_examples 'move quick action' do
wait_for_requests
- expect(page).to have_content 'Commands applied'
+ expect(page).to have_content "Failed to move this issue because target project doesn't exist."
expect(issue.reload).to be_open
end
end
@@ -56,7 +56,7 @@ shared_examples 'move quick action' do
shared_examples 'applies the commands to issues in both projects, target and source' do
it "applies quick actions" do
- expect(page).to have_content 'Commands applied'
+ expect(page).to have_content "Moved this issue to #{target_project.full_path}."
expect(issue.reload).to be_closed
visit project_issue_path(target_project, issue)
@@ -89,5 +89,54 @@ shared_examples 'move quick action' do
it_behaves_like 'applies the commands to issues in both projects, target and source'
end
end
+
+ context 'when editing comments' do
+ let(:target_project) { create(:project, :public) }
+
+ before do
+ target_project.add_maintainer(user)
+
+ sign_in(user)
+ visit project_issue_path(project, issue)
+ wait_for_all_requests
+ end
+
+ it 'moves the issue after quickcommand note was updated' do
+ # misspelled quick action
+ add_note("test note.\n/mvoe #{target_project.full_path}")
+
+ expect(issue.reload).not_to be_closed
+
+ edit_note("/mvoe #{target_project.full_path}", "test note.\n/move #{target_project.full_path}")
+ wait_for_all_requests
+
+ expect(page).to have_content 'test note.'
+ expect(issue.reload).to be_closed
+
+ visit project_issue_path(target_project, issue)
+ wait_for_all_requests
+
+ expect(page).to have_content 'Issues 1'
+ end
+
+ it 'deletes the note if it was updated to just contain a command' do
+ # missspelled quick action
+ add_note("test note.\n/mvoe #{target_project.full_path}")
+
+ expect(page).not_to have_content 'Commands applied'
+ expect(issue.reload).not_to be_closed
+
+ edit_note("/mvoe #{target_project.full_path}", "/move #{target_project.full_path}")
+ wait_for_all_requests
+
+ expect(page).not_to have_content "/move #{target_project.full_path}"
+ expect(issue.reload).to be_closed
+
+ visit project_issue_path(target_project, issue)
+ wait_for_all_requests
+
+ expect(page).to have_content 'Issues 1'
+ end
+ end
end
end
diff --git a/spec/support/shared_examples/quick_actions/merge_request/merge_quick_action_shared_examples.rb b/spec/support/shared_examples/quick_actions/merge_request/merge_quick_action_shared_examples.rb
index c454ddc4bba..ac7c17915de 100644
--- a/spec/support/shared_examples/quick_actions/merge_request/merge_quick_action_shared_examples.rb
+++ b/spec/support/shared_examples/quick_actions/merge_request/merge_quick_action_shared_examples.rb
@@ -10,7 +10,7 @@ shared_examples 'merge quick action' do
it 'merges the MR' do
add_note("/merge")
- expect(page).to have_content 'Commands applied'
+ expect(page).to have_content 'Scheduled to merge this merge request when the pipeline succeeds.'
expect(merge_request.reload).to be_merged
end
diff --git a/spec/support/shared_examples/reference_parser_shared_examples.rb b/spec/support/shared_examples/reference_parser_shared_examples.rb
index baf8bcc04b8..d903c0f10e0 100644
--- a/spec/support/shared_examples/reference_parser_shared_examples.rb
+++ b/spec/support/shared_examples/reference_parser_shared_examples.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
RSpec.shared_examples "referenced feature visibility" do |*related_features|
let(:feature_fields) do
related_features.map { |feature| (feature + "_access_level").to_sym }
diff --git a/spec/support/shared_examples/relative_positioning_shared_examples.rb b/spec/support/shared_examples/relative_positioning_shared_examples.rb
new file mode 100644
index 00000000000..b7382cea93c
--- /dev/null
+++ b/spec/support/shared_examples/relative_positioning_shared_examples.rb
@@ -0,0 +1,283 @@
+# frozen_string_literal: true
+
+RSpec.shared_examples 'a class that supports relative positioning' do
+ let(:item1) { create(factory, default_params) }
+ let(:item2) { create(factory, default_params) }
+ let(:new_item) { create(factory, default_params) }
+
+ def create_item(params)
+ create(factory, params.merge(default_params))
+ end
+
+ def create_items_with_positions(positions)
+ positions.map do |position|
+ create_item(relative_position: position)
+ end
+ end
+
+ describe '.move_nulls_to_end' do
+ it 'moves items with null relative_position to the end' do
+ item1.update!(relative_position: nil)
+ item2.update!(relative_position: nil)
+
+ described_class.move_nulls_to_end([item1, item2])
+
+ expect(item2.prev_relative_position).to eq item1.relative_position
+ expect(item1.prev_relative_position).to eq nil
+ expect(item2.next_relative_position).to eq nil
+ end
+
+ it 'moves the item near the start position when there are no existing positions' do
+ item1.update!(relative_position: nil)
+
+ described_class.move_nulls_to_end([item1])
+
+ expect(item1.relative_position).to eq(described_class::START_POSITION + described_class::IDEAL_DISTANCE)
+ end
+
+ it 'does not perform any moves if all items have their relative_position set' do
+ item1.update!(relative_position: 1)
+
+ expect(item1).not_to receive(:save)
+
+ described_class.move_nulls_to_end([item1])
+ end
+ end
+
+ describe '#max_relative_position' do
+ it 'returns maximum position' do
+ expect(item1.max_relative_position).to eq item2.relative_position
+ end
+ end
+
+ describe '#prev_relative_position' do
+ it 'returns previous position if there is an item above' do
+ item1.update(relative_position: 5)
+ item2.update(relative_position: 15)
+
+ expect(item2.prev_relative_position).to eq item1.relative_position
+ end
+
+ it 'returns nil if there is no item above' do
+ expect(item1.prev_relative_position).to eq nil
+ end
+ end
+
+ describe '#next_relative_position' do
+ it 'returns next position if there is an item below' do
+ item1.update(relative_position: 5)
+ item2.update(relative_position: 15)
+
+ expect(item1.next_relative_position).to eq item2.relative_position
+ end
+
+ it 'returns nil if there is no item below' do
+ expect(item2.next_relative_position).to eq nil
+ end
+ end
+
+ describe '#move_before' do
+ it 'moves item before' do
+ [item2, item1].each(&:move_to_end)
+
+ item1.move_before(item2)
+
+ expect(item1.relative_position).to be < item2.relative_position
+ end
+ end
+
+ describe '#move_after' do
+ it 'moves item after' do
+ [item1, item2].each(&:move_to_end)
+
+ item1.move_after(item2)
+
+ expect(item1.relative_position).to be > item2.relative_position
+ end
+ end
+
+ describe '#move_to_end' do
+ before do
+ [item1, item2].each do |item1|
+ item1.move_to_end && item1.save
+ end
+ end
+
+ it 'moves item to the end' do
+ new_item.move_to_end
+
+ expect(new_item.relative_position).to be > item2.relative_position
+ end
+ end
+
+ describe '#move_between' do
+ before do
+ [item1, item2].each do |item1|
+ item1.move_to_end && item1.save
+ end
+ end
+
+ it 'positions item between two other' do
+ new_item.move_between(item1, item2)
+
+ expect(new_item.relative_position).to be > item1.relative_position
+ expect(new_item.relative_position).to be < item2.relative_position
+ end
+
+ it 'positions item between on top' do
+ new_item.move_between(nil, item1)
+
+ expect(new_item.relative_position).to be < item1.relative_position
+ end
+
+ it 'positions item between to end' do
+ new_item.move_between(item2, nil)
+
+ expect(new_item.relative_position).to be > item2.relative_position
+ end
+
+ it 'positions items even when after and before positions are the same' do
+ item2.update relative_position: item1.relative_position
+
+ new_item.move_between(item1, item2)
+
+ expect(new_item.relative_position).to be > item1.relative_position
+ expect(item1.relative_position).to be < item2.relative_position
+ end
+
+ it 'positions items between other two if distance is 1' do
+ item2.update relative_position: item1.relative_position + 1
+
+ new_item.move_between(item1, item2)
+
+ expect(new_item.relative_position).to be > item1.relative_position
+ expect(item1.relative_position).to be < item2.relative_position
+ end
+
+ it 'positions item in the middle of other two if distance is big enough' do
+ item1.update relative_position: 6000
+ item2.update relative_position: 10000
+
+ new_item.move_between(item1, item2)
+
+ expect(new_item.relative_position).to eq(8000)
+ end
+
+ it 'positions item closer to the middle if we are at the very top' do
+ item2.update relative_position: 6000
+
+ new_item.move_between(nil, item2)
+
+ expect(new_item.relative_position).to eq(6000 - RelativePositioning::IDEAL_DISTANCE)
+ end
+
+ it 'positions item closer to the middle if we are at the very bottom' do
+ new_item.update relative_position: 1
+ item1.update relative_position: 6000
+ item2.destroy
+
+ new_item.move_between(item1, nil)
+
+ expect(new_item.relative_position).to eq(6000 + RelativePositioning::IDEAL_DISTANCE)
+ end
+
+ it 'positions item in the middle of other two if distance is not big enough' do
+ item1.update relative_position: 100
+ item2.update relative_position: 400
+
+ new_item.move_between(item1, item2)
+
+ expect(new_item.relative_position).to eq(250)
+ end
+
+ it 'positions item in the middle of other two is there is no place' do
+ item1.update relative_position: 100
+ item2.update relative_position: 101
+
+ new_item.move_between(item1, item2)
+
+ expect(new_item.relative_position).to be_between(item1.relative_position, item2.relative_position)
+ end
+
+ it 'uses rebalancing if there is no place' do
+ item1.update relative_position: 100
+ item2.update relative_position: 101
+ item3 = create_item(relative_position: 102)
+ new_item.update relative_position: 103
+
+ new_item.move_between(item2, item3)
+ new_item.save!
+
+ expect(new_item.relative_position).to be_between(item2.relative_position, item3.relative_position)
+ expect(item1.reload.relative_position).not_to eq(100)
+ end
+
+ it 'positions item right if we pass none-sequential parameters' do
+ item1.update relative_position: 99
+ item2.update relative_position: 101
+ item3 = create_item(relative_position: 102)
+ new_item.update relative_position: 103
+
+ new_item.move_between(item1, item3)
+ new_item.save!
+
+ expect(new_item.relative_position).to be(100)
+ end
+
+ it 'avoids N+1 queries when rebalancing other items' do
+ items = create_items_with_positions([100, 101, 102])
+
+ count = ActiveRecord::QueryRecorder.new do
+ new_item.move_between(items[-2], items[-1])
+ end
+
+ items = create_items_with_positions([150, 151, 152, 153, 154])
+
+ expect { new_item.move_between(items[-2], items[-1]) }.not_to exceed_query_limit(count)
+ end
+ end
+
+ describe '#move_sequence_before' do
+ it 'moves the whole sequence of items to the middle of the nearest gap' do
+ items = create_items_with_positions([90, 100, 101, 102])
+
+ items.last.move_sequence_before
+ items.last.save!
+
+ positions = items.map { |item| item.reload.relative_position }
+ expect(positions).to eq([90, 95, 96, 102])
+ end
+
+ it 'finds a gap if there are unused positions' do
+ items = create_items_with_positions([100, 101, 102])
+
+ items.last.move_sequence_before
+ items.last.save!
+
+ positions = items.map { |item| item.reload.relative_position }
+ expect(positions).to eq([50, 51, 102])
+ end
+ end
+
+ describe '#move_sequence_after' do
+ it 'moves the whole sequence of items to the middle of the nearest gap' do
+ items = create_items_with_positions([100, 101, 102, 110])
+
+ items.first.move_sequence_after
+ items.first.save!
+
+ positions = items.map { |item| item.reload.relative_position }
+ expect(positions).to eq([100, 105, 106, 110])
+ end
+
+ it 'finds a gap if there are unused positions' do
+ items = create_items_with_positions([100, 101, 102])
+
+ items.first.move_sequence_after
+ items.first.save!
+
+ positions = items.map { |item| item.reload.relative_position }
+ expect(positions).to eq([100, 601, 602])
+ end
+ end
+end
diff --git a/spec/support/shared_examples/requests/api/custom_attributes_shared_examples.rb b/spec/support/shared_examples/requests/api/custom_attributes_shared_examples.rb
index 8a7fcf856a1..776a0bdd29e 100644
--- a/spec/support/shared_examples/requests/api/custom_attributes_shared_examples.rb
+++ b/spec/support/shared_examples/requests/api/custom_attributes_shared_examples.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
shared_examples 'custom attributes endpoints' do |attributable_name|
let!(:custom_attribute1) { attributable.custom_attributes.create key: 'foo', value: 'foo' }
let!(:custom_attribute2) { attributable.custom_attributes.create key: 'bar', value: 'bar' }
diff --git a/spec/support/shared_examples/requests/api/diff_discussions.rb b/spec/support/shared_examples/requests/api/diff_discussions.rb
index 366c2955359..76c6c93964a 100644
--- a/spec/support/shared_examples/requests/api/diff_discussions.rb
+++ b/spec/support/shared_examples/requests/api/diff_discussions.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
shared_examples 'diff discussions API' do |parent_type, noteable_type, id_name|
describe "GET /#{parent_type}/:id/#{noteable_type}/:noteable_id/discussions" do
it "includes diff discussions" do
diff --git a/spec/support/shared_examples/requests/api/discussions.rb b/spec/support/shared_examples/requests/api/discussions.rb
index c3132c41f5b..a36bc2dc9b5 100644
--- a/spec/support/shared_examples/requests/api/discussions.rb
+++ b/spec/support/shared_examples/requests/api/discussions.rb
@@ -1,3 +1,59 @@
+# frozen_string_literal: true
+
+shared_examples 'with cross-reference system notes' do
+ let(:merge_request) { create(:merge_request) }
+ let(:project) { merge_request.project }
+ let(:new_merge_request) { create(:merge_request) }
+ let(:commit) { new_merge_request.project.commit }
+ let!(:note) { create(:system_note, noteable: merge_request, project: project, note: cross_reference) }
+ let!(:note_metadata) { create(:system_note_metadata, note: note, action: 'cross_reference') }
+ let(:cross_reference) { "test commit #{commit.to_reference(project)}" }
+ let(:pat) { create(:personal_access_token, user: user) }
+
+ before do
+ project.add_developer(user)
+ new_merge_request.project.add_developer(user)
+
+ hidden_merge_request = create(:merge_request)
+ new_cross_reference = "test commit #{hidden_merge_request.project.commit}"
+ new_note = create(:system_note, noteable: merge_request, project: project, note: new_cross_reference)
+ create(:system_note_metadata, note: new_note, action: 'cross_reference')
+ end
+
+ it 'returns only the note that the user should see' do
+ get api(url, user, personal_access_token: pat)
+
+ expect(response).to have_gitlab_http_status(200)
+ expect(json_response.count).to eq(1)
+ expect(notes_in_response.count).to eq(1)
+
+ parsed_note = notes_in_response.first
+ expect(parsed_note['id']).to eq(note.id)
+ expect(parsed_note['body']).to eq(cross_reference)
+ expect(parsed_note['system']).to be true
+ end
+
+ it 'avoids Git calls and N+1 SQL queries', :request_store do
+ expect_any_instance_of(Repository).not_to receive(:find_commit).with(commit.id)
+
+ control = ActiveRecord::QueryRecorder.new do
+ get api(url, user, personal_access_token: pat)
+ end
+
+ expect(response).to have_gitlab_http_status(200)
+
+ RequestStore.clear!
+
+ new_note = create(:system_note, noteable: merge_request, project: project, note: cross_reference)
+ create(:system_note_metadata, note: new_note, action: 'cross_reference')
+
+ RequestStore.clear!
+
+ expect { get api(url, user, personal_access_token: pat) }.not_to exceed_query_limit(control)
+ expect(response).to have_gitlab_http_status(200)
+ end
+end
+
shared_examples 'discussions API' do |parent_type, noteable_type, id_name, can_reply_to_individual_notes: false|
describe "GET /#{parent_type}/:id/#{noteable_type}/:noteable_id/discussions" do
it "returns an array of discussions" do
diff --git a/spec/support/shared_examples/requests/api/issuable_participants_examples.rb b/spec/support/shared_examples/requests/api/issuable_participants_examples.rb
index 96d59e0c472..9fe6288d53f 100644
--- a/spec/support/shared_examples/requests/api/issuable_participants_examples.rb
+++ b/spec/support/shared_examples/requests/api/issuable_participants_examples.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
shared_examples 'issuable participants endpoint' do
let(:area) { entity.class.name.underscore.pluralize }
diff --git a/spec/support/shared_examples/requests/api/issues/merge_requests_count_shared_examples.rb b/spec/support/shared_examples/requests/api/issues/merge_requests_count_shared_examples.rb
index 5f4e178f2e5..90c1ed8d09b 100644
--- a/spec/support/shared_examples/requests/api/issues/merge_requests_count_shared_examples.rb
+++ b/spec/support/shared_examples/requests/api/issues/merge_requests_count_shared_examples.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
def get_issue
json_response.is_a?(Array) ? json_response.detect {|issue| issue['id'] == target_issue.id} : json_response
end
diff --git a/spec/support/shared_examples/requests/api/notes.rb b/spec/support/shared_examples/requests/api/notes.rb
index 57eefd5ef01..354ae7288b1 100644
--- a/spec/support/shared_examples/requests/api/notes.rb
+++ b/spec/support/shared_examples/requests/api/notes.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
shared_examples 'noteable API' do |parent_type, noteable_type, id_name|
describe "GET /#{parent_type}/:id/#{noteable_type}/:noteable_id/notes" do
context 'sorting' do
diff --git a/spec/support/shared_examples/requests/api/pipelines/visibility_table_examples.rb b/spec/support/shared_examples/requests/api/pipelines/visibility_table_examples.rb
new file mode 100644
index 00000000000..dfd07176b1c
--- /dev/null
+++ b/spec/support/shared_examples/requests/api/pipelines/visibility_table_examples.rb
@@ -0,0 +1,235 @@
+# frozen_string_literal: true
+
+shared_examples 'pipelines visibility table' do
+ using RSpec::Parameterized::TableSyntax
+
+ let(:ci_user) { create(:user) }
+ let(:api_user) { user_role && ci_user }
+
+ let(:pipelines_api_path) do
+ "/projects/#{project.id}/pipelines"
+ end
+
+ let(:response_200) do
+ a_collection_containing_exactly(
+ a_hash_including('sha', 'ref', 'status', 'web_url', 'id' => pipeline.id)
+ )
+ end
+
+ let(:response_40x) do
+ a_hash_including('message')
+ end
+
+ let(:expected_response) do
+ if response_status == 200
+ response_200
+ else
+ response_40x
+ end
+ end
+
+ let(:api_response) { json_response }
+
+ let(:visibility_levels) do
+ {
+ private: Gitlab::VisibilityLevel::PRIVATE,
+ internal: Gitlab::VisibilityLevel::INTERNAL,
+ public: Gitlab::VisibilityLevel::PUBLIC
+ }
+ end
+
+ let(:builds_access_levels) do
+ {
+ enabled: ProjectFeature::ENABLED,
+ private: ProjectFeature::PRIVATE
+ }
+ end
+
+ let(:project_attributes) do
+ {
+ visibility_level: visibility_levels[visibility_level],
+ public_builds: public_builds
+ }
+ end
+
+ let(:project_feature_attributes) do
+ {
+ builds_access_level: builds_access_levels[builds_access_level]
+ }
+ end
+
+ where(:visibility_level, :builds_access_level, :public_builds, :is_admin, :user_role, :response_status) do
+ :private | :enabled | true | true | :non_member | 200
+ :private | :enabled | true | true | :guest | 200
+ :private | :enabled | true | true | :reporter | 200
+ :private | :enabled | true | true | :developer | 200
+ :private | :enabled | true | true | :maintainer | 200
+
+ :private | :enabled | true | false | nil | 404
+ :private | :enabled | true | false | :non_member | 404
+ :private | :enabled | true | false | :guest | 200
+ :private | :enabled | true | false | :reporter | 200
+ :private | :enabled | true | false | :developer | 200
+ :private | :enabled | true | false | :maintainer | 200
+
+ :private | :enabled | false | true | :non_member | 200
+ :private | :enabled | false | true | :guest | 200
+ :private | :enabled | false | true | :reporter | 200
+ :private | :enabled | false | true | :developer | 200
+ :private | :enabled | false | true | :maintainer | 200
+
+ :private | :enabled | false | false | nil | 404
+ :private | :enabled | false | false | :non_member | 404
+ :private | :enabled | false | false | :guest | 403
+ :private | :enabled | false | false | :reporter | 200
+ :private | :enabled | false | false | :developer | 200
+ :private | :enabled | false | false | :maintainer | 200
+
+ :private | :private | true | true | :non_member | 200
+ :private | :private | true | true | :guest | 200
+ :private | :private | true | true | :reporter | 200
+ :private | :private | true | true | :developer | 200
+ :private | :private | true | true | :maintainer | 200
+
+ :private | :private | true | false | nil | 404
+ :private | :private | true | false | :non_member | 404
+ :private | :private | true | false | :guest | 200
+ :private | :private | true | false | :reporter | 200
+ :private | :private | true | false | :developer | 200
+ :private | :private | true | false | :maintainer | 200
+
+ :private | :private | false | true | :non_member | 200
+ :private | :private | false | true | :guest | 200
+ :private | :private | false | true | :reporter | 200
+ :private | :private | false | true | :developer | 200
+ :private | :private | false | true | :maintainer | 200
+
+ :private | :private | false | false | nil | 404
+ :private | :private | false | false | :non_member | 404
+ :private | :private | false | false | :guest | 403
+ :private | :private | false | false | :reporter | 200
+ :private | :private | false | false | :developer | 200
+ :private | :private | false | false | :maintainer | 200
+
+ :internal | :enabled | true | true | :non_member | 200
+ :internal | :enabled | true | true | :guest | 200
+ :internal | :enabled | true | true | :reporter | 200
+ :internal | :enabled | true | true | :developer | 200
+ :internal | :enabled | true | true | :maintainer | 200
+
+ :internal | :enabled | true | false | nil | 404
+ :internal | :enabled | true | false | :non_member | 200
+ :internal | :enabled | true | false | :guest | 200
+ :internal | :enabled | true | false | :reporter | 200
+ :internal | :enabled | true | false | :developer | 200
+ :internal | :enabled | true | false | :maintainer | 200
+
+ :internal | :enabled | false | true | :non_member | 200
+ :internal | :enabled | false | true | :guest | 200
+ :internal | :enabled | false | true | :reporter | 200
+ :internal | :enabled | false | true | :developer | 200
+ :internal | :enabled | false | true | :maintainer | 200
+
+ :internal | :enabled | false | false | nil | 404
+ :internal | :enabled | false | false | :non_member | 403
+ :internal | :enabled | false | false | :guest | 403
+ :internal | :enabled | false | false | :reporter | 200
+ :internal | :enabled | false | false | :developer | 200
+ :internal | :enabled | false | false | :maintainer | 200
+
+ :internal | :private | true | true | :non_member | 200
+ :internal | :private | true | true | :guest | 200
+ :internal | :private | true | true | :reporter | 200
+ :internal | :private | true | true | :developer | 200
+ :internal | :private | true | true | :maintainer | 200
+
+ :internal | :private | true | false | nil | 404
+ :internal | :private | true | false | :non_member | 403
+ :internal | :private | true | false | :guest | 200
+ :internal | :private | true | false | :reporter | 200
+ :internal | :private | true | false | :developer | 200
+ :internal | :private | true | false | :maintainer | 200
+
+ :internal | :private | false | true | :non_member | 200
+ :internal | :private | false | true | :guest | 200
+ :internal | :private | false | true | :reporter | 200
+ :internal | :private | false | true | :developer | 200
+ :internal | :private | false | true | :maintainer | 200
+
+ :internal | :private | false | false | nil | 404
+ :internal | :private | false | false | :non_member | 403
+ :internal | :private | false | false | :guest | 403
+ :internal | :private | false | false | :reporter | 200
+ :internal | :private | false | false | :developer | 200
+ :internal | :private | false | false | :maintainer | 200
+
+ :public | :enabled | true | true | :non_member | 200
+ :public | :enabled | true | true | :guest | 200
+ :public | :enabled | true | true | :reporter | 200
+ :public | :enabled | true | true | :developer | 200
+ :public | :enabled | true | true | :maintainer | 200
+
+ :public | :enabled | true | false | nil | 200
+ :public | :enabled | true | false | :non_member | 200
+ :public | :enabled | true | false | :guest | 200
+ :public | :enabled | true | false | :reporter | 200
+ :public | :enabled | true | false | :developer | 200
+ :public | :enabled | true | false | :maintainer | 200
+
+ :public | :enabled | false | true | :non_member | 200
+ :public | :enabled | false | true | :guest | 200
+ :public | :enabled | false | true | :reporter | 200
+ :public | :enabled | false | true | :developer | 200
+ :public | :enabled | false | true | :maintainer | 200
+
+ :public | :enabled | false | false | nil | 403
+ :public | :enabled | false | false | :non_member | 403
+ :public | :enabled | false | false | :guest | 403
+ :public | :enabled | false | false | :reporter | 200
+ :public | :enabled | false | false | :developer | 200
+ :public | :enabled | false | false | :maintainer | 200
+
+ :public | :private | true | true | :non_member | 200
+ :public | :private | true | true | :guest | 200
+ :public | :private | true | true | :reporter | 200
+ :public | :private | true | true | :developer | 200
+ :public | :private | true | true | :maintainer | 200
+
+ :public | :private | true | false | nil | 403
+ :public | :private | true | false | :non_member | 403
+ :public | :private | true | false | :guest | 200
+ :public | :private | true | false | :reporter | 200
+ :public | :private | true | false | :developer | 200
+ :public | :private | true | false | :maintainer | 200
+
+ :public | :private | false | true | :non_member | 200
+ :public | :private | false | true | :guest | 200
+ :public | :private | false | true | :reporter | 200
+ :public | :private | false | true | :developer | 200
+ :public | :private | false | true | :maintainer | 200
+
+ :public | :private | false | false | nil | 403
+ :public | :private | false | false | :non_member | 403
+ :public | :private | false | false | :guest | 403
+ :public | :private | false | false | :reporter | 200
+ :public | :private | false | false | :developer | 200
+ :public | :private | false | false | :maintainer | 200
+ end
+
+ with_them do
+ before do
+ ci_user.update!(admin: is_admin) if user_role
+
+ project.update!(project_attributes)
+ project.project_feature.update!(project_feature_attributes)
+ project.add_role(ci_user, user_role) if user_role && user_role != :non_member
+
+ get api(pipelines_api_path, api_user)
+ end
+
+ it do
+ expect(response).to have_gitlab_http_status(response_status)
+ expect(api_response).to match(expected_response)
+ end
+ end
+end
diff --git a/spec/support/shared_examples/requests/api/resolvable_discussions.rb b/spec/support/shared_examples/requests/api/resolvable_discussions.rb
index 7e2416b23f3..42054a273f3 100644
--- a/spec/support/shared_examples/requests/api/resolvable_discussions.rb
+++ b/spec/support/shared_examples/requests/api/resolvable_discussions.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
shared_examples 'resolvable discussions API' do |parent_type, noteable_type, id_name|
describe "PUT /#{parent_type}/:id/#{noteable_type}/:noteable_id/discussions/:discussion_id" do
it "resolves discussion if resolved is true" do
diff --git a/spec/support/shared_examples/requests/api/status_shared_examples.rb b/spec/support/shared_examples/requests/api/status_shared_examples.rb
index ebfc5fed3bb..eebed7e42c1 100644
--- a/spec/support/shared_examples/requests/api/status_shared_examples.rb
+++ b/spec/support/shared_examples/requests/api/status_shared_examples.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
# Specs for status checking.
#
# Requires an API request:
diff --git a/spec/support/shared_examples/requests/graphql_shared_examples.rb b/spec/support/shared_examples/requests/graphql_shared_examples.rb
index 04140cad3f0..2a38d56141a 100644
--- a/spec/support/shared_examples/requests/graphql_shared_examples.rb
+++ b/spec/support/shared_examples/requests/graphql_shared_examples.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
shared_examples 'a working graphql query' do
diff --git a/spec/support/shared_examples/resource_label_events_api.rb b/spec/support/shared_examples/resource_label_events_api.rb
new file mode 100644
index 00000000000..945cb8d9f2c
--- /dev/null
+++ b/spec/support/shared_examples/resource_label_events_api.rb
@@ -0,0 +1,44 @@
+# frozen_string_literal: true
+
+shared_examples 'resource_label_events API' do |parent_type, eventable_type, id_name|
+ describe "GET /#{parent_type}/:id/#{eventable_type}/:noteable_id/resource_label_events" do
+ it "returns an array of resource label events" do
+ get api("/#{parent_type}/#{parent.id}/#{eventable_type}/#{eventable[id_name]}/resource_label_events", user)
+
+ expect(response).to have_gitlab_http_status(200)
+ expect(response).to include_pagination_headers
+ expect(json_response).to be_an Array
+ expect(json_response.first['id']).to eq(event.id)
+ end
+
+ it "returns a 404 error when eventable id not found" do
+ get api("/#{parent_type}/#{parent.id}/#{eventable_type}/12345/resource_label_events", user)
+
+ expect(response).to have_gitlab_http_status(404)
+ end
+
+ it "returns 404 when not authorized" do
+ parent.update!(visibility_level: Gitlab::VisibilityLevel::PRIVATE)
+ private_user = create(:user)
+
+ get api("/#{parent_type}/#{parent.id}/#{eventable_type}/#{eventable[id_name]}/resource_label_events", private_user)
+
+ expect(response).to have_gitlab_http_status(404)
+ end
+ end
+
+ describe "GET /#{parent_type}/:id/#{eventable_type}/:noteable_id/resource_label_events/:event_id" do
+ it "returns a resource label event by id" do
+ get api("/#{parent_type}/#{parent.id}/#{eventable_type}/#{eventable[id_name]}/resource_label_events/#{event.id}", user)
+
+ expect(response).to have_gitlab_http_status(200)
+ expect(json_response['id']).to eq(event.id)
+ end
+
+ it "returns a 404 error if resource label event not found" do
+ get api("/#{parent_type}/#{parent.id}/#{eventable_type}/#{eventable[id_name]}/resource_label_events/12345", user)
+
+ expect(response).to have_gitlab_http_status(404)
+ end
+ end
+end
diff --git a/spec/support/shared_examples/serializers/note_entity_examples.rb b/spec/support/shared_examples/serializers/note_entity_examples.rb
index ec208aba2a9..bfcaa2f1bd5 100644
--- a/spec/support/shared_examples/serializers/note_entity_examples.rb
+++ b/spec/support/shared_examples/serializers/note_entity_examples.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
shared_examples 'note entity' do
subject { entity.as_json }
diff --git a/spec/support/shared_examples/services/boards/boards_create_service.rb b/spec/support/shared_examples/services/boards/boards_create_service.rb
index 5bdc04f660f..19818a6091b 100644
--- a/spec/support/shared_examples/services/boards/boards_create_service.rb
+++ b/spec/support/shared_examples/services/boards/boards_create_service.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
shared_examples 'boards create service' do
context 'when parent does not have a board' do
it 'creates a new board' do
diff --git a/spec/support/shared_examples/services/boards/boards_list_service.rb b/spec/support/shared_examples/services/boards/boards_list_service.rb
index e0d5a7c61f2..566e5050f8e 100644
--- a/spec/support/shared_examples/services/boards/boards_list_service.rb
+++ b/spec/support/shared_examples/services/boards/boards_list_service.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
shared_examples 'boards list service' do
context 'when parent does not have a board' do
it 'creates a new parent board' do
diff --git a/spec/support/shared_examples/services/boards/issues_list_service.rb b/spec/support/shared_examples/services/boards/issues_list_service.rb
index 8b879cef084..75733c774ef 100644
--- a/spec/support/shared_examples/services/boards/issues_list_service.rb
+++ b/spec/support/shared_examples/services/boards/issues_list_service.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
shared_examples 'issues list service' do
it 'delegates search to IssuesFinder' do
params = { board_id: board.id, id: list1.id }
diff --git a/spec/support/shared_examples/services/boards/issues_move_service.rb b/spec/support/shared_examples/services/boards/issues_move_service.rb
index 5359831f8f8..d3fa8084185 100644
--- a/spec/support/shared_examples/services/boards/issues_move_service.rb
+++ b/spec/support/shared_examples/services/boards/issues_move_service.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
shared_examples 'issues move service' do |group|
shared_examples 'updating timestamps' do
it 'updates updated_at' do
diff --git a/spec/support/shared_examples/services/boards/lists_destroy_service.rb b/spec/support/shared_examples/services/boards/lists_destroy_service.rb
index 62b6ffe1836..95725078f9d 100644
--- a/spec/support/shared_examples/services/boards/lists_destroy_service.rb
+++ b/spec/support/shared_examples/services/boards/lists_destroy_service.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
shared_examples 'lists destroy service' do
context 'when list type is label' do
it 'removes list from board' do
diff --git a/spec/support/shared_examples/services/boards/lists_list_service.rb b/spec/support/shared_examples/services/boards/lists_list_service.rb
index 0a8220111ab..29784f6da08 100644
--- a/spec/support/shared_examples/services/boards/lists_list_service.rb
+++ b/spec/support/shared_examples/services/boards/lists_list_service.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
shared_examples 'lists list service' do
context 'when the board has a backlog list' do
let!(:backlog_list) { create(:backlog_list, board: board) }
diff --git a/spec/support/shared_examples/services/boards/lists_move_service.rb b/spec/support/shared_examples/services/boards/lists_move_service.rb
index 2cdb968a45d..0b3bfd8e2a8 100644
--- a/spec/support/shared_examples/services/boards/lists_move_service.rb
+++ b/spec/support/shared_examples/services/boards/lists_move_service.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
shared_examples 'lists move service' do
let!(:planning) { create(:list, board: board, position: 0) }
let!(:development) { create(:list, board: board, position: 1) }
diff --git a/spec/support/shared_examples/services/check_ingress_ip_address_service_shared_examples.rb b/spec/support/shared_examples/services/check_ingress_ip_address_service_shared_examples.rb
index 02de47a96dd..1e0ac8b7615 100644
--- a/spec/support/shared_examples/services/check_ingress_ip_address_service_shared_examples.rb
+++ b/spec/support/shared_examples/services/check_ingress_ip_address_service_shared_examples.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
shared_examples 'check ingress ip executions' do |app_name|
describe '#execute' do
let(:application) { create(app_name, :installed) }
diff --git a/spec/support/shared_examples/services/gitlab_projects_import_service_shared_examples.rb b/spec/support/shared_examples/services/gitlab_projects_import_service_shared_examples.rb
index b8db35a6ef9..1c3fa5644d3 100644
--- a/spec/support/shared_examples/services/gitlab_projects_import_service_shared_examples.rb
+++ b/spec/support/shared_examples/services/gitlab_projects_import_service_shared_examples.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
shared_examples 'gitlab projects import validations' do
context 'with an invalid path' do
let(:path) { '/invalid-path/' }
diff --git a/spec/support/shared_examples/services/notification_service_shared_examples.rb b/spec/support/shared_examples/services/notification_service_shared_examples.rb
new file mode 100644
index 00000000000..dd338ea47c7
--- /dev/null
+++ b/spec/support/shared_examples/services/notification_service_shared_examples.rb
@@ -0,0 +1,54 @@
+# frozen_string_literal: true
+
+# Note that we actually update the attribute on the target_project/group, rather than
+# using `allow`. This is because there are some specs where, based on how the notification
+# is done, using an `allow` doesn't change the correct object.
+shared_examples 'project emails are disabled' do
+ let(:target_project) { notification_target.is_a?(Project) ? notification_target : notification_target.project }
+
+ before do
+ reset_delivered_emails!
+ target_project.clear_memoization(:emails_disabled)
+ end
+
+ it 'sends no emails with project emails disabled' do
+ target_project.update_attribute(:emails_disabled, true)
+
+ notification_trigger
+
+ should_not_email_anyone
+ end
+
+ it 'sends emails to someone' do
+ target_project.update_attribute(:emails_disabled, false)
+
+ notification_trigger
+
+ should_email_anyone
+ end
+end
+
+shared_examples 'group emails are disabled' do
+ let(:target_group) { notification_target.is_a?(Group) ? notification_target : notification_target.project.group }
+
+ before do
+ reset_delivered_emails!
+ target_group.clear_memoization(:emails_disabled)
+ end
+
+ it 'sends no emails with group emails disabled' do
+ target_group.update_attribute(:emails_disabled, true)
+
+ notification_trigger
+
+ should_not_email_anyone
+ end
+
+ it 'sends emails to someone' do
+ target_group.update_attribute(:emails_disabled, false)
+
+ notification_trigger
+
+ should_email_anyone
+ end
+end
diff --git a/spec/support/shared_examples/slack_mattermost_notifications_shared_examples.rb b/spec/support/shared_examples/slack_mattermost_notifications_shared_examples.rb
index 36c486dbdd6..8ce94064dc3 100644
--- a/spec/support/shared_examples/slack_mattermost_notifications_shared_examples.rb
+++ b/spec/support/shared_examples/slack_mattermost_notifications_shared_examples.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
Dir[Rails.root.join("app/models/project_services/chat_message/*.rb")].each { |f| require f }
RSpec.shared_examples 'slack or mattermost notifications' do
@@ -452,7 +454,7 @@ RSpec.shared_examples 'slack or mattermost notifications' do
context 'only notify for the default branch' do
context 'when enabled' do
let(:pipeline) do
- create(:ci_pipeline, :failed, project: project, ref: 'not-the-default-branch')
+ create(:ci_pipeline, :failed, project: project, sha: project.commit.sha, ref: 'not-the-default-branch')
end
before do
@@ -470,7 +472,7 @@ RSpec.shared_examples 'slack or mattermost notifications' do
context 'when disabled' do
let(:pipeline) do
- create(:ci_pipeline, :failed, project: project, ref: 'not-the-default-branch')
+ create(:ci_pipeline, :failed, project: project, sha: project.commit.sha, ref: 'not-the-default-branch')
end
before do
diff --git a/spec/support/shared_examples/snippet_visibility_shared_examples.rb b/spec/support/shared_examples/snippet_visibility_shared_examples.rb
index 833c31a57cb..b5321c6db34 100644
--- a/spec/support/shared_examples/snippet_visibility_shared_examples.rb
+++ b/spec/support/shared_examples/snippet_visibility_shared_examples.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
RSpec.shared_examples 'snippet visibility' do
using RSpec::Parameterized::TableSyntax
diff --git a/spec/support/shared_examples/snippets_shared_examples.rb b/spec/support/shared_examples/snippets_shared_examples.rb
index 85f0facd5c3..5c35617bd36 100644
--- a/spec/support/shared_examples/snippets_shared_examples.rb
+++ b/spec/support/shared_examples/snippets_shared_examples.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
# These shared examples expect a `snippets` array of snippets
RSpec.shared_examples 'paginated snippets' do |remote: false|
it "is limited to #{Snippet.default_per_page} items per page" do
diff --git a/spec/support/shared_examples/taskable_shared_examples.rb b/spec/support/shared_examples/taskable_shared_examples.rb
index 4056ff06b84..f04f509f3d2 100644
--- a/spec/support/shared_examples/taskable_shared_examples.rb
+++ b/spec/support/shared_examples/taskable_shared_examples.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
# Specs for task state functionality for issues and merge requests.
#
# Requires a context containing:
@@ -105,4 +107,25 @@ shared_examples 'a Taskable' do
expect(subject.task_status_short).to match('1 task')
end
end
+
+ describe 'with tasks in blockquotes' do
+ before do
+ subject.description = <<-EOT.strip_heredoc
+ > - [ ] Task a
+ > > - [x] Task a.1
+
+ >>>
+ 1. [ ] Task 1
+ 1. [x] Task 2
+ >>>
+ EOT
+ end
+
+ it 'returns the correct task status' do
+ expect(subject.task_status).to match('2 of')
+ expect(subject.task_status).to match('4 tasks completed')
+ expect(subject.task_status_short).to match('2/')
+ expect(subject.task_status_short).to match('4 tasks')
+ end
+ end
end
diff --git a/spec/support/shared_examples/throttled_touch.rb b/spec/support/shared_examples/throttled_touch.rb
index eba990d4037..aaaa590862d 100644
--- a/spec/support/shared_examples/throttled_touch.rb
+++ b/spec/support/shared_examples/throttled_touch.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
shared_examples_for 'throttled touch' do
describe '#touch' do
it 'updates the updated_at timestamp' do
diff --git a/spec/support/shared_examples/unique_ip_check_shared_examples.rb b/spec/support/shared_examples/unique_ip_check_shared_examples.rb
index e5c8ac6a004..65d86ddee9e 100644
--- a/spec/support/shared_examples/unique_ip_check_shared_examples.rb
+++ b/spec/support/shared_examples/unique_ip_check_shared_examples.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
shared_context 'unique ips sign in limit' do
include StubENV
before do
diff --git a/spec/support/shared_examples/update_invalid_issuable.rb b/spec/support/shared_examples/update_invalid_issuable.rb
index 64568de424e..b7ac08372f9 100644
--- a/spec/support/shared_examples/update_invalid_issuable.rb
+++ b/spec/support/shared_examples/update_invalid_issuable.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
shared_examples 'update invalid issuable' do |klass|
let(:params) do
{
@@ -38,7 +40,7 @@ shared_examples 'update invalid issuable' do |klass|
put :update, params: params
expect(response.status).to eq(409)
- expect(JSON.parse(response.body)).to have_key('errors')
+ expect(json_response).to have_key('errors')
end
end
diff --git a/spec/support/shared_examples/updating_mentions_shared_examples.rb b/spec/support/shared_examples/updating_mentions_shared_examples.rb
index 5e3f19ba19e..ef385f94cc2 100644
--- a/spec/support/shared_examples/updating_mentions_shared_examples.rb
+++ b/spec/support/shared_examples/updating_mentions_shared_examples.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
RSpec.shared_examples 'updating mentions' do |service_class|
let(:mentioned_user) { create(:user) }
let(:service_class) { service_class }
diff --git a/spec/support/shared_examples/uploaders/gitlab_uploader_shared_examples.rb b/spec/support/shared_examples/uploaders/gitlab_uploader_shared_examples.rb
index 1190863d88e..9263aaff89a 100644
--- a/spec/support/shared_examples/uploaders/gitlab_uploader_shared_examples.rb
+++ b/spec/support/shared_examples/uploaders/gitlab_uploader_shared_examples.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
shared_examples "matches the method pattern" do |method|
let(:target) { subject }
let(:args) { nil }
diff --git a/spec/support/shared_examples/uploaders/object_storage_shared_examples.rb b/spec/support/shared_examples/uploaders/object_storage_shared_examples.rb
index 1bd176280c5..5d605dd811b 100644
--- a/spec/support/shared_examples/uploaders/object_storage_shared_examples.rb
+++ b/spec/support/shared_examples/uploaders/object_storage_shared_examples.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
shared_context 'with storage' do |store, **stub_params|
before do
subject.object_store = store
diff --git a/spec/support/shared_examples/url_validator_examples.rb b/spec/support/shared_examples/url_validator_examples.rb
index 25277ccd9aa..c5a775fefb6 100644
--- a/spec/support/shared_examples/url_validator_examples.rb
+++ b/spec/support/shared_examples/url_validator_examples.rb
@@ -1,10 +1,12 @@
+# frozen_string_literal: true
+
RSpec.shared_examples 'url validator examples' do |schemes|
- let(:validator) { described_class.new(attributes: [:link_url], **options) }
- let!(:badge) { build(:badge, link_url: 'http://www.example.com') }
+ describe '#validate' do
+ let(:validator) { described_class.new(attributes: [:link_url], **options) }
+ let(:badge) { build(:badge, link_url: 'http://www.example.com') }
- subject { validator.validate(badge) }
+ subject { validator.validate(badge) }
- describe '#validate' do
context 'with no options' do
let(:options) { {} }
@@ -40,3 +42,52 @@ RSpec.shared_examples 'url validator examples' do |schemes|
end
end
end
+
+RSpec.shared_examples 'public url validator examples' do |setting|
+ let(:validator) { described_class.new(attributes: [:link_url]) }
+ let(:badge) { build(:badge, link_url: 'http://www.example.com') }
+
+ subject { validator.validate(badge) }
+
+ context 'by default' do
+ it 'blocks urls pointing to localhost' do
+ badge.link_url = 'https://127.0.0.1'
+
+ subject
+
+ expect(badge.errors).to be_present
+ end
+
+ it 'blocks urls pointing to the local network' do
+ badge.link_url = 'https://192.168.1.1'
+
+ subject
+
+ expect(badge.errors).to be_present
+ end
+ end
+
+ context 'when local requests are allowed' do
+ let!(:settings) { create(:application_setting) }
+
+ before do
+ stub_application_setting(setting)
+ end
+
+ it 'does not block urls pointing to localhost' do
+ badge.link_url = 'https://127.0.0.1'
+
+ subject
+
+ expect(badge.errors).not_to be_present
+ end
+
+ it 'does not block urls pointing to the local network' do
+ badge.link_url = 'https://192.168.1.1'
+
+ subject
+
+ expect(badge.errors).not_to be_present
+ end
+ end
+end
diff --git a/spec/support/sidekiq.rb b/spec/support/sidekiq.rb
index d1a765f27b9..585c458a64e 100644
--- a/spec/support/sidekiq.rb
+++ b/spec/support/sidekiq.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'sidekiq/testing/inline'
# If Sidekiq::Testing.inline! is used, SQL transactions done inside
diff --git a/spec/support/stored_repositories.rb b/spec/support/stored_repositories.rb
index 55212355daa..95f0f971787 100644
--- a/spec/support/stored_repositories.rb
+++ b/spec/support/stored_repositories.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
RSpec.configure do |config|
config.before(:each, :broken_storage) do
allow(Gitlab::GitalyClient).to receive(:call) do
diff --git a/spec/support/test_reports/test_reports_helper.rb b/spec/support/test_reports/test_reports_helper.rb
index 6840fb9a860..6ba50c83b25 100644
--- a/spec/support/test_reports/test_reports_helper.rb
+++ b/spec/support/test_reports/test_reports_helper.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module TestReportsHelper
def create_test_case_rspec_success(name = 'test_spec')
Gitlab::Ci::Reports::TestCase.new(
diff --git a/spec/support/trace/trace_helpers.rb b/spec/support/trace/trace_helpers.rb
index c7802bbcb94..9255715ff71 100644
--- a/spec/support/trace/trace_helpers.rb
+++ b/spec/support/trace/trace_helpers.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module TraceHelpers
def create_legacy_trace(build, content)
File.open(legacy_trace_path(build), 'wb') { |stream| stream.write(content) }
diff --git a/spec/support/webmock.rb b/spec/support/webmock.rb
index 9ac7e7fc515..32b88edc2df 100644
--- a/spec/support/webmock.rb
+++ b/spec/support/webmock.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'webmock'
require 'webmock/rspec'