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

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2023-11-14 11:41:52 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2023-11-14 11:41:52 +0300
commit585826cb22ecea5998a2c2a4675735c94bdeedac (patch)
tree5b05f0b30d33cef48963609e8a18a4dff260eab3 /spec/lib/gitlab
parentdf221d036e5d0c6c0ee4d55b9c97f481ee05dee8 (diff)
Add latest changes from gitlab-org/gitlab@16-6-stable-eev16.6.0-rc42
Diffstat (limited to 'spec/lib/gitlab')
-rw-r--r--spec/lib/gitlab/alert_management/payload/base_spec.rb12
-rw-r--r--spec/lib/gitlab/analytics/cycle_analytics/average_spec.rb12
-rw-r--r--spec/lib/gitlab/asset_proxy_spec.rb2
-rw-r--r--spec/lib/gitlab/auth/ldap/auth_hash_spec.rb2
-rw-r--r--spec/lib/gitlab/auth/ldap/config_spec.rb10
-rw-r--r--spec/lib/gitlab/auth/ldap/person_spec.rb6
-rw-r--r--spec/lib/gitlab/auth/o_auth/user_spec.rb8
-rw-r--r--spec/lib/gitlab/auth/saml/auth_hash_spec.rb6
-rw-r--r--spec/lib/gitlab/auth/saml/config_spec.rb39
-rw-r--r--spec/lib/gitlab/auth/saml/user_spec.rb20
-rw-r--r--spec/lib/gitlab/auth_spec.rb145
-rw-r--r--spec/lib/gitlab/background_migration/backfill_packages_tags_project_id_spec.rb42
-rw-r--r--spec/lib/gitlab/background_migration/batched_migration_job_spec.rb103
-rw-r--r--spec/lib/gitlab/background_migration/copy_column_using_background_migration_job_spec.rb22
-rw-r--r--spec/lib/gitlab/background_migration/delete_invalid_protected_branch_merge_access_levels_spec.rb76
-rw-r--r--spec/lib/gitlab/background_migration/delete_invalid_protected_branch_push_access_levels_spec.rb76
-rw-r--r--spec/lib/gitlab/background_migration/delete_invalid_protected_tag_create_access_levels_spec.rb76
-rw-r--r--spec/lib/gitlab/background_migration/delete_orphaned_operational_vulnerabilities_spec.rb16
-rw-r--r--spec/lib/gitlab/background_migration/delete_orphans_approval_merge_request_rules_spec.rb9
-rw-r--r--spec/lib/gitlab/background_migration/delete_orphans_approval_project_rules_spec.rb9
-rw-r--r--spec/lib/gitlab/background_migration/destroy_invalid_group_members_spec.rb24
-rw-r--r--spec/lib/gitlab/background_migration/destroy_invalid_members_spec.rb84
-rw-r--r--spec/lib/gitlab/background_migration/destroy_invalid_project_members_spec.rb56
-rw-r--r--spec/lib/gitlab/background_migration/disable_legacy_open_source_licence_for_recent_public_projects_spec.rb19
-rw-r--r--spec/lib/gitlab/background_migration/disable_legacy_open_source_license_for_inactive_public_projects_spec.rb31
-rw-r--r--spec/lib/gitlab/background_migration/disable_legacy_open_source_license_for_no_issues_no_repo_projects_spec.rb37
-rw-r--r--spec/lib/gitlab/background_migration/disable_legacy_open_source_license_for_one_member_no_repo_projects_spec.rb37
-rw-r--r--spec/lib/gitlab/background_migration/disable_legacy_open_source_license_for_projects_less_than_five_mb_spec.rb33
-rw-r--r--spec/lib/gitlab/background_migration/disable_legacy_open_source_license_for_projects_less_than_one_mb_spec.rb33
-rw-r--r--spec/lib/gitlab/background_migration/expire_o_auth_tokens_spec.rb17
-rw-r--r--spec/lib/gitlab/background_migration/fix_incoherent_packages_size_on_project_statistics_spec.rb10
-rw-r--r--spec/lib/gitlab/background_migration/legacy_upload_mover_spec.rb56
-rw-r--r--spec/lib/gitlab/background_migration/remove_backfilled_job_artifacts_expire_at_spec.rb2
-rw-r--r--spec/lib/gitlab/batch_worker_context_spec.rb6
-rw-r--r--spec/lib/gitlab/bitbucket_import/importer_spec.rb2
-rw-r--r--spec/lib/gitlab/bitbucket_import/importers/issue_importer_spec.rb8
-rw-r--r--spec/lib/gitlab/bitbucket_import/importers/issues_importer_spec.rb47
-rw-r--r--spec/lib/gitlab/bitbucket_import/importers/issues_notes_importer_spec.rb6
-rw-r--r--spec/lib/gitlab/bitbucket_import/importers/pull_request_importer_spec.rb8
-rw-r--r--spec/lib/gitlab/bitbucket_import/importers/pull_request_notes_importer_spec.rb214
-rw-r--r--spec/lib/gitlab/bitbucket_import/importers/pull_requests_importer_spec.rb4
-rw-r--r--spec/lib/gitlab/bitbucket_import/importers/pull_requests_notes_importer_spec.rb4
-rw-r--r--spec/lib/gitlab/bitbucket_import/importers/repository_importer_spec.rb17
-rw-r--r--spec/lib/gitlab/bullet/exclusions_spec.rb2
-rw-r--r--spec/lib/gitlab/cache_spec.rb2
-rw-r--r--spec/lib/gitlab/ci/ansi2html_spec.rb8
-rw-r--r--spec/lib/gitlab/ci/ansi2json/line_spec.rb27
-rw-r--r--spec/lib/gitlab/ci/ansi2json/state_spec.rb21
-rw-r--r--spec/lib/gitlab/ci/ansi2json_spec.rb28
-rw-r--r--spec/lib/gitlab/ci/badge/pipeline/status_spec.rb5
-rw-r--r--spec/lib/gitlab/ci/build/artifacts/metadata/entry_spec.rb20
-rw-r--r--spec/lib/gitlab/ci/build/context/build_spec.rb20
-rw-r--r--spec/lib/gitlab/ci/build/hook_spec.rb6
-rw-r--r--spec/lib/gitlab/ci/build/policy/changes_spec.rb53
-rw-r--r--spec/lib/gitlab/ci/build/policy/variables_spec.rb37
-rw-r--r--spec/lib/gitlab/ci/build/rules/rule/clause/changes_spec.rb7
-rw-r--r--spec/lib/gitlab/ci/config/entry/bridge_spec.rb60
-rw-r--r--spec/lib/gitlab/ci/config/entry/commands_spec.rb2
-rw-r--r--spec/lib/gitlab/ci/config/entry/environment_spec.rb2
-rw-r--r--spec/lib/gitlab/ci/config/entry/image_spec.rb6
-rw-r--r--spec/lib/gitlab/ci/config/entry/job_spec.rb76
-rw-r--r--spec/lib/gitlab/ci/config/entry/pages_spec.rb49
-rw-r--r--spec/lib/gitlab/ci/config/entry/policy_spec.rb3
-rw-r--r--spec/lib/gitlab/ci/config/entry/processable_spec.rb14
-rw-r--r--spec/lib/gitlab/ci/config/entry/root_spec.rb14
-rw-r--r--spec/lib/gitlab/ci/config/entry/service_spec.rb12
-rw-r--r--spec/lib/gitlab/ci/config/extendable/entry_spec.rb13
-rw-r--r--spec/lib/gitlab/ci/config/external/file/base_spec.rb2
-rw-r--r--spec/lib/gitlab/ci/config/external/mapper_spec.rb12
-rw-r--r--spec/lib/gitlab/ci/config/header/input_spec.rb31
-rw-r--r--spec/lib/gitlab/ci/config/interpolation/inputs_spec.rb86
-rw-r--r--spec/lib/gitlab/ci/jwt_v2_spec.rb36
-rw-r--r--spec/lib/gitlab/ci/parsers/sbom/cyclonedx_properties_spec.rb36
-rw-r--r--spec/lib/gitlab/ci/parsers/sbom/source/container_scanning_spec.rb58
-rw-r--r--spec/lib/gitlab/ci/parsers/security/common_spec.rb2
-rw-r--r--spec/lib/gitlab/ci/parsers/security/secret_detection_spec.rb2
-rw-r--r--spec/lib/gitlab/ci/pipeline/chain/template_usage_spec.rb4
-rw-r--r--spec/lib/gitlab/ci/pipeline/expression/lexeme/equals_spec.rb2
-rw-r--r--spec/lib/gitlab/ci/pipeline/seed/build_spec.rb2
-rw-r--r--spec/lib/gitlab/ci/reports/accessibility_reports_comparer_spec.rb4
-rw-r--r--spec/lib/gitlab/ci/reports/accessibility_reports_spec.rb4
-rw-r--r--spec/lib/gitlab/ci/reports/test_suite_spec.rb2
-rw-r--r--spec/lib/gitlab/ci/status/composite_spec.rb59
-rw-r--r--spec/lib/gitlab/ci/status/stage/factory_spec.rb2
-rw-r--r--spec/lib/gitlab/ci/status/waiting_for_callback_spec.rb37
-rw-r--r--spec/lib/gitlab/ci/tags/bulk_insert_spec.rb2
-rw-r--r--spec/lib/gitlab/ci/templates/Jobs/deploy_gitlab_ci_yaml_spec.rb6
-rw-r--r--spec/lib/gitlab/ci/templates/Jobs/sast_iac_latest_gitlab_ci_yaml_spec.rb2
-rw-r--r--spec/lib/gitlab/ci/templates/auto_devops_gitlab_ci_yaml_spec.rb42
-rw-r--r--spec/lib/gitlab/ci/variables/collection/item_spec.rb8
-rw-r--r--spec/lib/gitlab/ci/yaml_processor/dag_spec.rb24
-rw-r--r--spec/lib/gitlab/ci/yaml_processor_spec.rb137
-rw-r--r--spec/lib/gitlab/composer/version_index_spec.rb26
-rw-r--r--spec/lib/gitlab/config/entry/factory_spec.rb12
-rw-r--r--spec/lib/gitlab/config/entry/validators_spec.rb2
-rw-r--r--spec/lib/gitlab/config_checker/puma_rugged_checker_spec.rb65
-rw-r--r--spec/lib/gitlab/conflict/file_spec.rb4
-rw-r--r--spec/lib/gitlab/data_builder/build_spec.rb2
-rw-r--r--spec/lib/gitlab/data_builder/pipeline_spec.rb2
-rw-r--r--spec/lib/gitlab/data_builder/push_spec.rb4
-rw-r--r--spec/lib/gitlab/database/background_migration/batched_job_spec.rb2
-rw-r--r--spec/lib/gitlab/database/background_migration/batched_job_transition_log_spec.rb4
-rw-r--r--spec/lib/gitlab/database/background_migration/batched_migration_spec.rb11
-rw-r--r--spec/lib/gitlab/database/background_migration/batched_migration_wrapper_spec.rb22
-rw-r--r--spec/lib/gitlab/database/background_migration/prometheus_metrics_spec.rb13
-rw-r--r--spec/lib/gitlab/database/bulk_update_spec.rb2
-rw-r--r--spec/lib/gitlab/database/dictionary_spec.rb84
-rw-r--r--spec/lib/gitlab/database/dynamic_model_helpers_spec.rb67
-rw-r--r--spec/lib/gitlab/database/gitlab_schema_spec.rb4
-rw-r--r--spec/lib/gitlab/database/loose_foreign_keys_spec.rb16
-rw-r--r--spec/lib/gitlab/database/migration_helpers/cascading_namespace_settings_spec.rb2
-rw-r--r--spec/lib/gitlab/database/migration_helpers/convert_to_bigint_spec.rb133
-rw-r--r--spec/lib/gitlab/database/migration_helpers/wraparound_autovacuum_spec.rb30
-rw-r--r--spec/lib/gitlab/database/migration_helpers_spec.rb40
-rw-r--r--spec/lib/gitlab/database/migrations/batched_background_migration_helpers_spec.rb6
-rw-r--r--spec/lib/gitlab/database/migrations/constraints_helpers_spec.rb40
-rw-r--r--spec/lib/gitlab/database/migrations/instrumentation_spec.rb16
-rw-r--r--spec/lib/gitlab/database/migrations/milestone_mixin_spec.rb13
-rw-r--r--spec/lib/gitlab/database/migrations/reestablished_connection_stack_spec.rb2
-rw-r--r--spec/lib/gitlab/database/migrations/test_batched_background_runner_spec.rb104
-rw-r--r--spec/lib/gitlab/database/no_cross_db_foreign_keys_spec.rb8
-rw-r--r--spec/lib/gitlab/database/no_new_tables_with_gitlab_main_schema_spec.rb63
-rw-r--r--spec/lib/gitlab/database/partitioning/detached_partition_dropper_spec.rb64
-rw-r--r--spec/lib/gitlab/database/partitioning/monthly_strategy_spec.rb36
-rw-r--r--spec/lib/gitlab/database/partitioning/partition_manager_spec.rb85
-rw-r--r--spec/lib/gitlab/database/partitioning/sliding_list_strategy_spec.rb27
-rw-r--r--spec/lib/gitlab/database/partitioning_migration_helpers/index_helpers_spec.rb7
-rw-r--r--spec/lib/gitlab/database/partitioning_migration_helpers/table_management_helpers_spec.rb541
-rw-r--r--spec/lib/gitlab/database/postgres_constraint_spec.rb16
-rw-r--r--spec/lib/gitlab/database/postgres_index_spec.rb4
-rw-r--r--spec/lib/gitlab/database/query_analyzers/gitlab_schemas_metrics_spec.rb6
-rw-r--r--spec/lib/gitlab/database/query_analyzers/gitlab_schemas_validate_connection_spec.rb16
-rw-r--r--spec/lib/gitlab/database/query_analyzers/prevent_set_operator_mismatch/columns_spec.rb88
-rw-r--r--spec/lib/gitlab/database/query_analyzers/prevent_set_operator_mismatch/common_table_expressions_spec.rb97
-rw-r--r--spec/lib/gitlab/database/query_analyzers/prevent_set_operator_mismatch/froms_spec.rb76
-rw-r--r--spec/lib/gitlab/database/query_analyzers/prevent_set_operator_mismatch/node_spec.rb68
-rw-r--r--spec/lib/gitlab/database/query_analyzers/prevent_set_operator_mismatch/references_spec.rb41
-rw-r--r--spec/lib/gitlab/database/query_analyzers/prevent_set_operator_mismatch/select_stmt_spec.rb361
-rw-r--r--spec/lib/gitlab/database/query_analyzers/prevent_set_operator_mismatch/targets_spec.rb94
-rw-r--r--spec/lib/gitlab/database/query_analyzers/prevent_set_operator_mismatch_spec.rb84
-rw-r--r--spec/lib/gitlab/database/reindexing_spec.rb2
-rw-r--r--spec/lib/gitlab/database/tables_locker_spec.rb44
-rw-r--r--spec/lib/gitlab/database/tables_truncate_spec.rb6
-rw-r--r--spec/lib/gitlab/database/transaction/observer_spec.rb2
-rw-r--r--spec/lib/gitlab/dependency_linker/base_linker_spec.rb4
-rw-r--r--spec/lib/gitlab/dependency_linker/cargo_toml_linker_spec.rb2
-rw-r--r--spec/lib/gitlab/dependency_linker/cartfile_linker_spec.rb2
-rw-r--r--spec/lib/gitlab/dependency_linker/composer_json_linker_spec.rb2
-rw-r--r--spec/lib/gitlab/dependency_linker/gemfile_linker_spec.rb2
-rw-r--r--spec/lib/gitlab/dependency_linker/gemspec_linker_spec.rb2
-rw-r--r--spec/lib/gitlab/dependency_linker/go_mod_linker_spec.rb2
-rw-r--r--spec/lib/gitlab/dependency_linker/go_sum_linker_spec.rb2
-rw-r--r--spec/lib/gitlab/dependency_linker/godeps_json_linker_spec.rb2
-rw-r--r--spec/lib/gitlab/dependency_linker/package_json_linker_spec.rb2
-rw-r--r--spec/lib/gitlab/dependency_linker/podfile_linker_spec.rb2
-rw-r--r--spec/lib/gitlab/dependency_linker/podspec_json_linker_spec.rb2
-rw-r--r--spec/lib/gitlab/dependency_linker/podspec_linker_spec.rb2
-rw-r--r--spec/lib/gitlab/dependency_linker/requirements_txt_linker_spec.rb2
-rw-r--r--spec/lib/gitlab/diff/file_collection/compare_spec.rb8
-rw-r--r--spec/lib/gitlab/diff/file_collection/merge_request_diff_batch_spec.rb25
-rw-r--r--spec/lib/gitlab/diff/file_collection/paginated_merge_request_diff_spec.rb16
-rw-r--r--spec/lib/gitlab/diff/file_spec.rb5
-rw-r--r--spec/lib/gitlab/diff/formatters/file_formatter_spec.rb2
-rw-r--r--spec/lib/gitlab/diff/highlight_cache_spec.rb20
-rw-r--r--spec/lib/gitlab/diff/highlight_spec.rb10
-rw-r--r--spec/lib/gitlab/diff/inline_diff_marker_spec.rb6
-rw-r--r--spec/lib/gitlab/diff/line_spec.rb14
-rw-r--r--spec/lib/gitlab/diff/suggestion_diff_spec.rb13
-rw-r--r--spec/lib/gitlab/diff/suggestion_spec.rb22
-rw-r--r--spec/lib/gitlab/diff/suggestions_parser_spec.rb67
-rw-r--r--spec/lib/gitlab/discussions_diff/file_collection_spec.rb15
-rw-r--r--spec/lib/gitlab/email/handler/service_desk_handler_spec.rb92
-rw-r--r--spec/lib/gitlab/email/handler_spec.rb8
-rw-r--r--spec/lib/gitlab/email/receiver_spec.rb2
-rw-r--r--spec/lib/gitlab/encoding_helper_spec.rb2
-rw-r--r--spec/lib/gitlab/endpoint_attributes_spec.rb14
-rw-r--r--spec/lib/gitlab/error_tracking/stack_trace_highlight_decorator_spec.rb2
-rw-r--r--spec/lib/gitlab/external_authorization/client_spec.rb2
-rw-r--r--spec/lib/gitlab/favicon_spec.rb4
-rw-r--r--spec/lib/gitlab/feature_categories_spec.rb2
-rw-r--r--spec/lib/gitlab/file_detector_spec.rb18
-rw-r--r--spec/lib/gitlab/gfm/reference_rewriter_spec.rb10
-rw-r--r--spec/lib/gitlab/git/blame_spec.rb8
-rw-r--r--spec/lib/gitlab/git/blob_spec.rb12
-rw-r--r--spec/lib/gitlab/git/commit_spec.rb24
-rw-r--r--spec/lib/gitlab/git/merge_base_spec.rb8
-rw-r--r--spec/lib/gitlab/git/repository_spec.rb10
-rw-r--r--spec/lib/gitlab/git/rugged_impl/use_rugged_spec.rb116
-rw-r--r--spec/lib/gitlab/git/tree_spec.rb118
-rw-r--r--spec/lib/gitlab/git_access_spec.rb2
-rw-r--r--spec/lib/gitlab/git_audit_event_spec.rb79
-rw-r--r--spec/lib/gitlab/gitaly_client/commit_service_spec.rb29
-rw-r--r--spec/lib/gitlab/gitaly_client/conflict_files_stitcher_spec.rb52
-rw-r--r--spec/lib/gitlab/gitaly_client/operation_service_spec.rb4
-rw-r--r--spec/lib/gitlab/gitaly_client/ref_service_spec.rb4
-rw-r--r--spec/lib/gitlab/gitaly_client/repository_service_spec.rb38
-rw-r--r--spec/lib/gitlab/gitaly_client/storage_settings_spec.rb18
-rw-r--r--spec/lib/gitlab/gitaly_client_spec.rb38
-rw-r--r--spec/lib/gitlab/github_import/attachments_downloader_spec.rb17
-rw-r--r--spec/lib/gitlab/github_import/client_spec.rb39
-rw-r--r--spec/lib/gitlab/github_import/importer/collaborators_importer_spec.rb2
-rw-r--r--spec/lib/gitlab/github_import/importer/diff_notes_importer_spec.rb2
-rw-r--r--spec/lib/gitlab/github_import/importer/issue_events_importer_spec.rb2
-rw-r--r--spec/lib/gitlab/github_import/importer/issues_importer_spec.rb2
-rw-r--r--spec/lib/gitlab/github_import/importer/lfs_objects_importer_spec.rb2
-rw-r--r--spec/lib/gitlab/github_import/importer/note_importer_spec.rb2
-rw-r--r--spec/lib/gitlab/github_import/importer/notes_importer_spec.rb2
-rw-r--r--spec/lib/gitlab/github_import/importer/protected_branches_importer_spec.rb2
-rw-r--r--spec/lib/gitlab/github_import/importer/pull_requests/review_requests_importer_spec.rb10
-rw-r--r--spec/lib/gitlab/github_import/importer/pull_requests_importer_spec.rb2
-rw-r--r--spec/lib/gitlab/github_import/issuable_finder_spec.rb64
-rw-r--r--spec/lib/gitlab/github_import/label_finder_spec.rb49
-rw-r--r--spec/lib/gitlab/github_import/milestone_finder_spec.rb57
-rw-r--r--spec/lib/gitlab/github_import/object_counter_spec.rb10
-rw-r--r--spec/lib/gitlab/github_import/parallel_scheduling_spec.rb12
-rw-r--r--spec/lib/gitlab/github_import/representation/to_hash_spec.rb12
-rw-r--r--spec/lib/gitlab/graphql/known_operations_spec.rb4
-rw-r--r--spec/lib/gitlab/graphql/tracers/metrics_tracer_spec.rb2
-rw-r--r--spec/lib/gitlab/group_search_results_spec.rb2
-rw-r--r--spec/lib/gitlab/hashed_path_spec.rb2
-rw-r--r--spec/lib/gitlab/health_checks/gitaly_check_spec.rb5
-rw-r--r--spec/lib/gitlab/highlight_spec.rb2
-rw-r--r--spec/lib/gitlab/i18n/translation_entry_spec.rb6
-rw-r--r--spec/lib/gitlab/import/import_failure_service_spec.rb38
-rw-r--r--spec/lib/gitlab/import_export/after_export_strategies/base_after_export_strategy_spec.rb2
-rw-r--r--spec/lib/gitlab/import_export/after_export_strategies/web_upload_strategy_spec.rb2
-rw-r--r--spec/lib/gitlab/import_export/all_models.yml2
-rw-r--r--spec/lib/gitlab/import_export/attribute_cleaner_spec.rb2
-rw-r--r--spec/lib/gitlab/import_export/attributes_permitter_spec.rb2
-rw-r--r--spec/lib/gitlab/import_export/command_line_util_spec.rb18
-rw-r--r--spec/lib/gitlab/import_export/error_spec.rb10
-rw-r--r--spec/lib/gitlab/import_export/fast_hash_serializer_spec.rb2
-rw-r--r--spec/lib/gitlab/import_export/json/ndjson_writer_spec.rb2
-rw-r--r--spec/lib/gitlab/import_export/lfs_restorer_spec.rb2
-rw-r--r--spec/lib/gitlab/import_export/lfs_saver_spec.rb2
-rw-r--r--spec/lib/gitlab/import_export/project/tree_saver_spec.rb2
-rw-r--r--spec/lib/gitlab/import_export/saver_spec.rb2
-rw-r--r--spec/lib/gitlab/import_export/snippet_repo_restorer_spec.rb2
-rw-r--r--spec/lib/gitlab/import_sources_spec.rb8
-rw-r--r--spec/lib/gitlab/instrumentation/redis_cluster_validator_spec.rb38
-rw-r--r--spec/lib/gitlab/instrumentation_helper_spec.rb61
-rw-r--r--spec/lib/gitlab/issues/rebalancing/state_spec.rb18
-rw-r--r--spec/lib/gitlab/jira/middleware_spec.rb40
-rw-r--r--spec/lib/gitlab/jira_import/handle_labels_service_spec.rb6
-rw-r--r--spec/lib/gitlab/jira_import/issue_serializer_spec.rb4
-rw-r--r--spec/lib/gitlab/jira_import/labels_importer_spec.rb10
-rw-r--r--spec/lib/gitlab/job_waiter_spec.rb66
-rw-r--r--spec/lib/gitlab/kubernetes/kubectl_cmd_spec.rb4
-rw-r--r--spec/lib/gitlab/kubernetes/role_spec.rb6
-rw-r--r--spec/lib/gitlab/language_data_spec.rb2
-rw-r--r--spec/lib/gitlab/mail_room/mail_room_spec.rb2
-rw-r--r--spec/lib/gitlab/markup_helper_spec.rb8
-rw-r--r--spec/lib/gitlab/memory/instrumentation_spec.rb2
-rw-r--r--spec/lib/gitlab/memory/reporter_spec.rb2
-rw-r--r--spec/lib/gitlab/memory/reports/heap_dump_spec.rb2
-rw-r--r--spec/lib/gitlab/memory/watchdog/configurator_spec.rb2
-rw-r--r--spec/lib/gitlab/memory/watchdog/event_reporter_spec.rb2
-rw-r--r--spec/lib/gitlab/memory/watchdog/handlers/null_handler_spec.rb2
-rw-r--r--spec/lib/gitlab/memory/watchdog/handlers/puma_handler_spec.rb2
-rw-r--r--spec/lib/gitlab/memory/watchdog/handlers/sidekiq_handler_spec.rb2
-rw-r--r--spec/lib/gitlab/memory/watchdog/monitor/rss_memory_limit_spec.rb2
-rw-r--r--spec/lib/gitlab/memory/watchdog/sidekiq_event_reporter_spec.rb2
-rw-r--r--spec/lib/gitlab/memory/watchdog_spec.rb2
-rw-r--r--spec/lib/gitlab/merge_requests/mergeability/check_result_spec.rb24
-rw-r--r--spec/lib/gitlab/metrics/exporter/base_exporter_spec.rb2
-rw-r--r--spec/lib/gitlab/metrics/rails_slis_spec.rb2
-rw-r--r--spec/lib/gitlab/metrics/samplers/threads_sampler_spec.rb8
-rw-r--r--spec/lib/gitlab/metrics/subscribers/action_cable_spec.rb2
-rw-r--r--spec/lib/gitlab/middleware/go_spec.rb4
-rw-r--r--spec/lib/gitlab/middleware/multipart_spec.rb4
-rw-r--r--spec/lib/gitlab/middleware/path_traversal_check_spec.rb183
-rw-r--r--spec/lib/gitlab/omniauth_initializer_spec.rb119
-rw-r--r--spec/lib/gitlab/other_markup_spec.rb43
-rw-r--r--spec/lib/gitlab/pages/deployment_update_spec.rb2
-rw-r--r--spec/lib/gitlab/pages/virtual_host_finder_spec.rb35
-rw-r--r--spec/lib/gitlab/pagination/cursor_based_keyset_spec.rb20
-rw-r--r--spec/lib/gitlab/pagination/keyset/order_spec.rb2
-rw-r--r--spec/lib/gitlab/pagination/offset_header_builder_spec.rb8
-rw-r--r--spec/lib/gitlab/patch/sidekiq_scheduled_enq_spec.rb26
-rw-r--r--spec/lib/gitlab/path_regex_spec.rb14
-rw-r--r--spec/lib/gitlab/popen_spec.rb8
-rw-r--r--spec/lib/gitlab/process_management_spec.rb4
-rw-r--r--spec/lib/gitlab/process_supervisor_spec.rb12
-rw-r--r--spec/lib/gitlab/project_template_spec.rb2
-rw-r--r--spec/lib/gitlab/quick_actions/extractor_spec.rb2
-rw-r--r--spec/lib/gitlab/redis/multi_store_spec.rb421
-rw-r--r--spec/lib/gitlab/redis/pubsub_spec.rb8
-rw-r--r--spec/lib/gitlab/reference_extractor_spec.rb4
-rw-r--r--spec/lib/gitlab/regex_requires_app_spec.rb40
-rw-r--r--spec/lib/gitlab/repository_cache_adapter_spec.rb12
-rw-r--r--spec/lib/gitlab/repository_hash_cache_spec.rb10
-rw-r--r--spec/lib/gitlab/repository_set_cache_spec.rb4
-rw-r--r--spec/lib/gitlab/rugged_instrumentation_spec.rb27
-rw-r--r--spec/lib/gitlab/runtime_spec.rb2
-rw-r--r--spec/lib/gitlab/search/abuse_detection_spec.rb4
-rw-r--r--spec/lib/gitlab/search_results_spec.rb6
-rw-r--r--spec/lib/gitlab/security/scan_configuration_spec.rb4
-rw-r--r--spec/lib/gitlab/seeders/ci/catalog/resource_seeder_spec.rb101
-rw-r--r--spec/lib/gitlab/shard_health_cache_spec.rb4
-rw-r--r--spec/lib/gitlab/sidekiq_config/cli_methods_spec.rb2
-rw-r--r--spec/lib/gitlab/sidekiq_config/worker_matcher_spec.rb76
-rw-r--r--spec/lib/gitlab/sidekiq_logging/structured_logger_spec.rb8
-rw-r--r--spec/lib/gitlab/sidekiq_middleware/duplicate_jobs/duplicate_job_spec.rb16
-rw-r--r--spec/lib/gitlab/sidekiq_middleware/server_metrics_spec.rb31
-rw-r--r--spec/lib/gitlab/sidekiq_middleware/skip_jobs_spec.rb15
-rw-r--r--spec/lib/gitlab/sidekiq_middleware/worker_context/client_spec.rb10
-rw-r--r--spec/lib/gitlab/sidekiq_status_spec.rb22
-rw-r--r--spec/lib/gitlab/ssh_public_key_spec.rb36
-rw-r--r--spec/lib/gitlab/string_range_marker_spec.rb8
-rw-r--r--spec/lib/gitlab/string_regex_marker_spec.rb18
-rw-r--r--spec/lib/gitlab/suggestions/suggestion_set_spec.rb2
-rw-r--r--spec/lib/gitlab/task_helpers_spec.rb6
-rw-r--r--spec/lib/gitlab/tracking/event_definition_spec.rb8
-rw-r--r--spec/lib/gitlab/url_builder_spec.rb1
-rw-r--r--spec/lib/gitlab/url_sanitizer_spec.rb8
-rw-r--r--spec/lib/gitlab/usage/metric_definition_spec.rb166
-rw-r--r--spec/lib/gitlab/usage/metric_spec.rb4
-rw-r--r--spec/lib/gitlab/usage/metrics/instrumentations/aggregated_metric_spec.rb3
-rw-r--r--spec/lib/gitlab/usage/metrics/instrumentations/count_projects_with_jira_dvcs_integration_metric_spec.rb50
-rw-r--r--spec/lib/gitlab/usage/metrics/instrumentations/database_metric_spec.rb2
-rw-r--r--spec/lib/gitlab/usage/metrics/instrumentations/generic_metric_spec.rb2
-rw-r--r--spec/lib/gitlab/usage/metrics/instrumentations/numbers_metric_spec.rb2
-rw-r--r--spec/lib/gitlab/usage/metrics/instrumentations/redis_hll_metric_spec.rb3
-rw-r--r--spec/lib/gitlab/usage/metrics/instrumentations/redis_metric_spec.rb3
-rw-r--r--spec/lib/gitlab/usage/service_ping/instrumented_payload_spec.rb4
-rw-r--r--spec/lib/gitlab/usage_data_counters/hll_redis_counter_spec.rb88
-rw-r--r--spec/lib/gitlab/usage_data_counters/redis_counter_spec.rb48
-rw-r--r--spec/lib/gitlab/usage_data_spec.rb8
-rw-r--r--spec/lib/gitlab/utils/log_limited_array_spec.rb2
-rw-r--r--spec/lib/gitlab/webpack/graphql_known_operations_spec.rb2
-rw-r--r--spec/lib/gitlab/wiki_pages/front_matter_parser_spec.rb2
-rw-r--r--spec/lib/gitlab/workhorse_spec.rb9
332 files changed, 5910 insertions, 2692 deletions
diff --git a/spec/lib/gitlab/alert_management/payload/base_spec.rb b/spec/lib/gitlab/alert_management/payload/base_spec.rb
index 3e8d71ac673..bfde0a69f98 100644
--- a/spec/lib/gitlab/alert_management/payload/base_spec.rb
+++ b/spec/lib/gitlab/alert_management/payload/base_spec.rb
@@ -32,7 +32,7 @@ RSpec.describe Gitlab::AlertManagement::Payload::Base do
context 'with multiple paths provided' do
let(:payload_class) do
Class.new(described_class) do
- attribute :test, paths: [['test'], %w(alt test)]
+ attribute :test, paths: [['test'], %w[alt test]]
end
end
@@ -204,8 +204,8 @@ RSpec.describe Gitlab::AlertManagement::Payload::Base do
end
context 'with too-long hosts array' do
- let(:hosts) { %w(abc def ghij) }
- let(:shortened_hosts) { %w(abc def ghi) }
+ let(:hosts) { %w[abc def ghij] }
+ let(:shortened_hosts) { %w[abc def ghi] }
before do
stub_const('::AlertManagement::Alert::HOSTS_MAX_LENGTH', 9)
@@ -215,15 +215,15 @@ RSpec.describe Gitlab::AlertManagement::Payload::Base do
it { is_expected.to eq(hosts: shortened_hosts, project_id: project.id) }
context 'with host cut off between elements' do
- let(:hosts) { %w(abcde fghij) }
- let(:shortened_hosts) { %w(abcde fghi) }
+ let(:hosts) { %w[abcde fghij] }
+ let(:shortened_hosts) { %w[abcde fghi] }
it { is_expected.to eq({ hosts: shortened_hosts, project_id: project.id }) }
end
context 'with nested hosts' do
let(:hosts) { ['abc', ['de', 'f'], 'g', 'hij'] } # rubocop:disable Style/WordArray
- let(:shortened_hosts) { %w(abc de f g hi) }
+ let(:shortened_hosts) { %w[abc de f g hi] }
it { is_expected.to eq({ hosts: shortened_hosts, project_id: project.id }) }
end
diff --git a/spec/lib/gitlab/analytics/cycle_analytics/average_spec.rb b/spec/lib/gitlab/analytics/cycle_analytics/average_spec.rb
index 261d587506f..b2a267d42ec 100644
--- a/spec/lib/gitlab/analytics/cycle_analytics/average_spec.rb
+++ b/spec/lib/gitlab/analytics/cycle_analytics/average_spec.rb
@@ -4,7 +4,6 @@ require 'spec_helper'
RSpec.describe Gitlab::Analytics::CycleAnalytics::Average, feature_category: :value_stream_management do
let_it_be(:project) { create(:project) }
-
let_it_be(:issue_1) do
# Duration: 10 days
create(:issue, project: project, created_at: 20.days.ago).tap do |issue|
@@ -30,8 +29,12 @@ RSpec.describe Gitlab::Analytics::CycleAnalytics::Average, feature_category: :va
let(:query) { Issue.joins(:metrics).in_projects(project.id) }
- around do |example|
- freeze_time { example.run }
+ before_all do
+ freeze_time
+ end
+
+ after :all do
+ unfreeze_time
end
subject(:average) { described_class.new(stage: stage, query: query) }
@@ -45,8 +48,7 @@ RSpec.describe Gitlab::Analytics::CycleAnalytics::Average, feature_category: :va
it { is_expected.to eq(nil) }
end
- context 'returns the average duration in seconds',
- quarantine: 'https://gitlab.com/gitlab-org/gitlab/-/issues/413223' do
+ context 'returns the average duration in seconds' do
it { is_expected.to be_within(0.5).of(7.5.days.to_f) }
end
end
diff --git a/spec/lib/gitlab/asset_proxy_spec.rb b/spec/lib/gitlab/asset_proxy_spec.rb
index 7d7952d5741..af8721739a0 100644
--- a/spec/lib/gitlab/asset_proxy_spec.rb
+++ b/spec/lib/gitlab/asset_proxy_spec.rb
@@ -17,7 +17,7 @@ RSpec.describe Gitlab::AssetProxy do
context 'when asset proxy is enabled' do
before do
- stub_asset_proxy_setting(allowlist: %w(gitlab.com *.mydomain.com))
+ stub_asset_proxy_setting(allowlist: %w[gitlab.com *.mydomain.com])
stub_asset_proxy_setting(
enabled: true,
url: 'https://assets.example.com',
diff --git a/spec/lib/gitlab/auth/ldap/auth_hash_spec.rb b/spec/lib/gitlab/auth/ldap/auth_hash_spec.rb
index c19d890a703..0208255d24d 100644
--- a/spec/lib/gitlab/auth/ldap/auth_hash_spec.rb
+++ b/spec/lib/gitlab/auth/ldap/auth_hash_spec.rb
@@ -52,7 +52,7 @@ RSpec.describe Gitlab::Auth::Ldap::AuthHash do
let(:attributes) do
{
- 'username' => %w(mail email),
+ 'username' => %w[mail email],
'name' => 'fullName'
}
end
diff --git a/spec/lib/gitlab/auth/ldap/config_spec.rb b/spec/lib/gitlab/auth/ldap/config_spec.rb
index 48039b58216..f97b16254e7 100644
--- a/spec/lib/gitlab/auth/ldap/config_spec.rb
+++ b/spec/lib/gitlab/auth/ldap/config_spec.rb
@@ -90,7 +90,7 @@ AtlErSqafbECNDSwS5BX8yDpu5yRBJ4xegO/rNlmb8ICRYkuJapD1xXicFOsmfUK
end
it 'returns one provider' do
- expect(described_class.available_providers).to match_array(%w(ldapmain))
+ expect(described_class.available_providers).to match_array(%w[ldapmain])
end
end
@@ -552,15 +552,15 @@ AtlErSqafbECNDSwS5BX8yDpu5yRBJ4xegO/rNlmb8ICRYkuJapD1xXicFOsmfUK
stub_ldap_config(
options: {
'attributes' => {
- 'username' => %w(sAMAccountName),
- 'email' => %w(userPrincipalName)
+ 'username' => %w[sAMAccountName],
+ 'email' => %w[userPrincipalName]
}
}
)
expect(config.attributes).to include({
- 'username' => %w(sAMAccountName),
- 'email' => %w(userPrincipalName),
+ 'username' => %w[sAMAccountName],
+ 'email' => %w[userPrincipalName],
'name' => 'cn'
})
end
diff --git a/spec/lib/gitlab/auth/ldap/person_spec.rb b/spec/lib/gitlab/auth/ldap/person_spec.rb
index f8268bb1666..b5fd44d4aa9 100644
--- a/spec/lib/gitlab/auth/ldap/person_spec.rb
+++ b/spec/lib/gitlab/auth/ldap/person_spec.rb
@@ -13,13 +13,13 @@ RSpec.describe Gitlab::Auth::Ldap::Person do
'uid' => 'uid',
'attributes' => {
'name' => 'cn',
- 'email' => %w(mail email userPrincipalName),
+ 'email' => %w[mail email userPrincipalName],
'username' => username_attribute
}
}
)
end
- let(:username_attribute) { %w(uid sAMAccountName userid) }
+ let(:username_attribute) { %w[uid sAMAccountName userid] }
describe '.normalize_dn' do
subject { described_class.normalize_dn(given) }
@@ -57,7 +57,7 @@ RSpec.describe Gitlab::Auth::Ldap::Person do
'attributes' => {
'name' => 'cn',
'email' => 'mail',
- 'username' => %w(uid mail),
+ 'username' => %w[uid mail],
'first_name' => ''
}
}
diff --git a/spec/lib/gitlab/auth/o_auth/user_spec.rb b/spec/lib/gitlab/auth/o_auth/user_spec.rb
index 8a9182f6457..c137ca88589 100644
--- a/spec/lib/gitlab/auth/o_auth/user_spec.rb
+++ b/spec/lib/gitlab/auth/o_auth/user_spec.rb
@@ -369,7 +369,7 @@ RSpec.describe Gitlab::Auth::OAuth::User, feature_category: :system_access do
context "and at least one LDAP provider is defined" do
before do
- stub_ldap_config(providers: %w(ldapmain))
+ stub_ldap_config(providers: %w[ldapmain])
end
context "and a corresponding LDAP person" do
@@ -570,7 +570,7 @@ RSpec.describe Gitlab::Auth::OAuth::User, feature_category: :system_access do
before do
allow(ldap_user).to receive(:uid) { uid }
allow(ldap_user).to receive(:username) { 'johndoe@example.com' }
- allow(ldap_user).to receive(:email) { %w(johndoe@example.com john2@example.com) }
+ allow(ldap_user).to receive(:email) { %w[johndoe@example.com john2@example.com] }
allow(ldap_user).to receive(:dn) { dn }
end
@@ -605,7 +605,7 @@ RSpec.describe Gitlab::Auth::OAuth::User, feature_category: :system_access do
context "and at least one LDAP provider is defined" do
before do
- stub_ldap_config(providers: %w(ldapmain))
+ stub_ldap_config(providers: %w[ldapmain])
end
context "and a corresponding LDAP person" do
@@ -1055,7 +1055,7 @@ RSpec.describe Gitlab::Auth::OAuth::User, feature_category: :system_access do
context "update only requested info" do
before do
stub_omniauth_setting(sync_profile_from_provider: ['my-provider'])
- stub_omniauth_setting(sync_profile_attributes: %w(name location))
+ stub_omniauth_setting(sync_profile_attributes: %w[name location])
end
it "updates the user name" do
diff --git a/spec/lib/gitlab/auth/saml/auth_hash_spec.rb b/spec/lib/gitlab/auth/saml/auth_hash_spec.rb
index 5286e22abc9..e37b9b10834 100644
--- a/spec/lib/gitlab/auth/saml/auth_hash_spec.rb
+++ b/spec/lib/gitlab/auth/saml/auth_hash_spec.rb
@@ -5,7 +5,7 @@ require 'spec_helper'
RSpec.describe Gitlab::Auth::Saml::AuthHash do
include LoginHelpers
- let(:raw_info_attr) { { 'groups' => %w(Developers Freelancers) } }
+ let(:raw_info_attr) { { 'groups' => %w[Developers Freelancers] } }
subject(:saml_auth_hash) { described_class.new(omniauth_auth_hash) }
let(:info_hash) do
@@ -23,12 +23,12 @@ RSpec.describe Gitlab::Auth::Saml::AuthHash do
end
before do
- stub_saml_group_config(%w(Developers Freelancers Designers))
+ stub_saml_group_config(%w[Developers Freelancers Designers])
end
describe '#groups' do
it 'returns array of groups' do
- expect(saml_auth_hash.groups).to eq(%w(Developers Freelancers))
+ expect(saml_auth_hash.groups).to eq(%w[Developers Freelancers])
end
context 'raw info hash attributes empty' do
diff --git a/spec/lib/gitlab/auth/saml/config_spec.rb b/spec/lib/gitlab/auth/saml/config_spec.rb
index d657622c9f2..c19171bb6f8 100644
--- a/spec/lib/gitlab/auth/saml/config_spec.rb
+++ b/spec/lib/gitlab/auth/saml/config_spec.rb
@@ -3,6 +3,8 @@
require 'spec_helper'
RSpec.describe Gitlab::Auth::Saml::Config do
+ include LoginHelpers
+
describe '.enabled?' do
subject { described_class.enabled? }
@@ -10,13 +12,48 @@ RSpec.describe Gitlab::Auth::Saml::Config do
context 'when SAML is enabled' do
before do
- allow(Gitlab::Auth::OAuth::Provider).to receive(:providers).and_return([:saml])
+ stub_basic_saml_config
end
it { is_expected.to eq(true) }
end
end
+ describe '.default_attribute_statements' do
+ it 'includes upstream defaults, nickname and Microsoft values' do
+ expect(described_class.default_attribute_statements).to match_array(
+ {
+ nickname: %w[username nickname],
+ name: [
+ 'name',
+ 'http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name',
+ 'http://schemas.microsoft.com/ws/2008/06/identity/claims/name'
+ ],
+ email: [
+ 'email',
+ 'mail',
+ 'http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress',
+ 'http://schemas.microsoft.com/ws/2008/06/identity/claims/emailaddress'
+ ],
+ first_name: [
+ 'first_name',
+ 'firstname',
+ 'firstName',
+ 'http://schemas.xmlsoap.org/ws/2005/05/identity/claims/givenname',
+ 'http://schemas.microsoft.com/ws/2008/06/identity/claims/givenname'
+ ],
+ last_name: [
+ 'last_name',
+ 'lastname',
+ 'lastName',
+ 'http://schemas.xmlsoap.org/ws/2005/05/identity/claims/surname',
+ 'http://schemas.microsoft.com/ws/2008/06/identity/claims/surname'
+ ]
+ }
+ )
+ end
+ end
+
describe '#external_groups' do
let(:config_1) { described_class.new('saml1') }
diff --git a/spec/lib/gitlab/auth/saml/user_spec.rb b/spec/lib/gitlab/auth/saml/user_spec.rb
index a8a5d8ae5df..034d1a69a0b 100644
--- a/spec/lib/gitlab/auth/saml/user_spec.rb
+++ b/spec/lib/gitlab/auth/saml/user_spec.rb
@@ -11,7 +11,7 @@ RSpec.describe Gitlab::Auth::Saml::User do
let(:uid) { 'my-uid' }
let(:dn) { 'uid=user1,ou=people,dc=example' }
let(:provider) { 'saml' }
- let(:raw_info_attr) { { 'groups' => %w(Developers Freelancers Designers) } }
+ let(:raw_info_attr) { { 'groups' => %w[Developers Freelancers Designers] } }
let(:auth_hash) { OmniAuth::AuthHash.new(uid: uid, provider: provider, info: info_hash, extra: { raw_info: OneLogin::RubySaml::Attributes.new(raw_info_attr) }) }
let(:info_hash) do
{
@@ -47,12 +47,12 @@ RSpec.describe Gitlab::Auth::Saml::User do
context 'external groups' do
before do
- stub_saml_group_config(%w(Interns))
+ stub_saml_group_config(%w[Interns])
end
context 'are defined' do
it 'marks the user as external' do
- stub_saml_group_config(%w(Freelancers))
+ stub_saml_group_config(%w[Freelancers])
saml_user.save # rubocop:disable Rails/SaveBang
expect(gl_user).to be_valid
expect(gl_user.external).to be_truthy
@@ -119,7 +119,7 @@ RSpec.describe Gitlab::Auth::Saml::User do
context 'external groups' do
context 'are defined' do
it 'marks the user as external' do
- stub_saml_group_config(%w(Freelancers))
+ stub_saml_group_config(%w[Freelancers])
saml_user.save # rubocop:disable Rails/SaveBang
expect(gl_user).to be_valid
expect(gl_user.external).to be_truthy
@@ -128,7 +128,7 @@ RSpec.describe Gitlab::Auth::Saml::User do
context 'are defined but the user does not belong there' do
it 'does not mark the user as external' do
- stub_saml_group_config(%w(Interns))
+ stub_saml_group_config(%w[Interns])
saml_user.save # rubocop:disable Rails/SaveBang
expect(gl_user).to be_valid
expect(gl_user.external).to be_falsey
@@ -151,7 +151,7 @@ RSpec.describe Gitlab::Auth::Saml::User do
context 'and at least one LDAP provider is defined' do
before do
- stub_ldap_config(providers: %w(ldapmain))
+ stub_ldap_config(providers: %w[ldapmain])
end
context 'and a corresponding LDAP person' do
@@ -160,7 +160,7 @@ RSpec.describe Gitlab::Auth::Saml::User do
before do
allow(ldap_user).to receive(:uid) { uid }
allow(ldap_user).to receive(:username) { uid }
- allow(ldap_user).to receive(:email) { %w(john@mail.com john2@example.com) }
+ allow(ldap_user).to receive(:email) { %w[john@mail.com john2@example.com] }
allow(ldap_user).to receive(:dn) { dn }
allow(Gitlab::Auth::Ldap::Adapter).to receive(:new).and_return(adapter)
allow(Gitlab::Auth::Ldap::Person).to receive(:find_by_uid).with(uid, adapter).and_return(ldap_user)
@@ -190,14 +190,14 @@ RSpec.describe Gitlab::Auth::Saml::User do
info: info_hash,
extra: {
raw_info: OneLogin::RubySaml::Attributes.new(
- { 'groups' => %w(Developers Freelancers Designers) }
+ { 'groups' => %w[Developers Freelancers Designers] }
)
}
}
end
let(:auth_hash) { OmniAuth::AuthHash.new(auth_hash_base_attributes) }
- let(:uid_types) { %w(uid dn email) }
+ let(:uid_types) { %w[uid dn email] }
before do
create(:omniauth_user,
@@ -410,7 +410,7 @@ RSpec.describe Gitlab::Auth::Saml::User do
let(:raw_info_attr) { {} }
it 'does not mark user as external' do
- stub_saml_group_config(%w(Freelancers))
+ stub_saml_group_config(%w[Freelancers])
expect(saml_user.find_user.external).to be_falsy
end
diff --git a/spec/lib/gitlab/auth_spec.rb b/spec/lib/gitlab/auth_spec.rb
index f5b9555916c..020089b3880 100644
--- a/spec/lib/gitlab/auth_spec.rb
+++ b/spec/lib/gitlab/auth_spec.rb
@@ -8,6 +8,8 @@ RSpec.describe Gitlab::Auth, :use_clean_rails_memory_store_caching, feature_cate
let(:auth_failure) { { actor: nil, project: nil, type: nil, authentication_abilities: nil } }
let(:gl_auth) { described_class }
+ let(:request) { instance_double(ActionDispatch::Request, ip: 'ip') }
+
describe 'constants' do
it 'API_SCOPES contains all scopes for API access' do
expect(subject::API_SCOPES).to match_array %i[api read_user read_api create_runner k8s_proxy]
@@ -202,7 +204,7 @@ RSpec.describe Gitlab::Auth, :use_clean_rails_memory_store_caching, feature_cate
end
context 'when IP is already banned' do
- subject { gl_auth.find_for_git_client('username-does-not-matter', 'password-does-not-matter', project: nil, ip: 'ip') }
+ subject { gl_auth.find_for_git_client('username-does-not-matter', 'password-does-not-matter', project: nil, request: request) }
before do
expect_next_instance_of(Gitlab::Auth::IpRateLimiter) do |rate_limiter|
@@ -223,7 +225,7 @@ RSpec.describe Gitlab::Auth, :use_clean_rails_memory_store_caching, feature_cate
expect(rate_limiter).not_to receive(:reset!)
end
- gl_auth.find_for_git_client('gitlab-ci-token', build.token, project: build.project, ip: 'ip')
+ gl_auth.find_for_git_client('gitlab-ci-token', build.token, project: build.project, request: request)
end
it 'skips rate limiting for failed auth' do
@@ -231,7 +233,7 @@ RSpec.describe Gitlab::Auth, :use_clean_rails_memory_store_caching, feature_cate
expect(rate_limiter).not_to receive(:register_fail!)
end
- gl_auth.find_for_git_client('gitlab-ci-token', 'wrong_token', project: build.project, ip: 'ip')
+ gl_auth.find_for_git_client('gitlab-ci-token', 'wrong_token', project: build.project, request: request)
end
end
@@ -243,7 +245,7 @@ RSpec.describe Gitlab::Auth, :use_clean_rails_memory_store_caching, feature_cate
expect(rate_limiter).to receive(:reset!)
end
- gl_auth.find_for_git_client(user.username, user.password, project: nil, ip: 'ip')
+ gl_auth.find_for_git_client(user.username, user.password, project: nil, request: request)
end
it 'rate limits a user by unique IPs' do
@@ -252,7 +254,7 @@ RSpec.describe Gitlab::Auth, :use_clean_rails_memory_store_caching, feature_cate
end
expect(Gitlab::Auth::UniqueIpsLimiter).to receive(:limit_user!).twice.and_call_original
- gl_auth.find_for_git_client(user.username, user.password, project: nil, ip: 'ip')
+ gl_auth.find_for_git_client(user.username, user.password, project: nil, request: request)
end
it 'registers failure for failed auth' do
@@ -260,13 +262,36 @@ RSpec.describe Gitlab::Auth, :use_clean_rails_memory_store_caching, feature_cate
expect(rate_limiter).to receive(:register_fail!)
end
- gl_auth.find_for_git_client(user.username, 'wrong_password', project: nil, ip: 'ip')
+ gl_auth.find_for_git_client(user.username, 'wrong_password', project: nil, request: request)
+ end
+
+ context 'when failure goes over threshold' do
+ let(:request) { instance_double(ActionDispatch::Request, fullpath: '/some/project.git/info/refs', request_method: 'GET', ip: 'ip') }
+
+ before do
+ expect_next_instance_of(Gitlab::Auth::IpRateLimiter) do |rate_limiter|
+ expect(rate_limiter).to receive(:register_fail!).and_return(true)
+ end
+ end
+
+ it 'logs a message' do
+ expect(Gitlab::AuthLogger).to receive(:error).with(
+ message: include('IP has been temporarily banned from Git auth'),
+ env: :blocklist,
+ remote_ip: request.ip,
+ request_method: request.request_method,
+ path: request.fullpath,
+ login: user.username
+ )
+
+ gl_auth.find_for_git_client(user.username, 'wrong_password', project: nil, request: request)
+ end
end
end
end
context 'build token' do
- subject { gl_auth.find_for_git_client(username, build.token, project: project, ip: 'ip') }
+ subject { gl_auth.find_for_git_client(username, build.token, project: project, request: request) }
let(:username) { 'gitlab-ci-token' }
@@ -344,20 +369,20 @@ RSpec.describe Gitlab::Auth, :use_clean_rails_memory_store_caching, feature_cate
project.create_drone_ci_integration(active: true)
project.drone_ci_integration.update!(token: 'token', drone_url: generate(:url))
- expect(gl_auth.find_for_git_client('drone-ci-token', 'token', project: project, ip: 'ip')).to have_attributes(actor: nil, project: project, type: :ci, authentication_abilities: described_class.build_authentication_abilities)
+ expect(gl_auth.find_for_git_client('drone-ci-token', 'token', project: project, request: request)).to have_attributes(actor: nil, project: project, type: :ci, authentication_abilities: described_class.build_authentication_abilities)
end
it 'recognizes master passwords' do
user = create(:user)
- expect(gl_auth.find_for_git_client(user.username, user.password, project: nil, ip: 'ip')).to have_attributes(actor: user, project: nil, type: :gitlab_or_ldap, authentication_abilities: described_class.full_authentication_abilities)
+ expect(gl_auth.find_for_git_client(user.username, user.password, project: nil, request: request)).to have_attributes(actor: user, project: nil, type: :gitlab_or_ldap, authentication_abilities: described_class.full_authentication_abilities)
end
include_examples 'user login operation with unique ip limit' do
let(:user) { create(:user) }
def operation
- expect(gl_auth.find_for_git_client(user.username, user.password, project: nil, ip: 'ip')).to have_attributes(actor: user, project: nil, type: :gitlab_or_ldap, authentication_abilities: described_class.full_authentication_abilities)
+ expect(gl_auth.find_for_git_client(user.username, user.password, project: nil, request: request)).to have_attributes(actor: user, project: nil, type: :gitlab_or_ldap, authentication_abilities: described_class.full_authentication_abilities)
end
end
@@ -366,14 +391,14 @@ RSpec.describe Gitlab::Auth, :use_clean_rails_memory_store_caching, feature_cate
user = create(:user)
token = Gitlab::LfsToken.new(user).token
- expect(gl_auth.find_for_git_client(user.username, token, project: nil, ip: 'ip')).to have_attributes(actor: user, project: nil, type: :lfs_token, authentication_abilities: described_class.read_write_project_authentication_abilities)
+ expect(gl_auth.find_for_git_client(user.username, token, project: nil, request: request)).to have_attributes(actor: user, project: nil, type: :lfs_token, authentication_abilities: described_class.read_write_project_authentication_abilities)
end
it 'recognizes deploy key lfs tokens' do
key = create(:deploy_key)
token = Gitlab::LfsToken.new(key).token
- expect(gl_auth.find_for_git_client("lfs+deploy-key-#{key.id}", token, project: nil, ip: 'ip')).to have_attributes(actor: key, project: nil, type: :lfs_deploy_token, authentication_abilities: described_class.read_only_authentication_abilities)
+ expect(gl_auth.find_for_git_client("lfs+deploy-key-#{key.id}", token, project: nil, request: request)).to have_attributes(actor: key, project: nil, type: :lfs_deploy_token, authentication_abilities: described_class.read_only_authentication_abilities)
end
it 'does not try password auth before oauth' do
@@ -382,7 +407,7 @@ RSpec.describe Gitlab::Auth, :use_clean_rails_memory_store_caching, feature_cate
expect(gl_auth).not_to receive(:find_with_user_password)
- gl_auth.find_for_git_client(user.username, token, project: nil, ip: 'ip')
+ gl_auth.find_for_git_client(user.username, token, project: nil, request: request)
end
it 'grants deploy key write permissions' do
@@ -390,14 +415,14 @@ RSpec.describe Gitlab::Auth, :use_clean_rails_memory_store_caching, feature_cate
create(:deploy_keys_project, :write_access, deploy_key: key, project: project)
token = Gitlab::LfsToken.new(key).token
- expect(gl_auth.find_for_git_client("lfs+deploy-key-#{key.id}", token, project: project, ip: 'ip')).to have_attributes(actor: key, project: nil, type: :lfs_deploy_token, authentication_abilities: described_class.read_write_authentication_abilities)
+ expect(gl_auth.find_for_git_client("lfs+deploy-key-#{key.id}", token, project: project, request: request)).to have_attributes(actor: key, project: nil, type: :lfs_deploy_token, authentication_abilities: described_class.read_write_authentication_abilities)
end
it 'does not grant deploy key write permissions' do
key = create(:deploy_key)
token = Gitlab::LfsToken.new(key).token
- expect(gl_auth.find_for_git_client("lfs+deploy-key-#{key.id}", token, project: project, ip: 'ip')).to have_attributes(actor: key, project: nil, type: :lfs_deploy_token, authentication_abilities: described_class.read_only_authentication_abilities)
+ expect(gl_auth.find_for_git_client("lfs+deploy-key-#{key.id}", token, project: project, request: request)).to have_attributes(actor: key, project: nil, type: :lfs_deploy_token, authentication_abilities: described_class.read_only_authentication_abilities)
end
end
@@ -409,7 +434,7 @@ RSpec.describe Gitlab::Auth, :use_clean_rails_memory_store_caching, feature_cate
it 'fails' do
access_token = Doorkeeper::AccessToken.create!(application_id: application.id, resource_owner_id: user.id, scopes: 'api')
- expect(gl_auth.find_for_git_client("oauth2", access_token.token, project: nil, ip: 'ip'))
+ expect(gl_auth.find_for_git_client("oauth2", access_token.token, project: nil, request: request))
.to have_attributes(auth_failure)
end
end
@@ -436,7 +461,7 @@ RSpec.describe Gitlab::Auth, :use_clean_rails_memory_store_caching, feature_cate
it 'authenticates with correct abilities' do
access_token = Doorkeeper::AccessToken.create!(application_id: application.id, resource_owner_id: user.id, scopes: scopes)
- expect(gl_auth.find_for_git_client("oauth2", access_token.token, project: nil, ip: 'ip'))
+ expect(gl_auth.find_for_git_client("oauth2", access_token.token, project: nil, request: request))
.to have_attributes(actor: user, project: nil, type: :oauth, authentication_abilities: abilities)
end
end
@@ -447,7 +472,7 @@ RSpec.describe Gitlab::Auth, :use_clean_rails_memory_store_caching, feature_cate
expect(gl_auth).not_to receive(:find_with_user_password)
- gl_auth.find_for_git_client("oauth2", access_token.token, project: nil, ip: 'ip')
+ gl_auth.find_for_git_client("oauth2", access_token.token, project: nil, request: request)
end
context 'blocked user' do
@@ -513,7 +538,7 @@ RSpec.describe Gitlab::Auth, :use_clean_rails_memory_store_caching, feature_cate
impersonation_token = create(:personal_access_token, :impersonation, scopes: ['api'])
- expect(gl_auth.find_for_git_client('', impersonation_token.token, project: nil, ip: 'ip'))
+ expect(gl_auth.find_for_git_client('', impersonation_token.token, project: nil, request: request))
.to have_attributes(auth_failure)
end
@@ -536,7 +561,7 @@ RSpec.describe Gitlab::Auth, :use_clean_rails_memory_store_caching, feature_cate
end
it 'fails if user is blocked' do
- expect(gl_auth.find_for_git_client('', personal_access_token.token, project: nil, ip: 'ip'))
+ expect(gl_auth.find_for_git_client('', personal_access_token.token, project: nil, request: request))
.to have_attributes(auth_failure)
end
end
@@ -544,19 +569,19 @@ RSpec.describe Gitlab::Auth, :use_clean_rails_memory_store_caching, feature_cate
context 'when using a resource access token' do
shared_examples 'with a valid access token' do
it 'successfully authenticates the project bot' do
- expect(gl_auth.find_for_git_client(project_bot_user.username, access_token.token, project: project, ip: 'ip'))
+ expect(gl_auth.find_for_git_client(project_bot_user.username, access_token.token, project: project, request: request))
.to have_attributes(actor: project_bot_user, project: nil, type: :personal_access_token, authentication_abilities: described_class.full_authentication_abilities)
end
it 'successfully authenticates the project bot with a nil project' do
- expect(gl_auth.find_for_git_client(project_bot_user.username, access_token.token, project: nil, ip: 'ip'))
+ expect(gl_auth.find_for_git_client(project_bot_user.username, access_token.token, project: nil, request: request))
.to have_attributes(actor: project_bot_user, project: nil, type: :personal_access_token, authentication_abilities: described_class.full_authentication_abilities)
end
end
shared_examples 'with an invalid access token' do
it 'fails for a non-member' do
- expect(gl_auth.find_for_git_client(project_bot_user.username, access_token.token, project: project, ip: 'ip'))
+ expect(gl_auth.find_for_git_client(project_bot_user.username, access_token.token, project: project, request: request))
.to have_attributes(auth_failure)
end
@@ -566,7 +591,7 @@ RSpec.describe Gitlab::Auth, :use_clean_rails_memory_store_caching, feature_cate
end
it 'fails for a blocked project bot' do
- expect(gl_auth.find_for_git_client(project_bot_user.username, access_token.token, project: project, ip: 'ip'))
+ expect(gl_auth.find_for_git_client(project_bot_user.username, access_token.token, project: project, request: request))
.to have_attributes(auth_failure)
end
end
@@ -637,7 +662,7 @@ RSpec.describe Gitlab::Auth, :use_clean_rails_memory_store_caching, feature_cate
it 'updates last_used_at column if token is valid' do
personal_access_token = create(:personal_access_token, scopes: ['write_repository'])
- expect { gl_auth.find_for_git_client('', personal_access_token.token, project: nil, ip: 'ip') }.to change { personal_access_token.reload.last_used_at }
+ expect { gl_auth.find_for_git_client('', personal_access_token.token, project: nil, request: request) }.to change { personal_access_token.reload.last_used_at }
end
end
@@ -649,7 +674,7 @@ RSpec.describe Gitlab::Auth, :use_clean_rails_memory_store_caching, feature_cate
username: 'normal_user'
)
- expect(gl_auth.find_for_git_client(user.username, user.password, project: nil, ip: 'ip'))
+ expect(gl_auth.find_for_git_client(user.username, user.password, project: nil, request: request))
.to have_attributes(auth_failure)
end
@@ -665,14 +690,14 @@ RSpec.describe Gitlab::Auth, :use_clean_rails_memory_store_caching, feature_cate
it 'fails if grace period expired' do
stub_application_setting(two_factor_grace_period: 0)
- expect { gl_auth.find_for_git_client(user.username, user.password, project: nil, ip: 'ip') }
+ expect { gl_auth.find_for_git_client(user.username, user.password, project: nil, request: request) }
.to raise_error(Gitlab::Auth::MissingPersonalAccessTokenError)
end
it 'goes through if grace period is not expired yet' do
stub_application_setting(two_factor_grace_period: 72)
- expect(gl_auth.find_for_git_client(user.username, user.password, project: nil, ip: 'ip'))
+ expect(gl_auth.find_for_git_client(user.username, user.password, project: nil, request: request))
.to have_attributes(actor: user, project: nil, type: :gitlab_or_ldap, authentication_abilities: described_class.full_authentication_abilities)
end
end
@@ -683,7 +708,7 @@ RSpec.describe Gitlab::Auth, :use_clean_rails_memory_store_caching, feature_cate
end
it 'fails' do
- expect { gl_auth.find_for_git_client(user.username, user.password, project: nil, ip: 'ip') }
+ expect { gl_auth.find_for_git_client(user.username, user.password, project: nil, request: request) }
.to raise_error(Gitlab::Auth::MissingPersonalAccessTokenError)
end
end
@@ -694,7 +719,7 @@ RSpec.describe Gitlab::Auth, :use_clean_rails_memory_store_caching, feature_cate
username: 'normal_user'
)
- expect(gl_auth.find_for_git_client(user.username, user.password, project: nil, ip: 'ip'))
+ expect(gl_auth.find_for_git_client(user.username, user.password, project: nil, request: request))
.to have_attributes(actor: user, project: nil, type: :gitlab_or_ldap, authentication_abilities: described_class.full_authentication_abilities)
end
@@ -704,7 +729,7 @@ RSpec.describe Gitlab::Auth, :use_clean_rails_memory_store_caching, feature_cate
username: 'oauth2'
)
- expect(gl_auth.find_for_git_client(user.username, user.password, project: nil, ip: 'ip'))
+ expect(gl_auth.find_for_git_client(user.username, user.password, project: nil, request: request))
.to have_attributes(actor: user, project: nil, type: :gitlab_or_ldap, authentication_abilities: described_class.full_authentication_abilities)
end
end
@@ -712,34 +737,34 @@ RSpec.describe Gitlab::Auth, :use_clean_rails_memory_store_caching, feature_cate
it 'returns double nil for invalid credentials' do
login = 'foo'
- expect(gl_auth.find_for_git_client(login, 'bar', project: nil, ip: 'ip')).to have_attributes(auth_failure)
+ expect(gl_auth.find_for_git_client(login, 'bar', project: nil, request: request)).to have_attributes(auth_failure)
end
it 'throws an error suggesting user create a PAT when internal auth is disabled' do
allow_any_instance_of(ApplicationSetting).to receive(:password_authentication_enabled_for_git?) { false }
- expect { gl_auth.find_for_git_client('foo', 'bar', project: nil, ip: 'ip') }.to raise_error(Gitlab::Auth::MissingPersonalAccessTokenError)
+ expect { gl_auth.find_for_git_client('foo', 'bar', project: nil, request: request) }.to raise_error(Gitlab::Auth::MissingPersonalAccessTokenError)
end
context 'while using deploy tokens' do
shared_examples 'registry token scope' do
it 'fails when login is not valid' do
- expect(gl_auth.find_for_git_client('random_login', deploy_token.token, project: project, ip: 'ip'))
+ expect(gl_auth.find_for_git_client('random_login', deploy_token.token, project: project, request: request))
.to have_attributes(auth_failure)
end
it 'fails when token is not valid' do
- expect(gl_auth.find_for_git_client(login, '123123', project: project, ip: 'ip'))
+ expect(gl_auth.find_for_git_client(login, '123123', project: project, request: request))
.to have_attributes(auth_failure)
end
it 'fails if token is nil' do
- expect(gl_auth.find_for_git_client(login, nil, project: nil, ip: 'ip'))
+ expect(gl_auth.find_for_git_client(login, nil, project: nil, request: request))
.to have_attributes(auth_failure)
end
it 'fails if token is not related to project' do
- expect(gl_auth.find_for_git_client(login, 'abcdef', project: nil, ip: 'ip'))
+ expect(gl_auth.find_for_git_client(login, 'abcdef', project: nil, request: request))
.to have_attributes(auth_failure)
end
@@ -747,7 +772,7 @@ RSpec.describe Gitlab::Auth, :use_clean_rails_memory_store_caching, feature_cate
deploy_token.revoke!
expect(deploy_token.revoked?).to be_truthy
- expect(gl_auth.find_for_git_client('deploy-token', deploy_token.token, project: nil, ip: 'ip'))
+ expect(gl_auth.find_for_git_client('deploy-token', deploy_token.token, project: nil, request: request))
.to have_attributes(auth_failure)
end
end
@@ -759,7 +784,7 @@ RSpec.describe Gitlab::Auth, :use_clean_rails_memory_store_caching, feature_cate
end
it 'fails when login and token are valid' do
- expect(gl_auth.find_for_git_client(login, deploy_token.token, project: nil, ip: 'ip'))
+ expect(gl_auth.find_for_git_client(login, deploy_token.token, project: nil, request: request))
.to have_attributes(auth_failure)
end
end
@@ -768,7 +793,7 @@ RSpec.describe Gitlab::Auth, :use_clean_rails_memory_store_caching, feature_cate
let(:project) { create(:project, :repository_disabled) }
it 'fails when login and token are valid' do
- expect(gl_auth.find_for_git_client(login, deploy_token.token, project: project, ip: 'ip'))
+ expect(gl_auth.find_for_git_client(login, deploy_token.token, project: project, request: request))
.to have_attributes(auth_failure)
end
end
@@ -782,14 +807,14 @@ RSpec.describe Gitlab::Auth, :use_clean_rails_memory_store_caching, feature_cate
it 'succeeds for the token' do
auth_success = { actor: deploy_token, project: project, type: :deploy_token, authentication_abilities: [:download_code] }
- expect(gl_auth.find_for_git_client(username, deploy_token.token, project: project, ip: 'ip'))
+ expect(gl_auth.find_for_git_client(username, deploy_token.token, project: project, request: request))
.to have_attributes(auth_success)
end
it 'succeeds for the user' do
auth_success = { actor: user, project: nil, type: :gitlab_or_ldap, authentication_abilities: described_class.full_authentication_abilities }
- expect(gl_auth.find_for_git_client(username, user.password, project: project, ip: 'ip'))
+ expect(gl_auth.find_for_git_client(username, user.password, project: project, request: request))
.to have_attributes(auth_success)
end
end
@@ -801,12 +826,12 @@ RSpec.describe Gitlab::Auth, :use_clean_rails_memory_store_caching, feature_cate
let(:auth_success) { { actor: read_repository, project: project, type: :deploy_token, authentication_abilities: [:download_code] } }
it 'succeeds for the right token' do
- expect(gl_auth.find_for_git_client('deployer', read_repository.token, project: project, ip: 'ip'))
+ expect(gl_auth.find_for_git_client('deployer', read_repository.token, project: project, request: request))
.to have_attributes(auth_success)
end
it 'fails for the wrong token' do
- expect(gl_auth.find_for_git_client('deployer', read_registry.token, project: project, ip: 'ip'))
+ expect(gl_auth.find_for_git_client('deployer', read_registry.token, project: project, request: request))
.not_to have_attributes(auth_success)
end
end
@@ -819,12 +844,12 @@ RSpec.describe Gitlab::Auth, :use_clean_rails_memory_store_caching, feature_cate
let(:auth_success) { { actor: read_repository, project: other_project, type: :deploy_token, authentication_abilities: [:download_code] } }
it 'succeeds for the right token' do
- expect(gl_auth.find_for_git_client('deployer', read_repository.token, project: other_project, ip: 'ip'))
+ expect(gl_auth.find_for_git_client('deployer', read_repository.token, project: other_project, request: request))
.to have_attributes(auth_success)
end
it 'fails for the wrong token' do
- expect(gl_auth.find_for_git_client('deployer', read_registry.token, project: other_project, ip: 'ip'))
+ expect(gl_auth.find_for_git_client('deployer', read_registry.token, project: other_project, request: request))
.not_to have_attributes(auth_success)
end
end
@@ -837,7 +862,7 @@ RSpec.describe Gitlab::Auth, :use_clean_rails_memory_store_caching, feature_cate
it 'succeeds when login and token are valid' do
auth_success = { actor: deploy_token, project: project, type: :deploy_token, authentication_abilities: [:download_code] }
- expect(gl_auth.find_for_git_client(login, deploy_token.token, project: project, ip: 'ip'))
+ expect(gl_auth.find_for_git_client(login, deploy_token.token, project: project, request: request))
.to have_attributes(auth_success)
end
@@ -845,34 +870,34 @@ RSpec.describe Gitlab::Auth, :use_clean_rails_memory_store_caching, feature_cate
deploy_token = create(:deploy_token, username: 'deployer', read_registry: false, projects: [project])
auth_success = { actor: deploy_token, project: project, type: :deploy_token, authentication_abilities: [:download_code] }
- expect(gl_auth.find_for_git_client('deployer', deploy_token.token, project: project, ip: 'ip'))
+ expect(gl_auth.find_for_git_client('deployer', deploy_token.token, project: project, request: request))
.to have_attributes(auth_success)
end
it 'does not attempt to rate limit unique IPs for a deploy token' do
expect(Gitlab::Auth::UniqueIpsLimiter).not_to receive(:limit_user!)
- gl_auth.find_for_git_client(login, deploy_token.token, project: project, ip: 'ip')
+ gl_auth.find_for_git_client(login, deploy_token.token, project: project, request: request)
end
it 'fails when login is not valid' do
- expect(gl_auth.find_for_git_client('random_login', deploy_token.token, project: project, ip: 'ip'))
+ expect(gl_auth.find_for_git_client('random_login', deploy_token.token, project: project, request: request))
.to have_attributes(auth_failure)
end
it 'fails when token is not valid' do
- expect(gl_auth.find_for_git_client(login, '123123', project: project, ip: 'ip'))
+ expect(gl_auth.find_for_git_client(login, '123123', project: project, request: request))
.to have_attributes(auth_failure)
end
it 'fails if token is nil' do
- expect(gl_auth.find_for_git_client(login, nil, project: project, ip: 'ip'))
+ expect(gl_auth.find_for_git_client(login, nil, project: project, request: request))
.to have_attributes(auth_failure)
end
it 'fails if token is not related to project' do
another_deploy_token = create(:deploy_token)
- expect(gl_auth.find_for_git_client(another_deploy_token.username, another_deploy_token.token, project: project, ip: 'ip'))
+ expect(gl_auth.find_for_git_client(another_deploy_token.username, another_deploy_token.token, project: project, request: request))
.to have_attributes(auth_failure)
end
@@ -880,7 +905,7 @@ RSpec.describe Gitlab::Auth, :use_clean_rails_memory_store_caching, feature_cate
deploy_token.revoke!
expect(deploy_token.revoked?).to be_truthy
- expect(gl_auth.find_for_git_client('deploy-token', deploy_token.token, project: project, ip: 'ip'))
+ expect(gl_auth.find_for_git_client('deploy-token', deploy_token.token, project: project, request: request))
.to have_attributes(auth_failure)
end
end
@@ -890,7 +915,7 @@ RSpec.describe Gitlab::Auth, :use_clean_rails_memory_store_caching, feature_cate
let(:deploy_token) { create(:deploy_token, :group, read_repository: true, groups: [project_with_group.group]) }
let(:login) { deploy_token.username }
- subject { gl_auth.find_for_git_client(login, deploy_token.token, project: project_with_group, ip: 'ip') }
+ subject { gl_auth.find_for_git_client(login, deploy_token.token, project: project_with_group, request: request) }
it 'succeeds when login and a group deploy token are valid' do
auth_success = { actor: deploy_token, project: project_with_group, type: :deploy_token, authentication_abilities: [:download_code, :read_container_image] }
@@ -901,7 +926,7 @@ RSpec.describe Gitlab::Auth, :use_clean_rails_memory_store_caching, feature_cate
it 'fails if token is not related to group' do
another_deploy_token = create(:deploy_token, :group, read_repository: true)
- expect(gl_auth.find_for_git_client(another_deploy_token.username, another_deploy_token.token, project: project_with_group, ip: 'ip'))
+ expect(gl_auth.find_for_git_client(another_deploy_token.username, another_deploy_token.token, project: project_with_group, request: request))
.to have_attributes(auth_failure)
end
end
@@ -918,7 +943,7 @@ RSpec.describe Gitlab::Auth, :use_clean_rails_memory_store_caching, feature_cate
it 'succeeds when login and a project token are valid' do
auth_success = { actor: deploy_token, project: project, type: :deploy_token, authentication_abilities: [:read_container_image] }
- expect(gl_auth.find_for_git_client(login, deploy_token.token, project: project, ip: 'ip'))
+ expect(gl_auth.find_for_git_client(login, deploy_token.token, project: project, request: request))
.to have_attributes(auth_success)
end
@@ -940,7 +965,7 @@ RSpec.describe Gitlab::Auth, :use_clean_rails_memory_store_caching, feature_cate
it 'succeeds when login and a project token are valid' do
auth_success = { actor: deploy_token, project: project, type: :deploy_token, authentication_abilities: [:create_container_image] }
- expect(gl_auth.find_for_git_client(login, deploy_token.token, project: project, ip: 'ip'))
+ expect(gl_auth.find_for_git_client(login, deploy_token.token, project: project, request: request))
.to have_attributes(auth_success)
end
@@ -953,7 +978,7 @@ RSpec.describe Gitlab::Auth, :use_clean_rails_memory_store_caching, feature_cate
end
describe '#build_access_token_check' do
- subject { gl_auth.find_for_git_client('gitlab-ci-token', build.token, project: build.project, ip: '1.2.3.4') }
+ subject { gl_auth.find_for_git_client('gitlab-ci-token', build.token, project: build.project, request: request) }
let_it_be(:user) { create(:user) }
@@ -1143,7 +1168,7 @@ RSpec.describe Gitlab::Auth, :use_clean_rails_memory_store_caching, feature_cate
private
def expect_results_with_abilities(personal_access_token, abilities, success = true)
- expect(gl_auth.find_for_git_client('', personal_access_token&.token, project: nil, ip: 'ip'))
+ expect(gl_auth.find_for_git_client('', personal_access_token&.token, project: nil, request: request))
.to have_attributes(actor: personal_access_token&.user, project: nil, type: personal_access_token.nil? ? nil : :personal_access_token, authentication_abilities: abilities)
end
end
diff --git a/spec/lib/gitlab/background_migration/backfill_packages_tags_project_id_spec.rb b/spec/lib/gitlab/background_migration/backfill_packages_tags_project_id_spec.rb
new file mode 100644
index 00000000000..423d9fe76ac
--- /dev/null
+++ b/spec/lib/gitlab/background_migration/backfill_packages_tags_project_id_spec.rb
@@ -0,0 +1,42 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::BackgroundMigration::BackfillPackagesTagsProjectId,
+ feature_category: :package_registry,
+ schema: 20231030051837 do # schema before we introduced the invalid not-null constraint
+ let!(:tags_without_project_id) do
+ (0...13).map do |i|
+ namespace = table(:namespaces).create!(name: 'my namespace', path: 'my-namespace')
+ project = table(:projects).create!(name: 'my project', path: 'my-project', namespace_id: namespace.id,
+ project_namespace_id: namespace.id)
+ package = table(:packages_packages).create!(project_id: project.id, created_at: Time.current,
+ updated_at: Time.current, name: "Package #{i}", package_type: 1, status: 1)
+ table(:packages_tags).create!(package_id: package.id, name: "Tag #{i}", created_at: Time.current,
+ updated_at: Time.current, project_id: nil)
+ end
+ end
+
+ let!(:starting_id) { table(:packages_tags).pluck(:id).min }
+ let!(:end_id) { table(:packages_tags).pluck(:id).max }
+
+ let!(:migration) do
+ described_class.new(
+ start_id: starting_id,
+ end_id: end_id,
+ batch_table: :packages_tags,
+ batch_column: :id,
+ sub_batch_size: 10,
+ pause_ms: 2,
+ connection: ::ApplicationRecord.connection
+ )
+ end
+
+ it 'backfills the missing project_id for the batch' do
+ expect do
+ migration.perform
+ end.to change { table(:packages_tags).where(project_id: nil).count }
+ .from(13)
+ .to(0)
+ end
+end
diff --git a/spec/lib/gitlab/background_migration/batched_migration_job_spec.rb b/spec/lib/gitlab/background_migration/batched_migration_job_spec.rb
index 781bf93dd85..da24e9b7978 100644
--- a/spec/lib/gitlab/background_migration/batched_migration_job_spec.rb
+++ b/spec/lib/gitlab/background_migration/batched_migration_job_spec.rb
@@ -2,22 +2,22 @@
require 'spec_helper'
-RSpec.describe Gitlab::BackgroundMigration::BatchedMigrationJob do
+RSpec.describe Gitlab::BackgroundMigration::BatchedMigrationJob, feature_category: :database do
let(:connection) { Gitlab::Database.database_base_models[:main].connection }
describe '.generic_instance' do
it 'defines generic instance with only some of the attributes set' do
generic_instance = described_class.generic_instance(
batch_table: 'projects', batch_column: 'id',
- job_arguments: %w(x y), connection: connection
+ job_arguments: %w[x y], connection: connection
)
expect(generic_instance.send(:batch_table)).to eq('projects')
expect(generic_instance.send(:batch_column)).to eq('id')
- expect(generic_instance.instance_variable_get(:@job_arguments)).to eq(%w(x y))
+ expect(generic_instance.instance_variable_get(:@job_arguments)).to eq(%w[x y])
expect(generic_instance.send(:connection)).to eq(connection)
- %i(start_id end_id sub_batch_size pause_ms).each do |attr|
+ %i[start_id end_id sub_batch_size pause_ms].each do |attr|
expect(generic_instance.send(attr)).to eq(0)
end
end
@@ -31,13 +31,16 @@ RSpec.describe Gitlab::BackgroundMigration::BatchedMigrationJob do
end
subject(:job_instance) do
- job_class.new(start_id: 1, end_id: 10,
- batch_table: '_test_table',
- batch_column: 'id',
- sub_batch_size: 2,
- pause_ms: 1000,
- job_arguments: %w(a b),
- connection: connection)
+ job_class.new(
+ start_id: 1,
+ end_id: 10,
+ batch_table: '_test_table',
+ batch_column: 'id',
+ sub_batch_size: 2,
+ pause_ms: 1000,
+ job_arguments: %w[a b],
+ connection: connection
+ )
end
it 'defines methods' do
@@ -61,13 +64,16 @@ RSpec.describe Gitlab::BackgroundMigration::BatchedMigrationJob do
subject(:perform_job) { job_instance.perform }
let(:job_instance) do
- job_class.new(start_id: 1, end_id: 10,
- batch_table: '_test_table',
- batch_column: 'id',
- sub_batch_size: 2,
- pause_ms: 1000,
- job_arguments: %w(a b),
- connection: connection)
+ job_class.new(
+ start_id: 1,
+ end_id: 10,
+ batch_table: '_test_table',
+ batch_column: 'id',
+ sub_batch_size: 2,
+ pause_ms: 1000,
+ job_arguments: %w[a b],
+ connection: connection
+ )
end
let(:job_class) do
@@ -124,13 +130,16 @@ RSpec.describe Gitlab::BackgroundMigration::BatchedMigrationJob do
describe '.scope_to' do
subject(:job_instance) do
- job_class.new(start_id: 1, end_id: 10,
- batch_table: '_test_table',
- batch_column: 'id',
- sub_batch_size: 2,
- pause_ms: 1000,
- job_arguments: %w(a b),
- connection: connection)
+ job_class.new(
+ start_id: 1,
+ end_id: 10,
+ batch_table: '_test_table',
+ batch_column: 'id',
+ sub_batch_size: 2,
+ pause_ms: 1000,
+ job_arguments: %w[a b],
+ connection: connection
+ )
end
context 'when additional scoping is defined' do
@@ -203,12 +212,15 @@ RSpec.describe Gitlab::BackgroundMigration::BatchedMigrationJob do
let(:job_class) { Class.new(described_class) }
let(:job_instance) do
- job_class.new(start_id: 1, end_id: 10,
- batch_table: '_test_table',
- batch_column: 'id',
- sub_batch_size: 2,
- pause_ms: 1000,
- connection: connection)
+ job_class.new(
+ start_id: 1,
+ end_id: 10,
+ batch_table: '_test_table',
+ batch_column: 'id',
+ sub_batch_size: 2,
+ pause_ms: 1000,
+ connection: connection
+ )
end
subject(:perform_job) { job_instance.perform }
@@ -313,9 +325,16 @@ RSpec.describe Gitlab::BackgroundMigration::BatchedMigrationJob do
end
let(:job_instance) do
- job_class.new(start_id: 1, end_id: 10, batch_table: '_test_table', batch_column: 'id',
- sub_batch_size: 2, pause_ms: 1000, connection: connection,
- sub_batch_exception: StandardError)
+ job_class.new(
+ start_id: 1,
+ end_id: 10,
+ batch_table: '_test_table',
+ batch_column: 'id',
+ sub_batch_size: 2,
+ pause_ms: 1000,
+ connection: connection,
+ sub_batch_exception: StandardError
+ )
end
it 'raises the expected error type' do
@@ -336,13 +355,15 @@ RSpec.describe Gitlab::BackgroundMigration::BatchedMigrationJob do
context 'when the subclass uses distinct each batch' do
let(:job_instance) do
- job_class.new(start_id: 1,
- end_id: 100,
- batch_table: '_test_table',
- batch_column: 'from_column',
- sub_batch_size: 2,
- pause_ms: 10,
- connection: connection)
+ job_class.new(
+ start_id: 1,
+ end_id: 100,
+ batch_table: '_test_table',
+ batch_column: 'from_column',
+ sub_batch_size: 2,
+ pause_ms: 10,
+ connection: connection
+ )
end
let(:job_class) do
diff --git a/spec/lib/gitlab/background_migration/copy_column_using_background_migration_job_spec.rb b/spec/lib/gitlab/background_migration/copy_column_using_background_migration_job_spec.rb
index 9c33100a0b3..a827116a900 100644
--- a/spec/lib/gitlab/background_migration/copy_column_using_background_migration_job_spec.rb
+++ b/spec/lib/gitlab/background_migration/copy_column_using_background_migration_job_spec.rb
@@ -16,16 +16,18 @@ RSpec.describe Gitlab::BackgroundMigration::CopyColumnUsingBackgroundMigrationJo
ActiveRecord::Migration.new.extend(Gitlab::Database::MigrationHelpers)
end
- let(:job_arguments) { %w(name name_convert_to_text) }
+ let(:job_arguments) { %w[name name_convert_to_text] }
let(:copy_job) do
- described_class.new(start_id: 12,
- end_id: 20,
- batch_table: table_name,
- batch_column: 'id',
- sub_batch_size: sub_batch_size,
- pause_ms: pause_ms,
- job_arguments: job_arguments,
- connection: connection)
+ described_class.new(
+ start_id: 12,
+ end_id: 20,
+ batch_table: table_name,
+ batch_column: 'id',
+ sub_batch_size: sub_batch_size,
+ pause_ms: pause_ms,
+ job_arguments: job_arguments,
+ connection: connection
+ )
end
before do
@@ -82,7 +84,7 @@ RSpec.describe Gitlab::BackgroundMigration::CopyColumnUsingBackgroundMigrationJo
end
context 'columns with NULLs' do
- let(:job_arguments) { %w(name name_convert_to_text) }
+ let(:job_arguments) { %w[name name_convert_to_text] }
it 'copies all in range' do
expect { copy_job.perform }
diff --git a/spec/lib/gitlab/background_migration/delete_invalid_protected_branch_merge_access_levels_spec.rb b/spec/lib/gitlab/background_migration/delete_invalid_protected_branch_merge_access_levels_spec.rb
new file mode 100644
index 00000000000..1e5b9d30436
--- /dev/null
+++ b/spec/lib/gitlab/background_migration/delete_invalid_protected_branch_merge_access_levels_spec.rb
@@ -0,0 +1,76 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::BackgroundMigration::DeleteInvalidProtectedBranchMergeAccessLevels,
+ feature_category: :source_code_management do
+ let(:projects_table) { table(:projects) }
+ let(:protected_branches_table) { table(:protected_branches) }
+ let(:namespaces_table) { table(:namespaces) }
+ let(:protected_branch_merge_access_levels_table) { table(:protected_branch_merge_access_levels) }
+ let(:project_group_links_table) { table(:project_group_links) }
+ let(:users_table) { table(:users) }
+
+ let(:user1) { users_table.create!(name: 'user1', email: 'user1@example.com', projects_limit: 5) }
+
+ let(:project_group) { namespaces_table.create!(name: 'group-1', path: 'group-1', type: 'Group') }
+ let(:project_namespace) { namespaces_table.create!(name: 'namespace', path: 'namespace-path-2', type: 'Project') }
+ let!(:project_1) do
+ projects_table
+ .create!(
+ name: 'project1',
+ path: 'path1',
+ namespace_id: project_group.id,
+ project_namespace_id: project_namespace.id,
+ visibility_level: 0
+ )
+ end
+
+ subject(:perform_migration) do
+ described_class.new(start_id: protected_branch_merge_access_levels_table.minimum(:id),
+ end_id: protected_branch_merge_access_levels_table.maximum(:id),
+ batch_table: :protected_branch_merge_access_levels,
+ batch_column: :id,
+ sub_batch_size: 1,
+ pause_ms: 0,
+ connection: ApplicationRecord.connection)
+ .perform
+ end
+
+ context 'when there are merge access levels' do
+ let(:protected_branch1) { protected_branches_table.create!(project_id: project_1.id, name: 'name') }
+ let!(:merge_access_level_for_user) do
+ protected_branch_merge_access_levels_table.create!(
+ protected_branch_id: protected_branch1.id,
+ user_id: user1.id
+ )
+ end
+
+ let(:invited_group) { namespaces_table.create!(name: 'group-2', path: 'group-2', type: 'Group') }
+ let!(:invited_group_link) do
+ project_group_links_table.create!(project_id: project_1.id, group_id: invited_group.id)
+ end
+
+ let!(:merge_access_level_with_linked_group) do
+ protected_branch_merge_access_levels_table.create!(
+ protected_branch_id: protected_branch1.id,
+ group_id: invited_group.id
+ )
+ end
+
+ let!(:merge_access_level_with_unlinked_group) do
+ protected_branch_merge_access_levels_table.create!(
+ protected_branch_id: protected_branch1.id,
+ group_id: project_group.id
+ )
+ end
+
+ it 'deletes merge access levels with groups that do not have project_group_links to the project' do
+ expect { subject }.to change { protected_branch_merge_access_levels_table.count }.from(3).to(2)
+ expect(protected_branch_merge_access_levels_table.all).to contain_exactly(
+ merge_access_level_with_linked_group,
+ merge_access_level_for_user
+ )
+ end
+ end
+end
diff --git a/spec/lib/gitlab/background_migration/delete_invalid_protected_branch_push_access_levels_spec.rb b/spec/lib/gitlab/background_migration/delete_invalid_protected_branch_push_access_levels_spec.rb
new file mode 100644
index 00000000000..62201831dd1
--- /dev/null
+++ b/spec/lib/gitlab/background_migration/delete_invalid_protected_branch_push_access_levels_spec.rb
@@ -0,0 +1,76 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::BackgroundMigration::DeleteInvalidProtectedBranchPushAccessLevels,
+ feature_category: :source_code_management do
+ let(:projects_table) { table(:projects) }
+ let(:protected_branches_table) { table(:protected_branches) }
+ let(:namespaces_table) { table(:namespaces) }
+ let(:protected_branch_push_access_levels_table) { table(:protected_branch_push_access_levels) }
+ let(:project_group_links_table) { table(:project_group_links) }
+ let(:users_table) { table(:users) }
+
+ let(:user1) { users_table.create!(name: 'user1', email: 'user1@example.com', projects_limit: 5) }
+
+ let(:project_group) { namespaces_table.create!(name: 'group-1', path: 'group-1', type: 'Group') }
+ let(:project_namespace) { namespaces_table.create!(name: 'namespace', path: 'namespace-path-2', type: 'Project') }
+ let!(:project_1) do
+ projects_table
+ .create!(
+ name: 'project1',
+ path: 'path1',
+ namespace_id: project_group.id,
+ project_namespace_id: project_namespace.id,
+ visibility_level: 0
+ )
+ end
+
+ subject(:perform_migration) do
+ described_class.new(start_id: protected_branch_push_access_levels_table.minimum(:id),
+ end_id: protected_branch_push_access_levels_table.maximum(:id),
+ batch_table: :protected_branch_push_access_levels,
+ batch_column: :id,
+ sub_batch_size: 1,
+ pause_ms: 0,
+ connection: ApplicationRecord.connection)
+ .perform
+ end
+
+ context 'when there are push access levels' do
+ let(:protected_branch1) { protected_branches_table.create!(project_id: project_1.id, name: 'name') }
+ let!(:push_access_level_for_user) do
+ protected_branch_push_access_levels_table.create!(
+ protected_branch_id: protected_branch1.id,
+ user_id: user1.id
+ )
+ end
+
+ let(:invited_group) { namespaces_table.create!(name: 'group-2', path: 'group-2', type: 'Group') }
+ let!(:invited_group_link) do
+ project_group_links_table.create!(project_id: project_1.id, group_id: invited_group.id)
+ end
+
+ let!(:push_access_level_with_linked_group) do
+ protected_branch_push_access_levels_table.create!(
+ protected_branch_id: protected_branch1.id,
+ group_id: invited_group.id
+ )
+ end
+
+ let!(:push_access_level_with_unlinked_group) do
+ protected_branch_push_access_levels_table.create!(
+ protected_branch_id: protected_branch1.id,
+ group_id: project_group.id
+ )
+ end
+
+ it 'deletes push access levels with groups that do not have project_group_links to the project' do
+ expect { subject }.to change { protected_branch_push_access_levels_table.count }.from(3).to(2)
+ expect(protected_branch_push_access_levels_table.all).to contain_exactly(
+ push_access_level_with_linked_group,
+ push_access_level_for_user
+ )
+ end
+ end
+end
diff --git a/spec/lib/gitlab/background_migration/delete_invalid_protected_tag_create_access_levels_spec.rb b/spec/lib/gitlab/background_migration/delete_invalid_protected_tag_create_access_levels_spec.rb
new file mode 100644
index 00000000000..fd6cee9e4db
--- /dev/null
+++ b/spec/lib/gitlab/background_migration/delete_invalid_protected_tag_create_access_levels_spec.rb
@@ -0,0 +1,76 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::BackgroundMigration::DeleteInvalidProtectedTagCreateAccessLevels,
+ feature_category: :source_code_management do
+ let(:projects_table) { table(:projects) }
+ let(:protected_tags_table) { table(:protected_tags) }
+ let(:namespaces_table) { table(:namespaces) }
+ let(:protected_tag_create_access_levels_table) { table(:protected_tag_create_access_levels) }
+ let(:project_group_links_table) { table(:project_group_links) }
+ let(:users_table) { table(:users) }
+
+ let(:user1) { users_table.create!(name: 'user1', email: 'user1@example.com', projects_limit: 5) }
+
+ let(:project_group) { namespaces_table.create!(name: 'group-1', path: 'group-1', type: 'Group') }
+ let(:project_namespace) { namespaces_table.create!(name: 'namespace', path: 'namespace-path-2', type: 'Project') }
+ let!(:project_1) do
+ projects_table
+ .create!(
+ name: 'project1',
+ path: 'path1',
+ namespace_id: project_group.id,
+ project_namespace_id: project_namespace.id,
+ visibility_level: 0
+ )
+ end
+
+ subject(:perform_migration) do
+ described_class.new(start_id: protected_tag_create_access_levels_table.minimum(:id),
+ end_id: protected_tag_create_access_levels_table.maximum(:id),
+ batch_table: :protected_tag_create_access_levels,
+ batch_column: :id,
+ sub_batch_size: 1,
+ pause_ms: 0,
+ connection: ApplicationRecord.connection)
+ .perform
+ end
+
+ context 'when there are push access levels' do
+ let(:protected_tag) { protected_tags_table.create!(project_id: project_1.id, name: 'name') }
+ let!(:push_access_level_for_user) do
+ protected_tag_create_access_levels_table.create!(
+ protected_tag_id: protected_tag.id,
+ user_id: user1.id
+ )
+ end
+
+ let(:invited_group) { namespaces_table.create!(name: 'group-2', path: 'group-2', type: 'Group') }
+ let!(:invited_group_link) do
+ project_group_links_table.create!(project_id: project_1.id, group_id: invited_group.id)
+ end
+
+ let!(:push_access_level_with_linked_group) do
+ protected_tag_create_access_levels_table.create!(
+ protected_tag_id: protected_tag.id,
+ group_id: invited_group.id
+ )
+ end
+
+ let!(:push_access_level_with_unlinked_group) do
+ protected_tag_create_access_levels_table.create!(
+ protected_tag_id: protected_tag.id,
+ group_id: project_group.id
+ )
+ end
+
+ it 'deletes push access levels with groups that do not have project_group_links to the project' do
+ expect { subject }.to change { protected_tag_create_access_levels_table.count }.from(3).to(2)
+ expect(protected_tag_create_access_levels_table.all).to contain_exactly(
+ push_access_level_with_linked_group,
+ push_access_level_for_user
+ )
+ end
+ end
+end
diff --git a/spec/lib/gitlab/background_migration/delete_orphaned_operational_vulnerabilities_spec.rb b/spec/lib/gitlab/background_migration/delete_orphaned_operational_vulnerabilities_spec.rb
index c03962c8d21..4a1985eeccd 100644
--- a/spec/lib/gitlab/background_migration/delete_orphaned_operational_vulnerabilities_spec.rb
+++ b/spec/lib/gitlab/background_migration/delete_orphaned_operational_vulnerabilities_spec.rb
@@ -87,13 +87,15 @@ RSpec.describe Gitlab::BackgroundMigration::DeleteOrphanedOperationalVulnerabili
end
subject(:background_migration) do
- described_class.new(start_id: vulnerabilities.minimum(:id),
- end_id: vulnerabilities.maximum(:id),
- batch_table: :vulnerabilities,
- batch_column: :id,
- sub_batch_size: 2,
- pause_ms: 0,
- connection: ActiveRecord::Base.connection)
+ described_class.new(
+ start_id: vulnerabilities.minimum(:id),
+ end_id: vulnerabilities.maximum(:id),
+ batch_table: :vulnerabilities,
+ batch_column: :id,
+ sub_batch_size: 2,
+ pause_ms: 0,
+ connection: ActiveRecord::Base.connection
+ )
end
it 'drops Cluster Image Scanning and Custom Vulnerabilities without any Findings' do
diff --git a/spec/lib/gitlab/background_migration/delete_orphans_approval_merge_request_rules_spec.rb b/spec/lib/gitlab/background_migration/delete_orphans_approval_merge_request_rules_spec.rb
index c5b46d3f57c..1ac4d184912 100644
--- a/spec/lib/gitlab/background_migration/delete_orphans_approval_merge_request_rules_spec.rb
+++ b/spec/lib/gitlab/background_migration/delete_orphans_approval_merge_request_rules_spec.rb
@@ -22,9 +22,12 @@ RSpec.describe Gitlab::BackgroundMigration::DeleteOrphansApprovalMergeRequestRul
let(:namespace_2) { namespaces.create!(name: 'name_2', path: 'path_2') }
let(:security_project) do
- projects
- .create!(name: "security_project", path: "security_project", namespace_id: namespace_2.id,
- project_namespace_id: namespace_2.id)
+ projects.create!(
+ name: "security_project",
+ path: "security_project",
+ namespace_id: namespace_2.id,
+ project_namespace_id: namespace_2.id
+ )
end
let!(:security_orchestration_policy_configuration) do
diff --git a/spec/lib/gitlab/background_migration/delete_orphans_approval_project_rules_spec.rb b/spec/lib/gitlab/background_migration/delete_orphans_approval_project_rules_spec.rb
index 16253255764..23026f76001 100644
--- a/spec/lib/gitlab/background_migration/delete_orphans_approval_project_rules_spec.rb
+++ b/spec/lib/gitlab/background_migration/delete_orphans_approval_project_rules_spec.rb
@@ -22,9 +22,12 @@ RSpec.describe Gitlab::BackgroundMigration::DeleteOrphansApprovalProjectRules do
let(:namespace_2) { namespaces.create!(name: 'name_2', path: 'path_2') }
let(:security_project) do
- projects
- .create!(name: "security_project", path: "security_project", namespace_id: namespace_2.id,
- project_namespace_id: namespace_2.id)
+ projects.create!(
+ name: "security_project",
+ path: "security_project",
+ namespace_id: namespace_2.id,
+ project_namespace_id: namespace_2.id
+ )
end
let!(:security_orchestration_policy_configuration) do
diff --git a/spec/lib/gitlab/background_migration/destroy_invalid_group_members_spec.rb b/spec/lib/gitlab/background_migration/destroy_invalid_group_members_spec.rb
index 76a9ea82c76..4e136808a36 100644
--- a/spec/lib/gitlab/background_migration/destroy_invalid_group_members_spec.rb
+++ b/spec/lib/gitlab/background_migration/destroy_invalid_group_members_spec.rb
@@ -76,13 +76,29 @@ RSpec.describe Gitlab::BackgroundMigration::DestroyInvalidGroupMembers, :migrati
end
def create_invalid_group_member(id:, user_id:)
- members_table.create!(id: id, user_id: user_id, source_id: non_existing_record_id, access_level: Gitlab::Access::MAINTAINER,
- type: "GroupMember", source_type: "Namespace", notification_level: 3, member_namespace_id: nil)
+ members_table.create!(
+ id: id,
+ user_id: user_id,
+ source_id: non_existing_record_id,
+ access_level: Gitlab::Access::MAINTAINER,
+ type: "GroupMember",
+ source_type: "Namespace",
+ notification_level: 3,
+ member_namespace_id: nil
+ )
end
def create_valid_group_member(id:, user_id:, group_id:)
- members_table.create!(id: id, user_id: user_id, source_id: group_id, access_level: Gitlab::Access::MAINTAINER,
- type: "GroupMember", source_type: "Namespace", member_namespace_id: group_id, notification_level: 3)
+ members_table.create!(
+ id: id,
+ user_id: user_id,
+ source_id: group_id,
+ access_level: Gitlab::Access::MAINTAINER,
+ type: "GroupMember",
+ source_type: "Namespace",
+ member_namespace_id: group_id,
+ notification_level: 3
+ )
end
# rubocop: enable Layout/LineLength
# rubocop: enable RSpec/ScatteredLet
diff --git a/spec/lib/gitlab/background_migration/destroy_invalid_members_spec.rb b/spec/lib/gitlab/background_migration/destroy_invalid_members_spec.rb
index 5059ad620aa..e5965d4a1d8 100644
--- a/spec/lib/gitlab/background_migration/destroy_invalid_members_spec.rb
+++ b/spec/lib/gitlab/background_migration/destroy_invalid_members_spec.rb
@@ -33,23 +33,39 @@ RSpec.describe Gitlab::BackgroundMigration::DestroyInvalidMembers, :migration, s
let!(:group1) { namespaces_table.create!(name: 'marvellous group 1', path: 'group-path-1', type: 'Group') }
let!(:group2) { namespaces_table.create!(name: 'outstanding group 2', path: 'group-path-2', type: 'Group') }
let!(:project_namespace1) do
- namespaces_table.create!(name: 'fabulous project', path: 'project-path-1',
- type: 'ProjectNamespace', parent_id: group1.id)
+ namespaces_table.create!(
+ name: 'fabulous project',
+ path: 'project-path-1',
+ type: 'ProjectNamespace',
+ parent_id: group1.id
+ )
end
let!(:project1) do
- projects_table.create!(name: 'fabulous project', path: 'project-path-1',
- project_namespace_id: project_namespace1.id, namespace_id: group1.id)
+ projects_table.create!(
+ name: 'fabulous project',
+ path: 'project-path-1',
+ project_namespace_id: project_namespace1.id,
+ namespace_id: group1.id
+ )
end
let!(:project_namespace2) do
- namespaces_table.create!(name: 'splendiferous project', path: 'project-path-2',
- type: 'ProjectNamespace', parent_id: group1.id)
+ namespaces_table.create!(
+ name: 'splendiferous project',
+ path: 'project-path-2',
+ type: 'ProjectNamespace',
+ parent_id: group1.id
+ )
end
let!(:project2) do
- projects_table.create!(name: 'splendiferous project', path: 'project-path-2',
- project_namespace_id: project_namespace2.id, namespace_id: group1.id)
+ projects_table.create!(
+ name: 'splendiferous project',
+ path: 'project-path-2',
+ project_namespace_id: project_namespace2.id,
+ namespace_id: group1.id
+ )
end
# create valid project member records
@@ -115,27 +131,55 @@ RSpec.describe Gitlab::BackgroundMigration::DestroyInvalidMembers, :migration, s
end
def create_invalid_project_member(id:, user_id:)
- members_table.create!(id: id, user_id: user_id, source_id: non_existing_record_id,
- access_level: Gitlab::Access::MAINTAINER, type: "ProjectMember",
- source_type: "Project", notification_level: 3, member_namespace_id: nil)
+ members_table.create!(
+ id: id,
+ user_id: user_id,
+ source_id: non_existing_record_id,
+ access_level: Gitlab::Access::MAINTAINER,
+ type: "ProjectMember",
+ source_type: "Project",
+ notification_level: 3,
+ member_namespace_id: nil
+ )
end
def create_valid_project_member(id:, user_id:, project:)
- members_table.create!(id: id, user_id: user_id, source_id: project.id,
- access_level: Gitlab::Access::MAINTAINER, type: "ProjectMember", source_type: "Project",
- member_namespace_id: project.project_namespace_id, notification_level: 3)
+ members_table.create!(
+ id: id,
+ user_id: user_id,
+ source_id: project.id,
+ access_level: Gitlab::Access::MAINTAINER,
+ type: "ProjectMember",
+ source_type: "Project",
+ member_namespace_id: project.project_namespace_id,
+ notification_level: 3
+ )
end
def create_invalid_group_member(id:, user_id:)
- members_table.create!(id: id, user_id: user_id, source_id: non_existing_record_id,
- access_level: Gitlab::Access::MAINTAINER, type: "GroupMember",
- source_type: "Namespace", notification_level: 3, member_namespace_id: nil)
+ members_table.create!(
+ id: id,
+ user_id: user_id,
+ source_id: non_existing_record_id,
+ access_level: Gitlab::Access::MAINTAINER,
+ type: "GroupMember",
+ source_type: "Namespace",
+ notification_level: 3,
+ member_namespace_id: nil
+ )
end
def create_valid_group_member(id:, user_id:, group_id:)
- members_table.create!(id: id, user_id: user_id, source_id: group_id,
- access_level: Gitlab::Access::MAINTAINER, type: "GroupMember",
- source_type: "Namespace", member_namespace_id: group_id, notification_level: 3)
+ members_table.create!(
+ id: id,
+ user_id: user_id,
+ source_id: group_id,
+ access_level: Gitlab::Access::MAINTAINER,
+ type: "GroupMember",
+ source_type: "Namespace",
+ member_namespace_id: group_id,
+ notification_level: 3
+ )
end
end
# rubocop: enable RSpec/MultipleMemoizedHelpers
diff --git a/spec/lib/gitlab/background_migration/destroy_invalid_project_members_spec.rb b/spec/lib/gitlab/background_migration/destroy_invalid_project_members_spec.rb
index 029a6adf831..090c31049b4 100644
--- a/spec/lib/gitlab/background_migration/destroy_invalid_project_members_spec.rb
+++ b/spec/lib/gitlab/background_migration/destroy_invalid_project_members_spec.rb
@@ -3,7 +3,6 @@
require 'spec_helper'
RSpec.describe Gitlab::BackgroundMigration::DestroyInvalidProjectMembers, :migration, schema: 20220901035725 do
- # rubocop: disable Layout/LineLength
# rubocop: disable RSpec/ScatteredLet
let!(:migration_attrs) do
{
@@ -36,23 +35,33 @@ RSpec.describe Gitlab::BackgroundMigration::DestroyInvalidProjectMembers, :migra
let!(:group1) { namespaces_table.create!(name: 'marvellous group 1', path: 'group-path-1', type: 'Group') }
let!(:project_namespace1) do
- namespaces_table.create!(name: 'fabulous project', path: 'project-path-1', type: 'ProjectNamespace',
- parent_id: group1.id)
+ namespaces_table.create!(
+ name: 'fabulous project', path: 'project-path-1', type: 'ProjectNamespace', parent_id: group1.id
+ )
end
let!(:project1) do
- projects_table.create!(name: 'fabulous project', path: 'project-path-1', project_namespace_id: project_namespace1.id,
- namespace_id: group1.id)
+ projects_table.create!(
+ name: 'fabulous project',
+ path: 'project-path-1',
+ project_namespace_id: project_namespace1.id,
+ namespace_id: group1.id
+ )
end
let!(:project_namespace2) do
- namespaces_table.create!(name: 'splendiferous project', path: 'project-path-2', type: 'ProjectNamespace',
- parent_id: group1.id)
+ namespaces_table.create!(
+ name: 'splendiferous project', path: 'project-path-2', type: 'ProjectNamespace', parent_id: group1.id
+ )
end
let!(:project2) do
- projects_table.create!(name: 'splendiferous project', path: 'project-path-2', project_namespace_id: project_namespace2.id,
- namespace_id: group1.id)
+ projects_table.create!(
+ name: 'splendiferous project',
+ path: 'project-path-2',
+ project_namespace_id: project_namespace2.id,
+ namespace_id: group1.id
+ )
end
# create project member records, a mix of both valid and invalid
@@ -72,7 +81,8 @@ RSpec.describe Gitlab::BackgroundMigration::DestroyInvalidProjectMembers, :migra
end
expect(queries.count).to eq(4)
- expect(members_table.where(type: 'ProjectMember')).to match_array([project_member2, project_member3, project_member5])
+ expect(members_table.where(type: 'ProjectMember'))
+ .to match_array([project_member2, project_member3, project_member5])
end
it 'tracks timings of queries' do
@@ -82,21 +92,33 @@ RSpec.describe Gitlab::BackgroundMigration::DestroyInvalidProjectMembers, :migra
end
it 'logs IDs of deleted records' do
- expect(Gitlab::AppLogger).to receive(:info).with({ message: 'Removing invalid project member records',
- deleted_count: 3, ids: [project_member1, project_member4, project_member6].map(&:id) })
+ expect(Gitlab::AppLogger).to receive(:info).with({
+ message: 'Removing invalid project member records',
+ deleted_count: 3,
+ ids: [project_member1, project_member4, project_member6].map(&:id)
+ })
perform_migration
end
def create_invalid_project_member(id:, user_id:)
- members_table.create!(id: id, user_id: user_id, source_id: non_existing_record_id, access_level: Gitlab::Access::MAINTAINER,
- type: "ProjectMember", source_type: "Project", notification_level: 3, member_namespace_id: nil)
+ members_table.create!(
+ id: id, user_id: user_id, source_id: non_existing_record_id, access_level: Gitlab::Access::MAINTAINER,
+ type: "ProjectMember", source_type: "Project", notification_level: 3, member_namespace_id: nil
+ )
end
def create_valid_project_member(id:, user_id:, project:)
- members_table.create!(id: id, user_id: user_id, source_id: project.id, access_level: Gitlab::Access::MAINTAINER,
- type: "ProjectMember", source_type: "Project", member_namespace_id: project.project_namespace_id, notification_level: 3)
+ members_table.create!(
+ id: id,
+ user_id: user_id,
+ source_id: project.id,
+ access_level: Gitlab::Access::MAINTAINER,
+ type: "ProjectMember",
+ source_type: "Project",
+ member_namespace_id: project.project_namespace_id,
+ notification_level: 3
+ )
end
- # rubocop: enable Layout/LineLength
# rubocop: enable RSpec/ScatteredLet
end
diff --git a/spec/lib/gitlab/background_migration/disable_legacy_open_source_licence_for_recent_public_projects_spec.rb b/spec/lib/gitlab/background_migration/disable_legacy_open_source_licence_for_recent_public_projects_spec.rb
index 7edba8cf524..740a90e0494 100644
--- a/spec/lib/gitlab/background_migration/disable_legacy_open_source_licence_for_recent_public_projects_spec.rb
+++ b/spec/lib/gitlab/background_migration/disable_legacy_open_source_licence_for_recent_public_projects_spec.rb
@@ -73,14 +73,15 @@ RSpec.describe Gitlab::BackgroundMigration::DisableLegacyOpenSourceLicenceForRec
let(:project_settings_table) { table(:project_settings) }
subject(:perform_migration) do
- described_class.new(start_id: projects_table.minimum(:id),
- end_id: projects_table.maximum(:id),
- batch_table: :projects,
- batch_column: :id,
- sub_batch_size: 2,
- pause_ms: 0,
- connection: ActiveRecord::Base.connection)
- .perform
+ described_class.new(
+ start_id: projects_table.minimum(:id),
+ end_id: projects_table.maximum(:id),
+ batch_table: :projects,
+ batch_column: :id,
+ sub_batch_size: 2,
+ pause_ms: 0,
+ connection: ActiveRecord::Base.connection
+ ).perform
end
before do
@@ -94,7 +95,7 @@ RSpec.describe Gitlab::BackgroundMigration::DisableLegacyOpenSourceLicenceForRec
end
it 'sets `legacy_open_source_license_available` attribute to false for public projects created after threshold time',
- :aggregate_failures do
+ :aggregate_failures do
record = ActiveRecord::QueryRecorder.new do
expect { perform_migration }
.to not_change { migrated_attribute(project_1.id) }.from(true)
diff --git a/spec/lib/gitlab/background_migration/disable_legacy_open_source_license_for_inactive_public_projects_spec.rb b/spec/lib/gitlab/background_migration/disable_legacy_open_source_license_for_inactive_public_projects_spec.rb
index f5a2dc91185..953eb09032f 100644
--- a/spec/lib/gitlab/background_migration/disable_legacy_open_source_license_for_inactive_public_projects_spec.rb
+++ b/spec/lib/gitlab/background_migration/disable_legacy_open_source_license_for_inactive_public_projects_spec.rb
@@ -8,14 +8,15 @@ RSpec.describe Gitlab::BackgroundMigration::DisableLegacyOpenSourceLicenseForIna
let(:project_settings_table) { table(:project_settings) }
subject(:perform_migration) do
- described_class.new(start_id: projects_table.minimum(:id),
- end_id: projects_table.maximum(:id),
- batch_table: :projects,
- batch_column: :id,
- sub_batch_size: 2,
- pause_ms: 0,
- connection: ActiveRecord::Base.connection)
- .perform
+ described_class.new(
+ start_id: projects_table.minimum(:id),
+ end_id: projects_table.maximum(:id),
+ batch_table: :projects,
+ batch_column: :id,
+ sub_batch_size: 2,
+ pause_ms: 0,
+ connection: ActiveRecord::Base.connection
+ ).perform
end
let(:queries) { ActiveRecord::QueryRecorder.new { perform_migration } }
@@ -27,32 +28,28 @@ RSpec.describe Gitlab::BackgroundMigration::DisableLegacyOpenSourceLicenseForIna
let(:project_namespace_5) { namespaces_table.create!(name: 'namespace', path: 'namespace-path-5', type: 'Project') }
let(:project_1) do
- projects_table
- .create!(
+ projects_table.create!(
name: 'proj-1', path: 'path-1', namespace_id: namespace_1.id,
project_namespace_id: project_namespace_2.id, visibility_level: 0
)
end
let(:project_2) do
- projects_table
- .create!(
+ projects_table.create!(
name: 'proj-2', path: 'path-2', namespace_id: namespace_1.id,
project_namespace_id: project_namespace_3.id, visibility_level: 10
)
end
let(:project_3) do
- projects_table
- .create!(
+ projects_table.create!(
name: 'proj-3', path: 'path-3', namespace_id: namespace_1.id,
project_namespace_id: project_namespace_4.id, visibility_level: 20, last_activity_at: '2021-01-01'
)
end
let(:project_4) do
- projects_table
- .create!(
+ projects_table.create!(
name: 'proj-4', path: 'path-4', namespace_id: namespace_1.id,
project_namespace_id: project_namespace_5.id, visibility_level: 20, last_activity_at: '2022-01-01'
)
@@ -66,7 +63,7 @@ RSpec.describe Gitlab::BackgroundMigration::DisableLegacyOpenSourceLicenseForIna
end
it 'sets `legacy_open_source_license_available` attribute to false for inactive, public projects',
- :aggregate_failures do
+ :aggregate_failures do
expect(queries.count).to eq(5)
expect(migrated_attribute(project_1.id)).to be_truthy
diff --git a/spec/lib/gitlab/background_migration/disable_legacy_open_source_license_for_no_issues_no_repo_projects_spec.rb b/spec/lib/gitlab/background_migration/disable_legacy_open_source_license_for_no_issues_no_repo_projects_spec.rb
index d60874c3159..93913a2742b 100644
--- a/spec/lib/gitlab/background_migration/disable_legacy_open_source_license_for_no_issues_no_repo_projects_spec.rb
+++ b/spec/lib/gitlab/background_migration/disable_legacy_open_source_license_for_no_issues_no_repo_projects_spec.rb
@@ -3,8 +3,8 @@
require 'spec_helper'
RSpec.describe Gitlab::BackgroundMigration::DisableLegacyOpenSourceLicenseForNoIssuesNoRepoProjects,
- :migration,
- schema: 20220722084543 do
+ :migration,
+ schema: 20220722084543 do
let(:namespaces_table) { table(:namespaces) }
let(:projects_table) { table(:projects) }
let(:project_settings_table) { table(:project_settings) }
@@ -12,18 +12,19 @@ RSpec.describe Gitlab::BackgroundMigration::DisableLegacyOpenSourceLicenseForNoI
let(:issues_table) { table(:issues) }
subject(:perform_migration) do
- described_class.new(start_id: projects_table.minimum(:id),
- end_id: projects_table.maximum(:id),
- batch_table: :projects,
- batch_column: :id,
- sub_batch_size: 2,
- pause_ms: 0,
- connection: ActiveRecord::Base.connection)
- .perform
+ described_class.new(
+ start_id: projects_table.minimum(:id),
+ end_id: projects_table.maximum(:id),
+ batch_table: :projects,
+ batch_column: :id,
+ sub_batch_size: 2,
+ pause_ms: 0,
+ connection: ActiveRecord::Base.connection
+ ).perform
end
it 'sets `legacy_open_source_license_available` to false only for public projects with no issues and no repo',
- :aggregate_failures do
+ :aggregate_failures do
project_with_no_issues_no_repo = create_legacy_license_public_project('project-with-no-issues-no-repo')
project_with_repo = create_legacy_license_public_project('project-with-repo', repo_size: 1)
project_with_issues = create_legacy_license_public_project('project-with-issues', with_issue: true)
@@ -41,13 +42,13 @@ RSpec.describe Gitlab::BackgroundMigration::DisableLegacyOpenSourceLicenseForNoI
def create_legacy_license_public_project(path, repo_size: 0, with_issue: false)
namespace = namespaces_table.create!(name: "namespace-#{path}", path: "namespace-#{path}")
- project_namespace =
- namespaces_table.create!(name: "-project-namespace-#{path}", path: "project-namespace-#{path}", type: 'Project')
- project = projects_table
- .create!(
- name: path, path: path, namespace_id: namespace.id,
- project_namespace_id: project_namespace.id, visibility_level: 20
- )
+ project_namespace = namespaces_table.create!(
+ name: "-project-namespace-#{path}", path: "project-namespace-#{path}", type: 'Project'
+ )
+ project = projects_table.create!(
+ name: path, path: path, namespace_id: namespace.id,
+ project_namespace_id: project_namespace.id, visibility_level: 20
+ )
project_statistics_table.create!(project_id: project.id, namespace_id: namespace.id, repository_size: repo_size)
issues_table.create!(project_id: project.id, namespace_id: project.project_namespace_id) if with_issue
diff --git a/spec/lib/gitlab/background_migration/disable_legacy_open_source_license_for_one_member_no_repo_projects_spec.rb b/spec/lib/gitlab/background_migration/disable_legacy_open_source_license_for_one_member_no_repo_projects_spec.rb
index 0dba1d7c8a2..285e5ebbee2 100644
--- a/spec/lib/gitlab/background_migration/disable_legacy_open_source_license_for_one_member_no_repo_projects_spec.rb
+++ b/spec/lib/gitlab/background_migration/disable_legacy_open_source_license_for_one_member_no_repo_projects_spec.rb
@@ -3,8 +3,8 @@
require 'spec_helper'
RSpec.describe Gitlab::BackgroundMigration::DisableLegacyOpenSourceLicenseForOneMemberNoRepoProjects,
- :migration,
- schema: 20220721031446 do
+ :migration,
+ schema: 20220721031446 do
let(:namespaces_table) { table(:namespaces) }
let(:projects_table) { table(:projects) }
let(:project_settings_table) { table(:project_settings) }
@@ -13,18 +13,19 @@ RSpec.describe Gitlab::BackgroundMigration::DisableLegacyOpenSourceLicenseForOne
let(:project_authorizations_table) { table(:project_authorizations) }
subject(:perform_migration) do
- described_class.new(start_id: projects_table.minimum(:id),
- end_id: projects_table.maximum(:id),
- batch_table: :projects,
- batch_column: :id,
- sub_batch_size: 2,
- pause_ms: 0,
- connection: ActiveRecord::Base.connection)
- .perform
+ described_class.new(
+ start_id: projects_table.minimum(:id),
+ end_id: projects_table.maximum(:id),
+ batch_table: :projects,
+ batch_column: :id,
+ sub_batch_size: 2,
+ pause_ms: 0,
+ connection: ActiveRecord::Base.connection
+ ).perform
end
it 'sets `legacy_open_source_license_available` to false only for public projects with 1 member and no repo',
- :aggregate_failures do
+ :aggregate_failures do
project_with_no_repo_one_member = create_legacy_license_public_project('project-with-one-member-no-repo')
project_with_repo_one_member = create_legacy_license_public_project('project-with-repo', repo_size: 1)
project_with_no_repo_two_members = create_legacy_license_public_project('project-with-two-members', members: 2)
@@ -42,13 +43,13 @@ RSpec.describe Gitlab::BackgroundMigration::DisableLegacyOpenSourceLicenseForOne
def create_legacy_license_public_project(path, repo_size: 0, members: 1)
namespace = namespaces_table.create!(name: "namespace-#{path}", path: "namespace-#{path}")
- project_namespace =
- namespaces_table.create!(name: "-project-namespace-#{path}", path: "project-namespace-#{path}", type: 'Project')
- project = projects_table
- .create!(
- name: path, path: path, namespace_id: namespace.id,
- project_namespace_id: project_namespace.id, visibility_level: 20
- )
+ project_namespace = namespaces_table.create!(
+ name: "-project-namespace-#{path}", path: "project-namespace-#{path}", type: 'Project'
+ )
+ project = projects_table.create!(
+ name: path, path: path, namespace_id: namespace.id,
+ project_namespace_id: project_namespace.id, visibility_level: 20
+ )
members.times do |member_id|
user = users_table.create!(email: "user#{member_id}-project-#{project.id}@gitlab.com", projects_limit: 100)
diff --git a/spec/lib/gitlab/background_migration/disable_legacy_open_source_license_for_projects_less_than_five_mb_spec.rb b/spec/lib/gitlab/background_migration/disable_legacy_open_source_license_for_projects_less_than_five_mb_spec.rb
index a153507837c..fedee9c5068 100644
--- a/spec/lib/gitlab/background_migration/disable_legacy_open_source_license_for_projects_less_than_five_mb_spec.rb
+++ b/spec/lib/gitlab/background_migration/disable_legacy_open_source_license_for_projects_less_than_five_mb_spec.rb
@@ -3,23 +3,24 @@
require 'spec_helper'
RSpec.describe Gitlab::BackgroundMigration::DisableLegacyOpenSourceLicenseForProjectsLessThanFiveMb,
- :migration,
- schema: 20221018095434,
- feature_category: :groups_and_projects do
+ :migration,
+ schema: 20221018095434,
+ feature_category: :groups_and_projects do
let(:namespaces_table) { table(:namespaces) }
let(:projects_table) { table(:projects) }
let(:project_settings_table) { table(:project_settings) }
let(:project_statistics_table) { table(:project_statistics) }
subject(:perform_migration) do
- described_class.new(start_id: project_settings_table.minimum(:project_id),
- end_id: project_settings_table.maximum(:project_id),
- batch_table: :project_settings,
- batch_column: :project_id,
- sub_batch_size: 2,
- pause_ms: 0,
- connection: ActiveRecord::Base.connection)
- .perform
+ described_class.new(
+ start_id: project_settings_table.minimum(:project_id),
+ end_id: project_settings_table.maximum(:project_id),
+ batch_table: :project_settings,
+ batch_column: :project_id,
+ sub_batch_size: 2,
+ pause_ms: 0,
+ connection: ActiveRecord::Base.connection
+ ).perform
end
it 'sets `legacy_open_source_license_available` to false only for projects less than 5 MiB', :aggregate_failures do
@@ -45,10 +46,12 @@ RSpec.describe Gitlab::BackgroundMigration::DisableLegacyOpenSourceLicenseForPro
def create_legacy_license_project_setting(repo_size:)
path = "path-for-repo-size-#{repo_size}"
namespace = namespaces_table.create!(name: "namespace-#{path}", path: "namespace-#{path}")
- project_namespace =
- namespaces_table.create!(name: "-project-namespace-#{path}", path: "project-namespace-#{path}", type: 'Project')
- project = projects_table
- .create!(name: path, path: path, namespace_id: namespace.id, project_namespace_id: project_namespace.id)
+ project_namespace = namespaces_table.create!(
+ name: "-project-namespace-#{path}", path: "project-namespace-#{path}", type: 'Project'
+ )
+ project = projects_table.create!(
+ name: path, path: path, namespace_id: namespace.id, project_namespace_id: project_namespace.id
+ )
size_in_bytes = 1.megabyte * repo_size
project_statistics_table.create!(project_id: project.id, namespace_id: namespace.id, repository_size: size_in_bytes)
diff --git a/spec/lib/gitlab/background_migration/disable_legacy_open_source_license_for_projects_less_than_one_mb_spec.rb b/spec/lib/gitlab/background_migration/disable_legacy_open_source_license_for_projects_less_than_one_mb_spec.rb
index 2e6bc2f77ae..cf544c87b31 100644
--- a/spec/lib/gitlab/background_migration/disable_legacy_open_source_license_for_projects_less_than_one_mb_spec.rb
+++ b/spec/lib/gitlab/background_migration/disable_legacy_open_source_license_for_projects_less_than_one_mb_spec.rb
@@ -3,26 +3,27 @@
require 'spec_helper'
RSpec.describe Gitlab::BackgroundMigration::DisableLegacyOpenSourceLicenseForProjectsLessThanOneMb,
- :migration,
- schema: 20220906074449 do
+ :migration,
+ schema: 20220906074449 do
let(:namespaces_table) { table(:namespaces) }
let(:projects_table) { table(:projects) }
let(:project_settings_table) { table(:project_settings) }
let(:project_statistics_table) { table(:project_statistics) }
subject(:perform_migration) do
- described_class.new(start_id: project_settings_table.minimum(:project_id),
- end_id: project_settings_table.maximum(:project_id),
- batch_table: :project_settings,
- batch_column: :project_id,
- sub_batch_size: 2,
- pause_ms: 0,
- connection: ActiveRecord::Base.connection)
- .perform
+ described_class.new(
+ start_id: project_settings_table.minimum(:project_id),
+ end_id: project_settings_table.maximum(:project_id),
+ batch_table: :project_settings,
+ batch_column: :project_id,
+ sub_batch_size: 2,
+ pause_ms: 0,
+ connection: ActiveRecord::Base.connection
+ ).perform
end
it 'sets `legacy_open_source_license_available` to false only for projects less than 1 MiB',
- :aggregate_failures do
+ :aggregate_failures do
project_setting_1_mb = create_legacy_license_project_setting(repo_size: 1)
project_setting_2_mb = create_legacy_license_project_setting(repo_size: 2)
project_setting_quarter_mb = create_legacy_license_project_setting(repo_size: 0.25)
@@ -43,10 +44,12 @@ RSpec.describe Gitlab::BackgroundMigration::DisableLegacyOpenSourceLicenseForPro
def create_legacy_license_project_setting(repo_size:)
path = "path-for-repo-size-#{repo_size}"
namespace = namespaces_table.create!(name: "namespace-#{path}", path: "namespace-#{path}")
- project_namespace =
- namespaces_table.create!(name: "-project-namespace-#{path}", path: "project-namespace-#{path}", type: 'Project')
- project = projects_table
- .create!(name: path, path: path, namespace_id: namespace.id, project_namespace_id: project_namespace.id)
+ project_namespace = namespaces_table.create!(
+ name: "-project-namespace-#{path}", path: "project-namespace-#{path}", type: 'Project'
+ )
+ project = projects_table.create!(
+ name: path, path: path, namespace_id: namespace.id, project_namespace_id: project_namespace.id
+ )
size_in_bytes = 1.megabyte * repo_size
project_statistics_table.create!(project_id: project.id, namespace_id: namespace.id, repository_size: size_in_bytes)
diff --git a/spec/lib/gitlab/background_migration/expire_o_auth_tokens_spec.rb b/spec/lib/gitlab/background_migration/expire_o_auth_tokens_spec.rb
index cffcda0a2ca..ba3aab03f2a 100644
--- a/spec/lib/gitlab/background_migration/expire_o_auth_tokens_spec.rb
+++ b/spec/lib/gitlab/background_migration/expire_o_auth_tokens_spec.rb
@@ -9,14 +9,15 @@ RSpec.describe Gitlab::BackgroundMigration::ExpireOAuthTokens, :migration, schem
let(:table_name) { 'oauth_access_tokens' }
subject(:perform_migration) do
- described_class.new(start_id: 1,
- end_id: 30,
- batch_table: :oauth_access_tokens,
- batch_column: :id,
- sub_batch_size: 2,
- pause_ms: 0,
- connection: ActiveRecord::Base.connection)
- .perform
+ described_class.new(
+ start_id: 1,
+ end_id: 30,
+ batch_table: :oauth_access_tokens,
+ batch_column: :id,
+ sub_batch_size: 2,
+ pause_ms: 0,
+ connection: ActiveRecord::Base.connection
+ ).perform
end
before do
diff --git a/spec/lib/gitlab/background_migration/fix_incoherent_packages_size_on_project_statistics_spec.rb b/spec/lib/gitlab/background_migration/fix_incoherent_packages_size_on_project_statistics_spec.rb
index f71b54a7eb4..2a53d39b6b1 100644
--- a/spec/lib/gitlab/background_migration/fix_incoherent_packages_size_on_project_statistics_spec.rb
+++ b/spec/lib/gitlab/background_migration/fix_incoherent_packages_size_on_project_statistics_spec.rb
@@ -4,7 +4,7 @@ require 'spec_helper'
# rubocop: disable RSpec/MultipleMemoizedHelpers
RSpec.describe Gitlab::BackgroundMigration::FixIncoherentPackagesSizeOnProjectStatistics,
- feature_category: :package_registry do
+ feature_category: :package_registry do
let(:project_statistics_table) { table(:project_statistics) }
let(:packages_table) { table(:packages_packages) }
let(:package_files_table) { table(:packages_package_files) }
@@ -197,8 +197,8 @@ RSpec.describe Gitlab::BackgroundMigration::FixIncoherentPackagesSizeOnProjectSt
context 'with incoherent packages_size' do
it_behaves_like 'enqueuing a buffered updates',
- incoherent_non_zero_statistics: 195,
- incoherent_zero_statistics: 200
+ incoherent_non_zero_statistics: 195,
+ incoherent_zero_statistics: 200
context 'with updates waiting on redis' do
before do
@@ -207,8 +207,8 @@ RSpec.describe Gitlab::BackgroundMigration::FixIncoherentPackagesSizeOnProjectSt
end
it_behaves_like 'enqueuing a buffered updates',
- incoherent_non_zero_statistics: 195,
- incoherent_zero_statistics: 200
+ incoherent_non_zero_statistics: 195,
+ incoherent_zero_statistics: 200
end
end
diff --git a/spec/lib/gitlab/background_migration/legacy_upload_mover_spec.rb b/spec/lib/gitlab/background_migration/legacy_upload_mover_spec.rb
index 71e9a568370..f4c5cd79863 100644
--- a/spec/lib/gitlab/background_migration/legacy_upload_mover_spec.rb
+++ b/spec/lib/gitlab/background_migration/legacy_upload_mover_spec.rb
@@ -18,9 +18,14 @@ RSpec.describe Gitlab::BackgroundMigration::LegacyUploadMover, :aggregate_failur
let(:legacy_upload) { create_upload(note, filename) }
def create_remote_upload(model, filename)
- create(:upload, :attachment_upload,
- path: "note/attachment/#{model.id}/#{filename}", secret: nil,
- store: ObjectStorage::Store::REMOTE, model: model)
+ create(
+ :upload,
+ :attachment_upload,
+ path: "note/attachment/#{model.id}/#{filename}",
+ secret: nil,
+ store: ObjectStorage::Store::REMOTE,
+ model: model
+ )
end
def create_upload(model, filename, with_file = true)
@@ -147,14 +152,23 @@ RSpec.describe Gitlab::BackgroundMigration::LegacyUploadMover, :aggregate_failur
end
let(:legacy_upload) do
- create(:upload, :with_file, :attachment_upload,
- path: "uploads/-/system/note/attachment/#{note.id}/#{filename}", model: note)
+ create(
+ :upload,
+ :with_file,
+ :attachment_upload,
+ path: "uploads/-/system/note/attachment/#{note.id}/#{filename}",
+ model: note
+ )
end
context 'when the file does not exist for the upload' do
let(:legacy_upload) do
- create(:upload, :attachment_upload,
- path: "uploads/-/system/note/attachment/#{note.id}/#{filename}", model: note)
+ create(
+ :upload,
+ :attachment_upload,
+ path: "uploads/-/system/note/attachment/#{note.id}/#{filename}",
+ model: note
+ )
end
it_behaves_like 'move error'
@@ -162,8 +176,13 @@ RSpec.describe Gitlab::BackgroundMigration::LegacyUploadMover, :aggregate_failur
context 'when the file does not exist on expected path' do
let(:legacy_upload) do
- create(:upload, :attachment_upload, :with_file,
- path: "uploads/-/system/note/attachment/some_part/#{note.id}/#{filename}", model: note)
+ create(
+ :upload,
+ :attachment_upload,
+ :with_file,
+ path: "uploads/-/system/note/attachment/some_part/#{note.id}/#{filename}",
+ model: note
+ )
end
it_behaves_like 'move error'
@@ -171,8 +190,13 @@ RSpec.describe Gitlab::BackgroundMigration::LegacyUploadMover, :aggregate_failur
context 'when the file path does not include system/note/attachment' do
let(:legacy_upload) do
- create(:upload, :attachment_upload, :with_file,
- path: "uploads/-/system#{note.id}/#{filename}", model: note)
+ create(
+ :upload,
+ :attachment_upload,
+ :with_file,
+ path: "uploads/-/system#{note.id}/#{filename}",
+ model: note
+ )
end
it_behaves_like 'move error'
@@ -188,8 +212,14 @@ RSpec.describe Gitlab::BackgroundMigration::LegacyUploadMover, :aggregate_failur
context 'when upload has mount_point nil' do
let(:legacy_upload) do
- create(:upload, :with_file, :attachment_upload,
- path: "uploads/-/system/note/attachment/#{note.id}/#{filename}", model: note, mount_point: nil)
+ create(
+ :upload,
+ :with_file,
+ :attachment_upload,
+ path: "uploads/-/system/note/attachment/#{note.id}/#{filename}",
+ model: note,
+ mount_point: nil
+ )
end
it_behaves_like 'migrates the file correctly', false
diff --git a/spec/lib/gitlab/background_migration/remove_backfilled_job_artifacts_expire_at_spec.rb b/spec/lib/gitlab/background_migration/remove_backfilled_job_artifacts_expire_at_spec.rb
index af8b5240e40..4c989ba9cef 100644
--- a/spec/lib/gitlab/background_migration/remove_backfilled_job_artifacts_expire_at_spec.rb
+++ b/spec/lib/gitlab/background_migration/remove_backfilled_job_artifacts_expire_at_spec.rb
@@ -7,7 +7,7 @@ RSpec.describe Gitlab::BackgroundMigration::RemoveBackfilledJobArtifactsExpireAt
describe '#perform' do
let(:job_artifact) { table(:ci_job_artifacts, database: :ci) }
- let(:jobs) { table(:ci_builds, database: :ci) { |model| model.primary_key = :id } }
+ let(:jobs) { table(:p_ci_builds, database: :ci) { |model| model.primary_key = :id } }
let(:test_worker) do
described_class.new(
diff --git a/spec/lib/gitlab/batch_worker_context_spec.rb b/spec/lib/gitlab/batch_worker_context_spec.rb
index 31641f7449e..a0a5bf0cba1 100644
--- a/spec/lib/gitlab/batch_worker_context_spec.rb
+++ b/spec/lib/gitlab/batch_worker_context_spec.rb
@@ -5,7 +5,7 @@ require 'spec_helper'
RSpec.describe Gitlab::BatchWorkerContext do
subject(:batch_context) do
described_class.new(
- %w(hello world),
+ %w[hello world],
arguments_proc: -> (word) { word },
context_proc: -> (word) { { user: build_stubbed(:user, username: word) } }
)
@@ -13,13 +13,13 @@ RSpec.describe Gitlab::BatchWorkerContext do
describe "#arguments" do
it "returns all the expected arguments in arrays" do
- expect(batch_context.arguments).to eq([%w(hello), %w(world)])
+ expect(batch_context.arguments).to eq([%w[hello], %w[world]])
end
end
describe "#context_for" do
it "returns the correct application context for the arguments" do
- context = batch_context.context_for(%w(world))
+ context = batch_context.context_for(%w[world])
expect(context).to be_a(Gitlab::ApplicationContext)
expect(context.to_lazy_hash[:user].call).to eq("world")
diff --git a/spec/lib/gitlab/bitbucket_import/importer_spec.rb b/spec/lib/gitlab/bitbucket_import/importer_spec.rb
index 517d557d665..d468483661a 100644
--- a/spec/lib/gitlab/bitbucket_import/importer_spec.rb
+++ b/spec/lib/gitlab/bitbucket_import/importer_spec.rb
@@ -220,7 +220,7 @@ RSpec.describe Gitlab::BitbucketImport::Importer, :clean_gitlab_redis_cache, fea
subject.execute
expect(subject.errors.count).to eq(1)
- expect(subject.errors.first.keys).to match_array(%i(type iid errors))
+ expect(subject.errors.first.keys).to match_array(%i[type iid errors])
end
end
diff --git a/spec/lib/gitlab/bitbucket_import/importers/issue_importer_spec.rb b/spec/lib/gitlab/bitbucket_import/importers/issue_importer_spec.rb
index 8f79390d2d9..8732c787657 100644
--- a/spec/lib/gitlab/bitbucket_import/importers/issue_importer_spec.rb
+++ b/spec/lib/gitlab/bitbucket_import/importers/issue_importer_spec.rb
@@ -99,5 +99,13 @@ RSpec.describe Gitlab::BitbucketImport::Importers::IssueImporter, :clean_gitlab_
importer.execute
end
+
+ it 'increments the issue counter' do
+ expect_next_instance_of(Gitlab::Import::Metrics) do |metrics|
+ expect(metrics).to receive_message_chain(:issues_counter, :increment)
+ end
+
+ importer.execute
+ end
end
end
diff --git a/spec/lib/gitlab/bitbucket_import/importers/issues_importer_spec.rb b/spec/lib/gitlab/bitbucket_import/importers/issues_importer_spec.rb
index a361a9343dd..af5a929683e 100644
--- a/spec/lib/gitlab/bitbucket_import/importers/issues_importer_spec.rb
+++ b/spec/lib/gitlab/bitbucket_import/importers/issues_importer_spec.rb
@@ -12,22 +12,37 @@ RSpec.describe Gitlab::BitbucketImport::Importers::IssuesImporter, feature_categ
)
end
+ let(:client) { Bitbucket::Client.new(project.import_data.credentials) }
+
+ before do
+ allow(Bitbucket::Client).to receive(:new).and_return(client)
+ allow(client).to receive(:repo).and_return(Bitbucket::Representation::Repo.new({ 'has_issues' => true }))
+ allow(client).to receive(:last_issue).and_return(Bitbucket::Representation::Issue.new({ 'id' => 2 }))
+ allow(client).to receive(:issues).and_return(
+ [
+ Bitbucket::Representation::Issue.new({ 'id' => 1 }),
+ Bitbucket::Representation::Issue.new({ 'id' => 2 })
+ ],
+ []
+ )
+ end
+
subject(:importer) { described_class.new(project) }
describe '#execute', :clean_gitlab_redis_cache do
- before do
- allow_next_instance_of(Bitbucket::Client) do |client|
- allow(client).to receive(:issues).and_return(
- [
- Bitbucket::Representation::Issue.new({ 'id' => 1 }),
- Bitbucket::Representation::Issue.new({ 'id' => 2 })
- ],
- []
- )
+ context 'when the repo does not have issue tracking enabled' do
+ before do
+ allow(client).to receive(:repo).and_return(Bitbucket::Representation::Repo.new({ 'has_issues' => false }))
+ end
+
+ it 'does not import issues' do
+ expect(Gitlab::BitbucketImport::ImportIssueWorker).not_to receive(:perform_in)
+
+ importer.execute
end
end
- it 'imports each issue in parallel', :aggregate_failures do
+ it 'imports each issue in parallel' do
expect(Gitlab::BitbucketImport::ImportIssueWorker).to receive(:perform_in).twice
waiter = importer.execute
@@ -38,11 +53,15 @@ RSpec.describe Gitlab::BitbucketImport::Importers::IssuesImporter, feature_categ
.to match_array(%w[1 2])
end
+ it 'allocates internal ids' do
+ expect(Issue).to receive(:track_namespace_iid!).with(project.project_namespace, 2)
+
+ importer.execute
+ end
+
context 'when the client raises an error' do
before do
- allow_next_instance_of(Bitbucket::Client) do |client|
- allow(client).to receive(:issues).and_raise(StandardError)
- end
+ allow(client).to receive(:issues).and_raise(StandardError)
end
it 'tracks the failure and does not fail' do
@@ -57,7 +76,7 @@ RSpec.describe Gitlab::BitbucketImport::Importers::IssuesImporter, feature_categ
Gitlab::Cache::Import::Caching.set_add(importer.already_enqueued_cache_key, 1)
end
- it 'does not schedule job for enqueued issues', :aggregate_failures do
+ it 'does not schedule job for enqueued issues' do
expect(Gitlab::BitbucketImport::ImportIssueWorker).to receive(:perform_in).once
waiter = importer.execute
diff --git a/spec/lib/gitlab/bitbucket_import/importers/issues_notes_importer_spec.rb b/spec/lib/gitlab/bitbucket_import/importers/issues_notes_importer_spec.rb
index 043cd7f17b9..a04543b0511 100644
--- a/spec/lib/gitlab/bitbucket_import/importers/issues_notes_importer_spec.rb
+++ b/spec/lib/gitlab/bitbucket_import/importers/issues_notes_importer_spec.rb
@@ -4,15 +4,13 @@ require 'spec_helper'
RSpec.describe Gitlab::BitbucketImport::Importers::IssuesNotesImporter, feature_category: :importers do
let_it_be(:project) { create(:project, :import_started) }
- # let_it_be(:merge_request_1) { create(:merge_request, source_project: project) }
- # let_it_be(:merge_request_2) { create(:merge_request, source_project: project, source_branch: 'other-branch') }
let_it_be(:issue_1) { create(:issue, project: project) }
let_it_be(:issue_2) { create(:issue, project: project) }
subject(:importer) { described_class.new(project) }
describe '#execute', :clean_gitlab_redis_cache do
- it 'imports the notes from each issue in parallel', :aggregate_failures do
+ it 'imports the notes from each issue in parallel' do
expect(Gitlab::BitbucketImport::ImportIssueNotesWorker).to receive(:perform_in).twice
waiter = importer.execute
@@ -40,7 +38,7 @@ RSpec.describe Gitlab::BitbucketImport::Importers::IssuesNotesImporter, feature_
Gitlab::Cache::Import::Caching.set_add(importer.already_enqueued_cache_key, 2)
end
- it 'does not schedule job for enqueued issues', :aggregate_failures do
+ it 'does not schedule job for enqueued issues' do
expect(Gitlab::BitbucketImport::ImportIssueNotesWorker).to receive(:perform_in).once
waiter = importer.execute
diff --git a/spec/lib/gitlab/bitbucket_import/importers/pull_request_importer_spec.rb b/spec/lib/gitlab/bitbucket_import/importers/pull_request_importer_spec.rb
index 2eca6bb47d6..1f36a353724 100644
--- a/spec/lib/gitlab/bitbucket_import/importers/pull_request_importer_spec.rb
+++ b/spec/lib/gitlab/bitbucket_import/importers/pull_request_importer_spec.rb
@@ -162,5 +162,13 @@ RSpec.describe Gitlab::BitbucketImport::Importers::PullRequestImporter, :clean_g
importer.execute
end
+
+ it 'increments the merge requests counter' do
+ expect_next_instance_of(Gitlab::Import::Metrics) do |metrics|
+ expect(metrics).to receive_message_chain(:merge_requests_counter, :increment)
+ end
+
+ importer.execute
+ end
end
end
diff --git a/spec/lib/gitlab/bitbucket_import/importers/pull_request_notes_importer_spec.rb b/spec/lib/gitlab/bitbucket_import/importers/pull_request_notes_importer_spec.rb
index 4a30f225d66..332f6e5bd03 100644
--- a/spec/lib/gitlab/bitbucket_import/importers/pull_request_notes_importer_spec.rb
+++ b/spec/lib/gitlab/bitbucket_import/importers/pull_request_notes_importer_spec.rb
@@ -2,9 +2,9 @@
require 'spec_helper'
-RSpec.describe Gitlab::BitbucketImport::Importers::PullRequestNotesImporter, feature_category: :importers do
+RSpec.describe Gitlab::BitbucketImport::Importers::PullRequestNotesImporter, :clean_gitlab_redis_cache, feature_category: :importers do
let_it_be(:project) do
- create(:project, :import_started,
+ create(:project, :repository, :import_started,
import_data_attributes: {
credentials: { 'base_uri' => 'http://bitbucket.org/', 'user' => 'bitbucket', 'password' => 'password' }
}
@@ -12,28 +12,216 @@ RSpec.describe Gitlab::BitbucketImport::Importers::PullRequestNotesImporter, fea
end
let_it_be(:merge_request) { create(:merge_request, source_project: project) }
-
+ let_it_be(:merge_request_diff) { create(:merge_request_diff, :external, merge_request: merge_request) }
+ let_it_be(:bitbucket_user) { create(:user) }
+ let_it_be(:identity) { create(:identity, user: bitbucket_user, extern_uid: 'bitbucket_user', provider: :bitbucket) }
let(:hash) { { iid: merge_request.iid } }
- let(:importer_helper) { Gitlab::BitbucketImport::Importer.new(project) }
+ let(:client) { Bitbucket::Client.new({}) }
+ let(:ref_converter) { Gitlab::BitbucketImport::RefConverter.new(project) }
+ let(:user_finder) { Gitlab::BitbucketImport::UserFinder.new(project) }
+ let(:note_body) { 'body' }
+ let(:comments) { [Bitbucket::Representation::PullRequestComment.new(note_hash)] }
+ let(:created_at) { Date.today - 2.days }
+ let(:updated_at) { Date.today }
+ let(:note_hash) do
+ {
+ 'id' => 12,
+ 'user' => { 'nickname' => 'bitbucket_user' },
+ 'content' => { 'raw' => note_body },
+ 'created_on' => created_at,
+ 'updated_on' => updated_at
+ }
+ end
subject(:importer) { described_class.new(project, hash) }
before do
- allow(Gitlab::BitbucketImport::Importer).to receive(:new).and_return(importer_helper)
+ allow(Bitbucket::Client).to receive(:new).and_return(client)
+ allow(Gitlab::BitbucketImport::RefConverter).to receive(:new).and_return(ref_converter)
+ allow(Gitlab::BitbucketImport::UserFinder).to receive(:new).and_return(user_finder)
+ allow(client).to receive(:pull_request_comments).and_return(comments)
end
describe '#execute' do
- it 'calls Importer.import_pull_request_comments' do
- expect(importer_helper).to receive(:import_pull_request_comments).once
+ context 'for standalone pr comments' do
+ it 'calls RefConverter' do
+ expect(ref_converter).to receive(:convert_note).once.and_call_original
+
+ importer.execute
+ end
+
+ it 'creates a note with the correct attributes' do
+ expect { importer.execute }.to change { merge_request.notes.count }.from(0).to(1)
+
+ note = merge_request.notes.first
+
+ expect(note.note).to eq(note_body)
+ expect(note.author).to eq(bitbucket_user)
+ expect(note.created_at).to eq(created_at)
+ expect(note.updated_at).to eq(updated_at)
+ end
+
+ context 'when the author does not have a bitbucket identity' do
+ before do
+ identity.update!(provider: :github)
+ end
+
+ it 'sets the author to the project creator and adds the author to the note' do
+ importer.execute
+
+ note = merge_request.notes.first
+
+ expect(note.author).to eq(project.creator)
+ expect(note.note).to eq("*Created by: bitbucket_user*\n\nbody")
+ end
+ end
+
+ context 'when the note is deleted' do
+ let(:note_hash) do
+ {
+ 'id' => 12,
+ 'user' => { 'nickname' => 'bitbucket_user' },
+ 'content' => { 'raw' => note_body },
+ 'deleted' => true,
+ 'created_on' => created_at,
+ 'updated_on' => updated_at
+ }
+ end
+
+ it 'does not create a note' do
+ expect { importer.execute }.not_to change { merge_request.notes.count }
+ end
+ end
+ end
+
+ context 'for threaded inline comments' do
+ let(:path) { project.repository.commit.raw_diffs.first.new_path }
+ let(:reply_body) { 'Some reply' }
+ let(:comments) do
+ [
+ Bitbucket::Representation::PullRequestComment.new(pr_comment_1),
+ Bitbucket::Representation::PullRequestComment.new(pr_comment_2)
+ ]
+ end
- importer.execute
+ let(:pr_comment_1) do
+ {
+ 'id' => 14,
+ 'inline' => {
+ 'path' => path,
+ 'from' => nil,
+ 'to' => 1
+ },
+ 'parent' => { 'id' => 13 },
+ 'user' => { 'nickname' => 'bitbucket_user' },
+ 'content' => { 'raw' => reply_body },
+ 'created_on' => created_at,
+ 'updated_on' => updated_at
+ }
+ end
+
+ let(:pr_comment_2) do
+ {
+ 'id' => 13,
+ 'inline' => {
+ 'path' => path,
+ 'from' => nil,
+ 'to' => 1
+ },
+ 'user' => { 'nickname' => 'non_existent_user' },
+ 'content' => { 'raw' => note_body },
+ 'created_on' => created_at,
+ 'updated_on' => updated_at
+ }
+ end
+
+ it 'creates notes in the correct position with the right attributes' do
+ expect { importer.execute }.to change { merge_request.notes.count }.from(0).to(2)
+
+ expect(merge_request.notes.map(&:discussion_id).uniq.count).to eq(1)
+
+ notes = merge_request.notes.order(:id).to_a
+
+ start_note = notes.first
+ expect(start_note).to be_a(DiffNote)
+ expect(start_note.note).to eq("*Created by: non_existent_user*\n\n#{note_body}")
+ expect(start_note.author).to eq(project.creator)
+
+ reply_note = notes.last
+ expect(reply_note).to be_a(DiffNote)
+ expect(reply_note.note).to eq(reply_body)
+ expect(reply_note.author).to eq(bitbucket_user)
+ end
+
+ context 'when the comments are not part of the diff' do
+ let(:pr_comment_1) do
+ {
+ 'id' => 14,
+ 'inline' => {
+ 'path' => path,
+ 'from' => nil,
+ 'to' => nil
+ },
+ 'parent' => { 'id' => 13 },
+ 'user' => { 'nickname' => 'bitbucket_user' },
+ 'content' => { 'raw' => reply_body },
+ 'created_on' => created_at,
+ 'updated_on' => updated_at
+ }
+ end
+
+ let(:pr_comment_2) do
+ {
+ 'id' => 13,
+ 'inline' => {
+ 'path' => path,
+ 'from' => nil,
+ 'to' => nil
+ },
+ 'user' => { 'nickname' => 'bitbucket_user' },
+ 'content' => { 'raw' => note_body },
+ 'created_on' => created_at,
+ 'updated_on' => updated_at
+ }
+ end
+
+ it 'creates them as normal notes' do
+ expect { importer.execute }.to change { merge_request.notes.count }.from(0).to(2)
+
+ notes = merge_request.notes.order(:id).to_a
+
+ first_note = notes.first
+ expect(first_note).not_to be_a(DiffNote)
+ expect(first_note.note).to eq("*Comment on*\n\n#{note_body}")
+ expect(first_note.author).to eq(bitbucket_user)
+
+ second_note = notes.last
+ expect(second_note).not_to be_a(DiffNote)
+ expect(second_note.note).to eq("*Comment on*\n\n#{reply_body}")
+ expect(second_note.author).to eq(bitbucket_user)
+ end
+ end
+
+ context 'when an error is raised for one note' do
+ before do
+ allow(user_finder).to receive(:gitlab_user_id).and_call_original
+ allow(user_finder).to receive(:gitlab_user_id).with(project, 'bitbucket_user').and_raise(StandardError)
+ end
+
+ it 'tracks the error and continues to import other notes' do
+ expect(Gitlab::ErrorTracking).to receive(:log_exception)
+ .with(anything, hash_including(comment_id: 14)).and_call_original
+
+ expect { importer.execute }.to change { merge_request.notes.count }.from(0).to(1)
+ end
+ end
end
context 'when the merge request does not exist' do
let(:hash) { { iid: 'nonexistent' } }
- it 'does not call Importer.import_pull_request_comments' do
- expect(importer_helper).not_to receive(:import_pull_request_comments)
+ it 'does not call #import_pull_request_comments' do
+ expect(importer).not_to receive(:import_pull_request_comments)
importer.execute
end
@@ -46,8 +234,8 @@ RSpec.describe Gitlab::BitbucketImport::Importers::PullRequestNotesImporter, fea
merge_request.update!(source_project: another_project, target_project: another_project)
end
- it 'does not call Importer.import_pull_request_comments' do
- expect(importer_helper).not_to receive(:import_pull_request_comments)
+ it 'does not call #import_pull_request_comments' do
+ expect(importer).not_to receive(:import_pull_request_comments)
importer.execute
end
@@ -55,7 +243,7 @@ RSpec.describe Gitlab::BitbucketImport::Importers::PullRequestNotesImporter, fea
context 'when an error is raised' do
before do
- allow(importer_helper).to receive(:import_pull_request_comments).and_raise(StandardError)
+ allow(importer).to receive(:import_pull_request_comments).and_raise(StandardError)
end
it 'tracks the failure and does not fail' do
diff --git a/spec/lib/gitlab/bitbucket_import/importers/pull_requests_importer_spec.rb b/spec/lib/gitlab/bitbucket_import/importers/pull_requests_importer_spec.rb
index 46bf099de0c..eba7ec92aba 100644
--- a/spec/lib/gitlab/bitbucket_import/importers/pull_requests_importer_spec.rb
+++ b/spec/lib/gitlab/bitbucket_import/importers/pull_requests_importer_spec.rb
@@ -28,7 +28,7 @@ RSpec.describe Gitlab::BitbucketImport::Importers::PullRequestsImporter, feature
end
end
- it 'imports each pull request in parallel', :aggregate_failures do
+ it 'imports each pull request in parallel' do
expect(Gitlab::BitbucketImport::ImportPullRequestWorker).to receive(:perform_in).exactly(3).times
waiter = importer.execute
@@ -58,7 +58,7 @@ RSpec.describe Gitlab::BitbucketImport::Importers::PullRequestsImporter, feature
Gitlab::Cache::Import::Caching.set_add(importer.already_enqueued_cache_key, 1)
end
- it 'does not schedule job for enqueued pull requests', :aggregate_failures do
+ it 'does not schedule job for enqueued pull requests' do
expect(Gitlab::BitbucketImport::ImportPullRequestWorker).to receive(:perform_in).twice
waiter = importer.execute
diff --git a/spec/lib/gitlab/bitbucket_import/importers/pull_requests_notes_importer_spec.rb b/spec/lib/gitlab/bitbucket_import/importers/pull_requests_notes_importer_spec.rb
index c44fc259c3b..78a08accf82 100644
--- a/spec/lib/gitlab/bitbucket_import/importers/pull_requests_notes_importer_spec.rb
+++ b/spec/lib/gitlab/bitbucket_import/importers/pull_requests_notes_importer_spec.rb
@@ -10,7 +10,7 @@ RSpec.describe Gitlab::BitbucketImport::Importers::PullRequestsNotesImporter, fe
subject(:importer) { described_class.new(project) }
describe '#execute', :clean_gitlab_redis_cache do
- it 'imports the notes from each merge request in parallel', :aggregate_failures do
+ it 'imports the notes from each merge request in parallel' do
expect(Gitlab::BitbucketImport::ImportPullRequestNotesWorker).to receive(:perform_in).twice
waiter = importer.execute
@@ -38,7 +38,7 @@ RSpec.describe Gitlab::BitbucketImport::Importers::PullRequestsNotesImporter, fe
Gitlab::Cache::Import::Caching.set_add(importer.already_enqueued_cache_key, 2)
end
- it 'does not schedule job for enqueued merge requests', :aggregate_failures do
+ it 'does not schedule job for enqueued merge requests' do
expect(Gitlab::BitbucketImport::ImportPullRequestNotesWorker).to receive(:perform_in).once
waiter = importer.execute
diff --git a/spec/lib/gitlab/bitbucket_import/importers/repository_importer_spec.rb b/spec/lib/gitlab/bitbucket_import/importers/repository_importer_spec.rb
index 1caf0b884c2..9e458780c78 100644
--- a/spec/lib/gitlab/bitbucket_import/importers/repository_importer_spec.rb
+++ b/spec/lib/gitlab/bitbucket_import/importers/repository_importer_spec.rb
@@ -7,6 +7,14 @@ RSpec.describe Gitlab::BitbucketImport::Importers::RepositoryImporter, feature_c
subject(:importer) { described_class.new(project) }
+ before do
+ allow_next_instance_of(Bitbucket::Client) do |client|
+ allow(client).to receive(:repo).and_return(Bitbucket::Representation::Repo.new(
+ { 'mainbranch' => { 'name' => 'develop' } }
+ ))
+ end
+ end
+
describe '#execute' do
context 'when repository is empty' do
it 'imports the repository' do
@@ -17,6 +25,15 @@ RSpec.describe Gitlab::BitbucketImport::Importers::RepositoryImporter, feature_c
importer.execute
end
+
+ it 'sets the default branch' do
+ allow(project.repository).to receive(:import_repository)
+ allow(project.repository).to receive(:fetch_as_mirror)
+
+ expect(project).to receive(:change_head).with('develop')
+
+ importer.execute
+ end
end
context 'when repository is not empty' do
diff --git a/spec/lib/gitlab/bullet/exclusions_spec.rb b/spec/lib/gitlab/bullet/exclusions_spec.rb
index ccedfee28c7..2cb824674dc 100644
--- a/spec/lib/gitlab/bullet/exclusions_spec.rb
+++ b/spec/lib/gitlab/bullet/exclusions_spec.rb
@@ -3,7 +3,7 @@
require 'fast_spec_helper'
require 'tempfile'
-RSpec.describe Gitlab::Bullet::Exclusions, feature_category: :application_performance do
+RSpec.describe Gitlab::Bullet::Exclusions, feature_category: :cloud_connector do
let(:config_file) do
file = Tempfile.new('bullet.yml')
File.basename(file)
diff --git a/spec/lib/gitlab/cache_spec.rb b/spec/lib/gitlab/cache_spec.rb
index 67c70a77880..92a5ea7bdfb 100644
--- a/spec/lib/gitlab/cache_spec.rb
+++ b/spec/lib/gitlab/cache_spec.rb
@@ -28,7 +28,7 @@ RSpec.describe Gitlab::Cache, :request_store do
end
describe '.delete' do
- let(:key) { %w{a cache key} }
+ let(:key) { %w[a cache key] }
subject(:delete) { described_class.delete(key) }
diff --git a/spec/lib/gitlab/ci/ansi2html_spec.rb b/spec/lib/gitlab/ci/ansi2html_spec.rb
index 30359a7170f..2990599f840 100644
--- a/spec/lib/gitlab/ci/ansi2html_spec.rb
+++ b/spec/lib/gitlab/ci/ansi2html_spec.rb
@@ -227,7 +227,7 @@ RSpec.describe Gitlab::Ci::Ansi2html do
text = "#{section_start}Some text#{section_end}"
class_name_start = section_start.gsub("\033[0K", '').gsub('<', '&lt;')
class_name_end = section_end.gsub("\033[0K", '').gsub('<', '&lt;')
- html = %{<span>#{class_name_start}Some text#{class_name_end}</span>}
+ html = %(<span>#{class_name_start}Some text#{class_name_end}</span>)
expect(convert_html(text)).to eq(html)
end
@@ -238,9 +238,9 @@ RSpec.describe Gitlab::Ci::Ansi2html do
it 'prints light red' do
text = "#{section_start}\e[91mHello\e[0m\nLine 1\nLine 2\nLine 3\n#{section_end}"
- header = %{<span class="term-fg-l-red section section-header js-s-#{class_name(section_name)}">Hello</span>}
- line_break = %{<span class="section section-header js-s-#{class_name(section_name)}"><br/></span>}
- output_line = %{<span class="section line js-s-#{class_name(section_name)}">Line 1<br/>Line 2<br/>Line 3<br/></span>}
+ header = %(<span class="term-fg-l-red section section-header js-s-#{class_name(section_name)}">Hello</span>)
+ line_break = %(<span class="section section-header js-s-#{class_name(section_name)}"><br/></span>)
+ output_line = %(<span class="section line js-s-#{class_name(section_name)}">Line 1<br/>Line 2<br/>Line 3<br/></span>)
html = "#{section_start_html}#{header}#{line_break}#{output_line}#{section_end_html}"
expect(convert_html(text)).to eq(html)
diff --git a/spec/lib/gitlab/ci/ansi2json/line_spec.rb b/spec/lib/gitlab/ci/ansi2json/line_spec.rb
index b8563bb1d1c..475a54b275d 100644
--- a/spec/lib/gitlab/ci/ansi2json/line_spec.rb
+++ b/spec/lib/gitlab/ci/ansi2json/line_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Gitlab::Ci::Ansi2json::Line do
+RSpec.describe Gitlab::Ci::Ansi2json::Line, feature_category: :continuous_integration do
let(:offset) { 0 }
let(:style) { Gitlab::Ci::Ansi2json::Style.new }
@@ -75,6 +75,14 @@ RSpec.describe Gitlab::Ci::Ansi2json::Line do
end
end
+ describe '#set_as_section_footer' do
+ it 'change the section_footer to true' do
+ expect { subject.set_as_section_footer }
+ .to change { subject.section_footer }
+ .to be_truthy
+ end
+ end
+
describe '#set_section_duration' do
using RSpec::Parameterized::TableSyntax
@@ -178,6 +186,23 @@ RSpec.describe Gitlab::Ci::Ansi2json::Line do
expect(subject.to_h).to eq(result)
end
end
+
+ context 'when section footer is set' do
+ before do
+ subject.set_as_section_footer
+ end
+
+ it 'serializes the attributes set' do
+ result = {
+ offset: 0,
+ content: [{ text: 'some data', style: 'term-bold' }],
+ section: 'section_2',
+ section_footer: true
+ }
+
+ expect(subject.to_h).to eq(result)
+ end
+ end
end
context 'when there are no sections' do
diff --git a/spec/lib/gitlab/ci/ansi2json/state_spec.rb b/spec/lib/gitlab/ci/ansi2json/state_spec.rb
index 8dd4092f3d8..07e6579829a 100644
--- a/spec/lib/gitlab/ci/ansi2json/state_spec.rb
+++ b/spec/lib/gitlab/ci/ansi2json/state_spec.rb
@@ -8,7 +8,7 @@ RSpec.describe Gitlab::Ci::Ansi2json::State, feature_category: :continuous_integ
state.offset = 1
state.new_line!(style: { fg: 'some-fg', bg: 'some-bg', mask: 1234 })
state.set_last_line_offset
- state.open_section('hello', 111, {})
+ state.open_section('hello', 100, {})
end
end
@@ -24,7 +24,7 @@ RSpec.describe Gitlab::Ci::Ansi2json::State, feature_category: :continuous_integ
fg: 'some-fg',
mask: 1234
})
- expect(new_state.open_sections).to eq({ 'hello' => 111 })
+ expect(new_state.open_sections).to eq({ 'hello' => 100 })
end
it 'ignores unsigned prior state', :aggregate_failures do
@@ -44,6 +44,23 @@ RSpec.describe Gitlab::Ci::Ansi2json::State, feature_category: :continuous_integ
expect(new_state.open_sections).to eq({})
end
+ it 'opens and closes a section', :aggregate_failures do
+ new_state = described_class.new('', 1000)
+
+ new_state.new_line!(style: {})
+ new_state.open_section('hello', 100, {})
+
+ expect(new_state.current_line.section_header).to eq(true)
+ expect(new_state.current_line.section_footer).to eq(false)
+
+ new_state.new_line!(style: {})
+ new_state.close_section('hello', 101)
+
+ expect(new_state.current_line.section_header).to eq(false)
+ expect(new_state.current_line.section_duration).to eq('00:01')
+ expect(new_state.current_line.section_footer).to eq(true)
+ end
+
it 'ignores bad input', :aggregate_failures do
expect(::Gitlab::AppLogger).to(
receive(:warn).with(
diff --git a/spec/lib/gitlab/ci/ansi2json_spec.rb b/spec/lib/gitlab/ci/ansi2json_spec.rb
index 98fca40e8ea..23be3209171 100644
--- a/spec/lib/gitlab/ci/ansi2json_spec.rb
+++ b/spec/lib/gitlab/ci/ansi2json_spec.rb
@@ -145,6 +145,7 @@ RSpec.describe Gitlab::Ci::Ansi2json, feature_category: :continuous_integration
offset: 63,
content: [],
section_duration: '01:03',
+ section_footer: true,
section: 'prepare-script'
}
])
@@ -163,7 +164,8 @@ RSpec.describe Gitlab::Ci::Ansi2json, feature_category: :continuous_integration
offset: 56,
content: [],
section: 'prepare-script',
- section_duration: '01:03'
+ section_duration: '01:03',
+ section_footer: true
}
])
end
@@ -181,7 +183,8 @@ RSpec.describe Gitlab::Ci::Ansi2json, feature_category: :continuous_integration
offset: 49,
content: [],
section: 'prepare-script',
- section_duration: '01:03'
+ section_duration: '01:03',
+ section_footer: true
},
{
offset: 91,
@@ -262,7 +265,8 @@ RSpec.describe Gitlab::Ci::Ansi2json, feature_category: :continuous_integration
offset: 75,
content: [],
section: 'prepare-script',
- section_duration: '01:03'
+ section_duration: '01:03',
+ section_footer: true
}
])
end
@@ -300,7 +304,8 @@ RSpec.describe Gitlab::Ci::Ansi2json, feature_category: :continuous_integration
offset: 106,
content: [],
section: 'prepare-script-nested',
- section_duration: '00:02'
+ section_duration: '00:02',
+ section_footer: true
},
{
offset: 155,
@@ -311,7 +316,8 @@ RSpec.describe Gitlab::Ci::Ansi2json, feature_category: :continuous_integration
offset: 158,
content: [],
section: 'prepare-script',
- section_duration: '01:03'
+ section_duration: '01:03',
+ section_footer: true
},
{
offset: 200,
@@ -345,13 +351,15 @@ RSpec.describe Gitlab::Ci::Ansi2json, feature_category: :continuous_integration
offset: 115,
content: [],
section: 'prepare-script-nested',
- section_duration: '00:02'
+ section_duration: '00:02',
+ section_footer: true
},
{
offset: 164,
content: [],
section: 'prepare-script',
- section_duration: '01:03'
+ section_duration: '01:03',
+ section_footer: true
}
])
end
@@ -378,7 +386,8 @@ RSpec.describe Gitlab::Ci::Ansi2json, feature_category: :continuous_integration
offset: 83,
content: [],
section: 'prepare-script',
- section_duration: '01:03'
+ section_duration: '01:03',
+ section_footer: true
}
])
end
@@ -554,7 +563,8 @@ RSpec.describe Gitlab::Ci::Ansi2json, feature_category: :continuous_integration
offset: 77,
content: [],
section: 'prepare-script',
- section_duration: '01:03'
+ section_duration: '01:03',
+ section_footer: true
}
]
end
diff --git a/spec/lib/gitlab/ci/badge/pipeline/status_spec.rb b/spec/lib/gitlab/ci/badge/pipeline/status_spec.rb
index 45d0d781090..d6b59d0da64 100644
--- a/spec/lib/gitlab/ci/badge/pipeline/status_spec.rb
+++ b/spec/lib/gitlab/ci/badge/pipeline/status_spec.rb
@@ -117,10 +117,7 @@ RSpec.describe Gitlab::Ci::Badge::Pipeline::Status do
end
def create_pipeline(project, sha, branch)
- pipeline = create(:ci_empty_pipeline,
- project: project,
- sha: sha,
- ref: branch)
+ pipeline = create(:ci_empty_pipeline, project: project, sha: sha, ref: branch)
create(:ci_build, pipeline: pipeline, stage: 'notify')
end
diff --git a/spec/lib/gitlab/ci/build/artifacts/metadata/entry_spec.rb b/spec/lib/gitlab/ci/build/artifacts/metadata/entry_spec.rb
index 7b35c9ba483..6cd9432c6c5 100644
--- a/spec/lib/gitlab/ci/build/artifacts/metadata/entry_spec.rb
+++ b/spec/lib/gitlab/ci/build/artifacts/metadata/entry_spec.rb
@@ -69,9 +69,11 @@ RSpec.describe Gitlab::Ci::Build::Artifacts::Metadata::Entry do
it { is_expected.to all(be_an_instance_of(described_class)) }
it do
- is_expected.to contain_exactly entry('path/dir_1/file_1'),
- entry('path/dir_1/file_b'),
- entry('path/dir_1/subdir/')
+ is_expected.to contain_exactly(
+ entry('path/dir_1/file_1'),
+ entry('path/dir_1/file_b'),
+ entry('path/dir_1/subdir/')
+ )
end
end
@@ -82,8 +84,10 @@ RSpec.describe Gitlab::Ci::Build::Artifacts::Metadata::Entry do
it { is_expected.to all(be_an_instance_of(described_class)) }
it do
- is_expected.to contain_exactly entry('path/dir_1/file_1'),
- entry('path/dir_1/file_b')
+ is_expected.to contain_exactly(
+ entry('path/dir_1/file_1'),
+ entry('path/dir_1/file_b')
+ )
end
end
@@ -103,8 +107,10 @@ RSpec.describe Gitlab::Ci::Build::Artifacts::Metadata::Entry do
it { is_expected.to all(be_an_instance_of(described_class)) }
it do
- is_expected.to contain_exactly entry('path/dir_1/subdir/'),
- entry('path/')
+ is_expected.to contain_exactly(
+ entry('path/dir_1/subdir/'),
+ entry('path/')
+ )
end
end
diff --git a/spec/lib/gitlab/ci/build/context/build_spec.rb b/spec/lib/gitlab/ci/build/context/build_spec.rb
index fae02e140f2..9fdb4ee9393 100644
--- a/spec/lib/gitlab/ci/build/context/build_spec.rb
+++ b/spec/lib/gitlab/ci/build/context/build_spec.rb
@@ -41,16 +41,6 @@ RSpec.describe Gitlab::Ci::Build::Context::Build, feature_category: :pipeline_co
it { expect(context.variables).to be_instance_of(Gitlab::Ci::Variables::Collection) }
it_behaves_like 'variables collection'
-
- context 'with FF disabled' do
- before do
- stub_feature_flags(reduced_build_attributes_list_for_rules: false)
- end
-
- it { expect(context.variables).to be_instance_of(Gitlab::Ci::Variables::Collection) }
-
- it_behaves_like 'variables collection'
- end
end
describe '#variables_hash' do
@@ -59,15 +49,5 @@ RSpec.describe Gitlab::Ci::Build::Context::Build, feature_category: :pipeline_co
it { expect(context.variables_hash).to be_instance_of(ActiveSupport::HashWithIndifferentAccess) }
it_behaves_like 'variables collection'
-
- context 'with FF disabled' do
- before do
- stub_feature_flags(reduced_build_attributes_list_for_rules: false)
- end
-
- it { expect(context.variables_hash).to be_instance_of(ActiveSupport::HashWithIndifferentAccess) }
-
- it_behaves_like 'variables collection'
- end
end
end
diff --git a/spec/lib/gitlab/ci/build/hook_spec.rb b/spec/lib/gitlab/ci/build/hook_spec.rb
index 6c9175b4260..da9a680f110 100644
--- a/spec/lib/gitlab/ci/build/hook_spec.rb
+++ b/spec/lib/gitlab/ci/build/hook_spec.rb
@@ -4,8 +4,10 @@ require 'spec_helper'
RSpec.describe Gitlab::Ci::Build::Hook, feature_category: :pipeline_composition do
let_it_be(:build1) do
- FactoryBot.build(:ci_build,
- options: { hooks: { pre_get_sources_script: ["echo 'hello pre_get_sources_script'"] } })
+ build(
+ :ci_build,
+ options: { hooks: { pre_get_sources_script: ["echo 'hello pre_get_sources_script'"] } }
+ )
end
describe '.from_hooks' do
diff --git a/spec/lib/gitlab/ci/build/policy/changes_spec.rb b/spec/lib/gitlab/ci/build/policy/changes_spec.rb
index 5d5a212b9a5..00e44650d44 100644
--- a/spec/lib/gitlab/ci/build/policy/changes_spec.rb
+++ b/spec/lib/gitlab/ci/build/policy/changes_spec.rb
@@ -8,11 +8,14 @@ RSpec.describe Gitlab::Ci::Build::Policy::Changes do
describe '#satisfied_by?' do
describe 'paths matching' do
let(:pipeline) do
- build(:ci_empty_pipeline, project: project,
- ref: 'master',
- source: :push,
- sha: '1234abcd',
- before_sha: '0123aabb')
+ build(
+ :ci_empty_pipeline,
+ project: project,
+ ref: 'master',
+ source: :push,
+ sha: '1234abcd',
+ before_sha: '0123aabb'
+ )
end
let(:ci_build) do
@@ -92,11 +95,14 @@ RSpec.describe Gitlab::Ci::Build::Policy::Changes do
let_it_be(:project) { create(:project, :repository) }
let(:pipeline) do
- create(:ci_empty_pipeline, project: project,
- ref: 'master',
- source: :push,
- sha: '498214d',
- before_sha: '281d3a7')
+ create(
+ :ci_empty_pipeline,
+ project: project,
+ ref: 'master',
+ source: :push,
+ sha: '498214d',
+ before_sha: '281d3a7'
+ )
end
let(:build) do
@@ -122,12 +128,15 @@ RSpec.describe Gitlab::Ci::Build::Policy::Changes do
let_it_be(:project) { create(:project, :repository) }
let(:pipeline) do
- create(:ci_empty_pipeline, project: project,
- ref: 'feature',
- source: source,
- sha: '0b4bc9a4',
- before_sha: Gitlab::Git::BLANK_SHA,
- merge_request: merge_request)
+ create(
+ :ci_empty_pipeline,
+ project: project,
+ ref: 'feature',
+ source: source,
+ sha: '0b4bc9a4',
+ before_sha: Gitlab::Git::BLANK_SHA,
+ merge_request: merge_request
+ )
end
let(:ci_build) do
@@ -140,11 +149,13 @@ RSpec.describe Gitlab::Ci::Build::Policy::Changes do
let(:source) { :merge_request_event }
let(:merge_request) do
- create(:merge_request,
- source_project: project,
- source_branch: 'feature',
- target_project: project,
- target_branch: 'master')
+ create(
+ :merge_request,
+ source_project: project,
+ source_branch: 'feature',
+ target_project: project,
+ target_branch: 'master'
+ )
end
it 'is satified by changes in the merge request' do
diff --git a/spec/lib/gitlab/ci/build/policy/variables_spec.rb b/spec/lib/gitlab/ci/build/policy/variables_spec.rb
index e560f1c2b5a..1073df60d4a 100644
--- a/spec/lib/gitlab/ci/build/policy/variables_spec.rb
+++ b/spec/lib/gitlab/ci/build/policy/variables_spec.rb
@@ -104,23 +104,32 @@ RSpec.describe Gitlab::Ci::Build::Policy::Variables do
context 'when using project ci variables in environment scope' do
let(:ci_build) do
- build(:ci_build, pipeline: pipeline,
- project: project,
- ref: 'master',
- stage: 'review',
- environment: 'test/$CI_JOB_STAGE/1',
- ci_stage: build(:ci_stage, name: 'review', project: project, pipeline: pipeline))
+ build(
+ :ci_build,
+ pipeline: pipeline,
+ project: project,
+ ref: 'master',
+ stage: 'review',
+ environment: 'test/$CI_JOB_STAGE/1',
+ ci_stage: build(:ci_stage, name: 'review', project: project, pipeline: pipeline)
+ )
end
before do
- create(:ci_variable, project: project,
- key: 'SCOPED_VARIABLE',
- value: 'my-value-1')
-
- create(:ci_variable, project: project,
- key: 'SCOPED_VARIABLE',
- value: 'my-value-2',
- environment_scope: 'test/review/*')
+ create(
+ :ci_variable,
+ project: project,
+ key: 'SCOPED_VARIABLE',
+ value: 'my-value-1'
+ )
+
+ create(
+ :ci_variable,
+ project: project,
+ key: 'SCOPED_VARIABLE',
+ value: 'my-value-2',
+ environment_scope: 'test/review/*'
+ )
end
it 'is satisfied by scoped variable match' do
diff --git a/spec/lib/gitlab/ci/build/rules/rule/clause/changes_spec.rb b/spec/lib/gitlab/ci/build/rules/rule/clause/changes_spec.rb
index a22aa30304b..1fe54b9f2d5 100644
--- a/spec/lib/gitlab/ci/build/rules/rule/clause/changes_spec.rb
+++ b/spec/lib/gitlab/ci/build/rules/rule/clause/changes_spec.rb
@@ -95,8 +95,11 @@ RSpec.describe Gitlab::Ci::Build::Rules::Rule::Clause::Changes do
context 'when using compare_to' do
let_it_be(:project) do
- create(:project, :custom_repo,
- files: { 'README.md' => 'readme' })
+ create(
+ :project,
+ :custom_repo,
+ files: { 'README.md' => 'readme' }
+ )
end
let_it_be(:user) { project.owner }
diff --git a/spec/lib/gitlab/ci/config/entry/bridge_spec.rb b/spec/lib/gitlab/ci/config/entry/bridge_spec.rb
index 567ffa68836..6e6b9d949c5 100644
--- a/spec/lib/gitlab/ci/config/entry/bridge_spec.rb
+++ b/spec/lib/gitlab/ci/config/entry/bridge_spec.rb
@@ -101,14 +101,16 @@ RSpec.describe Gitlab::Ci::Config::Entry::Bridge do
describe '#value' do
it 'is returns a bridge job configuration' do
- expect(subject.value).to eq(name: :my_bridge,
- trigger: { project: 'some/project' },
- ignore: false,
- stage: 'test',
- only: { refs: %w[branches tags] },
- job_variables: {},
- root_variables_inheritance: true,
- scheduling_type: :stage)
+ expect(subject.value).to eq(
+ name: :my_bridge,
+ trigger: { project: 'some/project' },
+ ignore: false,
+ stage: 'test',
+ only: { refs: %w[branches tags] },
+ job_variables: {},
+ root_variables_inheritance: true,
+ scheduling_type: :stage
+ )
end
end
end
@@ -124,15 +126,16 @@ RSpec.describe Gitlab::Ci::Config::Entry::Bridge do
describe '#value' do
it 'is returns a bridge job configuration hash' do
- expect(subject.value).to eq(name: :my_bridge,
- trigger: { project: 'some/project',
- branch: 'feature' },
- ignore: false,
- stage: 'test',
- only: { refs: %w[branches tags] },
- job_variables: {},
- root_variables_inheritance: true,
- scheduling_type: :stage)
+ expect(subject.value).to eq(
+ name: :my_bridge,
+ trigger: { project: 'some/project', branch: 'feature' },
+ ignore: false,
+ stage: 'test',
+ only: { refs: %w[branches tags] },
+ job_variables: {},
+ root_variables_inheritance: true,
+ scheduling_type: :stage
+ )
end
end
end
@@ -283,8 +286,8 @@ RSpec.describe Gitlab::Ci::Config::Entry::Bridge do
ignore: false,
stage: 'test',
only: { refs: %w[branches tags] },
- parallel: { matrix: [{ 'PROVIDER' => ['aws'], 'STACK' => %w(monitoring app1) },
- { 'PROVIDER' => ['gcp'], 'STACK' => %w(data) }] },
+ parallel: { matrix: [{ 'PROVIDER' => ['aws'], 'STACK' => %w[monitoring app1] },
+ { 'PROVIDER' => ['gcp'], 'STACK' => %w[data] }] },
job_variables: {},
root_variables_inheritance: true,
scheduling_type: :stage
@@ -305,15 +308,16 @@ RSpec.describe Gitlab::Ci::Config::Entry::Bridge do
describe '#value' do
it 'returns a bridge job configuration hash' do
- expect(subject.value).to eq(name: :my_bridge,
- trigger: { project: 'some/project',
- forward: { pipeline_variables: true } },
- ignore: false,
- stage: 'test',
- only: { refs: %w[branches tags] },
- job_variables: {},
- root_variables_inheritance: true,
- scheduling_type: :stage)
+ expect(subject.value).to eq(
+ name: :my_bridge,
+ trigger: { project: 'some/project', forward: { pipeline_variables: true } },
+ ignore: false,
+ stage: 'test',
+ only: { refs: %w[branches tags] },
+ job_variables: {},
+ root_variables_inheritance: true,
+ scheduling_type: :stage
+ )
end
end
end
diff --git a/spec/lib/gitlab/ci/config/entry/commands_spec.rb b/spec/lib/gitlab/ci/config/entry/commands_spec.rb
index 1b8dfae692a..f84a78b4804 100644
--- a/spec/lib/gitlab/ci/config/entry/commands_spec.rb
+++ b/spec/lib/gitlab/ci/config/entry/commands_spec.rb
@@ -6,7 +6,7 @@ RSpec.describe Gitlab::Ci::Config::Entry::Commands do
let(:entry) { described_class.new(config) }
context 'when entry config value is an array of strings' do
- let(:config) { %w(ls pwd) }
+ let(:config) { %w[ls pwd] }
describe '#value' do
it 'returns array of strings' do
diff --git a/spec/lib/gitlab/ci/config/entry/environment_spec.rb b/spec/lib/gitlab/ci/config/entry/environment_spec.rb
index 3562706ff33..cff94a96c99 100644
--- a/spec/lib/gitlab/ci/config/entry/environment_spec.rb
+++ b/spec/lib/gitlab/ci/config/entry/environment_spec.rb
@@ -93,7 +93,7 @@ RSpec.describe Gitlab::Ci::Config::Entry::Environment do
context 'when valid action is used' do
where(:action) do
- %w(start stop prepare verify access)
+ %w[start stop prepare verify access]
end
with_them do
diff --git a/spec/lib/gitlab/ci/config/entry/image_spec.rb b/spec/lib/gitlab/ci/config/entry/image_spec.rb
index b37498ba10a..17c45ec4c2c 100644
--- a/spec/lib/gitlab/ci/config/entry/image_spec.rb
+++ b/spec/lib/gitlab/ci/config/entry/image_spec.rb
@@ -56,7 +56,7 @@ RSpec.describe Gitlab::Ci::Config::Entry::Image do
end
context 'when configuration is a hash' do
- let(:config) { { name: 'image:1.0', entrypoint: %w(/bin/sh run) } }
+ let(:config) { { name: 'image:1.0', entrypoint: %w[/bin/sh run] } }
describe '#value' do
it 'returns image hash' do
@@ -84,13 +84,13 @@ RSpec.describe Gitlab::Ci::Config::Entry::Image do
describe '#entrypoint' do
it "returns image's entrypoint" do
- expect(entry.entrypoint).to eq %w(/bin/sh run)
+ expect(entry.entrypoint).to eq %w[/bin/sh run]
end
end
context 'when configuration has ports' do
let(:ports) { [{ number: 80, protocol: 'http', name: 'foobar' }] }
- let(:config) { { name: 'image:1.0', entrypoint: %w(/bin/sh run), ports: ports } }
+ let(:config) { { name: 'image:1.0', entrypoint: %w[/bin/sh run], ports: ports } }
let(:entry) { described_class.new(config, with_image_ports: image_ports) }
let(:image_ports) { false }
diff --git a/spec/lib/gitlab/ci/config/entry/job_spec.rb b/spec/lib/gitlab/ci/config/entry/job_spec.rb
index 1a78d929871..24d3cac6616 100644
--- a/spec/lib/gitlab/ci/config/entry/job_spec.rb
+++ b/spec/lib/gitlab/ci/config/entry/job_spec.rb
@@ -598,7 +598,7 @@ RSpec.describe Gitlab::Ci::Config::Entry::Job, feature_category: :pipeline_compo
end
end
- context 'when job is not a pages job' do
+ context 'when job is not a pages job', feature_category: :pages do
let(:name) { :rspec }
context 'if the config contains a publish entry' do
@@ -609,9 +609,18 @@ RSpec.describe Gitlab::Ci::Config::Entry::Job, feature_category: :pipeline_compo
expect(entry.errors).to include /job publish can only be used within a `pages` job/
end
end
+
+ context 'if the config contains a pages entry' do
+ let(:entry) { described_class.new({ script: 'echo', pages: { path_prefix: 'foo' } }, name: name) }
+
+ it 'is invalid' do
+ expect(entry).not_to be_valid
+ expect(entry.errors).to include /job pages can only be used within a `pages` job/
+ end
+ end
end
- context 'when job is a pages job' do
+ context 'when job is a pages job', feature_category: :pages do
let(:name) { :pages }
context 'when it does not have a publish entry' do
@@ -629,6 +638,28 @@ RSpec.describe Gitlab::Ci::Config::Entry::Job, feature_category: :pipeline_compo
expect(entry).to be_valid
end
end
+
+ context 'when it has a pages entry' do
+ let(:entry) { described_class.new({ script: 'echo', pages: { path_prefix: 'foo' } }, name: name) }
+
+ it 'is valid' do
+ expect(entry).to be_valid
+ end
+ end
+ end
+ end
+
+ describe '#pages_job?', :aggregate_failures, feature_category: :pages do
+ where(:name, :result) do
+ :pages | true
+ :'pages:staging' | false
+ :'something:pages:else' | false
+ end
+
+ with_them do
+ subject { described_class.new({}, name: name).pages_job? }
+
+ it { is_expected.to eq(result) }
end
end
@@ -739,20 +770,6 @@ RSpec.describe Gitlab::Ci::Config::Entry::Job, feature_category: :pipeline_compo
end
end
- describe '#pages_job?', :aggregate_failures, feature_category: :pages do
- where(:name, :result) do
- :pages | true
- :'pages:staging' | false
- :'something:pages:else' | false
- end
-
- with_them do
- subject { described_class.new({}, name: name).pages_job? }
-
- it { is_expected.to eq(result) }
- end
- end
-
context 'when composed' do
before do
entry.compose!
@@ -773,19 +790,20 @@ RSpec.describe Gitlab::Ci::Config::Entry::Job, feature_category: :pipeline_compo
end
it 'returns correct value' do
- expect(entry.value)
- .to eq(name: :rspec,
- before_script: %w[ls pwd],
- script: %w[rspec],
- stage: 'test',
- ignore: false,
- after_script: %w[cleanup],
- hooks: { pre_get_sources_script: ['echo hello'] },
- only: { refs: %w[branches tags] },
- job_variables: {},
- root_variables_inheritance: true,
- scheduling_type: :stage,
- id_tokens: { TEST_ID_TOKEN: { aud: 'https://gitlab.com' } })
+ expect(entry.value).to eq(
+ name: :rspec,
+ before_script: %w[ls pwd],
+ script: %w[rspec],
+ stage: 'test',
+ ignore: false,
+ after_script: %w[cleanup],
+ hooks: { pre_get_sources_script: ['echo hello'] },
+ only: { refs: %w[branches tags] },
+ job_variables: {},
+ root_variables_inheritance: true,
+ scheduling_type: :stage,
+ id_tokens: { TEST_ID_TOKEN: { aud: 'https://gitlab.com' } }
+ )
end
end
end
diff --git a/spec/lib/gitlab/ci/config/entry/pages_spec.rb b/spec/lib/gitlab/ci/config/entry/pages_spec.rb
new file mode 100644
index 00000000000..0ee692a443e
--- /dev/null
+++ b/spec/lib/gitlab/ci/config/entry/pages_spec.rb
@@ -0,0 +1,49 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::Ci::Config::Entry::Pages, feature_category: :pages do
+ subject(:entry) { described_class.new(config) }
+
+ describe 'validation' do
+ context 'when value given is not a hash' do
+ let(:config) { 'value' }
+
+ it 'is invalid' do
+ expect(entry).not_to be_valid
+ expect(entry.errors).to include('pages config should be a hash')
+ end
+ end
+
+ context 'when value is a hash' do
+ context 'when the hash is valid' do
+ let(:config) { { path_prefix: 'prefix' } }
+
+ it 'is valid' do
+ expect(entry).to be_valid
+ expect(entry.value).to eq({
+ path_prefix: 'prefix'
+ })
+ end
+ end
+
+ context 'when path_prefix key is not a string' do
+ let(:config) { { path_prefix: 1 } }
+
+ it 'is invalid' do
+ expect(entry).not_to be_valid
+ expect(entry.errors).to include('pages path prefix should be a string')
+ end
+ end
+
+ context 'when hash contains not allowed keys' do
+ let(:config) { { unknown: 'echo' } }
+
+ it 'is invalid' do
+ expect(entry).not_to be_valid
+ expect(entry.errors).to include('pages config contains unknown keys: unknown')
+ end
+ end
+ end
+ end
+end
diff --git a/spec/lib/gitlab/ci/config/entry/policy_spec.rb b/spec/lib/gitlab/ci/config/entry/policy_spec.rb
index 7093a0a6edf..77a895b75c0 100644
--- a/spec/lib/gitlab/ci/config/entry/policy_spec.rb
+++ b/spec/lib/gitlab/ci/config/entry/policy_spec.rb
@@ -221,8 +221,7 @@ RSpec.describe Gitlab::Ci::Config::Entry::Policy, feature_category: :continuous_
let(:config) { { variables: %w[$VARIABLE] } }
it 'includes default values' do
- expect(entry.value).to eq(refs: %w[branches tags],
- variables: %w[$VARIABLE])
+ expect(entry.value).to eq(refs: %w[branches tags], variables: %w[$VARIABLE])
end
end
end
diff --git a/spec/lib/gitlab/ci/config/entry/processable_spec.rb b/spec/lib/gitlab/ci/config/entry/processable_spec.rb
index 132e75a808b..44e2fdbac37 100644
--- a/spec/lib/gitlab/ci/config/entry/processable_spec.rb
+++ b/spec/lib/gitlab/ci/config/entry/processable_spec.rb
@@ -119,6 +119,20 @@ RSpec.describe Gitlab::Ci::Config::Entry::Processable, feature_category: :pipeli
end
end
+ context 'when script: and trigger: are used together' do
+ let(:config) do
+ {
+ script: 'echo',
+ trigger: 'test-group/test-project'
+ }
+ end
+
+ it 'returns is invalid' do
+ expect(entry).not_to be_valid
+ expect(entry.errors).to include(/these keys cannot be used together: script, trigger/)
+ end
+ end
+
context 'when only: is used with rules:' do
let(:config) { { only: ['merge_requests'], rules: [{ if: '$THIS' }] } }
diff --git a/spec/lib/gitlab/ci/config/entry/root_spec.rb b/spec/lib/gitlab/ci/config/entry/root_spec.rb
index 5fac5298e8e..0370bcbccf5 100644
--- a/spec/lib/gitlab/ci/config/entry/root_spec.rb
+++ b/spec/lib/gitlab/ci/config/entry/root_spec.rb
@@ -31,7 +31,7 @@ RSpec.describe Gitlab::Ci::Config::Entry::Root do
context 'when top-level entries are defined' do
let(:hash) do
{
- before_script: %w(ls pwd),
+ before_script: %w[ls pwd],
image: 'image:1.0',
default: {},
services: ['postgres:9.1', 'mysql:5.5'],
@@ -41,7 +41,7 @@ RSpec.describe Gitlab::Ci::Config::Entry::Root do
VAR3: { value: 'val3', options: %w[val3 val4 val5], description: 'this is var 3 and some options' }
},
after_script: ['make clean'],
- stages: %w(build pages release),
+ stages: %w[build pages release],
cache: { key: 'k', untracked: true, paths: ['public/'] },
rspec: { script: %w[rspec ls] },
spinach: { before_script: [], variables: {}, script: 'spinach' },
@@ -123,7 +123,7 @@ RSpec.describe Gitlab::Ci::Config::Entry::Root do
expect(root.jobs_value[:rspec]).to eq(
{ name: :rspec,
script: %w[rspec ls],
- before_script: %w(ls pwd),
+ before_script: %w[ls pwd],
image: { name: 'image:1.0' },
services: [{ name: 'postgres:9.1' }, { name: 'mysql:5.5' }],
stage: 'test',
@@ -162,7 +162,7 @@ RSpec.describe Gitlab::Ci::Config::Entry::Root do
services: [{ name: "postgres:9.1" }, { name: "mysql:5.5" }],
cache: [{ key: "k", untracked: true, paths: ["public/"], policy: "pull-push", when: 'on_success',
unprotect: false, fallback_keys: [] }],
- only: { refs: %w(branches tags) },
+ only: { refs: %w[branches tags] },
job_variables: { 'VAR' => { value: 'job' } },
root_variables_inheritance: true,
after_script: [],
@@ -176,14 +176,14 @@ RSpec.describe Gitlab::Ci::Config::Entry::Root do
context 'when a mix of top-level and default entries is used' do
let(:hash) do
- { before_script: %w(ls pwd),
+ { before_script: %w[ls pwd],
after_script: ['make clean'],
default: {
image: 'image:1.0',
services: ['postgres:9.1', 'mysql:5.5']
},
variables: { VAR: 'root' },
- stages: %w(build pages),
+ stages: %w[build pages],
cache: { key: 'k', untracked: true, paths: ['public/'] },
rspec: { script: %w[rspec ls] },
spinach: { before_script: [], variables: { VAR: 'job' }, script: 'spinach' } }
@@ -205,7 +205,7 @@ RSpec.describe Gitlab::Ci::Config::Entry::Root do
expect(root.jobs_value).to eq(
rspec: { name: :rspec,
script: %w[rspec ls],
- before_script: %w(ls pwd),
+ before_script: %w[ls pwd],
image: { name: 'image:1.0' },
services: [{ name: 'postgres:9.1' }, { name: 'mysql:5.5' }],
stage: 'test',
diff --git a/spec/lib/gitlab/ci/config/entry/service_spec.rb b/spec/lib/gitlab/ci/config/entry/service_spec.rb
index e36484bb0ae..1f935bebed5 100644
--- a/spec/lib/gitlab/ci/config/entry/service_spec.rb
+++ b/spec/lib/gitlab/ci/config/entry/service_spec.rb
@@ -51,7 +51,7 @@ RSpec.describe Gitlab::Ci::Config::Entry::Service do
context 'when configuration is a hash' do
let(:config) do
- { name: 'postgresql:9.5', alias: 'db', command: %w(cmd run), entrypoint: %w(/bin/sh run) }
+ { name: 'postgresql:9.5', alias: 'db', command: %w[cmd run], entrypoint: %w[/bin/sh run] }
end
describe '#valid?' do
@@ -80,13 +80,13 @@ RSpec.describe Gitlab::Ci::Config::Entry::Service do
describe '#command' do
it "returns service's command" do
- expect(entry.command).to eq %w(cmd run)
+ expect(entry.command).to eq %w[cmd run]
end
end
describe '#entrypoint' do
it "returns service's entrypoint" do
- expect(entry.entrypoint).to eq %w(/bin/sh run)
+ expect(entry.entrypoint).to eq %w[/bin/sh run]
end
end
@@ -99,7 +99,7 @@ RSpec.describe Gitlab::Ci::Config::Entry::Service do
context 'when configuration has ports' do
let(:ports) { [{ number: 80, protocol: 'http', name: 'foobar' }] }
let(:config) do
- { name: 'postgresql:9.5', alias: 'db', command: %w(cmd run), entrypoint: %w(/bin/sh run), ports: ports }
+ { name: 'postgresql:9.5', alias: 'db', command: %w[cmd run], entrypoint: %w[/bin/sh run], ports: ports }
end
let(:entry) { described_class.new(config, with_image_ports: image_ports) }
@@ -198,7 +198,7 @@ RSpec.describe Gitlab::Ci::Config::Entry::Service do
context 'when service has ports' do
let(:ports) { [{ number: 80, protocol: 'http', name: 'foobar' }] }
let(:config) do
- { name: 'postgresql:9.5', command: %w(cmd run), entrypoint: %w(/bin/sh run), ports: ports }
+ { name: 'postgresql:9.5', command: %w[cmd run], entrypoint: %w[/bin/sh run], ports: ports }
end
it 'alias field is mandatory' do
@@ -209,7 +209,7 @@ RSpec.describe Gitlab::Ci::Config::Entry::Service do
context 'when service does not have ports' do
let(:config) do
- { name: 'postgresql:9.5', alias: 'db', command: %w(cmd run), entrypoint: %w(/bin/sh run) }
+ { name: 'postgresql:9.5', alias: 'db', command: %w[cmd run], entrypoint: %w[/bin/sh run] }
end
it 'alias field is optional' do
diff --git a/spec/lib/gitlab/ci/config/extendable/entry_spec.rb b/spec/lib/gitlab/ci/config/extendable/entry_spec.rb
index 69aa3bab77a..b57a56b8389 100644
--- a/spec/lib/gitlab/ci/config/extendable/entry_spec.rb
+++ b/spec/lib/gitlab/ci/config/extendable/entry_spec.rb
@@ -128,8 +128,7 @@ RSpec.describe Gitlab::Ci::Config::Extendable::Entry do
it 'raises an error' do
expect { subject.extend! }
- .to raise_error(described_class::InvalidExtensionError,
- /invalid base hash/)
+ .to raise_error(described_class::InvalidExtensionError, /invalid base hash/)
end
end
@@ -140,8 +139,7 @@ RSpec.describe Gitlab::Ci::Config::Extendable::Entry do
it 'raises an error' do
expect { subject.extend! }
- .to raise_error(described_class::InvalidExtensionError,
- /unknown key/)
+ .to raise_error(described_class::InvalidExtensionError, /unknown key/)
end
end
@@ -178,7 +176,7 @@ RSpec.describe Gitlab::Ci::Config::Extendable::Entry do
{
first: { script: 'my value', image: 'ubuntu' },
second: { image: 'alpine' },
- test: { extends: %w(first second) }
+ test: { extends: %w[first second] }
}
end
@@ -186,7 +184,7 @@ RSpec.describe Gitlab::Ci::Config::Extendable::Entry do
{
first: { script: 'my value', image: 'ubuntu' },
second: { image: 'alpine' },
- test: { extends: %w(first second), script: 'my value', image: 'alpine' }
+ test: { extends: %w[first second], script: 'my value', image: 'alpine' }
}
end
@@ -230,8 +228,7 @@ RSpec.describe Gitlab::Ci::Config::Extendable::Entry do
it 'raises an error' do
expect { subject.extend! }
- .to raise_error(described_class::CircularDependencyError,
- /circular dependency detected/)
+ .to raise_error(described_class::CircularDependencyError, /circular dependency detected/)
end
end
diff --git a/spec/lib/gitlab/ci/config/external/file/base_spec.rb b/spec/lib/gitlab/ci/config/external/file/base_spec.rb
index 1415dbeb532..bcfab620bd9 100644
--- a/spec/lib/gitlab/ci/config/external/file/base_spec.rb
+++ b/spec/lib/gitlab/ci/config/external/file/base_spec.rb
@@ -60,7 +60,7 @@ RSpec.describe Gitlab::Ci::Config::External::File::Base, feature_category: :pipe
end
context 'when location is not a string' do
- let(:location) { %w(some/file.txt other/file.txt) }
+ let(:location) { %w[some/file.txt other/file.txt] }
it { is_expected.to be_falsy }
end
diff --git a/spec/lib/gitlab/ci/config/external/mapper_spec.rb b/spec/lib/gitlab/ci/config/external/mapper_spec.rb
index 56d1ddee4b8..5f28b45496f 100644
--- a/spec/lib/gitlab/ci/config/external/mapper_spec.rb
+++ b/spec/lib/gitlab/ci/config/external/mapper_spec.rb
@@ -406,8 +406,10 @@ RSpec.describe Gitlab::Ci::Config::External::Mapper, feature_category: :pipeline
end
it 'includes the matched local files' do
- expect(subject).to contain_exactly(an_instance_of(Gitlab::Ci::Config::External::File::Local),
- an_instance_of(Gitlab::Ci::Config::External::File::Local))
+ expect(subject).to contain_exactly(
+ an_instance_of(Gitlab::Ci::Config::External::File::Local),
+ an_instance_of(Gitlab::Ci::Config::External::File::Local)
+ )
expect(subject.map(&:location)).to contain_exactly('myfolder/file1.yml', 'myfolder/file2.yml')
end
@@ -424,8 +426,10 @@ RSpec.describe Gitlab::Ci::Config::External::Mapper, feature_category: :pipeline
let(:project_id) { project.id }
it 'includes the file' do
- expect(subject).to contain_exactly(an_instance_of(Gitlab::Ci::Config::External::File::Remote),
- an_instance_of(Gitlab::Ci::Config::External::File::Local))
+ expect(subject).to contain_exactly(
+ an_instance_of(Gitlab::Ci::Config::External::File::Remote),
+ an_instance_of(Gitlab::Ci::Config::External::File::Local)
+ )
end
end
diff --git a/spec/lib/gitlab/ci/config/header/input_spec.rb b/spec/lib/gitlab/ci/config/header/input_spec.rb
index 5d1fa4a8e6e..df70d1fd7c8 100644
--- a/spec/lib/gitlab/ci/config/header/input_spec.rb
+++ b/spec/lib/gitlab/ci/config/header/input_spec.rb
@@ -40,12 +40,24 @@ RSpec.describe Gitlab::Ci::Config::Header::Input, feature_category: :pipeline_co
end
end
- context 'when has a default value' do
+ context 'when has a string default value' do
let(:input_hash) { { default: 'bar' } }
it_behaves_like 'a valid input'
end
+ context 'when has a numeric default value' do
+ let(:input_hash) { { default: 6.66 } }
+
+ it_behaves_like 'a valid input'
+ end
+
+ context 'when has a boolean default value' do
+ let(:input_hash) { { default: true } }
+
+ it_behaves_like 'a valid input'
+ end
+
context 'when has a description value' do
let(:input_hash) { { description: 'bar' } }
@@ -103,4 +115,21 @@ RSpec.describe Gitlab::Ci::Config::Header::Input, feature_category: :pipeline_co
it_behaves_like 'an invalid input'
end
+
+ context 'when the limit for allowed number of options is reached' do
+ let(:limit) { described_class::ALLOWED_OPTIONS_LIMIT }
+ let(:input_hash) { { default: 'value1', options: options } }
+ let(:options) { Array.new(limit.next) { |i| "value#{i}" } }
+
+ describe '#valid?' do
+ it { is_expected.not_to be_valid }
+ end
+
+ describe '#errors' do
+ it 'returns error about incorrect type' do
+ expect(config.errors).to contain_exactly(
+ "foo config cannot define more than #{limit} options")
+ end
+ end
+ end
end
diff --git a/spec/lib/gitlab/ci/config/interpolation/inputs_spec.rb b/spec/lib/gitlab/ci/config/interpolation/inputs_spec.rb
index b0618081207..57ced4eab98 100644
--- a/spec/lib/gitlab/ci/config/interpolation/inputs_spec.rb
+++ b/spec/lib/gitlab/ci/config/interpolation/inputs_spec.rb
@@ -7,6 +7,90 @@ RSpec.describe Gitlab::Ci::Config::Interpolation::Inputs, feature_category: :pip
let(:specs) { { foo: { default: 'bar' } } }
let(:args) { {} }
+ context 'when inputs are valid strings and have options' do
+ let(:specs) { { foo: { default: 'one', options: %w[one two three] } } }
+
+ context 'and the value is selected' do
+ let(:args) { { foo: 'two' } }
+
+ it 'assigns the selected value' do
+ expect(inputs).to be_valid
+ expect(inputs.to_hash).to eq({ foo: 'two' })
+ end
+ end
+
+ context 'and the value is not selected' do
+ it 'assigns the default value' do
+ expect(inputs).to be_valid
+ expect(inputs.to_hash).to eq({ foo: 'one' })
+ end
+ end
+ end
+
+ context 'when inputs options are valid integers' do
+ let(:specs) { { foo: { default: 1, options: [1, 2, 3, 4, 5], type: 'number' } } }
+
+ context 'and a value of the wrong type is given' do
+ let(:args) { { foo: 'word' } }
+
+ it 'returns an error' do
+ expect(inputs).not_to be_valid
+ expect(inputs.errors).to contain_exactly(
+ "`foo` input: `word` cannot be used because it is not in the list of the allowed options",
+ "`foo` input: provided value is not a number"
+ )
+ end
+ end
+
+ context 'and the value is selected' do
+ let(:args) { { foo: 2 } }
+
+ it 'assigns the selected value' do
+ expect(inputs).to be_valid
+ expect(inputs.to_hash).to eq({ foo: 2 })
+ end
+ end
+
+ context 'and the value is not selected' do
+ it 'assigns the default value' do
+ expect(inputs).to be_valid
+ expect(inputs.to_hash).to eq({ foo: 1 })
+ end
+ end
+ end
+
+ context 'when inputs have invalid type options' do
+ let(:specs) { { foo: { default: true, options: [true, false], type: 'boolean' } } }
+
+ it 'returns an error' do
+ expect(inputs).not_to be_valid
+ expect(inputs.errors).to contain_exactly("`foo` input: Options can only be used with string and number inputs")
+ end
+ end
+
+ context 'when inputs are valid with options but the default value is not in the options' do
+ let(:specs) { { foo: { default: 'coop', options: %w[one two three] } } }
+
+ it 'returns an error' do
+ expect(inputs).not_to be_valid
+ expect(inputs.errors).to contain_exactly(
+ '`foo` input: `coop` cannot be used because it is not in the list of allowed options'
+ )
+ end
+ end
+
+ context 'when inputs are valid with options but the value is not in the options' do
+ let(:specs) { { foo: { default: 'one', options: %w[one two three] } } }
+ let(:args) { { foo: 'niet' } }
+
+ it 'returns an error' do
+ expect(inputs).not_to be_valid
+ expect(inputs.errors).to contain_exactly(
+ '`foo` input: `niet` cannot be used because it is not in the list of allowed options'
+ )
+ end
+ end
+
context 'when given unrecognized inputs' do
let(:specs) { { foo: nil } }
let(:args) { { foo: 'bar', test: 'bar' } }
@@ -164,7 +248,7 @@ RSpec.describe Gitlab::Ci::Config::Interpolation::Inputs, feature_category: :pip
context 'when the value is not a number' do
let(:specs) { { number_input: { type: 'number' } } }
- let(:args) { { number_input: 'NaN' } }
+ let(:args) { { number_input: false } }
it 'is invalid' do
expect(inputs).not_to be_valid
diff --git a/spec/lib/gitlab/ci/jwt_v2_spec.rb b/spec/lib/gitlab/ci/jwt_v2_spec.rb
index d45d8cacb88..c2ced10620b 100644
--- a/spec/lib/gitlab/ci/jwt_v2_spec.rb
+++ b/spec/lib/gitlab/ci/jwt_v2_spec.rb
@@ -33,14 +33,6 @@ RSpec.describe Gitlab::Ci::JwtV2, feature_category: :continuous_integration do
describe '#payload' do
subject(:payload) { ci_job_jwt_v2.payload }
- it 'has correct values for the standard JWT attributes' do
- aggregate_failures do
- expect(payload[:iss]).to eq(Settings.gitlab.base_url)
- expect(payload[:aud]).to eq(Settings.gitlab.base_url)
- expect(payload[:sub]).to eq("project_path:#{project.full_path}:ref_type:branch:ref:#{pipeline.source_ref}")
- end
- end
-
it 'includes user identities when enabled' do
expect(user).to receive(:pass_user_identities_to_ci_jwt).and_return(true)
identities = payload[:user_identities].map { |identity| identity.slice(:extern_uid, :provider) }
@@ -53,6 +45,34 @@ RSpec.describe Gitlab::Ci::JwtV2, feature_category: :continuous_integration do
expect(payload).not_to include(:user_identities)
end
+ context 'when oidc_issuer_url is disabled' do
+ before do
+ stub_feature_flags(oidc_issuer_url: false)
+ end
+
+ it 'has correct values for the standard JWT attributes' do
+ aggregate_failures do
+ expect(payload[:iss]).to eq(Settings.gitlab.base_url)
+ expect(payload[:aud]).to eq(Settings.gitlab.base_url)
+ expect(payload[:sub]).to eq("project_path:#{project.full_path}:ref_type:branch:ref:#{pipeline.source_ref}")
+ end
+ end
+ end
+
+ context 'when oidc_issuer_url is enabled' do
+ before do
+ stub_feature_flags(oidc_issuer_url: true)
+ end
+
+ it 'has correct values for the standard JWT attributes' do
+ aggregate_failures do
+ expect(payload[:iss]).to eq(Gitlab.config.gitlab.url)
+ expect(payload[:aud]).to eq(Settings.gitlab.base_url)
+ expect(payload[:sub]).to eq("project_path:#{project.full_path}:ref_type:branch:ref:#{pipeline.source_ref}")
+ end
+ end
+ end
+
context 'when given an aud' do
let(:aud) { 'AWS' }
diff --git a/spec/lib/gitlab/ci/parsers/sbom/cyclonedx_properties_spec.rb b/spec/lib/gitlab/ci/parsers/sbom/cyclonedx_properties_spec.rb
index dacbe07c8b3..2c57106b07c 100644
--- a/spec/lib/gitlab/ci/parsers/sbom/cyclonedx_properties_spec.rb
+++ b/spec/lib/gitlab/ci/parsers/sbom/cyclonedx_properties_spec.rb
@@ -42,15 +42,16 @@ RSpec.describe Gitlab::Ci::Parsers::Sbom::CyclonedxProperties, feature_category:
it { is_expected.to be_nil }
end
- context 'when no dependency_scanning properties are present' do
+ context 'when no dependency_scanning or container_scanning properties are present' do
let(:properties) do
[
{ 'name' => 'gitlab:meta:schema_version', 'value' => '1' }
]
end
- it 'does not call dependency_scanning parser' do
+ it 'does not call source parsers' do
expect(Gitlab::Ci::Parsers::Sbom::Source::DependencyScanning).not_to receive(:source)
+ expect(Gitlab::Ci::Parsers::Sbom::Source::ContainerScanning).not_to receive(:source)
parse_source_from_properties
end
@@ -85,4 +86,35 @@ RSpec.describe Gitlab::Ci::Parsers::Sbom::CyclonedxProperties, feature_category:
parse_source_from_properties
end
end
+
+ context 'when container_scanning properties are present' do
+ let(:properties) do
+ [
+ { 'name' => 'gitlab:meta:schema_version', 'value' => '1' },
+ { 'name' => 'gitlab:container_scanning:image:name', 'value' => 'photon' },
+ { 'name' => 'gitlab:container_scanning:image:tag', 'value' => '5.0-20231007' },
+ { 'name' => 'gitlab:container_scanning:operating_system:name', 'value' => 'Photon OS' },
+ { 'name' => 'gitlab:container_scanning:operating_system:version', 'value' => '5.0' }
+ ]
+ end
+
+ let(:expected_input) do
+ {
+ 'image' => {
+ 'name' => 'photon',
+ 'tag' => '5.0-20231007'
+ },
+ 'operating_system' => {
+ 'name' => 'Photon OS',
+ 'version' => '5.0'
+ }
+ }
+ end
+
+ it 'passes only supported properties to the container scanning parser' do
+ expect(Gitlab::Ci::Parsers::Sbom::Source::ContainerScanning).to receive(:source).with(expected_input)
+
+ parse_source_from_properties
+ end
+ end
end
diff --git a/spec/lib/gitlab/ci/parsers/sbom/source/container_scanning_spec.rb b/spec/lib/gitlab/ci/parsers/sbom/source/container_scanning_spec.rb
new file mode 100644
index 00000000000..410b2c0098a
--- /dev/null
+++ b/spec/lib/gitlab/ci/parsers/sbom/source/container_scanning_spec.rb
@@ -0,0 +1,58 @@
+# frozen_string_literal: true
+
+require 'fast_spec_helper'
+
+RSpec.describe Gitlab::Ci::Parsers::Sbom::Source::ContainerScanning, feature_category: :container_scanning do
+ subject { described_class.source(property_data) }
+
+ context 'when required properties are present' do
+ let(:property_data) do
+ {
+ 'image' => {
+ 'name' => 'photon',
+ 'tag' => '5.0-20231007'
+ },
+ 'operating_system' => {
+ 'name' => 'Photon OS',
+ 'version' => '5.0'
+ }
+ }
+ end
+
+ it 'returns expected source data' do
+ is_expected.to have_attributes(
+ source_type: :container_scanning,
+ data: property_data
+ )
+ end
+ end
+
+ context 'when required properties are missing' do
+ let(:property_data) do
+ {
+ 'operating_system' => {
+ 'name' => 'Photon OS',
+ 'version' => '5.0'
+ }
+ }
+ end
+
+ it { is_expected.to be_nil }
+ end
+
+ context 'when some operating_system properties are missing' do
+ let(:property_data) do
+ {
+ 'image' => {
+ 'name' => 'photon',
+ 'tag' => '5.0-20231007'
+ },
+ 'operating_system' => {
+ 'name' => 'Photon OS'
+ }
+ }
+ end
+
+ it { is_expected.to be_nil }
+ end
+end
diff --git a/spec/lib/gitlab/ci/parsers/security/common_spec.rb b/spec/lib/gitlab/ci/parsers/security/common_spec.rb
index 648b8ac2db9..431a6d94c48 100644
--- a/spec/lib/gitlab/ci/parsers/security/common_spec.rb
+++ b/spec/lib/gitlab/ci/parsers/security/common_spec.rb
@@ -335,7 +335,7 @@ RSpec.describe Gitlab::Ci::Parsers::Security::Common, feature_category: :vulnera
expect(flags).to contain_exactly(
have_attributes(type: 'flagged-as-likely-false-positive', origin: 'post analyzer X', description: 'static string to sink'),
- have_attributes(type: 'flagged-as-likely-false-positive', origin: 'post analyzer Y', description: 'integer to sink')
+ have_attributes(type: 'flagged-as-likely-false-positive', origin: 'post analyzer Y', description: 'integer to sink')
)
end
end
diff --git a/spec/lib/gitlab/ci/parsers/security/secret_detection_spec.rb b/spec/lib/gitlab/ci/parsers/security/secret_detection_spec.rb
index 13999b2a9e5..640bed0d329 100644
--- a/spec/lib/gitlab/ci/parsers/security/secret_detection_spec.rb
+++ b/spec/lib/gitlab/ci/parsers/security/secret_detection_spec.rb
@@ -9,7 +9,7 @@ RSpec.describe Gitlab::Ci::Parsers::Security::SecretDetection do
let(:created_at) { 2.weeks.ago }
context "when parsing valid reports" do
- where(report_format: %i(secret_detection))
+ where(report_format: %i[secret_detection])
with_them do
let(:report) { Gitlab::Ci::Reports::Security::Report.new(artifact.file_type, pipeline, created_at) }
diff --git a/spec/lib/gitlab/ci/pipeline/chain/template_usage_spec.rb b/spec/lib/gitlab/ci/pipeline/chain/template_usage_spec.rb
index ddd0de69d79..70d73a8095c 100644
--- a/spec/lib/gitlab/ci/pipeline/chain/template_usage_spec.rb
+++ b/spec/lib/gitlab/ci/pipeline/chain/template_usage_spec.rb
@@ -21,11 +21,11 @@ RSpec.describe Gitlab::Ci::Pipeline::Chain::TemplateUsage do
expect(command).to(
receive(:yaml_processor_result)
.and_return(
- double(included_templates: %w(Template-1 Template-2))
+ double(included_templates: %w[Template-1 Template-2])
)
)
- %w(Template-1 Template-2).each do |expected_template|
+ %w[Template-1 Template-2].each do |expected_template|
expect(Gitlab::UsageDataCounters::CiTemplateUniqueCounter).to(
receive(:track_unique_project_event)
.with(project: project, template: expected_template, config_source: pipeline.config_source, user: user)
diff --git a/spec/lib/gitlab/ci/pipeline/expression/lexeme/equals_spec.rb b/spec/lib/gitlab/ci/pipeline/expression/lexeme/equals_spec.rb
index ab223ae41fa..eb71cc0f0bc 100644
--- a/spec/lib/gitlab/ci/pipeline/expression/lexeme/equals_spec.rb
+++ b/spec/lib/gitlab/ci/pipeline/expression/lexeme/equals_spec.rb
@@ -49,7 +49,7 @@ RSpec.describe Gitlab::Ci::Pipeline::Expression::Lexeme::Equals do
context 'when left and right are equal' do
where(:left_value, :right_value) do
- [%w(string string)]
+ [%w[string string]]
end
with_them do
diff --git a/spec/lib/gitlab/ci/pipeline/seed/build_spec.rb b/spec/lib/gitlab/ci/pipeline/seed/build_spec.rb
index 54e569f424b..ef9b8f2b82f 100644
--- a/spec/lib/gitlab/ci/pipeline/seed/build_spec.rb
+++ b/spec/lib/gitlab/ci/pipeline/seed/build_spec.rb
@@ -395,7 +395,7 @@ RSpec.describe Gitlab::Ci::Pipeline::Seed::Build, feature_category: :pipeline_co
end
context 'when root_variables_inheritance is an array' do
- let(:root_variables_inheritance) { %w(VAR1 VAR2 VAR3) }
+ let(:root_variables_inheritance) { %w[VAR1 VAR2 VAR3] }
it 'returns calculated yaml variables' do
expect(subject[:yaml_variables]).to match_array(
diff --git a/spec/lib/gitlab/ci/reports/accessibility_reports_comparer_spec.rb b/spec/lib/gitlab/ci/reports/accessibility_reports_comparer_spec.rb
index ad8f1dc11f8..6d8b472a240 100644
--- a/spec/lib/gitlab/ci/reports/accessibility_reports_comparer_spec.rb
+++ b/spec/lib/gitlab/ci/reports/accessibility_reports_comparer_spec.rb
@@ -14,7 +14,7 @@ RSpec.describe Gitlab::Ci::Reports::AccessibilityReportsComparer do
"type" => "error",
"typeCode" => 1,
"message" => "Anchor element found with a valid href attribute, but no link content has been supplied.",
- "context" => %{<a href="/" class="navbar-brand animated"><svg height="36" viewBox="0 0 1...</a>},
+ "context" => %(<a href="/" class="navbar-brand animated"><svg height="36" viewBox="0 0 1...</a>),
"selector" => "#main-nav > div:nth-child(1) > a",
"runner" => "htmlcs",
"runnerExtras" => {}
@@ -29,7 +29,7 @@ RSpec.describe Gitlab::Ci::Reports::AccessibilityReportsComparer do
"type" => "error",
"typeCode" => 1,
"message" => "This element has insufficient contrast at this conformance level.",
- "context" => %{<a href="/stages-devops-lifecycle/" class="main-nav-link">Product</a>},
+ "context" => %(<a href="/stages-devops-lifecycle/" class="main-nav-link">Product</a>),
"selector" => "#main-nav > div:nth-child(2) > ul > li:nth-child(1) > a",
"runner" => "htmlcs",
"runnerExtras" => {}
diff --git a/spec/lib/gitlab/ci/reports/accessibility_reports_spec.rb b/spec/lib/gitlab/ci/reports/accessibility_reports_spec.rb
index af6844491ca..dff59474746 100644
--- a/spec/lib/gitlab/ci/reports/accessibility_reports_spec.rb
+++ b/spec/lib/gitlab/ci/reports/accessibility_reports_spec.rb
@@ -12,7 +12,7 @@ RSpec.describe Gitlab::Ci::Reports::AccessibilityReports do
"type": "error",
"typeCode": 1,
"message": "Anchor element found with a valid href attribute, but no link content has been supplied.",
- "context": %{<a href="/customers/worldline"><svg viewBox="0 0 509 89" xmln...</a>},
+ "context": %(<a href="/customers/worldline"><svg viewBox="0 0 509 89" xmln...</a>),
"selector": "html > body > div:nth-child(9) > div:nth-child(2) > a:nth-child(17)",
"runner": "htmlcs",
"runnerExtras": {}
@@ -22,7 +22,7 @@ RSpec.describe Gitlab::Ci::Reports::AccessibilityReports do
"type": "error",
"typeCode": 1,
"message": "Anchor element found with a valid href attribute, but no link content has been supplied.",
- "context": %{<a href="/customers/equinix"><svg xmlns="http://www.w3.org/...</a>},
+ "context": %(<a href="/customers/equinix"><svg xmlns="http://www.w3.org/...</a>),
"selector": "html > body > div:nth-child(9) > div:nth-child(2) > a:nth-child(18)",
"runner": "htmlcs",
"runnerExtras": {}
diff --git a/spec/lib/gitlab/ci/reports/test_suite_spec.rb b/spec/lib/gitlab/ci/reports/test_suite_spec.rb
index 05f6a8a8cb6..46ab0802200 100644
--- a/spec/lib/gitlab/ci/reports/test_suite_spec.rb
+++ b/spec/lib/gitlab/ci/reports/test_suite_spec.rb
@@ -192,7 +192,7 @@ RSpec.describe Gitlab::Ci::Reports::TestSuite do
end
context 'when there are multiple test cases' do
- let(:status_ordered) { %w(error failed success skipped) }
+ let(:status_ordered) { %w[error failed success skipped] }
before do
test_suite.add_test_case(test_case_success)
diff --git a/spec/lib/gitlab/ci/status/composite_spec.rb b/spec/lib/gitlab/ci/status/composite_spec.rb
index cbf0976c976..e46ad573235 100644
--- a/spec/lib/gitlab/ci/status/composite_spec.rb
+++ b/spec/lib/gitlab/ci/status/composite_spec.rb
@@ -43,28 +43,29 @@ RSpec.describe Gitlab::Ci::Status::Composite, feature_category: :continuous_inte
context 'allow_failure: false' do
where(:build_statuses, :dag, :result, :has_warnings) do
- %i(skipped) | false | 'skipped' | false
- %i(skipped success) | false | 'success' | false
- %i(skipped success) | true | 'skipped' | false
- %i(created) | false | 'created' | false
- %i(preparing) | false | 'preparing' | false
- %i(canceled success skipped) | false | 'canceled' | false
- %i(canceled success skipped) | true | 'skipped' | false
- %i(pending created skipped) | false | 'pending' | false
- %i(pending created skipped success) | false | 'running' | false
- %i(running created skipped success) | false | 'running' | false
- %i(pending created skipped) | true | 'skipped' | false
- %i(pending created skipped success) | true | 'skipped' | false
- %i(running created skipped success) | true | 'skipped' | false
- %i(success waiting_for_resource) | false | 'waiting_for_resource' | false
- %i(success manual) | false | 'manual' | false
- %i(success scheduled) | false | 'scheduled' | false
- %i(created preparing) | false | 'preparing' | false
- %i(created success pending) | false | 'running' | false
- %i(skipped success failed) | false | 'failed' | false
- %i(skipped success failed) | true | 'skipped' | false
- %i(success manual) | true | 'manual' | false
- %i(success failed created) | true | 'running' | false
+ %i[skipped] | false | 'skipped' | false
+ %i[skipped success] | false | 'success' | false
+ %i[skipped success] | true | 'skipped' | false
+ %i[created] | false | 'created' | false
+ %i[preparing] | false | 'preparing' | false
+ %i[canceled success skipped] | false | 'canceled' | false
+ %i[canceled success skipped] | true | 'skipped' | false
+ %i[pending created skipped] | false | 'pending' | false
+ %i[pending created skipped success] | false | 'running' | false
+ %i[running created skipped success] | false | 'running' | false
+ %i[pending created skipped] | true | 'skipped' | false
+ %i[pending created skipped success] | true | 'skipped' | false
+ %i[running created skipped success] | true | 'skipped' | false
+ %i[success waiting_for_resource] | false | 'waiting_for_resource' | false
+ %i[success waiting_for_callback] | false | 'waiting_for_callback' | false
+ %i[success manual] | false | 'manual' | false
+ %i[success scheduled] | false | 'scheduled' | false
+ %i[created preparing] | false | 'preparing' | false
+ %i[created success pending] | false | 'running' | false
+ %i[skipped success failed] | false | 'failed' | false
+ %i[skipped success failed] | true | 'skipped' | false
+ %i[success manual] | true | 'manual' | false
+ %i[success failed created] | true | 'running' | false
end
with_them do
@@ -78,13 +79,13 @@ RSpec.describe Gitlab::Ci::Status::Composite, feature_category: :continuous_inte
context 'allow_failure: true' do
where(:build_statuses, :dag, :result, :has_warnings) do
- %i(manual) | false | 'skipped' | false
- %i(skipped failed) | false | 'success' | true
- %i(skipped failed) | true | 'skipped' | true
- %i(success manual) | true | 'skipped' | false
- %i(success manual) | false | 'success' | false
- %i(created failed) | false | 'created' | true
- %i(preparing manual) | false | 'preparing' | false
+ %i[manual] | false | 'skipped' | false
+ %i[skipped failed] | false | 'success' | true
+ %i[skipped failed] | true | 'skipped' | true
+ %i[success manual] | true | 'skipped' | false
+ %i[success manual] | false | 'success' | false
+ %i[created failed] | false | 'created' | true
+ %i[preparing manual] | false | 'preparing' | false
end
with_them do
diff --git a/spec/lib/gitlab/ci/status/stage/factory_spec.rb b/spec/lib/gitlab/ci/status/stage/factory_spec.rb
index 34e430202c9..98fefea7bdf 100644
--- a/spec/lib/gitlab/ci/status/stage/factory_spec.rb
+++ b/spec/lib/gitlab/ci/status/stage/factory_spec.rb
@@ -22,7 +22,7 @@ RSpec.describe Gitlab::Ci::Status::Stage::Factory, feature_category: :continuous
end
context 'when stage has a core status' do
- (Ci::HasStatus::AVAILABLE_STATUSES - %w(manual skipped scheduled)).each do |core_status|
+ (Ci::HasStatus::AVAILABLE_STATUSES - %w[manual skipped scheduled]).each do |core_status|
context "when core status is #{core_status}" do
let(:stage) { create(:ci_stage, pipeline: pipeline, status: core_status) }
diff --git a/spec/lib/gitlab/ci/status/waiting_for_callback_spec.rb b/spec/lib/gitlab/ci/status/waiting_for_callback_spec.rb
new file mode 100644
index 00000000000..6c833e96137
--- /dev/null
+++ b/spec/lib/gitlab/ci/status/waiting_for_callback_spec.rb
@@ -0,0 +1,37 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::Ci::Status::WaitingForCallback, feature_category: :deployment_management do
+ subject do
+ described_class.new(double, double)
+ end
+
+ describe '#text' do
+ it { expect(subject.text).to eq 'Waiting' }
+ end
+
+ describe '#label' do
+ it { expect(subject.label).to eq 'waiting for callback' }
+ end
+
+ describe '#icon' do
+ it { expect(subject.icon).to eq 'status_pending' }
+ end
+
+ describe '#favicon' do
+ it { expect(subject.favicon).to eq 'favicon_status_pending' }
+ end
+
+ describe '#group' do
+ it { expect(subject.group).to eq 'waiting-for-callback' }
+ end
+
+ describe '#name' do
+ it { expect(subject.name).to eq 'WAITING_FOR_CALLBACK' }
+ end
+
+ describe '#details_path' do
+ it { expect(subject.details_path).to be_nil }
+ end
+end
diff --git a/spec/lib/gitlab/ci/tags/bulk_insert_spec.rb b/spec/lib/gitlab/ci/tags/bulk_insert_spec.rb
index 460ecbb05d0..c5125689207 100644
--- a/spec/lib/gitlab/ci/tags/bulk_insert_spec.rb
+++ b/spec/lib/gitlab/ci/tags/bulk_insert_spec.rb
@@ -13,7 +13,7 @@ RSpec.describe Gitlab::Ci::Tags::BulkInsert do
subject(:service) { described_class.new(statuses) }
describe 'gem version' do
- let(:acceptable_version) { '9.0.1' }
+ let(:acceptable_version) { '10.0.0' }
let(:error_message) do
<<~MESSAGE
diff --git a/spec/lib/gitlab/ci/templates/Jobs/deploy_gitlab_ci_yaml_spec.rb b/spec/lib/gitlab/ci/templates/Jobs/deploy_gitlab_ci_yaml_spec.rb
index acb296082b8..dc9999ab9e4 100644
--- a/spec/lib/gitlab/ci/templates/Jobs/deploy_gitlab_ci_yaml_spec.rb
+++ b/spec/lib/gitlab/ci/templates/Jobs/deploy_gitlab_ci_yaml_spec.rb
@@ -58,7 +58,7 @@ RSpec.describe 'Jobs/Deploy.gitlab-ci.yml' do
context 'with no cluster or agent' do
it 'does not create any kubernetes deployment jobs' do
- expect(build_names).to eq %w(placeholder)
+ expect(build_names).to eq %w[placeholder]
end
end
@@ -68,7 +68,7 @@ RSpec.describe 'Jobs/Deploy.gitlab-ci.yml' do
end
it 'does not create any kubernetes deployment jobs' do
- expect(build_names).to eq %w(placeholder)
+ expect(build_names).to eq %w[placeholder]
end
end
@@ -81,7 +81,7 @@ RSpec.describe 'Jobs/Deploy.gitlab-ci.yml' do
it 'when CI_DEPLOY_FREEZE is present' do
create(:ci_variable, project: project, key: 'CI_DEPLOY_FREEZE', value: 'true')
- expect(build_names).to eq %w(placeholder)
+ expect(build_names).to eq %w[placeholder]
end
it 'when CANARY_ENABLED' do
diff --git a/spec/lib/gitlab/ci/templates/Jobs/sast_iac_latest_gitlab_ci_yaml_spec.rb b/spec/lib/gitlab/ci/templates/Jobs/sast_iac_latest_gitlab_ci_yaml_spec.rb
index 2b9213ea921..86bc9259789 100644
--- a/spec/lib/gitlab/ci/templates/Jobs/sast_iac_latest_gitlab_ci_yaml_spec.rb
+++ b/spec/lib/gitlab/ci/templates/Jobs/sast_iac_latest_gitlab_ci_yaml_spec.rb
@@ -44,7 +44,7 @@ RSpec.describe 'Jobs/SAST-IaC.latest.gitlab-ci.yml', feature_category: :continuo
it 'creates a pipeline with the expected jobs' do
expect(pipeline).to be_merge_request_event
expect(pipeline.errors.full_messages).to be_empty
- expect(build_names).to match_array(%w(kics-iac-sast))
+ expect(build_names).to match_array(%w[kics-iac-sast])
end
end
end
diff --git a/spec/lib/gitlab/ci/templates/auto_devops_gitlab_ci_yaml_spec.rb b/spec/lib/gitlab/ci/templates/auto_devops_gitlab_ci_yaml_spec.rb
index 09ca2678de5..7471dc58e44 100644
--- a/spec/lib/gitlab/ci/templates/auto_devops_gitlab_ci_yaml_spec.rb
+++ b/spec/lib/gitlab/ci/templates/auto_devops_gitlab_ci_yaml_spec.rb
@@ -94,7 +94,7 @@ RSpec.describe 'Auto-DevOps.gitlab-ci.yml', feature_category: :auto_devops do
project.repository.create_branch(pipeline_branch, default_branch)
end
- %w(review_ecs review_fargate).each do |job|
+ %w[review_ecs review_fargate].each do |job|
it_behaves_like 'no ECS job when AUTO_DEVOPS_PLATFORM_TARGET is not present' do
let(:job_name) { job }
end
@@ -142,7 +142,7 @@ RSpec.describe 'Auto-DevOps.gitlab-ci.yml', feature_category: :auto_devops do
context 'when the project has no active cluster' do
it 'only creates a build and a test stage' do
- expect(pipeline.stages_names).to eq(%w(build test))
+ expect(pipeline.stages_names).to eq(%w[build test])
end
it_behaves_like 'no Kubernetes deployment job'
@@ -273,25 +273,25 @@ RSpec.describe 'Auto-DevOps.gitlab-ci.yml', feature_category: :auto_devops do
using RSpec::Parameterized::TableSyntax
where(:case_name, :files, :variables, :include_build_names, :not_include_build_names) do
- 'No match' | { 'README.md' => '' } | {} | %w() | %w(build test)
- 'Buildpack' | { 'README.md' => '' } | { 'BUILDPACK_URL' => 'http://example.com' } | %w(build test) | %w()
- 'Explicit set' | { 'README.md' => '' } | { 'AUTO_DEVOPS_EXPLICITLY_ENABLED' => '1' } | %w(build test) | %w()
- 'Explicit unset' | { 'README.md' => '' } | { 'AUTO_DEVOPS_EXPLICITLY_ENABLED' => '0' } | %w() | %w(build test)
- 'DOCKERFILE_PATH' | { 'README.md' => '' } | { 'DOCKERFILE_PATH' => 'Docker.file' } | %w(build test) | %w()
- 'Dockerfile' | { 'Dockerfile' => '' } | {} | %w(build test) | %w()
- 'Clojure' | { 'project.clj' => '' } | {} | %w(build test) | %w()
- 'Go modules' | { 'go.mod' => '' } | {} | %w(build test) | %w()
- 'Go gb' | { 'src/gitlab.com/gopackage.go' => '' } | {} | %w(build test) | %w()
- 'Gradle' | { 'gradlew' => '' } | {} | %w(build test) | %w()
- 'Java' | { 'pom.xml' => '' } | {} | %w(build test) | %w()
- 'Multi-buildpack' | { '.buildpacks' => '' } | {} | %w(build test) | %w()
- 'NodeJS' | { 'package.json' => '' } | {} | %w(build test) | %w()
- 'PHP' | { 'composer.json' => '' } | {} | %w(build test) | %w()
- 'Play' | { 'conf/application.conf' => '' } | {} | %w(build test) | %w()
- 'Python' | { 'Pipfile' => '' } | {} | %w(build test) | %w()
- 'Ruby' | { 'Gemfile' => '' } | {} | %w(build test) | %w()
- 'Scala' | { 'build.sbt' => '' } | {} | %w(build test) | %w()
- 'Static' | { '.static' => '' } | {} | %w(build test) | %w()
+ 'No match' | { 'README.md' => '' } | {} | %w[] | %w[build test]
+ 'Buildpack' | { 'README.md' => '' } | { 'BUILDPACK_URL' => 'http://example.com' } | %w[build test] | %w[]
+ 'Explicit set' | { 'README.md' => '' } | { 'AUTO_DEVOPS_EXPLICITLY_ENABLED' => '1' } | %w[build test] | %w[]
+ 'Explicit unset' | { 'README.md' => '' } | { 'AUTO_DEVOPS_EXPLICITLY_ENABLED' => '0' } | %w[] | %w[build test]
+ 'DOCKERFILE_PATH' | { 'README.md' => '' } | { 'DOCKERFILE_PATH' => 'Docker.file' } | %w[build test] | %w[]
+ 'Dockerfile' | { 'Dockerfile' => '' } | {} | %w[build test] | %w[]
+ 'Clojure' | { 'project.clj' => '' } | {} | %w[build test] | %w[]
+ 'Go modules' | { 'go.mod' => '' } | {} | %w[build test] | %w[]
+ 'Go gb' | { 'src/gitlab.com/gopackage.go' => '' } | {} | %w[build test] | %w[]
+ 'Gradle' | { 'gradlew' => '' } | {} | %w[build test] | %w[]
+ 'Java' | { 'pom.xml' => '' } | {} | %w[build test] | %w[]
+ 'Multi-buildpack' | { '.buildpacks' => '' } | {} | %w[build test] | %w[]
+ 'NodeJS' | { 'package.json' => '' } | {} | %w[build test] | %w[]
+ 'PHP' | { 'composer.json' => '' } | {} | %w[build test] | %w[]
+ 'Play' | { 'conf/application.conf' => '' } | {} | %w[build test] | %w[]
+ 'Python' | { 'Pipfile' => '' } | {} | %w[build test] | %w[]
+ 'Ruby' | { 'Gemfile' => '' } | {} | %w[build test] | %w[]
+ 'Scala' | { 'build.sbt' => '' } | {} | %w[build test] | %w[]
+ 'Static' | { '.static' => '' } | {} | %w[build test] | %w[]
end
with_them do
diff --git a/spec/lib/gitlab/ci/variables/collection/item_spec.rb b/spec/lib/gitlab/ci/variables/collection/item_spec.rb
index d96c8f1bd0c..aa612899f4b 100644
--- a/spec/lib/gitlab/ci/variables/collection/item_spec.rb
+++ b/spec/lib/gitlab/ci/variables/collection/item_spec.rb
@@ -123,11 +123,11 @@ RSpec.describe Gitlab::Ci::Variables::Collection::Item, feature_category: :secre
},
"simple variable reference": {
variable: { key: 'VAR', value: 'something_$VAR2' },
- expected_depends_on: %w(VAR2)
+ expected_depends_on: %w[VAR2]
},
"complex expansion": {
variable: { key: 'VAR', value: 'something_${VAR2}_$VAR3' },
- expected_depends_on: %w(VAR2 VAR3)
+ expected_depends_on: %w[VAR2 VAR3]
},
"complex expansion in raw variable": {
variable: { key: 'VAR', value: 'something_${VAR2}_$VAR3', raw: true },
@@ -135,7 +135,7 @@ RSpec.describe Gitlab::Ci::Variables::Collection::Item, feature_category: :secre
},
"complex expansions for Windows": {
variable: { key: 'variable3', value: 'key%variable%%variable2%' },
- expected_depends_on: %w(variable variable2)
+ expected_depends_on: %w[variable variable2]
}
}
end
@@ -282,7 +282,7 @@ RSpec.describe Gitlab::Ci::Variables::Collection::Item, feature_category: :secre
it '#depends_on contains names of dependencies' do
runner_variable = described_class.new(key: 'CI_VAR', value: '${CI_VAR_2}-123-$CI_VAR_3')
- expect(runner_variable.depends_on).to eq(%w(CI_VAR_2 CI_VAR_3))
+ expect(runner_variable.depends_on).to eq(%w[CI_VAR_2 CI_VAR_3])
end
end
diff --git a/spec/lib/gitlab/ci/yaml_processor/dag_spec.rb b/spec/lib/gitlab/ci/yaml_processor/dag_spec.rb
index 082febacbd7..496d89403d5 100644
--- a/spec/lib/gitlab/ci/yaml_processor/dag_spec.rb
+++ b/spec/lib/gitlab/ci/yaml_processor/dag_spec.rb
@@ -3,38 +3,48 @@
require 'fast_spec_helper'
require 'tsort'
-RSpec.describe Gitlab::Ci::YamlProcessor::Dag do
+RSpec.describe Gitlab::Ci::YamlProcessor::Dag, feature_category: :pipeline_composition do
let(:nodes) { {} }
subject(:result) { described_class.new(nodes).tsort }
context 'when it is a regular pipeline' do
let(:nodes) do
- { 'job_c' => %w(job_b job_d), 'job_d' => %w(job_a), 'job_b' => %w(job_a), 'job_a' => %w() }
+ { 'job_c' => %w[job_b job_d], 'job_d' => %w[job_a], 'job_b' => %w[job_a], 'job_a' => %w[] }
end
it 'returns ordered jobs' do
- expect(result).to eq(%w(job_a job_b job_d job_c))
+ expect(result).to eq(%w[job_a job_b job_d job_c])
end
end
context 'when there is a circular dependency' do
let(:nodes) do
- { 'job_a' => %w(job_c), 'job_b' => %w(job_a), 'job_c' => %w(job_b) }
+ { 'job_a' => %w[job_c], 'job_b' => %w[job_a], 'job_c' => %w[job_b] }
end
- it 'raises TSort::Cyclic' do
+ it 'raises TSort::Cyclic error' do
expect { result }.to raise_error(TSort::Cyclic, /topological sort failed/)
end
+
+ context 'when a job has a self-dependency' do
+ let(:nodes) do
+ { 'job_a' => %w[job_a] }
+ end
+
+ it 'raises TSort::Cyclic error' do
+ expect { result }.to raise_error(TSort::Cyclic, "self-dependency: job_a")
+ end
+ end
end
context 'when there are some missing jobs' do
let(:nodes) do
- { 'job_a' => %w(job_d job_f), 'job_b' => %w(job_a job_c job_e) }
+ { 'job_a' => %w[job_d job_f], 'job_b' => %w[job_a job_c job_e] }
end
it 'ignores the missing ones and returns in a valid order' do
- expect(result).to eq(%w(job_d job_f job_a job_c job_e job_b))
+ expect(result).to eq(%w[job_d job_f job_a job_c job_e job_b])
end
end
end
diff --git a/spec/lib/gitlab/ci/yaml_processor_spec.rb b/spec/lib/gitlab/ci/yaml_processor_spec.rb
index 81bc8c7ab9a..f01c1c7d053 100644
--- a/spec/lib/gitlab/ci/yaml_processor_spec.rb
+++ b/spec/lib/gitlab/ci/yaml_processor_spec.rb
@@ -1510,7 +1510,7 @@ module Gitlab
it 'correctly extends rspec job' do
expect(config_processor.builds).to be_one
- expect(subject.dig(:options, :script)).to eq %w(test)
+ expect(subject.dig(:options, :script)).to eq %w[test]
expect(subject.dig(:options, :image, :name)).to eq 'ruby:alpine'
end
end
@@ -1595,7 +1595,7 @@ module Gitlab
it 'correctly extends rspec job' do
expect(config_processor.builds).to be_one
expect(subject.dig(:options, :before_script)).to eq ["bundle install"]
- expect(subject.dig(:options, :script)).to eq %w(rspec)
+ expect(subject.dig(:options, :script)).to eq %w[rspec]
expect(subject.dig(:options, :image, :name)).to eq 'image:test'
expect(subject.dig(:when)).to eq 'always'
end
@@ -2386,7 +2386,7 @@ module Gitlab
end
context 'dependencies to builds' do
- let(:dependencies) { %w(build1 build2) }
+ let(:dependencies) { %w[build1 build2] }
it { is_expected.to be_valid }
end
@@ -2457,7 +2457,7 @@ module Gitlab
end
context 'needs a job from the same stage' do
- let(:needs) { %w(test2) }
+ let(:needs) { %w[test2] }
it 'creates jobs with valid specifications' do
expect(subject.builds.size).to eq(7)
@@ -2494,7 +2494,7 @@ module Gitlab
end
context 'needs two builds' do
- let(:needs) { %w(build1 build2) }
+ let(:needs) { %w[build1 build2] }
it "does create jobs with valid specification" do
expect(subject.builds.size).to eq(7)
@@ -2578,7 +2578,7 @@ module Gitlab
end
context 'needs parallel job' do
- let(:needs) { %w(parallel) }
+ let(:needs) { %w[parallel] }
it "does create jobs with valid specification" do
expect(subject.builds.size).to eq(7)
@@ -2707,7 +2707,7 @@ module Gitlab
context 'duplicate needs' do
context 'when needs are specified in an array' do
- let(:needs) { %w(build1 build1) }
+ let(:needs) { %w[build1 build1] }
it_behaves_like 'returns errors', 'test1 has the following needs duplicated: build1.'
end
@@ -2736,8 +2736,8 @@ module Gitlab
end
context 'needs and dependencies that are mismatching' do
- let(:needs) { %w(build1) }
- let(:dependencies) { %w(build2) }
+ let(:needs) { %w[build1] }
+ let(:dependencies) { %w[build2] }
it_behaves_like 'returns errors', 'jobs:test1 dependencies the build2 should be part of needs'
end
@@ -2750,13 +2750,13 @@ module Gitlab
]
end
- let(:dependencies) { %w(build3) }
+ let(:dependencies) { %w[build3] }
it_behaves_like 'returns errors', 'jobs:test1 dependencies the build3 should be part of needs'
end
context 'needs with an array type and dependency with a string type' do
- let(:needs) { %w(build1) }
+ let(:needs) { %w[build1] }
let(:dependencies) { 'deploy' }
it_behaves_like 'returns errors', 'jobs:test1 dependencies should be an array of strings'
@@ -2764,7 +2764,7 @@ module Gitlab
context 'needs with a string type and dependency with an array type' do
let(:needs) { 'build1' }
- let(:dependencies) { %w(deploy) }
+ let(:dependencies) { %w[deploy] }
it_behaves_like 'returns errors', 'jobs:test1:needs config can only be a hash or an array'
end
@@ -3252,7 +3252,7 @@ module Gitlab
end
context 'returns errors if job stage is not a defined stage' do
- let(:config) { YAML.dump({ stages: %w(build test), rspec: { script: "test", stage: "acceptance" } }) }
+ let(:config) { YAML.dump({ stages: %w[build test], rspec: { script: "test", stage: "acceptance" } }) }
it_behaves_like 'returns errors', 'rspec job: chosen stage does not exist; available stages are .pre, build, test, .post'
end
@@ -3288,37 +3288,37 @@ module Gitlab
end
context 'returns errors if job artifacts:name is not an a string' do
- let(:config) { YAML.dump({ stages: %w(build test), rspec: { script: "test", artifacts: { name: 1 } } }) }
+ let(:config) { YAML.dump({ stages: %w[build test], rspec: { script: "test", artifacts: { name: 1 } } }) }
it_behaves_like 'returns errors', 'jobs:rspec:artifacts name should be a string'
end
context 'returns errors if job artifacts:when is not an a predefined value' do
- let(:config) { YAML.dump({ stages: %w(build test), rspec: { script: "test", artifacts: { when: 1 } } }) }
+ let(:config) { YAML.dump({ stages: %w[build test], rspec: { script: "test", artifacts: { when: 1 } } }) }
it_behaves_like 'returns errors', 'jobs:rspec:artifacts when should be one of: on_success, on_failure, always'
end
context 'returns errors if job artifacts:expire_in is not an a string' do
- let(:config) { YAML.dump({ stages: %w(build test), rspec: { script: "test", artifacts: { expire_in: 1 } } }) }
+ let(:config) { YAML.dump({ stages: %w[build test], rspec: { script: "test", artifacts: { expire_in: 1 } } }) }
it_behaves_like 'returns errors', 'jobs:rspec:artifacts expire in should be a duration'
end
context 'returns errors if job artifacts:expire_in is not an a valid duration' do
- let(:config) { YAML.dump({ stages: %w(build test), rspec: { script: "test", artifacts: { expire_in: "7 elephants" } } }) }
+ let(:config) { YAML.dump({ stages: %w[build test], rspec: { script: "test", artifacts: { expire_in: "7 elephants" } } }) }
it_behaves_like 'returns errors', 'jobs:rspec:artifacts expire in should be a duration'
end
context 'returns errors if job artifacts:untracked is not an array of strings' do
- let(:config) { YAML.dump({ stages: %w(build test), rspec: { script: "test", artifacts: { untracked: "string" } } }) }
+ let(:config) { YAML.dump({ stages: %w[build test], rspec: { script: "test", artifacts: { untracked: "string" } } }) }
it_behaves_like 'returns errors', 'jobs:rspec:artifacts untracked should be a boolean value'
end
context 'returns errors if job artifacts:paths is not an array of strings' do
- let(:config) { YAML.dump({ stages: %w(build test), rspec: { script: "test", artifacts: { paths: "string" } } }) }
+ let(:config) { YAML.dump({ stages: %w[build test], rspec: { script: "test", artifacts: { paths: "string" } } }) }
it_behaves_like 'returns errors', 'jobs:rspec:artifacts paths should be an array of strings'
end
@@ -3342,49 +3342,49 @@ module Gitlab
end
context 'returns errors if job cache:key is not an a string' do
- let(:config) { YAML.dump({ stages: %w(build test), rspec: { script: "test", cache: { key: 1 } } }) }
+ let(:config) { YAML.dump({ stages: %w[build test], rspec: { script: "test", cache: { key: 1 } } }) }
it_behaves_like 'returns errors', "jobs:rspec:cache:key should be a hash, a string or a symbol"
end
context 'returns errors if job cache:key:files is not an array of strings' do
- let(:config) { YAML.dump({ stages: %w(build test), rspec: { script: "test", cache: { key: { files: [1] } } } }) }
+ let(:config) { YAML.dump({ stages: %w[build test], rspec: { script: "test", cache: { key: { files: [1] } } } }) }
it_behaves_like 'returns errors', 'jobs:rspec:cache:key:files config should be an array of strings'
end
context 'returns errors if job cache:key:files is an empty array' do
- let(:config) { YAML.dump({ stages: %w(build test), rspec: { script: "test", cache: { key: { files: [] } } } }) }
+ let(:config) { YAML.dump({ stages: %w[build test], rspec: { script: "test", cache: { key: { files: [] } } } }) }
it_behaves_like 'returns errors', 'jobs:rspec:cache:key:files config requires at least 1 item'
end
context 'returns errors if job defines only cache:key:prefix' do
- let(:config) { YAML.dump({ stages: %w(build test), rspec: { script: "test", cache: { key: { prefix: 'prefix-key' } } } }) }
+ let(:config) { YAML.dump({ stages: %w[build test], rspec: { script: "test", cache: { key: { prefix: 'prefix-key' } } } }) }
it_behaves_like 'returns errors', 'jobs:rspec:cache:key config missing required keys: files'
end
context 'returns errors if job cache:key:prefix is not an a string' do
- let(:config) { YAML.dump({ stages: %w(build test), rspec: { script: "test", cache: { key: { prefix: 1, files: ['file'] } } } }) }
+ let(:config) { YAML.dump({ stages: %w[build test], rspec: { script: "test", cache: { key: { prefix: 1, files: ['file'] } } } }) }
it_behaves_like 'returns errors', 'jobs:rspec:cache:key:prefix config should be a string or symbol'
end
context "returns errors if job cache:untracked is not an array of strings" do
- let(:config) { YAML.dump({ stages: %w(build test), rspec: { script: "test", cache: { untracked: "string" } } }) }
+ let(:config) { YAML.dump({ stages: %w[build test], rspec: { script: "test", cache: { untracked: "string" } } }) }
it_behaves_like 'returns errors', "jobs:rspec:cache:untracked config should be a boolean value"
end
context "returns errors if job cache:paths is not an array of strings" do
- let(:config) { YAML.dump({ stages: %w(build test), rspec: { script: "test", cache: { paths: "string" } } }) }
+ let(:config) { YAML.dump({ stages: %w[build test], rspec: { script: "test", cache: { paths: "string" } } }) }
it_behaves_like 'returns errors', "jobs:rspec:cache:paths config should be an array of strings"
end
context "returns errors if job dependencies is not an array of strings" do
- let(:config) { YAML.dump({ stages: %w(build test), rspec: { script: "test", dependencies: "string" } }) }
+ let(:config) { YAML.dump({ stages: %w[build test], rspec: { script: "test", dependencies: "string" } }) }
it_behaves_like 'returns errors', "jobs:rspec dependencies should be an array of strings"
end
@@ -3433,7 +3433,24 @@ module Gitlab
YAML
end
- it_behaves_like 'returns errors', 'The pipeline has circular dependencies'
+ it_behaves_like 'returns errors', 'The pipeline has circular dependencies: topological sort failed: ["job_a", "job_c", "job_b"]'
+
+ context 'when a job has a self-dependency' do
+ let(:config) do
+ <<~YAML
+ job_0:
+ stage: test
+ script: build
+
+ job:
+ stage: test
+ script: build
+ needs: [job_0, job]
+ YAML
+ end
+
+ it_behaves_like 'returns errors', 'The pipeline has circular dependencies: self-dependency: job'
+ end
end
end
@@ -3668,6 +3685,70 @@ module Gitlab
it { is_expected.to be_valid }
end
end
+
+ context 'for pages jobs', feature_category: :pages do
+ context 'on publish option' do
+ context 'when not in a pages job' do
+ let(:config) do
+ <<-EOYML
+ not-pages:
+ script: echo
+ publish: 'foo'
+ EOYML
+ end
+
+ it_behaves_like 'returns errors', 'jobs:not-pages publish can only be used within a `pages` job'
+ end
+
+ context 'when in a pages job' do
+ let(:config) do
+ <<-EOYML
+ pages:
+ script: echo
+ publish: 'foo'
+ EOYML
+ end
+
+ it { is_expected.to be_valid }
+
+ it 'sets the publish configuration' do
+ expect(subject.builds.first[:options][:publish]).to eq('foo')
+ end
+ end
+ end
+
+ context 'on pages option' do
+ context 'when not in a pages job' do
+ let(:config) do
+ <<-EOYML
+ not-pages:
+ script: echo
+ pages:
+ path_prefix: 'foo'
+ EOYML
+ end
+
+ it_behaves_like 'returns errors', 'jobs:not-pages pages can only be used within a `pages` job'
+ end
+
+ context 'when in a pages job' do
+ let(:config) do
+ <<-EOYML
+ pages:
+ script: echo
+ pages:
+ path_prefix: 'foo'
+ EOYML
+ end
+
+ it { is_expected.to be_valid }
+
+ it 'sets the pages configuration' do
+ expect(subject.builds.first[:options][:pages]).to eq(path_prefix: 'foo')
+ end
+ end
+ end
+ end
end
end
end
diff --git a/spec/lib/gitlab/composer/version_index_spec.rb b/spec/lib/gitlab/composer/version_index_spec.rb
index 63efa8cae95..c5bc6dc0195 100644
--- a/spec/lib/gitlab/composer/version_index_spec.rb
+++ b/spec/lib/gitlab/composer/version_index_spec.rb
@@ -83,32 +83,6 @@ RSpec.describe Gitlab::Composer::VersionIndex, feature_category: :package_regist
it_behaves_like 'returns the packages json'
end
-
- context 'with composer_use_ssh_source_urls disabled' do
- before do
- stub_feature_flags(composer_use_ssh_source_urls: false)
- end
-
- context 'with a public project' do
- it_behaves_like 'returns the packages json'
- end
-
- context 'with an internal project' do
- before do
- project.update!(visibility: Gitlab::VisibilityLevel::INTERNAL)
- end
-
- it_behaves_like 'returns the packages json'
- end
-
- context 'with a private project' do
- before do
- project.update!(visibility: Gitlab::VisibilityLevel::PRIVATE)
- end
-
- it_behaves_like 'returns the packages json'
- end
- end
end
describe '#sha' do
diff --git a/spec/lib/gitlab/config/entry/factory_spec.rb b/spec/lib/gitlab/config/entry/factory_spec.rb
index be4dfd31651..bbbba0cf7cd 100644
--- a/spec/lib/gitlab/config/entry/factory_spec.rb
+++ b/spec/lib/gitlab/config/entry/factory_spec.rb
@@ -21,16 +21,16 @@ RSpec.describe Gitlab::Config::Entry::Factory do
context 'when setting a concrete value' do
it 'creates entry with valid value' do
entry = factory
- .value(%w(ls pwd))
+ .value(%w[ls pwd])
.create!
- expect(entry.value).to eq %w(ls pwd)
+ expect(entry.value).to eq %w[ls pwd]
end
context 'when setting description' do
before do
factory
- .value(%w(ls pwd))
+ .value(%w[ls pwd])
.with(description: 'test description')
end
@@ -41,7 +41,7 @@ RSpec.describe Gitlab::Config::Entry::Factory do
it 'creates entry with description' do
entry = factory.create!
- expect(entry.value).to eq %w(ls pwd)
+ expect(entry.value).to eq %w[ls pwd]
expect(entry.description).to eq 'test description'
end
end
@@ -49,7 +49,7 @@ RSpec.describe Gitlab::Config::Entry::Factory do
context 'when setting inherit' do
before do
factory
- .value(%w(ls pwd))
+ .value(%w[ls pwd])
.with(inherit: true)
end
@@ -61,7 +61,7 @@ RSpec.describe Gitlab::Config::Entry::Factory do
context 'when setting key' do
it 'creates entry with custom key' do
entry = factory
- .value(%w(ls pwd))
+ .value(%w[ls pwd])
.with(key: 'test key')
.create!
diff --git a/spec/lib/gitlab/config/entry/validators_spec.rb b/spec/lib/gitlab/config/entry/validators_spec.rb
index 6fa9f9d0767..e13c09f97ca 100644
--- a/spec/lib/gitlab/config/entry/validators_spec.rb
+++ b/spec/lib/gitlab/config/entry/validators_spec.rb
@@ -35,7 +35,7 @@ RSpec.describe Gitlab::Config::Entry::Validators, feature_category: :pipeline_co
expect(instance.valid?).to be(valid_result)
unless valid_result
- expect(instance.errors.messages_for(:config)).to include /please use only one of the following keys: foo, bar/
+ expect(instance.errors.messages_for(:config)).to include(/these keys cannot be used together: foo, bar/)
end
end
end
diff --git a/spec/lib/gitlab/config_checker/puma_rugged_checker_spec.rb b/spec/lib/gitlab/config_checker/puma_rugged_checker_spec.rb
deleted file mode 100644
index afee3c5536e..00000000000
--- a/spec/lib/gitlab/config_checker/puma_rugged_checker_spec.rb
+++ /dev/null
@@ -1,65 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-RSpec.describe Gitlab::ConfigChecker::PumaRuggedChecker do
- describe '#check' do
- subject { described_class.check }
-
- context 'application is not puma' do
- before do
- allow(Gitlab::Runtime).to receive(:puma?).and_return(false)
- end
-
- it { is_expected.to be_empty }
- end
-
- context 'application is puma' do
- let(:notice_multi_threaded_puma_with_rugged) do
- {
- type: 'warning',
- message: 'Puma is running with a thread count above 1 and the Rugged '\
- 'service is enabled. This may decrease performance in some environments. '\
- 'See our <a href="https://docs.gitlab.com/ee/administration/operations/puma.html#performance-caveat-when-using-puma-with-rugged">documentation</a> '\
- 'for details of this issue.'
- }
- end
-
- before do
- allow(Gitlab::Runtime).to receive(:puma?).and_return(true)
- allow(described_class).to receive(:running_puma_with_multiple_threads?).and_return(multithreaded_puma)
- allow(described_class).to receive(:rugged_enabled_through_feature_flag?).and_return(rugged_enabled)
- end
-
- context 'not multithreaded_puma and rugged API enabled' do
- let(:multithreaded_puma) { false }
- let(:rugged_enabled) { true }
-
- it { is_expected.to be_empty }
- end
-
- context 'not multithreaded_puma and rugged API is not enabled' do
- let(:multithreaded_puma) { false }
- let(:rugged_enabled) { false }
-
- it { is_expected.to be_empty }
- end
-
- context 'multithreaded_puma and rugged API is not enabled' do
- let(:multithreaded_puma) { true }
- let(:rugged_enabled) { false }
-
- it { is_expected.to be_empty }
- end
-
- context 'multithreaded_puma and rugged API is enabled' do
- let(:multithreaded_puma) { true }
- let(:rugged_enabled) { true }
-
- it 'report multi_threaded_puma_with_rugged notices' do
- is_expected.to contain_exactly(notice_multi_threaded_puma_with_rugged)
- end
- end
- end
- end
-end
diff --git a/spec/lib/gitlab/conflict/file_spec.rb b/spec/lib/gitlab/conflict/file_spec.rb
index 6ea8e6c6706..49252a6537c 100644
--- a/spec/lib/gitlab/conflict/file_spec.rb
+++ b/spec/lib/gitlab/conflict/file_spec.rb
@@ -58,7 +58,7 @@ RSpec.describe Gitlab::Conflict::File do
it 'returns a file containing only the chosen parts of the resolved sections' do
expect(resolved_lines.chunk { |line| line.type || 'both' }.map(&:first))
- .to eq(%w(both new both old both new both))
+ .to eq(%w[both new both old both new both])
end
end
@@ -193,7 +193,7 @@ RSpec.describe Gitlab::Conflict::File do
it 'sets conflict to true for sections with only changed lines' do
conflict_file.sections.select { |section| section[:conflict] }.each do |section|
section[:lines].each do |line|
- expect(line.type).to be_in(%w(new old))
+ expect(line.type).to be_in(%w[new old])
end
end
end
diff --git a/spec/lib/gitlab/data_builder/build_spec.rb b/spec/lib/gitlab/data_builder/build_spec.rb
index 66890315ee8..7afd16f53e5 100644
--- a/spec/lib/gitlab/data_builder/build_spec.rb
+++ b/spec/lib/gitlab/data_builder/build_spec.rb
@@ -49,7 +49,7 @@ RSpec.describe Gitlab::DataBuilder::Build, feature_category: :integrations do
it { expect(data[:commit][:id]).to eq(ci_build.pipeline.id) }
it { expect(data[:runner][:id]).to eq(ci_build.runner.id) }
- it { expect(data[:runner][:tags]).to match_array(%w(tag1 tag2)) }
+ it { expect(data[:runner][:tags]).to match_array(%w[tag1 tag2]) }
it { expect(data[:runner][:description]).to eq(ci_build.runner.description) }
it { expect(data[:runner][:runner_type]).to eq(ci_build.runner.runner_type) }
it { expect(data[:runner][:is_shared]).to eq(ci_build.runner.instance_type?) }
diff --git a/spec/lib/gitlab/data_builder/pipeline_spec.rb b/spec/lib/gitlab/data_builder/pipeline_spec.rb
index 351872ffbc5..ad7cd2dc736 100644
--- a/spec/lib/gitlab/data_builder/pipeline_spec.rb
+++ b/spec/lib/gitlab/data_builder/pipeline_spec.rb
@@ -66,7 +66,7 @@ RSpec.describe Gitlab::DataBuilder::Pipeline, feature_category: :continuous_inte
end
context 'build with runner' do
- let_it_be(:tag_names) { %w(tag-1 tag-2) }
+ let_it_be(:tag_names) { %w[tag-1 tag-2] }
let_it_be(:ci_runner) { create(:ci_runner, tag_list: tag_names.map { |n| ActsAsTaggableOn::Tag.create!(name: n) }) }
let_it_be(:build) { create(:ci_build, pipeline: pipeline, runner: ci_runner) }
diff --git a/spec/lib/gitlab/data_builder/push_spec.rb b/spec/lib/gitlab/data_builder/push_spec.rb
index a3dd4e49e83..02dc596c5eb 100644
--- a/spec/lib/gitlab/data_builder/push_spec.rb
+++ b/spec/lib/gitlab/data_builder/push_spec.rb
@@ -26,7 +26,7 @@ RSpec.describe Gitlab::DataBuilder::Push do
it 'returns commit hook data' do
expect(subject[:project]).to eq(project.hook_attrs)
- expect(subject[:commits].first.keys).to include(*%i(added removed modified))
+ expect(subject[:commits].first.keys).to include(*%i[added removed modified])
end
end
@@ -35,7 +35,7 @@ RSpec.describe Gitlab::DataBuilder::Push do
it 'returns commit hook data without include deltas' do
expect(subject[:project]).to eq(project.hook_attrs)
- expect(subject[:commits].first.keys).not_to include(*%i(added removed modified))
+ expect(subject[:commits].first.keys).not_to include(*%i[added removed modified])
end
end
end
diff --git a/spec/lib/gitlab/database/background_migration/batched_job_spec.rb b/spec/lib/gitlab/database/background_migration/batched_job_spec.rb
index d9b81a2be30..e1d1674d05c 100644
--- a/spec/lib/gitlab/database/background_migration/batched_job_spec.rb
+++ b/spec/lib/gitlab/database/background_migration/batched_job_spec.rb
@@ -25,7 +25,7 @@ RSpec.describe Gitlab::Database::BackgroundMigration::BatchedJob, type: :model d
describe 'state machine' do
let_it_be(:job) { create(:batched_background_migration_job, :failed) }
- it { expect(described_class.state_machine.states.map(&:name)).to eql(%i(pending running failed succeeded)) }
+ it { expect(described_class.state_machine.states.map(&:name)).to eql(%i[pending running failed succeeded]) }
context 'when a job is running' do
it 'logs the transition' do
diff --git a/spec/lib/gitlab/database/background_migration/batched_job_transition_log_spec.rb b/spec/lib/gitlab/database/background_migration/batched_job_transition_log_spec.rb
index 59f4f40c0ef..7cf7be8ffc2 100644
--- a/spec/lib/gitlab/database/background_migration/batched_job_transition_log_spec.rb
+++ b/spec/lib/gitlab/database/background_migration/batched_job_transition_log_spec.rb
@@ -15,7 +15,7 @@ RSpec.describe Gitlab::Database::BackgroundMigration::BatchedJobTransitionLog, t
it { is_expected.to validate_presence_of(:batched_job) }
it { is_expected.to validate_length_of(:exception_class).is_at_most(100) }
it { is_expected.to validate_length_of(:exception_message).is_at_most(1000) }
- it { is_expected.to define_enum_for(:previous_status).with_values(%i(pending running failed succeeded)).with_prefix }
- it { is_expected.to define_enum_for(:next_status).with_values(%i(pending running failed succeeded)).with_prefix }
+ it { is_expected.to define_enum_for(:previous_status).with_values(%i[pending running failed succeeded]).with_prefix }
+ it { is_expected.to define_enum_for(:next_status).with_values(%i[pending running failed succeeded]).with_prefix }
end
end
diff --git a/spec/lib/gitlab/database/background_migration/batched_migration_spec.rb b/spec/lib/gitlab/database/background_migration/batched_migration_spec.rb
index 213dee0d19d..f70b38377d8 100644
--- a/spec/lib/gitlab/database/background_migration/batched_migration_spec.rb
+++ b/spec/lib/gitlab/database/background_migration/batched_migration_spec.rb
@@ -422,11 +422,12 @@ RSpec.describe Gitlab::Database::BackgroundMigration::BatchedMigration, type: :m
describe '#create_batched_job!' do
let(:batched_migration) do
- create(:batched_background_migration,
- batch_size: 999,
- sub_batch_size: 99,
- pause_ms: 250
- )
+ create(
+ :batched_background_migration,
+ batch_size: 999,
+ sub_batch_size: 99,
+ pause_ms: 250
+ )
end
it 'creates a batched_job with the correct batch configuration' do
diff --git a/spec/lib/gitlab/database/background_migration/batched_migration_wrapper_spec.rb b/spec/lib/gitlab/database/background_migration/batched_migration_wrapper_spec.rb
index 8d74d16f4e5..bbcb65109ce 100644
--- a/spec/lib/gitlab/database/background_migration/batched_migration_wrapper_spec.rb
+++ b/spec/lib/gitlab/database/background_migration/batched_migration_wrapper_spec.rb
@@ -32,17 +32,17 @@ RSpec.describe Gitlab::Database::BackgroundMigration::BatchedMigrationWrapper, '
end
it 'runs the migration job' do
- expect(job_class).to receive(:new)
- .with(start_id: 1,
- end_id: 10,
- batch_table: 'events',
- batch_column: 'id',
- sub_batch_size: 1,
- pause_ms: pause_ms,
- job_arguments: active_migration.job_arguments,
- connection: connection,
- sub_batch_exception: sub_batch_exception)
- .and_return(job_instance)
+ expect(job_class).to receive(:new).with(
+ start_id: 1,
+ end_id: 10,
+ batch_table: 'events',
+ batch_column: 'id',
+ sub_batch_size: 1,
+ pause_ms: pause_ms,
+ job_arguments: active_migration.job_arguments,
+ connection: connection,
+ sub_batch_exception: sub_batch_exception
+ ).and_return(job_instance)
expect(job_instance).to receive(:perform).with(no_args)
diff --git a/spec/lib/gitlab/database/background_migration/prometheus_metrics_spec.rb b/spec/lib/gitlab/database/background_migration/prometheus_metrics_spec.rb
index 1f256de35ec..8f380a8229c 100644
--- a/spec/lib/gitlab/database/background_migration/prometheus_metrics_spec.rb
+++ b/spec/lib/gitlab/database/background_migration/prometheus_metrics_spec.rb
@@ -5,11 +5,14 @@ require 'spec_helper'
RSpec.describe Gitlab::Database::BackgroundMigration::PrometheusMetrics, :prometheus do
describe '#track' do
let(:job_record) do
- build(:batched_background_migration_job, :succeeded,
- started_at: Time.current - 2.minutes,
- finished_at: Time.current - 1.minute,
- updated_at: Time.current,
- metrics: { 'timings' => { 'update_all' => [0.05, 0.2, 0.4, 0.9, 4] } })
+ build(
+ :batched_background_migration_job,
+ :succeeded,
+ started_at: Time.current - 2.minutes,
+ finished_at: Time.current - 1.minute,
+ updated_at: Time.current,
+ metrics: { 'timings' => { 'update_all' => [0.05, 0.2, 0.4, 0.9, 4] } }
+ )
end
let(:labels) { job_record.batched_migration.prometheus_labels }
diff --git a/spec/lib/gitlab/database/bulk_update_spec.rb b/spec/lib/gitlab/database/bulk_update_spec.rb
index fa519cffd6b..2f0859dba74 100644
--- a/spec/lib/gitlab/database/bulk_update_spec.rb
+++ b/spec/lib/gitlab/database/bulk_update_spec.rb
@@ -92,7 +92,7 @@ RSpec.describe Gitlab::Database::BulkUpdate do
end
context 'validates prepared_statements support', :reestablished_active_record_base,
- :suppress_gitlab_schemas_validate_connection do
+ :suppress_gitlab_schemas_validate_connection do
using RSpec::Parameterized::TableSyntax
where(:prepared_statements) do
diff --git a/spec/lib/gitlab/database/dictionary_spec.rb b/spec/lib/gitlab/database/dictionary_spec.rb
new file mode 100644
index 00000000000..6d2de41468b
--- /dev/null
+++ b/spec/lib/gitlab/database/dictionary_spec.rb
@@ -0,0 +1,84 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::Database::Dictionary, feature_category: :database do
+ subject(:database_dictionary) { described_class.new(file_path) }
+
+ context 'for a table' do
+ let(:file_path) { 'db/docs/application_settings.yml' }
+
+ describe '#name_and_schema' do
+ it 'returns the name of the table and its gitlab schema' do
+ expect(database_dictionary.name_and_schema).to match_array(['application_settings', :gitlab_main_clusterwide])
+ end
+ end
+
+ describe '#table_name' do
+ it 'returns the name of the table' do
+ expect(database_dictionary.table_name).to eq('application_settings')
+ end
+ end
+
+ describe '#view_name' do
+ it 'returns nil' do
+ expect(database_dictionary.view_name).to be_nil
+ end
+ end
+
+ describe '#milestone' do
+ it 'returns the milestone in which the table was introduced' do
+ expect(database_dictionary.milestone).to eq('7.7')
+ end
+ end
+
+ describe '#gitlab_schema' do
+ it 'returns the gitlab_schema of the table' do
+ expect(database_dictionary.table_name).to eq('application_settings')
+ end
+ end
+
+ describe '#schema?' do
+ it 'checks if the given schema matches the schema of the table' do
+ expect(database_dictionary.schema?('gitlab_main')).to eq(false)
+ expect(database_dictionary.schema?('gitlab_main_clusterwide')).to eq(true)
+ end
+ end
+
+ describe '#key_name' do
+ it 'returns the value of the name of the table' do
+ expect(database_dictionary.key_name).to eq('application_settings')
+ end
+ end
+
+ describe '#validate!' do
+ it 'raises an error if the gitlab_schema is empty' do
+ allow(database_dictionary).to receive(:gitlab_schema).and_return(nil)
+
+ expect { database_dictionary.validate! }.to raise_error(Gitlab::Database::GitlabSchema::UnknownSchemaError)
+ end
+ end
+ end
+
+ context 'for a view' do
+ let(:file_path) { 'db/docs/views/postgres_constraints.yml' }
+
+ describe '#table_name' do
+ it 'returns nil' do
+ expect(database_dictionary.table_name).to be_nil
+ end
+ end
+
+ describe '#view_name' do
+ it 'returns the name of the view' do
+ expect(database_dictionary.view_name).to eq('postgres_constraints')
+ end
+ end
+
+ describe '#key_name' do
+ it 'returns the value of the name of the view' do
+ expect(database_dictionary.key_name).to eq('postgres_constraints')
+ end
+ end
+ end
+end
diff --git a/spec/lib/gitlab/database/dynamic_model_helpers_spec.rb b/spec/lib/gitlab/database/dynamic_model_helpers_spec.rb
index fe423b3639b..7ab50d47408 100644
--- a/spec/lib/gitlab/database/dynamic_model_helpers_spec.rb
+++ b/spec/lib/gitlab/database/dynamic_model_helpers_spec.rb
@@ -2,28 +2,83 @@
require 'spec_helper'
-RSpec.describe Gitlab::Database::DynamicModelHelpers do
+RSpec.describe Gitlab::Database::DynamicModelHelpers, feature_category: :database do
let(:including_class) { Class.new.include(described_class) }
let(:table_name) { Project.table_name }
let(:connection) { Project.connection }
describe '#define_batchable_model' do
- subject { including_class.new.define_batchable_model(table_name, connection: connection) }
+ subject(:model) { including_class.new.define_batchable_model(table_name, connection: connection) }
it 'is an ActiveRecord model' do
- expect(subject.ancestors).to include(ActiveRecord::Base)
+ expect(model.ancestors).to include(ActiveRecord::Base)
end
it 'includes EachBatch' do
- expect(subject.included_modules).to include(EachBatch)
+ expect(model.included_modules).to include(EachBatch)
end
it 'has the correct table name' do
- expect(subject.table_name).to eq(table_name)
+ expect(model.table_name).to eq(table_name)
end
it 'has the inheritance type column disable' do
- expect(subject.inheritance_column).to eq('_type_disabled')
+ expect(model.inheritance_column).to eq('_type_disabled')
+ end
+
+ context 'for primary key' do
+ subject(:model) do
+ including_class.new.define_batchable_model(table_name, connection: connection, primary_key: primary_key)
+ end
+
+ context 'when table primary key is a single column' do
+ let(:primary_key) { nil }
+
+ context 'when primary key is nil' do
+ it 'does not change the primary key from :id' do
+ expect(model.primary_key).to eq('id')
+ end
+ end
+
+ context 'when primary key is not nil' do
+ let(:primary_key) { 'other_column' }
+
+ it 'does not change the primary key from :id' do
+ expect(model.primary_key).to eq('id')
+ end
+ end
+ end
+
+ context 'when table has composite primary key' do
+ let(:primary_key) { nil }
+ let(:table_name) { :_test_composite_primary_key }
+
+ before do
+ connection.execute(<<~SQL)
+ DROP TABLE IF EXISTS #{table_name};
+
+ CREATE TABLE #{table_name} (
+ id integer NOT NULL,
+ partition_id integer NOT NULL,
+ PRIMARY KEY (id, partition_id)
+ );
+ SQL
+ end
+
+ context 'when primary key is nil' do
+ it 'does not change the primary key from nil' do
+ expect(model.primary_key).to be_nil
+ end
+ end
+
+ context 'when primary key is not nil' do
+ let(:primary_key) { 'id' }
+
+ it 'changes the primary key' do
+ expect(model.primary_key).to eq('id')
+ end
+ end
+ end
end
end
diff --git a/spec/lib/gitlab/database/gitlab_schema_spec.rb b/spec/lib/gitlab/database/gitlab_schema_spec.rb
index a6de695c345..a47e53c18a5 100644
--- a/spec/lib/gitlab/database/gitlab_schema_spec.rb
+++ b/spec/lib/gitlab/database/gitlab_schema_spec.rb
@@ -95,10 +95,10 @@ RSpec.describe Gitlab::Database::GitlabSchema, feature_category: :database do
# ignore gitlab_internal due to `ar_internal_metadata`, `schema_migrations`
table_and_view_names = table_and_view_names
- .reject { |_, gitlab_schema| gitlab_schema == :gitlab_internal }
+ .reject { |database_dictionary| database_dictionary.schema?('gitlab_internal') }
duplicated_tables = table_and_view_names
- .group_by(&:first)
+ .group_by(&:key_name)
.select { |_, schemas| schemas.count > 1 }
.keys
diff --git a/spec/lib/gitlab/database/loose_foreign_keys_spec.rb b/spec/lib/gitlab/database/loose_foreign_keys_spec.rb
index 552df64096a..1824a50cb28 100644
--- a/spec/lib/gitlab/database/loose_foreign_keys_spec.rb
+++ b/spec/lib/gitlab/database/loose_foreign_keys_spec.rb
@@ -8,14 +8,14 @@ RSpec.describe Gitlab::Database::LooseForeignKeys do
it 'all definitions have assigned a known gitlab_schema and on_delete' do
is_expected.to all(have_attributes(
- options: a_hash_including(
- column: be_a(String),
- gitlab_schema: be_in(Gitlab::Database.schemas_to_base_models.symbolize_keys.keys),
- on_delete: be_in([:async_delete, :async_nullify])
- ),
- from_table: be_a(String),
- to_table: be_a(String)
- ))
+ options: a_hash_including(
+ column: be_a(String),
+ gitlab_schema: be_in(Gitlab::Database.schemas_to_base_models.symbolize_keys.keys),
+ on_delete: be_in([:async_delete, :async_nullify])
+ ),
+ from_table: be_a(String),
+ to_table: be_a(String)
+ ))
end
context 'ensure keys are sorted' do
diff --git a/spec/lib/gitlab/database/migration_helpers/cascading_namespace_settings_spec.rb b/spec/lib/gitlab/database/migration_helpers/cascading_namespace_settings_spec.rb
index e11ffe53c61..fb3da38a7be 100644
--- a/spec/lib/gitlab/database/migration_helpers/cascading_namespace_settings_spec.rb
+++ b/spec/lib/gitlab/database/migration_helpers/cascading_namespace_settings_spec.rb
@@ -27,7 +27,7 @@ RSpec.describe Gitlab::Database::MigrationHelpers::CascadingNamespaceSettings do
it 'raises an error when some columns already exist' do
expect do
migration.add_cascading_namespace_setting(:cascading_setting, :integer)
- end.to raise_error %r/Existing columns: namespace_settings.cascading_setting, application_settings.lock_cascading_setting/
+ end.to raise_error %r{Existing columns: namespace_settings.cascading_setting, application_settings.lock_cascading_setting}
end
end
end
diff --git a/spec/lib/gitlab/database/migration_helpers/convert_to_bigint_spec.rb b/spec/lib/gitlab/database/migration_helpers/convert_to_bigint_spec.rb
index 1ff157b51d4..b0384a37746 100644
--- a/spec/lib/gitlab/database/migration_helpers/convert_to_bigint_spec.rb
+++ b/spec/lib/gitlab/database/migration_helpers/convert_to_bigint_spec.rb
@@ -5,7 +5,7 @@ require 'spec_helper'
RSpec.describe Gitlab::Database::MigrationHelpers::ConvertToBigint, feature_category: :database do
let(:migration) do
Class
- .new
+ .new(Gitlab::Database::Migration[2.1])
.include(described_class)
.include(Gitlab::Database::MigrationHelpers)
.new
@@ -73,4 +73,135 @@ RSpec.describe Gitlab::Database::MigrationHelpers::ConvertToBigint, feature_cate
expect(migration.columns_swapped?(:test_table, :id)).to eq(false)
end
end
+
+ describe '#add_bigint_column_indexes' do
+ let(:connection) { migration.connection }
+
+ let(:table_name) { '_test_table_bigint_indexes' }
+ let(:int_column) { 'token' }
+ let(:bigint_column) { 'token_convert_to_bigint' }
+
+ subject(:add_bigint_column_indexes) { migration.add_bigint_column_indexes(table_name, int_column) }
+
+ before do
+ connection.execute(<<~SQL)
+ CREATE TABLE IF NOT EXISTS public.#{table_name} (
+ name varchar(40),
+ #{int_column} integer
+ );
+ SQL
+
+ allow(migration).to receive(:transaction_open?).and_return(false)
+ allow(migration).to receive(:disable_statement_timeout).and_call_original
+ end
+
+ after do
+ connection.execute("DROP TABLE IF EXISTS #{table_name}")
+ end
+
+ context 'without corresponding bigint column' do
+ let(:error_msg) { "Bigint column '#{bigint_column}' does not exist on #{table_name}" }
+
+ it { expect { subject }.to raise_error(RuntimeError, error_msg) }
+ end
+
+ context 'with corresponding bigint column' do
+ let(:indexes) { connection.indexes(table_name) }
+ let(:int_column_indexes) { indexes.select { |i| i.columns.include?(int_column) } }
+ let(:bigint_column_indexes) { indexes.select { |i| i.columns.include?(bigint_column) } }
+
+ before do
+ connection.execute("ALTER TABLE #{table_name} ADD COLUMN #{bigint_column} bigint")
+ end
+
+ context 'without the integer column index' do
+ it 'does not create new bigint index' do
+ expect(int_column_indexes).to be_empty
+
+ add_bigint_column_indexes
+
+ expect(bigint_column_indexes).to be_empty
+ end
+ end
+
+ context 'with integer column indexes' do
+ let(:bigint_index_name) { ->(int_index_name) { migration.bigint_index_name(int_index_name) } }
+ let(:expected_bigint_indexes) do
+ [
+ {
+ name: bigint_index_name.call("hash_idx_#{table_name}"),
+ column: [bigint_column],
+ using: 'hash'
+ },
+ {
+ name: bigint_index_name.call("idx_#{table_name}"),
+ column: [bigint_column],
+ using: 'btree'
+ },
+ {
+ name: bigint_index_name.call("idx_#{table_name}_combined"),
+ column: "#{bigint_column}, lower((name)::text)",
+ where: "(#{bigint_column} IS NOT NULL)",
+ using: 'btree'
+ },
+ {
+ name: bigint_index_name.call("idx_#{table_name}_functional"),
+ column: "#{bigint_column}, lower((name)::text)",
+ using: 'btree'
+ },
+ {
+ name: bigint_index_name.call("idx_#{table_name}_ordered"),
+ column: [bigint_column],
+ order: 'DESC NULLS LAST',
+ using: 'btree'
+ },
+ {
+ name: bigint_index_name.call("idx_#{table_name}_ordered_multiple"),
+ column: [bigint_column, 'name'],
+ order: { bigint_column => 'DESC NULLS LAST', 'name' => 'desc' },
+ using: 'btree'
+ },
+ {
+ name: bigint_index_name.call("idx_#{table_name}_partial"),
+ column: [bigint_column],
+ where: "(#{bigint_column} IS NOT NULL)",
+ using: 'btree'
+ },
+ {
+ name: bigint_index_name.call("uniq_idx_#{table_name}"),
+ column: [bigint_column],
+ unique: true,
+ using: 'btree'
+ }
+ ]
+ end
+
+ before do
+ connection.execute(<<~SQL)
+ CREATE INDEX "hash_idx_#{table_name}" ON #{table_name} USING hash (#{int_column});
+ CREATE INDEX "idx_#{table_name}" ON #{table_name} USING btree (#{int_column});
+ CREATE INDEX "idx_#{table_name}_combined" ON #{table_name} USING btree (#{int_column}, lower((name)::text)) WHERE (#{int_column} IS NOT NULL);
+ CREATE INDEX "idx_#{table_name}_functional" ON #{table_name} USING btree (#{int_column}, lower((name)::text));
+ CREATE INDEX "idx_#{table_name}_ordered" ON #{table_name} USING btree (#{int_column} DESC NULLS LAST);
+ CREATE INDEX "idx_#{table_name}_ordered_multiple" ON #{table_name} USING btree (#{int_column} DESC NULLS LAST, name DESC);
+ CREATE INDEX "idx_#{table_name}_partial" ON #{table_name} USING btree (#{int_column}) WHERE (#{int_column} IS NOT NULL);
+ CREATE UNIQUE INDEX "uniq_idx_#{table_name}" ON #{table_name} USING btree (#{int_column});
+ SQL
+ end
+
+ it 'creates appropriate bigint indexes' do
+ expected_bigint_indexes.each do |bigint_index|
+ expect(migration).to receive(:add_concurrent_index).with(
+ table_name,
+ bigint_index[:column],
+ name: bigint_index[:name],
+ ** bigint_index.except(:name, :column)
+ )
+ end
+
+ add_bigint_column_indexes
+ end
+ end
+ end
+ end
end
diff --git a/spec/lib/gitlab/database/migration_helpers/wraparound_autovacuum_spec.rb b/spec/lib/gitlab/database/migration_helpers/wraparound_autovacuum_spec.rb
index 1cc4ff6891c..b88d26100c9 100644
--- a/spec/lib/gitlab/database/migration_helpers/wraparound_autovacuum_spec.rb
+++ b/spec/lib/gitlab/database/migration_helpers/wraparound_autovacuum_spec.rb
@@ -14,20 +14,30 @@ RSpec.describe Gitlab::Database::MigrationHelpers::WraparoundAutovacuum, feature
describe '#can_execute_on?' do
using RSpec::Parameterized::TableSyntax
- where(:dot_com, :dev_or_test, :wraparound_prevention, :expectation) do
- true | true | true | false
- true | false | true | false
- false | true | true | false
- false | false | true | false
- true | true | false | true
- true | false | false | true
- false | true | false | true
- false | false | false | false
+ where(:dot_com, :jh, :dev_or_test, :wraparound_prevention, :expectation) do
+ true | true | true | true | false
+ true | true | false | true | false
+ false | true | true | true | false
+ false | true | false | true | false
+ true | true | true | false | true
+ true | true | false | false | false
+ false | true | true | false | true
+ false | true | false | false | false
+
+ true | false | true | true | false
+ true | false | false | true | false
+ false | false | true | true | false
+ false | false | false | true | false
+ true | false | true | false | true
+ true | false | false | false | true
+ false | false | true | false | true
+ false | false | false | false | false
end
with_them do
- it 'returns true for GitLab.com, dev, or test' do
+ it 'returns as expected for GitLab.com, dev, or test' do
allow(Gitlab).to receive(:com?).and_return(dot_com)
+ allow(Gitlab).to receive(:jh?).and_return(jh)
allow(Gitlab).to receive(:dev_or_test_env?).and_return(dev_or_test)
allow(migration).to receive(:wraparound_prevention_on_tables?).with([:table]).and_return(wraparound_prevention)
diff --git a/spec/lib/gitlab/database/migration_helpers_spec.rb b/spec/lib/gitlab/database/migration_helpers_spec.rb
index dd51cca688c..8bf05f56b3f 100644
--- a/spec/lib/gitlab/database/migration_helpers_spec.rb
+++ b/spec/lib/gitlab/database/migration_helpers_spec.rb
@@ -118,7 +118,7 @@ RSpec.describe Gitlab::Database::MigrationHelpers, feature_category: :database d
it 'cannot add unacceptable column names' do
expect do
model.add_timestamps_with_timezone(:foo, columns: [:bar])
- end.to raise_error %r/Illegal timestamp column name/
+ end.to raise_error %r{Illegal timestamp column name}
end
end
@@ -1753,8 +1753,8 @@ RSpec.describe Gitlab::Database::MigrationHelpers, feature_category: :database d
describe '#indexes_for' do
it 'returns the indexes for a column' do
- idx1 = double(:idx, columns: %w(project_id))
- idx2 = double(:idx, columns: %w(user_id))
+ idx1 = double(:idx, columns: %w[project_id])
+ idx2 = double(:idx, columns: %w[user_id])
allow(model).to receive(:indexes).with('table').and_return([idx1, idx2])
@@ -1777,7 +1777,7 @@ RSpec.describe Gitlab::Database::MigrationHelpers, feature_category: :database d
context 'when index name is too long' do
it 'does not fail' do
index = double(:index,
- columns: %w(uuid),
+ columns: %w[uuid],
name: 'index_vuln_findings_on_uuid_including_vuln_id_1',
using: nil,
where: nil,
@@ -1791,7 +1791,7 @@ RSpec.describe Gitlab::Database::MigrationHelpers, feature_category: :database d
expect(model).to receive(:add_concurrent_index)
.with(:vulnerability_occurrences,
- %w(tmp_undo_cleanup_column_8cbf300838),
+ %w[tmp_undo_cleanup_column_8cbf300838],
{
unique: true,
name: 'idx_copy_191a1af1a0',
@@ -1806,7 +1806,7 @@ RSpec.describe Gitlab::Database::MigrationHelpers, feature_category: :database d
context 'using a regular index using a single column' do
it 'copies the index' do
index = double(:index,
- columns: %w(project_id),
+ columns: %w[project_id],
name: 'index_on_issues_project_id',
using: nil,
where: nil,
@@ -1820,7 +1820,7 @@ RSpec.describe Gitlab::Database::MigrationHelpers, feature_category: :database d
expect(model).to receive(:add_concurrent_index)
.with(:issues,
- %w(gl_project_id),
+ %w[gl_project_id],
{
unique: false,
name: 'index_on_issues_gl_project_id',
@@ -1835,7 +1835,7 @@ RSpec.describe Gitlab::Database::MigrationHelpers, feature_category: :database d
context 'using a regular index with multiple columns' do
it 'copies the index' do
index = double(:index,
- columns: %w(project_id foobar),
+ columns: %w[project_id foobar],
name: 'index_on_issues_project_id_foobar',
using: nil,
where: nil,
@@ -1849,7 +1849,7 @@ RSpec.describe Gitlab::Database::MigrationHelpers, feature_category: :database d
expect(model).to receive(:add_concurrent_index)
.with(:issues,
- %w(gl_project_id foobar),
+ %w[gl_project_id foobar],
{
unique: false,
name: 'index_on_issues_gl_project_id_foobar',
@@ -1864,7 +1864,7 @@ RSpec.describe Gitlab::Database::MigrationHelpers, feature_category: :database d
context 'using an index with a WHERE clause' do
it 'copies the index' do
index = double(:index,
- columns: %w(project_id),
+ columns: %w[project_id],
name: 'index_on_issues_project_id',
using: nil,
where: 'foo',
@@ -1878,7 +1878,7 @@ RSpec.describe Gitlab::Database::MigrationHelpers, feature_category: :database d
expect(model).to receive(:add_concurrent_index)
.with(:issues,
- %w(gl_project_id),
+ %w[gl_project_id],
{
unique: false,
name: 'index_on_issues_gl_project_id',
@@ -1894,7 +1894,7 @@ RSpec.describe Gitlab::Database::MigrationHelpers, feature_category: :database d
context 'using an index with a USING clause' do
it 'copies the index' do
index = double(:index,
- columns: %w(project_id),
+ columns: %w[project_id],
name: 'index_on_issues_project_id',
where: nil,
using: 'foo',
@@ -1908,7 +1908,7 @@ RSpec.describe Gitlab::Database::MigrationHelpers, feature_category: :database d
expect(model).to receive(:add_concurrent_index)
.with(:issues,
- %w(gl_project_id),
+ %w[gl_project_id],
{
unique: false,
name: 'index_on_issues_gl_project_id',
@@ -1924,7 +1924,7 @@ RSpec.describe Gitlab::Database::MigrationHelpers, feature_category: :database d
context 'using an index with custom operator classes' do
it 'copies the index' do
index = double(:index,
- columns: %w(project_id),
+ columns: %w[project_id],
name: 'index_on_issues_project_id',
using: nil,
where: nil,
@@ -1938,7 +1938,7 @@ RSpec.describe Gitlab::Database::MigrationHelpers, feature_category: :database d
expect(model).to receive(:add_concurrent_index)
.with(:issues,
- %w(gl_project_id),
+ %w[gl_project_id],
{
unique: false,
name: 'index_on_issues_gl_project_id',
@@ -1955,7 +1955,7 @@ RSpec.describe Gitlab::Database::MigrationHelpers, feature_category: :database d
it 'copies the index' do
index = double(:index,
{
- columns: %w(project_id foobar),
+ columns: %w[project_id foobar],
name: 'index_on_issues_project_id_foobar',
using: :gin,
where: nil,
@@ -1970,7 +1970,7 @@ RSpec.describe Gitlab::Database::MigrationHelpers, feature_category: :database d
expect(model).to receive(:add_concurrent_index)
.with(:issues,
- %w(gl_project_id foobar),
+ %w[gl_project_id foobar],
{
unique: false,
name: 'index_on_issues_gl_project_id_foobar',
@@ -1988,7 +1988,7 @@ RSpec.describe Gitlab::Database::MigrationHelpers, feature_category: :database d
it 'copies the index' do
index = double(:index,
{
- columns: %w(project_id foobar),
+ columns: %w[project_id foobar],
name: 'index_on_issues_project_id_foobar',
using: :gin,
where: nil,
@@ -2003,7 +2003,7 @@ RSpec.describe Gitlab::Database::MigrationHelpers, feature_category: :database d
expect(model).to receive(:add_concurrent_index)
.with(:issues,
- %w(gl_project_id foobar),
+ %w[gl_project_id foobar],
{
unique: false,
name: 'index_on_issues_gl_project_id_foobar',
@@ -2020,7 +2020,7 @@ RSpec.describe Gitlab::Database::MigrationHelpers, feature_category: :database d
describe 'using an index of which the name does not contain the source column' do
it 'raises RuntimeError' do
index = double(:index,
- columns: %w(project_id),
+ columns: %w[project_id],
name: 'index_foobar_index',
using: nil,
where: nil,
diff --git a/spec/lib/gitlab/database/migrations/batched_background_migration_helpers_spec.rb b/spec/lib/gitlab/database/migrations/batched_background_migration_helpers_spec.rb
index f1271f2434c..a81ccf9583a 100644
--- a/spec/lib/gitlab/database/migrations/batched_background_migration_helpers_spec.rb
+++ b/spec/lib/gitlab/database/migrations/batched_background_migration_helpers_spec.rb
@@ -443,10 +443,10 @@ RSpec.describe Gitlab::Database::Migrations::BatchedBackgroundMigrationHelpers,
describe '#ensure_batched_background_migration_is_finished' do
let(:job_class_name) { 'CopyColumnUsingBackgroundMigrationJob' }
- let(:table_name) { 'events' }
+ let(:table_name) { '_test_table' }
let(:column_name) { :id }
let(:job_arguments) { [["id"], ["id_convert_to_bigint"], nil] }
- let(:gitlab_schema) { Gitlab::Database::GitlabSchema.table_schema!(table_name) }
+ let(:gitlab_schema) { :gitlab_main }
let(:configuration) do
{
@@ -484,7 +484,7 @@ RSpec.describe Gitlab::Database::Migrations::BatchedBackgroundMigrationHelpers,
"\n\n" \
"Finalize it manually by running the following command in a `bash` or `sh` shell:" \
"\n\n" \
- "\tsudo gitlab-rake gitlab:background_migrations:finalize[CopyColumnUsingBackgroundMigrationJob,events,id,'[[\"id\"]\\,[\"id_convert_to_bigint\"]\\,null]']" \
+ "\tsudo gitlab-rake gitlab:background_migrations:finalize[CopyColumnUsingBackgroundMigrationJob,_test_table,id,'[[\"id\"]\\,[\"id_convert_to_bigint\"]\\,null]']" \
"\n\n" \
"For more information, check the documentation" \
"\n\n" \
diff --git a/spec/lib/gitlab/database/migrations/constraints_helpers_spec.rb b/spec/lib/gitlab/database/migrations/constraints_helpers_spec.rb
index 476b5f3a784..4d7c51a3fbf 100644
--- a/spec/lib/gitlab/database/migrations/constraints_helpers_spec.rb
+++ b/spec/lib/gitlab/database/migrations/constraints_helpers_spec.rb
@@ -13,9 +13,11 @@ RSpec.describe Gitlab::Database::Migrations::ConstraintsHelpers do
describe '#check_constraint_name' do
it 'returns a valid constraint name' do
- name = model.check_constraint_name(:this_is_a_very_long_table_name,
- :with_a_very_long_column_name,
- :with_a_very_long_type)
+ name = model.check_constraint_name(
+ :this_is_a_very_long_table_name,
+ :with_a_very_long_column_name,
+ :with_a_very_long_type
+ )
expect(name).to be_an_instance_of(String)
expect(name).to start_with('check_')
@@ -404,9 +406,7 @@ RSpec.describe Gitlab::Database::Migrations::ConstraintsHelpers do
describe '#add_text_limit' do
context 'when it is called with the default options' do
it 'calls add_check_constraint with an infered constraint name and validate: true' do
- constraint_name = model.check_constraint_name(:test_table,
- :name,
- 'max_length')
+ constraint_name = model.check_constraint_name(:test_table, :name, 'max_length')
check = "char_length(name) <= 255"
expect(model).to receive(:check_constraint_name).and_call_original
@@ -440,9 +440,7 @@ RSpec.describe Gitlab::Database::Migrations::ConstraintsHelpers do
describe '#validate_text_limit' do
context 'when constraint_name is not provided' do
it 'calls validate_check_constraint with an infered constraint name' do
- constraint_name = model.check_constraint_name(:test_table,
- :name,
- 'max_length')
+ constraint_name = model.check_constraint_name(:test_table, :name, 'max_length')
expect(model).to receive(:check_constraint_name).and_call_original
expect(model).to receive(:validate_check_constraint)
@@ -468,9 +466,7 @@ RSpec.describe Gitlab::Database::Migrations::ConstraintsHelpers do
describe '#remove_text_limit' do
context 'when constraint_name is not provided' do
it 'calls remove_check_constraint with an infered constraint name' do
- constraint_name = model.check_constraint_name(:test_table,
- :name,
- 'max_length')
+ constraint_name = model.check_constraint_name(:test_table, :name, 'max_length')
expect(model).to receive(:check_constraint_name).and_call_original
expect(model).to receive(:remove_check_constraint)
@@ -496,9 +492,7 @@ RSpec.describe Gitlab::Database::Migrations::ConstraintsHelpers do
describe '#check_text_limit_exists?' do
context 'when constraint_name is not provided' do
it 'calls check_constraint_exists? with an infered constraint name' do
- constraint_name = model.check_constraint_name(:test_table,
- :name,
- 'max_length')
+ constraint_name = model.check_constraint_name(:test_table, :name, 'max_length')
expect(model).to receive(:check_constraint_name).and_call_original
expect(model).to receive(:check_constraint_exists?)
@@ -524,9 +518,7 @@ RSpec.describe Gitlab::Database::Migrations::ConstraintsHelpers do
describe '#add_not_null_constraint' do
context 'when it is called with the default options' do
it 'calls add_check_constraint with an infered constraint name and validate: true' do
- constraint_name = model.check_constraint_name(:test_table,
- :name,
- 'not_null')
+ constraint_name = model.check_constraint_name(:test_table, :name, 'not_null')
check = "name IS NOT NULL"
expect(model).to receive(:column_is_nullable?).and_return(true)
@@ -571,9 +563,7 @@ RSpec.describe Gitlab::Database::Migrations::ConstraintsHelpers do
describe '#validate_not_null_constraint' do
context 'when constraint_name is not provided' do
it 'calls validate_check_constraint with an infered constraint name' do
- constraint_name = model.check_constraint_name(:test_table,
- :name,
- 'not_null')
+ constraint_name = model.check_constraint_name(:test_table, :name, 'not_null')
expect(model).to receive(:check_constraint_name).and_call_original
expect(model).to receive(:validate_check_constraint)
@@ -599,9 +589,7 @@ RSpec.describe Gitlab::Database::Migrations::ConstraintsHelpers do
describe '#remove_not_null_constraint' do
context 'when constraint_name is not provided' do
it 'calls remove_check_constraint with an infered constraint name' do
- constraint_name = model.check_constraint_name(:test_table,
- :name,
- 'not_null')
+ constraint_name = model.check_constraint_name(:test_table, :name, 'not_null')
expect(model).to receive(:check_constraint_name).and_call_original
expect(model).to receive(:remove_check_constraint)
@@ -627,9 +615,7 @@ RSpec.describe Gitlab::Database::Migrations::ConstraintsHelpers do
describe '#check_not_null_constraint_exists?' do
context 'when constraint_name is not provided' do
it 'calls check_constraint_exists? with an infered constraint name' do
- constraint_name = model.check_constraint_name(:test_table,
- :name,
- 'not_null')
+ constraint_name = model.check_constraint_name(:test_table, :name, 'not_null')
expect(model).to receive(:check_constraint_name).and_call_original
expect(model).to receive(:check_constraint_exists?)
diff --git a/spec/lib/gitlab/database/migrations/instrumentation_spec.rb b/spec/lib/gitlab/database/migrations/instrumentation_spec.rb
index a12e0909dc2..81368dde94d 100644
--- a/spec/lib/gitlab/database/migrations/instrumentation_spec.rb
+++ b/spec/lib/gitlab/database/migrations/instrumentation_spec.rb
@@ -75,8 +75,12 @@ RSpec.describe Gitlab::Database::Migrations::Instrumentation do
context 'on successful execution' do
subject do
- instrumentation.observe(version: migration_version, name: migration_name,
- connection: connection, meta: migration_meta) {}
+ instrumentation.observe(
+ version: migration_version,
+ name: migration_name,
+ connection: connection,
+ meta: migration_meta
+ ) {}
end
it 'records a valid observation', :aggregate_failures do
@@ -98,8 +102,12 @@ RSpec.describe Gitlab::Database::Migrations::Instrumentation do
with_them do
subject(:observe) do
- instrumentation.observe(version: migration_version, name: migration_name,
- connection: connection, meta: migration_meta) { raise exception, error_message }
+ instrumentation.observe(
+ version: migration_version,
+ name: migration_name,
+ connection: connection,
+ meta: migration_meta
+ ) { raise exception, error_message }
end
context 'retrieving observations' do
diff --git a/spec/lib/gitlab/database/migrations/milestone_mixin_spec.rb b/spec/lib/gitlab/database/migrations/milestone_mixin_spec.rb
index e375af494a2..1ed5c846550 100644
--- a/spec/lib/gitlab/database/migrations/milestone_mixin_spec.rb
+++ b/spec/lib/gitlab/database/migrations/milestone_mixin_spec.rb
@@ -12,14 +12,11 @@ RSpec.describe Gitlab::Database::Migrations::MilestoneMixin, feature_category: :
end
let(:migration_mixin) do
- Class.new(Gitlab::Database::Migration[2.1]) do
- include Gitlab::Database::Migrations::MilestoneMixin
- end
+ Class.new(Gitlab::Database::Migration[2.2])
end
let(:migration_mixin_version) do
- Class.new(Gitlab::Database::Migration[2.1]) do
- include Gitlab::Database::Migrations::MilestoneMixin
+ Class.new(Gitlab::Database::Migration[2.2]) do
milestone '16.4'
end
end
@@ -44,5 +41,11 @@ RSpec.describe Gitlab::Database::Migrations::MilestoneMixin, feature_category: :
expect { migration_mixin_version.new(4, 4, :regular) }.not_to raise_error
end
end
+
+ context 'when initialize arguments are not provided' do
+ it "does not raise an error" do
+ expect { migration_mixin_version.new }.not_to raise_error
+ end
+ end
end
end
diff --git a/spec/lib/gitlab/database/migrations/reestablished_connection_stack_spec.rb b/spec/lib/gitlab/database/migrations/reestablished_connection_stack_spec.rb
index c6327de98d1..6e943307ae6 100644
--- a/spec/lib/gitlab/database/migrations/reestablished_connection_stack_spec.rb
+++ b/spec/lib/gitlab/database/migrations/reestablished_connection_stack_spec.rb
@@ -31,7 +31,7 @@ RSpec.describe Gitlab::Database::Migrations::ReestablishedConnectionStack do
# establish connection
ApplicationRecord.connection.select_one("SELECT 1 FROM projects LIMIT 1")
- Ci::ApplicationRecord.connection.select_one("SELECT 1 FROM ci_builds LIMIT 1")
+ Ci::ApplicationRecord.connection.select_one("SELECT 1 FROM p_ci_builds LIMIT 1")
end
expect(new_handler).not_to eq(original_handler), "is reconnected"
diff --git a/spec/lib/gitlab/database/migrations/test_batched_background_runner_spec.rb b/spec/lib/gitlab/database/migrations/test_batched_background_runner_spec.rb
index 31a194ae883..660c4347ffa 100644
--- a/spec/lib/gitlab/database/migrations/test_batched_background_runner_spec.rb
+++ b/spec/lib/gitlab/database/migrations/test_batched_background_runner_spec.rb
@@ -80,8 +80,11 @@ RSpec.describe Gitlab::Database::Migrations::TestBatchedBackgroundRunner, :freez
end
subject(:sample_migration) do
- described_class.new(result_dir: result_dir, connection: connection,
- from_id: from_id).run_jobs(for_duration: 1.minute)
+ described_class.new(
+ result_dir: result_dir,
+ connection: connection,
+ from_id: from_id
+ ).run_jobs(for_duration: 1.minute)
end
it 'runs sampled jobs from the batched background migration' do
@@ -125,12 +128,19 @@ RSpec.describe Gitlab::Database::Migrations::TestBatchedBackgroundRunner, :freez
calls << args
end
- queue_migration(migration_name, table_name, :id,
- job_interval: 5.minutes,
- batch_size: 100)
+ queue_migration(
+ migration_name,
+ table_name,
+ :id,
+ job_interval: 5.minutes,
+ batch_size: 100
+ )
- described_class.new(result_dir: result_dir, connection: connection,
- from_id: from_id).run_jobs(for_duration: 3.minutes)
+ described_class.new(
+ result_dir: result_dir,
+ connection: connection,
+ from_id: from_id
+ ).run_jobs(for_duration: 3.minutes)
expect(calls).not_to be_empty
end
@@ -142,13 +152,19 @@ RSpec.describe Gitlab::Database::Migrations::TestBatchedBackgroundRunner, :freez
calls << args
end
- queue_migration(migration_name, table_name, :id,
- job_interval: 5.minutes,
- batch_size: num_rows_in_table * 2,
- sub_batch_size: num_rows_in_table * 2)
+ queue_migration(
+ migration_name,
+ table_name, :id,
+ job_interval: 5.minutes,
+ batch_size: num_rows_in_table * 2,
+ sub_batch_size: num_rows_in_table * 2
+ )
- described_class.new(result_dir: result_dir, connection: connection,
- from_id: from_id).run_jobs(for_duration: 3.minutes)
+ described_class.new(
+ result_dir: result_dir,
+ connection: connection,
+ from_id: from_id
+ ).run_jobs(for_duration: 3.minutes)
expect(calls.size).to eq(1)
end
@@ -161,13 +177,20 @@ RSpec.describe Gitlab::Database::Migrations::TestBatchedBackgroundRunner, :freez
calls << args
end
- queue_migration(migration_name, table_name, :id,
- job_interval: 5.minutes,
- batch_size: num_rows_in_table * 2,
- sub_batch_size: num_rows_in_table * 2)
-
- described_class.new(result_dir: result_dir, connection: connection,
- from_id: from_id).run_jobs(for_duration: 3.minutes)
+ queue_migration(
+ migration_name,
+ table_name,
+ :id,
+ job_interval: 5.minutes,
+ batch_size: num_rows_in_table * 2,
+ sub_batch_size: num_rows_in_table * 2
+ )
+
+ described_class.new(
+ result_dir: result_dir,
+ connection: connection,
+ from_id: from_id
+ ).run_jobs(for_duration: 3.minutes)
expect(calls.count).to eq(0)
end
@@ -181,26 +204,41 @@ RSpec.describe Gitlab::Database::Migrations::TestBatchedBackgroundRunner, :freez
it 'runs all pending jobs based on the last migration id' do
old_migration = define_background_migration(migration_name)
- queue_migration(migration_name, table_name, :id,
- job_interval: 5.minutes,
- batch_size: 100)
+ queue_migration(
+ migration_name,
+ table_name,
+ :id,
+ job_interval: 5.minutes,
+ batch_size: 100
+ )
last_id
new_migration = define_background_migration('NewMigration') { travel 1.second }
- queue_migration('NewMigration', table_name, :id,
- job_interval: 5.minutes,
- batch_size: 10,
- sub_batch_size: 5)
+ queue_migration(
+ 'NewMigration',
+ table_name,
+ :id,
+ job_interval: 5.minutes,
+ batch_size: 10,
+ sub_batch_size: 5
+ )
other_new_migration = define_background_migration('NewMigration2') { travel 2.seconds }
- queue_migration('NewMigration2', table_name, :id,
- job_interval: 5.minutes,
- batch_size: 10,
- sub_batch_size: 5)
+ queue_migration(
+ 'NewMigration2',
+ table_name,
+ :id,
+ job_interval: 5.minutes,
+ batch_size: 10,
+ sub_batch_size: 5
+ )
expect_migration_runs(new_migration => 3, other_new_migration => 2, old_migration => 0) do
- described_class.new(result_dir: result_dir, connection: connection,
- from_id: last_id).run_jobs(for_duration: 5.seconds)
+ described_class.new(
+ result_dir: result_dir,
+ connection: connection,
+ from_id: last_id
+ ).run_jobs(for_duration: 5.seconds)
end
end
end
diff --git a/spec/lib/gitlab/database/no_cross_db_foreign_keys_spec.rb b/spec/lib/gitlab/database/no_cross_db_foreign_keys_spec.rb
index c6cd5e55754..c57b8bb5992 100644
--- a/spec/lib/gitlab/database/no_cross_db_foreign_keys_spec.rb
+++ b/spec/lib/gitlab/database/no_cross_db_foreign_keys_spec.rb
@@ -11,6 +11,7 @@ RSpec.describe 'cross-database foreign keys' do
# should be added as a comment along with the name of the column.
let!(:allowed_cross_database_foreign_keys) do
[
+ 'events.author_id', # https://gitlab.com/gitlab-org/gitlab/-/issues/429803
'gitlab_subscriptions.hosted_plan_id', # https://gitlab.com/gitlab-org/gitlab/-/issues/422012
'group_import_states.user_id', # https://gitlab.com/gitlab-org/gitlab/-/issues/421210
'identities.saml_provider_id', # https://gitlab.com/gitlab-org/gitlab/-/issues/422010
@@ -18,11 +19,18 @@ RSpec.describe 'cross-database foreign keys' do
'issues.closed_by_id', # https://gitlab.com/gitlab-org/gitlab/-/issues/422154
'issues.updated_by_id', # https://gitlab.com/gitlab-org/gitlab/-/issues/422154
'issue_assignees.user_id', # https://gitlab.com/gitlab-org/gitlab/-/issues/422154
+ 'lfs_file_locks.user_id', # https://gitlab.com/gitlab-org/gitlab/-/issues/430838
'merge_requests.assignee_id', # https://gitlab.com/gitlab-org/gitlab/-/issues/422080
'merge_requests.updated_by_id', # https://gitlab.com/gitlab-org/gitlab/-/issues/422080
'merge_requests.merge_user_id', # https://gitlab.com/gitlab-org/gitlab/-/issues/422080
'merge_requests.author_id', # https://gitlab.com/gitlab-org/gitlab/-/issues/422080
+ 'namespace_commit_emails.email_id', # https://gitlab.com/gitlab-org/gitlab/-/issues/429804
+ 'namespace_commit_emails.user_id', # https://gitlab.com/gitlab-org/gitlab/-/issues/429804
+ 'path_locks.user_id', # https://gitlab.com/gitlab-org/gitlab/-/issues/429380
'project_authorizations.user_id', # https://gitlab.com/gitlab-org/gitlab/-/issues/422044
+ 'protected_branch_push_access_levels.user_id', # https://gitlab.com/gitlab-org/gitlab/-/issues/431054
+ 'protected_branch_merge_access_levels.user_id', # https://gitlab.com/gitlab-org/gitlab/-/issues/431055
+ 'security_orchestration_policy_configurations.bot_user_id', # https://gitlab.com/gitlab-org/gitlab/-/issues/429438
'user_group_callouts.user_id' # https://gitlab.com/gitlab-org/gitlab/-/issues/421287
]
end
diff --git a/spec/lib/gitlab/database/no_new_tables_with_gitlab_main_schema_spec.rb b/spec/lib/gitlab/database/no_new_tables_with_gitlab_main_schema_spec.rb
new file mode 100644
index 00000000000..338475fa9c4
--- /dev/null
+++ b/spec/lib/gitlab/database/no_new_tables_with_gitlab_main_schema_spec.rb
@@ -0,0 +1,63 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe 'new tables with gitlab_main schema', feature_category: :cell do
+ # During the development of Cells, we will be moving tables from the `gitlab_main` schema
+ # to either the `gitlab_main_clusterwide` or `gitlab_main_cell` schema.
+ # As part of this process, starting from milestone 16.7, it will be a mandatory requirement that
+ # all newly created tables are associated with one of these two schemas.
+ # Any attempt to set the `gitlab_main` schema for a new table will result in a failure of this spec.
+
+ # Specific tables can be exempted from this requirement, and such tables must be added to the `exempted_tables` list.
+ let!(:exempted_tables) do
+ []
+ end
+
+ let!(:starting_from_milestone) { 16.7 }
+
+ it 'only allows exempted tables to have `gitlab_main` as its schema, after milestone 16.7', :aggregate_failures do
+ tables_having_gitlab_main_schema(starting_from_milestone: starting_from_milestone).each do |table_name|
+ expect(exempted_tables).to include(table_name), error_message(table_name)
+ end
+ end
+
+ it 'only allows tables having `gitlab_main` as its schema in `exempted_tables`', :aggregate_failures do
+ tables_having_gitlab_main_schema = gitlab_main_schema_tables.map(&:table_name)
+
+ exempted_tables.each do |exempted_table|
+ expect(tables_having_gitlab_main_schema).to include(exempted_table),
+ "`#{exempted_table}` does not have `gitlab_main` as its schema.
+ Please remove this table from the `exempted_tables` list."
+ end
+ end
+
+ private
+
+ def error_message(table_name)
+ <<~HEREDOC
+ The table `#{table_name}` has been added with `gitlab_main` schema.
+ Starting from GitLab #{starting_from_milestone}, we expect new tables to use either the `gitlab_main_cell` or the
+ `gitlab_main_clusterwide` schema.
+
+ To choose an appropriate schema for this table from among `gitlab_main_cell` and `gitlab_main_clusterwide`, please refer
+ to our guidelines at https://docs.gitlab.com/ee/development/database/multiple_databases.html#guidelines-on-choosing-between-gitlab_main_cell-and-gitlab_main_clusterwide-schema, or consult with the Tenant Scale group.
+
+ Please see issue https://gitlab.com/gitlab-org/gitlab/-/issues/424990 to understand why this change is being enforced.
+ HEREDOC
+ end
+
+ def tables_having_gitlab_main_schema(starting_from_milestone:)
+ selected_data = gitlab_main_schema_tables.select do |database_dictionary|
+ database_dictionary.milestone.to_f >= starting_from_milestone
+ end
+
+ selected_data.map(&:table_name)
+ end
+
+ def gitlab_main_schema_tables
+ ::Gitlab::Database::GitlabSchema.build_dictionary('').select do |database_dictionary|
+ database_dictionary.schema?('gitlab_main')
+ end
+ end
+end
diff --git a/spec/lib/gitlab/database/partitioning/detached_partition_dropper_spec.rb b/spec/lib/gitlab/database/partitioning/detached_partition_dropper_spec.rb
index 04940028aee..eb78d836be0 100644
--- a/spec/lib/gitlab/database/partitioning/detached_partition_dropper_spec.rb
+++ b/spec/lib/gitlab/database/partitioning/detached_partition_dropper_spec.rb
@@ -57,17 +57,19 @@ RSpec.describe Gitlab::Database::Partitioning::DetachedPartitionDropper do
SQL
end
- Postgresql::DetachedPartition.create!(table_name: name,
- drop_after: drop_after)
+ Postgresql::DetachedPartition.create!(table_name: name, drop_after: drop_after)
end
describe '#perform' do
context 'when the partition should not be dropped yet' do
it 'does not drop the partition' do
- create_partition(name: :_test_partition,
- from: 2.months.ago, to: 1.month.ago,
- attached: false,
- drop_after: 1.day.from_now)
+ create_partition(
+ name: :_test_partition,
+ from: 2.months.ago,
+ to: 1.month.ago,
+ attached: false,
+ drop_after: 1.day.from_now
+ )
dropper.perform
@@ -77,11 +79,13 @@ RSpec.describe Gitlab::Database::Partitioning::DetachedPartitionDropper do
context 'with a partition to drop' do
before do
- create_partition(name: :_test_partition,
- from: 2.months.ago,
- to: 1.month.ago.beginning_of_month,
- attached: false,
- drop_after: 1.second.ago)
+ create_partition(
+ name: :_test_partition,
+ from: 2.months.ago,
+ to: 1.month.ago.beginning_of_month,
+ attached: false,
+ drop_after: 1.second.ago
+ )
end
it 'drops the partition' do
@@ -159,11 +163,13 @@ RSpec.describe Gitlab::Database::Partitioning::DetachedPartitionDropper do
context 'when the partition to drop is still attached to its table' do
before do
- create_partition(name: :_test_partition,
- from: 2.months.ago,
- to: 1.month.ago.beginning_of_month,
- attached: true,
- drop_after: 1.second.ago)
+ create_partition(
+ name: :_test_partition,
+ from: 2.months.ago,
+ to: 1.month.ago.beginning_of_month,
+ attached: true,
+ drop_after: 1.second.ago
+ )
end
it 'does not drop the partition, but does remove the DetachedPartition entry' do
@@ -192,17 +198,21 @@ RSpec.describe Gitlab::Database::Partitioning::DetachedPartitionDropper do
context 'with multiple partitions to drop' do
before do
- create_partition(name: :_test_partition_1,
- from: 3.months.ago,
- to: 2.months.ago,
- attached: false,
- drop_after: 1.second.ago)
-
- create_partition(name: :_test_partition_2,
- from: 2.months.ago,
- to: 1.month.ago,
- attached: false,
- drop_after: 1.second.ago)
+ create_partition(
+ name: :_test_partition_1,
+ from: 3.months.ago,
+ to: 2.months.ago,
+ attached: false,
+ drop_after: 1.second.ago
+ )
+
+ create_partition(
+ name: :_test_partition_2,
+ from: 2.months.ago,
+ to: 1.month.ago,
+ attached: false,
+ drop_after: 1.second.ago
+ )
end
it 'drops both partitions' do
diff --git a/spec/lib/gitlab/database/partitioning/monthly_strategy_spec.rb b/spec/lib/gitlab/database/partitioning/monthly_strategy_spec.rb
index 3afa338fdf7..8b18e5b6d08 100644
--- a/spec/lib/gitlab/database/partitioning/monthly_strategy_spec.rb
+++ b/spec/lib/gitlab/database/partitioning/monthly_strategy_spec.rb
@@ -235,8 +235,12 @@ RSpec.describe Gitlab::Database::Partitioning::MonthlyStrategy, feature_category
subject { described_class.new(model, partitioning_key, retain_for: 3.months).extra_partitions }
it 'prunes the unbounded partition ending 2020-05-01' do
- min_value_to_may = Gitlab::Database::Partitioning::TimePartition.new(model.table_name, nil, '2020-05-01',
- partition_name: '_test_partitioned_test_000000')
+ min_value_to_may = Gitlab::Database::Partitioning::TimePartition.new(
+ model.table_name,
+ nil,
+ '2020-05-01',
+ partition_name: '_test_partitioned_test_000000'
+ )
expect(subject).to contain_exactly(min_value_to_may)
end
@@ -247,8 +251,18 @@ RSpec.describe Gitlab::Database::Partitioning::MonthlyStrategy, feature_category
it 'prunes the unbounded partition and the partition for May-June' do
expect(subject).to contain_exactly(
- Gitlab::Database::Partitioning::TimePartition.new(model.table_name, nil, '2020-05-01', partition_name: '_test_partitioned_test_000000'),
- Gitlab::Database::Partitioning::TimePartition.new(model.table_name, '2020-05-01', '2020-06-01', partition_name: '_test_partitioned_test_202005')
+ Gitlab::Database::Partitioning::TimePartition.new(
+ model.table_name,
+ nil,
+ '2020-05-01',
+ partition_name: '_test_partitioned_test_000000'
+ ),
+ Gitlab::Database::Partitioning::TimePartition.new(
+ model.table_name,
+ '2020-05-01',
+ '2020-06-01',
+ partition_name: '_test_partitioned_test_202005'
+ )
)
end
@@ -257,8 +271,18 @@ RSpec.describe Gitlab::Database::Partitioning::MonthlyStrategy, feature_category
it 'prunes empty partitions' do
expect(subject).to contain_exactly(
- Gitlab::Database::Partitioning::TimePartition.new(model.table_name, nil, '2020-05-01', partition_name: '_test_partitioned_test_000000'),
- Gitlab::Database::Partitioning::TimePartition.new(model.table_name, '2020-05-01', '2020-06-01', partition_name: '_test_partitioned_test_202005')
+ Gitlab::Database::Partitioning::TimePartition.new(
+ model.table_name,
+ nil,
+ '2020-05-01',
+ partition_name: '_test_partitioned_test_000000'
+ ),
+ Gitlab::Database::Partitioning::TimePartition.new(
+ model.table_name,
+ '2020-05-01',
+ '2020-06-01',
+ partition_name: '_test_partitioned_test_202005'
+ )
)
end
diff --git a/spec/lib/gitlab/database/partitioning/partition_manager_spec.rb b/spec/lib/gitlab/database/partitioning/partition_manager_spec.rb
index 80ffa708d8a..336cd2d912d 100644
--- a/spec/lib/gitlab/database/partitioning/partition_manager_spec.rb
+++ b/spec/lib/gitlab/database/partitioning/partition_manager_spec.rb
@@ -6,6 +6,7 @@ RSpec.describe Gitlab::Database::Partitioning::PartitionManager, feature_categor
include ActiveSupport::Testing::TimeHelpers
include Database::PartitioningHelpers
include ExclusiveLeaseHelpers
+ using RSpec::Parameterized::TableSyntax
let(:partitioned_table_name) { :_test_gitlab_main_my_model_example_table }
@@ -107,14 +108,88 @@ RSpec.describe Gitlab::Database::Partitioning::PartitionManager, feature_categor
end
end
- before do
- my_model.table_name = partitioned_table_name
+ context 'when single database is configured' do
+ before do
+ skip_if_database_exists(:ci)
- create_partitioned_table(connection, partitioned_table_name)
+ my_model.table_name = partitioned_table_name
+
+ create_partitioned_table(connection, partitioned_table_name)
+ end
+
+ it 'creates partitions' do
+ expect { sync_partitions }.to change { find_partitions(my_model.table_name, schema: Gitlab::Database::DYNAMIC_PARTITIONS_SCHEMA).size }.from(0)
+ end
end
- it 'creates partitions' do
- expect { sync_partitions }.to change { find_partitions(my_model.table_name, schema: Gitlab::Database::DYNAMIC_PARTITIONS_SCHEMA).size }.from(0)
+ context 'when multiple databases are configured' do
+ before do
+ skip_if_shared_database(:ci)
+
+ my_model.table_name = partitioned_table_name
+
+ create_partitioned_table(connection, partitioned_table_name)
+
+ stub_feature_flags(automatic_lock_writes_on_partition_tables: ff_enabled)
+
+ sync_partitions
+ end
+
+ where(:gitlab_schema, :database, :expectation) do
+ :gitlab_main | :main | false
+ :gitlab_main | :ci | true
+ :gitlab_ci | :main | true
+ :gitlab_ci | :ci | false
+ end
+ with_them do
+ subject(:sync_partitions) { described_class.new(my_model, connection: connection).sync_partitions }
+
+ let(:partitioned_table_name) { "_test_gitlab_#{database}_my_model_example_#{gitlab_schema}" }
+ let(:base_model) { Gitlab::Database.schemas_to_base_models[gitlab_schema].first }
+ let(:connection) { Gitlab::Database.database_base_models[database.to_s].connection }
+
+ let(:my_model) do
+ Class.new(base_model) do
+ include PartitionedTable
+
+ partitioned_by :created_at, strategy: :monthly
+ end
+ end
+
+ let(:partitions) do
+ Gitlab::Database::PostgresPartition.using_connection(connection) { Gitlab::Database::PostgresPartition.for_parent_table(partitioned_table_name).to_a }
+ end
+
+ let(:partitions_locked_for_writes?) do
+ partitions.map do |partition|
+ Gitlab::Database::LockWritesManager.new(
+ table_name: "#{partition.schema}.#{partition.name}",
+ connection: connection,
+ database_name: gitlab_schema
+ ).table_locked_for_writes?
+ end.all?(true)
+ end
+
+ context 'when feature flag is enabled' do
+ let(:ff_enabled) { true }
+
+ it "matches expectation" do
+ sync_partitions
+
+ expect(partitions_locked_for_writes?).to eq(expectation)
+ end
+ end
+
+ context 'when feature flag is disabled' do
+ let(:ff_enabled) { false }
+
+ it "will not lock created partition" do
+ sync_partitions
+
+ expect(partitions_locked_for_writes?).to eq(false)
+ end
+ end
+ end
end
end
diff --git a/spec/lib/gitlab/database/partitioning/sliding_list_strategy_spec.rb b/spec/lib/gitlab/database/partitioning/sliding_list_strategy_spec.rb
index ac4d345271e..9ca0a1b6e57 100644
--- a/spec/lib/gitlab/database/partitioning/sliding_list_strategy_spec.rb
+++ b/spec/lib/gitlab/database/partitioning/sliding_list_strategy_spec.rb
@@ -15,9 +15,12 @@ RSpec.describe Gitlab::Database::Partitioning::SlidingListStrategy, feature_cate
let(:detach_partition_if) { double('detach_partition_if') }
subject(:strategy) do
- described_class.new(model, :partition,
- next_partition_if: next_partition_if,
- detach_partition_if: detach_partition_if)
+ described_class.new(
+ model,
+ :partition,
+ next_partition_if: next_partition_if,
+ detach_partition_if: detach_partition_if
+ )
end
before do
@@ -213,9 +216,9 @@ RSpec.describe Gitlab::Database::Partitioning::SlidingListStrategy, feature_cate
include PartitionedTable
partitioned_by :partition,
- strategy: :sliding_list,
- next_partition_if: proc { false },
- detach_partition_if: proc { false }
+ strategy: :sliding_list,
+ next_partition_if: proc { false },
+ detach_partition_if: proc { false }
end
end.to raise_error(/ignored_columns/)
end
@@ -228,9 +231,9 @@ RSpec.describe Gitlab::Database::Partitioning::SlidingListStrategy, feature_cate
self.ignored_columns = [:partition]
partitioned_by :partition,
- strategy: :sliding_list,
- next_partition_if: proc { false },
- detach_partition_if: proc { false }
+ strategy: :sliding_list,
+ next_partition_if: proc { false },
+ detach_partition_if: proc { false }
end
end.not_to raise_error
end
@@ -255,9 +258,9 @@ RSpec.describe Gitlab::Database::Partitioning::SlidingListStrategy, feature_cate
detach_partition?(...)
end
partitioned_by :partition,
- strategy: :sliding_list,
- next_partition_if: method(:next_partition_if_wrapper),
- detach_partition_if: method(:detach_partition_if_wrapper)
+ strategy: :sliding_list,
+ next_partition_if: method(:next_partition_if_wrapper),
+ detach_partition_if: method(:detach_partition_if_wrapper)
def self.next_partition?(current_partition); end
diff --git a/spec/lib/gitlab/database/partitioning_migration_helpers/index_helpers_spec.rb b/spec/lib/gitlab/database/partitioning_migration_helpers/index_helpers_spec.rb
index a81c8a5a49c..aa644885306 100644
--- a/spec/lib/gitlab/database/partitioning_migration_helpers/index_helpers_spec.rb
+++ b/spec/lib/gitlab/database/partitioning_migration_helpers/index_helpers_spec.rb
@@ -99,8 +99,11 @@ RSpec.describe Gitlab::Database::PartitioningMigrationHelpers::IndexHelpers do
expect(migration).to receive(:add_index)
.with(table_name, column_name, { name: index_name, where: 'x > 0', unique: true })
- migration.add_concurrent_partitioned_index(table_name, column_name,
- { name: index_name, where: 'x > 0', unique: true })
+ migration.add_concurrent_partitioned_index(
+ table_name,
+ column_name,
+ { name: index_name, where: 'x > 0', unique: true }
+ )
end
end
diff --git a/spec/lib/gitlab/database/partitioning_migration_helpers/table_management_helpers_spec.rb b/spec/lib/gitlab/database/partitioning_migration_helpers/table_management_helpers_spec.rb
index 6a947044317..31c669ff330 100644
--- a/spec/lib/gitlab/database/partitioning_migration_helpers/table_management_helpers_spec.rb
+++ b/spec/lib/gitlab/database/partitioning_migration_helpers/table_management_helpers_spec.rb
@@ -2,6 +2,173 @@
require 'spec_helper'
+RSpec.shared_examples "a measurable object" do
+ context 'when the table is not allowed' do
+ let(:source_table) { :_test_this_table_is_not_allowed }
+
+ it 'raises an error' do
+ expect(migration).to receive(:assert_table_is_allowed).with(source_table).and_call_original
+
+ expect do
+ subject
+ end.to raise_error(/#{source_table} is not allowed for use/)
+ end
+ end
+
+ context 'when run inside a transaction block' do
+ it 'raises an error' do
+ expect(migration).to receive(:transaction_open?).and_return(true)
+
+ expect do
+ subject
+ end.to raise_error(/can not be run inside a transaction/)
+ end
+ end
+
+ context 'when the given table does not have a primary key' do
+ it 'raises an error' do
+ migration.execute(<<~SQL)
+ ALTER TABLE #{source_table}
+ DROP CONSTRAINT #{source_table}_pkey
+ SQL
+
+ expect do
+ subject
+ end.to raise_error(/primary key not defined for #{source_table}/)
+ end
+ end
+
+ it 'creates the partitioned table with the same non-key columns' do
+ subject
+
+ copied_columns = filter_columns_by_name(connection.columns(partitioned_table), new_primary_key)
+ original_columns = filter_columns_by_name(connection.columns(source_table), new_primary_key)
+
+ expect(copied_columns).to match_array(original_columns)
+ end
+
+ it 'removes the default from the primary key column' do
+ subject
+
+ pk_column = connection.columns(partitioned_table).find { |c| c.name == old_primary_key }
+
+ expect(pk_column.default_function).to be_nil
+ end
+
+ describe 'constructing the partitioned table' do
+ it 'creates a table partitioned by the proper column' do
+ subject
+
+ expect(connection.table_exists?(partitioned_table)).to be(true)
+ expect(connection.primary_key(partitioned_table)).to eq(new_primary_key)
+
+ expect_table_partitioned_by(partitioned_table, [partition_column_name])
+ end
+
+ it 'requires the migration helper to be run in DDL mode' do
+ expect(Gitlab::Database::QueryAnalyzers::RestrictAllowedSchemas).to receive(:require_ddl_mode!)
+
+ subject
+
+ expect(connection.table_exists?(partitioned_table)).to be(true)
+ expect(connection.primary_key(partitioned_table)).to eq(new_primary_key)
+
+ expect_table_partitioned_by(partitioned_table, [partition_column_name])
+ end
+
+ it 'changes the primary key datatype to bigint' do
+ subject
+
+ pk_column = connection.columns(partitioned_table).find { |c| c.name == old_primary_key }
+
+ expect(pk_column.sql_type).to eq('bigint')
+ end
+
+ it 'removes the default from the primary key column' do
+ subject
+
+ pk_column = connection.columns(partitioned_table).find { |c| c.name == old_primary_key }
+
+ expect(pk_column.default_function).to be_nil
+ end
+
+ it 'creates the partitioned table with the same non-key columns' do
+ subject
+
+ copied_columns = filter_columns_by_name(connection.columns(partitioned_table), new_primary_key)
+ original_columns = filter_columns_by_name(connection.columns(source_table), new_primary_key)
+
+ expect(copied_columns).to match_array(original_columns)
+ end
+ end
+
+ describe 'keeping data in sync with the partitioned table' do
+ before do
+ partitioned_model.primary_key = :id
+ partitioned_model.table_name = partitioned_table
+ end
+
+ it 'creates a trigger function on the original table' do
+ expect_function_not_to_exist(function_name)
+ expect_trigger_not_to_exist(source_table, trigger_name)
+
+ subject
+
+ expect_function_to_exist(function_name)
+ expect_valid_function_trigger(source_table, trigger_name, function_name, after: %w[delete insert update])
+ end
+
+ it 'syncs inserts to the partitioned tables' do
+ subject
+
+ expect(partitioned_model.count).to eq(0)
+
+ first_record = source_model.create!(name: 'Bob', age: 20, created_at: timestamp, external_id: 1, updated_at: timestamp)
+ second_record = source_model.create!(name: 'Alice', age: 30, created_at: timestamp, external_id: 2, updated_at: timestamp)
+
+ expect(partitioned_model.count).to eq(2)
+ expect(partitioned_model.find(first_record.id).attributes).to eq(first_record.attributes)
+ expect(partitioned_model.find(second_record.id).attributes).to eq(second_record.attributes)
+ end
+
+ it 'syncs updates to the partitioned tables' do
+ subject
+
+ first_record = source_model.create!(name: 'Bob', age: 20, created_at: timestamp, external_id: 1, updated_at: timestamp)
+ second_record = source_model.create!(name: 'Alice', age: 30, created_at: timestamp, external_id: 2, updated_at: timestamp)
+
+ expect(partitioned_model.count).to eq(2)
+
+ first_copy = partitioned_model.find(first_record.id)
+ second_copy = partitioned_model.find(second_record.id)
+
+ expect(first_copy.attributes).to eq(first_record.attributes)
+ expect(second_copy.attributes).to eq(second_record.attributes)
+
+ first_record.update!(age: 21, updated_at: timestamp + 1.hour, external_id: 3)
+
+ expect(partitioned_model.count).to eq(2)
+ expect(first_copy.reload.attributes).to eq(first_record.attributes)
+ expect(second_copy.reload.attributes).to eq(second_record.attributes)
+ end
+
+ it 'syncs deletes to the partitioned tables' do
+ subject
+
+ first_record = source_model.create!(name: 'Bob', age: 20, created_at: timestamp, external_id: 1, updated_at: timestamp)
+ second_record = source_model.create!(name: 'Alice', age: 30, created_at: timestamp, external_id: 2, updated_at: timestamp)
+
+ expect(partitioned_model.count).to eq(2)
+
+ first_record.destroy!
+
+ expect(partitioned_model.count).to eq(1)
+ expect(partitioned_model.find_by_id(first_record.id)).to be_nil
+ expect(partitioned_model.find(second_record.id).attributes).to eq(second_record.attributes)
+ end
+ end
+end
+
RSpec.describe Gitlab::Database::PartitioningMigrationHelpers::TableManagementHelpers, feature_category: :database do
include Database::PartitioningHelpers
include Database::TriggerHelpers
@@ -18,6 +185,7 @@ RSpec.describe Gitlab::Database::PartitioningMigrationHelpers::TableManagementHe
let(:partitioned_table) { :_test_migration_partitioned_table }
let(:function_name) { :_test_migration_function_name }
let(:trigger_name) { :_test_migration_trigger_name }
+ let(:partition_column2) { 'external_id' }
let(:partition_column) { 'created_at' }
let(:min_date) { Date.new(2019, 12) }
let(:max_date) { Date.new(2020, 3) }
@@ -29,6 +197,7 @@ RSpec.describe Gitlab::Database::PartitioningMigrationHelpers::TableManagementHe
migration.create_table source_table do |t|
t.string :name, null: false
t.integer :age, null: false
+ t.integer partition_column2
t.datetime partition_column
t.datetime :updated_at
end
@@ -51,13 +220,15 @@ RSpec.describe Gitlab::Database::PartitioningMigrationHelpers::TableManagementHe
end
it 'delegates to a method on List::ConvertTable' do
- expect_next_instance_of(Gitlab::Database::Partitioning::List::ConvertTable,
- migration_context: migration,
- table_name: source_table,
- parent_table_name: partitioned_table,
- partitioning_column: partition_column,
- zero_partition_value: min_date,
- **extra_options) do |converter|
+ expect_next_instance_of(
+ Gitlab::Database::Partitioning::List::ConvertTable,
+ migration_context: migration,
+ table_name: source_table,
+ parent_table_name: partitioned_table,
+ partitioning_column: partition_column,
+ zero_partition_value: min_date,
+ **extra_options
+ ) do |converter|
expect(converter).to receive(expected_method)
end
@@ -70,11 +241,13 @@ RSpec.describe Gitlab::Database::PartitioningMigrationHelpers::TableManagementHe
let(:lock_tables) { [source_table] }
let(:expected_method) { :partition }
let(:migrate) do
- migration.convert_table_to_first_list_partition(table_name: source_table,
- partitioning_column: partition_column,
- parent_table_name: partitioned_table,
- initial_partitioning_value: min_date,
- lock_tables: lock_tables)
+ migration.convert_table_to_first_list_partition(
+ table_name: source_table,
+ partitioning_column: partition_column,
+ parent_table_name: partitioned_table,
+ initial_partitioning_value: min_date,
+ lock_tables: lock_tables
+ )
end
end
end
@@ -83,10 +256,12 @@ RSpec.describe Gitlab::Database::PartitioningMigrationHelpers::TableManagementHe
it_behaves_like 'delegates to ConvertTable' do
let(:expected_method) { :revert_partitioning }
let(:migrate) do
- migration.revert_converting_table_to_first_list_partition(table_name: source_table,
- partitioning_column: partition_column,
- parent_table_name: partitioned_table,
- initial_partitioning_value: min_date)
+ migration.revert_converting_table_to_first_list_partition(
+ table_name: source_table,
+ partitioning_column: partition_column,
+ parent_table_name: partitioned_table,
+ initial_partitioning_value: min_date
+ )
end
end
end
@@ -95,11 +270,13 @@ RSpec.describe Gitlab::Database::PartitioningMigrationHelpers::TableManagementHe
it_behaves_like 'delegates to ConvertTable' do
let(:expected_method) { :prepare_for_partitioning }
let(:migrate) do
- migration.prepare_constraint_for_list_partitioning(table_name: source_table,
- partitioning_column: partition_column,
- parent_table_name: partitioned_table,
- initial_partitioning_value: min_date,
- async: false)
+ migration.prepare_constraint_for_list_partitioning(
+ table_name: source_table,
+ partitioning_column: partition_column,
+ parent_table_name: partitioned_table,
+ initial_partitioning_value: min_date,
+ async: false
+ )
end
end
end
@@ -108,41 +285,200 @@ RSpec.describe Gitlab::Database::PartitioningMigrationHelpers::TableManagementHe
it_behaves_like 'delegates to ConvertTable' do
let(:expected_method) { :revert_preparation_for_partitioning }
let(:migrate) do
- migration.revert_preparing_constraint_for_list_partitioning(table_name: source_table,
- partitioning_column: partition_column,
- parent_table_name: partitioned_table,
- initial_partitioning_value: min_date)
+ migration.revert_preparing_constraint_for_list_partitioning(
+ table_name: source_table,
+ partitioning_column: partition_column,
+ parent_table_name: partitioned_table,
+ initial_partitioning_value: min_date
+ )
end
end
end
end
- describe '#partition_table_by_date' do
- let(:partition_column) { 'created_at' }
+ describe '#partition_table_by_int_range' do
let(:old_primary_key) { 'id' }
- let(:new_primary_key) { [old_primary_key, partition_column] }
+ let(:new_primary_key) { ['id', partition_column2] }
+ let(:partition_column_name) { partition_column2 }
+ let(:partitioned_model) { Class.new(ActiveRecord::Base) }
+ let(:timestamp) { Time.utc(2019, 12, 1, 12).round }
+ let(:partition_size) { 500 }
- context 'when the table is not allowed' do
- let(:source_table) { :_test_this_table_is_not_allowed }
+ subject { migration.partition_table_by_int_range(source_table, partition_column2, partition_size: partition_size, primary_key: ['id', partition_column2]) }
- it 'raises an error' do
- expect(migration).to receive(:assert_table_is_allowed).with(source_table).and_call_original
+ include_examples "a measurable object"
- expect do
- migration.partition_table_by_date source_table, partition_column, min_date: min_date, max_date: max_date
- end.to raise_error(/#{source_table} is not allowed for use/)
+ context 'simulates the merge_request_diff_commits migration' do
+ let(:table_name) { '_test_merge_request_diff_commits' }
+ let(:partition_column_name) { 'relative_order' }
+ let(:partition_size) { 2 }
+ let(:partitions) do
+ {
+ '1' => %w[1 3],
+ '3' => %w[3 5],
+ '5' => %w[5 7],
+ '7' => %w[7 9],
+ '9' => %w[9 11],
+ '11' => %w[11 13]
+ }
+ end
+
+ let(:buffer_partitions) do
+ {
+ '13' => %w[13 15],
+ '15' => %w[15 17],
+ '17' => %w[17 19],
+ '19' => %w[19 21],
+ '21' => %w[21 23],
+ '23' => %w[23 25]
+ }
+ end
+
+ let(:new_table_defition) do
+ {
+ new_path: { default: 'test', null: true, sql_type: 'text' },
+ merge_request_diff_id: { default: nil, null: false, sql_type: 'bigint' },
+ relative_order: { default: nil, null: false, sql_type: 'integer' }
+ }
+ end
+
+ let(:primary_key) { %w[merge_request_diff_id relative_order] }
+
+ before do
+ migration.create_table table_name, primary_key: primary_key do |t|
+ t.integer :merge_request_diff_id, null: false, default: 1
+ t.integer :relative_order, null: false
+ t.text :new_path, null: true, default: 'test'
+ end
+
+ source_model.table_name = table_name
+ end
+
+ it 'creates the partitions' do
+ migration.partition_table_by_int_range(table_name, partition_column_name, partition_size: partition_size, primary_key: primary_key)
+
+ expect_range_partitions_for(partitioned_table, partitions.merge(buffer_partitions))
+ end
+
+ it 'creates a composite primary key' do
+ migration.partition_table_by_int_range(table_name, partition_column_name, partition_size: partition_size, primary_key: primary_key)
+
+ expect(connection.primary_key(:_test_migration_partitioned_table)).to eql(%w[merge_request_diff_id relative_order])
+ end
+
+ it 'applies the correct column schema for the new table' do
+ migration.partition_table_by_int_range(table_name, partition_column_name, partition_size: partition_size, primary_key: primary_key)
+
+ columns = connection.columns(:_test_migration_partitioned_table)
+
+ columns.each do |column|
+ column_name = column.name.to_sym
+
+ expect(column.default).to eql(new_table_defition[column_name][:default])
+ expect(column.null).to eql(new_table_defition[column_name][:null])
+ expect(column.sql_type).to eql(new_table_defition[column_name][:sql_type])
+ end
+ end
+
+ it 'creates multiple partitions' do
+ migration.partition_table_by_int_range(table_name, partition_column_name, partition_size: 500, primary_key: primary_key)
+
+ expect_range_partitions_for(partitioned_table, {
+ '1' => %w[1 501],
+ '501' => %w[501 1001],
+ '1001' => %w[1001 1501],
+ '1501' => %w[1501 2001],
+ '2001' => %w[2001 2501],
+ '2501' => %w[2501 3001],
+ '3001' => %w[3001 3501],
+ '3501' => %w[3501 4001],
+ '4001' => %w[4001 4501],
+ '4501' => %w[4501 5001],
+ '5001' => %w[5001 5501],
+ '5501' => %w[5501 6001]
+ })
+ end
+
+ context 'when the table is not empty' do
+ before do
+ source_model.create!(merge_request_diff_id: 1, relative_order: 7, new_path: 'new_path')
+ end
+
+ let(:partition_size) { 2 }
+
+ let(:partitions) do
+ {
+ '1' => %w[1 3],
+ '3' => %w[3 5],
+ '5' => %w[5 7]
+ }
+ end
+
+ let(:buffer_partitions) do
+ {
+ '7' => %w[7 9],
+ '9' => %w[9 11],
+ '11' => %w[11 13],
+ '13' => %w[13 15],
+ '15' => %w[15 17],
+ '17' => %w[17 19]
+ }
+ end
+
+ it 'defaults the min_id to 1 and the max_id to 7' do
+ migration.partition_table_by_int_range(table_name, partition_column_name, partition_size: partition_size, primary_key: primary_key)
+
+ expect_range_partitions_for(partitioned_table, partitions.merge(buffer_partitions))
+ end
end
end
- context 'when run inside a transaction block' do
+ context 'when an invalid partition column is given' do
+ let(:invalid_column) { :_this_is_not_real }
+
it 'raises an error' do
- expect(migration).to receive(:transaction_open?).and_return(true)
+ expect do
+ migration.partition_table_by_int_range(source_table, invalid_column, partition_size: partition_size, primary_key: ['id'])
+ end.to raise_error(/partition column #{invalid_column} does not exist/)
+ end
+ end
+ context 'when partition_size is less than 1' do
+ let(:partition_size) { 1 }
+
+ it 'raises an error' do
expect do
- migration.partition_table_by_date source_table, partition_column, min_date: min_date, max_date: max_date
- end.to raise_error(/can not be run inside a transaction/)
+ subject
+ end.to raise_error(/partition_size must be greater than 1/)
+ end
+ end
+
+ context 'when the partitioned table already exists' do
+ before do
+ migration.send(:create_range_id_partitioned_copy, source_table,
+ migration.send(:make_partitioned_table_name, source_table),
+ connection.columns(source_table).find { |c| c.name == partition_column2 },
+ connection.columns(source_table).select { |c| new_primary_key.include?(c.name) })
+ end
+
+ it 'raises an error' do
+ expect(Gitlab::AppLogger).to receive(:warn).with(/Partitioned table not created because it already exists/)
+ expect { subject }.not_to raise_error
end
end
+ end
+
+ describe '#partition_table_by_date' do
+ let(:partition_column) { 'created_at' }
+ let(:old_primary_key) { 'id' }
+ let(:new_primary_key) { [old_primary_key, partition_column] }
+ let(:partition_column_name) { 'created_at' }
+ let(:partitioned_model) { Class.new(ActiveRecord::Base) }
+ let(:timestamp) { Time.utc(2019, 12, 1, 12).round }
+
+ subject { migration.partition_table_by_date source_table, partition_column, min_date: min_date, max_date: max_date }
+
+ include_examples "a measurable object"
context 'when the the max_date is less than the min_date' do
let(:max_date) { Time.utc(2019, 6) }
@@ -164,19 +500,6 @@ RSpec.describe Gitlab::Database::PartitioningMigrationHelpers::TableManagementHe
end
end
- context 'when the given table does not have a primary key' do
- it 'raises an error' do
- migration.execute(<<~SQL)
- ALTER TABLE #{source_table}
- DROP CONSTRAINT #{source_table}_pkey
- SQL
-
- expect do
- migration.partition_table_by_date source_table, partition_column, min_date: min_date, max_date: max_date
- end.to raise_error(/primary key not defined for #{source_table}/)
- end
- end
-
context 'when an invalid partition column is given' do
let(:invalid_column) { :_this_is_not_real }
@@ -188,34 +511,6 @@ RSpec.describe Gitlab::Database::PartitioningMigrationHelpers::TableManagementHe
end
describe 'constructing the partitioned table' do
- it 'creates a table partitioned by the proper column' do
- migration.partition_table_by_date source_table, partition_column, min_date: min_date, max_date: max_date
-
- expect(connection.table_exists?(partitioned_table)).to be(true)
- expect(connection.primary_key(partitioned_table)).to eq(new_primary_key)
-
- expect_table_partitioned_by(partitioned_table, [partition_column])
- end
-
- it 'requires the migration helper to be run in DDL mode' do
- expect(Gitlab::Database::QueryAnalyzers::RestrictAllowedSchemas).to receive(:require_ddl_mode!)
-
- migration.partition_table_by_date source_table, partition_column, min_date: min_date, max_date: max_date
-
- expect(connection.table_exists?(partitioned_table)).to be(true)
- expect(connection.primary_key(partitioned_table)).to eq(new_primary_key)
-
- expect_table_partitioned_by(partitioned_table, [partition_column])
- end
-
- it 'changes the primary key datatype to bigint' do
- migration.partition_table_by_date source_table, partition_column, min_date: min_date, max_date: max_date
-
- pk_column = connection.columns(partitioned_table).find { |c| c.name == old_primary_key }
-
- expect(pk_column.sql_type).to eq('bigint')
- end
-
context 'with a non-integer primary key datatype' do
before do
connection.create_table non_int_table, id: false do |t|
@@ -238,23 +533,6 @@ RSpec.describe Gitlab::Database::PartitioningMigrationHelpers::TableManagementHe
end
end
- it 'removes the default from the primary key column' do
- migration.partition_table_by_date source_table, partition_column, min_date: min_date, max_date: max_date
-
- pk_column = connection.columns(partitioned_table).find { |c| c.name == old_primary_key }
-
- expect(pk_column.default_function).to be_nil
- end
-
- it 'creates the partitioned table with the same non-key columns' do
- migration.partition_table_by_date source_table, partition_column, min_date: min_date, max_date: max_date
-
- copied_columns = filter_columns_by_name(connection.columns(partitioned_table), new_primary_key)
- original_columns = filter_columns_by_name(connection.columns(source_table), new_primary_key)
-
- expect(copied_columns).to match_array(original_columns)
- end
-
it 'creates a partition spanning over each month in the range given' do
migration.partition_table_by_date source_table, partition_column, min_date: min_date, max_date: max_date
@@ -340,75 +618,6 @@ RSpec.describe Gitlab::Database::PartitioningMigrationHelpers::TableManagementHe
end
end
end
-
- describe 'keeping data in sync with the partitioned table' do
- let(:partitioned_model) { Class.new(ActiveRecord::Base) }
- let(:timestamp) { Time.utc(2019, 12, 1, 12).round }
-
- before do
- partitioned_model.primary_key = :id
- partitioned_model.table_name = partitioned_table
- end
-
- it 'creates a trigger function on the original table' do
- expect_function_not_to_exist(function_name)
- expect_trigger_not_to_exist(source_table, trigger_name)
-
- migration.partition_table_by_date source_table, partition_column, min_date: min_date, max_date: max_date
-
- expect_function_to_exist(function_name)
- expect_valid_function_trigger(source_table, trigger_name, function_name, after: %w[delete insert update])
- end
-
- it 'syncs inserts to the partitioned tables' do
- migration.partition_table_by_date source_table, partition_column, min_date: min_date, max_date: max_date
-
- expect(partitioned_model.count).to eq(0)
-
- first_record = source_model.create!(name: 'Bob', age: 20, created_at: timestamp, updated_at: timestamp)
- second_record = source_model.create!(name: 'Alice', age: 30, created_at: timestamp, updated_at: timestamp)
-
- expect(partitioned_model.count).to eq(2)
- expect(partitioned_model.find(first_record.id).attributes).to eq(first_record.attributes)
- expect(partitioned_model.find(second_record.id).attributes).to eq(second_record.attributes)
- end
-
- it 'syncs updates to the partitioned tables' do
- migration.partition_table_by_date source_table, partition_column, min_date: min_date, max_date: max_date
-
- first_record = source_model.create!(name: 'Bob', age: 20, created_at: timestamp, updated_at: timestamp)
- second_record = source_model.create!(name: 'Alice', age: 30, created_at: timestamp, updated_at: timestamp)
-
- expect(partitioned_model.count).to eq(2)
-
- first_copy = partitioned_model.find(first_record.id)
- second_copy = partitioned_model.find(second_record.id)
-
- expect(first_copy.attributes).to eq(first_record.attributes)
- expect(second_copy.attributes).to eq(second_record.attributes)
-
- first_record.update!(age: 21, updated_at: timestamp + 1.hour)
-
- expect(partitioned_model.count).to eq(2)
- expect(first_copy.reload.attributes).to eq(first_record.attributes)
- expect(second_copy.reload.attributes).to eq(second_record.attributes)
- end
-
- it 'syncs deletes to the partitioned tables' do
- migration.partition_table_by_date source_table, partition_column, min_date: min_date, max_date: max_date
-
- first_record = source_model.create!(name: 'Bob', age: 20, created_at: timestamp, updated_at: timestamp)
- second_record = source_model.create!(name: 'Alice', age: 30, created_at: timestamp, updated_at: timestamp)
-
- expect(partitioned_model.count).to eq(2)
-
- first_record.destroy!
-
- expect(partitioned_model.count).to eq(1)
- expect(partitioned_model.find_by_id(first_record.id)).to be_nil
- expect(partitioned_model.find(second_record.id).attributes).to eq(second_record.attributes)
- end
- end
end
describe '#drop_partitioned_table_for' do
diff --git a/spec/lib/gitlab/database/postgres_constraint_spec.rb b/spec/lib/gitlab/database/postgres_constraint_spec.rb
index 75084a69115..140180540e0 100644
--- a/spec/lib/gitlab/database/postgres_constraint_spec.rb
+++ b/spec/lib/gitlab/database/postgres_constraint_spec.rb
@@ -51,9 +51,11 @@ RSpec.describe Gitlab::Database::PostgresConstraint, type: :model do
subject(:check_constraints) { described_class.check_constraints.by_table_identifier(table_identifier) }
it 'finds check constraints for the table' do
- expect(check_constraints.map(&:name)).to contain_exactly(check_constraint_a_positive,
- check_constraint_a_gt_b,
- invalid_constraint_a)
+ expect(check_constraints.map(&:name)).to contain_exactly(
+ check_constraint_a_positive,
+ check_constraint_a_gt_b,
+ invalid_constraint_a
+ )
end
it 'includes columns for the check constraints', :aggregate_failures do
@@ -108,8 +110,12 @@ RSpec.describe Gitlab::Database::PostgresConstraint, type: :model do
describe '#including_column' do
it 'only matches constraints on the given column' do
constraints_on_a = described_class.by_table_identifier(table_identifier).including_column('a').map(&:name)
- expect(constraints_on_a).to contain_exactly(check_constraint_a_positive, check_constraint_a_gt_b,
- unique_constraint_a, invalid_constraint_a)
+ expect(constraints_on_a).to contain_exactly(
+ check_constraint_a_positive,
+ check_constraint_a_gt_b,
+ unique_constraint_a,
+ invalid_constraint_a
+ )
end
end
diff --git a/spec/lib/gitlab/database/postgres_index_spec.rb b/spec/lib/gitlab/database/postgres_index_spec.rb
index d8a2612caf3..2e654a33a58 100644
--- a/spec/lib/gitlab/database/postgres_index_spec.rb
+++ b/spec/lib/gitlab/database/postgres_index_spec.rb
@@ -40,7 +40,7 @@ RSpec.describe Gitlab::Database::PostgresIndex do
it 'only btree and gist indexes' do
types = described_class.reindexing_support.map(&:type).uniq
- expect(types & %w(btree gist)).to eq(types)
+ expect(types & %w[btree gist]).to eq(types)
end
context 'with leftover indexes' do
@@ -71,7 +71,7 @@ RSpec.describe Gitlab::Database::PostgresIndex do
end
it 'retrieves leftover indexes matching the /_ccnew[0-9]*$/ pattern' do
- expect(subject.map(&:name)).to eq(%w(foobar_ccnew foobar_ccnew1))
+ expect(subject.map(&:name)).to eq(%w[foobar_ccnew foobar_ccnew1])
end
end
diff --git a/spec/lib/gitlab/database/query_analyzers/gitlab_schemas_metrics_spec.rb b/spec/lib/gitlab/database/query_analyzers/gitlab_schemas_metrics_spec.rb
index f325060e592..1909e134e66 100644
--- a/spec/lib/gitlab/database/query_analyzers/gitlab_schemas_metrics_spec.rb
+++ b/spec/lib/gitlab/database/query_analyzers/gitlab_schemas_metrics_spec.rb
@@ -35,7 +35,7 @@ RSpec.describe Gitlab::Database::QueryAnalyzers::GitlabSchemasMetrics, query_ana
},
"for query accessing gitlab_ci and gitlab_main" => {
model: ApplicationRecord,
- sql: "SELECT 1 FROM projects LEFT JOIN ci_builds ON ci_builds.project_id=projects.id",
+ sql: "SELECT 1 FROM projects LEFT JOIN p_ci_builds ON p_ci_builds.project_id=projects.id",
expectations: {
gitlab_schemas: "gitlab_ci,gitlab_main_cell",
db_config_name: "main"
@@ -43,7 +43,7 @@ RSpec.describe Gitlab::Database::QueryAnalyzers::GitlabSchemasMetrics, query_ana
},
"for query accessing gitlab_ci and gitlab_main the gitlab_schemas is always ordered" => {
model: ApplicationRecord,
- sql: "SELECT 1 FROM ci_builds LEFT JOIN projects ON ci_builds.project_id=projects.id",
+ sql: "SELECT 1 FROM p_ci_builds LEFT JOIN projects ON p_ci_builds.project_id=projects.id",
expectations: {
gitlab_schemas: "gitlab_ci,gitlab_main_cell",
db_config_name: "main"
@@ -51,7 +51,7 @@ RSpec.describe Gitlab::Database::QueryAnalyzers::GitlabSchemasMetrics, query_ana
},
"for query accessing CI database" => {
model: Ci::ApplicationRecord,
- sql: "SELECT 1 FROM ci_builds",
+ sql: "SELECT 1 FROM p_ci_builds",
expectations: {
gitlab_schemas: "gitlab_ci",
db_config_name: "ci"
diff --git a/spec/lib/gitlab/database/query_analyzers/gitlab_schemas_validate_connection_spec.rb b/spec/lib/gitlab/database/query_analyzers/gitlab_schemas_validate_connection_spec.rb
index e3ff5ab4779..0664508fa8d 100644
--- a/spec/lib/gitlab/database/query_analyzers/gitlab_schemas_validate_connection_spec.rb
+++ b/spec/lib/gitlab/database/query_analyzers/gitlab_schemas_validate_connection_spec.rb
@@ -26,14 +26,14 @@ RSpec.describe Gitlab::Database::QueryAnalyzers::GitlabSchemasValidateConnection
},
"for query accessing gitlab_ci and gitlab_main" => {
model: ApplicationRecord,
- sql: "SELECT 1 FROM projects LEFT JOIN ci_builds ON ci_builds.project_id=projects.id",
- expect_error: /The query tried to access \["projects", "ci_builds"\]/,
+ sql: "SELECT 1 FROM projects LEFT JOIN p_ci_builds ON p_ci_builds.project_id=projects.id",
+ expect_error: /The query tried to access \["projects", "p_ci_builds"\]/,
setup: -> (_) { skip_if_shared_database(:ci) }
},
"for query accessing gitlab_ci and gitlab_main the gitlab_schemas is always ordered" => {
model: ApplicationRecord,
- sql: "SELECT 1 FROM ci_builds LEFT JOIN projects ON ci_builds.project_id=projects.id",
- expect_error: /The query tried to access \["ci_builds", "projects"\]/,
+ sql: "SELECT 1 FROM p_ci_builds LEFT JOIN projects ON p_ci_builds.project_id=projects.id",
+ expect_error: /The query tried to access \["p_ci_builds", "projects"\]/,
setup: -> (_) { skip_if_shared_database(:ci) }
},
"for query accessing main table from CI database" => {
@@ -44,13 +44,13 @@ RSpec.describe Gitlab::Database::QueryAnalyzers::GitlabSchemasValidateConnection
},
"for query accessing CI database" => {
model: Ci::ApplicationRecord,
- sql: "SELECT 1 FROM ci_builds",
+ sql: "SELECT 1 FROM p_ci_builds",
expect_error: nil
},
"for query accessing CI table from main database" => {
model: ::ApplicationRecord,
- sql: "SELECT 1 FROM ci_builds",
- expect_error: /The query tried to access \["ci_builds"\]/,
+ sql: "SELECT 1 FROM p_ci_builds",
+ expect_error: /The query tried to access \["p_ci_builds"\]/,
setup: -> (_) { skip_if_shared_database(:ci) }
},
"for query accessing unknown gitlab_schema" => {
@@ -89,7 +89,7 @@ RSpec.describe Gitlab::Database::QueryAnalyzers::GitlabSchemasValidateConnection
it "throws an error when trying to access a table that belongs to the gitlab_ci schema from the main database" do
expect do
- ApplicationRecord.connection.execute("select * from ci_builds limit 1")
+ ApplicationRecord.connection.execute("select * from p_ci_builds limit 1")
end.to raise_error(Gitlab::Database::QueryAnalyzers::GitlabSchemasValidateConnection::CrossSchemaAccessError)
end
end
diff --git a/spec/lib/gitlab/database/query_analyzers/prevent_set_operator_mismatch/columns_spec.rb b/spec/lib/gitlab/database/query_analyzers/prevent_set_operator_mismatch/columns_spec.rb
new file mode 100644
index 00000000000..042bc297520
--- /dev/null
+++ b/spec/lib/gitlab/database/query_analyzers/prevent_set_operator_mismatch/columns_spec.rb
@@ -0,0 +1,88 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::Database::QueryAnalyzers::PreventSetOperatorMismatch::Columns,
+ feature_category: :cell do
+ include PreventSetOperatorMismatchHelper
+
+ let_it_be(:namespace_columns) { Namespace.column_names.join(',') }
+
+ describe '.types' do
+ let(:node) { sql_select_node(sql) }
+ let(:cte_refs) { {} }
+ let(:select_stmt) do
+ Gitlab::Database::QueryAnalyzers::PreventSetOperatorMismatch::SelectStmt.new(node, cte_refs)
+ end
+
+ subject { described_class.types(select_stmt) }
+
+ context 'when static column' do
+ let(:sql) { 'SELECT id FROM namespaces' }
+
+ it do
+ expect(subject).to contain_exactly(Type::STATIC)
+ end
+
+ context 'with dynamic reference' do
+ let(:sql) { 'SELECT id FROM (SELECT * FROM namespaces) AS xyz' }
+
+ it do
+ expect(subject).to contain_exactly(Type::STATIC)
+ end
+ end
+ end
+
+ context 'when dynamic column' do
+ let(:sql) { 'SELECT * FROM namespaces' }
+
+ it do
+ expect(subject).to contain_exactly(Type::DYNAMIC)
+ end
+
+ context 'with static reference' do
+ let(:sql) { 'SELECT * FROM (SELECT 1) AS xyz' }
+
+ it do
+ expect(subject).to contain_exactly(Type::STATIC)
+ end
+ end
+ end
+
+ context 'when reference has errors' do
+ let(:cte_refs) { { 'namespaces' => [Type::INVALID].to_set } }
+ let(:sql) { 'SELECT * FROM namespaces' }
+
+ it 'forward through error state' do
+ expect(subject).to include(Type::INVALID)
+ end
+ end
+
+ context 'when static and dynamic columns' do
+ let(:sql) { 'SELECT *, users.id FROM namespaces, users' }
+
+ it do
+ expect(subject).to contain_exactly(Type::DYNAMIC, Type::STATIC)
+ end
+ end
+
+ context 'when static column and error' do
+ let(:error_column) { "SELECT #{namespace_columns} FROM namespaces UNION SELECT * FROM namespaces" }
+ let(:sql) { "SELECT id, (#{error_column}) FROM namespaces" }
+
+ it do
+ expect(subject).to contain_exactly(Type::STATIC, Type::INVALID)
+ end
+ end
+
+ context 'when dynamic column and error' do
+ let(:error_column) { "SELECT #{namespace_columns} FROM namespaces UNION SELECT * FROM namespaces" }
+ let(:sql) { "SELECT *, (#{error_column}) FROM namespaces" }
+
+ it do
+ # The sub-select is treated as a Type::STATIC column for now. This could do with some refinement.
+ expect(subject).to contain_exactly(Type::DYNAMIC, Type::STATIC, Type::INVALID)
+ end
+ end
+ end
+end
diff --git a/spec/lib/gitlab/database/query_analyzers/prevent_set_operator_mismatch/common_table_expressions_spec.rb b/spec/lib/gitlab/database/query_analyzers/prevent_set_operator_mismatch/common_table_expressions_spec.rb
new file mode 100644
index 00000000000..eacaa643ba5
--- /dev/null
+++ b/spec/lib/gitlab/database/query_analyzers/prevent_set_operator_mismatch/common_table_expressions_spec.rb
@@ -0,0 +1,97 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::Database::QueryAnalyzers::PreventSetOperatorMismatch::CommonTableExpressions,
+ feature_category: :cell do
+ include PreventSetOperatorMismatchHelper
+
+ describe '.references' do
+ let(:node) { sql_select_node(sql) }
+ let(:cte_refs) { {} }
+
+ subject { described_class.references(node, cte_refs) }
+
+ context 'when standard CTE' do
+ let(:sql) do
+ <<-SQL
+ WITH some_cte AS (#{cte})
+ SELECT 1
+ FROM some_cte
+ SQL
+ end
+
+ context 'with static SELECT' do
+ let(:cte) { 'SELECT 1' }
+
+ it do
+ exp = { "some_cte" => Set.new([Type::STATIC]) }
+ expect(subject).to eq(exp)
+ end
+ end
+
+ context 'with dynamic SELECT' do
+ let(:cte) { 'SELECT * FROM namespaces' }
+
+ it do
+ exp = { "some_cte" => Set.new([Type::DYNAMIC]) }
+ expect(subject).to eq(exp)
+ end
+ end
+ end
+
+ context 'when recursive CTE' do
+ let(:sql) do
+ <<-SQL
+ WITH RECURSIVE some_cte AS (#{cte})
+ SELECT 1
+ FROM some_cte
+ SQL
+ end
+
+ context 'with static SELECT' do
+ let(:cte) { 'SELECT 1 UNION SELECT 2' }
+
+ it do
+ exp = { "some_cte" => Set.new([Type::STATIC]) }
+ expect(subject).to eq(exp)
+ end
+ end
+
+ context 'with dynamic SELECT' do
+ let(:cte) { 'SELECT * FROM namespaces UNION SELECT * FROM namespaces' }
+
+ it do
+ exp = { "some_cte" => Set.new([Type::DYNAMIC]) }
+ expect(subject).to eq(exp)
+ end
+ end
+
+ context 'with error SELECT' do
+ let(:cte) { 'SELECT * FROM namespaces UNION SELECT id FROM namespaces' }
+
+ it do
+ exp = { "some_cte" => Set.new([Type::DYNAMIC, Type::STATIC, Type::INVALID]) }
+ expect(subject).to eq(exp)
+ end
+ end
+ end
+
+ context 'with inherited CTE references' do
+ let(:sql) do
+ <<-SQL
+ WITH some_cte AS (SELECT 1)
+ SELECT 1
+ FROM some_cte
+ SQL
+ end
+
+ let(:cte_refs) { { 'some_reference' => 123 } }
+
+ it 'maintains inherited CTE references' do
+ subject_ref_names = subject.keys
+ expect(subject_ref_names).to eq(cte_refs.keys + ['some_cte'])
+ end
+ end
+ end
+end
diff --git a/spec/lib/gitlab/database/query_analyzers/prevent_set_operator_mismatch/froms_spec.rb b/spec/lib/gitlab/database/query_analyzers/prevent_set_operator_mismatch/froms_spec.rb
new file mode 100644
index 00000000000..03c0a845e60
--- /dev/null
+++ b/spec/lib/gitlab/database/query_analyzers/prevent_set_operator_mismatch/froms_spec.rb
@@ -0,0 +1,76 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::Database::QueryAnalyzers::PreventSetOperatorMismatch::Froms,
+ feature_category: :cell do
+ include PreventSetOperatorMismatchHelper
+
+ describe '.references' do
+ let(:node) { sql_select_node(sql) }
+ let(:cte_refs) { {} }
+
+ subject { described_class.references(node, cte_refs) }
+
+ context 'when node is nil' do
+ let(:node) { nil }
+
+ it { is_expected.to eq({}) }
+ end
+
+ context 'when range_var' do
+ let(:sql) { 'SELECT 1 FROM namespaces' }
+
+ it { is_expected.to match({ 'namespaces' => an_instance_of(PgQuery::RangeVar) }) }
+ end
+
+ context 'when range_var with alias' do
+ let(:sql) { 'SELECT 1 FROM namespaces ns' }
+
+ it { is_expected.to match({ 'ns' => an_instance_of(PgQuery::RangeVar) }) }
+ end
+
+ context 'when join expression' do
+ let(:sql) do
+ <<-SQL
+ SELECT 1 FROM namespaces
+ INNER JOIN organizations ON namespaces.organization_id = organization.id
+ SQL
+ end
+
+ it do
+ is_expected.to match({
+ 'namespaces' => an_instance_of(PgQuery::RangeVar),
+ 'organizations' => an_instance_of(PgQuery::RangeVar)
+ })
+ end
+ end
+
+ context 'when join expression with alias' do
+ let(:sql) do
+ <<-SQL
+ SELECT 1 FROM namespaces ns
+ INNER JOIN organizations o ON ns.organization_id = o.id
+ SQL
+ end
+
+ it do
+ is_expected.to match({
+ 'ns' => an_instance_of(PgQuery::RangeVar),
+ 'o' => an_instance_of(PgQuery::RangeVar)
+ })
+ end
+ end
+
+ context 'when sub-query' do
+ let(:sql) do
+ <<-SQL
+ SELECT 1
+ FROM (SELECT 1) some_subquery
+ SQL
+ end
+
+ it { is_expected.to match({ 'some_subquery' => [Type::STATIC].to_set }) }
+ end
+ end
+end
diff --git a/spec/lib/gitlab/database/query_analyzers/prevent_set_operator_mismatch/node_spec.rb b/spec/lib/gitlab/database/query_analyzers/prevent_set_operator_mismatch/node_spec.rb
new file mode 100644
index 00000000000..a8294376107
--- /dev/null
+++ b/spec/lib/gitlab/database/query_analyzers/prevent_set_operator_mismatch/node_spec.rb
@@ -0,0 +1,68 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::Database::QueryAnalyzers::PreventSetOperatorMismatch::Node, feature_category: :cell do
+ include PreventSetOperatorMismatchHelper
+
+ let(:sql) { 'SELECT id FROM namespaces' }
+ let(:node) { sql_select_node(sql) }
+
+ describe '.descendants' do
+ context 'with a block' do
+ it do
+ nodes = []
+ described_class.descendants(node.from_clause) do |node|
+ nodes << node.class
+ end
+ expect(nodes).to match_array [PgQuery::Node, PgQuery::RangeVar]
+ end
+ end
+
+ context 'without a block' do
+ subject { described_class.descendants(node) }
+
+ it { is_expected.to be_instance_of Enumerator }
+ end
+
+ context 'with a filter' do
+ let(:filter) { ->(field) { %i[from_clause target_list].include?(field) } }
+
+ subject { described_class.descendants(node, filter: filter).count }
+
+ it 'only traverse nodes that match the filter' do
+ is_expected.to eq 2
+ end
+ end
+ end
+
+ describe '.locate_descendant' do
+ subject { described_class.locate_descendant(node.target_list, :res_target) }
+
+ it { is_expected.to be_instance_of PgQuery::ResTarget }
+
+ context 'with a filter' do
+ subject { described_class.locate_descendant(node.target_list, :res_target, filter: ->(_) { false }) }
+
+ it { is_expected.to be_nil }
+ end
+ end
+
+ describe '.locate_descendants' do
+ subject { described_class.locate_descendants(node.target_list, :res_target) }
+
+ it { is_expected.to be_instance_of Array }
+
+ context 'with a filter' do
+ subject { described_class.locate_descendant(node.target_list, :res_target, filter: ->(_) { false }) }
+
+ it { is_expected.to be_nil }
+ end
+ end
+
+ describe '.dig' do
+ subject { described_class.dig(node.target_list[0], :res_target, :val, :column_ref) }
+
+ it { is_expected.to be_instance_of PgQuery::ColumnRef }
+ end
+end
diff --git a/spec/lib/gitlab/database/query_analyzers/prevent_set_operator_mismatch/references_spec.rb b/spec/lib/gitlab/database/query_analyzers/prevent_set_operator_mismatch/references_spec.rb
new file mode 100644
index 00000000000..0f0f92aa1f2
--- /dev/null
+++ b/spec/lib/gitlab/database/query_analyzers/prevent_set_operator_mismatch/references_spec.rb
@@ -0,0 +1,41 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::Database::QueryAnalyzers::PreventSetOperatorMismatch::References,
+ feature_category: :cell do
+ include PreventSetOperatorMismatchHelper
+
+ let(:refs) do
+ {
+ 'resolved_reference' => Set.new,
+ 'unresolved_reference' => double,
+ 'table_reference' => PgQuery::RangeVar.new,
+ 'error_reference' => [Type::INVALID].to_set
+ }
+ end
+
+ describe '.resolved' do
+ subject { described_class.resolved(refs) }
+
+ it { is_expected.to eq refs.slice('resolved_reference', 'error_reference') }
+ end
+
+ describe '.unresolved' do
+ subject { described_class.unresolved(refs) }
+
+ it { is_expected.to eq refs.slice('unresolved_reference') }
+ end
+
+ describe '.errors?' do
+ subject { described_class.errors?(refs) }
+
+ it { is_expected.to be_truthy }
+
+ context 'when no errors exist' do
+ subject { described_class.errors?(refs.except('error_reference')) }
+
+ it { is_expected.to be_falsey }
+ end
+ end
+end
diff --git a/spec/lib/gitlab/database/query_analyzers/prevent_set_operator_mismatch/select_stmt_spec.rb b/spec/lib/gitlab/database/query_analyzers/prevent_set_operator_mismatch/select_stmt_spec.rb
new file mode 100644
index 00000000000..52d6c9f1032
--- /dev/null
+++ b/spec/lib/gitlab/database/query_analyzers/prevent_set_operator_mismatch/select_stmt_spec.rb
@@ -0,0 +1,361 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::Database::QueryAnalyzers::PreventSetOperatorMismatch::SelectStmt, feature_category: :cell do
+ include PreventSetOperatorMismatchHelper
+
+ let_it_be(:static_namespace_columns) { Namespace.column_names.join(', ') }
+
+ let(:node) { sql_select_node(sql) }
+
+ subject { described_class.new(node).types }
+
+ shared_examples 'valid SQL' do
+ it { is_expected.not_to include(Type::INVALID) }
+ end
+
+ shared_examples 'invalid SQL' do
+ it { is_expected.to include(Type::INVALID) }
+ end
+
+ shared_context 'with basic set operator queries' do
+ let(:set_operator_queries) do
+ {
+ 'set operator with static columns' => <<-SQL,
+ SELECT id, name FROM namespaces WHERE name = 'test1'
+ #{set_operator}
+ SELECT id, name FROM namespaces WHERE name = 'test2'
+ SQL
+ 'set operator with static referenced columns' => <<-SQL,
+ SELECT namespaces.id, name FROM namespaces WHERE name = 'test1'
+ #{set_operator}
+ SELECT id, namespaces.name FROM namespaces WHERE name = 'test2'
+ SQL
+ 'set operator with static alias referenced columns' => <<-SQL,
+ SELECT namespaces.id, name FROM namespaces WHERE name = 'test1'
+ #{set_operator}
+ SELECT id, namespaces2.name FROM namespaces2 WHERE name = 'test2'
+ SQL
+ 'set operator with dynamic columns' => <<-SQL,
+ SELECT * FROM namespaces WHERE name = 'test1'
+ #{set_operator}
+ SELECT * FROM namespaces WHERE name = 'test2'
+ SQL
+ 'set operator with dynamic referenced columns' => <<-SQL,
+ SELECT namespaces.* FROM namespaces WHERE name = 'test1'
+ #{set_operator}
+ SELECT namespaces.* FROM namespaces WHERE name = 'test2'
+ SQL
+ 'set operator with dynamic referenced aliased columns' => <<-SQL,
+ SELECT namespaces.* FROM namespaces WHERE name = 'test1'
+ #{set_operator}
+ SELECT namespaces2.* FROM namespaces namespaces2 WHERE name = 'test2'
+ SQL
+ 'set operator with dynamic columns without using star' => <<-SQL,
+ SELECT namespaces FROM namespaces WHERE name = 'test1'
+ #{set_operator}
+ SELECT * FROM namespaces WHERE name = 'test2'
+ SQL
+ 'set operator with single dynamic referenced columns' => <<-SQL,
+ SELECT namespaces.* FROM namespaces WHERE name = 'test1'
+ #{set_operator}
+ SELECT * FROM namespaces WHERE name = 'test2'
+ SQL
+ 'set operator with static and dynamic columns' => <<-SQL,
+ SELECT #{static_namespace_columns} FROM namespaces WHERE name = 'test1'
+ #{set_operator}
+ SELECT * FROM namespaces WHERE name = 'test2'
+ SQL
+ 'set operator with static aliased columns and dynamic columns' => <<-SQL,
+ SELECT #{Namespace.column_names.map { |c| "namespaces2.#{c}" }.join(', ')}
+ FROM namespaces namespaces2
+ WHERE name = 'test1'
+ #{set_operator}
+ SELECT * FROM namespaces WHERE name = 'test2'
+ SQL
+ 'set operator with static columns and dynamic aliased columns' => <<-SQL,
+ SELECT #{static_namespace_columns} FROM namespaces WHERE name = 'test1'
+ #{set_operator}
+ SELECT namespaces2.* FROM namespaces namespaces2 WHERE name = 'test2'
+ SQL
+ 'set operator with static and dynamic aliased columns' => <<-SQL,
+ SELECT #{Namespace.column_names.map { |c| "namespaces2.#{c}" }.join(', ')}
+ FROM namespaces namespaces2
+ WHERE name = 'test1'
+ #{set_operator}
+ SELECT namespaces3.* FROM namespaces namespaces3 WHERE name = 'test2'
+ SQL
+ 'set operator with mixed dynamic and static columns' => <<-SQL,
+ SELECT namespaces.*, projects.id FROM namespaces, projects WHERE name = 'test1'
+ #{set_operator}
+ SELECT namespaces.*, projects.id FROM namespaces, projects WHERE name = 'test2'
+ SQL
+ 'set operator without references' => <<-SQL
+ SELECT 1
+ #{set_operator}
+ SELECT 2
+ SQL
+ }
+ end
+
+ where(:query_name, :behavior) do
+ [
+ ['set operator with static columns', 'valid SQL'],
+ ['set operator with static referenced columns', 'valid SQL'],
+ ['set operator with static alias referenced columns', 'valid SQL'],
+ ['set operator with dynamic columns', 'valid SQL'],
+ ['set operator with dynamic referenced columns', 'valid SQL'],
+ ['set operator with dynamic referenced aliased columns', 'valid SQL'],
+ ['set operator with dynamic columns without using star', 'invalid SQL'],
+ ['set operator with single dynamic referenced columns', 'valid SQL'],
+ ['set operator with static and dynamic columns', 'invalid SQL'],
+ ['set operator with static and dynamic aliased columns', 'invalid SQL'],
+ ['set operator with static aliased columns and dynamic columns', 'invalid SQL'],
+ ['set operator with static columns and dynamic aliased columns', 'invalid SQL'],
+ ['set operator with static and dynamic aliased columns', 'invalid SQL'],
+ ['set operator with mixed dynamic and static columns', 'valid SQL'],
+ ['set operator without references', 'valid SQL']
+ ]
+ end
+ end
+
+ %w[UNION INTERSECT EXCEPT].each do |set_operator|
+ context "with #{set_operator}" do
+ let(:set_operator) { set_operator }
+
+ context "for basic #{set_operator} queries" do
+ include_context 'with basic set operator queries'
+
+ with_them do
+ let(:sql) { set_operator_queries[query_name] }
+
+ it_behaves_like params[:behavior]
+ end
+ end
+
+ context 'for subquery' do
+ context "with #{set_operator}" do
+ where(:select_columns) do
+ [
+ ['*'],
+ ['sub.*'],
+ ['sub'],
+ ['sub.id']
+ ]
+ end
+
+ with_them do
+ include_context 'with basic set operator queries'
+
+ with_them do
+ let(:sql) do
+ <<-SQL
+ SELECT #{select_columns}
+ FROM (
+ #{set_operator_queries[query_name]}
+ ) sub
+ SQL
+ end
+
+ it_behaves_like params[:behavior]
+ end
+ end
+ end
+
+ context "when used by one side of #{set_operator}" do
+ let(:sql) do
+ <<-SQL
+ SELECT #{union1}
+ FROM (
+ SELECT #{subquery}
+ FROM namespaces
+ ) namespaces
+
+ #{set_operator}
+
+ SELECT #{union2}
+ FROM namespaces
+ SQL
+ end
+
+ where(:union1, :union2, :subquery, :expected) do
+ [
+ ['*', '*', '*', 'valid SQL'],
+ [ref(:static_namespace_columns), '*', '*', 'invalid SQL'],
+ ['*', ref(:static_namespace_columns), '*', 'invalid SQL'],
+ ['*', '*', ref(:static_namespace_columns), 'invalid SQL'],
+ [ref(:static_namespace_columns), ref(:static_namespace_columns), '*', 'valid SQL'],
+ [ref(:static_namespace_columns), '*', ref(:static_namespace_columns), 'invalid SQL'],
+ ['*', ref(:static_namespace_columns), ref(:static_namespace_columns), 'valid SQL'],
+ ['namespaces', 'namespaces', 'namespaces', 'valid SQL'],
+ # Used by our keyset pagination queries.
+ ['NULL :: namespaces', 'namespaces', 'id, name', 'valid SQL'],
+ ['NULL :: namespaces, id, name', 'namespaces, id, name', 'namespaces', 'valid SQL']
+ ]
+ end
+
+ with_them do
+ it_behaves_like params[:expected]
+ end
+ end
+ end
+
+ context 'for CTE' do
+ context "when #{set_operator}" do
+ where(:select_columns) do
+ [
+ ['*'],
+ ['namespaces_cte.*'],
+ ['namespaces_cte.id']
+ ]
+ end
+
+ with_them do
+ include_context 'with basic set operator queries'
+
+ with_them do
+ let(:sql) do
+ <<-SQL
+ WITH namespaces_cte AS (
+ #{set_operator_queries[query_name]}
+ )
+ SELECT *
+ FROM namespaces_cte
+ SQL
+ end
+
+ it_behaves_like params[:behavior]
+ end
+ end
+ end
+
+ context "when used by one side of #{set_operator}" do
+ let(:sql) do
+ <<-SQL
+ WITH #{cte_name} AS (
+ SELECT #{cte_select_columns}
+ FROM namespaces
+ )
+ SELECT #{select_columns}
+ FROM #{cte_name}
+
+ #{set_operator}
+
+ SELECT *
+ FROM namespaces
+ SQL
+ end
+
+ where(:cte_select_columns, :select_columns, :cte_name, :expected) do
+ [
+ ['*', '*', 'some_cte', 'valid SQL'],
+ [ref(:static_namespace_columns), '*', 'some_cte', 'invalid SQL'],
+ ['*', ref(:static_namespace_columns), 'some_cte', 'invalid SQL'],
+ [ref(:static_namespace_columns), ref(:static_namespace_columns), 'some_cte', 'invalid SQL'],
+ ['*', '*', 'some_cte', 'valid SQL'],
+ # Same scenarios as above, but the CTE name matches the table name in the CTE.
+ ['*', '*', 'namespaces', 'valid SQL'],
+ [ref(:static_namespace_columns), '*', 'namespaces', 'valid SQL'],
+ ['*', ref(:static_namespace_columns), 'namespaces', 'invalid SQL'],
+ [ref(:static_namespace_columns), ref(:static_namespace_columns), 'namespaces', 'valid SQL'],
+ ['*', '*', 'namespaces', 'valid SQL']
+ ]
+ end
+
+ with_them do
+ it_behaves_like params[:expected]
+ end
+ end
+
+ context 'when recursive' do
+ let(:sql) do
+ <<-SQL
+ WITH RECURSIVE namespaces_cte AS (
+ (
+ SELECT #{select1}
+ FROM namespaces
+ )
+ UNION
+ (
+ SELECT #{select2}
+ FROM namespaces_cte
+ )
+ )
+ SELECT *
+ FROM namespaces_cte
+ SQL
+ end
+
+ where(:select1, :select2, :expected) do
+ [
+ ['id', 'id', 'valid SQL'],
+ [ref(:static_namespace_columns), '*', 'valid SQL'],
+ ['*', ref(:static_namespace_columns), 'invalid SQL']
+ ]
+ end
+
+ with_them do
+ it_behaves_like params[:expected]
+ end
+ end
+ end
+
+ context 'for subselect' do
+ context 'with set operator' do
+ let(:sql) do
+ <<-SQL
+ SELECT (
+ SELECT id FROM namespaces
+ #{set_operator}
+ SELECT id FROM namespaces
+ ) AS namespace_id
+ SQL
+ end
+
+ it_behaves_like 'valid SQL'
+ end
+ end
+ end
+ end
+
+ context 'with lateral join' do
+ let(:sql) do
+ <<-SQL
+ SELECT namespaces.id
+ FROM
+ namespaces CROSS
+ JOIN LATERAL (
+ SELECT
+ namespaces.traversal_ids[array_length(namespaces.traversal_ids, 1) ] AS id
+ FROM
+ namespaces
+ WHERE
+ namespaces.type = 'Group'
+ AND namespaces.traversal_ids @ > ARRAY[members.source_id]
+ ) namespaces
+ SQL
+ end
+
+ pending
+ end
+
+ context 'when columns are not referenced' do
+ let(:sql) do
+ <<-SQL
+ SELECT
+ COUNT(1)
+ FROM (
+ SELECT #{static_namespace_columns}
+ FROM namespaces
+ UNION
+ SELECT *
+ FROM namespaces
+ ) invalid_union
+ SQL
+ end
+
+ # Error will bubble up even though the parent query does not reference any of the sub-query columns.
+ it_behaves_like 'invalid SQL'
+ end
+end
diff --git a/spec/lib/gitlab/database/query_analyzers/prevent_set_operator_mismatch/targets_spec.rb b/spec/lib/gitlab/database/query_analyzers/prevent_set_operator_mismatch/targets_spec.rb
new file mode 100644
index 00000000000..2ea69f3726e
--- /dev/null
+++ b/spec/lib/gitlab/database/query_analyzers/prevent_set_operator_mismatch/targets_spec.rb
@@ -0,0 +1,94 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::Database::QueryAnalyzers::PreventSetOperatorMismatch::Targets, feature_category: :cell do
+ include PreventSetOperatorMismatchHelper
+
+ let(:node) { sql_select_node(sql) }
+ let(:select_stmt) { Gitlab::Database::QueryAnalyzers::PreventSetOperatorMismatch::SelectStmt.new(node) }
+ let(:target) { node.target_list[0].res_target }
+
+ describe '.reference_names' do
+ subject { described_class.reference_names(target, select_stmt) }
+
+ context 'with a literal target' do
+ let(:sql) { 'SELECT 1' }
+
+ it { is_expected.to be_empty }
+ end
+
+ context 'with a function target' do
+ let(:sql) { 'SELECT unnest(ARRAY[1,2]) FROM namespaces, users' }
+
+ it { is_expected.to be_empty }
+ end
+
+ context 'with a subselect target' do
+ let(:sql) { 'SELECT (SELECT 1) xyz FROM namespaces' }
+
+ it { is_expected.to eq(%w[xyz_subselect]) }
+
+ it 'updates all_references in the select statement' do
+ expect { subject }.to change { select_stmt.all_references }
+ .to include('xyz_subselect')
+ end
+ end
+
+ context 'with an unqualified column name' do
+ let(:sql) { 'SELECT id FROM namespaces, users' }
+
+ it { is_expected.to eq(%w[namespaces users]) }
+ end
+
+ context 'with a qualified column name' do
+ let(:sql) { 'SELECT namespaces.id FROM namespaces, users' }
+
+ it { is_expected.to eq(%w[namespaces]) }
+ end
+
+ context 'with a table name' do
+ let(:sql) { 'SELECT namespaces FROM namespaces, users' }
+
+ it { is_expected.to eq(%w[namespaces]) }
+ end
+
+ context 'with a *' do
+ let(:sql) { 'SELECT * FROM namespaces, users' }
+
+ it { is_expected.to eq(%w[namespaces users]) }
+ end
+ end
+
+ describe '.a_star?' do
+ subject { described_class.a_star?(target) }
+
+ context 'when * is used' do
+ let(:sql) { 'SELECT * FROM namespaces' }
+
+ it { is_expected.to be_truthy }
+ end
+
+ context 'when no * is used' do
+ let(:sql) { 'SELECT 1' }
+
+ it { is_expected.to be_falsey }
+ end
+ end
+
+ describe '.null?' do
+ subject { described_class.null?(target) }
+
+ context 'when target is null' do
+ let(:sql) { 'SELECT NULL::namespaces FROM namespaces' }
+
+ it { is_expected.to be_truthy }
+ end
+
+ context 'when target is not null' do
+ let(:sql) { 'SELECT 1' }
+
+ it { is_expected.to be_falsey }
+ end
+ end
+end
diff --git a/spec/lib/gitlab/database/query_analyzers/prevent_set_operator_mismatch_spec.rb b/spec/lib/gitlab/database/query_analyzers/prevent_set_operator_mismatch_spec.rb
new file mode 100644
index 00000000000..28c155c1eb1
--- /dev/null
+++ b/spec/lib/gitlab/database/query_analyzers/prevent_set_operator_mismatch_spec.rb
@@ -0,0 +1,84 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::Database::QueryAnalyzers::PreventSetOperatorMismatch, query_analyzers: false, feature_category: :cell do
+ let(:analyzer) { described_class }
+ let_it_be(:static_namespace_columns) { Namespace.column_names.join(', ') }
+
+ def process_sql(sql, model = ApplicationRecord)
+ Gitlab::Database::QueryAnalyzer.instance.within([analyzer]) do
+ # Skip load balancer and retrieve connection assigned to model
+ Gitlab::Database::QueryAnalyzer.instance.send(:process_sql, sql, model.retrieve_connection)
+ end
+ end
+
+ shared_examples 'parses SQL' do
+ it do
+ expect_next_instance_of(described_class::SelectStmt) do |select_stmt|
+ expect(select_stmt).to receive(:types).and_return(Set.new)
+ end
+
+ process_sql sql
+ end
+ end
+
+ context 'when SQL includes a UNION' do
+ let(:sql) { 'SELECT 1 UNION SELECT 2' }
+
+ include_examples 'parses SQL'
+ end
+
+ context 'when SQL includes a INTERSECT' do
+ let(:sql) { 'SELECT 1 INTERSECT SELECT 2' }
+
+ include_examples 'parses SQL'
+ end
+
+ context 'when SQL includes a EXCEPT' do
+ let(:sql) { 'SELECT 1 EXCEPT SELECT 2' }
+
+ include_examples 'parses SQL'
+ end
+
+ context 'when SQL does not include a set operator' do
+ let(:sql) { 'SELECT 1' }
+
+ it 'does not parse SQL' do
+ expect(described_class::SelectStmt).not_to receive(:new)
+
+ process_sql sql
+ end
+ end
+
+ context 'when SQL is invalid' do
+ it 'raises error' do
+ expect do
+ process_sql "SELECT #{static_namespace_columns} FROM namespaces UNION SELECT * FROM namespaces"
+ end.to raise_error(described_class::SetOperatorStarError)
+ end
+ end
+
+ context 'when SQL is valid' do
+ it 'does not raise error' do
+ expect do
+ process_sql 'SELECT 1'
+ end.not_to raise_error
+ end
+ end
+
+ context 'when SQL has many select statements' do
+ let(:sql) do
+ <<-SQL
+ SELECT 1 UNION SELECT 1;
+ SELECT #{static_namespace_columns} FROM namespaces UNION SELECT * FROM namespaces
+ SQL
+ end
+
+ it 'raises error' do
+ expect do
+ process_sql sql
+ end.to raise_error(described_class::SetOperatorStarError)
+ end
+ end
+end
diff --git a/spec/lib/gitlab/database/reindexing_spec.rb b/spec/lib/gitlab/database/reindexing_spec.rb
index 441f6476abe..2321f5d933d 100644
--- a/spec/lib/gitlab/database/reindexing_spec.rb
+++ b/spec/lib/gitlab/database/reindexing_spec.rb
@@ -231,7 +231,7 @@ RSpec.describe Gitlab::Database::Reindexing, feature_category: :database, time_t
states = queued_actions.map(&:reload).map(&:state)
- expect(states).to eq(%w(failed done queued))
+ expect(states).to eq(%w[failed done queued])
end
end
diff --git a/spec/lib/gitlab/database/tables_locker_spec.rb b/spec/lib/gitlab/database/tables_locker_spec.rb
index 0e7e929d54b..e3bd61b32a1 100644
--- a/spec/lib/gitlab/database/tables_locker_spec.rb
+++ b/spec/lib/gitlab/database/tables_locker_spec.rb
@@ -33,30 +33,40 @@ RSpec.describe Gitlab::Database::TablesLocker, :suppress_gitlab_schemas_validate
FOR VALUES IN (0)
SQL
- ApplicationRecord.connection.execute(create_partition_sql)
- Ci::ApplicationRecord.connection.execute(create_partition_sql)
-
create_detached_partition_sql = <<~SQL
CREATE TABLE IF NOT EXISTS #{Gitlab::Database::DYNAMIC_PARTITIONS_SCHEMA}._test_gitlab_main_part_202201 (
id bigserial primary key not null
)
SQL
- ApplicationRecord.connection.execute(create_detached_partition_sql)
- Ci::ApplicationRecord.connection.execute(create_detached_partition_sql)
+ [ApplicationRecord, Ci::ApplicationRecord]
+ .map(&:connection)
+ .each do |conn|
+ conn.execute(create_partition_sql)
+ conn.execute(
+ "DROP TABLE IF EXISTS #{Gitlab::Database::DYNAMIC_PARTITIONS_SCHEMA}._test_gitlab_main_part_202201"
+ )
+ conn.execute(create_detached_partition_sql)
+
+ Gitlab::Database::SharedModel.using_connection(conn) do
+ Postgresql::DetachedPartition.delete_all
+ Postgresql::DetachedPartition.create!(
+ table_name: '_test_gitlab_main_part_20220101',
+ drop_after: Time.current
+ )
+ end
+ end
+ end
- Gitlab::Database::SharedModel.using_connection(ApplicationRecord.connection) do
- Postgresql::DetachedPartition.create!(
- table_name: '_test_gitlab_main_part_20220101',
- drop_after: Time.current
- )
- end
- Gitlab::Database::SharedModel.using_connection(Ci::ApplicationRecord.connection) do
- Postgresql::DetachedPartition.create!(
- table_name: '_test_gitlab_main_part_20220101',
- drop_after: Time.current
- )
- end
+ after(:all) do
+ [ApplicationRecord, Ci::ApplicationRecord]
+ .map(&:connection)
+ .each do |conn|
+ conn.execute(
+ "DROP TABLE IF EXISTS #{Gitlab::Database::DYNAMIC_PARTITIONS_SCHEMA}._test_gitlab_main_part_202201"
+ )
+ Gitlab::Database::SharedModel.using_connection(conn) { Postgresql::DetachedPartition.delete_all }
+ end
end
shared_examples "lock tables" do |gitlab_schema, database_name|
diff --git a/spec/lib/gitlab/database/tables_truncate_spec.rb b/spec/lib/gitlab/database/tables_truncate_spec.rb
index e41c7d34378..352c2fff779 100644
--- a/spec/lib/gitlab/database/tables_truncate_spec.rb
+++ b/spec/lib/gitlab/database/tables_truncate_spec.rb
@@ -3,7 +3,7 @@
require 'spec_helper'
RSpec.describe Gitlab::Database::TablesTruncate, :reestablished_active_record_base,
- :suppress_gitlab_schemas_validate_connection, feature_category: :cell do
+ :suppress_gitlab_schemas_validate_connection, feature_category: :cell do
include MigrationsHelpers
let(:min_batch_size) { 1 }
@@ -373,7 +373,9 @@ RSpec.describe Gitlab::Database::TablesTruncate, :reestablished_active_record_ba
context 'with no main data in ci datatabase' do
before do
# Remove 'main' data in ci database
- ci_connection.truncate_tables([:_test_gitlab_main_items, :_test_gitlab_main_references])
+ ci_connection.execute(
+ "TRUNCATE TABLE _test_gitlab_main_items, _test_gitlab_main_references RESTART IDENTITY CASCADE;"
+ )
end
it { is_expected.to eq(false) }
diff --git a/spec/lib/gitlab/database/transaction/observer_spec.rb b/spec/lib/gitlab/database/transaction/observer_spec.rb
index d1cb014a594..778212add66 100644
--- a/spec/lib/gitlab/database/transaction/observer_spec.rb
+++ b/spec/lib/gitlab/database/transaction/observer_spec.rb
@@ -25,7 +25,7 @@ RSpec.describe Gitlab::Database::Transaction::Observer, feature_category: :datab
User.first
expect(transaction_context).to be_a(::Gitlab::Database::Transaction::Context)
- expect(context.keys).to match_array(%i(start_time depth savepoints queries backtraces external_http_count_start external_http_duration_start))
+ expect(context.keys).to match_array(%i[start_time depth savepoints queries backtraces external_http_count_start external_http_duration_start])
expect(context[:depth]).to eq(2)
expect(context[:savepoints]).to eq(1)
expect(context[:queries].length).to eq(1)
diff --git a/spec/lib/gitlab/dependency_linker/base_linker_spec.rb b/spec/lib/gitlab/dependency_linker/base_linker_spec.rb
index 2811bc859da..ef61a962279 100644
--- a/spec/lib/gitlab/dependency_linker/base_linker_spec.rb
+++ b/spec/lib/gitlab/dependency_linker/base_linker_spec.rb
@@ -46,8 +46,8 @@ RSpec.describe Gitlab::DependencyLinker::BaseLinker do
'target="_blank"'
]
- attrs.unshift(%{href="#{url}"}) if url
+ attrs.unshift(%(href="#{url}")) if url
- %{<a #{attrs.join(' ')}>#{text}</a>}
+ %(<a #{attrs.join(' ')}>#{text}</a>)
end
end
diff --git a/spec/lib/gitlab/dependency_linker/cargo_toml_linker_spec.rb b/spec/lib/gitlab/dependency_linker/cargo_toml_linker_spec.rb
index 7f6b3b86799..d147afbf3bd 100644
--- a/spec/lib/gitlab/dependency_linker/cargo_toml_linker_spec.rb
+++ b/spec/lib/gitlab/dependency_linker/cargo_toml_linker_spec.rb
@@ -70,7 +70,7 @@ RSpec.describe Gitlab::DependencyLinker::CargoTomlLinker do
subject { Gitlab::Highlight.highlight(file_name, file_content) }
def link(name, url)
- %{<a href="#{url}" rel="nofollow noreferrer noopener" target="_blank">#{name}</a>}
+ %(<a href="#{url}" rel="nofollow noreferrer noopener" target="_blank">#{name}</a>)
end
it 'links dependencies' do
diff --git a/spec/lib/gitlab/dependency_linker/cartfile_linker_spec.rb b/spec/lib/gitlab/dependency_linker/cartfile_linker_spec.rb
index 52ddba24458..eeb7471cd18 100644
--- a/spec/lib/gitlab/dependency_linker/cartfile_linker_spec.rb
+++ b/spec/lib/gitlab/dependency_linker/cartfile_linker_spec.rb
@@ -54,7 +54,7 @@ RSpec.describe Gitlab::DependencyLinker::CartfileLinker do
subject { Gitlab::Highlight.highlight(file_name, file_content) }
def link(name, url)
- %{<a href="#{url}" rel="nofollow noreferrer noopener" target="_blank">#{name}</a>}
+ %(<a href="#{url}" rel="nofollow noreferrer noopener" target="_blank">#{name}</a>)
end
it 'links dependencies' do
diff --git a/spec/lib/gitlab/dependency_linker/composer_json_linker_spec.rb b/spec/lib/gitlab/dependency_linker/composer_json_linker_spec.rb
index 02fac96a02f..cf636a7f201 100644
--- a/spec/lib/gitlab/dependency_linker/composer_json_linker_spec.rb
+++ b/spec/lib/gitlab/dependency_linker/composer_json_linker_spec.rb
@@ -50,7 +50,7 @@ RSpec.describe Gitlab::DependencyLinker::ComposerJsonLinker do
subject { Gitlab::Highlight.highlight(file_name, file_content) }
def link(name, url)
- %{<a href="#{url}" rel="nofollow noreferrer noopener" target="_blank">#{name}</a>}
+ %(<a href="#{url}" rel="nofollow noreferrer noopener" target="_blank">#{name}</a>)
end
it 'does not link the module name' do
diff --git a/spec/lib/gitlab/dependency_linker/gemfile_linker_spec.rb b/spec/lib/gitlab/dependency_linker/gemfile_linker_spec.rb
index 00e95dea224..a5507fab3fe 100644
--- a/spec/lib/gitlab/dependency_linker/gemfile_linker_spec.rb
+++ b/spec/lib/gitlab/dependency_linker/gemfile_linker_spec.rb
@@ -35,7 +35,7 @@ RSpec.describe Gitlab::DependencyLinker::GemfileLinker do
subject { Gitlab::Highlight.highlight(file_name, file_content) }
def link(name, url)
- %{<a href="#{url}" rel="nofollow noreferrer noopener" target="_blank">#{name}</a>}
+ %(<a href="#{url}" rel="nofollow noreferrer noopener" target="_blank">#{name}</a>)
end
it 'links sources' do
diff --git a/spec/lib/gitlab/dependency_linker/gemspec_linker_spec.rb b/spec/lib/gitlab/dependency_linker/gemspec_linker_spec.rb
index ae82dd51c95..9f207459113 100644
--- a/spec/lib/gitlab/dependency_linker/gemspec_linker_spec.rb
+++ b/spec/lib/gitlab/dependency_linker/gemspec_linker_spec.rb
@@ -42,7 +42,7 @@ RSpec.describe Gitlab::DependencyLinker::GemspecLinker do
subject { Gitlab::Highlight.highlight(file_name, file_content) }
def link(name, url)
- %{<a href="#{url}" rel="nofollow noreferrer noopener" target="_blank">#{name}</a>}
+ %(<a href="#{url}" rel="nofollow noreferrer noopener" target="_blank">#{name}</a>)
end
it 'does not link the gem name' do
diff --git a/spec/lib/gitlab/dependency_linker/go_mod_linker_spec.rb b/spec/lib/gitlab/dependency_linker/go_mod_linker_spec.rb
index 605b14bc923..fbd8b6477a2 100644
--- a/spec/lib/gitlab/dependency_linker/go_mod_linker_spec.rb
+++ b/spec/lib/gitlab/dependency_linker/go_mod_linker_spec.rb
@@ -55,7 +55,7 @@ RSpec.describe Gitlab::DependencyLinker::GoModLinker do
subject { Gitlab::Highlight.highlight(file_name, file_content) }
def link(name, url)
- %{<a href="#{url}" rel="nofollow noreferrer noopener" target="_blank">#{name}</a>}
+ %(<a href="#{url}" rel="nofollow noreferrer noopener" target="_blank">#{name}</a>)
end
it 'links the module name' do
diff --git a/spec/lib/gitlab/dependency_linker/go_sum_linker_spec.rb b/spec/lib/gitlab/dependency_linker/go_sum_linker_spec.rb
index 2836c0e9f29..559c27e91ba 100644
--- a/spec/lib/gitlab/dependency_linker/go_sum_linker_spec.rb
+++ b/spec/lib/gitlab/dependency_linker/go_sum_linker_spec.rb
@@ -35,7 +35,7 @@ RSpec.describe Gitlab::DependencyLinker::GoSumLinker do
subject { Gitlab::Highlight.highlight(file_name, file_content) }
def link(name, url)
- %{<a href="#{url}" rel="nofollow noreferrer noopener" target="_blank">#{name}</a>}
+ %(<a href="#{url}" rel="nofollow noreferrer noopener" target="_blank">#{name}</a>)
end
it 'links modules' do
diff --git a/spec/lib/gitlab/dependency_linker/godeps_json_linker_spec.rb b/spec/lib/gitlab/dependency_linker/godeps_json_linker_spec.rb
index c1ed030c548..3ac234f47d9 100644
--- a/spec/lib/gitlab/dependency_linker/godeps_json_linker_spec.rb
+++ b/spec/lib/gitlab/dependency_linker/godeps_json_linker_spec.rb
@@ -61,7 +61,7 @@ RSpec.describe Gitlab::DependencyLinker::GodepsJsonLinker do
subject { Gitlab::Highlight.highlight(file_name, file_content) }
def link(name, url)
- %{<a href="#{url}" rel="nofollow noreferrer noopener" target="_blank">#{name}</a>}
+ %(<a href="#{url}" rel="nofollow noreferrer noopener" target="_blank">#{name}</a>)
end
it 'links the package name' do
diff --git a/spec/lib/gitlab/dependency_linker/package_json_linker_spec.rb b/spec/lib/gitlab/dependency_linker/package_json_linker_spec.rb
index cdfc0e89bc7..127f437dd54 100644
--- a/spec/lib/gitlab/dependency_linker/package_json_linker_spec.rb
+++ b/spec/lib/gitlab/dependency_linker/package_json_linker_spec.rb
@@ -51,7 +51,7 @@ RSpec.describe Gitlab::DependencyLinker::PackageJsonLinker do
subject { Gitlab::Highlight.highlight(file_name, file_content) }
def link(name, url)
- %{<a href="#{url}" rel="nofollow noreferrer noopener" target="_blank">#{name}</a>}
+ %(<a href="#{url}" rel="nofollow noreferrer noopener" target="_blank">#{name}</a>)
end
it 'does not link the module name' do
diff --git a/spec/lib/gitlab/dependency_linker/podfile_linker_spec.rb b/spec/lib/gitlab/dependency_linker/podfile_linker_spec.rb
index 8e536c00ea6..41c29278bda 100644
--- a/spec/lib/gitlab/dependency_linker/podfile_linker_spec.rb
+++ b/spec/lib/gitlab/dependency_linker/podfile_linker_spec.rb
@@ -35,7 +35,7 @@ RSpec.describe Gitlab::DependencyLinker::PodfileLinker do
subject { Gitlab::Highlight.highlight(file_name, file_content) }
def link(name, url)
- %{<a href="#{url}" rel="nofollow noreferrer noopener" target="_blank">#{name}</a>}
+ %(<a href="#{url}" rel="nofollow noreferrer noopener" target="_blank">#{name}</a>)
end
it 'links sources' do
diff --git a/spec/lib/gitlab/dependency_linker/podspec_json_linker_spec.rb b/spec/lib/gitlab/dependency_linker/podspec_json_linker_spec.rb
index 1f81049a41e..f8b782a7cda 100644
--- a/spec/lib/gitlab/dependency_linker/podspec_json_linker_spec.rb
+++ b/spec/lib/gitlab/dependency_linker/podspec_json_linker_spec.rb
@@ -66,7 +66,7 @@ RSpec.describe Gitlab::DependencyLinker::PodspecJsonLinker do
subject { Gitlab::Highlight.highlight(file_name, file_content) }
def link(name, url)
- %{<a href="#{url}" rel="nofollow noreferrer noopener" target="_blank">#{name}</a>}
+ %(<a href="#{url}" rel="nofollow noreferrer noopener" target="_blank">#{name}</a>)
end
it 'links the gem name' do
diff --git a/spec/lib/gitlab/dependency_linker/podspec_linker_spec.rb b/spec/lib/gitlab/dependency_linker/podspec_linker_spec.rb
index 132b5b21d85..6f2653829e2 100644
--- a/spec/lib/gitlab/dependency_linker/podspec_linker_spec.rb
+++ b/spec/lib/gitlab/dependency_linker/podspec_linker_spec.rb
@@ -41,7 +41,7 @@ RSpec.describe Gitlab::DependencyLinker::PodspecLinker do
subject { Gitlab::Highlight.highlight(file_name, file_content) }
def link(name, url)
- %{<a href="#{url}" rel="nofollow noreferrer noopener" target="_blank">#{name}</a>}
+ %(<a href="#{url}" rel="nofollow noreferrer noopener" target="_blank">#{name}</a>)
end
it 'does not link the pod name' do
diff --git a/spec/lib/gitlab/dependency_linker/requirements_txt_linker_spec.rb b/spec/lib/gitlab/dependency_linker/requirements_txt_linker_spec.rb
index 86ebddc9681..fc3c57b7cff 100644
--- a/spec/lib/gitlab/dependency_linker/requirements_txt_linker_spec.rb
+++ b/spec/lib/gitlab/dependency_linker/requirements_txt_linker_spec.rb
@@ -64,7 +64,7 @@ RSpec.describe Gitlab::DependencyLinker::RequirementsTxtLinker do
subject { Gitlab::Highlight.highlight(file_name, file_content) }
def link(name, url)
- %{<a href="#{url}" rel="nofollow noreferrer noopener" target="_blank">#{name}</a>}
+ %(<a href="#{url}" rel="nofollow noreferrer noopener" target="_blank">#{name}</a>)
end
it 'links dependencies' do
diff --git a/spec/lib/gitlab/diff/file_collection/compare_spec.rb b/spec/lib/gitlab/diff/file_collection/compare_spec.rb
index c3f768db7f0..5469a43e46e 100644
--- a/spec/lib/gitlab/diff/file_collection/compare_spec.rb
+++ b/spec/lib/gitlab/diff/file_collection/compare_spec.rb
@@ -10,9 +10,11 @@ RSpec.describe Gitlab::Diff::FileCollection::Compare do
let(:start_commit) { sample_image_commit }
let(:head_commit) { sample_commit }
let(:raw_compare) do
- Gitlab::Git::Compare.new(project.repository.raw_repository,
- start_commit.id,
- head_commit.id)
+ Gitlab::Git::Compare.new(
+ project.repository.raw_repository,
+ start_commit.id,
+ head_commit.id
+ )
end
let(:diffable) { Compare.new(raw_compare, project) }
diff --git a/spec/lib/gitlab/diff/file_collection/merge_request_diff_batch_spec.rb b/spec/lib/gitlab/diff/file_collection/merge_request_diff_batch_spec.rb
index 8e14f48ae29..65e96f8e936 100644
--- a/spec/lib/gitlab/diff/file_collection/merge_request_diff_batch_spec.rb
+++ b/spec/lib/gitlab/diff/file_collection/merge_request_diff_batch_spec.rb
@@ -10,10 +10,7 @@ RSpec.describe Gitlab::Diff::FileCollection::MergeRequestDiffBatch, feature_cate
let(:diff_files_relation) { diffable.merge_request_diff_files }
subject do
- described_class.new(diffable,
- batch_page,
- batch_size,
- diff_options: nil)
+ described_class.new(diffable, batch_page, batch_size, diff_options: nil)
end
let(:diff_files) { subject.diff_files }
@@ -87,10 +84,7 @@ RSpec.describe Gitlab::Diff::FileCollection::MergeRequestDiffBatch, feature_cate
context 'last page' do
it 'returns correct diff files' do
last_page = diff_files_relation.count - batch_size
- collection = described_class.new(diffable,
- last_page,
- batch_size,
- diff_options: nil)
+ collection = described_class.new(diffable, last_page, batch_size, diff_options: nil)
expected_batch_files = diff_files_relation.offset(last_page).limit(batch_size).map(&:new_path)
@@ -101,10 +95,7 @@ RSpec.describe Gitlab::Diff::FileCollection::MergeRequestDiffBatch, feature_cate
it_behaves_like 'unfoldable diff' do
subject do
- described_class.new(merge_request.merge_request_diff,
- batch_page,
- batch_size,
- diff_options: nil)
+ described_class.new(merge_request.merge_request_diff, batch_page, batch_size, diff_options: nil)
end
end
@@ -118,10 +109,7 @@ RSpec.describe Gitlab::Diff::FileCollection::MergeRequestDiffBatch, feature_cate
let(:stub_path) { '.gitignore' }
subject do
- described_class.new(merge_request.merge_request_diff,
- batch_page,
- batch_size,
- **collection_default_args)
+ described_class.new(merge_request.merge_request_diff, batch_page, batch_size, **collection_default_args)
end
end
@@ -136,10 +124,7 @@ RSpec.describe Gitlab::Diff::FileCollection::MergeRequestDiffBatch, feature_cate
end
subject do
- described_class.new(merge_request.merge_request_diff,
- batch_page,
- batch_size,
- **collection_default_args)
+ described_class.new(merge_request.merge_request_diff, batch_page, batch_size, **collection_default_args)
end
end
end
diff --git a/spec/lib/gitlab/diff/file_collection/paginated_merge_request_diff_spec.rb b/spec/lib/gitlab/diff/file_collection/paginated_merge_request_diff_spec.rb
index ee956d04325..891336658ce 100644
--- a/spec/lib/gitlab/diff/file_collection/paginated_merge_request_diff_spec.rb
+++ b/spec/lib/gitlab/diff/file_collection/paginated_merge_request_diff_spec.rb
@@ -11,9 +11,7 @@ RSpec.describe Gitlab::Diff::FileCollection::PaginatedMergeRequestDiff, feature_
let(:diff_files) { subject.diff_files }
subject do
- described_class.new(diffable,
- page,
- per_page)
+ described_class.new(diffable, page, per_page)
end
describe '#diff_files' do
@@ -79,9 +77,7 @@ RSpec.describe Gitlab::Diff::FileCollection::PaginatedMergeRequestDiff, feature_
context 'when last page' do
it 'returns correct diff files' do
last_page = diff_files_relation.count - per_page
- collection = described_class.new(diffable,
- last_page,
- per_page)
+ collection = described_class.new(diffable, last_page, per_page)
expected_batch_files = diff_files_relation.page(last_page).per(per_page).map(&:new_path)
@@ -92,9 +88,7 @@ RSpec.describe Gitlab::Diff::FileCollection::PaginatedMergeRequestDiff, feature_
it_behaves_like 'unfoldable diff' do
subject do
- described_class.new(merge_request.merge_request_diff,
- page,
- per_page)
+ described_class.new(merge_request.merge_request_diff, page, per_page)
end
end
@@ -106,9 +100,7 @@ RSpec.describe Gitlab::Diff::FileCollection::PaginatedMergeRequestDiff, feature_
let(:diffable) { merge_request.merge_request_diff }
subject do
- described_class.new(merge_request.merge_request_diff,
- page,
- per_page)
+ described_class.new(merge_request.merge_request_diff, page, per_page)
end
end
end
diff --git a/spec/lib/gitlab/diff/file_spec.rb b/spec/lib/gitlab/diff/file_spec.rb
index ad2524e40c5..bc4fc49b1b7 100644
--- a/spec/lib/gitlab/diff/file_spec.rb
+++ b/spec/lib/gitlab/diff/file_spec.rb
@@ -407,10 +407,7 @@ RSpec.describe Gitlab::Diff::File do
context 'diff file stats' do
let(:diff_file) do
- described_class.new(diff,
- diff_refs: commit.diff_refs,
- repository: project.repository,
- stats: stats)
+ described_class.new(diff, diff_refs: commit.diff_refs, repository: project.repository, stats: stats)
end
let(:raw_diff) do
diff --git a/spec/lib/gitlab/diff/formatters/file_formatter_spec.rb b/spec/lib/gitlab/diff/formatters/file_formatter_spec.rb
index 32e5f17f7eb..fc77ed5d763 100644
--- a/spec/lib/gitlab/diff/formatters/file_formatter_spec.rb
+++ b/spec/lib/gitlab/diff/formatters/file_formatter_spec.rb
@@ -17,7 +17,7 @@ RSpec.describe Gitlab::Diff::Formatters::FileFormatter, feature_category: :code_
let(:attrs) { base_attrs.merge(old_path: 'path.rb', new_path: 'path.rb') }
it_behaves_like 'position formatter' do
- # rubocop:disable Fips/SHA1 (This is used to match the existing class method)
+ # rubocop:disable Fips/SHA1 -- This is used to match the existing class method
let(:key) do
[123, 456, 789,
Digest::SHA1.hexdigest(formatter.old_path), Digest::SHA1.hexdigest(formatter.new_path),
diff --git a/spec/lib/gitlab/diff/highlight_cache_spec.rb b/spec/lib/gitlab/diff/highlight_cache_spec.rb
index c51eaa4fa18..94a5d30283c 100644
--- a/spec/lib/gitlab/diff/highlight_cache_spec.rb
+++ b/spec/lib/gitlab/diff/highlight_cache_spec.rb
@@ -49,10 +49,12 @@ RSpec.describe Gitlab::Diff::HighlightCache, :clean_gitlab_redis_cache, feature_
let(:diff_file) do
diffs = merge_request.diffs
raw_diff = diffs.diffable.raw_diffs(diffs.diff_options.merge(paths: ['CHANGELOG'])).first
- Gitlab::Diff::File.new(raw_diff,
- repository: diffs.project.repository,
- diff_refs: diffs.diff_refs,
- fallback_diff_refs: diffs.fallback_diff_refs)
+ Gitlab::Diff::File.new(
+ raw_diff,
+ repository: diffs.project.repository,
+ diff_refs: diffs.diff_refs,
+ fallback_diff_refs: diffs.fallback_diff_refs
+ )
end
before do
@@ -227,10 +229,12 @@ RSpec.describe Gitlab::Diff::HighlightCache, :clean_gitlab_redis_cache, feature_
let(:diff_file) do
diffs = merge_request.diffs
raw_diff = diffs.diffable.raw_diffs(diffs.diff_options.merge(paths: ['CHANGELOG'])).first
- Gitlab::Diff::File.new(raw_diff,
- repository: diffs.project.repository,
- diff_refs: diffs.diff_refs,
- fallback_diff_refs: diffs.fallback_diff_refs)
+ Gitlab::Diff::File.new(
+ raw_diff,
+ repository: diffs.project.repository,
+ diff_refs: diffs.diff_refs,
+ fallback_diff_refs: diffs.fallback_diff_refs
+ )
end
it "uses ActiveSupport::Gzip when reading from the cache" do
diff --git a/spec/lib/gitlab/diff/highlight_spec.rb b/spec/lib/gitlab/diff/highlight_spec.rb
index e39c15c8fd7..e65f5a618a5 100644
--- a/spec/lib/gitlab/diff/highlight_spec.rb
+++ b/spec/lib/gitlab/diff/highlight_spec.rb
@@ -44,13 +44,13 @@ RSpec.describe Gitlab::Diff::Highlight, feature_category: :source_code_managemen
end
it 'highlights and marks removed lines' do
- code = %{-<span id="LC9" class="line" lang="ruby"> <span class="k">raise</span> <span class="s2">"System commands must be given as an array of strings"</span></span>\n}
+ code = %(-<span id="LC9" class="line" lang="ruby"> <span class="k">raise</span> <span class="s2">"System commands must be given as an array of strings"</span></span>\n)
expect(subject[4].rich_text).to eq(code)
end
it 'highlights and marks added lines' do
- code = %{+<span id="LC9" class="line" lang="ruby"> <span class="k">raise</span> <span class="no"><span class="idiff left addition">RuntimeError</span></span><span class="p"><span class="idiff addition">,</span></span><span class="idiff right addition"> </span><span class="s2">"System commands must be given as an array of strings"</span></span>\n}
+ code = %(+<span id="LC9" class="line" lang="ruby"> <span class="k">raise</span> <span class="no"><span class="idiff left addition">RuntimeError</span></span><span class="p"><span class="idiff addition">,</span></span><span class="idiff right addition"> </span><span class="s2">"System commands must be given as an array of strings"</span></span>\n)
expect(subject[5].rich_text).to eq(code)
end
@@ -86,14 +86,14 @@ RSpec.describe Gitlab::Diff::Highlight, feature_category: :source_code_managemen
end
it 'marks removed lines' do
- code = %q{- raise "System commands must be given as an array of strings"}
+ code = %q(- raise "System commands must be given as an array of strings")
expect(subject[4].text).to eq(code)
expect(subject[4].text).not_to be_html_safe
end
it 'marks added lines' do
- code = %q{+ raise <span class="idiff left right addition">RuntimeError, </span>&quot;System commands must be given as an array of strings&quot;}
+ code = %q(+ raise <span class="idiff left right addition">RuntimeError, </span>&quot;System commands must be given as an array of strings&quot;)
expect(subject[5].rich_text).to eq(code)
expect(subject[5].rich_text).to be_html_safe
@@ -107,7 +107,7 @@ RSpec.describe Gitlab::Diff::Highlight, feature_category: :source_code_managemen
it 'keeps the original rich line' do
allow(Gitlab::ErrorTracking).to receive(:track_and_raise_for_dev_exception)
- code = %q{+ raise RuntimeError, "System commands must be given as an array of strings"}
+ code = %q(+ raise RuntimeError, "System commands must be given as an array of strings")
expect(subject[5].text).to eq(code)
expect(subject[5].text).not_to be_html_safe
diff --git a/spec/lib/gitlab/diff/inline_diff_marker_spec.rb b/spec/lib/gitlab/diff/inline_diff_marker_spec.rb
index 8ab2a7b64dd..602f1b1c2b2 100644
--- a/spec/lib/gitlab/diff/inline_diff_marker_spec.rb
+++ b/spec/lib/gitlab/diff/inline_diff_marker_spec.rb
@@ -10,10 +10,10 @@ RSpec.describe Gitlab::Diff::InlineDiffMarker do
subject { described_class.new(raw, rich).mark(inline_diffs) }
context "when the rich text is html safe" do
- let(:rich) { %{<span class="abc">abc</span><span class="space"> </span><span class="def">&#39;def&#39;</span>}.html_safe }
+ let(:rich) { %(<span class="abc">abc</span><span class="space"> </span><span class="def">&#39;def&#39;</span>).html_safe }
it 'marks the range' do
- expect(subject).to eq(%{<span class="abc">ab<span class="idiff left">c</span></span><span class="space"><span class="idiff"> </span></span><span class="def"><span class="idiff right">&#39;d</span>ef&#39;</span>})
+ expect(subject).to eq(%(<span class="abc">ab<span class="idiff left">c</span></span><span class="space"><span class="idiff"> </span></span><span class="def"><span class="idiff right">&#39;d</span>ef&#39;</span>))
expect(subject).to be_html_safe
end
end
@@ -22,7 +22,7 @@ RSpec.describe Gitlab::Diff::InlineDiffMarker do
let(:rich) { "abc 'def' differs" }
it 'marks the range' do
- expect(subject).to eq(%{ab<span class="idiff left right">c &#39;d</span>ef&#39; differs})
+ expect(subject).to eq(%(ab<span class="idiff left right">c &#39;d</span>ef&#39; differs))
expect(subject).to be_html_safe
end
end
diff --git a/spec/lib/gitlab/diff/line_spec.rb b/spec/lib/gitlab/diff/line_spec.rb
index 949def599ae..b23ba3a0f00 100644
--- a/spec/lib/gitlab/diff/line_spec.rb
+++ b/spec/lib/gitlab/diff/line_spec.rb
@@ -11,10 +11,16 @@ RSpec.describe Gitlab::Diff::Line do
end
let(:line) do
- described_class.new('<input>', 'match', 0, 0, 1,
- parent_file: double(:file),
- line_code: double(:line_code),
- rich_text: rich_text)
+ described_class.new(
+ '<input>',
+ 'match',
+ 0,
+ 0,
+ 1,
+ parent_file: double(:file),
+ line_code: double(:line_code),
+ rich_text: rich_text
+ )
end
let(:rich_text) { nil }
diff --git a/spec/lib/gitlab/diff/suggestion_diff_spec.rb b/spec/lib/gitlab/diff/suggestion_diff_spec.rb
index 9546c581112..f9d56662753 100644
--- a/spec/lib/gitlab/diff/suggestion_diff_spec.rb
+++ b/spec/lib/gitlab/diff/suggestion_diff_spec.rb
@@ -22,9 +22,7 @@ RSpec.describe Gitlab::Diff::SuggestionDiff do
end
let(:suggestion) do
- instance_double(Suggestion, from_line: 12,
- from_content: from_content,
- to_content: to_content)
+ instance_double(Suggestion, from_line: 12, from_content: from_content, to_content: to_content)
end
subject { described_class.new(suggestion).diff_lines }
@@ -56,9 +54,12 @@ RSpec.describe Gitlab::Diff::SuggestionDiff do
it 'returns a correct value if there is no newline at the end of the file' do
from_content = "One line test"
to_content = "Successful test!"
- suggestion = instance_double(Suggestion, from_line: 1,
- from_content: from_content,
- to_content: to_content)
+ suggestion = instance_double(
+ Suggestion,
+ from_line: 1,
+ from_content: from_content,
+ to_content: to_content
+ )
diff_lines = described_class.new(suggestion).diff_lines
diff --git a/spec/lib/gitlab/diff/suggestion_spec.rb b/spec/lib/gitlab/diff/suggestion_spec.rb
index 40779faf917..9f654c44852 100644
--- a/spec/lib/gitlab/diff/suggestion_spec.rb
+++ b/spec/lib/gitlab/diff/suggestion_spec.rb
@@ -5,10 +5,12 @@ require 'spec_helper'
RSpec.describe Gitlab::Diff::Suggestion do
shared_examples 'correct suggestion raw content' do
it 'returns correct raw data' do
- expect(suggestion.to_hash).to include(from_content: expected_lines.join,
- to_content: "#{text}\n",
- lines_above: above,
- lines_below: below)
+ expect(suggestion.to_hash).to include(
+ from_content: expected_lines.join,
+ to_content: "#{text}\n",
+ lines_above: above,
+ lines_below: below
+ )
end
it 'returns diff lines with correct line numbers' do
@@ -25,11 +27,13 @@ RSpec.describe Gitlab::Diff::Suggestion do
let(:merge_request) { create(:merge_request) }
let(:project) { merge_request.project }
let(:position) do
- Gitlab::Diff::Position.new(old_path: "files/ruby/popen.rb",
- new_path: "files/ruby/popen.rb",
- old_line: nil,
- new_line: 9,
- diff_refs: merge_request.diff_refs)
+ Gitlab::Diff::Position.new(
+ old_path: "files/ruby/popen.rb",
+ new_path: "files/ruby/popen.rb",
+ old_line: nil,
+ new_line: 9,
+ diff_refs: merge_request.diff_refs
+ )
end
let(:diff_file) do
diff --git a/spec/lib/gitlab/diff/suggestions_parser_spec.rb b/spec/lib/gitlab/diff/suggestions_parser_spec.rb
index a00c55d4fb2..ef845dbdc4c 100644
--- a/spec/lib/gitlab/diff/suggestions_parser_spec.rb
+++ b/spec/lib/gitlab/diff/suggestions_parser_spec.rb
@@ -7,11 +7,13 @@ RSpec.describe Gitlab::Diff::SuggestionsParser do
let(:merge_request) { create(:merge_request) }
let(:project) { merge_request.project }
let(:position) do
- Gitlab::Diff::Position.new(old_path: "files/ruby/popen.rb",
- new_path: "files/ruby/popen.rb",
- old_line: nil,
- new_line: 9,
- diff_refs: merge_request.diff_refs)
+ Gitlab::Diff::Position.new(
+ old_path: "files/ruby/popen.rb",
+ new_path: "files/ruby/popen.rb",
+ old_line: nil,
+ new_line: 9,
+ diff_refs: merge_request.diff_refs
+ )
end
let(:diff_file) do
@@ -19,8 +21,7 @@ RSpec.describe Gitlab::Diff::SuggestionsParser do
end
subject do
- described_class.parse(markdown, project: merge_request.project,
- position: position)
+ described_class.parse(markdown, project: merge_request.project, position: position)
end
def blob_lines_data(from_line, to_line)
@@ -59,15 +60,19 @@ RSpec.describe Gitlab::Diff::SuggestionsParser do
from_line = position.new_line
to_line = position.new_line
- expect(subject.first.to_hash).to include(from_content: blob_lines_data(from_line, to_line),
- to_content: " foo\n bar\n",
- lines_above: 0,
- lines_below: 0)
-
- expect(subject.second.to_hash).to include(from_content: blob_lines_data(from_line, to_line),
- to_content: " xpto\n baz\n",
- lines_above: 0,
- lines_below: 0)
+ expect(subject.first.to_hash).to include(
+ from_content: blob_lines_data(from_line, to_line),
+ to_content: " foo\n bar\n",
+ lines_above: 0,
+ lines_below: 0
+ )
+
+ expect(subject.second.to_hash).to include(
+ from_content: blob_lines_data(from_line, to_line),
+ to_content: " xpto\n baz\n",
+ lines_above: 0,
+ lines_below: 0
+ )
end
end
@@ -105,30 +110,36 @@ RSpec.describe Gitlab::Diff::SuggestionsParser do
from_line = position.new_line - 2
to_line = position.new_line + 1
- expect(subject.first.to_hash).to include(from_content: blob_lines_data(from_line, to_line),
- to_content: " # above and below\n",
- lines_above: 2,
- lines_below: 1)
+ expect(subject.first.to_hash).to include(
+ from_content: blob_lines_data(from_line, to_line),
+ to_content: " # above and below\n",
+ lines_above: 2,
+ lines_below: 1
+ )
end
it 'suggestion with above param has correct data' do
from_line = position.new_line - 3
to_line = position.new_line
- expect(subject.second.to_hash).to eq(from_content: blob_lines_data(from_line, to_line),
- to_content: " # only above\n",
- lines_above: 3,
- lines_below: 0)
+ expect(subject.second.to_hash).to eq(
+ from_content: blob_lines_data(from_line, to_line),
+ to_content: " # only above\n",
+ lines_above: 3,
+ lines_below: 0
+ )
end
it 'suggestion with below param has correct data' do
from_line = position.new_line
to_line = position.new_line + 3
- expect(subject.third.to_hash).to eq(from_content: blob_lines_data(from_line, to_line),
- to_content: " # only below\n",
- lines_above: 0,
- lines_below: 3)
+ expect(subject.third.to_hash).to eq(
+ from_content: blob_lines_data(from_line, to_line),
+ to_content: " # only below\n",
+ lines_above: 0,
+ lines_below: 3
+ )
end
end
end
diff --git a/spec/lib/gitlab/discussions_diff/file_collection_spec.rb b/spec/lib/gitlab/discussions_diff/file_collection_spec.rb
index f85a68ada15..a1d9a861355 100644
--- a/spec/lib/gitlab/discussions_diff/file_collection_spec.rb
+++ b/spec/lib/gitlab/discussions_diff/file_collection_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Gitlab::DiscussionsDiff::FileCollection do
+RSpec.describe Gitlab::DiscussionsDiff::FileCollection, :clean_gitlab_redis_shared_state do
let(:merge_request) { create(:merge_request) }
let!(:diff_note_a) { create(:diff_note_on_merge_request, project: merge_request.project, noteable: merge_request) }
let!(:diff_note_b) { create(:diff_note_on_merge_request, project: merge_request.project, noteable: merge_request) }
@@ -11,7 +11,18 @@ RSpec.describe Gitlab::DiscussionsDiff::FileCollection do
subject { described_class.new([note_diff_file_a, note_diff_file_b]) }
- describe '#load_highlight', :clean_gitlab_redis_shared_state do
+ describe '#load_highlight' do
+ it 'only takes into account for the specific diff note ids' do
+ file_a_caching_content = diff_note_a.diff_file.highlighted_diff_lines.map(&:to_hash)
+
+ expect(Gitlab::DiscussionsDiff::HighlightCache)
+ .to receive(:write_multiple)
+ .with({ note_diff_file_a.id => file_a_caching_content })
+ .and_call_original
+
+ subject.load_highlight(diff_note_ids: [note_diff_file_a.diff_note_id])
+ end
+
it 'writes uncached diffs highlight' do
file_a_caching_content = diff_note_a.diff_file.highlighted_diff_lines.map(&:to_hash)
file_b_caching_content = diff_note_b.diff_file.highlighted_diff_lines.map(&:to_hash)
diff --git a/spec/lib/gitlab/email/handler/service_desk_handler_spec.rb b/spec/lib/gitlab/email/handler/service_desk_handler_spec.rb
index e6fff939632..f13fd0be4cd 100644
--- a/spec/lib/gitlab/email/handler/service_desk_handler_spec.rb
+++ b/spec/lib/gitlab/email/handler/service_desk_handler_spec.rb
@@ -8,12 +8,14 @@ RSpec.describe Gitlab::Email::Handler::ServiceDeskHandler, feature_category: :se
before do
stub_incoming_email_setting(enabled: true, address: "incoming+%{key}@appmail.adventuretime.ooo")
+ stub_service_desk_email_setting(enabled: true, address: "contact+%{key}@example.com")
stub_config_setting(host: 'localhost')
end
let(:email_raw) { email_fixture('emails/service_desk.eml') }
let(:author_email) { 'jake@adventuretime.ooo' }
let(:message_id) { 'CADkmRc+rNGAGGbV2iE5p918UVy4UyJqVcXRO2=otppgzduJSg@mail.gmail.com' }
+ let(:issue_email_participants_count) { 1 }
let_it_be(:group) { create(:group, :private, :crm_enabled, name: "email") }
@@ -22,7 +24,7 @@ RSpec.describe Gitlab::Email::Handler::ServiceDeskHandler, feature_category: :se
end
context 'service desk is enabled for the project' do
- let_it_be(:project) { create(:project, :repository, :private, group: group, path: 'test', service_desk_enabled: true) }
+ let_it_be_with_reload(:project) { create(:project, :repository, :private, group: group, path: 'test', service_desk_enabled: true) }
before do
allow(Gitlab::ServiceDesk).to receive(:supported?).and_return(true)
@@ -50,6 +52,7 @@ RSpec.describe Gitlab::Email::Handler::ServiceDeskHandler, feature_category: :se
receiver.execute
new_issue = Issue.last
+ expect(new_issue.issue_email_participants.count).to eq(issue_email_participants_count)
expect(new_issue.issue_email_participants.first.email).to eq(author_email)
end
@@ -96,6 +99,72 @@ RSpec.describe Gitlab::Email::Handler::ServiceDeskHandler, feature_category: :se
expect(new_issue.issue_customer_relations_contacts.map(&:contact)).to contain_exactly(contact, contact2, contact3)
end
+ context 'when add_external_participants_from_cc is true' do
+ shared_examples 'does not add CC address' do
+ it 'creates a new issue and adds issue_email_participant from From header' do
+ expect { receiver.execute }.to change { Issue.count }.by(1)
+ expect(Issue.last.issue_email_participants.map(&:email)).to match_array(%w[from@example.com])
+ end
+ end
+
+ let_it_be(:setting) { create(:service_desk_setting, project: project, add_external_participants_from_cc: true) }
+
+ # Original email contains two CC email addresses
+ let(:issue_email_participants_count) { 3 }
+ let(:to_address) { project.service_desk_incoming_address }
+
+ it_behaves_like 'a new issue request'
+
+ context 'when no CC header is present' do
+ let(:email_raw) do
+ <<~EMAIL
+ From: from@example.com
+ To: #{to_address}
+ Subject: Issue title
+
+ Issue description
+ EMAIL
+ end
+
+ it_behaves_like 'does not add CC address'
+ end
+
+ context 'when service desk system address is in CC' do
+ let(:cc_address) { project.service_desk_incoming_address }
+ let(:email_raw) do
+ <<~EMAIL
+ From: from@example.com
+ To: #{to_address}
+ Cc: #{cc_address}
+ Subject: Issue title
+
+ Issue description
+ EMAIL
+ end
+
+ it_behaves_like 'does not add CC address'
+
+ context 'when service_desk_email is part of CC' do
+ let(:cc_address) { project.service_desk_alias_address }
+
+ it_behaves_like 'does not add CC address'
+ end
+
+ context 'when custom email is part of CC' do
+ let!(:credential) { create(:service_desk_custom_email_credential, project: project) }
+ let!(:verification) { create(:service_desk_custom_email_verification, :finished, project: project) }
+ let(:cc_address) { project.service_desk_custom_address }
+
+ before do
+ project.reset
+ setting.update!(custom_email: 'support@example.com', custom_email_enabled: true)
+ end
+
+ it_behaves_like 'does not add CC address'
+ end
+ end
+ end
+
context 'with legacy incoming email address' do
let(:email_raw) { fixture_file('emails/service_desk_legacy.eml') }
@@ -140,25 +209,26 @@ RSpec.describe Gitlab::Email::Handler::ServiceDeskHandler, feature_category: :se
subject
end
- context 'when issue_email_participants FF is enabled' do
- it 'creates 2 issue_email_participants' do
- subject
+ it 'creates issue_email_participants for author and reply author' do
+ subject
- expect(Issue.last.issue_email_participants.map(&:email))
- .to match_array(%w(alan@adventuretime.ooo jake@adventuretime.ooo))
- end
+ # 1 from issue creation
+ # 1 from new note reply
+ expect(Issue.last.issue_email_participants.map(&:email))
+ .to match_array(%w[alan@adventuretime.ooo jake@adventuretime.ooo])
end
context 'when issue_email_participants FF is disabled' do
before do
+ # Was turned off after issue creation
stub_feature_flags(issue_email_participants: false)
end
- it 'creates only 1 issue_email_participant' do
+ it 'creates issue_email_participant for the author' do
subject
expect(Issue.last.issue_email_participants.map(&:email))
- .to match_array(%w(jake@adventuretime.ooo))
+ .to match_array(%w[jake@adventuretime.ooo])
end
end
end
@@ -182,11 +252,11 @@ RSpec.describe Gitlab::Email::Handler::ServiceDeskHandler, feature_category: :se
subject
end
- it 'creates 1 issue_email_participant' do
+ it 'creates issue_email_participant for the author' do
subject
expect(Issue.last.issue_email_participants.map(&:email))
- .to match_array(%w(alan@adventuretime.ooo))
+ .to match_array(%w[alan@adventuretime.ooo])
end
end
end
diff --git a/spec/lib/gitlab/email/handler_spec.rb b/spec/lib/gitlab/email/handler_spec.rb
index d3a4d77c58e..47907401a63 100644
--- a/spec/lib/gitlab/email/handler_spec.rb
+++ b/spec/lib/gitlab/email/handler_spec.rb
@@ -60,10 +60,10 @@ RSpec.describe Gitlab::Email::Handler do
describe 'regexps are set properly' do
let(:addresses) do
- %W(sent_notification_key#{Gitlab::Email::Common::UNSUBSCRIBE_SUFFIX} sent_notification_key#{Gitlab::Email::Common::UNSUBSCRIBE_SUFFIX_LEGACY}) +
- %w(sent_notification_key path-to-project-123-user_email_token-merge-request) +
- %w(path-to-project-123-user_email_token-issue path-to-project-123-user_email_token-issue-123) +
- %w(path/to/project+user_email_token path/to/project+merge-request+user_email_token some/project)
+ %W[sent_notification_key#{Gitlab::Email::Common::UNSUBSCRIBE_SUFFIX} sent_notification_key#{Gitlab::Email::Common::UNSUBSCRIBE_SUFFIX_LEGACY}] +
+ %w[sent_notification_key path-to-project-123-user_email_token-merge-request] +
+ %w[path-to-project-123-user_email_token-issue path-to-project-123-user_email_token-issue-123] +
+ %w[path/to/project+user_email_token path/to/project+merge-request+user_email_token some/project]
end
before do
diff --git a/spec/lib/gitlab/email/receiver_spec.rb b/spec/lib/gitlab/email/receiver_spec.rb
index f8084d24850..c86a83092a4 100644
--- a/spec/lib/gitlab/email/receiver_spec.rb
+++ b/spec/lib/gitlab/email/receiver_spec.rb
@@ -33,7 +33,7 @@ RSpec.describe Gitlab::Email::Receiver do
metadata = receiver.mail_metadata
- expect(metadata.keys).to match_array(%i(mail_uid from_address to_address mail_key references delivered_to envelope_to x_envelope_to meta received_recipients cc_address))
+ expect(metadata.keys).to match_array(%i[mail_uid from_address to_address mail_key references delivered_to envelope_to x_envelope_to meta received_recipients cc_address])
expect(metadata[:meta]).to include(client_id: client_id, project: project.full_path)
expect(metadata[meta_key]).to eq(meta_value)
end
diff --git a/spec/lib/gitlab/encoding_helper_spec.rb b/spec/lib/gitlab/encoding_helper_spec.rb
index 1b7c11dfef6..db7961fc0c9 100644
--- a/spec/lib/gitlab/encoding_helper_spec.rb
+++ b/spec/lib/gitlab/encoding_helper_spec.rb
@@ -214,7 +214,7 @@ RSpec.describe Gitlab::EncodingHelper, feature_category: :shared do
[nil, ""],
["", ""],
[" ", " "],
- %w(a1 a1),
+ %w[a1 a1],
["编码", "\xE7\xBC\x96\xE7\xA0\x81".b]
].each do |input, result|
it "encodes #{input.inspect} to #{result.inspect}" do
diff --git a/spec/lib/gitlab/endpoint_attributes_spec.rb b/spec/lib/gitlab/endpoint_attributes_spec.rb
index a623070c3eb..34f4221b86a 100644
--- a/spec/lib/gitlab/endpoint_attributes_spec.rb
+++ b/spec/lib/gitlab/endpoint_attributes_spec.rb
@@ -11,19 +11,19 @@ RSpec.describe Gitlab::EndpointAttributes, feature_category: :api do
let(:controller) do
Class.new(base_controller) do
- feature_category :foo, %w(update edit)
- feature_category :bar, %w(index show)
- feature_category :quux, %w(destroy)
+ feature_category :foo, %w[update edit]
+ feature_category :bar, %w[index show]
+ feature_category :quux, %w[destroy]
- urgency :high, %w(do_a)
- urgency :low, %w(do_b do_c)
+ urgency :high, %w[do_a]
+ urgency :low, %w[do_b do_c]
end
end
let(:subclass) do
Class.new(controller) do
- feature_category :baz, %w(subclass_index)
- urgency :high, %w(superclass_do_something)
+ feature_category :baz, %w[subclass_index]
+ urgency :high, %w[superclass_do_something]
end
end
diff --git a/spec/lib/gitlab/error_tracking/stack_trace_highlight_decorator_spec.rb b/spec/lib/gitlab/error_tracking/stack_trace_highlight_decorator_spec.rb
index a854adca32b..eae6186e789 100644
--- a/spec/lib/gitlab/error_tracking/stack_trace_highlight_decorator_spec.rb
+++ b/spec/lib/gitlab/error_tracking/stack_trace_highlight_decorator_spec.rb
@@ -28,7 +28,7 @@ RSpec.describe Gitlab::ErrorTracking::StackTraceHighlightDecorator do
[11, '<span id="LC1" class="line" lang="ruby"><span class="k">class</span> <span class="nc">HelloWorld</span></span>'],
[12, '<span id="LC1" class="line" lang="ruby"> <span class="k">def</span> <span class="nc">self</span><span class="o">.</span><span class="nf">message</span></span>'],
[13, '<span id="LC1" class="line" lang="ruby"> <span class="vi">@name</span> <span class="o">=</span> <span class="s1">\'World\'</span></span>'],
- [14, %[<span id="LC1" class="line" lang="ruby"> <span class="nb">puts</span> <span class="s2">"Hello </span><span class="si">\#{</span><span class="vi">@name</span><span class="si">}</span><span class="s2">"</span></span>]],
+ [14, %(<span id="LC1" class="line" lang="ruby"> <span class="nb">puts</span> <span class="s2">"Hello </span><span class="si">\#{</span><span class="vi">@name</span><span class="si">}</span><span class="s2">"</span></span>)],
[15, '<span id="LC1" class="line" lang="ruby"> <span class="k">end</span></span>'],
[16, '<span id="LC1" class="line" lang="ruby"><span class="k">end</span></span>']
]
diff --git a/spec/lib/gitlab/external_authorization/client_spec.rb b/spec/lib/gitlab/external_authorization/client_spec.rb
index b907b0bb262..b507fe7bde8 100644
--- a/spec/lib/gitlab/external_authorization/client_spec.rb
+++ b/spec/lib/gitlab/external_authorization/client_spec.rb
@@ -109,7 +109,7 @@ RSpec.describe Gitlab::ExternalAuthorization::Client do
describe 'for non-ldap users with identities' do
before do
- %w(twitter facebook).each do |provider|
+ %w[twitter facebook].each do |provider|
create(:identity, provider: provider, extern_uid: "#{provider}_external_id", user: user)
end
end
diff --git a/spec/lib/gitlab/favicon_spec.rb b/spec/lib/gitlab/favicon_spec.rb
index 033fa5d1b42..62071293764 100644
--- a/spec/lib/gitlab/favicon_spec.rb
+++ b/spec/lib/gitlab/favicon_spec.rb
@@ -60,7 +60,7 @@ RSpec.describe Gitlab::Favicon, :request_store do
subject { described_class.available_status_names }
it 'returns the available status names' do
- expect(subject).to eq %w(
+ expect(subject).to eq %w[
favicon_status_canceled
favicon_status_created
favicon_status_failed
@@ -73,7 +73,7 @@ RSpec.describe Gitlab::Favicon, :request_store do
favicon_status_skipped
favicon_status_success
favicon_status_warning
- )
+ ]
end
end
end
diff --git a/spec/lib/gitlab/feature_categories_spec.rb b/spec/lib/gitlab/feature_categories_spec.rb
index a35166a4499..11ddd08c968 100644
--- a/spec/lib/gitlab/feature_categories_spec.rb
+++ b/spec/lib/gitlab/feature_categories_spec.rb
@@ -3,7 +3,7 @@
require 'spec_helper'
RSpec.describe Gitlab::FeatureCategories do
- let(:fake_categories) { %w(foo bar) }
+ let(:fake_categories) { %w[foo bar] }
subject(:feature_categories) { described_class.new(fake_categories) }
diff --git a/spec/lib/gitlab/file_detector_spec.rb b/spec/lib/gitlab/file_detector_spec.rb
index 208acf28cc4..55bb1804d86 100644
--- a/spec/lib/gitlab/file_detector_spec.rb
+++ b/spec/lib/gitlab/file_detector_spec.rb
@@ -1,17 +1,17 @@
# frozen_string_literal: true
-require 'fast_spec_helper'
+require 'spec_helper'
RSpec.describe Gitlab::FileDetector do
describe '.types_in_paths' do
it 'returns the file types for the given paths' do
- expect(described_class.types_in_paths(%w(README.md CHANGELOG VERSION VERSION)))
- .to eq(%i{readme changelog version})
+ expect(described_class.types_in_paths(%w[README.md CHANGELOG VERSION VERSION]))
+ .to eq(%i[readme changelog version])
end
it 'does not include unrecognized file paths' do
- expect(described_class.types_in_paths(%w(README.md foo.txt)))
- .to eq(%i{readme})
+ expect(described_class.types_in_paths(%w[README.md foo.txt]))
+ .to eq(%i[readme])
end
end
@@ -25,7 +25,7 @@ RSpec.describe Gitlab::FileDetector do
extensions = ['txt', *Gitlab::MarkupHelper::EXTENSIONS]
extensions.each do |ext|
- %w(index readme).each do |file|
+ %w[index readme].each do |file|
expect(described_class.type_of("#{file}.#{ext}")).to eq(:readme)
end
end
@@ -45,13 +45,13 @@ RSpec.describe Gitlab::FileDetector do
end
it 'returns the type of a changelog file' do
- %w(CHANGELOG HISTORY CHANGES NEWS).each do |file|
+ %w[CHANGELOG HISTORY CHANGES NEWS].each do |file|
expect(described_class.type_of(file)).to eq(:changelog)
end
end
it 'returns the type of a license file' do
- %w(LICENSE LICENCE COPYING UNLICENSE UNLICENCE).each do |file|
+ %w[LICENSE LICENCE COPYING UNLICENSE UNLICENCE].each do |file|
expect(described_class.type_of(file)).to eq(:license)
end
end
@@ -73,7 +73,7 @@ RSpec.describe Gitlab::FileDetector do
end
it 'returns the type of an avatar' do
- %w(logo.gif logo.png logo.jpg).each do |file|
+ %w[logo.gif logo.png logo.jpg].each do |file|
expect(described_class.type_of(file)).to eq(:avatar)
end
end
diff --git a/spec/lib/gitlab/gfm/reference_rewriter_spec.rb b/spec/lib/gitlab/gfm/reference_rewriter_spec.rb
index 6de7cab9c42..75427ac0402 100644
--- a/spec/lib/gitlab/gfm/reference_rewriter_spec.rb
+++ b/spec/lib/gitlab/gfm/reference_rewriter_spec.rb
@@ -78,13 +78,13 @@ RSpec.describe Gitlab::Gfm::ReferenceRewriter do
context 'label referenced by id' do
let(:text) { '#1 and ~123' }
- it { is_expected.to eq %{#{old_project_ref}#1 and #{old_project_ref}~123} }
+ it { is_expected.to eq %(#{old_project_ref}#1 and #{old_project_ref}~123) }
end
context 'label referenced by text' do
let(:text) { '#1 and ~"test"' }
- it { is_expected.to eq %{#{old_project_ref}#1 and #{old_project_ref}~123} }
+ it { is_expected.to eq %(#{old_project_ref}#1 and #{old_project_ref}~123) }
end
end
@@ -99,13 +99,13 @@ RSpec.describe Gitlab::Gfm::ReferenceRewriter do
context 'label referenced by id' do
let(:text) { '#1 and ~321' }
- it { is_expected.to eq %{#{old_project_ref}#1 and #{old_project_ref}~321} }
+ it { is_expected.to eq %(#{old_project_ref}#1 and #{old_project_ref}~321) }
end
context 'label referenced by text' do
let(:text) { '#1 and ~"group label"' }
- it { is_expected.to eq %{#{old_project_ref}#1 and #{old_project_ref}~321} }
+ it { is_expected.to eq %(#{old_project_ref}#1 and #{old_project_ref}~321) }
end
end
end
@@ -149,7 +149,7 @@ RSpec.describe Gitlab::Gfm::ReferenceRewriter do
let(:text) { 'milestone: %"9.0"' }
- it { is_expected.to eq %[milestone: #{old_project_ref}%"9.0"] }
+ it { is_expected.to eq %(milestone: #{old_project_ref}%"9.0") }
end
context 'when referring to group milestone' do
diff --git a/spec/lib/gitlab/git/blame_spec.rb b/spec/lib/gitlab/git/blame_spec.rb
index 77361b09857..751611be5d2 100644
--- a/spec/lib/gitlab/git/blame_spec.rb
+++ b/spec/lib/gitlab/git/blame_spec.rb
@@ -48,6 +48,14 @@ RSpec.describe Gitlab::Git::Blame, feature_category: :source_code_management do
end
end
+ context 'when path is missing' do
+ let(:path) { 'unknown_file' }
+
+ it 'returns an empty array' do
+ expect(result).to eq([])
+ end
+ end
+
context "ISO-8859 encoding" do
let(:path) { 'encoding/iso8859.txt' }
diff --git a/spec/lib/gitlab/git/blob_spec.rb b/spec/lib/gitlab/git/blob_spec.rb
index 5bb4b84835d..59cf87ddc7e 100644
--- a/spec/lib/gitlab/git/blob_spec.rb
+++ b/spec/lib/gitlab/git/blob_spec.rb
@@ -154,18 +154,6 @@ RSpec.describe Gitlab::Git::Blob do
it_behaves_like '.find'
end
- describe '.find with Rugged enabled', :enable_rugged do
- it 'calls out to the Rugged implementation' do
- allow_next_instance_of(Rugged) do |instance|
- allow(instance).to receive(:rev_parse).with(TestEnv::BRANCH_SHA['master']).and_call_original
- end
-
- described_class.find(repository, TestEnv::BRANCH_SHA['master'], 'files/images/6049019_460s.jpg')
- end
-
- it_behaves_like '.find'
- end
-
describe '.raw' do
let(:raw_blob) { described_class.raw(repository, SeedRepo::RubyBlob::ID) }
let(:bad_blob) { described_class.raw(repository, SeedRepo::BigCommit::ID) }
diff --git a/spec/lib/gitlab/git/commit_spec.rb b/spec/lib/gitlab/git/commit_spec.rb
index 5c4be1003c3..d8d62ac9670 100644
--- a/spec/lib/gitlab/git/commit_spec.rb
+++ b/spec/lib/gitlab/git/commit_spec.rb
@@ -160,18 +160,6 @@ RSpec.describe Gitlab::Git::Commit, feature_category: :source_code_management do
it_behaves_like '.find'
end
- describe '.find with Rugged enabled', :enable_rugged do
- it 'calls out to the Rugged implementation' do
- allow_next_instance_of(Rugged) do |instance|
- allow(instance).to receive(:rev_parse).with(SeedRepo::Commit::ID).and_call_original
- end
-
- described_class.find(repository, SeedRepo::Commit::ID)
- end
-
- it_behaves_like '.find'
- end
-
describe '.last_for_path' do
context 'no path' do
subject { described_class.last_for_path(repository, 'master') }
@@ -459,18 +447,6 @@ RSpec.describe Gitlab::Git::Commit, feature_category: :source_code_management do
end
end
- describe '.batch_by_oid with Rugged enabled', :enable_rugged do
- it_behaves_like '.batch_by_oid'
-
- it 'calls out to the Rugged implementation' do
- allow_next_instance_of(Rugged) do |instance|
- allow(instance).to receive(:rev_parse).with(SeedRepo::Commit::ID).and_call_original
- end
-
- described_class.batch_by_oid(repository, [SeedRepo::Commit::ID])
- end
- end
-
describe '.extract_signature_lazily' do
subject { described_class.extract_signature_lazily(repository, commit_id).itself }
diff --git a/spec/lib/gitlab/git/merge_base_spec.rb b/spec/lib/gitlab/git/merge_base_spec.rb
index fda2232c2c3..cbe47aae852 100644
--- a/spec/lib/gitlab/git/merge_base_spec.rb
+++ b/spec/lib/gitlab/git/merge_base_spec.rb
@@ -11,13 +11,13 @@ RSpec.describe Gitlab::Git::MergeBase do
shared_context 'existing refs with a merge base', :existing_refs do
let(:refs) do
- %w(304d257dcb821665ab5110318fc58a007bd104ed 0031876facac3f2b2702a0e53a26e89939a42209)
+ %w[304d257dcb821665ab5110318fc58a007bd104ed 0031876facac3f2b2702a0e53a26e89939a42209]
end
end
shared_context 'when passing a missing ref', :missing_ref do
let(:refs) do
- %w(304d257dcb821665ab5110318fc58a007bd104ed aaaa)
+ %w[304d257dcb821665ab5110318fc58a007bd104ed aaaa]
end
end
@@ -51,13 +51,13 @@ RSpec.describe Gitlab::Git::MergeBase do
end
it 'returns a merge base when passing 2 branch names' do
- merge_base = described_class.new(repository, %w(master feature))
+ merge_base = described_class.new(repository, %w[master feature])
expect(merge_base.sha).to be_present
end
it 'returns a merge base when passing a tag name' do
- merge_base = described_class.new(repository, %w(master v1.0.0))
+ merge_base = described_class.new(repository, %w[master v1.0.0])
expect(merge_base.sha).to be_present
end
diff --git a/spec/lib/gitlab/git/repository_spec.rb b/spec/lib/gitlab/git/repository_spec.rb
index 47b5986cfd8..5791d9c524f 100644
--- a/spec/lib/gitlab/git/repository_spec.rb
+++ b/spec/lib/gitlab/git/repository_spec.rb
@@ -2435,7 +2435,7 @@ RSpec.describe Gitlab::Git::Repository, feature_category: :source_code_managemen
end
it 'deletes all refs except those with the specified prefixes' do
- repository.delete_all_refs_except(%w(refs/keep refs/also-keep refs/heads))
+ repository.delete_all_refs_except(%w[refs/keep refs/also-keep refs/heads])
expect(repository.ref_exists?("refs/delete/a")).to be(false)
expect(repository.ref_exists?("refs/also-delete/b")).to be(false)
expect(repository.ref_exists?("refs/keep/c")).to be(true)
@@ -2722,15 +2722,15 @@ RSpec.describe Gitlab::Git::Repository, feature_category: :source_code_managemen
describe '#check_objects_exist' do
it 'returns hash specifying which object exists in repo' do
- refs_exist = %w(
+ refs_exist = %w[
b83d6e391c22777fca1ed3012fce84f633d7fed0
498214de67004b1da3d820901307bed2a68a8ef6
1b12f15a11fc6e62177bef08f47bc7b5ce50b141
- )
- refs_dont_exist = %w(
+ ]
+ refs_dont_exist = %w[
1111111111111111111111111111111111111111
2222222222222222222222222222222222222222
- )
+ ]
object_existence_map = repository.check_objects_exist(refs_exist + refs_dont_exist)
expect(object_existence_map).to eq({
'b83d6e391c22777fca1ed3012fce84f633d7fed0' => true,
diff --git a/spec/lib/gitlab/git/rugged_impl/use_rugged_spec.rb b/spec/lib/gitlab/git/rugged_impl/use_rugged_spec.rb
deleted file mode 100644
index d5a0ab3d5e0..00000000000
--- a/spec/lib/gitlab/git/rugged_impl/use_rugged_spec.rb
+++ /dev/null
@@ -1,116 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-RSpec.describe Gitlab::Git::RuggedImpl::UseRugged, feature_category: :gitaly do
- let(:project) { create(:project, :repository) }
- let(:repository) { project.repository }
- let(:feature_flag_name) { wrapper.rugged_feature_keys.first }
-
- subject(:wrapper) do
- klazz = Class.new do
- include Gitlab::Git::RuggedImpl::UseRugged
-
- def rugged_test(ref, test_number); end
- end
-
- klazz.new
- end
-
- describe '#execute_rugged_call', :request_store do
- let(:args) { ['refs/heads/master', 1] }
-
- before do
- allow(Gitlab::PerformanceBar).to receive(:enabled_for_request?).and_return(true)
- end
-
- it 'instruments Rugged call' do
- expect(subject).to receive(:rugged_test).with(args)
-
- subject.execute_rugged_call(:rugged_test, args)
-
- expect(Gitlab::RuggedInstrumentation.query_count).to eq(1)
- expect(Gitlab::RuggedInstrumentation.list_call_details.count).to eq(1)
- end
- end
-
- describe '#use_rugged?' do
- it 'returns false' do
- expect(subject.use_rugged?(repository, feature_flag_name)).to be false
- end
- end
-
- describe '#running_puma_with_multiple_threads?' do
- context 'when using Puma' do
- before do
- stub_const('::Puma', double('puma constant'))
- allow(Gitlab::Runtime).to receive(:puma?).and_return(true)
- end
-
- it "returns false when Puma doesn't support the cli_config method" do
- allow(::Puma).to receive(:respond_to?).with(:cli_config).and_return(false)
-
- expect(subject.running_puma_with_multiple_threads?).to be_falsey
- end
-
- it 'returns false for single thread Puma' do
- allow(::Puma).to receive_message_chain(:cli_config, :options).and_return(max_threads: 1)
-
- expect(subject.running_puma_with_multiple_threads?).to be false
- end
-
- it 'returns true for multi-threaded Puma' do
- allow(::Puma).to receive_message_chain(:cli_config, :options).and_return(max_threads: 2)
-
- expect(subject.running_puma_with_multiple_threads?).to be true
- end
- end
-
- context 'when not using Puma' do
- before do
- allow(Gitlab::Runtime).to receive(:puma?).and_return(false)
- end
-
- it 'returns false' do
- expect(subject.running_puma_with_multiple_threads?).to be false
- end
- end
- end
-
- describe '#rugged_enabled_through_feature_flag?' do
- subject { wrapper.send(:rugged_enabled_through_feature_flag?) }
-
- before do
- allow(Feature).to receive(:enabled?).with(:feature_key_1).and_return(true)
- allow(Feature).to receive(:enabled?).with(:feature_key_2).and_return(true)
- allow(Feature).to receive(:enabled?).with(:feature_key_3).and_return(false)
- allow(Feature).to receive(:enabled?).with(:feature_key_4).and_return(false)
-
- stub_const('Gitlab::Git::RuggedImpl::Repository::FEATURE_FLAGS', feature_keys)
- end
-
- context 'no feature keys given' do
- let(:feature_keys) { [] }
-
- it { is_expected.to be_falsey }
- end
-
- context 'all features are enabled' do
- let(:feature_keys) { [:feature_key_1, :feature_key_2] }
-
- it { is_expected.to be_falsey }
- end
-
- context 'all features are not enabled' do
- let(:feature_keys) { [:feature_key_3, :feature_key_4] }
-
- it { is_expected.to be_falsey }
- end
-
- context 'some feature is enabled' do
- let(:feature_keys) { [:feature_key_4, :feature_key_2] }
-
- it { is_expected.to be_falsey }
- end
- end
-end
diff --git a/spec/lib/gitlab/git/tree_spec.rb b/spec/lib/gitlab/git/tree_spec.rb
index 9675e48a77f..090f9af2620 100644
--- a/spec/lib/gitlab/git/tree_spec.rb
+++ b/spec/lib/gitlab/git/tree_spec.rb
@@ -192,122 +192,4 @@ RSpec.describe Gitlab::Git::Tree, feature_category: :source_code_management do
end
end
end
-
- describe '.where with Rugged enabled', :enable_rugged do
- it 'does not call to the Rugged implementation' do
- allow_next_instance_of(Rugged) do |instance|
- allow(instance).not_to receive(:lookup)
- end
-
- described_class.where(repository, SeedRepo::Commit::ID, 'files', false, false)
- end
-
- it_behaves_like 'repo' do
- describe 'Pagination' do
- context 'with restrictive limit' do
- let(:pagination_params) { { limit: 3, page_token: nil } }
-
- it 'returns limited paginated list of tree objects' do
- expect(entries.count).to eq(3)
- expect(cursor.next_cursor).to be_present
- end
- end
-
- context 'when limit is equal to number of entries' do
- let(:entries_count) { entries.count }
-
- it 'returns all entries with a cursor' do
- result, cursor = Gitlab::Git::Tree.where(repository, sha, path, recursive, skip_flat_paths, rescue_not_found, { limit: entries_count, page_token: nil })
-
- expect(cursor).to eq(Gitaly::PaginationCursor.new)
- expect(result.entries.count).to eq(entries_count)
- end
- end
-
- context 'when limit is 0' do
- let(:pagination_params) { { limit: 0, page_token: nil } }
-
- it 'returns empty result' do
- expect(entries).to eq([])
- expect(cursor).to be_nil
- end
- end
-
- context 'when limit is missing' do
- let(:pagination_params) { { limit: nil, page_token: nil } }
-
- it 'returns all entries' do
- expect(entries.count).to be < 20
- expect(cursor).to eq(Gitaly::PaginationCursor.new)
- end
- end
-
- context 'when limit is negative' do
- let(:entries_count) { entries.count }
-
- it 'returns all entries' do
- result, cursor = Gitlab::Git::Tree.where(repository, sha, path, recursive, skip_flat_paths, rescue_not_found, { limit: -1, page_token: nil })
-
- expect(result.count).to eq(entries_count)
- expect(cursor).to eq(Gitaly::PaginationCursor.new)
- end
-
- context 'when token is provided' do
- let(:pagination_params) { { limit: 1000, page_token: nil } }
- let(:token) { entries.second.id }
-
- it 'returns all entries after token' do
- result, cursor = Gitlab::Git::Tree.where(repository, sha, path, recursive, skip_flat_paths, rescue_not_found, { limit: -1, page_token: token })
-
- expect(result.count).to eq(entries.count - 2)
- expect(cursor).to eq(Gitaly::PaginationCursor.new)
- end
- end
- end
-
- context 'when token does not exist' do
- let(:pagination_params) { { limit: 5, page_token: 'aabbccdd' } }
-
- it 'raises a command error' do
- expect { entries }.to raise_error(Gitlab::Git::CommandError, /could not find starting OID: aabbccdd/)
- end
- end
-
- context 'when limit is bigger than number of entries' do
- let(:pagination_params) { { limit: 1000, page_token: nil } }
-
- it 'returns only available entries' do
- expect(entries.count).to be < 20
- expect(cursor).to eq(Gitaly::PaginationCursor.new)
- end
- end
-
- it 'returns all tree entries in specific order during cursor pagination' do
- collected_entries = []
- token = nil
-
- expected_entries = entries
-
- loop do
- result, cursor = Gitlab::Git::Tree.where(repository, sha, path, recursive, skip_flat_paths, rescue_not_found, { limit: 5, page_token: token })
-
- collected_entries += result.entries
- token = cursor&.next_cursor
-
- break if token.blank?
- end
-
- expect(collected_entries.map(&:path)).to match_array(expected_entries.map(&:path))
-
- expected_order = [
- collected_entries.select(&:dir?).map(&:path),
- collected_entries.select(&:file?).map(&:path),
- collected_entries.select(&:submodule?).map(&:path)
- ].flatten
-
- expect(collected_entries.map(&:path)).to eq(expected_order)
- end
- end
- end
- end
end
diff --git a/spec/lib/gitlab/git_access_spec.rb b/spec/lib/gitlab/git_access_spec.rb
index 1b205aa5c85..975e8bdd3ac 100644
--- a/spec/lib/gitlab/git_access_spec.rb
+++ b/spec/lib/gitlab/git_access_spec.rb
@@ -957,7 +957,7 @@ RSpec.describe Gitlab::GitAccess, :aggregate_failures, feature_category: :system
}
}
- [%w(feature exact), ['feat*', 'wildcard']].each do |protected_branch_name, protected_branch_type|
+ [%w[feature exact], ['feat*', 'wildcard']].each do |protected_branch_name, protected_branch_type|
context do
let(:who_can_action) { :maintainers_can_push }
let(:protected_branch) { create(:protected_branch, who_can_action, name: protected_branch_name, project: project) }
diff --git a/spec/lib/gitlab/git_audit_event_spec.rb b/spec/lib/gitlab/git_audit_event_spec.rb
deleted file mode 100644
index c533b39f550..00000000000
--- a/spec/lib/gitlab/git_audit_event_spec.rb
+++ /dev/null
@@ -1,79 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-RSpec.describe Gitlab::GitAuditEvent, feature_category: :source_code_management do
- let_it_be(:player) { create(:user) }
- let_it_be(:group) { create(:group, :public) }
- let_it_be(:project) { create(:project) }
-
- subject { described_class.new(player, project) }
-
- describe '#send_audit_event' do
- let(:msg) { 'valid_msg' }
-
- context 'with successfully sending' do
- let_it_be(:project) { create(:project, namespace: group) }
-
- before do
- allow(::Gitlab::Audit::Auditor).to receive(:audit)
- end
-
- context 'when player is a regular user' do
- it 'sends git audit event' do
- expect(::Gitlab::Audit::Auditor).to receive(:audit).with(a_hash_including(
- name: 'repository_git_operation',
- stream_only: true,
- author: player,
- scope: project,
- target: project,
- message: msg
- )).once
-
- subject.send_audit_event(msg)
- end
- end
-
- context 'when player is ::API::Support::GitAccessActor' do
- let_it_be(:user) { player }
- let_it_be(:key) { create(:key, user: user) }
- let_it_be(:git_access_actor) { ::API::Support::GitAccessActor.new(user: user, key: key) }
-
- subject { described_class.new(git_access_actor, project) }
-
- it 'sends git audit event' do
- expect(::Gitlab::Audit::Auditor).to receive(:audit).with(a_hash_including(
- name: 'repository_git_operation',
- stream_only: true,
- author: git_access_actor.deploy_key_or_user,
- scope: project,
- target: project,
- message: msg
- )).once
-
- subject.send_audit_event(msg)
- end
- end
- end
-
- context 'when user is blank' do
- let_it_be(:player) { nil }
-
- it 'does not send git audit event' do
- expect(::Gitlab::Audit::Auditor).not_to receive(:audit)
-
- subject.send_audit_event(msg)
- end
- end
-
- context 'when project is blank' do
- let_it_be(:project) { nil }
-
- it 'does not send git audit event' do
- expect(::Gitlab::Audit::Auditor).not_to receive(:audit)
-
- subject.send_audit_event(msg)
- end
- end
- end
-end
diff --git a/spec/lib/gitlab/gitaly_client/commit_service_spec.rb b/spec/lib/gitlab/gitaly_client/commit_service_spec.rb
index 2ee9d85c723..02c7abadd99 100644
--- a/spec/lib/gitlab/gitaly_client/commit_service_spec.rb
+++ b/spec/lib/gitlab/gitaly_client/commit_service_spec.rb
@@ -1041,9 +1041,11 @@ RSpec.describe Gitlab::GitalyClient::CommitService, feature_category: :gitaly do
end
describe '#raw_blame' do
- let(:project) { create(:project, :test_repo) }
+ let_it_be(:project) { create(:project, :test_repo) }
+
let(:revision) { 'blame-on-renamed' }
let(:path) { 'files/plain_text/renamed' }
+ let(:range) { nil }
let(:blame_headers) do
[
@@ -1073,6 +1075,31 @@ RSpec.describe Gitlab::GitalyClient::CommitService, feature_category: :gitaly do
is_expected.not_to include(blame_headers[0], blame_headers[1], blame_headers[4])
end
end
+
+ context 'when out of range' do
+ let(:range) { '9999,99999' }
+
+ it { expect { blame }.to raise_error(ArgumentError, 'range is outside of the file length') }
+ end
+
+ context 'when a file path is not found' do
+ let(:path) { 'unknown/path' }
+
+ it { expect { blame }.to raise_error(ArgumentError, 'path not found in revision') }
+ end
+
+ context 'when an unknown exception is raised' do
+ let(:gitaly_exception) { GRPC::BadStatus.new(GRPC::Core::StatusCodes::NOT_FOUND) }
+
+ before do
+ expect_any_instance_of(Gitaly::CommitService::Stub)
+ .to receive(:raw_blame)
+ .with(gitaly_request_with_path(storage_name, relative_path), kind_of(Hash))
+ .and_raise(gitaly_exception)
+ end
+
+ it { expect { blame }.to raise_error(gitaly_exception) }
+ end
end
describe '#get_commit_signatures' do
diff --git a/spec/lib/gitlab/gitaly_client/conflict_files_stitcher_spec.rb b/spec/lib/gitlab/gitaly_client/conflict_files_stitcher_spec.rb
index d0787d8b673..816b59b96ae 100644
--- a/spec/lib/gitlab/gitaly_client/conflict_files_stitcher_spec.rb
+++ b/spec/lib/gitlab/gitaly_client/conflict_files_stitcher_spec.rb
@@ -3,12 +3,12 @@
require 'spec_helper'
RSpec.describe Gitlab::GitalyClient::ConflictFilesStitcher do
+ let_it_be(:target_project) { create(:project, :repository) }
+ let_it_be(:target_repository) { target_project.repository.raw }
+ let_it_be(:target_gitaly_repository) { target_repository.gitaly_repository }
+
describe 'enumeration' do
it 'combines segregated ConflictFile messages together' do
- target_project = create(:project, :repository)
- target_repository = target_project.repository.raw
- target_gitaly_repository = target_repository.gitaly_repository
-
ancestor_path_1 = 'ancestor/path/1'
our_path_1 = 'our/path/1'
their_path_1 = 'their/path/1'
@@ -69,5 +69,49 @@ RSpec.describe Gitlab::GitalyClient::ConflictFilesStitcher do
expect(conflict_files[1].repository).to eq(target_repository)
expect(conflict_files[1].commit_oid).to eq(commit_oid_2)
end
+
+ it 'handles non-latin character names' do
+ ancestor_path_1_utf8 = "ancestor/テスト.txt"
+ our_path_1_utf8 = "our/テスト.txt"
+ their_path_1_utf8 = "their/テスト.txt"
+
+ ancestor_path_1 = String.new('ancestor/テスト.txt', encoding: Encoding::US_ASCII)
+ our_path_1 = String.new('our/テスト.txt', encoding: Encoding::US_ASCII)
+ their_path_1 = String.new('their/テスト.txt', encoding: Encoding::US_ASCII)
+ our_mode_1 = 0744
+ commit_oid_1 = 'f00'
+ content_1 = 'content of the first file'
+
+ header_1 = double(
+ repository: target_gitaly_repository,
+ commit_oid: commit_oid_1,
+ ancestor_path: ancestor_path_1.dup,
+ our_path: our_path_1.dup,
+ their_path: their_path_1.dup,
+ our_mode: our_mode_1
+ )
+
+ messages = [
+ double(files: [double(header: header_1), double(header: nil, content: content_1[0..5])]),
+ double(files: [double(header: nil, content: content_1[6..])])
+ ]
+
+ conflict_files = described_class.new(messages, target_repository.gitaly_repository).to_a
+
+ expect(conflict_files.size).to be(1)
+
+ expect(conflict_files[0].content).to eq(content_1)
+ expect(conflict_files[0].ancestor_path).to eq(ancestor_path_1_utf8)
+ expect(conflict_files[0].their_path).to eq(their_path_1_utf8)
+ expect(conflict_files[0].our_path).to eq(our_path_1_utf8)
+ expect(conflict_files[0].our_mode).to be(our_mode_1)
+ expect(conflict_files[0].repository).to eq(target_repository)
+ expect(conflict_files[0].commit_oid).to eq(commit_oid_1)
+
+ # Doesn't equal the ASCII version
+ expect(conflict_files[0].ancestor_path).not_to eq(ancestor_path_1)
+ expect(conflict_files[0].their_path).not_to eq(their_path_1)
+ expect(conflict_files[0].our_path).not_to eq(our_path_1)
+ end
end
end
diff --git a/spec/lib/gitlab/gitaly_client/operation_service_spec.rb b/spec/lib/gitlab/gitaly_client/operation_service_spec.rb
index bd0341d51bf..f50675fee60 100644
--- a/spec/lib/gitlab/gitaly_client/operation_service_spec.rb
+++ b/spec/lib/gitlab/gitaly_client/operation_service_spec.rb
@@ -1184,7 +1184,7 @@ RSpec.describe Gitlab::GitalyClient::OperationService, feature_category: :source
patch_names.map { |name| File.read(File.join(patches_folder, name)) }.join("\n")
end
- let(:patch_names) { %w(0001-This-does-not-apply-to-the-feature-branch.patch) }
+ let(:patch_names) { %w[0001-This-does-not-apply-to-the-feature-branch.patch] }
let(:branch_name) { 'branch-with-patches' }
subject(:commit_patches) do
@@ -1203,7 +1203,7 @@ RSpec.describe Gitlab::GitalyClient::OperationService, feature_category: :source
end
context 'when the patch could not be applied' do
- let(:patch_names) { %w(0001-This-does-not-apply-to-the-feature-branch.patch) }
+ let(:patch_names) { %w[0001-This-does-not-apply-to-the-feature-branch.patch] }
let(:branch_name) { 'feature' }
it 'raises the correct error' do
diff --git a/spec/lib/gitlab/gitaly_client/ref_service_spec.rb b/spec/lib/gitlab/gitaly_client/ref_service_spec.rb
index ae9276cf90b..118b316f2d4 100644
--- a/spec/lib/gitlab/gitaly_client/ref_service_spec.rb
+++ b/spec/lib/gitlab/gitaly_client/ref_service_spec.rb
@@ -67,7 +67,7 @@ RSpec.describe Gitlab::GitalyClient::RefService, feature_category: :gitaly do
.with(gitaly_request_with_params(merged_only: true, merged_branches: ['test']), kind_of(Hash))
.and_return([])
- client.merged_branches(%w(test))
+ client.merged_branches(%w[test])
end
end
@@ -425,7 +425,7 @@ RSpec.describe Gitlab::GitalyClient::RefService, feature_category: :gitaly do
end
describe '#delete_refs' do
- let(:prefixes) { %w(refs/heads refs/keep-around) }
+ let(:prefixes) { %w[refs/heads refs/keep-around] }
subject(:delete_refs) { client.delete_refs(except_with_prefixes: prefixes) }
diff --git a/spec/lib/gitlab/gitaly_client/repository_service_spec.rb b/spec/lib/gitlab/gitaly_client/repository_service_spec.rb
index 283a9cb45dc..727bf494ee6 100644
--- a/spec/lib/gitlab/gitaly_client/repository_service_spec.rb
+++ b/spec/lib/gitlab/gitaly_client/repository_service_spec.rb
@@ -140,6 +140,44 @@ RSpec.describe Gitlab::GitalyClient::RepositoryService, feature_category: :gital
end
end
+ describe '#fork_repository' do
+ let(:source_repository) { Gitlab::Git::Repository.new('default', 'repo/path', '', 'group/project') }
+
+ context 'when branch is not provided' do
+ it 'sends a create_fork message' do
+ expected_request = gitaly_request_with_params(
+ source_repository: source_repository.gitaly_repository,
+ revision: ""
+ )
+
+ expect_any_instance_of(Gitaly::RepositoryService::Stub)
+ .to receive(:create_fork)
+ .with(expected_request, kind_of(Hash))
+ .and_return(double(value: true))
+
+ client.fork_repository(source_repository)
+ end
+ end
+
+ context 'when branch is provided' do
+ it 'sends a create_fork message including revision' do
+ branch = 'wip'
+
+ expected_request = gitaly_request_with_params(
+ source_repository: source_repository.gitaly_repository,
+ revision: "refs/heads/#{branch}"
+ )
+
+ expect_any_instance_of(Gitaly::RepositoryService::Stub)
+ .to receive(:create_fork)
+ .with(expected_request, kind_of(Hash))
+ .and_return(double(value: true))
+
+ client.fork_repository(source_repository, branch)
+ end
+ end
+ end
+
describe '#import_repository' do
let(:source) { 'https://example.com/git/repo.git' }
diff --git a/spec/lib/gitlab/gitaly_client/storage_settings_spec.rb b/spec/lib/gitlab/gitaly_client/storage_settings_spec.rb
index 0c4c8de52ae..7252f7d6afb 100644
--- a/spec/lib/gitlab/gitaly_client/storage_settings_spec.rb
+++ b/spec/lib/gitlab/gitaly_client/storage_settings_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Gitlab::GitalyClient::StorageSettings do
+RSpec.describe Gitlab::GitalyClient::StorageSettings, feature_category: :gitaly do
describe "#initialize" do
context 'when the storage contains no path' do
it 'raises an error' do
@@ -62,16 +62,16 @@ RSpec.describe Gitlab::GitalyClient::StorageSettings do
end
describe '.disk_access_denied?' do
- context 'when Rugged is enabled', :enable_rugged do
- it 'returns false' do
- expect(described_class.disk_access_denied?).to be_falsey
- end
- end
+ subject { described_class.disk_access_denied? }
- context 'when Rugged is disabled' do
- it 'returns true' do
- expect(described_class.disk_access_denied?).to be_truthy
+ it { is_expected.to be_truthy }
+
+ context 'in case of an exception' do
+ before do
+ allow(described_class).to receive(:temporarily_allowed?).and_raise('boom')
end
+
+ it { is_expected.to be_falsey }
end
end
end
diff --git a/spec/lib/gitlab/gitaly_client_spec.rb b/spec/lib/gitlab/gitaly_client_spec.rb
index 0073d2ebe80..00639d9574b 100644
--- a/spec/lib/gitlab/gitaly_client_spec.rb
+++ b/spec/lib/gitlab/gitaly_client_spec.rb
@@ -517,6 +517,44 @@ RSpec.describe Gitlab::GitalyClient, feature_category: :gitaly do
end
end
+ describe '.fetch_relative_path' do
+ subject { described_class.request_kwargs('default', timeout: 1)[:metadata]['relative-path-bin'] }
+
+ let(:relative_path) { 'relative_path' }
+
+ context 'when RequestStore is disabled' do
+ it 'does not set a relative path' do
+ is_expected.to be_nil
+ end
+ end
+
+ context 'when RequestStore is enabled', :request_store do
+ context 'when RequestStore is empty' do
+ it 'does not set a relative path' do
+ is_expected.to be_nil
+ end
+ end
+
+ context 'when RequestStore contains a relalive_path value' do
+ before do
+ Gitlab::SafeRequestStore[:gitlab_git_relative_path] = relative_path
+ end
+
+ it 'sets a base64 encoded version of relative_path' do
+ is_expected.to eq(relative_path)
+ end
+
+ context 'when relalive_path is empty' do
+ let(:relative_path) { '' }
+
+ it 'does not set a relative path' do
+ is_expected.to be_nil
+ end
+ end
+ end
+ end
+ end
+
context 'gitlab_git_env' do
let(:policy) { 'gitaly-route-repository-accessor-policy' }
diff --git a/spec/lib/gitlab/github_import/attachments_downloader_spec.rb b/spec/lib/gitlab/github_import/attachments_downloader_spec.rb
index 72d8a9c0403..65c5a7daeb2 100644
--- a/spec/lib/gitlab/github_import/attachments_downloader_spec.rb
+++ b/spec/lib/gitlab/github_import/attachments_downloader_spec.rb
@@ -94,9 +94,9 @@ RSpec.describe Gitlab::GithubImport::AttachmentsDownloader, feature_category: :i
end
end
- context 'when attachment is behind a redirect' do
- let_it_be(:file_url) { "https://github.com/test/project/assets/142635249/4b9f9c90-f060-4845-97cf-b24c558bcb11" }
- let(:redirect_url) { "https://https://github-production-user-asset-6210df.s3.amazonaws.com/142635249/740edb05293e.jpg" }
+ context 'when attachment is behind a github asset endpoint' do
+ let(:file_url) { "https://github.com/test/project/assets/142635249/4b9f9c90-f060-4845-97cf-b24c558bcb11" }
+ let(:redirect_url) { "https://github-production-user-asset-6210df.s3.amazonaws.com/142635249/740edb05293e.jpg" }
let(:sample_response) do
instance_double(HTTParty::Response, redirection?: true, headers: { location: redirect_url })
end
@@ -115,6 +115,8 @@ RSpec.describe Gitlab::GithubImport::AttachmentsDownloader, feature_category: :i
end
context 'when url is not a redirection' do
+ let(:file_url) { "https://github.com/test/project/assets/142635249/4b9f9c90-f060-4845-97cf-b24c558bcb11.jpg" }
+
let(:sample_response) do
instance_double(HTTParty::Response, code: 200, redirection?: false)
end
@@ -125,8 +127,13 @@ RSpec.describe Gitlab::GithubImport::AttachmentsDownloader, feature_category: :i
.and_return sample_response
end
- it 'raises upon unsuccessful redirection' do
- expect { downloader.perform }.to raise_error("expected a redirect response, got #{sample_response.code}")
+ it 'queries with original file_url' do
+ expect(Gitlab::HTTP).to receive(:perform_request)
+ .with(Net::HTTP::Get, file_url, stream_body: true).and_yield(chunk_double)
+
+ file = downloader.perform
+
+ expect(File.exist?(file.path)).to eq(true)
end
end
diff --git a/spec/lib/gitlab/github_import/client_spec.rb b/spec/lib/gitlab/github_import/client_spec.rb
index 5f321a15de9..c409ec6983f 100644
--- a/spec/lib/gitlab/github_import/client_spec.rb
+++ b/spec/lib/gitlab/github_import/client_spec.rb
@@ -278,7 +278,7 @@ RSpec.describe Gitlab::GithubImport::Client, feature_category: :importers do
client.with_rate_limit do
if retries == 0
retries += 1
- raise(Octokit::TooManyRequests)
+ raise(Octokit::TooManyRequests.new(body: 'primary'))
end
end
@@ -306,6 +306,37 @@ RSpec.describe Gitlab::GithubImport::Client, feature_category: :importers do
expect(client.with_rate_limit { 10 }).to eq(10)
end
+ context 'when threshold is hit' do
+ it 'raises a RateLimitError with the appropriate message' do
+ expect(client).to receive(:requests_remaining?).and_return(false)
+
+ expect { client.with_rate_limit }
+ .to raise_error(Gitlab::GithubImport::RateLimitError, 'Internal threshold reached')
+ end
+ end
+
+ context 'when primary rate limit hit' do
+ let(:limited_block) { -> { raise(Octokit::TooManyRequests.new(body: 'primary')) } }
+
+ it 're-raises a RateLimitError with the appropriate message' do
+ expect(client).to receive(:requests_remaining?).and_return(true)
+
+ expect { client.with_rate_limit(&limited_block) }
+ .to raise_error(Gitlab::GithubImport::RateLimitError, 'primary')
+ end
+ end
+
+ context 'when secondary rate limit hit' do
+ let(:limited_block) { -> { raise(Octokit::TooManyRequests.new(body: 'secondary')) } }
+
+ it 're-raises a RateLimitError with the appropriate message' do
+ expect(client).to receive(:requests_remaining?).and_return(true)
+
+ expect { client.with_rate_limit(&limited_block) }
+ .to raise_error(Gitlab::GithubImport::RateLimitError, 'secondary')
+ end
+ end
+
context 'when Faraday error received from octokit', :aggregate_failures do
let(:error_class) { described_class::CLIENT_CONNECTION_ERROR }
let(:info_params) { { 'error.class': error_class } }
@@ -392,7 +423,7 @@ RSpec.describe Gitlab::GithubImport::Client, feature_category: :importers do
describe '#raise_or_wait_for_rate_limit' do
context 'when running in parallel mode' do
it 'raises RateLimitError' do
- expect { client.raise_or_wait_for_rate_limit }
+ expect { client.raise_or_wait_for_rate_limit('primary') }
.to raise_error(Gitlab::GithubImport::RateLimitError)
end
end
@@ -404,7 +435,7 @@ RSpec.describe Gitlab::GithubImport::Client, feature_category: :importers do
expect(client).to receive(:rate_limit_resets_in).and_return(1)
expect(client).to receive(:sleep).with(1)
- client.raise_or_wait_for_rate_limit
+ client.raise_or_wait_for_rate_limit('primary')
end
it 'increments the rate limit counter' do
@@ -420,7 +451,7 @@ RSpec.describe Gitlab::GithubImport::Client, feature_category: :importers do
.to receive(:increment)
.and_call_original
- client.raise_or_wait_for_rate_limit
+ client.raise_or_wait_for_rate_limit('primary')
end
end
end
diff --git a/spec/lib/gitlab/github_import/importer/collaborators_importer_spec.rb b/spec/lib/gitlab/github_import/importer/collaborators_importer_spec.rb
index dcb02f32a28..6f602531d23 100644
--- a/spec/lib/gitlab/github_import/importer/collaborators_importer_spec.rb
+++ b/spec/lib/gitlab/github_import/importer/collaborators_importer_spec.rb
@@ -82,7 +82,7 @@ RSpec.describe Gitlab::GithubImport::Importer::CollaboratorsImporter, feature_ca
it 'imports each collaborator in parallel' do
expect(Gitlab::GithubImport::ImportCollaboratorWorker).to receive(:perform_in)
- .with(1.second, project.id, an_instance_of(Hash), an_instance_of(String))
+ .with(1, project.id, an_instance_of(Hash), an_instance_of(String))
waiter = importer.parallel_import
diff --git a/spec/lib/gitlab/github_import/importer/diff_notes_importer_spec.rb b/spec/lib/gitlab/github_import/importer/diff_notes_importer_spec.rb
index 945b742b025..4e8066ecb69 100644
--- a/spec/lib/gitlab/github_import/importer/diff_notes_importer_spec.rb
+++ b/spec/lib/gitlab/github_import/importer/diff_notes_importer_spec.rb
@@ -98,7 +98,7 @@ RSpec.describe Gitlab::GithubImport::Importer::DiffNotesImporter, feature_catego
.and_yield(github_comment)
expect(Gitlab::GithubImport::ImportDiffNoteWorker).to receive(:perform_in)
- .with(1.second, project.id, an_instance_of(Hash), an_instance_of(String))
+ .with(1, project.id, an_instance_of(Hash), an_instance_of(String))
waiter = importer.parallel_import
diff --git a/spec/lib/gitlab/github_import/importer/issue_events_importer_spec.rb b/spec/lib/gitlab/github_import/importer/issue_events_importer_spec.rb
index 04b694dc0cb..9aba6a2b02c 100644
--- a/spec/lib/gitlab/github_import/importer/issue_events_importer_spec.rb
+++ b/spec/lib/gitlab/github_import/importer/issue_events_importer_spec.rb
@@ -78,7 +78,7 @@ RSpec.describe Gitlab::GithubImport::Importer::IssueEventsImporter, feature_cate
allow(importer).to receive(:each_object_to_import).and_yield(issue_event)
expect(Gitlab::GithubImport::ImportIssueEventWorker).to receive(:perform_in).with(
- 1.second, project.id, an_instance_of(Hash), an_instance_of(String)
+ 1, project.id, an_instance_of(Hash), an_instance_of(String)
)
waiter = importer.parallel_import
diff --git a/spec/lib/gitlab/github_import/importer/issues_importer_spec.rb b/spec/lib/gitlab/github_import/importer/issues_importer_spec.rb
index d6fd1a4739c..1bfdce04187 100644
--- a/spec/lib/gitlab/github_import/importer/issues_importer_spec.rb
+++ b/spec/lib/gitlab/github_import/importer/issues_importer_spec.rb
@@ -92,7 +92,7 @@ RSpec.describe Gitlab::GithubImport::Importer::IssuesImporter, feature_category:
expect(Gitlab::GithubImport::ImportIssueWorker)
.to receive(:perform_in)
- .with(1.second, project.id, an_instance_of(Hash), an_instance_of(String))
+ .with(1, project.id, an_instance_of(Hash), an_instance_of(String))
waiter = importer.parallel_import
diff --git a/spec/lib/gitlab/github_import/importer/lfs_objects_importer_spec.rb b/spec/lib/gitlab/github_import/importer/lfs_objects_importer_spec.rb
index fab9d26532d..3f5ee68d264 100644
--- a/spec/lib/gitlab/github_import/importer/lfs_objects_importer_spec.rb
+++ b/spec/lib/gitlab/github_import/importer/lfs_objects_importer_spec.rb
@@ -119,7 +119,7 @@ RSpec.describe Gitlab::GithubImport::Importer::LfsObjectsImporter, feature_categ
end
expect(Gitlab::GithubImport::ImportLfsObjectWorker).to receive(:perform_in)
- .with(1.second, project.id, an_instance_of(Hash), an_instance_of(String))
+ .with(1, project.id, an_instance_of(Hash), an_instance_of(String))
waiter = importer.parallel_import
diff --git a/spec/lib/gitlab/github_import/importer/note_importer_spec.rb b/spec/lib/gitlab/github_import/importer/note_importer_spec.rb
index 91311a8e90f..b5fe8c207c8 100644
--- a/spec/lib/gitlab/github_import/importer/note_importer_spec.rb
+++ b/spec/lib/gitlab/github_import/importer/note_importer_spec.rb
@@ -99,7 +99,7 @@ RSpec.describe Gitlab::GithubImport::Importer::NoteImporter, feature_category: :
end
context 'when the note have invalid chars' do
- let(:note_body) { %{There were an invalid char "\u0000" <= right here} }
+ let(:note_body) { %(There were an invalid char "\u0000" <= right here) }
it 'removes invalid chars' do
expect(importer.user_finder)
diff --git a/spec/lib/gitlab/github_import/importer/notes_importer_spec.rb b/spec/lib/gitlab/github_import/importer/notes_importer_spec.rb
index 841cc8178ea..8c93963f325 100644
--- a/spec/lib/gitlab/github_import/importer/notes_importer_spec.rb
+++ b/spec/lib/gitlab/github_import/importer/notes_importer_spec.rb
@@ -84,7 +84,7 @@ RSpec.describe Gitlab::GithubImport::Importer::NotesImporter, feature_category:
.and_yield(github_comment)
expect(Gitlab::GithubImport::ImportNoteWorker).to receive(:perform_in)
- .with(1.second, project.id, an_instance_of(Hash), an_instance_of(String))
+ .with(1, project.id, an_instance_of(Hash), an_instance_of(String))
waiter = importer.parallel_import
diff --git a/spec/lib/gitlab/github_import/importer/protected_branches_importer_spec.rb b/spec/lib/gitlab/github_import/importer/protected_branches_importer_spec.rb
index 6a8b14a2690..8e99585109b 100644
--- a/spec/lib/gitlab/github_import/importer/protected_branches_importer_spec.rb
+++ b/spec/lib/gitlab/github_import/importer/protected_branches_importer_spec.rb
@@ -144,7 +144,7 @@ RSpec.describe Gitlab::GithubImport::Importer::ProtectedBranchesImporter, featur
it 'imports each protected branch in parallel' do
expect(Gitlab::GithubImport::ImportProtectedBranchWorker)
.to receive(:perform_in)
- .with(1.second, project.id, an_instance_of(Hash), an_instance_of(String))
+ .with(1, project.id, an_instance_of(Hash), an_instance_of(String))
expect(Gitlab::GithubImport::ObjectCounter)
.to receive(:increment).with(project, :protected_branch, :fetched)
diff --git a/spec/lib/gitlab/github_import/importer/pull_requests/review_requests_importer_spec.rb b/spec/lib/gitlab/github_import/importer/pull_requests/review_requests_importer_spec.rb
index d0145ba1120..1977815e3a0 100644
--- a/spec/lib/gitlab/github_import/importer/pull_requests/review_requests_importer_spec.rb
+++ b/spec/lib/gitlab/github_import/importer/pull_requests/review_requests_importer_spec.rb
@@ -97,7 +97,7 @@ RSpec.describe Gitlab::GithubImport::Importer::PullRequests::ReviewRequestsImpor
{ id: 4, login: 'alice' },
{ id: 5, login: 'bob' }
]
- },
+ }.deep_stringify_keys,
instance_of(String)
],
[
@@ -108,7 +108,7 @@ RSpec.describe Gitlab::GithubImport::Importer::PullRequests::ReviewRequestsImpor
users: [
{ id: 4, login: 'alice' }
]
- },
+ }.deep_stringify_keys,
instance_of(String)
]
]
@@ -116,10 +116,10 @@ RSpec.describe Gitlab::GithubImport::Importer::PullRequests::ReviewRequestsImpor
it 'schedule import for each merge request reviewers' do
expect(Gitlab::GithubImport::PullRequests::ImportReviewRequestWorker)
- .to receive(:perform_in).with(1.second, *expected_worker_payload.first)
+ .to receive(:perform_in).with(1, *expected_worker_payload.first)
expect(Gitlab::GithubImport::PullRequests::ImportReviewRequestWorker)
- .to receive(:perform_in).with(1.second, *expected_worker_payload.second)
+ .to receive(:perform_in).with(1, *expected_worker_payload.second)
expect(Gitlab::GithubImport::ObjectCounter)
.to receive(:increment).twice.with(project, :pull_request_review_request, :fetched)
@@ -137,7 +137,7 @@ RSpec.describe Gitlab::GithubImport::Importer::PullRequests::ReviewRequestsImpor
it "doesn't schedule import this merge request reviewers" do
expect(Gitlab::GithubImport::PullRequests::ImportReviewRequestWorker)
- .to receive(:perform_in).with(1.second, *expected_worker_payload.second)
+ .to receive(:perform_in).with(1, *expected_worker_payload.second)
expect(Gitlab::GithubImport::ObjectCounter)
.to receive(:increment).once.with(project, :pull_request_review_request, :fetched)
diff --git a/spec/lib/gitlab/github_import/importer/pull_requests_importer_spec.rb b/spec/lib/gitlab/github_import/importer/pull_requests_importer_spec.rb
index cfd75fba849..10e413fdfe5 100644
--- a/spec/lib/gitlab/github_import/importer/pull_requests_importer_spec.rb
+++ b/spec/lib/gitlab/github_import/importer/pull_requests_importer_spec.rb
@@ -102,7 +102,7 @@ RSpec.describe Gitlab::GithubImport::Importer::PullRequestsImporter, feature_cat
expect(Gitlab::GithubImport::ImportPullRequestWorker)
.to receive(:perform_in)
- .with(1.second, project.id, an_instance_of(Hash), an_instance_of(String))
+ .with(1, project.id, an_instance_of(Hash), an_instance_of(String))
waiter = importer.parallel_import
diff --git a/spec/lib/gitlab/github_import/issuable_finder_spec.rb b/spec/lib/gitlab/github_import/issuable_finder_spec.rb
index d3236994cef..977fef95d64 100644
--- a/spec/lib/gitlab/github_import/issuable_finder_spec.rb
+++ b/spec/lib/gitlab/github_import/issuable_finder_spec.rb
@@ -2,40 +2,80 @@
require 'spec_helper'
-RSpec.describe Gitlab::GithubImport::IssuableFinder, :clean_gitlab_redis_cache do
- let(:project) { double(:project, id: 4, import_data: import_data) }
+RSpec.describe Gitlab::GithubImport::IssuableFinder, :clean_gitlab_redis_cache, feature_category: :importers do
+ let(:project) { build(:project, id: 20, import_data_attributes: import_data_attributes) }
let(:single_endpoint_optional_stage) { false }
- let(:import_data) do
- instance_double(
- ProjectImportData,
+ let(:import_data_attributes) do
+ {
data: {
optional_stages: {
single_endpoint_notes_import: single_endpoint_optional_stage
}
- }.deep_stringify_keys
- )
+ }
+ }
end
- let(:issue) { double(:issue, issuable_type: MergeRequest, issuable_id: 1) }
+ let(:merge_request) { create(:merge_request, source_project: project) }
+ let(:issue) { double(:issue, issuable_type: 'MergeRequest', issuable_id: merge_request.iid) }
let(:finder) { described_class.new(project, issue) }
describe '#database_id' do
- it 'returns nil when no cache is in place' do
- expect(finder.database_id).to be_nil
+ it 'returns nil if object does not exist' do
+ missing_issue = double(:issue, issuable_type: 'MergeRequest', issuable_id: 999)
+
+ expect(described_class.new(project, missing_issue).database_id).to be_nil
+ end
+
+ it 'fetches object id from database if not in cache' do
+ expect(finder.database_id).to eq(merge_request.id)
end
- it 'returns the ID of an issuable when the cache is in place' do
+ it 'fetches object id from cache if present' do
finder.cache_database_id(10)
expect(finder.database_id).to eq(10)
end
+ it 'returns nil and skips database read if cache has no record' do
+ finder.cache_database_id(-1)
+
+ expect(finder.database_id).to be_nil
+ end
+
it 'raises TypeError when the object is not supported' do
finder = described_class.new(project, double(:issue))
expect { finder.database_id }.to raise_error(TypeError)
end
+ context 'with FF import_fallback_to_db_empty_cache disabled' do
+ before do
+ stub_feature_flags(import_fallback_to_db_empty_cache: false)
+ end
+
+ it 'returns nil if object does not exist' do
+ missing_issue = double(:issue, issuable_type: 'MergeRequest', issuable_id: 999)
+
+ expect(described_class.new(project, missing_issue).database_id).to be_nil
+ end
+
+ it 'does not fetch object id from database if not in cache' do
+ expect(finder.database_id).to eq(nil)
+ end
+
+ it 'fetches object id from cache if present' do
+ finder.cache_database_id(10)
+
+ expect(finder.database_id).to eq(10)
+ end
+
+ it 'returns -1 if cache is -1' do
+ finder.cache_database_id(-1)
+
+ expect(finder.database_id).to eq(-1)
+ end
+ end
+
context 'when group is present' do
context 'when settings single_endpoint_notes_import is enabled' do
let(:single_endpoint_optional_stage) { true }
@@ -65,7 +105,7 @@ RSpec.describe Gitlab::GithubImport::IssuableFinder, :clean_gitlab_redis_cache d
it 'caches the ID of a database row' do
expect(Gitlab::Cache::Import::Caching)
.to receive(:write)
- .with('github-import/issuable-finder/4/MergeRequest/1', 10, timeout: 86400)
+ .with("github-import/issuable-finder/20/MergeRequest/#{merge_request.iid}", 10, timeout: 86400)
finder.cache_database_id(10)
end
diff --git a/spec/lib/gitlab/github_import/label_finder_spec.rb b/spec/lib/gitlab/github_import/label_finder_spec.rb
index 9905fce2a20..e46595974d1 100644
--- a/spec/lib/gitlab/github_import/label_finder_spec.rb
+++ b/spec/lib/gitlab/github_import/label_finder_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Gitlab::GithubImport::LabelFinder, :clean_gitlab_redis_cache do
+RSpec.describe Gitlab::GithubImport::LabelFinder, :clean_gitlab_redis_cache, feature_category: :importers do
let_it_be(:project) { create(:project) }
let_it_be(:finder) { described_class.new(project) }
let_it_be(:bug) { create(:label, project: project, name: 'Bug') }
@@ -18,23 +18,64 @@ RSpec.describe Gitlab::GithubImport::LabelFinder, :clean_gitlab_redis_cache do
expect(finder.id_for(feature.name)).to eq(feature.id)
end
- it 'returns nil for an empty cache key' do
+ it 'fetches object id from database if not in cache' do
key = finder.cache_key_for(bug.name)
Gitlab::Cache::Import::Caching.write(key, '')
- expect(finder.id_for(bug.name)).to be_nil
+ expect(finder.id_for(bug.name)).to eq(bug.id)
end
it 'returns nil for a non existing label name' do
expect(finder.id_for('kittens')).to be_nil
end
+
+ it 'returns nil and skips database read if cache has no record' do
+ key = finder.cache_key_for(bug.name)
+
+ Gitlab::Cache::Import::Caching.write(key, -1)
+
+ expect(finder.id_for(bug.name)).to be_nil
+ end
end
context 'without a cache in place' do
- it 'returns nil for a label' do
+ it 'caches the ID of a database row and returns the ID' do
+ expect(Gitlab::Cache::Import::Caching)
+ .to receive(:write)
+ .with("github-import/label-finder/#{project.id}/#{feature.name}", feature.id)
+ .and_call_original
+
+ expect(finder.id_for(feature.name)).to eq(feature.id)
+ end
+ end
+
+ context 'with FF import_fallback_to_db_empty_cache disabled' do
+ before do
+ stub_feature_flags(import_fallback_to_db_empty_cache: false)
+ end
+
+ it 'returns nil for a non existing label name' do
+ expect(finder.id_for('kittens')).to be_nil
+ end
+
+ it 'does not fetch object id from database if not in cache' do
expect(finder.id_for(feature.name)).to be_nil
end
+
+ it 'fetches object id from cache if present' do
+ finder.build_cache
+
+ expect(finder.id_for(feature.name)).to eq(feature.id)
+ end
+
+ it 'returns -1 if cache is -1' do
+ key = finder.cache_key_for(bug.name)
+
+ Gitlab::Cache::Import::Caching.write(key, -1)
+
+ expect(finder.id_for(bug.name)).to eq(-1)
+ end
end
end
diff --git a/spec/lib/gitlab/github_import/milestone_finder_spec.rb b/spec/lib/gitlab/github_import/milestone_finder_spec.rb
index e7f47d334e8..62886981de1 100644
--- a/spec/lib/gitlab/github_import/milestone_finder_spec.rb
+++ b/spec/lib/gitlab/github_import/milestone_finder_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Gitlab::GithubImport::MilestoneFinder, :clean_gitlab_redis_cache do
+RSpec.describe Gitlab::GithubImport::MilestoneFinder, :clean_gitlab_redis_cache, feature_category: :importers do
let_it_be(:project) { create(:project) }
let_it_be(:milestone) { create(:milestone, project: project) }
@@ -20,23 +20,72 @@ RSpec.describe Gitlab::GithubImport::MilestoneFinder, :clean_gitlab_redis_cache
expect(finder.id_for(issuable)).to eq(milestone.id)
end
- it 'returns nil for an empty cache key' do
+ it 'returns nil if object does not exist' do
+ missing_issuable = double(:issuable, milestone_number: 999)
+
+ expect(finder.id_for(missing_issuable)).to be_nil
+ end
+
+ it 'fetches object id from database if not in cache' do
key = finder.cache_key_for(milestone.iid)
Gitlab::Cache::Import::Caching.write(key, '')
- expect(finder.id_for(issuable)).to be_nil
+ expect(finder.id_for(issuable)).to eq(milestone.id)
end
it 'returns nil for an issuable with a non-existing milestone' do
expect(finder.id_for(double(:issuable, milestone_number: 5))).to be_nil
end
+
+ it 'returns nil and skips database read if cache has no record' do
+ key = finder.cache_key_for(milestone.iid)
+
+ Gitlab::Cache::Import::Caching.write(key, -1)
+
+ expect(finder.id_for(issuable)).to be_nil
+ end
end
context 'without a cache in place' do
- it 'returns nil' do
+ it 'caches the ID of a database row and returns the ID' do
+ expect(Gitlab::Cache::Import::Caching)
+ .to receive(:write)
+ .with("github-import/milestone-finder/#{project.id}/1", milestone.id)
+ .and_call_original
+
+ expect(finder.id_for(issuable)).to eq(milestone.id)
+ end
+ end
+
+ context 'with FF import_fallback_to_db_empty_cache disabled' do
+ before do
+ stub_feature_flags(import_fallback_to_db_empty_cache: false)
+ end
+
+ it 'returns nil if object does not exist' do
+ missing_issuable = double(:issuable, milestone_number: 999)
+
+ expect(finder.id_for(missing_issuable)).to be_nil
+ end
+
+ it 'does not fetch object id from database if not in cache' do
expect(finder.id_for(issuable)).to be_nil
end
+
+ it 'fetches object id from cache if present' do
+ finder.build_cache
+
+ expect(finder.id_for(issuable)).to eq(milestone.id)
+ end
+
+ it 'returns -1 if cache is -1' do
+ key = finder.cache_key_for(milestone.iid)
+
+ Gitlab::Cache::Import::Caching.write(key, -1)
+
+ expect(finder.id_for(issuable)).to eq(-1)
+ end
end
end
diff --git a/spec/lib/gitlab/github_import/object_counter_spec.rb b/spec/lib/gitlab/github_import/object_counter_spec.rb
index e41a2cff989..964bdd6aad1 100644
--- a/spec/lib/gitlab/github_import/object_counter_spec.rb
+++ b/spec/lib/gitlab/github_import/object_counter_spec.rb
@@ -68,6 +68,16 @@ RSpec.describe Gitlab::GithubImport::ObjectCounter, :clean_gitlab_redis_cache, f
'imported' => { 'issue' => 8 }
)
end
+
+ it 'uses the same TTL as when incrementing' do
+ expect(Gitlab::Cache::Import::Caching)
+ .to receive(:read_integer)
+ .with(anything, timeout: described_class::IMPORT_CACHING_TIMEOUT)
+ .twice
+ .and_call_original
+
+ described_class.summary(project)
+ end
end
context 'when import is in progress but cache expired' do
diff --git a/spec/lib/gitlab/github_import/parallel_scheduling_spec.rb b/spec/lib/gitlab/github_import/parallel_scheduling_spec.rb
index 9de39a3ff7e..e0b1ff1bc33 100644
--- a/spec/lib/gitlab/github_import/parallel_scheduling_spec.rb
+++ b/spec/lib/gitlab/github_import/parallel_scheduling_spec.rb
@@ -296,11 +296,11 @@ RSpec.describe Gitlab::GithubImport::ParallelScheduling, feature_category: :impo
expect(importer).to receive(:each_object_to_import)
.and_yield(object).and_yield(object).and_yield(object)
expect(worker_class).to receive(:perform_in)
- .with(1.second, project.id, { title: 'One' }, 'waiter-key').ordered
+ .with(1, project.id, { 'title' => 'One' }, 'waiter-key').ordered
expect(worker_class).to receive(:perform_in)
- .with(1.second, project.id, { title: 'Two' }, 'waiter-key').ordered
+ .with(1, project.id, { 'title' => 'Two' }, 'waiter-key').ordered
expect(worker_class).to receive(:perform_in)
- .with(1.minute + 1.second, project.id, { title: 'Three' }, 'waiter-key').ordered
+ .with(61, project.id, { 'title' => 'Three' }, 'waiter-key').ordered
job_waiter = importer.parallel_import
@@ -325,11 +325,11 @@ RSpec.describe Gitlab::GithubImport::ParallelScheduling, feature_category: :impo
expect(importer).to receive(:each_object_to_import).and_yield(object).and_yield(object).and_yield(object)
expect(worker_class).to receive(:perform_in)
- .with(1.second, project.id, { title: 'One' }, 'waiter-key').ordered
+ .with(1, project.id, { 'title' => 'One' }, 'waiter-key').ordered
expect(worker_class).to receive(:perform_in)
- .with(1.minute + 1.second, project.id, { title: 'Two' }, 'waiter-key').ordered
+ .with(61, project.id, { 'title' => 'Two' }, 'waiter-key').ordered
expect(worker_class).to receive(:perform_in)
- .with(2.minutes + 1.second, project.id, { title: 'Three' }, 'waiter-key').ordered
+ .with(121, project.id, { 'title' => 'Three' }, 'waiter-key').ordered
job_waiter = importer.parallel_import
diff --git a/spec/lib/gitlab/github_import/representation/to_hash_spec.rb b/spec/lib/gitlab/github_import/representation/to_hash_spec.rb
index 739c832025c..52edffe586d 100644
--- a/spec/lib/gitlab/github_import/representation/to_hash_spec.rb
+++ b/spec/lib/gitlab/github_import/representation/to_hash_spec.rb
@@ -2,14 +2,14 @@
require 'fast_spec_helper'
-RSpec.describe Gitlab::GithubImport::Representation::ToHash do
+RSpec.describe Gitlab::GithubImport::Representation::ToHash, feature_category: :importers do
describe '#to_hash' do
let(:user) { double(:user, attributes: { login: 'alice' }) }
let(:issue) do
double(
:issue,
- attributes: { user: user, assignees: [user], number: 42 }
+ attributes: { user: user, assignees: [user], number: 42, created_at: 5.days.ago, status: :valid }
)
end
@@ -35,5 +35,13 @@ RSpec.describe Gitlab::GithubImport::Representation::ToHash do
it 'keeps values as-is if they do not respond to #to_hash' do
expect(issue_hash[:number]).to eq(42)
end
+
+ it 'converts Date value to String' do
+ expect(issue_hash[:created_at]).to be_an_instance_of(String)
+ end
+
+ it 'converts Symbol value to String' do
+ expect(issue_hash[:status]).to be_an_instance_of(String)
+ end
end
end
diff --git a/spec/lib/gitlab/graphql/known_operations_spec.rb b/spec/lib/gitlab/graphql/known_operations_spec.rb
index c7bc47e1e6a..acb85bc737b 100644
--- a/spec/lib/gitlab/graphql/known_operations_spec.rb
+++ b/spec/lib/gitlab/graphql/known_operations_spec.rb
@@ -7,7 +7,7 @@ RSpec.describe Gitlab::Graphql::KnownOperations do
using RSpec::Parameterized::TableSyntax
# Include duplicated operation names to test that we are unique-ifying them
- let(:fake_operations) { %w(foo foo bar bar) }
+ let(:fake_operations) { %w[foo foo bar bar] }
let(:fake_schema) do
Class.new(GraphQL::Schema) do
query Graphql::FakeQueryType
@@ -34,7 +34,7 @@ RSpec.describe Gitlab::Graphql::KnownOperations do
describe "#operations" do
it "returns array of known operations" do
- expect(subject.operations.map(&:name)).to match_array(%w(unknown foo bar))
+ expect(subject.operations.map(&:name)).to match_array(%w[unknown foo bar])
end
end
diff --git a/spec/lib/gitlab/graphql/tracers/metrics_tracer_spec.rb b/spec/lib/gitlab/graphql/tracers/metrics_tracer_spec.rb
index f0312293469..f077cff6875 100644
--- a/spec/lib/gitlab/graphql/tracers/metrics_tracer_spec.rb
+++ b/spec/lib/gitlab/graphql/tracers/metrics_tracer_spec.rb
@@ -6,7 +6,7 @@ require 'rspec-parameterized'
RSpec.describe Gitlab::Graphql::Tracers::MetricsTracer do
using RSpec::Parameterized::TableSyntax
- let(:default_known_operations) { ::Gitlab::Graphql::KnownOperations.new(%w(lorem foo bar)) }
+ let(:default_known_operations) { ::Gitlab::Graphql::KnownOperations.new(%w[lorem foo bar]) }
let(:fake_schema) do
Class.new(GraphQL::Schema) do
diff --git a/spec/lib/gitlab/group_search_results_spec.rb b/spec/lib/gitlab/group_search_results_spec.rb
index 84a2a0549d5..8466e8a1bb5 100644
--- a/spec/lib/gitlab/group_search_results_spec.rb
+++ b/spec/lib/gitlab/group_search_results_spec.rb
@@ -48,7 +48,7 @@ RSpec.describe Gitlab::GroupSearchResults, feature_category: :global_search do
end
include_examples 'search results filtered by state'
- include_examples 'search results filtered by archived', 'search_merge_requests_hide_archived_projects'
+ include_examples 'search results filtered by archived'
end
describe 'milestones search' do
diff --git a/spec/lib/gitlab/hashed_path_spec.rb b/spec/lib/gitlab/hashed_path_spec.rb
index 051c5196748..cf31e891957 100644
--- a/spec/lib/gitlab/hashed_path_spec.rb
+++ b/spec/lib/gitlab/hashed_path_spec.rb
@@ -18,7 +18,7 @@ RSpec.describe Gitlab::HashedPath do
end
context 'when path contains multiple values' do
- let(:path) { %w(path1 path2) }
+ let(:path) { %w[path1 path2] }
it 'returns the disk path' do
expect(subject).to match(%r[\h{2}/\h{2}/\h{64}/path1/path2])
diff --git a/spec/lib/gitlab/health_checks/gitaly_check_spec.rb b/spec/lib/gitlab/health_checks/gitaly_check_spec.rb
index 64c4e92f80b..8f676d20c22 100644
--- a/spec/lib/gitlab/health_checks/gitaly_check_spec.rb
+++ b/spec/lib/gitlab/health_checks/gitaly_check_spec.rb
@@ -4,11 +4,6 @@ require 'fast_spec_helper'
RSpec.describe Gitlab::HealthChecks::GitalyCheck do
let(:result_class) { Gitlab::HealthChecks::Result }
- let(:repository_storages) { ['default'] }
-
- before do
- allow(described_class).to receive(:repository_storages) { repository_storages }
- end
describe '#readiness' do
subject { described_class.readiness }
diff --git a/spec/lib/gitlab/highlight_spec.rb b/spec/lib/gitlab/highlight_spec.rb
index 173131b1d5c..ef3765e479f 100644
--- a/spec/lib/gitlab/highlight_spec.rb
+++ b/spec/lib/gitlab/highlight_spec.rb
@@ -43,7 +43,7 @@ RSpec.describe Gitlab::Highlight do
it 'returns plain version for unknown lexer context' do
result = described_class.highlight(plain_text_file_name, plain_text_content)
- expect(result).to eq(%[<span id="LC1" class="line" lang="plaintext">plain text contents</span>])
+ expect(result).to eq(%(<span id="LC1" class="line" lang="plaintext">plain text contents</span>))
end
context 'when content is too long to be highlighted' do
diff --git a/spec/lib/gitlab/i18n/translation_entry_spec.rb b/spec/lib/gitlab/i18n/translation_entry_spec.rb
index df503e68cf1..3531314cf9c 100644
--- a/spec/lib/gitlab/i18n/translation_entry_spec.rb
+++ b/spec/lib/gitlab/i18n/translation_entry_spec.rb
@@ -108,7 +108,7 @@ RSpec.describe Gitlab::I18n::TranslationEntry do
describe '#msgid_contains_newlines' do
it 'is true when the msgid is an array' do
- data = { msgid: %w(hello world) }
+ data = { msgid: %w[hello world] }
entry = described_class.new(entry_data: data, nplurals: 2)
expect(entry.msgid_has_multiple_lines?).to be_truthy
@@ -117,7 +117,7 @@ RSpec.describe Gitlab::I18n::TranslationEntry do
describe '#plural_id_contains_newlines' do
it 'is true when the msgid is an array' do
- data = { msgid_plural: %w(hello world) }
+ data = { msgid_plural: %w[hello world] }
entry = described_class.new(entry_data: data, nplurals: 2)
expect(entry.plural_id_has_multiple_lines?).to be_truthy
@@ -126,7 +126,7 @@ RSpec.describe Gitlab::I18n::TranslationEntry do
describe '#translations_contain_newlines' do
it 'is true when the msgid is an array' do
- data = { msgstr: %w(hello world) }
+ data = { msgstr: %w[hello world] }
entry = described_class.new(entry_data: data, nplurals: 2)
expect(entry.translations_have_multiple_lines?).to be_truthy
diff --git a/spec/lib/gitlab/import/import_failure_service_spec.rb b/spec/lib/gitlab/import/import_failure_service_spec.rb
index a4682a9495e..362d809bb56 100644
--- a/spec/lib/gitlab/import/import_failure_service_spec.rb
+++ b/spec/lib/gitlab/import/import_failure_service_spec.rb
@@ -10,7 +10,7 @@ RSpec.describe Gitlab::Import::ImportFailureService, :aggregate_failures, featur
let(:import_state) { nil }
let(:fail_import) { false }
let(:metrics) { false }
- let(:external_identifiers) { {} }
+ let(:external_identifiers) { { foo: 'bar' } }
let(:project_id) { project.id }
let(:arguments) do
@@ -90,13 +90,19 @@ RSpec.describe Gitlab::Import::ImportFailureService, :aggregate_failures, featur
)
service.execute
-
- expect(project.import_state.reload.status).to eq('failed')
-
- expect(project.import_failures).not_to be_empty
- expect(project.import_failures.last.exception_class).to eq('StandardError')
- expect(project.import_failures.last.exception_message).to eq('some error')
- expect(project.import_failures.last.retry_count).to eq(0)
+ project.reload
+
+ expect(project.import_state.status).to eq('failed')
+ expect(project.import_failures).to contain_exactly(
+ have_attributes(
+ retry_count: 0,
+ exception_class: 'StandardError',
+ exception_message: 'some error',
+ external_identifiers: external_identifiers.with_indifferent_access,
+ correlation_id_value: Labkit::Correlation::CorrelationId.current_or_new_id,
+ source: 'SomeImporter'
+ )
+ )
end
end
@@ -128,13 +134,19 @@ RSpec.describe Gitlab::Import::ImportFailureService, :aggregate_failures, featur
)
service.execute
+ project.reload
expect(project.import_state.reload.status).to eq('started')
-
- expect(project.import_failures).not_to be_empty
- expect(project.import_failures.last.exception_class).to eq('StandardError')
- expect(project.import_failures.last.exception_message).to eq('some error')
- expect(project.import_failures.last.retry_count).to eq(nil)
+ expect(project.import_failures).to contain_exactly(
+ have_attributes(
+ retry_count: nil,
+ exception_class: 'StandardError',
+ exception_message: 'some error',
+ external_identifiers: external_identifiers.with_indifferent_access,
+ correlation_id_value: Labkit::Correlation::CorrelationId.current_or_new_id,
+ source: 'SomeImporter'
+ )
+ )
end
end
diff --git a/spec/lib/gitlab/import_export/after_export_strategies/base_after_export_strategy_spec.rb b/spec/lib/gitlab/import_export/after_export_strategies/base_after_export_strategy_spec.rb
index fc794f11499..2046e1b5ae5 100644
--- a/spec/lib/gitlab/import_export/after_export_strategies/base_after_export_strategy_spec.rb
+++ b/spec/lib/gitlab/import_export/after_export_strategies/base_after_export_strategy_spec.rb
@@ -100,7 +100,7 @@ RSpec.describe Gitlab::ImportExport::AfterExportStrategies::BaseAfterExportStrat
describe '#log_validation_errors' do
it 'add the message to the shared context' do
- errors = %w(test_message test_message2)
+ errors = %w[test_message test_message2]
allow(service).to receive(:invalid?).and_return(true)
allow(service.errors).to receive(:full_messages).and_return(errors)
diff --git a/spec/lib/gitlab/import_export/after_export_strategies/web_upload_strategy_spec.rb b/spec/lib/gitlab/import_export/after_export_strategies/web_upload_strategy_spec.rb
index 297fe3ade07..0f9cbe8aea3 100644
--- a/spec/lib/gitlab/import_export/after_export_strategies/web_upload_strategy_spec.rb
+++ b/spec/lib/gitlab/import_export/after_export_strategies/web_upload_strategy_spec.rb
@@ -27,7 +27,7 @@ RSpec.describe Gitlab::ImportExport::AfterExportStrategies::WebUploadStrategy do
describe 'validations' do
it 'only POST and PUT method allowed' do
- %w(POST post PUT put).each do |method|
+ %w[POST post PUT put].each do |method|
expect(subject.new(url: example_url, http_method: method)).to be_valid
end
diff --git a/spec/lib/gitlab/import_export/all_models.yml b/spec/lib/gitlab/import_export/all_models.yml
index cd899a79451..722b47ac9b8 100644
--- a/spec/lib/gitlab/import_export/all_models.yml
+++ b/spec/lib/gitlab/import_export/all_models.yml
@@ -660,6 +660,7 @@ project:
- pages_domains
- pages_metadatum
- pages_deployments
+- active_pages_deployments
- authorized_users
- project_authorizations
- remote_mirrors
@@ -1061,6 +1062,7 @@ approval_rules:
- users
- groups
- group_users
+ - group_members
- security_orchestration_policy_configuration
- protected_branches
- approval_merge_request_rule_sources
diff --git a/spec/lib/gitlab/import_export/attribute_cleaner_spec.rb b/spec/lib/gitlab/import_export/attribute_cleaner_spec.rb
index 272c2629b08..9d69e1fec05 100644
--- a/spec/lib/gitlab/import_export/attribute_cleaner_spec.rb
+++ b/spec/lib/gitlab/import_export/attribute_cleaner_spec.rb
@@ -34,7 +34,7 @@ RSpec.describe Gitlab::ImportExport::AttributeCleaner do
'note_ids' => [1, 2, 3],
'remote_attachment_url' => 'http://something.dodgy',
'remote_attachment_request_header' => 'bad value',
- 'remote_attachment_urls' => %w(http://something.dodgy http://something.okay),
+ 'remote_attachment_urls' => %w[http://something.dodgy http://something.okay],
'attributes' => {
'issue_ids' => [1, 2, 3],
'merge_request_ids' => [1, 2, 3],
diff --git a/spec/lib/gitlab/import_export/attributes_permitter_spec.rb b/spec/lib/gitlab/import_export/attributes_permitter_spec.rb
index 08abd7908d2..996b32ed341 100644
--- a/spec/lib/gitlab/import_export/attributes_permitter_spec.rb
+++ b/spec/lib/gitlab/import_export/attributes_permitter_spec.rb
@@ -33,7 +33,7 @@ RSpec.describe Gitlab::ImportExport::AttributesPermitter, feature_category: :imp
EOF
end
- let(:file) { Tempfile.new(%w(import_export .yml)) }
+ let(:file) { Tempfile.new(%w[import_export .yml]) }
let(:config_hash) { Gitlab::ImportExport::Config.new(config: file.path).to_h }
before do
diff --git a/spec/lib/gitlab/import_export/command_line_util_spec.rb b/spec/lib/gitlab/import_export/command_line_util_spec.rb
index 42c3b170e4d..ab47de8f874 100644
--- a/spec/lib/gitlab/import_export/command_line_util_spec.rb
+++ b/spec/lib/gitlab/import_export/command_line_util_spec.rb
@@ -263,7 +263,11 @@ RSpec.describe Gitlab::ImportExport::CommandLineUtil, feature_category: :importe
context 'when exception occurs' do
it 'raises an exception' do
- expect { subject.gzip(dir: path, filename: 'test') }.to raise_error(Gitlab::ImportExport::Error)
+ expect { subject.gzip(dir: path, filename: 'test') }
+ .to raise_error(
+ Gitlab::ImportExport::Error,
+ %r{File compression or decompression failed. Command exited with error code 1: gzip}
+ )
end
end
end
@@ -283,7 +287,11 @@ RSpec.describe Gitlab::ImportExport::CommandLineUtil, feature_category: :importe
context 'when exception occurs' do
it 'raises an exception' do
- expect { subject.gunzip(dir: path, filename: 'test') }.to raise_error(Gitlab::ImportExport::Error)
+ expect { subject.gunzip(dir: path, filename: 'test') }
+ .to raise_error(
+ Gitlab::ImportExport::Error,
+ %r{File compression or decompression failed. Command exited with error code 1: gzip}
+ )
end
end
end
@@ -306,7 +314,7 @@ RSpec.describe Gitlab::ImportExport::CommandLineUtil, feature_category: :importe
include Gitlab::ImportExport::CommandLineUtil
end.new
- expect { klass.tar_cf(archive: 'test', dir: 'test') }.to raise_error(Gitlab::ImportExport::Error, 'command exited with error code 1: Error')
+ expect { klass.tar_cf(archive: 'test', dir: 'test') }.to raise_error(Gitlab::ImportExport::Error, 'Command exited with error code 1: Error')
end
end
end
@@ -363,7 +371,7 @@ RSpec.describe Gitlab::ImportExport::CommandLineUtil, feature_category: :importe
include Gitlab::ImportExport::CommandLineUtil
end.new
- expect { klass.untar_xf(archive: 'test', dir: 'test') }.to raise_error(Gitlab::ImportExport::Error, 'command exited with error code 1: Error')
+ expect { klass.untar_xf(archive: 'test', dir: 'test') }.to raise_error(Gitlab::ImportExport::Error, 'Command exited with error code 1: Error')
end
it 'returns false and includes error status' do
@@ -378,7 +386,7 @@ RSpec.describe Gitlab::ImportExport::CommandLineUtil, feature_category: :importe
end.new
expect(klass.tar_czf(archive: 'test', dir: 'test')).to eq(false)
- expect(klass.shared.errors).to eq(['command exited with error code 1: Error'])
+ expect(klass.shared.errors).to eq(['Command exited with error code 1: Error'])
end
end
end
diff --git a/spec/lib/gitlab/import_export/error_spec.rb b/spec/lib/gitlab/import_export/error_spec.rb
index 015133a399b..db16d0f1e45 100644
--- a/spec/lib/gitlab/import_export/error_spec.rb
+++ b/spec/lib/gitlab/import_export/error_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Gitlab::ImportExport::Error do
+RSpec.describe Gitlab::ImportExport::Error, feature_category: :importers do
describe '.permission_error' do
subject(:error) do
described_class.permission_error(user, importable)
@@ -28,4 +28,12 @@ RSpec.describe Gitlab::ImportExport::Error do
end
end
end
+
+ describe '.file_compression_error' do
+ it 'adds error to exception message' do
+ message = described_class.file_compression_error('Error').message
+
+ expect(message).to eq('File compression or decompression failed. Error')
+ end
+ end
end
diff --git a/spec/lib/gitlab/import_export/fast_hash_serializer_spec.rb b/spec/lib/gitlab/import_export/fast_hash_serializer_spec.rb
index dfc7202194d..f6ad3e47c30 100644
--- a/spec/lib/gitlab/import_export/fast_hash_serializer_spec.rb
+++ b/spec/lib/gitlab/import_export/fast_hash_serializer_spec.rb
@@ -156,7 +156,7 @@ RSpec.describe Gitlab::ImportExport::FastHashSerializer, :with_license, feature_
it 'has project and group labels' do
label_types = subject['issues'].first['label_links'].map { |link| link['label']['type'] }
- expect(label_types).to match_array(%w(ProjectLabel GroupLabel))
+ expect(label_types).to match_array(%w[ProjectLabel GroupLabel])
end
it 'has priorities associated to labels' do
diff --git a/spec/lib/gitlab/import_export/json/ndjson_writer_spec.rb b/spec/lib/gitlab/import_export/json/ndjson_writer_spec.rb
index 486d179ae05..a7aeb9e8c3b 100644
--- a/spec/lib/gitlab/import_export/json/ndjson_writer_spec.rb
+++ b/spec/lib/gitlab/import_export/json/ndjson_writer_spec.rb
@@ -54,7 +54,7 @@ RSpec.describe Gitlab::ImportExport::Json::NdjsonWriter, feature_category: :impo
describe "#write_relation_array" do
it "writes json in correct files" do
values = [{ "key" => "value_1", "key_1" => "value_1" }, { "key" => "value_2", "key_1" => "value_2" }]
- relations = %w(relation1 relation2)
+ relations = %w[relation1 relation2]
relations.each do |relation|
subject.write_relation_array(exportable_path, relation, values.to_enum)
end
diff --git a/spec/lib/gitlab/import_export/lfs_restorer_spec.rb b/spec/lib/gitlab/import_export/lfs_restorer_spec.rb
index fe064c50b9e..042a49f9419 100644
--- a/spec/lib/gitlab/import_export/lfs_restorer_spec.rb
+++ b/spec/lib/gitlab/import_export/lfs_restorer_spec.rb
@@ -27,7 +27,7 @@ RSpec.describe Gitlab::ImportExport::LfsRestorer do
# Use the LfsSaver to save data to be restored
def save_lfs_data
- %w(project wiki).each do |repository_type|
+ %w[project wiki].each do |repository_type|
create(
:lfs_objects_project,
project: project,
diff --git a/spec/lib/gitlab/import_export/lfs_saver_spec.rb b/spec/lib/gitlab/import_export/lfs_saver_spec.rb
index 5b6f50025ff..bd225265ef0 100644
--- a/spec/lib/gitlab/import_export/lfs_saver_spec.rb
+++ b/spec/lib/gitlab/import_export/lfs_saver_spec.rb
@@ -60,7 +60,7 @@ RSpec.describe Gitlab::ImportExport::LfsSaver do
describe 'saving a json file' do
before do
# Create two more LfsObjectProject records with different `repository_type`s
- %w(wiki design).each do |repository_type|
+ %w[wiki design].each do |repository_type|
create(
:lfs_objects_project,
project: project,
diff --git a/spec/lib/gitlab/import_export/project/tree_saver_spec.rb b/spec/lib/gitlab/import_export/project/tree_saver_spec.rb
index 1bf1e5b47e1..2e82351db10 100644
--- a/spec/lib/gitlab/import_export/project/tree_saver_spec.rb
+++ b/spec/lib/gitlab/import_export/project/tree_saver_spec.rb
@@ -190,7 +190,7 @@ RSpec.describe Gitlab::ImportExport::Project::TreeSaver, :with_license, feature_
it 'has project and group labels' do
label_types = subject.first['label_links'].map { |link| link['label']['type'] }
- expect(label_types).to match_array(%w(ProjectLabel GroupLabel))
+ expect(label_types).to match_array(%w[ProjectLabel GroupLabel])
end
it 'has priorities associated to labels' do
diff --git a/spec/lib/gitlab/import_export/saver_spec.rb b/spec/lib/gitlab/import_export/saver_spec.rb
index a34e68ecd19..ba38a5d7960 100644
--- a/spec/lib/gitlab/import_export/saver_spec.rb
+++ b/spec/lib/gitlab/import_export/saver_spec.rb
@@ -33,7 +33,7 @@ RSpec.describe Gitlab::ImportExport::Saver do
subject.save # rubocop:disable Rails/SaveBang
expect(ImportExportUpload.find_by(project: project).export_file.url)
- .to match(%r[/uploads/-/system/import_export_upload/export_file.*])
+ .to match(%r{/uploads/-/system/import_export_upload/export_file.*})
end
it 'logs metrics after saving' do
diff --git a/spec/lib/gitlab/import_export/snippet_repo_restorer_spec.rb b/spec/lib/gitlab/import_export/snippet_repo_restorer_spec.rb
index d7b1b180e2e..97e3caba9b3 100644
--- a/spec/lib/gitlab/import_export/snippet_repo_restorer_spec.rb
+++ b/spec/lib/gitlab/import_export/snippet_repo_restorer_spec.rb
@@ -31,7 +31,7 @@ RSpec.describe Gitlab::ImportExport::SnippetRepoRestorer do
expect(restorer.restore).to be_truthy
end.to change { SnippetRepository.count }.by(1)
- snippet.repository.expire_method_caches(%i(exists?))
+ snippet.repository.expire_method_caches(%i[exists?])
expect(snippet.repository_exists?).to be_truthy
blob = snippet.repository.blob_at(snippet.default_branch, snippet.file_name)
diff --git a/spec/lib/gitlab/import_sources_spec.rb b/spec/lib/gitlab/import_sources_spec.rb
index db23e3b1fd4..19f17c9079d 100644
--- a/spec/lib/gitlab/import_sources_spec.rb
+++ b/spec/lib/gitlab/import_sources_spec.rb
@@ -24,7 +24,7 @@ RSpec.describe Gitlab::ImportSources, feature_category: :importers do
describe '.values' do
it 'returns an array' do
expected =
- %w(
+ %w[
github
bitbucket
bitbucket_server
@@ -33,7 +33,7 @@ RSpec.describe Gitlab::ImportSources, feature_category: :importers do
gitlab_project
gitea
manifest
- )
+ ]
expect(described_class.values).to eq(expected)
end
@@ -42,14 +42,14 @@ RSpec.describe Gitlab::ImportSources, feature_category: :importers do
describe '.importer_names' do
it 'returns an array of importer names' do
expected =
- %w(
+ %w[
github
bitbucket
bitbucket_server
fogbugz
gitlab_project
gitea
- )
+ ]
expect(described_class.importer_names).to eq(expected)
end
diff --git a/spec/lib/gitlab/instrumentation/redis_cluster_validator_spec.rb b/spec/lib/gitlab/instrumentation/redis_cluster_validator_spec.rb
index ddb5245f825..ea5a32a25ff 100644
--- a/spec/lib/gitlab/instrumentation/redis_cluster_validator_spec.rb
+++ b/spec/lib/gitlab/instrumentation/redis_cluster_validator_spec.rb
@@ -11,25 +11,25 @@ RSpec.describe Gitlab::Instrumentation::RedisClusterValidator, feature_category:
using RSpec::Parameterized::TableSyntax
where(:command, :arguments, :keys, :is_valid) do
- :rename | %w(foo bar) | 2 | false
- :RENAME | %w(foo bar) | 2 | false
- 'rename' | %w(foo bar) | 2 | false
- 'RENAME' | %w(foo bar) | 2 | false
- :rename | %w(iaa ahy) | 2 | true # 'iaa' and 'ahy' hash to the same slot
- :rename | %w({foo}:1 {foo}:2) | 2 | true
- :rename | %w(foo foo bar) | 2 | true # This is not a valid command but should not raise here
- :mget | %w(foo bar) | 2 | false
- :mget | %w(foo foo bar) | 3 | false
- :mget | %w(foo foo) | 2 | true
- :blpop | %w(foo bar 1) | 2 | false
- :blpop | %w(foo foo 1) | 2 | true
- :mset | %w(foo a bar a) | 2 | false
- :mset | %w(foo a foo a) | 2 | true
- :del | %w(foo bar) | 2 | false
- :del | [%w(foo bar)] | 2 | false # Arguments can be a nested array
- :del | %w(foo foo) | 2 | true
- :hset | %w(foo bar) | 1 | nil # Single key write
- :get | %w(foo) | 1 | nil # Single key read
+ :rename | %w[foo bar] | 2 | false
+ :RENAME | %w[foo bar] | 2 | false
+ 'rename' | %w[foo bar] | 2 | false
+ 'RENAME' | %w[foo bar] | 2 | false
+ :rename | %w[iaa ahy] | 2 | true # 'iaa' and 'ahy' hash to the same slot
+ :rename | %w[{foo}:1 {foo}:2] | 2 | true
+ :rename | %w[foo foo bar] | 2 | true # This is not a valid command but should not raise here
+ :mget | %w[foo bar] | 2 | false
+ :mget | %w[foo foo bar] | 3 | false
+ :mget | %w[foo foo] | 2 | true
+ :blpop | %w[foo bar 1] | 2 | false
+ :blpop | %w[foo foo 1] | 2 | true
+ :mset | %w[foo a bar a] | 2 | false
+ :mset | %w[foo a foo a] | 2 | true
+ :del | %w[foo bar] | 2 | false
+ :del | [%w[foo bar]] | 2 | false # Arguments can be a nested array
+ :del | %w[foo foo] | 2 | true
+ :hset | %w[foo bar] | 1 | nil # Single key write
+ :get | %w[foo] | 1 | nil # Single key read
:mget | [] | 0 | true # This is invalid, but not because it's a cross-slot command
end
diff --git a/spec/lib/gitlab/instrumentation_helper_spec.rb b/spec/lib/gitlab/instrumentation_helper_spec.rb
index 698c8a37d48..f8a4d8023c1 100644
--- a/spec/lib/gitlab/instrumentation_helper_spec.rb
+++ b/spec/lib/gitlab/instrumentation_helper_spec.rb
@@ -7,6 +7,7 @@ require 'support/helpers/rails_helpers'
RSpec.describe Gitlab::InstrumentationHelper, :clean_gitlab_redis_repository_cache, :clean_gitlab_redis_cache,
:use_null_store_as_repository_cache, feature_category: :scalability do
using RSpec::Parameterized::TableSyntax
+ include RedisHelpers
describe '.add_instrumentation_data', :request_store do
let(:payload) { {} }
@@ -39,11 +40,23 @@ RSpec.describe Gitlab::InstrumentationHelper, :clean_gitlab_redis_repository_cac
end
context 'when Redis calls are made' do
- it 'adds Redis data and omits Gitaly data' do
- stub_rails_env('staging') # to avoid raising CrossSlotError
- Gitlab::Redis::Sessions.with { |redis| redis.mset('test-cache', 123, 'test-cache2', 123) }
+ let_it_be(:redis_store_class) { define_helper_redis_store_class }
+
+ before do
+ redis_store_class.with(&:ping)
+ Gitlab::Redis::Queues.with(&:ping)
+ RequestStore.clear!
+ end
+
+ it 'adds Redis data including cross slot calls' do
+ expect(Gitlab::Instrumentation::RedisBase)
+ .to receive(:raise_cross_slot_validation_errors?)
+ .once.and_return(false)
+
+ redis_store_class.with { |redis| redis.mset('test-cache', 123, 'test-cache2', 123) }
+
Gitlab::Instrumentation::RedisClusterValidator.allow_cross_slot_commands do
- Gitlab::Redis::Sessions.with { |redis| redis.mget('cache-test', 'cache-test-2') }
+ redis_store_class.with { |redis| redis.mget('cache-test', 'cache-test-2') }
end
Gitlab::Redis::Queues.with { |redis| redis.set('test-queues', 321) }
@@ -249,15 +262,12 @@ RSpec.describe Gitlab::InstrumentationHelper, :clean_gitlab_redis_repository_cac
end
end
- describe 'duration calculations' do
- where(:end_time, :start_time, :time_now, :expected_duration) do
+ describe '.queue_duration_for_job' do
+ where(:enqueued_at, :created_at, :time_now, :expected_duration) do
"2019-06-01T00:00:00.000+0000" | nil | "2019-06-01T02:00:00.000+0000" | 2.hours.to_f
- "2019-06-01T02:00:00.000+0000" | nil | "2019-06-01T02:00:00.001+0000" | 0.001
"2019-06-01T02:00:00.000+0000" | "2019-05-01T02:00:00.000+0000" | "2019-06-01T02:00:01.000+0000" | 1
- nil | "2019-06-01T02:00:00.000+0000" | "2019-06-01T02:00:00.001+0000" | 0.001
nil | nil | "2019-06-01T02:00:00.001+0000" | nil
"2019-06-01T02:00:00.000+0200" | nil | "2019-06-01T02:00:00.000-0200" | 4.hours.to_f
- 1571825569.998168 | nil | "2019-10-23T12:13:16.000+0200" | 26.001832
1571825569 | nil | "2019-10-23T12:13:16.000+0200" | 27
"invalid_date" | nil | "2019-10-23T12:13:16.000+0200" | nil
"" | nil | "2019-10-23T12:13:16.000+0200" | nil
@@ -267,27 +277,30 @@ RSpec.describe Gitlab::InstrumentationHelper, :clean_gitlab_redis_repository_cac
Time.at(1571999233).utc | nil | "2019-10-25T12:29:16.000+0200" | 123
end
- describe '.queue_duration_for_job' do
- with_them do
- let(:job) { { 'enqueued_at' => end_time, 'created_at' => start_time } }
+ with_them do
+ let(:job) { { 'enqueued_at' => enqueued_at, 'created_at' => created_at } }
- it "returns the correct duration" do
- travel_to(Time.iso8601(time_now)) do
- expect(described_class.queue_duration_for_job(job)).to eq(expected_duration)
- end
+ it "returns the correct duration" do
+ travel_to(Time.iso8601(time_now)) do
+ expect(described_class.queue_duration_for_job(job)).to eq(expected_duration)
end
end
end
+ end
- describe '.enqueue_latency_for_scheduled_job' do
- with_them do
- let(:job) { { 'enqueued_at' => end_time, 'scheduled_at' => start_time } }
+ describe '.enqueue_latency_for_scheduled_job' do
+ where(:scheduled_at, :enqueued_at, :expected_duration) do
+ "2019-06-01T02:00:00.000+0000" | "2019-06-01T02:00:00.001+0000" | 0.001
+ "2019-06-01T02:00:00.000+0000" | "2019-06-01T02:00:01.000+0000" | 1
+ "2019-06-01T02:00:00.000+0000" | nil | nil
+ nil | "2019-06-01T02:00:01.000+0000" | nil
+ end
- it "returns the correct duration" do
- travel_to(Time.iso8601(time_now)) do
- expect(described_class.enqueue_latency_for_scheduled_job(job)).to eq(expected_duration)
- end
- end
+ with_them do
+ let(:job) { { 'enqueued_at' => enqueued_at, 'scheduled_at' => scheduled_at } }
+
+ it "returns the correct duration" do
+ expect(described_class.enqueue_latency_for_scheduled_job(job)).to eq(expected_duration)
end
end
end
diff --git a/spec/lib/gitlab/issues/rebalancing/state_spec.rb b/spec/lib/gitlab/issues/rebalancing/state_spec.rb
index 5adf1328b87..a0ea5fec8ec 100644
--- a/spec/lib/gitlab/issues/rebalancing/state_spec.rb
+++ b/spec/lib/gitlab/issues/rebalancing/state_spec.rb
@@ -67,11 +67,11 @@ RSpec.describe Gitlab::Issues::Rebalancing::State, :clean_gitlab_redis_shared_st
end
it 'returns array of issue ids' do
- expect(rebalance_caching.get_cached_issue_ids(0, 100)).to eq(%w(1 2 3))
+ expect(rebalance_caching.get_cached_issue_ids(0, 100)).to eq(%w[1 2 3])
end
it 'limits returned values' do
- expect(rebalance_caching.get_cached_issue_ids(0, 2)).to eq(%w(1 2))
+ expect(rebalance_caching.get_cached_issue_ids(0, 2)).to eq(%w[1 2])
end
context 'when caching duplicate issue_ids' do
@@ -84,7 +84,7 @@ RSpec.describe Gitlab::Issues::Rebalancing::State, :clean_gitlab_redis_shared_st
end
it 'returns cached issues with latest scores' do
- expect(rebalance_caching.get_cached_issue_ids(0, 100)).to eq(%w(3 2 1))
+ expect(rebalance_caching.get_cached_issue_ids(0, 100)).to eq(%w[3 2 1])
end
end
end
@@ -231,8 +231,16 @@ RSpec.describe Gitlab::Issues::Rebalancing::State, :clean_gitlab_redis_shared_st
def check_existing_keys
index = 0
- # spec only, we do not actually scan keys in the code
- recently_finished_keys_count = Gitlab::Redis::SharedState.with { |redis| redis.scan(0, match: "#{described_class::RECENTLY_FINISHED_REBALANCE_PREFIX}:*") }.last.count
+ cursor = '0'
+ recently_finished_keys_count = 0
+
+ # loop to scan since it may run against a Redis Cluster
+ loop do
+ # spec only, we do not actually scan keys in the code
+ cursor, items = Gitlab::Redis::SharedState.with { |redis| redis.scan(cursor, match: "#{described_class::RECENTLY_FINISHED_REBALANCE_PREFIX}:*") }
+ recently_finished_keys_count += items.count
+ break if cursor == '0'
+ end
index += 1 if rebalance_caching.get_current_index > 0
index += 1 if rebalance_caching.get_current_project_id.present?
diff --git a/spec/lib/gitlab/jira/middleware_spec.rb b/spec/lib/gitlab/jira/middleware_spec.rb
deleted file mode 100644
index 09cf67d0657..00000000000
--- a/spec/lib/gitlab/jira/middleware_spec.rb
+++ /dev/null
@@ -1,40 +0,0 @@
-# frozen_string_literal: true
-
-require 'fast_spec_helper'
-
-RSpec.describe Gitlab::Jira::Middleware do
- let(:app) { double(:app) }
- let(:middleware) { described_class.new(app) }
- let(:jira_user_agent) { 'Jira DVCS Connector Vertigo/5.0.0-D20170810T012915' }
-
- describe '.jira_dvcs_connector?' do
- it 'returns true when DVCS connector' do
- expect(described_class.jira_dvcs_connector?('HTTP_USER_AGENT' => jira_user_agent)).to eq(true)
- end
-
- it 'returns true if user agent starts with "Jira DVCS Connector"' do
- expect(described_class.jira_dvcs_connector?('HTTP_USER_AGENT' => 'Jira DVCS Connector')).to eq(true)
- end
-
- it 'returns false when not DVCS connector' do
- expect(described_class.jira_dvcs_connector?('HTTP_USER_AGENT' => 'pokemon')).to eq(false)
- end
- end
-
- describe '#call' do
- it 'adjusts HTTP_AUTHORIZATION env when request from Jira DVCS user agent' do
- expect(app).to receive(:call).with({ 'HTTP_USER_AGENT' => jira_user_agent,
- 'HTTP_AUTHORIZATION' => 'Bearer hash-123' })
-
- middleware.call('HTTP_USER_AGENT' => jira_user_agent, 'HTTP_AUTHORIZATION' => 'token hash-123')
- end
-
- it 'does not change HTTP_AUTHORIZATION env when request is not from Jira DVCS user agent' do
- env = { 'HTTP_USER_AGENT' => 'Mozilla/5.0', 'HTTP_AUTHORIZATION' => 'token hash-123' }
-
- expect(app).to receive(:call).with(env)
-
- middleware.call(env)
- end
- end
-end
diff --git a/spec/lib/gitlab/jira_import/handle_labels_service_spec.rb b/spec/lib/gitlab/jira_import/handle_labels_service_spec.rb
index b8c0dc64581..82233641778 100644
--- a/spec/lib/gitlab/jira_import/handle_labels_service_spec.rb
+++ b/spec/lib/gitlab/jira_import/handle_labels_service_spec.rb
@@ -11,7 +11,7 @@ RSpec.describe Gitlab::JiraImport::HandleLabelsService do
let_it_be(:other_project_label) { create(:label, title: 'feature') }
let_it_be(:group_label) { create(:group_label, group: group, title: 'dev') }
- let(:jira_labels) { %w(bug feature dev group::new) }
+ let(:jira_labels) { %w[bug feature dev group::new] }
subject { described_class.new(project, jira_labels).execute }
@@ -23,7 +23,7 @@ RSpec.describe Gitlab::JiraImport::HandleLabelsService do
it 'creates the missing labels on the project level' do
expect { subject }.to change { Label.count }.from(3).to(5)
- expect(created_labels.map(&:title)).to match_array(%w(feature group::new))
+ expect(created_labels.map(&:title)).to match_array(%w[feature group::new])
end
it 'returns the id of all labels matching the title' do
@@ -32,7 +32,7 @@ RSpec.describe Gitlab::JiraImport::HandleLabelsService do
end
context 'when no provided jira labels are missing' do
- let(:jira_labels) { %w(bug dev) }
+ let(:jira_labels) { %w[bug dev] }
it 'does not create any new labels' do
expect { subject }.not_to change { Label.count }.from(3)
diff --git a/spec/lib/gitlab/jira_import/issue_serializer_spec.rb b/spec/lib/gitlab/jira_import/issue_serializer_spec.rb
index 30ad24472b4..98958d8a92e 100644
--- a/spec/lib/gitlab/jira_import/issue_serializer_spec.rb
+++ b/spec/lib/gitlab/jira_import/issue_serializer_spec.rb
@@ -28,7 +28,7 @@ RSpec.describe Gitlab::JiraImport::IssueSerializer do
end
let(:priority_field) { { 'name' => 'Medium' } }
- let(:labels_field) { %w(bug dev backend frontend) }
+ let(:labels_field) { %w[bug dev backend frontend] }
let(:fields) do
{
@@ -101,7 +101,7 @@ RSpec.describe Gitlab::JiraImport::IssueSerializer do
end
context 'when there are no new labels' do
- let(:labels_field) { %w(bug dev) }
+ let(:labels_field) { %w[bug dev] }
it 'assigns the labels to the Issue hash' do
expect(subject[:label_ids]).to match_array([project_label.id, group_label.id])
diff --git a/spec/lib/gitlab/jira_import/labels_importer_spec.rb b/spec/lib/gitlab/jira_import/labels_importer_spec.rb
index 4fb5e363475..7579e2c65f4 100644
--- a/spec/lib/gitlab/jira_import/labels_importer_spec.rb
+++ b/spec/lib/gitlab/jira_import/labels_importer_spec.rb
@@ -36,8 +36,8 @@ RSpec.describe Gitlab::JiraImport::LabelsImporter do
let_it_be(:jira_import_with_label) { create(:jira_import_state, label: label, project: project) }
let_it_be(:issue_label) { create(:label, project: project, title: 'bug') }
- let(:jira_labels_1) { { "maxResults" => 2, "startAt" => 0, "total" => 3, "isLast" => false, "values" => %w(backend bug) } }
- let(:jira_labels_2) { { "maxResults" => 2, "startAt" => 2, "total" => 3, "isLast" => true, "values" => %w(feature) } }
+ let(:jira_labels_1) { { "maxResults" => 2, "startAt" => 0, "total" => 3, "isLast" => false, "values" => %w[backend bug] } }
+ let(:jira_labels_2) { { "maxResults" => 2, "startAt" => 2, "total" => 3, "isLast" => true, "values" => %w[feature] } }
context 'when labels are returned from jira' do
before do
@@ -55,8 +55,8 @@ RSpec.describe Gitlab::JiraImport::LabelsImporter do
end
it 'calls Gitlab::JiraImport::HandleLabelsService' do
- expect(Gitlab::JiraImport::HandleLabelsService).to receive(:new).with(project, %w(backend bug)).and_return(double(execute: [1, 2]))
- expect(Gitlab::JiraImport::HandleLabelsService).to receive(:new).with(project, %w(feature)).and_return(double(execute: [3]))
+ expect(Gitlab::JiraImport::HandleLabelsService).to receive(:new).with(project, %w[backend bug]).and_return(double(execute: [1, 2]))
+ expect(Gitlab::JiraImport::HandleLabelsService).to receive(:new).with(project, %w[feature]).and_return(double(execute: [3]))
subject
end
@@ -92,7 +92,7 @@ RSpec.describe Gitlab::JiraImport::LabelsImporter do
end
context 'when the isLast argument is missing' do
- let(:jira_labels) { { "maxResults" => 2, "startAt" => 0, "total" => 3, "values" => %w(bug dev) } }
+ let(:jira_labels) { { "maxResults" => 2, "startAt" => 0, "total" => 3, "values" => %w[bug dev] } }
it_behaves_like 'no labels handling'
end
diff --git a/spec/lib/gitlab/job_waiter_spec.rb b/spec/lib/gitlab/job_waiter_spec.rb
index b000f55e739..e3d7d59df04 100644
--- a/spec/lib/gitlab/job_waiter_spec.rb
+++ b/spec/lib/gitlab/job_waiter_spec.rb
@@ -62,6 +62,10 @@ RSpec.describe Gitlab::JobWaiter, :redis, feature_category: :shared do
before do
allow_any_instance_of(described_class).to receive(:wait).and_call_original
+ stub_feature_flags(
+ use_primary_and_secondary_stores_for_shared_state: false,
+ use_primary_store_as_default_for_shared_state: false
+ )
end
it 'returns when all jobs have been completed' do
@@ -83,36 +87,54 @@ RSpec.describe Gitlab::JobWaiter, :redis, feature_category: :shared do
expect(result).to contain_exactly('a')
end
- context 'when a label is provided' do
- let(:waiter) { described_class.new(2, worker_label: 'Foo') }
- let(:started_total) { double(:started_total) }
- let(:timeouts_total) { double(:timeouts_total) }
+ context 'when migration is ongoing' do
+ let(:waiter) { described_class.new(3) }
- before do
- allow(Gitlab::Metrics).to receive(:counter)
- .with(described_class::STARTED_METRIC, anything)
- .and_return(started_total)
+ shared_examples 'returns all jobs' do
+ it 'returns all jobs' do
+ result = nil
+ expect { Timeout.timeout(6) { result = waiter.wait(5) } }.not_to raise_error
- allow(Gitlab::Metrics).to receive(:counter)
- .with(described_class::TIMEOUTS_METRIC, anything)
- .and_return(timeouts_total)
+ expect(result).to contain_exactly('a', 'b', 'c')
+ end
end
- it 'increments just job_waiter_started_total when all jobs complete' do
- expect(started_total).to receive(:increment).with(worker: 'Foo')
- expect(timeouts_total).not_to receive(:increment)
+ context 'when using both stores' do
+ context 'with existing jobs in old store' do
+ before do
+ described_class.notify(waiter.key, 'a')
+ described_class.notify(waiter.key, 'b')
+ described_class.notify(waiter.key, 'c')
+ stub_feature_flags(use_primary_and_secondary_stores_for_shared_state: true)
+ end
- described_class.notify(waiter.key, 'a')
- described_class.notify(waiter.key, 'b')
+ it_behaves_like 'returns all jobs'
+ end
- expect { Timeout.timeout(1) { waiter.wait(2) } }.not_to raise_error
- end
+ context 'with jobs in both stores' do
+ before do
+ stub_feature_flags(use_primary_and_secondary_stores_for_shared_state: true)
+ described_class.notify(waiter.key, 'a')
+ described_class.notify(waiter.key, 'b')
+ described_class.notify(waiter.key, 'c')
+ end
- it 'increments job_waiter_started_total and job_waiter_timeouts_total when it times out' do
- expect(started_total).to receive(:increment).with(worker: 'Foo')
- expect(timeouts_total).to receive(:increment).with(worker: 'Foo')
+ it_behaves_like 'returns all jobs'
+ end
- expect { Timeout.timeout(2) { waiter.wait(1) } }.not_to raise_error
+ context 'when using primary store as default store' do
+ before do
+ stub_feature_flags(
+ use_primary_and_secondary_stores_for_shared_state: true,
+ use_primary_store_as_default_for_shared_state: true
+ )
+ described_class.notify(waiter.key, 'a')
+ described_class.notify(waiter.key, 'b')
+ described_class.notify(waiter.key, 'c')
+ end
+
+ it_behaves_like 'returns all jobs'
+ end
end
end
end
diff --git a/spec/lib/gitlab/kubernetes/kubectl_cmd_spec.rb b/spec/lib/gitlab/kubernetes/kubectl_cmd_spec.rb
index 3028e0a13aa..f88f7c4c108 100644
--- a/spec/lib/gitlab/kubernetes/kubectl_cmd_spec.rb
+++ b/spec/lib/gitlab/kubernetes/kubectl_cmd_spec.rb
@@ -7,7 +7,7 @@ require_relative '../../../../lib/gitlab/kubernetes/pod_cmd'
RSpec.describe Gitlab::Kubernetes::KubectlCmd do
describe '.delete' do
it 'constructs string properly' do
- args = %w(resource_type type --flag-1 --flag-2)
+ args = %w[resource_type type --flag-1 --flag-2]
expected_command = 'kubectl delete resource_type type --flag-1 --flag-2'
@@ -31,7 +31,7 @@ RSpec.describe Gitlab::Kubernetes::KubectlCmd do
context 'with optional args' do
it 'constructs command properly with many args' do
- args = %w(arg-1 --flag-0-1 arg-2 --flag-0-2)
+ args = %w[arg-1 --flag-0-1 arg-2 --flag-0-2]
expected_command = 'kubectl apply -f filename arg-1 --flag-0-1 arg-2 --flag-0-2'
diff --git a/spec/lib/gitlab/kubernetes/role_spec.rb b/spec/lib/gitlab/kubernetes/role_spec.rb
index acb9b5d4e8e..288a5406372 100644
--- a/spec/lib/gitlab/kubernetes/role_spec.rb
+++ b/spec/lib/gitlab/kubernetes/role_spec.rb
@@ -9,9 +9,9 @@ RSpec.describe Gitlab::Kubernetes::Role do
let(:rules) do
[{
- apiGroups: %w(hello.world),
- resources: %w(oil diamonds coffee),
- verbs: %w(say do walk run)
+ apiGroups: %w[hello.world],
+ resources: %w[oil diamonds coffee],
+ verbs: %w[say do walk run]
}]
end
diff --git a/spec/lib/gitlab/language_data_spec.rb b/spec/lib/gitlab/language_data_spec.rb
index bb4b0c3855c..828fd95f78e 100644
--- a/spec/lib/gitlab/language_data_spec.rb
+++ b/spec/lib/gitlab/language_data_spec.rb
@@ -15,7 +15,7 @@ RSpec.describe Gitlab::LanguageData do
expect(described_class.extensions).to be_a(Set)
expect(described_class.extensions.count).to be > 0
# Sanity check for known extensions
- expect(described_class.extensions).to include(*%w(.rb .yml .json))
+ expect(described_class.extensions).to include(*%w[.rb .yml .json])
end
end
end
diff --git a/spec/lib/gitlab/mail_room/mail_room_spec.rb b/spec/lib/gitlab/mail_room/mail_room_spec.rb
index 7259b5e2484..d3ddf034cd3 100644
--- a/spec/lib/gitlab/mail_room/mail_room_spec.rb
+++ b/spec/lib/gitlab/mail_room/mail_room_spec.rb
@@ -245,7 +245,6 @@ RSpec.describe Gitlab::MailRoom, feature_category: :build do
delivery_options: {
redis_url: "localhost",
redis_db: 99,
- namespace: "resque:gitlab",
queue: "default",
worker: "EmailReceiverWorker",
sentinels: [{ host: "localhost", port: 1234 }]
@@ -258,7 +257,6 @@ RSpec.describe Gitlab::MailRoom, feature_category: :build do
delivery_options: {
redis_url: "localhost",
redis_db: 99,
- namespace: "resque:gitlab",
queue: "default",
worker: "ServiceDeskEmailReceiverWorker",
sentinels: [{ host: "localhost", port: 1234 }]
diff --git a/spec/lib/gitlab/markup_helper_spec.rb b/spec/lib/gitlab/markup_helper_spec.rb
index 2bffd029568..a7508288f4e 100644
--- a/spec/lib/gitlab/markup_helper_spec.rb
+++ b/spec/lib/gitlab/markup_helper_spec.rb
@@ -4,8 +4,8 @@ require 'fast_spec_helper'
RSpec.describe Gitlab::MarkupHelper do
describe '#markup?' do
- %w(textile rdoc org creole wiki
- mediawiki rst adoc ad asciidoc mdown md markdown).each do |type|
+ %w[textile rdoc org creole wiki
+ mediawiki rst adoc ad asciidoc mdown md markdown].each do |type|
it "returns true for #{type} files" do
expect(described_class.markup?("README.#{type}")).to be_truthy
end
@@ -17,7 +17,7 @@ RSpec.describe Gitlab::MarkupHelper do
end
describe '#gitlab_markdown?' do
- %w(mdown mkd mkdn md markdown).each do |type|
+ %w[mdown mkd mkdn md markdown].each do |type|
it "returns true for #{type} files" do
expect(described_class.gitlab_markdown?("README.#{type}")).to be_truthy
end
@@ -29,7 +29,7 @@ RSpec.describe Gitlab::MarkupHelper do
end
describe '#asciidoc?' do
- %w(adoc ad asciidoc ADOC).each do |type|
+ %w[adoc ad asciidoc ADOC].each do |type|
it "returns true for #{type} files" do
expect(described_class.asciidoc?("README.#{type}")).to be_truthy
end
diff --git a/spec/lib/gitlab/memory/instrumentation_spec.rb b/spec/lib/gitlab/memory/instrumentation_spec.rb
index f287edb7da3..059bcad37e7 100644
--- a/spec/lib/gitlab/memory/instrumentation_spec.rb
+++ b/spec/lib/gitlab/memory/instrumentation_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Gitlab::Memory::Instrumentation, feature_category: :application_performance do
+RSpec.describe Gitlab::Memory::Instrumentation, feature_category: :cloud_connector do
include MemoryInstrumentationHelper
before do
diff --git a/spec/lib/gitlab/memory/reporter_spec.rb b/spec/lib/gitlab/memory/reporter_spec.rb
index 1d19d7129cf..5ba429ae6bc 100644
--- a/spec/lib/gitlab/memory/reporter_spec.rb
+++ b/spec/lib/gitlab/memory/reporter_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Gitlab::Memory::Reporter, :aggregate_failures, feature_category: :application_performance do
+RSpec.describe Gitlab::Memory::Reporter, :aggregate_failures, feature_category: :cloud_connector do
let(:fake_report) do
Class.new do
def name
diff --git a/spec/lib/gitlab/memory/reports/heap_dump_spec.rb b/spec/lib/gitlab/memory/reports/heap_dump_spec.rb
index 4e235a71bdb..7888f8b0c79 100644
--- a/spec/lib/gitlab/memory/reports/heap_dump_spec.rb
+++ b/spec/lib/gitlab/memory/reports/heap_dump_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Gitlab::Memory::Reports::HeapDump, feature_category: :application_performance do
+RSpec.describe Gitlab::Memory::Reports::HeapDump, feature_category: :cloud_connector do
# Copy this class so we do not mess with its state.
let(:klass) { described_class.dup }
diff --git a/spec/lib/gitlab/memory/watchdog/configurator_spec.rb b/spec/lib/gitlab/memory/watchdog/configurator_spec.rb
index 035652abfe6..cd9ac0d7a8d 100644
--- a/spec/lib/gitlab/memory/watchdog/configurator_spec.rb
+++ b/spec/lib/gitlab/memory/watchdog/configurator_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Gitlab::Memory::Watchdog::Configurator, feature_category: :application_performance do
+RSpec.describe Gitlab::Memory::Watchdog::Configurator, feature_category: :cloud_connector do
shared_examples 'as configurator' do |handler_class, event_reporter_class, sleep_time_env, sleep_time|
it 'configures the correct handler' do
configurator.call(configuration)
diff --git a/spec/lib/gitlab/memory/watchdog/event_reporter_spec.rb b/spec/lib/gitlab/memory/watchdog/event_reporter_spec.rb
index f1d241249e2..e27f842bc71 100644
--- a/spec/lib/gitlab/memory/watchdog/event_reporter_spec.rb
+++ b/spec/lib/gitlab/memory/watchdog/event_reporter_spec.rb
@@ -3,7 +3,7 @@
require 'fast_spec_helper'
require 'prometheus/client'
-RSpec.describe Gitlab::Memory::Watchdog::EventReporter, feature_category: :application_performance do
+RSpec.describe Gitlab::Memory::Watchdog::EventReporter, feature_category: :cloud_connector do
let(:logger) { instance_double(::Logger) }
let(:violations_counter) { instance_double(::Prometheus::Client::Counter) }
let(:violations_handled_counter) { instance_double(::Prometheus::Client::Counter) }
diff --git a/spec/lib/gitlab/memory/watchdog/handlers/null_handler_spec.rb b/spec/lib/gitlab/memory/watchdog/handlers/null_handler_spec.rb
index 09c76de9611..96cb02393f9 100644
--- a/spec/lib/gitlab/memory/watchdog/handlers/null_handler_spec.rb
+++ b/spec/lib/gitlab/memory/watchdog/handlers/null_handler_spec.rb
@@ -2,7 +2,7 @@
require 'fast_spec_helper'
-RSpec.describe Gitlab::Memory::Watchdog::Handlers::NullHandler, feature_category: :application_performance do
+RSpec.describe Gitlab::Memory::Watchdog::Handlers::NullHandler, feature_category: :cloud_connector do
subject(:handler) { described_class.instance }
describe '#call' do
diff --git a/spec/lib/gitlab/memory/watchdog/handlers/puma_handler_spec.rb b/spec/lib/gitlab/memory/watchdog/handlers/puma_handler_spec.rb
index 7df95c1722e..4c2fd5a3283 100644
--- a/spec/lib/gitlab/memory/watchdog/handlers/puma_handler_spec.rb
+++ b/spec/lib/gitlab/memory/watchdog/handlers/puma_handler_spec.rb
@@ -2,7 +2,7 @@
require 'fast_spec_helper'
-RSpec.describe Gitlab::Memory::Watchdog::Handlers::PumaHandler, feature_category: :application_performance do
+RSpec.describe Gitlab::Memory::Watchdog::Handlers::PumaHandler, feature_category: :cloud_connector do
# rubocop: disable RSpec/VerifiedDoubles
# In tests, the Puma constant is not loaded so we cannot make this an instance_double.
let(:puma_worker_handle_class) { double('Puma::Cluster::WorkerHandle') }
diff --git a/spec/lib/gitlab/memory/watchdog/handlers/sidekiq_handler_spec.rb b/spec/lib/gitlab/memory/watchdog/handlers/sidekiq_handler_spec.rb
index d1f303e7731..68dd784fb7e 100644
--- a/spec/lib/gitlab/memory/watchdog/handlers/sidekiq_handler_spec.rb
+++ b/spec/lib/gitlab/memory/watchdog/handlers/sidekiq_handler_spec.rb
@@ -3,7 +3,7 @@
require 'fast_spec_helper'
require 'sidekiq'
-RSpec.describe Gitlab::Memory::Watchdog::Handlers::SidekiqHandler, feature_category: :application_performance do
+RSpec.describe Gitlab::Memory::Watchdog::Handlers::SidekiqHandler, feature_category: :cloud_connector do
let(:sleep_time) { 3 }
let(:shutdown_timeout_seconds) { 30 }
let(:handler_iterations) { 0 }
diff --git a/spec/lib/gitlab/memory/watchdog/monitor/rss_memory_limit_spec.rb b/spec/lib/gitlab/memory/watchdog/monitor/rss_memory_limit_spec.rb
index 67d185fd2f1..552736a55ef 100644
--- a/spec/lib/gitlab/memory/watchdog/monitor/rss_memory_limit_spec.rb
+++ b/spec/lib/gitlab/memory/watchdog/monitor/rss_memory_limit_spec.rb
@@ -4,7 +4,7 @@ require 'fast_spec_helper'
require 'prometheus/client'
require 'support/shared_examples/lib/gitlab/memory/watchdog/monitor_result_shared_examples'
-RSpec.describe Gitlab::Memory::Watchdog::Monitor::RssMemoryLimit, feature_category: :application_performance do
+RSpec.describe Gitlab::Memory::Watchdog::Monitor::RssMemoryLimit, feature_category: :cloud_connector do
let(:max_rss_limit_gauge) { instance_double(::Prometheus::Client::Gauge) }
let(:memory_limit_bytes) { 2_097_152_000 }
let(:worker_memory_bytes) { 1_048_576_000 }
diff --git a/spec/lib/gitlab/memory/watchdog/sidekiq_event_reporter_spec.rb b/spec/lib/gitlab/memory/watchdog/sidekiq_event_reporter_spec.rb
index 48595c3f172..06b1646d418 100644
--- a/spec/lib/gitlab/memory/watchdog/sidekiq_event_reporter_spec.rb
+++ b/spec/lib/gitlab/memory/watchdog/sidekiq_event_reporter_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Gitlab::Memory::Watchdog::SidekiqEventReporter, feature_category: :application_performance do
+RSpec.describe Gitlab::Memory::Watchdog::SidekiqEventReporter, feature_category: :cloud_connector do
let(:counter) { instance_double(::Prometheus::Client::Counter) }
before do
diff --git a/spec/lib/gitlab/memory/watchdog_spec.rb b/spec/lib/gitlab/memory/watchdog_spec.rb
index dd6bfb6da2c..c442208617f 100644
--- a/spec/lib/gitlab/memory/watchdog_spec.rb
+++ b/spec/lib/gitlab/memory/watchdog_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Gitlab::Memory::Watchdog, :aggregate_failures, feature_category: :application_performance do
+RSpec.describe Gitlab::Memory::Watchdog, :aggregate_failures, feature_category: :cloud_connector do
context 'watchdog' do
let(:configuration) { instance_double(described_class::Configuration) }
let(:handler) { instance_double(described_class::Handlers::NullHandler) }
diff --git a/spec/lib/gitlab/merge_requests/mergeability/check_result_spec.rb b/spec/lib/gitlab/merge_requests/mergeability/check_result_spec.rb
index 74aa3528328..cd84525f7e5 100644
--- a/spec/lib/gitlab/merge_requests/mergeability/check_result_spec.rb
+++ b/spec/lib/gitlab/merge_requests/mergeability/check_result_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Gitlab::MergeRequests::Mergeability::CheckResult do
+RSpec.describe Gitlab::MergeRequests::Mergeability::CheckResult, feature_category: :code_review_workflow do
subject(:check_result) { described_class }
let(:time) { Time.current }
@@ -63,6 +63,28 @@ RSpec.describe Gitlab::MergeRequests::Mergeability::CheckResult do
end
end
+ describe '.inactive' do
+ subject(:inactive) { check_result.inactive(payload: payload) }
+
+ let(:payload) { {} }
+
+ it 'creates a inactive result' do
+ expect(inactive.status).to eq described_class::INACTIVE_STATUS
+ end
+
+ it 'uses the default payload' do
+ expect(inactive.payload).to eq described_class.default_payload
+ end
+
+ context 'when given a payload' do
+ let(:payload) { { last_run_at: time + 1.day, test: 'test' } }
+
+ it 'uses the payload passed' do
+ expect(inactive.payload).to eq payload
+ end
+ end
+ end
+
describe '.from_hash' do
subject(:from_hash) { described_class.from_hash(hash) }
diff --git a/spec/lib/gitlab/metrics/exporter/base_exporter_spec.rb b/spec/lib/gitlab/metrics/exporter/base_exporter_spec.rb
index 6673cc50d67..4184c674823 100644
--- a/spec/lib/gitlab/metrics/exporter/base_exporter_spec.rb
+++ b/spec/lib/gitlab/metrics/exporter/base_exporter_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Gitlab::Metrics::Exporter::BaseExporter, feature_category: :application_performance do
+RSpec.describe Gitlab::Metrics::Exporter::BaseExporter, feature_category: :cloud_connector do
let(:settings) { double('settings') }
let(:log_enabled) { false }
let(:exporter) { described_class.new(settings, log_enabled: log_enabled, log_file: 'test_exporter.log') }
diff --git a/spec/lib/gitlab/metrics/rails_slis_spec.rb b/spec/lib/gitlab/metrics/rails_slis_spec.rb
index ef996f61082..3050c769117 100644
--- a/spec/lib/gitlab/metrics/rails_slis_spec.rb
+++ b/spec/lib/gitlab/metrics/rails_slis_spec.rb
@@ -3,7 +3,7 @@ require 'spec_helper'
RSpec.describe Gitlab::Metrics::RailsSlis, feature_category: :error_budgets do
before do
- allow(Gitlab::Graphql::KnownOperations).to receive(:default).and_return(Gitlab::Graphql::KnownOperations.new(%w(foo bar)))
+ allow(Gitlab::Graphql::KnownOperations).to receive(:default).and_return(Gitlab::Graphql::KnownOperations.new(%w[foo bar]))
end
describe '.initialize_request_slis!' do
diff --git a/spec/lib/gitlab/metrics/samplers/threads_sampler_spec.rb b/spec/lib/gitlab/metrics/samplers/threads_sampler_spec.rb
index 5dabafb7c0b..0a3648c8b9a 100644
--- a/spec/lib/gitlab/metrics/samplers/threads_sampler_spec.rb
+++ b/spec/lib/gitlab/metrics/samplers/threads_sampler_spec.rb
@@ -40,11 +40,11 @@ RSpec.describe Gitlab::Metrics::Samplers::ThreadsSampler do
context 'thread names', :aggregate_failures do
where(:thread_names, :expected_names) do
[
- [[nil], %w(unnamed)],
+ [[nil], %w[unnamed]],
[['puma threadpool 1', 'puma threadpool 001', 'puma threadpool 002'], ['puma threadpool']],
- [%w(sidekiq_worker_thread), %w(sidekiq_worker_thread)],
- [%w(some_sampler some_exporter), %w(some_sampler some_exporter)],
- [%w(unknown thing), %w(unrecognized)]
+ [%w[sidekiq_worker_thread], %w[sidekiq_worker_thread]],
+ [%w[some_sampler some_exporter], %w[some_sampler some_exporter]],
+ [%w[unknown thing], %w[unrecognized]]
]
end
diff --git a/spec/lib/gitlab/metrics/subscribers/action_cable_spec.rb b/spec/lib/gitlab/metrics/subscribers/action_cable_spec.rb
index 54868bb6ca4..8fbfcdc3bd5 100644
--- a/spec/lib/gitlab/metrics/subscribers/action_cable_spec.rb
+++ b/spec/lib/gitlab/metrics/subscribers/action_cable_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Gitlab::Metrics::Subscribers::ActionCable, :request_store, feature_category: :application_performance do
+RSpec.describe Gitlab::Metrics::Subscribers::ActionCable, :request_store, feature_category: :cloud_connector do
let(:subscriber) { described_class.new }
let(:counter) { double(:counter) }
let(:transmitted_bytes_counter) { double(:counter) }
diff --git a/spec/lib/gitlab/middleware/go_spec.rb b/spec/lib/gitlab/middleware/go_spec.rb
index a3835f9eed0..4820f42ade3 100644
--- a/spec/lib/gitlab/middleware/go_spec.rb
+++ b/spec/lib/gitlab/middleware/go_spec.rb
@@ -206,7 +206,7 @@ RSpec.describe Gitlab::Middleware::Go, feature_category: :source_code_management
expect(response[0]).to eq(404)
expect(response[1]['Content-Type']).to eq('text/html')
- expected_body = %{<html><body>go get #{Gitlab.config.gitlab.url}/#{project.full_path}</body></html>}
+ expected_body = %(<html><body>go get #{Gitlab.config.gitlab.url}/#{project.full_path}</body></html>)
expect(response[2]).to eq([expected_body])
end
end
@@ -278,7 +278,7 @@ RSpec.describe Gitlab::Middleware::Go, feature_category: :source_code_management
project_url = "http://#{Gitlab.config.gitlab.host}/#{path}"
expect(response[0]).to eq(200)
expect(response[1]['Content-Type']).to eq('text/html')
- expected_body = %{<html><head><meta name="go-import" content="#{Gitlab.config.gitlab.host}/#{path} git #{repository_url}"><meta name="go-source" content="#{Gitlab.config.gitlab.host}/#{path} #{project_url} #{project_url}/-/tree/#{branch}{/dir} #{project_url}/-/blob/#{branch}{/dir}/{file}#L{line}"></head><body>go get #{Gitlab.config.gitlab.url}/#{path}</body></html>}
+ expected_body = %(<html><head><meta name="go-import" content="#{Gitlab.config.gitlab.host}/#{path} git #{repository_url}"><meta name="go-source" content="#{Gitlab.config.gitlab.host}/#{path} #{project_url} #{project_url}/-/tree/#{branch}{/dir} #{project_url}/-/blob/#{branch}{/dir}/{file}#L{line}"></head><body>go get #{Gitlab.config.gitlab.url}/#{path}</body></html>)
expect(response[2]).to eq([expected_body])
end
end
diff --git a/spec/lib/gitlab/middleware/multipart_spec.rb b/spec/lib/gitlab/middleware/multipart_spec.rb
index 509a4bb921b..b857ed47d42 100644
--- a/spec/lib/gitlab/middleware/multipart_spec.rb
+++ b/spec/lib/gitlab/middleware/multipart_spec.rb
@@ -33,7 +33,7 @@ RSpec.describe Gitlab::Middleware::Multipart do
let(:params) { upload_parameters_for(key: 'file', mode: mode, filename: filename, remote_id: remote_id).merge('file.path' => '/should/not/be/read') }
it 'builds an UploadedFile' do
- expect_uploaded_files(original_filename: filename, remote_id: remote_id, size: uploaded_file.size, params_path: %w(file))
+ expect_uploaded_files(original_filename: filename, remote_id: remote_id, size: uploaded_file.size, params_path: %w[file])
subject
end
@@ -61,7 +61,7 @@ RSpec.describe Gitlab::Middleware::Multipart do
let(:params) { upload_parameters_for(filepath: uploaded_filepath, key: 'file', mode: mode, filename: filename) }
it 'builds an UploadedFile' do
- expect_uploaded_files(filepath: uploaded_filepath, original_filename: filename, size: uploaded_file.size, params_path: %w(file))
+ expect_uploaded_files(filepath: uploaded_filepath, original_filename: filename, size: uploaded_file.size, params_path: %w[file])
subject
end
diff --git a/spec/lib/gitlab/middleware/path_traversal_check_spec.rb b/spec/lib/gitlab/middleware/path_traversal_check_spec.rb
index 3d334a60c49..91081cc88ea 100644
--- a/spec/lib/gitlab/middleware/path_traversal_check_spec.rb
+++ b/spec/lib/gitlab/middleware/path_traversal_check_spec.rb
@@ -55,6 +55,34 @@ RSpec.describe ::Gitlab::Middleware::PathTraversalCheck, feature_category: :shar
end
end
+ shared_examples 'excluded path' do
+ it 'measures and logs the execution time' do
+ expect(::Gitlab::PathTraversal)
+ .not_to receive(:check_path_traversal!)
+ expect(::Gitlab::AppLogger)
+ .to receive(:warn)
+ .with({ class_name: described_class.name, duration_ms: instance_of(Float) })
+ .and_call_original
+
+ expect(subject).to eq(fake_response)
+ end
+
+ context 'with log_execution_time_path_traversal_middleware disabled' do
+ before do
+ stub_feature_flags(log_execution_time_path_traversal_middleware: false)
+ end
+
+ it 'does nothing' do
+ expect(::Gitlab::PathTraversal)
+ .not_to receive(:check_path_traversal!)
+ expect(::Gitlab::AppLogger)
+ .not_to receive(:warn)
+
+ expect(subject).to eq(fake_response)
+ end
+ end
+ end
+
shared_examples 'path traversal' do
it 'logs the problem and measures the execution time' do
expect(::Gitlab::PathTraversal)
@@ -70,7 +98,8 @@ RSpec.describe ::Gitlab::Middleware::PathTraversalCheck, feature_category: :shar
class_name: described_class.name,
duration_ms: instance_of(Float),
message: described_class::PATH_TRAVERSAL_MESSAGE,
- fullpath: fullpath
+ fullpath: fullpath,
+ method: method.upcase
}).and_call_original
expect(subject).to eq(fake_response)
@@ -94,7 +123,8 @@ RSpec.describe ::Gitlab::Middleware::PathTraversalCheck, feature_category: :shar
.with({
class_name: described_class.name,
message: described_class::PATH_TRAVERSAL_MESSAGE,
- fullpath: fullpath
+ fullpath: fullpath,
+ method: method.upcase
}).and_call_original
expect(subject).to eq(fake_response)
@@ -110,23 +140,90 @@ RSpec.describe ::Gitlab::Middleware::PathTraversalCheck, feature_category: :shar
let(:method) { 'get' }
where(:path, :query_params, :shared_example_name) do
- '/foo/bar' | {} | 'no issue'
- '/foo/../bar' | {} | 'path traversal'
- '/foo%2Fbar' | {} | 'no issue'
- '/foo%2F..%2Fbar' | {} | 'path traversal'
- '/foo%252F..%252Fbar' | {} | 'no issue'
- '/foo/bar' | { x: 'foo' } | 'no issue'
- '/foo/bar' | { x: 'foo/../bar' } | 'path traversal'
- '/foo/bar' | { x: 'foo%2Fbar' } | 'no issue'
- '/foo/bar' | { x: 'foo%2F..%2Fbar' } | 'no issue'
- '/foo/bar' | { x: 'foo%252F..%252Fbar' } | 'no issue'
- '/foo%2F..%2Fbar' | { x: 'foo%252F..%252Fbar' } | 'path traversal'
+ '/foo/bar' | {} | 'no issue'
+ '/foo/../bar' | {} | 'path traversal'
+ '/foo%2Fbar' | {} | 'no issue'
+ '/foo%2F..%2Fbar' | {} | 'path traversal'
+ '/foo%252F..%252Fbar' | {} | 'no issue'
+
+ '/foo/bar' | { x: 'foo' } | 'no issue'
+ '/foo/bar' | { x: 'foo/../bar' } | 'path traversal'
+ '/foo/bar' | { x: 'foo%2Fbar' } | 'no issue'
+ '/foo/bar' | { x: 'foo%2F..%2Fbar' } | 'no issue'
+ '/foo/bar' | { x: 'foo%252F..%252Fbar' } | 'no issue'
+ '/foo%2F..%2Fbar' | { x: 'foo%252F..%252Fbar' } | 'path traversal'
end
with_them do
it_behaves_like params[:shared_example_name]
end
+ context 'for global search excluded paths' do
+ excluded_paths = %w[
+ /search
+ /search/count
+ /api/v4/search
+ /api/v4/search.json
+ /api/v4/projects/4/search
+ /api/v4/projects/4/search.json
+ /api/v4/projects/4/-/search
+ /api/v4/projects/4/-/search.json
+ /api/v4/projects/my%2Fproject/search
+ /api/v4/projects/my%2Fproject/search.json
+ /api/v4/projects/my%2Fproject/-/search
+ /api/v4/projects/my%2Fproject/-/search.json
+ /api/v4/groups/4/search
+ /api/v4/groups/4/search.json
+ /api/v4/groups/4/-/search
+ /api/v4/groups/4/-/search.json
+ /api/v4/groups/my%2Fgroup/search
+ /api/v4/groups/my%2Fgroup/search.json
+ /api/v4/groups/my%2Fgroup/-/search
+ /api/v4/groups/my%2Fgroup/-/search.json
+ ]
+ query_params_with_no_path_traversal = [
+ {},
+ { x: 'foo' },
+ { x: 'foo%2F..%2Fbar' },
+ { x: 'foo%2F..%2Fbar' },
+ { x: 'foo%252F..%252Fbar' }
+ ]
+ query_params_with_path_traversal = [
+ { x: 'foo/../bar' }
+ ]
+
+ excluded_paths.each do |excluded_path|
+ [query_params_with_no_path_traversal + query_params_with_path_traversal].flatten.each do |qp|
+ context "for excluded path #{excluded_path} with query params #{qp}" do
+ let(:query_params) { qp }
+ let(:path) { excluded_path }
+
+ it_behaves_like 'excluded path'
+ end
+ end
+
+ non_excluded_path = excluded_path.gsub('search', 'searchtest')
+
+ query_params_with_no_path_traversal.each do |qp|
+ context "for non excluded path #{non_excluded_path} with query params #{qp}" do
+ let(:query_params) { qp }
+ let(:path) { non_excluded_path }
+
+ it_behaves_like 'no issue'
+ end
+ end
+
+ query_params_with_path_traversal.each do |qp|
+ context "for non excluded path #{non_excluded_path} with query params #{qp}" do
+ let(:query_params) { qp }
+ let(:path) { non_excluded_path }
+
+ it_behaves_like 'path traversal'
+ end
+ end
+ end
+ end
+
context 'with a issues search path' do
let(:query_params) { {} }
let(:path) do
@@ -147,6 +244,7 @@ RSpec.describe ::Gitlab::Middleware::PathTraversalCheck, feature_category: :shar
'/foo%2Fbar' | {} | 'no issue'
'/foo%2F..%2Fbar' | {} | 'path traversal'
'/foo%252F..%252Fbar' | {} | 'no issue'
+
'/foo/bar' | { x: 'foo' } | 'no issue'
'/foo/bar' | { x: 'foo/../bar' } | 'no issue'
'/foo/bar' | { x: 'foo%2Fbar' } | 'no issue'
@@ -158,6 +256,59 @@ RSpec.describe ::Gitlab::Middleware::PathTraversalCheck, feature_category: :shar
with_them do
it_behaves_like params[:shared_example_name]
end
+
+ context 'for global search excluded paths' do
+ excluded_paths = %w[
+ /search
+ /search/count
+ /api/v4/search
+ /api/v4/search.json
+ /api/v4/projects/4/search
+ /api/v4/projects/4/search.json
+ /api/v4/projects/4/-/search
+ /api/v4/projects/4/-/search.json
+ /api/v4/projects/my%2Fproject/search
+ /api/v4/projects/my%2Fproject/search.json
+ /api/v4/projects/my%2Fproject/-/search
+ /api/v4/projects/my%2Fproject/-/search.json
+ /api/v4/groups/4/search
+ /api/v4/groups/4/search.json
+ /api/v4/groups/4/-/search
+ /api/v4/groups/4/-/search.json
+ /api/v4/groups/my%2Fgroup/search
+ /api/v4/groups/my%2Fgroup/search.json
+ /api/v4/groups/my%2Fgroup/-/search
+ /api/v4/groups/my%2Fgroup/-/search.json
+ ]
+ all_query_params = [
+ {},
+ { x: 'foo' },
+ { x: 'foo%2F..%2Fbar' },
+ { x: 'foo%2F..%2Fbar' },
+ { x: 'foo%252F..%252Fbar' },
+ { x: 'foo/../bar' }
+ ]
+
+ excluded_paths.each do |excluded_path|
+ all_query_params.each do |qp|
+ context "for excluded path #{excluded_path} with query params #{qp}" do
+ let(:query_params) { qp }
+ let(:path) { excluded_path }
+
+ it_behaves_like 'excluded path'
+ end
+
+ non_excluded_path = excluded_path.gsub('search', 'searchtest')
+
+ context "for non excluded path #{non_excluded_path} with query params #{qp}" do
+ let(:query_params) { qp }
+ let(:path) { excluded_path.gsub('search', 'searchtest') }
+
+ it_behaves_like 'no issue'
+ end
+ end
+ end
+ end
end
end
@@ -177,6 +328,12 @@ RSpec.describe ::Gitlab::Middleware::PathTraversalCheck, feature_category: :shar
'/foo/bar' | { x: 'foo%2Fbar' }
'/foo/bar' | { x: 'foo%2F..%2Fbar' }
'/foo/bar' | { x: 'foo%252F..%252Fbar' }
+ '/search' | { x: 'foo/../bar' }
+ '/search' | { x: 'foo%2F..%2Fbar' }
+ '/search' | { x: 'foo%252F..%252Fbar' }
+ '%2Fsearch' | { x: 'foo/../bar' }
+ '%2Fsearch' | { x: 'foo%2F..%2Fbar' }
+ '%2Fsearch' | { x: 'foo%252F..%252Fbar' }
end
with_them do
diff --git a/spec/lib/gitlab/omniauth_initializer_spec.rb b/spec/lib/gitlab/omniauth_initializer_spec.rb
index 1c665ec6e18..e12c0f4e78b 100644
--- a/spec/lib/gitlab/omniauth_initializer_spec.rb
+++ b/spec/lib/gitlab/omniauth_initializer_spec.rb
@@ -2,7 +2,9 @@
require 'spec_helper'
-RSpec.describe Gitlab::OmniauthInitializer do
+RSpec.describe Gitlab::OmniauthInitializer, feature_category: :system_access do
+ include LoginHelpers
+
let(:devise_config) { class_double(Devise) }
subject(:initializer) { described_class.new(devise_config) }
@@ -171,7 +173,7 @@ RSpec.describe Gitlab::OmniauthInitializer do
end
it 'allows "args" array for app_id and app_secret' do
- legacy_config = { 'name' => 'legacy', 'args' => %w(123 abc) }
+ legacy_config = { 'name' => 'legacy', 'args' => %w[123 abc] }
expect(devise_config).to receive(:omniauth).with(:legacy, '123', 'abc')
@@ -224,6 +226,119 @@ RSpec.describe Gitlab::OmniauthInitializer do
subject.execute([shibboleth_config])
end
+ context 'when SAML providers are configured' do
+ it 'configures default args for a single SAML provider' do
+ stub_omniauth_config(providers: [{ name: 'saml', args: { idp_sso_service_url: 'https://saml.example.com' } }])
+
+ expect(devise_config).to receive(:omniauth).with(
+ :saml,
+ {
+ idp_sso_service_url: 'https://saml.example.com',
+ attribute_statements: ::Gitlab::Auth::Saml::Config.default_attribute_statements
+ }
+ )
+
+ initializer.execute(Gitlab.config.omniauth.providers)
+ end
+
+ context 'when configuration provides matching keys' do
+ before do
+ stub_omniauth_config(
+ providers: [
+ {
+ name: 'saml',
+ args: { idp_sso_service_url: 'https://saml.example.com', attribute_statements: { email: ['custom_attr'] } }
+ }
+ ]
+ )
+ end
+
+ it 'merges arguments with user configuration preference' do
+ expect(devise_config).to receive(:omniauth).with(
+ :saml,
+ {
+ idp_sso_service_url: 'https://saml.example.com',
+ attribute_statements: ::Gitlab::Auth::Saml::Config.default_attribute_statements
+ .merge({ email: ['custom_attr'] })
+ }
+ )
+
+ initializer.execute(Gitlab.config.omniauth.providers)
+ end
+
+ it 'merges arguments with defaults preference when invert_omniauth_args_merging is not enabled' do
+ stub_feature_flags(invert_omniauth_args_merging: false)
+
+ expect(devise_config).to receive(:omniauth).with(
+ :saml,
+ {
+ idp_sso_service_url: 'https://saml.example.com',
+ attribute_statements: ::Gitlab::Auth::Saml::Config.default_attribute_statements
+ }
+ )
+
+ initializer.execute(Gitlab.config.omniauth.providers)
+ end
+ end
+
+ it 'configures defaults args for multiple SAML providers' do
+ stub_omniauth_config(
+ providers: [
+ { name: 'saml', args: { idp_sso_service_url: 'https://saml.example.com' } },
+ {
+ name: 'saml2',
+ args: { strategy_class: 'OmniAuth::Strategies::SAML', idp_sso_service_url: 'https://saml2.example.com' }
+ }
+ ]
+ )
+
+ expect(devise_config).to receive(:omniauth).with(
+ :saml,
+ {
+ idp_sso_service_url: 'https://saml.example.com',
+ attribute_statements: ::Gitlab::Auth::Saml::Config.default_attribute_statements
+ }
+ )
+ expect(devise_config).to receive(:omniauth).with(
+ :saml2,
+ {
+ idp_sso_service_url: 'https://saml2.example.com',
+ strategy_class: OmniAuth::Strategies::SAML,
+ attribute_statements: ::Gitlab::Auth::Saml::Config.default_attribute_statements
+ }
+ )
+
+ initializer.execute(Gitlab.config.omniauth.providers)
+ end
+
+ it 'merges arguments with user configuration preference for custom SAML provider' do
+ stub_omniauth_config(
+ providers: [
+ {
+ name: 'custom_saml',
+ args: {
+ strategy_class: 'OmniAuth::Strategies::SAML',
+ idp_sso_service_url: 'https://saml2.example.com',
+ attribute_statements: { email: ['custom_attr'] }
+ }
+ }
+ ]
+ )
+
+ expect(devise_config).to receive(:omniauth).with(
+ :custom_saml,
+ {
+ idp_sso_service_url: 'https://saml2.example.com',
+ strategy_class: OmniAuth::Strategies::SAML,
+ attribute_statements: ::Gitlab::Auth::Saml::Config.default_attribute_statements
+ .merge({ email: ['custom_attr'] })
+ }
+ )
+
+ initializer.execute(Gitlab.config.omniauth.providers)
+ end
+ end
+
it 'configures defaults for google_oauth2' do
google_config = {
'name' => 'google_oauth2',
diff --git a/spec/lib/gitlab/other_markup_spec.rb b/spec/lib/gitlab/other_markup_spec.rb
index 34f1e0cfbc5..266cb75a8ac 100644
--- a/spec/lib/gitlab/other_markup_spec.rb
+++ b/spec/lib/gitlab/other_markup_spec.rb
@@ -59,6 +59,31 @@ RSpec.describe Gitlab::OtherMarkup, feature_category: :wiki do
end
end
+ context 'when mediawiki content' do
+ links = {
+ 'p' => {
+ file: 'file.mediawiki',
+ input: 'Red Bridge (JRuby Embed)',
+ output: "\n<p>Red Bridge (JRuby Embed)</p>"
+ },
+ 'h1' => {
+ file: 'file.mediawiki',
+ input: '= Red Bridge (JRuby Embed) =',
+ output: "\n\n<h1>\n<a name=\"Red_Bridge_JRuby_Embed\"></a><span>Red Bridge (JRuby Embed)</span>\n</h1>\n"
+ },
+ 'h2' => {
+ file: 'file.mediawiki',
+ input: '== Red Bridge (JRuby Embed) ==',
+ output: "\n\n<h2>\n<a name=\"Red_Bridge_JRuby_Embed\"></a><span>Red Bridge (JRuby Embed)</span>\n</h2>\n"
+ }
+ }
+ links.each do |name, data|
+ it "does render into #{name} element" do
+ expect(render(data[:file], data[:input], context)).to eq(data[:output])
+ end
+ end
+ end
+
context 'when rendering takes too long' do
let_it_be(:file_name) { 'foo.bar' }
let_it_be(:project) { create(:project, :repository) }
@@ -86,6 +111,24 @@ RSpec.describe Gitlab::OtherMarkup, feature_category: :wiki do
end
end
+ context 'RedCloth markup' do
+ it 'renders textile correctly' do
+ test_text = '"This is *my* text."'
+ expected_res = "<p>&#8220;This is <strong>my</strong> text.&#8221;</p>"
+ expect(RedCloth.new(test_text).to_html).to eq(expected_res)
+ end
+
+ it 'protects against malicious backtracking' do
+ test_text = '<A' + ('A' * 54773)
+
+ expect do
+ Timeout.timeout(Gitlab::OtherMarkup::RENDER_TIMEOUT.seconds) do
+ RedCloth.new(test_text, [:sanitize_html]).to_html
+ end
+ end.not_to raise_error
+ end
+ end
+
def render(...)
described_class.render(...)
end
diff --git a/spec/lib/gitlab/pages/deployment_update_spec.rb b/spec/lib/gitlab/pages/deployment_update_spec.rb
index cf109248f36..9a7564ddd59 100644
--- a/spec/lib/gitlab/pages/deployment_update_spec.rb
+++ b/spec/lib/gitlab/pages/deployment_update_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Gitlab::Pages::DeploymentUpdate do
+RSpec.describe Gitlab::Pages::DeploymentUpdate, feature_category: :pages do
let_it_be(:project, refind: true) { create(:project, :repository) }
let_it_be(:old_pipeline) { create(:ci_pipeline, project: project, sha: project.commit('HEAD').sha) }
diff --git a/spec/lib/gitlab/pages/virtual_host_finder_spec.rb b/spec/lib/gitlab/pages/virtual_host_finder_spec.rb
index 8c34968bbfc..bc3f9d89b5f 100644
--- a/spec/lib/gitlab/pages/virtual_host_finder_spec.rb
+++ b/spec/lib/gitlab/pages/virtual_host_finder_spec.rb
@@ -5,10 +5,6 @@ require 'spec_helper'
RSpec.describe Gitlab::Pages::VirtualHostFinder, feature_category: :pages do
let_it_be(:project) { create(:project) }
- before_all do
- project.update_pages_deployment!(create(:pages_deployment, project: project))
- end
-
before do
stub_pages_setting(host: 'example.com')
end
@@ -24,10 +20,6 @@ RSpec.describe Gitlab::Pages::VirtualHostFinder, feature_category: :pages do
subject(:virtual_domain) { described_class.new(pages_domain.domain).execute }
context 'when there are no pages deployed for the project' do
- before_all do
- project.mark_pages_as_not_deployed
- end
-
it 'returns nil' do
expect(virtual_domain).to be_nil
end
@@ -35,7 +27,7 @@ RSpec.describe Gitlab::Pages::VirtualHostFinder, feature_category: :pages do
context 'when there are pages deployed for the project' do
before_all do
- project.mark_pages_as_deployed
+ create(:pages_deployment, project: project)
end
it 'returns the virual domain when there are pages deployed for the project' do
@@ -48,10 +40,6 @@ RSpec.describe Gitlab::Pages::VirtualHostFinder, feature_category: :pages do
context 'when host is a namespace domain' do
context 'when there are no pages deployed for the project' do
- before_all do
- project.mark_pages_as_not_deployed
- end
-
it 'returns no result if the provided host is not subdomain of the Pages host' do
virtual_domain = described_class.new("#{project.namespace.path}.something.io").execute
@@ -68,7 +56,7 @@ RSpec.describe Gitlab::Pages::VirtualHostFinder, feature_category: :pages do
context 'when there are pages deployed for the project' do
before_all do
- project.mark_pages_as_deployed
+ create(:pages_deployment, project: project)
project.namespace.update!(path: 'topNAMEspace')
end
@@ -109,10 +97,6 @@ RSpec.describe Gitlab::Pages::VirtualHostFinder, feature_category: :pages do
end
context 'when there are no pages deployed for the project' do
- before_all do
- project.mark_pages_as_not_deployed
- end
-
it 'returns nil' do
expect(virtual_domain).to be_nil
end
@@ -120,7 +104,7 @@ RSpec.describe Gitlab::Pages::VirtualHostFinder, feature_category: :pages do
context 'when there are pages deployed for the project' do
before_all do
- project.mark_pages_as_deployed
+ create(:pages_deployment, project: project)
end
it 'returns the virual domain when there are pages deployed for the project' do
@@ -133,9 +117,10 @@ RSpec.describe Gitlab::Pages::VirtualHostFinder, feature_category: :pages do
it 'prioritizes the unique domain project' do
group = create(:group, path: 'unique-domain')
other_project = build(:project, path: 'unique-domain.example.com', group: group)
- other_project.save!(validate: false)
- other_project.update_pages_deployment!(create(:pages_deployment, project: other_project))
- other_project.mark_pages_as_deployed
+ .tap { |project| project.save!(validate: false) }
+
+ create(:pages_deployment, project: project)
+ create(:pages_deployment, project: other_project)
expect(virtual_domain).to be_an_instance_of(Pages::VirtualDomain)
expect(virtual_domain.lookup_paths.first.project_id).to eq(project.id)
@@ -150,10 +135,6 @@ RSpec.describe Gitlab::Pages::VirtualHostFinder, feature_category: :pages do
end
context 'when there are no pages deployed for the project' do
- before_all do
- project.mark_pages_as_not_deployed
- end
-
it 'returns nil' do
expect(virtual_domain).to be_nil
end
@@ -161,7 +142,7 @@ RSpec.describe Gitlab::Pages::VirtualHostFinder, feature_category: :pages do
context 'when there are pages deployed for the project' do
before_all do
- project.mark_pages_as_deployed
+ create(:pages_deployment, project: project)
end
it 'returns nil' do
diff --git a/spec/lib/gitlab/pagination/cursor_based_keyset_spec.rb b/spec/lib/gitlab/pagination/cursor_based_keyset_spec.rb
index effe767e41d..e5958549a81 100644
--- a/spec/lib/gitlab/pagination/cursor_based_keyset_spec.rb
+++ b/spec/lib/gitlab/pagination/cursor_based_keyset_spec.rb
@@ -28,7 +28,9 @@ RSpec.describe Gitlab::Pagination::CursorBasedKeyset do
end
describe '.enforced_for_type?' do
- subject { described_class.enforced_for_type?(relation) }
+ let_it_be(:project) { create(:project) }
+
+ subject { described_class.enforced_for_type?(project, relation) }
context 'when relation is Group' do
let(:relation) { Group.all }
@@ -45,7 +47,21 @@ RSpec.describe Gitlab::Pagination::CursorBasedKeyset do
context 'when relation is Ci::Build' do
let(:relation) { Ci::Build.all }
- it { is_expected.to be false }
+ before do
+ stub_feature_flags(enforce_ci_builds_pagination_limit: false)
+ end
+
+ context 'when feature flag enforce_ci_builds_pagination_limit is enabled' do
+ before do
+ stub_feature_flags(enforce_ci_builds_pagination_limit: project)
+ end
+
+ it { is_expected.to be true }
+ end
+
+ context 'when feature fllag enforce_ci_builds_pagination_limit is disabled' do
+ it { is_expected.to be false }
+ end
end
end
diff --git a/spec/lib/gitlab/pagination/keyset/order_spec.rb b/spec/lib/gitlab/pagination/keyset/order_spec.rb
index 05bb0bb8b3a..52d2688c06e 100644
--- a/spec/lib/gitlab/pagination/keyset/order_spec.rb
+++ b/spec/lib/gitlab/pagination/keyset/order_spec.rb
@@ -726,7 +726,7 @@ RSpec.describe Gitlab::Pagination::Keyset::Order do
end
describe '#attribute_names' do
- let(:expected_attribute_names) { %w(id name) }
+ let(:expected_attribute_names) { %w[id name] }
let(:order) do
described_class.build(
[
diff --git a/spec/lib/gitlab/pagination/offset_header_builder_spec.rb b/spec/lib/gitlab/pagination/offset_header_builder_spec.rb
index a415bad5135..f43216702a8 100644
--- a/spec/lib/gitlab/pagination/offset_header_builder_spec.rb
+++ b/spec/lib/gitlab/pagination/offset_header_builder_spec.rb
@@ -15,11 +15,15 @@ RSpec.describe Gitlab::Pagination::OffsetHeaderBuilder do
describe '#execute' do
let(:basic_links) do
- %{<http://localhost?page=1&per_page=5>; rel="prev", <http://localhost?page=3&per_page=5>; rel="next", <http://localhost?page=1&per_page=5>; rel="first"}
+ [
+ %(<http://localhost?page=1&per_page=5>; rel="prev"),
+ %(<http://localhost?page=3&per_page=5>; rel="next"),
+ %(<http://localhost?page=1&per_page=5>; rel="first")
+ ].join(', ')
end
let(:last_link) do
- %{, <http://localhost?page=3&per_page=5>; rel="last"}
+ %(, <http://localhost?page=3&per_page=5>; rel="last")
end
def expect_basic_headers
diff --git a/spec/lib/gitlab/patch/sidekiq_scheduled_enq_spec.rb b/spec/lib/gitlab/patch/sidekiq_scheduled_enq_spec.rb
index f57257cd1c0..cd3718f5dcc 100644
--- a/spec/lib/gitlab/patch/sidekiq_scheduled_enq_spec.rb
+++ b/spec/lib/gitlab/patch/sidekiq_scheduled_enq_spec.rb
@@ -10,7 +10,7 @@ RSpec.describe Gitlab::Patch::SidekiqScheduledEnq, :clean_gitlab_redis_queues, f
allow(Sidekiq).to receive(:load_json).and_return(payload)
# stub data in both namespaces
- Sidekiq.redis { |c| c.zadd('schedule', 100, 'dummy') }
+ Gitlab::Redis::Queues.with { |c| c.zadd('resque:gitlab:schedule', 100, 'dummy') }
Gitlab::Redis::Queues.with { |c| c.zadd('schedule', 100, 'dummy') }
end
@@ -26,7 +26,7 @@ RSpec.describe Gitlab::Patch::SidekiqScheduledEnq, :clean_gitlab_redis_queues, f
end
Gitlab::Redis::Queues.with do |conn|
- expect(conn.zcard('schedule')).to eq(0)
+ expect(conn.zcard('resque:gitlab:schedule')).to eq(0)
end
end
@@ -45,29 +45,13 @@ RSpec.describe Gitlab::Patch::SidekiqScheduledEnq, :clean_gitlab_redis_queues, f
end
Gitlab::Redis::Queues.with do |conn|
- expect(conn.zcard('schedule')).to eq(1)
+ expect(conn.zcard('resque:gitlab:schedule')).to eq(1)
end
end
end
- context 'when both envvar are enabled' do
- around do |example|
- # runs the zadd to ensure it goes into namespaced set
- Sidekiq.redis { |c| c.zadd('schedule', 100, 'dummy') }
-
- holder = Sidekiq.redis_pool
-
- # forcibly replace Sidekiq.redis since this is set in config/initializer/sidekiq.rb
- Sidekiq.redis = Gitlab::Redis::Queues.pool
-
- example.run
-
- ensure
- Sidekiq.redis = holder
- end
-
+ context 'when SIDEKIQ_ENABLE_DUAL_NAMESPACE_POLLING is enabled' do
before do
- stub_env('SIDEKIQ_ENQUEUE_NON_NAMESPACED', 'true')
stub_env('SIDEKIQ_ENABLE_DUAL_NAMESPACE_POLLING', 'true')
end
@@ -81,7 +65,7 @@ RSpec.describe Gitlab::Patch::SidekiqScheduledEnq, :clean_gitlab_redis_queues, f
end
Gitlab::Redis::Queues.with do |conn|
- expect(conn.zcard('schedule')).to eq(0)
+ expect(conn.zcard('resque:gitlab:schedule')).to eq(0)
end
end
end
diff --git a/spec/lib/gitlab/path_regex_spec.rb b/spec/lib/gitlab/path_regex_spec.rb
index 53dc145dcc4..eee05c0bb15 100644
--- a/spec/lib/gitlab/path_regex_spec.rb
+++ b/spec/lib/gitlab/path_regex_spec.rb
@@ -103,21 +103,27 @@ RSpec.describe Gitlab::PathRegex do
.concat(Array(API::API.prefix.to_s))
.concat(sitemap_words)
.concat(deprecated_routes)
+ .concat(reserved_routes)
.compact
.uniq
end
let(:sitemap_words) do
- %w(sitemap sitemap.xml sitemap.xml.gz)
+ %w[sitemap sitemap.xml sitemap.xml.gz]
end
let(:deprecated_routes) do
# profile was deprecated in https://gitlab.com/gitlab-org/gitlab/-/merge_requests/51646
- %w(profile s)
+ %w[profile s]
+ end
+
+ let(:reserved_routes) do
+ # login was reserved in https://gitlab.com/gitlab-org/gitlab/-/merge_requests/134791
+ ['login']
end
let(:ee_top_level_words) do
- %w(unsubscribes v2)
+ %w[unsubscribes v2]
end
let(:files_in_public) do
@@ -126,7 +132,7 @@ RSpec.describe Gitlab::PathRegex do
.split("\n")
.map { |entry| entry.start_with?('public/-/') ? '-' : entry.gsub('public/', '') }
.uniq
- tracked + %w(assets uploads)
+ tracked + %w[assets uploads]
end
# All routes that start with a namespaced path, that have 1 or more
diff --git a/spec/lib/gitlab/popen_spec.rb b/spec/lib/gitlab/popen_spec.rb
index 0a186b07d19..78455cb705f 100644
--- a/spec/lib/gitlab/popen_spec.rb
+++ b/spec/lib/gitlab/popen_spec.rb
@@ -24,7 +24,7 @@ RSpec.describe Gitlab::Popen do
context 'zero status' do
before do
- @output, @status = @klass.new.popen(%w(ls), path)
+ @output, @status = @klass.new.popen(%w[ls], path)
end
it { expect(@status).to be_zero }
@@ -33,7 +33,7 @@ RSpec.describe Gitlab::Popen do
context 'non-zero status' do
before do
- @output, @status = @klass.new.popen(%w(cat NOTHING), path)
+ @output, @status = @klass.new.popen(%w[cat NOTHING], path)
end
it { expect(@status).to eq(1) }
@@ -64,7 +64,7 @@ RSpec.describe Gitlab::Popen do
it 'calls popen3 with the provided environment variables' do
expect(Open3).to receive(:popen3).with(vars, 'ls', options)
- @output, @status = @klass.new.popen(%w(ls), path, { 'foobar' => 123 })
+ @output, @status = @klass.new.popen(%w[ls], path, { 'foobar' => 123 })
end
end
@@ -83,7 +83,7 @@ RSpec.describe Gitlab::Popen do
context 'without a directory argument' do
before do
- @output, @status = @klass.new.popen(%w(ls))
+ @output, @status = @klass.new.popen(%w[ls])
end
it { expect(@status).to be_zero }
diff --git a/spec/lib/gitlab/process_management_spec.rb b/spec/lib/gitlab/process_management_spec.rb
index fbd39702efb..709e4611954 100644
--- a/spec/lib/gitlab/process_management_spec.rb
+++ b/spec/lib/gitlab/process_management_spec.rb
@@ -8,7 +8,7 @@ RSpec.describe Gitlab::ProcessManagement do
expect(described_class).to receive(:trap).ordered.with(:INT)
expect(described_class).to receive(:trap).ordered.with(:HUP)
- described_class.trap_signals(%i(INT HUP))
+ described_class.trap_signals(%i[INT HUP])
end
end
@@ -17,7 +17,7 @@ RSpec.describe Gitlab::ProcessManagement do
expect(described_class).to receive(:trap).ordered.with(:INT, 'DEFAULT')
expect(described_class).to receive(:trap).ordered.with(:HUP, 'DEFAULT')
- described_class.modify_signals(%i(INT HUP), 'DEFAULT')
+ described_class.modify_signals(%i[INT HUP], 'DEFAULT')
end
end
diff --git a/spec/lib/gitlab/process_supervisor_spec.rb b/spec/lib/gitlab/process_supervisor_spec.rb
index 18de5053362..94535e96843 100644
--- a/spec/lib/gitlab/process_supervisor_spec.rb
+++ b/spec/lib/gitlab/process_supervisor_spec.rb
@@ -2,7 +2,7 @@
require_relative '../../../lib/gitlab/process_supervisor'
-RSpec.describe Gitlab::ProcessSupervisor, feature_category: :application_performance do
+RSpec.describe Gitlab::ProcessSupervisor, feature_category: :cloud_connector do
let(:health_check_interval_seconds) { 0.1 }
let(:check_terminate_interval_seconds) { 1 }
let(:forwarded_signals) { [] }
@@ -152,13 +152,13 @@ RSpec.describe Gitlab::ProcessSupervisor, feature_category: :application_perform
end
context 'termination signals' do
- let(:term_signals) { %i(INT TERM) }
+ let(:term_signals) { %i[INT TERM] }
context 'when TERM results in timely shutdown of processes' do
it 'forwards them to observed processes without waiting for grace period to expire' do
allow(Gitlab::ProcessManagement).to receive(:any_alive?).and_return(false)
- expect(Gitlab::ProcessManagement).to receive(:trap_signals).ordered.with(%i(INT TERM)).and_yield(:TERM)
+ expect(Gitlab::ProcessManagement).to receive(:trap_signals).ordered.with(%i[INT TERM]).and_yield(:TERM)
expect(Gitlab::ProcessManagement).to receive(:signal_processes).ordered.with(process_ids, :TERM)
expect(supervisor).not_to receive(:sleep).with(check_terminate_interval_seconds)
@@ -168,7 +168,7 @@ RSpec.describe Gitlab::ProcessSupervisor, feature_category: :application_perform
context 'when TERM does not result in timely shutdown of processes' do
it 'issues a KILL signal after the grace period expires' do
- expect(Gitlab::ProcessManagement).to receive(:trap_signals).with(%i(INT TERM)).and_yield(:TERM)
+ expect(Gitlab::ProcessManagement).to receive(:trap_signals).with(%i[INT TERM]).and_yield(:TERM)
expect(Gitlab::ProcessManagement).to receive(:signal_processes).ordered.with(process_ids, :TERM)
expect(supervisor).to receive(:sleep).ordered.with(check_terminate_interval_seconds).at_least(:once)
expect(Gitlab::ProcessManagement).to receive(:signal_processes).ordered.with(process_ids, '-KILL')
@@ -179,10 +179,10 @@ RSpec.describe Gitlab::ProcessSupervisor, feature_category: :application_perform
end
context 'forwarded signals' do
- let(:forwarded_signals) { %i(USR1) }
+ let(:forwarded_signals) { %i[USR1] }
it 'forwards given signals to the observed processes' do
- expect(Gitlab::ProcessManagement).to receive(:trap_signals).with(%i(USR1)).and_yield(:USR1)
+ expect(Gitlab::ProcessManagement).to receive(:trap_signals).with(%i[USR1]).and_yield(:USR1)
expect(Gitlab::ProcessManagement).to receive(:signal_processes).ordered.with(process_ids, :USR1)
supervisor.supervise(process_ids) { [] }
diff --git a/spec/lib/gitlab/project_template_spec.rb b/spec/lib/gitlab/project_template_spec.rb
index 998fff12e94..07cdbf97091 100644
--- a/spec/lib/gitlab/project_template_spec.rb
+++ b/spec/lib/gitlab/project_template_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Gitlab::ProjectTemplate do
+RSpec.describe Gitlab::ProjectTemplate, feature_category: :source_code_management do
include ProjectTemplateTestHelper
describe '.all' do
diff --git a/spec/lib/gitlab/quick_actions/extractor_spec.rb b/spec/lib/gitlab/quick_actions/extractor_spec.rb
index f91e8d2a7ef..063b416c514 100644
--- a/spec/lib/gitlab/quick_actions/extractor_spec.rb
+++ b/spec/lib/gitlab/quick_actions/extractor_spec.rb
@@ -246,7 +246,7 @@ RSpec.describe Gitlab::QuickActions::Extractor, feature_category: :team_planning
msg = %(hello\nworld\n/reopen\n/shrug this is great?\n/shrug meh)
msg, commands = extractor.extract_commands(msg)
- expect(commands).to eq [['reopen'], ['shrug', 'this is great?'], %w(shrug meh)]
+ expect(commands).to eq [['reopen'], ['shrug', 'this is great?'], %w[shrug meh]]
expect(msg).to eq "hello\nworld\nthis is great? SHRUG\nmeh SHRUG"
end
diff --git a/spec/lib/gitlab/redis/multi_store_spec.rb b/spec/lib/gitlab/redis/multi_store_spec.rb
index 1745a745ec3..6b1c0fb2e81 100644
--- a/spec/lib/gitlab/redis/multi_store_spec.rb
+++ b/spec/lib/gitlab/redis/multi_store_spec.rb
@@ -3,7 +3,6 @@
require 'spec_helper'
RSpec.describe Gitlab::Redis::MultiStore, feature_category: :redis do
- using RSpec::Parameterized::TableSyntax
include RedisHelpers
let_it_be(:redis_store_class) { define_helper_redis_store_class }
@@ -56,7 +55,6 @@ RSpec.describe Gitlab::Redis::MultiStore, feature_category: :redis do
context 'when primary_store is not a ::Redis instance' do
before do
allow(primary_store).to receive(:is_a?).with(::Redis).and_return(false)
- allow(primary_store).to receive(:is_a?).with(::Redis::Namespace).and_return(false)
end
it 'fails with exception' do
@@ -65,21 +63,9 @@ RSpec.describe Gitlab::Redis::MultiStore, feature_category: :redis do
end
end
- context 'when primary_store is a ::Redis::Namespace instance' do
- before do
- allow(primary_store).to receive(:is_a?).with(::Redis).and_return(false)
- allow(primary_store).to receive(:is_a?).with(::Redis::Namespace).and_return(true)
- end
-
- it 'fails with exception' do
- expect { described_class.new(primary_store, secondary_store, instance_name) }.not_to raise_error
- end
- end
-
context 'when secondary_store is not a ::Redis instance' do
before do
allow(secondary_store).to receive(:is_a?).with(::Redis).and_return(false)
- allow(secondary_store).to receive(:is_a?).with(::Redis::Namespace).and_return(false)
end
it 'fails with exception' do
@@ -88,130 +74,22 @@ RSpec.describe Gitlab::Redis::MultiStore, feature_category: :redis do
end
end
- context 'when secondary_store is a ::Redis::Namespace instance' do
- before do
- allow(secondary_store).to receive(:is_a?).with(::Redis).and_return(false)
- allow(secondary_store).to receive(:is_a?).with(::Redis::Namespace).and_return(true)
- end
-
- it 'fails with exception' do
- expect { described_class.new(primary_store, secondary_store, instance_name) }.not_to raise_error
- end
- end
-
# rubocop:disable RSpec/MultipleMemoizedHelpers
context 'with READ redis commands' do
subject do
multi_store.send(name, *args, **kwargs)
end
- let_it_be(:key1) { "redis:{1}:key_a" }
- let_it_be(:key2) { "redis:{1}:key_b" }
- let_it_be(:value1) { "redis_value1" }
- let_it_be(:value2) { "redis_value2" }
- let_it_be(:skey) { "redis:set:key" }
- let_it_be(:skey2) { "redis:set:key2" }
- let_it_be(:smemberargs) { [skey, value1] }
- let_it_be(:hkey) { "redis:hash:key" }
- let_it_be(:hkey2) { "redis:hash:key2" }
- let_it_be(:zkey) { "redis:sortedset:key" }
- let_it_be(:zkey2) { "redis:sortedset:key2" }
- let_it_be(:hitem1) { "item1" }
- let_it_be(:hitem2) { "item2" }
- let_it_be(:keys) { [key1, key2] }
- let_it_be(:values) { [value1, value2] }
- let_it_be(:svalues) { [value2, value1] }
- let_it_be(:hgetargs) { [hkey, hitem1] }
- let_it_be(:hmgetval) { [value1] }
- let_it_be(:mhmgetargs) { [hkey, hitem1] }
- let_it_be(:hvalmapped) { { "item1" => value1 } }
- let_it_be(:sscanargs) { [skey2, 0] }
- let_it_be(:sscanval) { ["0", [value1]] }
- let_it_be(:scanargs) { ["0"] }
- let_it_be(:scankwargs) { { match: '*:set:key2*' } }
- let_it_be(:scanval) { ["0", [skey2]] }
- let_it_be(:sscan_eachval) { [value1] }
- let_it_be(:sscan_each_arg) { { match: '*1*' } }
- let_it_be(:hscan_eachval) { [[hitem1, value1]] }
- let_it_be(:zscan_eachval) { [[value1, 1.0]] }
- let_it_be(:scan_each_arg) { { match: 'redis*' } }
- let_it_be(:scan_each_val) { [key1, key2, skey, skey2, hkey, hkey2, zkey, zkey2] }
-
- # rubocop:disable Layout/LineLength
- where(:case_name, :name, :args, :value, :kwargs, :block) do
- 'execute :get command' | :get | ref(:key1) | ref(:value1) | {} | nil
- 'execute :mget command' | :mget | ref(:keys) | ref(:values) | {} | nil
- 'execute :mget with block' | :mget | ref(:keys) | ref(:values) | {} | ->(value) { value }
- 'execute :smembers command' | :smembers | ref(:skey) | ref(:svalues) | {} | nil
- 'execute :scard command' | :scard | ref(:skey) | 2 | {} | nil
- 'execute :sismember command' | :sismember | ref(:smemberargs) | true | {} | nil
- 'execute :exists command' | :exists | ref(:key1) | 1 | {} | nil
- 'execute :exists? command' | :exists? | ref(:key1) | true | {} | nil
- 'execute :hget command' | :hget | ref(:hgetargs) | ref(:value1) | {} | nil
- 'execute :hlen command' | :hlen | ref(:hkey) | 1 | {} | nil
- 'execute :hgetall command' | :hgetall | ref(:hkey) | ref(:hvalmapped) | {} | nil
- 'execute :hexists command' | :hexists | ref(:hgetargs) | true | {} | nil
- 'execute :hmget command' | :hmget | ref(:hgetargs) | ref(:hmgetval) | {} | nil
- 'execute :mapped_hmget command' | :mapped_hmget | ref(:mhmgetargs) | ref(:hvalmapped) | {} | nil
- 'execute :sscan command' | :sscan | ref(:sscanargs) | ref(:sscanval) | {} | nil
- 'execute :scan command' | :scan | ref(:scanargs) | ref(:scanval) | ref(:scankwargs) | nil
-
- # we run *scan_each here as they are reads too
- 'execute :scan_each command' | :scan_each | nil | ref(:scan_each_val) | ref(:scan_each_arg) | nil
- 'execute :sscan_each command' | :sscan_each | ref(:skey2) | ref(:sscan_eachval) | {} | nil
- 'execute :sscan_each w block' | :sscan_each | ref(:skey) | ref(:sscan_eachval) | ref(:sscan_each_arg) | nil
- 'execute :hscan_each command' | :hscan_each | ref(:hkey) | ref(:hscan_eachval) | {} | nil
- 'execute :hscan_each w block' | :hscan_each | ref(:hkey2) | ref(:hscan_eachval) | ref(:sscan_each_arg) | nil
- 'execute :zscan_each command' | :zscan_each | ref(:zkey) | ref(:zscan_eachval) | {} | nil
- 'execute :zscan_each w block' | :zscan_each | ref(:zkey2) | ref(:zscan_eachval) | ref(:sscan_each_arg) | nil
- end
- # rubocop:enable Layout/LineLength
-
- before do
- primary_store.set(key1, value1)
- primary_store.set(key2, value2)
- primary_store.sadd?(skey, [value1, value2])
- primary_store.sadd?(skey2, [value1])
- primary_store.hset(hkey, hitem1, value1)
- primary_store.hset(hkey2, hitem1, value1, hitem2, value2)
- primary_store.zadd(zkey, 1, value1)
- primary_store.zadd(zkey2, [[1, value1], [2, value2]])
-
- secondary_store.set(key1, value1)
- secondary_store.set(key2, value2)
- secondary_store.sadd?(skey, [value1, value2])
- secondary_store.sadd?(skey2, [value1])
- secondary_store.hset(hkey, hitem1, value1)
- secondary_store.hset(hkey2, hitem1, value1, hitem2, value2)
- secondary_store.zadd(zkey, 1, value1)
- secondary_store.zadd(zkey2, [[1, value1], [2, value2]])
- end
-
- after do
- primary_store.flushdb
- secondary_store.flushdb
- end
-
- RSpec.shared_examples_for 'reads correct value' do
- it 'returns the correct value' do
- if value.is_a?(Array)
- # :smembers does not guarantee the order it will return the values (unsorted set)
- is_expected.to match_array(value)
- else
- is_expected.to eq(value)
- end
- end
- end
+ let(:args) { 'args' }
+ let(:kwargs) { { match: '*:set:key2*' } }
RSpec.shared_examples_for 'secondary store' do
it 'execute on the secondary instance' do
- expect(secondary_store).to receive(name).with(*expected_args).and_call_original
+ expect(secondary_store).to receive(name).with(*expected_args)
subject
end
- include_examples 'reads correct value'
-
it 'does not execute on the primary store' do
expect(primary_store).not_to receive(name)
@@ -219,23 +97,22 @@ RSpec.describe Gitlab::Redis::MultiStore, feature_category: :redis do
end
end
- with_them do
+ described_class::READ_COMMANDS.each do |name|
describe name.to_s do
- let(:expected_args) { kwargs&.present? ? [*args, { **kwargs }] : Array(args) }
+ let(:expected_args) { [*args, { **kwargs }] }
+ let(:name) { name }
before do
- allow(primary_store).to receive(name).and_call_original
- allow(secondary_store).to receive(name).and_call_original
+ allow(primary_store).to receive(name)
+ allow(secondary_store).to receive(name)
end
context 'when reading from the primary is successful' do
it 'returns the correct value' do
- expect(primary_store).to receive(name).with(*expected_args).and_call_original
+ expect(primary_store).to receive(name).with(*expected_args)
subject
end
-
- include_examples 'reads correct value'
end
context 'when reading from default instance is raising an exception' do
@@ -246,23 +123,13 @@ RSpec.describe Gitlab::Redis::MultiStore, feature_category: :redis do
it 'logs the exception and re-raises the error' do
expect(Gitlab::ErrorTracking).to receive(:log_exception).with(an_instance_of(StandardError),
- hash_including(:multi_store_error_message, instance_name: instance_name, command_name: name))
+ hash_including(:multi_store_error_message,
+ instance_name: instance_name, command_name: name))
expect { subject }.to raise_error(an_instance_of(StandardError))
end
end
- context 'when reading from empty default instance' do
- before do
- # this ensures a cache miss without having to stub the default store
- multi_store.default_store.flushdb
- end
-
- it 'does not call the non_default_store' do
- expect(multi_store.non_default_store).not_to receive(name)
- end
- end
-
context 'when the command is executed within pipelined block' do
subject do
multi_store.pipelined do |pipeline|
@@ -276,7 +143,7 @@ RSpec.describe Gitlab::Redis::MultiStore, feature_category: :redis do
2.times do
expect_next_instance_of(Redis::PipelinedConnection) do |pipeline|
- expect(pipeline).to receive(name).with(*expected_args).once.and_call_original
+ expect(pipeline).to receive(name).with(*expected_args).once
end
end
@@ -284,27 +151,16 @@ RSpec.describe Gitlab::Redis::MultiStore, feature_category: :redis do
end
end
- if params[:block]
+ context 'when block provided' do
subject do
- multi_store.send(name, *expected_args, &block)
+ multi_store.send(name, expected_args) { nil }
end
- context 'when block is provided' do
- it 'only default store yields to the block' do
- expect(primary_store).to receive(name).and_yield(value)
- expect(secondary_store).not_to receive(name).and_yield(value)
-
- subject
- end
-
- it 'only default store to execute' do
- expect(primary_store).to receive(name).with(*expected_args).and_call_original
- expect(secondary_store).not_to receive(name).with(*expected_args).and_call_original
-
- subject
- end
+ it 'only default store to execute' do
+ expect(primary_store).to receive(:send).with(name, expected_args)
+ expect(secondary_store).not_to receive(:send)
- include_examples 'reads correct value'
+ subject
end
end
@@ -327,8 +183,8 @@ RSpec.describe Gitlab::Redis::MultiStore, feature_category: :redis do
end
it 'executes only on secondary redis store', :aggregate_failures do
- expect(secondary_store).to receive(name).with(*expected_args).and_call_original
- expect(primary_store).not_to receive(name).with(*expected_args).and_call_original
+ expect(secondary_store).to receive(name).with(*expected_args)
+ expect(primary_store).not_to receive(name).with(*expected_args)
subject
end
@@ -336,8 +192,8 @@ RSpec.describe Gitlab::Redis::MultiStore, feature_category: :redis do
context 'when using primary store as default' do
it 'executes only on primary redis store', :aggregate_failures do
- expect(primary_store).to receive(name).with(*expected_args).and_call_original
- expect(secondary_store).not_to receive(name).with(*expected_args).and_call_original
+ expect(primary_store).to receive(name).with(*expected_args)
+ expect(secondary_store).not_to receive(name).with(*expected_args)
subject
end
@@ -429,110 +285,24 @@ RSpec.describe Gitlab::Redis::MultiStore, feature_category: :redis do
end
end
- RSpec.shared_examples_for 'verify that store contains values' do |store|
- it "#{store} redis store contains correct values", :aggregate_failures do
- subject
-
- redis_store = multi_store.send(store)
-
- if expected_value.is_a?(Array)
- # :smembers does not guarantee the order it will return the values
- expect(redis_store.send(verification_name, *verification_args)).to match_array(expected_value)
- else
- expect(redis_store.send(verification_name, *verification_args)).to eq(expected_value)
- end
- end
- end
-
- # rubocop:disable RSpec/MultipleMemoizedHelpers
context 'with WRITE redis commands' do
- let_it_be(:ikey1) { "counter1" }
- let_it_be(:ikey2) { "counter2" }
- let_it_be(:iargs) { [ikey2, 3] }
- let_it_be(:ivalue1) { "1" }
- let_it_be(:ivalue2) { "3" }
- let_it_be(:key1) { "redis:{1}:key_a" }
- let_it_be(:key2) { "redis:{1}:key_b" }
- let_it_be(:key3) { "redis:{1}:key_c" }
- let_it_be(:key4) { "redis:{1}:key_d" }
- let_it_be(:value1) { "redis_value1" }
- let_it_be(:value2) { "redis_value2" }
- let_it_be(:key1_value1) { [key1, value1] }
- let_it_be(:key1_value2) { [key1, value2] }
- let_it_be(:ttl) { 10 }
- let_it_be(:key1_ttl_value1) { [key1, ttl, value1] }
- let_it_be(:skey) { "redis:set:key" }
- let_it_be(:svalues1) { [value2, value1] }
- let_it_be(:svalues2) { [value1] }
- let_it_be(:skey_value1) { [skey, [value1]] }
- let_it_be(:skey_value2) { [skey, [value2]] }
- let_it_be(:script) { %(redis.call("set", "#{key1}", "#{value1}")) }
- let_it_be(:hkey1) { "redis:{1}:hash_a" }
- let_it_be(:hkey2) { "redis:{1}:hash_b" }
- let_it_be(:item) { "item" }
- let_it_be(:hdelarg) { [hkey1, item] }
- let_it_be(:hsetarg) { [hkey2, item, value1] }
- let_it_be(:mhsetarg) { [hkey2, { "item" => value1 }] }
- let_it_be(:hgetarg) { [hkey2, item] }
- let_it_be(:expireargs) { [key3, ttl] }
-
- # rubocop:disable Layout/LineLength
- where(:case_name, :name, :args, :expected_value, :verification_name, :verification_args) do
- 'execute :set command' | :set | ref(:key1_value1) | ref(:value1) | :get | ref(:key1)
- 'execute :setnx command' | :setnx | ref(:key1_value2) | ref(:value1) | :get | ref(:key2)
- 'execute :setex command' | :setex | ref(:key1_ttl_value1) | ref(:ttl) | :ttl | ref(:key1)
- 'execute :sadd command' | :sadd | ref(:skey_value2) | ref(:svalues1) | :smembers | ref(:skey)
- 'execute :sadd? command' | :sadd? | ref(:skey_value2) | ref(:svalues1) | :smembers | ref(:skey)
- 'execute :srem command' | :srem | ref(:skey_value1) | [] | :smembers | ref(:skey)
- 'execute :del command' | :del | ref(:key2) | nil | :get | ref(:key2)
- 'execute :unlink command' | :unlink | ref(:key3) | nil | :get | ref(:key3)
- 'execute :flushdb command' | :flushdb | nil | 0 | :dbsize | nil
- 'execute :eval command' | :eval | ref(:script) | ref(:value1) | :get | ref(:key1)
- 'execute :incr command' | :incr | ref(:ikey1) | ref(:ivalue1) | :get | ref(:ikey1)
- 'execute :incrby command' | :incrby | ref(:iargs) | ref(:ivalue2) | :get | ref(:ikey2)
- 'execute :hset command' | :hset | ref(:hsetarg) | ref(:value1) | :hget | ref(:hgetarg)
- 'execute :hdel command' | :hdel | ref(:hdelarg) | nil | :hget | ref(:hdelarg)
- 'execute :expire command' | :expire | ref(:expireargs) | ref(:ttl) | :ttl | ref(:key3)
- 'execute :mapped_hmset command' | :mapped_hmset | ref(:mhsetarg) | ref(:value1) | :hget | ref(:hgetarg)
- end
- # rubocop:enable Layout/LineLength
-
- before do
- primary_store.flushdb
- secondary_store.flushdb
-
- primary_store.set(key2, value1)
- primary_store.set(key3, value1)
- primary_store.set(key4, value1)
- primary_store.sadd?(skey, value1)
- primary_store.hset(hkey2, item, value1)
-
- secondary_store.set(key2, value1)
- secondary_store.set(key3, value1)
- secondary_store.set(key4, value1)
- secondary_store.sadd?(skey, value1)
- secondary_store.hset(hkey2, item, value1)
- end
-
- with_them do
+ described_class::WRITE_COMMANDS.each do |name|
describe name.to_s do
- let(:expected_args) { args || no_args }
+ let(:args) { "dummy_args" }
+ let(:name) { name }
before do
- allow(primary_store).to receive(name).and_call_original
- allow(secondary_store).to receive(name).and_call_original
+ allow(primary_store).to receive(name)
+ allow(secondary_store).to receive(name)
end
context 'when executing on primary instance is successful' do
it 'executes on both primary and secondary redis store', :aggregate_failures do
- expect(primary_store).to receive(name).with(*expected_args).and_call_original
- expect(secondary_store).to receive(name).with(*expected_args).and_call_original
+ expect(primary_store).to receive(name).with(*args)
+ expect(secondary_store).to receive(name).with(*args)
subject
end
-
- include_examples 'verify that store contains values', :primary_store
- include_examples 'verify that store contains values', :secondary_store
end
context 'when use_primary_and_secondary_stores feature flag is disabled' do
@@ -546,8 +316,8 @@ RSpec.describe Gitlab::Redis::MultiStore, feature_category: :redis do
end
it 'executes only on secondary redis store', :aggregate_failures do
- expect(secondary_store).to receive(name).with(*expected_args).and_call_original
- expect(primary_store).not_to receive(name).with(*expected_args).and_call_original
+ expect(secondary_store).to receive(name).with(*args)
+ expect(primary_store).not_to receive(name).with(*args)
subject
end
@@ -555,8 +325,8 @@ RSpec.describe Gitlab::Redis::MultiStore, feature_category: :redis do
context 'when using primary store as default' do
it 'executes only on primary redis store', :aggregate_failures do
- expect(primary_store).to receive(name).with(*expected_args).and_call_original
- expect(secondary_store).not_to receive(name).with(*expected_args).and_call_original
+ expect(primary_store).to receive(name).with(*args)
+ expect(secondary_store).not_to receive(name).with(*args)
subject
end
@@ -565,31 +335,30 @@ RSpec.describe Gitlab::Redis::MultiStore, feature_category: :redis do
context 'when executing on the default instance is raising an exception' do
before do
- allow(multi_store.default_store).to receive(name).with(*expected_args).and_raise(StandardError)
+ allow(multi_store.default_store).to receive(name).with(*args).and_raise(StandardError)
allow(Gitlab::ErrorTracking).to receive(:log_exception)
end
it 'raises error and does not execute on non default instance', :aggregate_failures do
- expect(multi_store.non_default_store).not_to receive(name).with(*expected_args)
+ expect(multi_store.non_default_store).not_to receive(name).with(*args)
expect { subject }.to raise_error(StandardError)
end
end
context 'when executing on the non default instance is raising an exception' do
before do
- allow(multi_store.non_default_store).to receive(name).with(*expected_args).and_raise(StandardError)
+ allow(multi_store.non_default_store).to receive(name).with(*args).and_raise(StandardError)
allow(Gitlab::ErrorTracking).to receive(:log_exception)
end
it 'logs the exception and execute on default instance', :aggregate_failures do
expect(Gitlab::ErrorTracking).to receive(:log_exception).with(an_instance_of(StandardError),
- hash_including(:multi_store_error_message, command_name: name, instance_name: instance_name))
- expect(multi_store.default_store).to receive(name).with(*expected_args).and_call_original
+ hash_including(:multi_store_error_message,
+ command_name: name, instance_name: instance_name))
+ expect(multi_store.default_store).to receive(name).with(*args)
subject
end
-
- include_examples 'verify that store contains values', :default_store
end
context 'when the command is executed within pipelined block' do
@@ -602,24 +371,35 @@ RSpec.describe Gitlab::Redis::MultiStore, feature_category: :redis do
it 'is executed only 1 time on each instance', :aggregate_failures do
expect(primary_store).to receive(:pipelined).and_call_original
expect_next_instance_of(Redis::PipelinedConnection) do |pipeline|
- expect(pipeline).to receive(name).with(*expected_args).once.and_call_original
+ expect(pipeline).to receive(name).with(*args).once
end
expect(secondary_store).to receive(:pipelined).and_call_original
expect_next_instance_of(Redis::PipelinedConnection) do |pipeline|
- expect(pipeline).to receive(name).with(*expected_args).once.and_call_original
+ expect(pipeline).to receive(name).with(*args).once
end
subject
end
-
- include_examples 'verify that store contains values', :primary_store
- include_examples 'verify that store contains values', :secondary_store
end
end
end
end
- # rubocop:enable RSpec/MultipleMemoizedHelpers
+
+ RSpec.shared_examples_for 'verify that store contains values' do |store|
+ it "#{store} redis store contains correct values", :aggregate_failures do
+ subject
+
+ redis_store = multi_store.send(store)
+
+ if expected_value.is_a?(Array)
+ # :smembers does not guarantee the order it will return the values
+ expect(redis_store.send(verification_name, *verification_args)).to match_array(expected_value)
+ else
+ expect(redis_store.send(verification_name, *verification_args)).to eq(expected_value)
+ end
+ end
+ end
RSpec.shared_examples_for 'pipelined command' do |name|
let_it_be(:key1) { "redis:{1}:key_a" }
@@ -951,11 +731,7 @@ RSpec.describe Gitlab::Redis::MultiStore, feature_category: :redis do
describe '#close' do
subject { multi_store.close }
- context 'when using both stores' do
- before do
- allow(multi_store).to receive(:use_primary_and_secondary_stores?).and_return(true)
- end
-
+ context 'when using both stores are different' do
it 'closes both stores' do
expect(primary_store).to receive(:close)
expect(secondary_store).to receive(:close)
@@ -964,36 +740,72 @@ RSpec.describe Gitlab::Redis::MultiStore, feature_category: :redis do
end
end
- context 'when using only one store' do
+ context 'when using identical stores' do
before do
- allow(multi_store).to receive(:use_primary_and_secondary_stores?).and_return(false)
+ allow(multi_store).to receive(:same_redis_store?).and_return(true)
end
- context 'when using primary_store as default store' do
- before do
- allow(multi_store).to receive(:use_primary_store_as_default?).and_return(true)
- end
+ it 'closes secondary store' do
+ expect(secondary_store).to receive(:close)
+ expect(primary_store).not_to receive(:close)
- it 'closes primary store' do
- expect(primary_store).to receive(:close)
- expect(secondary_store).not_to receive(:close)
+ subject
+ end
+ end
+ end
- subject
- end
+ describe '#blpop' do
+ let_it_be(:key) { "mylist" }
+
+ subject { multi_store.blpop(key, timeout: 0.1) }
+
+ shared_examples 'calls blpop on default_store' do
+ it 'calls blpop on default_store' do
+ expect(multi_store.default_store).to receive(:blpop).with(key, { timeout: 0.1 })
+
+ subject
end
+ end
- context 'when using secondary_store as default store' do
+ shared_examples 'does not call lpop on non_default_store' do
+ it 'does not call blpop on non_default_store' do
+ expect(multi_store.non_default_store).not_to receive(:blpop)
+
+ subject
+ end
+ end
+
+ context 'when using both stores' do
+ before do
+ allow(multi_store).to receive(:use_primary_and_secondary_stores?).and_return(true)
+ end
+
+ it_behaves_like 'calls blpop on default_store'
+
+ context "when an element exists in the default_store" do
before do
- allow(multi_store).to receive(:use_primary_store_as_default?).and_return(false)
+ multi_store.default_store.lpush(key, 'abc')
end
- it 'closes secondary store' do
- expect(primary_store).not_to receive(:close)
- expect(secondary_store).to receive(:close)
+ it 'calls lpop on non_default_store' do
+ expect(multi_store.non_default_store).to receive(:blpop).with(key, { timeout: 1 })
subject
end
end
+
+ context 'when the list is empty in default_store' do
+ it_behaves_like 'does not call lpop on non_default_store'
+ end
+ end
+
+ context 'when using one store' do
+ before do
+ allow(multi_store).to receive(:use_primary_and_secondary_stores?).and_return(false)
+ end
+
+ it_behaves_like 'calls blpop on default_store'
+ it_behaves_like 'does not call lpop on non_default_store'
end
end
@@ -1279,4 +1091,19 @@ RSpec.describe Gitlab::Redis::MultiStore, feature_category: :redis do
end
end
end
+
+ describe '*_COMMANDS' do
+ it 'checks if every command is only defined once' do
+ commands = [
+ described_class::REDIS_CLIENT_COMMANDS,
+ described_class::PUBSUB_SUBSCRIBE_COMMANDS,
+ described_class::READ_COMMANDS,
+ described_class::WRITE_COMMANDS,
+ described_class::PIPELINED_COMMANDS
+ ].inject([], :concat)
+ duplicated_commands = commands.group_by { |c| c }.select { |k, v| v.size > 1 }.map(&:first)
+
+ expect(duplicated_commands).to be_empty, "commands #{duplicated_commands} defined more than once"
+ end
+ end
end
diff --git a/spec/lib/gitlab/redis/pubsub_spec.rb b/spec/lib/gitlab/redis/pubsub_spec.rb
deleted file mode 100644
index e196d02116e..00000000000
--- a/spec/lib/gitlab/redis/pubsub_spec.rb
+++ /dev/null
@@ -1,8 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-RSpec.describe Gitlab::Redis::Pubsub, feature_category: :redis do
- include_examples "redis_new_instance_shared_examples", 'pubsub', Gitlab::Redis::SharedState
- include_examples "redis_shared_examples"
-end
diff --git a/spec/lib/gitlab/reference_extractor_spec.rb b/spec/lib/gitlab/reference_extractor_spec.rb
index 37db13b76b9..9b8143f7bb8 100644
--- a/spec/lib/gitlab/reference_extractor_spec.rb
+++ b/spec/lib/gitlab/reference_extractor_spec.rb
@@ -31,7 +31,7 @@ RSpec.describe Gitlab::ReferenceExtractor do
project.add_reporter(@u_foo)
project.add_reporter(@u_bar)
- subject.analyze(%{
+ subject.analyze(%(
Inline code: `@foo`
Code block:
@@ -43,7 +43,7 @@ RSpec.describe Gitlab::ReferenceExtractor do
Quote:
> @offteam
- })
+ ))
expect(subject.users).to match_array([])
end
diff --git a/spec/lib/gitlab/regex_requires_app_spec.rb b/spec/lib/gitlab/regex_requires_app_spec.rb
index bea5d25dbc8..7a247e5e8cf 100644
--- a/spec/lib/gitlab/regex_requires_app_spec.rb
+++ b/spec/lib/gitlab/regex_requires_app_spec.rb
@@ -5,6 +5,18 @@ require 'spec_helper'
# Only specs that *cannot* be run with fast_spec_helper only
# See regex_spec for tests that do not require the full spec_helper
RSpec.describe Gitlab::Regex, feature_category: :tooling do
+ shared_examples_for 'npm package name regex' do
+ it { is_expected.to match('@scope/package') }
+ it { is_expected.to match('unscoped-package') }
+ it { is_expected.not_to match('@first-scope@second-scope/package') }
+ it { is_expected.not_to match('scope-without-at-symbol/package') }
+ it { is_expected.not_to match('@not-a-scoped-package') }
+ it { is_expected.not_to match('@scope/sub/package') }
+ it { is_expected.not_to match('@scope/../../package') }
+ it { is_expected.not_to match('@scope%2e%2e%2fpackage') }
+ it { is_expected.not_to match('@%2e%2e%2f/package') }
+ end
+
describe '.debian_architecture_regex' do
subject { described_class.debian_architecture_regex }
@@ -37,15 +49,7 @@ RSpec.describe Gitlab::Regex, feature_category: :tooling do
describe '.npm_package_name_regex' do
subject { described_class.npm_package_name_regex }
- it { is_expected.to match('@scope/package') }
- it { is_expected.to match('unscoped-package') }
- it { is_expected.not_to match('@first-scope@second-scope/package') }
- it { is_expected.not_to match('scope-without-at-symbol/package') }
- it { is_expected.not_to match('@not-a-scoped-package') }
- it { is_expected.not_to match('@scope/sub/package') }
- it { is_expected.not_to match('@scope/../../package') }
- it { is_expected.not_to match('@scope%2e%2e%2fpackage') }
- it { is_expected.not_to match('@%2e%2e%2f/package') }
+ it_behaves_like 'npm package name regex'
context 'capturing group' do
[
@@ -63,6 +67,24 @@ RSpec.describe Gitlab::Regex, feature_category: :tooling do
end
end
+ describe '.protection_rules_npm_package_name_pattern_regex' do
+ subject { described_class.protection_rules_npm_package_name_pattern_regex }
+
+ it_behaves_like 'npm package name regex'
+
+ it { is_expected.to match('@scope/package-*') }
+ it { is_expected.to match('@my-scope/*my-package-with-wildcard-inbetween') }
+ it { is_expected.to match('@my-scope/*my-package-with-wildcard-start') }
+ it { is_expected.to match('@my-scope/my-*package-*with-wildcard-multiple-*') }
+ it { is_expected.to match('@my-scope/my-package-with_____underscore') }
+ it { is_expected.to match('@my-scope/my-package-with-wildcard-end*') }
+ it { is_expected.to match('@my-scope/my-package-with-regex-characters.+') }
+
+ it { is_expected.not_to match('@my-scope/my-package-with-percent-sign-%') }
+ it { is_expected.not_to match('*@my-scope/my-package-with-wildcard-start') }
+ it { is_expected.not_to match('@my-scope/my-package-with-backslash-\*') }
+ end
+
describe '.debian_distribution_regex' do
subject { described_class.debian_distribution_regex }
diff --git a/spec/lib/gitlab/repository_cache_adapter_spec.rb b/spec/lib/gitlab/repository_cache_adapter_spec.rb
index 71a20cc58fd..c35038b3b75 100644
--- a/spec/lib/gitlab/repository_cache_adapter_spec.rb
+++ b/spec/lib/gitlab/repository_cache_adapter_spec.rb
@@ -15,7 +15,7 @@ RSpec.describe Gitlab::RepositoryCacheAdapter do
include Gitlab::RepositoryCacheAdapter # can't use described_class here
def letters
- %w(b a c)
+ %w[b a c]
end
cache_method_as_redis_set(:letters)
@@ -47,11 +47,11 @@ RSpec.describe Gitlab::RepositoryCacheAdapter do
expect(fake_repository).to receive(:_uncached_letters).once.and_call_original
2.times do
- expect(fake_repository.letters).to eq(%w(a b c))
+ expect(fake_repository.letters).to eq(%w[a b c])
end
expect(redis_set_cache.exist?(:letters)).to eq(true)
- expect(fake_repository.instance_variable_get(:@letters)).to eq(%w(a b c))
+ expect(fake_repository.instance_variable_get(:@letters)).to eq(%w[a b c])
end
context 'membership checks' do
@@ -69,7 +69,7 @@ RSpec.describe Gitlab::RepositoryCacheAdapter do
context 'when the cache key exists' do
before do
- redis_set_cache.write(:letters, %w(b a c))
+ redis_set_cache.write(:letters, %w[b a c])
end
it 'calls #try_include? on the set cache' do
@@ -300,7 +300,7 @@ RSpec.describe Gitlab::RepositoryCacheAdapter do
expect(redis_set_cache).to receive(:expire).with(:branch_names)
expect(redis_hash_cache).to receive(:delete).with(:branch_names)
- repository.expire_method_caches(%i(branch_names))
+ repository.expire_method_caches(%i[branch_names])
end
it 'does not expire caches for non-existent methods' do
@@ -308,7 +308,7 @@ RSpec.describe Gitlab::RepositoryCacheAdapter do
expect(Gitlab::AppLogger).to(
receive(:error).with("Requested to expire non-existent method 'nonexistent' for Repository"))
- repository.expire_method_caches(%i(nonexistent))
+ repository.expire_method_caches(%i[nonexistent])
end
end
end
diff --git a/spec/lib/gitlab/repository_hash_cache_spec.rb b/spec/lib/gitlab/repository_hash_cache_spec.rb
index e3cc6ed69fb..4b4a2092c98 100644
--- a/spec/lib/gitlab/repository_hash_cache_spec.rb
+++ b/spec/lib/gitlab/repository_hash_cache_spec.rb
@@ -88,7 +88,7 @@ RSpec.describe Gitlab::RepositoryHashCache, :clean_gitlab_redis_repository_cache
describe "#read_members" do
subject { cache.read_members(:example, keys) }
- let(:keys) { %w(test missing) }
+ let(:keys) { %w[test missing] }
context "all data is cached" do
before do
@@ -140,7 +140,7 @@ RSpec.describe Gitlab::RepositoryHashCache, :clean_gitlab_redis_repository_cache
end
end
- let(:keys) { %w(test) }
+ let(:keys) { %w[test] }
it "records metrics" do
# Here we expect it to receive "test" as a missing key because we
@@ -151,7 +151,7 @@ RSpec.describe Gitlab::RepositoryHashCache, :clean_gitlab_redis_repository_cache
end
context "fully cached" do
- let(:keys) { %w(test another) }
+ let(:keys) { %w[test another] }
before do
cache.write(:example, test_hash.merge({ "another" => "not_missing" }))
@@ -169,7 +169,7 @@ RSpec.describe Gitlab::RepositoryHashCache, :clean_gitlab_redis_repository_cache
end
context "partially cached" do
- let(:keys) { %w(test missing) }
+ let(:keys) { %w[test missing] }
before do
cache.write(:example, test_hash)
@@ -187,7 +187,7 @@ RSpec.describe Gitlab::RepositoryHashCache, :clean_gitlab_redis_repository_cache
end
context "uncached" do
- let(:keys) { %w(test missing) }
+ let(:keys) { %w[test missing] }
it "returns a hash" do
is_expected.to eq({ "test" => "was_missing", "missing" => "was_missing" })
diff --git a/spec/lib/gitlab/repository_set_cache_spec.rb b/spec/lib/gitlab/repository_set_cache_spec.rb
index 23b2a2b9493..42378a16046 100644
--- a/spec/lib/gitlab/repository_set_cache_spec.rb
+++ b/spec/lib/gitlab/repository_set_cache_spec.rb
@@ -90,7 +90,7 @@ RSpec.describe Gitlab::RepositorySetCache, :clean_gitlab_redis_repository_cache,
end
context 'single key' do
- let(:keys) { %w(foo) }
+ let(:keys) { %w[foo] }
it { is_expected.to eq(1) }
@@ -102,7 +102,7 @@ RSpec.describe Gitlab::RepositorySetCache, :clean_gitlab_redis_repository_cache,
end
context 'multiple keys' do
- let(:keys) { %w(foo bar) }
+ let(:keys) { %w[foo bar] }
it { is_expected.to eq(2) }
diff --git a/spec/lib/gitlab/rugged_instrumentation_spec.rb b/spec/lib/gitlab/rugged_instrumentation_spec.rb
deleted file mode 100644
index 393bb957aba..00000000000
--- a/spec/lib/gitlab/rugged_instrumentation_spec.rb
+++ /dev/null
@@ -1,27 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-RSpec.describe Gitlab::RuggedInstrumentation, :request_store do
- subject { described_class }
-
- describe '.query_time' do
- it 'increments query times' do
- subject.add_query_time(0.4510004)
- subject.add_query_time(0.3220004)
-
- expect(subject.query_time).to eq(0.773001)
- expect(subject.query_time_ms).to eq(773.0)
- end
- end
-
- describe '.increment_query_count' do
- it 'tracks query counts' do
- expect(subject.query_count).to eq(0)
-
- 2.times { subject.increment_query_count }
-
- expect(subject.query_count).to eq(2)
- end
- end
-end
diff --git a/spec/lib/gitlab/runtime_spec.rb b/spec/lib/gitlab/runtime_spec.rb
index 01cfa91bb59..05bcdf2fc96 100644
--- a/spec/lib/gitlab/runtime_spec.rb
+++ b/spec/lib/gitlab/runtime_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Gitlab::Runtime, feature_category: :application_performance do
+RSpec.describe Gitlab::Runtime, feature_category: :cloud_connector do
shared_examples "valid runtime" do |runtime, max_threads|
it "identifies itself" do
expect(subject.identify).to eq(runtime)
diff --git a/spec/lib/gitlab/search/abuse_detection_spec.rb b/spec/lib/gitlab/search/abuse_detection_spec.rb
index cbf20614ba5..d244234e763 100644
--- a/spec/lib/gitlab/search/abuse_detection_spec.rb
+++ b/spec/lib/gitlab/search/abuse_detection_spec.rb
@@ -20,7 +20,7 @@ RSpec.describe Gitlab::Search::AbuseDetection, feature_category: :global_search
end
describe 'abusive character matching' do
- refs = %w(
+ refs = %w[
main
тест
maiñ
@@ -30,7 +30,7 @@ RSpec.describe Gitlab::Search::AbuseDetection, feature_category: :global_search
feature/it_works
really_important!
测试
- )
+ ]
refs.each do |ref|
it "does match refs permitted by git refname: #{ref}" do
diff --git a/spec/lib/gitlab/search_results_spec.rb b/spec/lib/gitlab/search_results_spec.rb
index 00e68f73d2d..a3acb8b92ed 100644
--- a/spec/lib/gitlab/search_results_spec.rb
+++ b/spec/lib/gitlab/search_results_spec.rb
@@ -99,7 +99,7 @@ RSpec.describe Gitlab::SearchResults, feature_category: :global_search do
describe '#aggregations' do
where(:scope) do
- %w(projects issues merge_requests blobs commits wiki_blobs epics milestones users unknown)
+ %w[projects issues merge_requests blobs commits wiki_blobs epics milestones users unknown]
end
with_them do
@@ -197,7 +197,7 @@ RSpec.describe Gitlab::SearchResults, feature_category: :global_search do
let(:query) { 'foo' }
include_examples 'search results filtered by state'
- include_examples 'search results filtered by archived', 'search_merge_requests_hide_archived_projects'
+ include_examples 'search results filtered by archived'
end
context 'ordering' do
@@ -244,7 +244,7 @@ RSpec.describe Gitlab::SearchResults, feature_category: :global_search do
include_examples 'search results filtered by state'
include_examples 'search results filtered by confidential'
- include_examples 'search results filtered by archived', 'search_issues_hide_archived_projects'
+ include_examples 'search results filtered by archived'
end
context 'ordering' do
diff --git a/spec/lib/gitlab/security/scan_configuration_spec.rb b/spec/lib/gitlab/security/scan_configuration_spec.rb
index faa8a206d74..9151db3c5ff 100644
--- a/spec/lib/gitlab/security/scan_configuration_spec.rb
+++ b/spec/lib/gitlab/security/scan_configuration_spec.rb
@@ -15,7 +15,7 @@ RSpec.describe ::Gitlab::Security::ScanConfiguration do
let(:configured) { true }
context 'with a core scanner' do
- where(type: %i(sast sast_iac secret_detection container_scanning))
+ where(type: %i[sast sast_iac secret_detection container_scanning])
with_them do
it { is_expected.to be_truthy }
@@ -73,7 +73,7 @@ RSpec.describe ::Gitlab::Security::ScanConfiguration do
let(:configured) { true }
context 'with a core scanner' do
- where(type: %i(sast sast_iac secret_detection))
+ where(type: %i[sast sast_iac secret_detection])
with_them do
it { is_expected.to be_truthy }
diff --git a/spec/lib/gitlab/seeders/ci/catalog/resource_seeder_spec.rb b/spec/lib/gitlab/seeders/ci/catalog/resource_seeder_spec.rb
new file mode 100644
index 00000000000..4bd4455d1bd
--- /dev/null
+++ b/spec/lib/gitlab/seeders/ci/catalog/resource_seeder_spec.rb
@@ -0,0 +1,101 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe ::Gitlab::Seeders::Ci::Catalog::ResourceSeeder, feature_category: :pipeline_composition do
+ let_it_be(:admin) { create(:admin) }
+ let_it_be_with_reload(:group) { create(:group) }
+ let_it_be(:seed_count) { 2 }
+ let_it_be(:last_resource_id) { seed_count - 1 }
+
+ let(:group_path) { group.path }
+
+ subject(:seeder) { described_class.new(group_path: group_path, seed_count: seed_count) }
+
+ before_all do
+ group.add_owner(admin)
+ end
+
+ describe '#seed' do
+ subject(:seed) { seeder.seed }
+
+ context 'when the group does not exists' do
+ let(:group_path) { 'nonexistent_group' }
+
+ it 'skips seeding' do
+ expect { seed }.not_to change { Project.count }
+ end
+ end
+
+ context 'when project name already exists' do
+ before do
+ create(:project, namespace: group, name: "ci_seed_resource_0")
+ end
+
+ it 'skips that project creation and keeps seeding' do
+ expect { seed }.to change { Project.count }.by(seed_count - 1)
+ end
+ end
+
+ context 'when project.saved? fails' do
+ before do
+ project = build(:project, name: nil)
+
+ allow_next_instance_of(::Projects::CreateService) do |service|
+ allow(service).to receive(:execute).and_return(project)
+ end
+ end
+
+ it 'does not modify the projects count' do
+ expect { seed }.not_to change { Project.count }
+ end
+ end
+
+ context 'when ci resource creation fails' do
+ before do
+ allow_next_instance_of(::Ci::Catalog::Resources::CreateService) do |service|
+ allow(service).to receive(:execute).and_return(ServiceResponse.error(message: 'error'))
+ end
+ end
+
+ it 'does not add a catalog resource' do
+ expect { seed }.to change { Project.count }.by(seed_count)
+
+ expect(group.projects.all?(&:catalog_resource)).to eq false
+ end
+ end
+
+ it 'skips seeding a project if the project name already exists' do
+ # We call the same command twice, as it means it would try to recreate
+ # projects that were already created!
+ expect { seed }.to change { group.projects.count }.by(seed_count)
+ expect { seed }.to change { group.projects.count }.by(0)
+ end
+
+ it 'creates as many projects as specific in the argument' do
+ expect { seed }.to change {
+ group.projects.count
+ }.by(seed_count)
+
+ last_ci_resource = Project.last
+
+ expect(last_ci_resource.name).to eq "ci_seed_resource_#{last_resource_id}"
+ end
+
+ it 'adds a README and a template.yml file to the projects' do
+ seed
+ project = group.projects.last
+ default_branch = project.default_branch_or_main
+
+ expect(project.repository.blob_at(default_branch, "README.md")).not_to be_nil
+ expect(project.repository.blob_at(default_branch, "template.yml")).not_to be_nil
+ end
+
+ # This should be run again when fixing: https://gitlab.com/gitlab-org/gitlab/-/issues/429649
+ xit 'creates projects with CI catalog resources' do
+ expect { seed }.to change { Project.count }.by(seed_count)
+
+ expect(group.projects.all?(&:catalog_resource)).to eq true
+ end
+ end
+end
diff --git a/spec/lib/gitlab/shard_health_cache_spec.rb b/spec/lib/gitlab/shard_health_cache_spec.rb
index 0c25cc7dab5..8d0eebbb23e 100644
--- a/spec/lib/gitlab/shard_health_cache_spec.rb
+++ b/spec/lib/gitlab/shard_health_cache_spec.rb
@@ -3,7 +3,7 @@
require 'spec_helper'
RSpec.describe Gitlab::ShardHealthCache, :clean_gitlab_redis_cache do
- let(:shards) { %w(foo bar) }
+ let(:shards) { %w[foo bar] }
before do
described_class.update(shards) # rubocop:disable Rails/SaveBang
@@ -23,7 +23,7 @@ RSpec.describe Gitlab::ShardHealthCache, :clean_gitlab_redis_cache do
end
it 'replaces the existing set' do
- new_set = %w(test me more)
+ new_set = %w[test me more]
described_class.update(new_set) # rubocop:disable Rails/SaveBang
expect(described_class.cached_healthy_shards).to match_array(new_set)
diff --git a/spec/lib/gitlab/sidekiq_config/cli_methods_spec.rb b/spec/lib/gitlab/sidekiq_config/cli_methods_spec.rb
index 576b36c1829..1145fd02891 100644
--- a/spec/lib/gitlab/sidekiq_config/cli_methods_spec.rb
+++ b/spec/lib/gitlab/sidekiq_config/cli_methods_spec.rb
@@ -173,7 +173,7 @@ RSpec.describe Gitlab::SidekiqConfig::CliMethods do
end
it 'returns the queue names of matched workers' do
- expect(described_class.query_queues(query, worker_metadatas)).to match(%w(a a:2 c))
+ expect(described_class.query_queues(query, worker_metadatas)).to match(%w[a a:2 c])
end
end
end
diff --git a/spec/lib/gitlab/sidekiq_config/worker_matcher_spec.rb b/spec/lib/gitlab/sidekiq_config/worker_matcher_spec.rb
index dfe9358f70b..08ead3282fd 100644
--- a/spec/lib/gitlab/sidekiq_config/worker_matcher_spec.rb
+++ b/spec/lib/gitlab/sidekiq_config/worker_matcher_spec.rb
@@ -51,61 +51,61 @@ RSpec.describe Gitlab::SidekiqConfig::WorkerMatcher do
context 'with valid input' do
where(:query, :expected_metadatas) do
# worker_name
- 'worker_name=WorkerA' | %w(WorkerA)
- 'worker_name=WorkerA2' | %w(WorkerA2)
- 'worker_name=WorkerB|worker_name=WorkerD' | %w(WorkerB)
- 'worker_name!=WorkerA' | %w(WorkerA2 WorkerB WorkerC)
+ 'worker_name=WorkerA' | %w[WorkerA]
+ 'worker_name=WorkerA2' | %w[WorkerA2]
+ 'worker_name=WorkerB|worker_name=WorkerD' | %w[WorkerB]
+ 'worker_name!=WorkerA' | %w[WorkerA2 WorkerB WorkerC]
# feature_category
- 'feature_category=category_a' | %w(WorkerA WorkerA2)
- 'feature_category=category_a,category_c' | %w(WorkerA WorkerA2 WorkerC)
- 'feature_category=category_a|feature_category=category_c' | %w(WorkerA WorkerA2 WorkerC)
- 'feature_category!=category_a' | %w(WorkerB WorkerC)
+ 'feature_category=category_a' | %w[WorkerA WorkerA2]
+ 'feature_category=category_a,category_c' | %w[WorkerA WorkerA2 WorkerC]
+ 'feature_category=category_a|feature_category=category_c' | %w[WorkerA WorkerA2 WorkerC]
+ 'feature_category!=category_a' | %w[WorkerB WorkerC]
# has_external_dependencies
- 'has_external_dependencies=true' | %w(WorkerB)
- 'has_external_dependencies=false' | %w(WorkerA WorkerA2 WorkerC)
- 'has_external_dependencies=true,false' | %w(WorkerA WorkerA2 WorkerB WorkerC)
- 'has_external_dependencies=true|has_external_dependencies=false' | %w(WorkerA WorkerA2 WorkerB WorkerC)
- 'has_external_dependencies!=true' | %w(WorkerA WorkerA2 WorkerC)
+ 'has_external_dependencies=true' | %w[WorkerB]
+ 'has_external_dependencies=false' | %w[WorkerA WorkerA2 WorkerC]
+ 'has_external_dependencies=true,false' | %w[WorkerA WorkerA2 WorkerB WorkerC]
+ 'has_external_dependencies=true|has_external_dependencies=false' | %w[WorkerA WorkerA2 WorkerB WorkerC]
+ 'has_external_dependencies!=true' | %w[WorkerA WorkerA2 WorkerC]
# urgency
- 'urgency=high' | %w(WorkerA2 WorkerB)
- 'urgency=low' | %w(WorkerA)
- 'urgency=high,low,throttled' | %w(WorkerA WorkerA2 WorkerB WorkerC)
- 'urgency=low|urgency=throttled' | %w(WorkerA WorkerC)
- 'urgency!=high' | %w(WorkerA WorkerC)
+ 'urgency=high' | %w[WorkerA2 WorkerB]
+ 'urgency=low' | %w[WorkerA]
+ 'urgency=high,low,throttled' | %w[WorkerA WorkerA2 WorkerB WorkerC]
+ 'urgency=low|urgency=throttled' | %w[WorkerA WorkerC]
+ 'urgency!=high' | %w[WorkerA WorkerC]
# name
- 'name=a' | %w(WorkerA)
- 'name=a,b' | %w(WorkerA WorkerB)
- 'name=a,a:2|name=b' | %w(WorkerA WorkerA2 WorkerB)
- 'name!=a,a:2' | %w(WorkerB WorkerC)
+ 'name=a' | %w[WorkerA]
+ 'name=a,b' | %w[WorkerA WorkerB]
+ 'name=a,a:2|name=b' | %w[WorkerA WorkerA2 WorkerB]
+ 'name!=a,a:2' | %w[WorkerB WorkerC]
# resource_boundary
- 'resource_boundary=memory' | %w(WorkerB WorkerC)
- 'resource_boundary=memory,cpu' | %w(WorkerA WorkerB WorkerC)
- 'resource_boundary=memory|resource_boundary=cpu' | %w(WorkerA WorkerB WorkerC)
- 'resource_boundary!=memory,cpu' | %w(WorkerA2)
+ 'resource_boundary=memory' | %w[WorkerB WorkerC]
+ 'resource_boundary=memory,cpu' | %w[WorkerA WorkerB WorkerC]
+ 'resource_boundary=memory|resource_boundary=cpu' | %w[WorkerA WorkerB WorkerC]
+ 'resource_boundary!=memory,cpu' | %w[WorkerA2]
# tags
- 'tags=no_disk_io' | %w(WorkerA WorkerB)
- 'tags=no_disk_io,git_access' | %w(WorkerA WorkerA2 WorkerB)
- 'tags=no_disk_io|tags=git_access' | %w(WorkerA WorkerA2 WorkerB)
- 'tags=no_disk_io&tags=git_access' | %w(WorkerA)
- 'tags!=no_disk_io' | %w(WorkerA2 WorkerC)
- 'tags!=no_disk_io,git_access' | %w(WorkerC)
+ 'tags=no_disk_io' | %w[WorkerA WorkerB]
+ 'tags=no_disk_io,git_access' | %w[WorkerA WorkerA2 WorkerB]
+ 'tags=no_disk_io|tags=git_access' | %w[WorkerA WorkerA2 WorkerB]
+ 'tags=no_disk_io&tags=git_access' | %w[WorkerA]
+ 'tags!=no_disk_io' | %w[WorkerA2 WorkerC]
+ 'tags!=no_disk_io,git_access' | %w[WorkerC]
'tags=unknown_tag' | []
- 'tags!=no_disk_io' | %w(WorkerA2 WorkerC)
- 'tags!=no_disk_io,git_access' | %w(WorkerC)
- 'tags!=unknown_tag' | %w(WorkerA WorkerA2 WorkerB WorkerC)
+ 'tags!=no_disk_io' | %w[WorkerA2 WorkerC]
+ 'tags!=no_disk_io,git_access' | %w[WorkerC]
+ 'tags!=unknown_tag' | %w[WorkerA WorkerA2 WorkerB WorkerC]
# combinations
- 'feature_category=category_a&urgency=high' | %w(WorkerA2)
- 'feature_category=category_a&urgency=high|feature_category=category_c' | %w(WorkerA2 WorkerC)
+ 'feature_category=category_a&urgency=high' | %w[WorkerA2]
+ 'feature_category=category_a&urgency=high|feature_category=category_c' | %w[WorkerA2 WorkerC]
# Match all
- '*' | %w(WorkerA WorkerA2 WorkerB WorkerC)
+ '*' | %w[WorkerA WorkerA2 WorkerB WorkerC]
end
with_them do
diff --git a/spec/lib/gitlab/sidekiq_logging/structured_logger_spec.rb b/spec/lib/gitlab/sidekiq_logging/structured_logger_spec.rb
index 4550ccc2fff..2e07fa100e8 100644
--- a/spec/lib/gitlab/sidekiq_logging/structured_logger_spec.rb
+++ b/spec/lib/gitlab/sidekiq_logging/structured_logger_spec.rb
@@ -181,7 +181,7 @@ RSpec.describe Gitlab::SidekiqLogging::StructuredLogger do
it 'logs without created_at and enqueued_at fields' do
travel_to(timestamp) do
- excluded_fields = %w(created_at enqueued_at args scheduling_latency_s)
+ excluded_fields = %w[created_at enqueued_at args scheduling_latency_s]
expect(logger).to receive(:info).with(start_payload.except(*excluded_fields)).ordered
expect(logger).to receive(:info).with(end_payload.except(*excluded_fields)).ordered
@@ -238,13 +238,11 @@ RSpec.describe Gitlab::SidekiqLogging::StructuredLogger do
end
end
- context 'with Gitaly, Rugged, and Redis calls' do
+ context 'with Gitaly, and Redis calls' do
let(:timing_data) do
{
gitaly_calls: 10,
gitaly_duration_s: 10000,
- rugged_calls: 1,
- rugged_duration_s: 5000,
redis_calls: 3,
redis_duration_s: 1234
}
@@ -261,7 +259,7 @@ RSpec.describe Gitlab::SidekiqLogging::StructuredLogger do
end
end
- it 'logs with Gitaly and Rugged timing data', :aggregate_failures do
+ it 'logs with Gitaly timing data', :aggregate_failures do
travel_to(timestamp) do
expect(logger).to receive(:info).with(start_payload).ordered
expect(logger).to receive(:info).with(expected_end_payload).ordered
diff --git a/spec/lib/gitlab/sidekiq_middleware/duplicate_jobs/duplicate_job_spec.rb b/spec/lib/gitlab/sidekiq_middleware/duplicate_jobs/duplicate_job_spec.rb
index 7138ad04f69..dbfab116479 100644
--- a/spec/lib/gitlab/sidekiq_middleware/duplicate_jobs/duplicate_job_spec.rb
+++ b/spec/lib/gitlab/sidekiq_middleware/duplicate_jobs/duplicate_job_spec.rb
@@ -106,9 +106,21 @@ RSpec.describe Gitlab::SidekiqMiddleware::DuplicateJobs::DuplicateJob,
end
context 'when TTL option is not set' do
- let(:expected_ttl) { described_class::DEFAULT_DUPLICATE_KEY_TTL }
+ context 'when reduce_duplicate_job_key_ttl is enabled' do
+ let(:expected_ttl) { described_class::SHORT_DUPLICATE_KEY_TTL }
- it_behaves_like 'sets Redis keys with correct TTL'
+ it_behaves_like 'sets Redis keys with correct TTL'
+ end
+
+ context 'when reduce_duplicate_job_key_ttl is disabled' do
+ before do
+ stub_feature_flags(reduce_duplicate_job_key_ttl: false)
+ end
+
+ let(:expected_ttl) { described_class::DEFAULT_DUPLICATE_KEY_TTL }
+
+ it_behaves_like 'sets Redis keys with correct TTL'
+ end
end
context 'when TTL option is set' do
diff --git a/spec/lib/gitlab/sidekiq_middleware/server_metrics_spec.rb b/spec/lib/gitlab/sidekiq_middleware/server_metrics_spec.rb
index a27e723e392..9cf9901007c 100644
--- a/spec/lib/gitlab/sidekiq_middleware/server_metrics_spec.rb
+++ b/spec/lib/gitlab/sidekiq_middleware/server_metrics_spec.rb
@@ -3,7 +3,7 @@
require 'spec_helper'
# rubocop: disable RSpec/MultipleMemoizedHelpers
-RSpec.describe Gitlab::SidekiqMiddleware::ServerMetrics do
+RSpec.describe Gitlab::SidekiqMiddleware::ServerMetrics, feature_category: :shared do
shared_examples "a metrics middleware" do
context "with mocked prometheus" do
include_context 'server metrics with mocked prometheus'
@@ -452,11 +452,6 @@ RSpec.describe Gitlab::SidekiqMiddleware::ServerMetrics do
end
context 'when emit_sidekiq_histogram_metrics FF is disabled' do
- include_context 'server metrics with mocked prometheus'
- include_context 'server metrics call' do
- let(:stub_subject) { false }
- end
-
subject(:middleware) { described_class.new }
let(:job) { {} }
@@ -484,16 +479,38 @@ RSpec.describe Gitlab::SidekiqMiddleware::ServerMetrics do
stub_feature_flags(emit_sidekiq_histogram_metrics: false)
end
+ # include_context below must run after stubbing FF above because
+ # the middleware initialization depends on the FF and it's being initialized
+ # in the 'server metrics call' shared_context
+ include_context 'server metrics with mocked prometheus'
+ include_context 'server metrics call'
+
it 'does not emit histogram metrics' do
expect(completion_seconds_metric).not_to receive(:observe)
expect(queue_duration_seconds).not_to receive(:observe)
expect(failed_total_metric).not_to receive(:increment)
+ expect(user_execution_seconds_metric).not_to receive(:observe)
+ expect(db_seconds_metric).not_to receive(:observe)
+ expect(gitaly_seconds_metric).not_to receive(:observe)
+ expect(redis_seconds_metric).not_to receive(:observe)
+ expect(elasticsearch_seconds_metric).not_to receive(:observe)
middleware.call(worker, job, queue) { nil }
end
- it 'emits sidekiq_jobs_completion_seconds_sum metric' do
+ it 'emits sidekiq_jobs_completion_seconds sum and count metric' do
expect(completion_seconds_sum_metric).to receive(:increment).with(labels, monotonic_time_duration)
+ expect(completion_count_metric).to receive(:increment).with(labels, 1)
+
+ middleware.call(worker, job, queue) { nil }
+ end
+
+ it 'emits resource usage sum metrics' do
+ expect(cpu_seconds_sum_metric).to receive(:increment).with(labels, thread_cputime_duration)
+ expect(db_seconds_sum_metric).to receive(:increment).with(labels, db_duration)
+ expect(gitaly_seconds_sum_metric).to receive(:increment).with(labels, gitaly_duration)
+ expect(redis_seconds_sum_metric).to receive(:increment).with(labels, redis_duration)
+ expect(elasticsearch_seconds_sum_metric).to receive(:increment).with(labels, elasticsearch_duration)
middleware.call(worker, job, queue) { nil }
end
diff --git a/spec/lib/gitlab/sidekiq_middleware/skip_jobs_spec.rb b/spec/lib/gitlab/sidekiq_middleware/skip_jobs_spec.rb
index 2fa0e44d44f..6df77c350e2 100644
--- a/spec/lib/gitlab/sidekiq_middleware/skip_jobs_spec.rb
+++ b/spec/lib/gitlab/sidekiq_middleware/skip_jobs_spec.rb
@@ -185,6 +185,21 @@ RSpec.describe Gitlab::SidekiqMiddleware::SkipJobs, feature_category: :scalabili
TestWorker.perform_async(*job['args'])
end
end
+
+ context 'when a block is provided' do
+ before do
+ TestWorker.defer_on_database_health_signal(*health_signal_attrs.values) do
+ [:gitlab_ci, [:ci_pipelines]]
+ end
+ end
+
+ it 'uses the lazy evaluated schema and tables returned by the block' do
+ expect(Gitlab::Database::HealthStatus::Context).to receive(:new)
+ .with(anything, anything, [:ci_pipelines], :gitlab_ci).and_call_original
+
+ expect { |b| subject.call(TestWorker.new, job, queue, &b) }.to yield_control
+ end
+ end
end
end
end
diff --git a/spec/lib/gitlab/sidekiq_middleware/worker_context/client_spec.rb b/spec/lib/gitlab/sidekiq_middleware/worker_context/client_spec.rb
index 4fbc64a45d6..0f8d84d13ec 100644
--- a/spec/lib/gitlab/sidekiq_middleware/worker_context/client_spec.rb
+++ b/spec/lib/gitlab/sidekiq_middleware/worker_context/client_spec.rb
@@ -73,7 +73,7 @@ RSpec.describe Gitlab::SidekiqMiddleware::WorkerContext::Client do
'job2' => build_stubbed(:user, username: 'user-2') }
TestWithContextWorker.bulk_perform_async_with_contexts(
- %w(job1 job2),
+ %w[job1 job2],
arguments_proc: -> (name) { [name, 1, 2, 3] },
context_proc: -> (name) { { user: user_per_job[name] } }
)
@@ -88,7 +88,7 @@ RSpec.describe Gitlab::SidekiqMiddleware::WorkerContext::Client do
context 'when the feature category is set in the context_proc' do
it 'takes the feature category from the worker, not the caller' do
TestWithContextWorker.bulk_perform_async_with_contexts(
- %w(job1 job2),
+ %w[job1 job2],
arguments_proc: -> (name) { [name, 1, 2, 3] },
context_proc: -> (_) { { feature_category: 'code_review' } }
)
@@ -102,7 +102,7 @@ RSpec.describe Gitlab::SidekiqMiddleware::WorkerContext::Client do
it 'takes the feature category from the caller if the worker is not owned' do
TestNotOwnedWithContextWorker.bulk_perform_async_with_contexts(
- %w(job1 job2),
+ %w[job1 job2],
arguments_proc: -> (name) { [name, 1, 2, 3] },
context_proc: -> (_) { { feature_category: 'code_review' } }
)
@@ -125,7 +125,7 @@ RSpec.describe Gitlab::SidekiqMiddleware::WorkerContext::Client do
it 'takes the feature category from the worker, not the caller' do
Gitlab::ApplicationContext.with_context(feature_category: 'system_access') do
TestWithContextWorker.bulk_perform_async_with_contexts(
- %w(job1 job2),
+ %w[job1 job2],
arguments_proc: -> (name) { [name, 1, 2, 3] },
context_proc: -> (_) { {} }
)
@@ -141,7 +141,7 @@ RSpec.describe Gitlab::SidekiqMiddleware::WorkerContext::Client do
it 'takes the feature category from the caller if the worker is not owned' do
Gitlab::ApplicationContext.with_context(feature_category: 'system_access') do
TestNotOwnedWithContextWorker.bulk_perform_async_with_contexts(
- %w(job1 job2),
+ %w[job1 job2],
arguments_proc: -> (name) { [name, 1, 2, 3] },
context_proc: -> (_) { {} }
)
diff --git a/spec/lib/gitlab/sidekiq_status_spec.rb b/spec/lib/gitlab/sidekiq_status_spec.rb
index 7f1504a8df9..a555e6a828a 100644
--- a/spec/lib/gitlab/sidekiq_status_spec.rb
+++ b/spec/lib/gitlab/sidekiq_status_spec.rb
@@ -55,13 +55,13 @@ RSpec.describe Gitlab::SidekiqStatus, :clean_gitlab_redis_queues, :clean_gitlab_
describe '.all_completed?' do
it 'returns true if all jobs have been completed' do
- expect(described_class.all_completed?(%w(123))).to eq(true)
+ expect(described_class.all_completed?(%w[123])).to eq(true)
end
it 'returns false if a job has not yet been completed' do
described_class.set('123')
- expect(described_class.all_completed?(%w(123 456))).to eq(false)
+ expect(described_class.all_completed?(%w[123 456])).to eq(false)
end
end
@@ -79,40 +79,40 @@ RSpec.describe Gitlab::SidekiqStatus, :clean_gitlab_redis_queues, :clean_gitlab_
describe '.num_running' do
it 'returns 0 if all jobs have been completed' do
- expect(described_class.num_running(%w(123))).to eq(0)
+ expect(described_class.num_running(%w[123])).to eq(0)
end
it 'returns 2 if two jobs are still running' do
described_class.set('123')
described_class.set('456')
- expect(described_class.num_running(%w(123 456 789))).to eq(2)
+ expect(described_class.num_running(%w[123 456 789])).to eq(2)
end
end
describe '.num_completed' do
it 'returns 1 if all jobs have been completed' do
- expect(described_class.num_completed(%w(123))).to eq(1)
+ expect(described_class.num_completed(%w[123])).to eq(1)
end
it 'returns 1 if a job has not yet been completed' do
described_class.set('123')
described_class.set('456')
- expect(described_class.num_completed(%w(123 456 789))).to eq(1)
+ expect(described_class.num_completed(%w[123 456 789])).to eq(1)
end
end
describe '.completed_jids' do
it 'returns the completed job' do
- expect(described_class.completed_jids(%w(123))).to eq(['123'])
+ expect(described_class.completed_jids(%w[123])).to eq(['123'])
end
it 'returns only the jobs completed' do
described_class.set('123')
described_class.set('456')
- expect(described_class.completed_jids(%w(123 456 789))).to eq(['789'])
+ expect(described_class.completed_jids(%w[123 456 789])).to eq(['789'])
end
end
@@ -122,7 +122,7 @@ RSpec.describe Gitlab::SidekiqStatus, :clean_gitlab_redis_queues, :clean_gitlab_
described_class.set('456')
described_class.unset('123')
- expect(described_class.job_status(%w(123 456 789))).to eq([false, true, false])
+ expect(described_class.job_status(%w[123 456 789])).to eq([false, true, false])
end
it 'handles an empty array' do
@@ -140,7 +140,7 @@ RSpec.describe Gitlab::SidekiqStatus, :clean_gitlab_redis_queues, :clean_gitlab_
expect(Gitlab::Redis::SidekiqStatus).to receive(:with).and_call_original
expect(Sidekiq).not_to receive(:redis)
- described_class.job_status(%w(123 456 789))
+ described_class.job_status(%w[123 456 789])
end
it_behaves_like 'tracking status in redis'
@@ -160,7 +160,7 @@ RSpec.describe Gitlab::SidekiqStatus, :clean_gitlab_redis_queues, :clean_gitlab_
expect(Sidekiq).to receive(:redis).and_call_original
expect(Gitlab::Redis::SidekiqStatus).not_to receive(:with)
- described_class.job_status(%w(123 456 789))
+ described_class.job_status(%w[123 456 789])
end
it_behaves_like 'tracking status in redis'
diff --git a/spec/lib/gitlab/ssh_public_key_spec.rb b/spec/lib/gitlab/ssh_public_key_spec.rb
index d4b0b1ea53b..df9f04eb7a0 100644
--- a/spec/lib/gitlab/ssh_public_key_spec.rb
+++ b/spec/lib/gitlab/ssh_public_key_spec.rb
@@ -87,28 +87,28 @@ RSpec.describe Gitlab::SSHPublicKey, lib: true, fips_mode: false do
describe '.supported_algorithms' do
it 'returns all supported algorithms' do
expect(described_class.supported_algorithms).to eq(
- %w(
+ %w[
ssh-rsa
ssh-dss
ecdsa-sha2-nistp256 ecdsa-sha2-nistp384 ecdsa-sha2-nistp521
ssh-ed25519
sk-ecdsa-sha2-nistp256@openssh.com
sk-ssh-ed25519@openssh.com
- )
+ ]
)
end
context 'FIPS mode', :fips_mode do
it 'returns all supported algorithms' do
expect(described_class.supported_algorithms).to eq(
- %w(
+ %w[
ssh-rsa
ssh-dss
ecdsa-sha2-nistp256 ecdsa-sha2-nistp384 ecdsa-sha2-nistp521
ssh-ed25519
sk-ecdsa-sha2-nistp256@openssh.com
sk-ssh-ed25519@openssh.com
- )
+ ]
)
end
end
@@ -117,12 +117,12 @@ RSpec.describe Gitlab::SSHPublicKey, lib: true, fips_mode: false do
describe '.supported_algorithms_for_name' do
where(:name, :algorithms) do
[
- [:rsa, %w(ssh-rsa)],
- [:dsa, %w(ssh-dss)],
- [:ecdsa, %w(ecdsa-sha2-nistp256 ecdsa-sha2-nistp384 ecdsa-sha2-nistp521)],
- [:ed25519, %w(ssh-ed25519)],
- [:ecdsa_sk, %w(sk-ecdsa-sha2-nistp256@openssh.com)],
- [:ed25519_sk, %w(sk-ssh-ed25519@openssh.com)]
+ [:rsa, %w[ssh-rsa]],
+ [:dsa, %w[ssh-dss]],
+ [:ecdsa, %w[ecdsa-sha2-nistp256 ecdsa-sha2-nistp384 ecdsa-sha2-nistp521]],
+ [:ed25519, %w[ssh-ed25519]],
+ [:ecdsa_sk, %w[sk-ecdsa-sha2-nistp256@openssh.com]],
+ [:ed25519_sk, %w[sk-ssh-ed25519@openssh.com]]
]
end
@@ -136,12 +136,12 @@ RSpec.describe Gitlab::SSHPublicKey, lib: true, fips_mode: false do
context 'FIPS mode', :fips_mode do
where(:name, :algorithms) do
[
- [:rsa, %w(ssh-rsa)],
- [:dsa, %w(ssh-dss)],
- [:ecdsa, %w(ecdsa-sha2-nistp256 ecdsa-sha2-nistp384 ecdsa-sha2-nistp521)],
- [:ed25519, %w(ssh-ed25519)],
- [:ecdsa_sk, %w(sk-ecdsa-sha2-nistp256@openssh.com)],
- [:ed25519_sk, %w(sk-ssh-ed25519@openssh.com)]
+ [:rsa, %w[ssh-rsa]],
+ [:dsa, %w[ssh-dss]],
+ [:ecdsa, %w[ecdsa-sha2-nistp256 ecdsa-sha2-nistp384 ecdsa-sha2-nistp521]],
+ [:ed25519, %w[ssh-ed25519]],
+ [:ecdsa_sk, %w[sk-ecdsa-sha2-nistp256@openssh.com]],
+ [:ed25519_sk, %w[sk-ssh-ed25519@openssh.com]]
]
end
@@ -194,7 +194,7 @@ RSpec.describe Gitlab::SSHPublicKey, lib: true, fips_mode: false do
context 'with a valid SSH key' do
where(:factory) do
- %i(rsa_key_2048
+ %i[rsa_key_2048
rsa_key_4096
rsa_key_5120
rsa_key_8192
@@ -202,7 +202,7 @@ RSpec.describe Gitlab::SSHPublicKey, lib: true, fips_mode: false do
ecdsa_key_256
ed25519_key_256
ecdsa_sk_key_256
- ed25519_sk_key_256)
+ ed25519_sk_key_256]
end
with_them do
diff --git a/spec/lib/gitlab/string_range_marker_spec.rb b/spec/lib/gitlab/string_range_marker_spec.rb
index 2ababd6a938..fcee64bc01c 100644
--- a/spec/lib/gitlab/string_range_marker_spec.rb
+++ b/spec/lib/gitlab/string_range_marker_spec.rb
@@ -14,10 +14,10 @@ RSpec.describe Gitlab::StringRangeMarker do
end
context "when the rich text is html safe" do
- let(:rich) { %{<span class="abc">abc</span><span class="space"> </span><span class="def">&lt;def&gt;</span>}.html_safe }
+ let(:rich) { %(<span class="abc">abc</span><span class="space"> </span><span class="def">&lt;def&gt;</span>).html_safe }
it 'marks the inline diffs' do
- expect(mark_diff(rich)).to eq(%{<span class="abc">abLEFTcRIGHT</span><span class="space">LEFT RIGHT</span><span class="def">LEFT&lt;dRIGHTef&gt;</span>})
+ expect(mark_diff(rich)).to eq(%(<span class="abc">abLEFTcRIGHT</span><span class="space">LEFT RIGHT</span><span class="def">LEFT&lt;dRIGHTef&gt;</span>))
expect(mark_diff(rich)).to be_html_safe
end
end
@@ -25,7 +25,7 @@ RSpec.describe Gitlab::StringRangeMarker do
context "when the rich text is not html safe" do
context 'when rich text equals raw text' do
it 'marks the inline diffs' do
- expect(mark_diff).to eq(%{abLEFTc <dRIGHTef>})
+ expect(mark_diff).to eq(%(abLEFTc <dRIGHTef>))
expect(mark_diff).not_to be_html_safe
end
end
@@ -34,7 +34,7 @@ RSpec.describe Gitlab::StringRangeMarker do
let(:rich) { "abc <def> differs" }
it 'marks the inline diffs' do
- expect(mark_diff(rich)).to eq(%{abLEFTc &lt;dRIGHTef&gt; differs})
+ expect(mark_diff(rich)).to eq(%(abLEFTc &lt;dRIGHTef&gt; differs))
expect(mark_diff(rich)).to be_html_safe
end
end
diff --git a/spec/lib/gitlab/string_regex_marker_spec.rb b/spec/lib/gitlab/string_regex_marker_spec.rb
index 393bfea7c6b..87df8b9baab 100644
--- a/spec/lib/gitlab/string_regex_marker_spec.rb
+++ b/spec/lib/gitlab/string_regex_marker_spec.rb
@@ -5,34 +5,34 @@ require 'fast_spec_helper'
RSpec.describe Gitlab::StringRegexMarker do
describe '#mark' do
context 'with a single occurrence' do
- let(:raw) { %{"name": "AFNetworking"} }
- let(:rich) { %{<span class="key">"name"</span><span class="punctuation">: </span><span class="value">"AFNetworking"</span>}.html_safe }
+ let(:raw) { %("name": "AFNetworking") }
+ let(:rich) { %(<span class="key">"name"</span><span class="punctuation">: </span><span class="value">"AFNetworking"</span>).html_safe }
subject do
described_class.new(raw, rich).mark(/"[^"]+":\s*"(?<name>[^"]+)"/, group: :name) do |text, left:, right:, mode:|
- %{<a href="#">#{text}</a>}.html_safe
+ %(<a href="#">#{text}</a>).html_safe
end
end
it 'marks the match' do
- expect(subject).to eq(%{<span class="key">"name"</span><span class="punctuation">: </span><span class="value">"<a href="#">AFNetworking</a>"</span>})
+ expect(subject).to eq(%(<span class="key">"name"</span><span class="punctuation">: </span><span class="value">"<a href="#">AFNetworking</a>"</span>))
expect(subject).to be_html_safe
end
end
context 'with multiple occurrences' do
- let(:raw) { %{a <b> <c> d} }
- let(:rich) { %{a &lt;b&gt; &lt;c&gt; d}.html_safe }
+ let(:raw) { %(a <b> <c> d) }
+ let(:rich) { %(a &lt;b&gt; &lt;c&gt; d).html_safe }
let(:regexp) { /<[a-z]>/ }
subject do
described_class.new(raw, rich).mark(regexp) do |text, left:, right:, mode:|
- %{<strong>#{text}</strong>}.html_safe
+ %(<strong>#{text}</strong>).html_safe
end
end
it 'marks the matches' do
- expect(subject).to eq(%{a <strong>&lt;b&gt;</strong> <strong>&lt;c&gt;</strong> d})
+ expect(subject).to eq(%(a <strong>&lt;b&gt;</strong> <strong>&lt;c&gt;</strong> d))
expect(subject).to be_html_safe
end
@@ -40,7 +40,7 @@ RSpec.describe Gitlab::StringRegexMarker do
let(:regexp) { Gitlab::UntrustedRegexp.new('<[a-z]>') }
it 'marks the matches' do
- expect(subject).to eq(%{a <strong>&lt;b&gt;</strong> <strong>&lt;c&gt;</strong> d})
+ expect(subject).to eq(%(a <strong>&lt;b&gt;</strong> <strong>&lt;c&gt;</strong> d))
expect(subject).to be_html_safe
end
end
diff --git a/spec/lib/gitlab/suggestions/suggestion_set_spec.rb b/spec/lib/gitlab/suggestions/suggestion_set_spec.rb
index 469646986e1..298ade2e33f 100644
--- a/spec/lib/gitlab/suggestions/suggestion_set_spec.rb
+++ b/spec/lib/gitlab/suggestions/suggestion_set_spec.rb
@@ -114,7 +114,7 @@ RSpec.describe Gitlab::Suggestions::SuggestionSet do
it 'returns an array of unique file paths associated with the suggestions' do
suggestion_set = described_class.new([suggestion, suggestion2, suggestion3])
- expected_paths = %w(files/ruby/popen.rb files/ruby/regex.rb)
+ expected_paths = %w[files/ruby/popen.rb files/ruby/regex.rb]
actual_paths = suggestion_set.file_paths
diff --git a/spec/lib/gitlab/task_helpers_spec.rb b/spec/lib/gitlab/task_helpers_spec.rb
index 0c43dd15e8c..448406dfb99 100644
--- a/spec/lib/gitlab/task_helpers_spec.rb
+++ b/spec/lib/gitlab/task_helpers_spec.rb
@@ -84,17 +84,17 @@ RSpec.describe Gitlab::TaskHelpers do
describe '#run_command' do
it 'runs command and return the output' do
- expect(subject.run_command(%w(echo it works!))).to eq("it works!\n")
+ expect(subject.run_command(%w[echo it works!])).to eq("it works!\n")
end
it 'returns empty string when command doesnt exist' do
- expect(subject.run_command(%w(nonexistentcommand with arguments))).to eq('')
+ expect(subject.run_command(%w[nonexistentcommand with arguments])).to eq('')
end
end
describe '#run_command!' do
it 'runs command and return the output' do
- expect(subject.run_command!(%w(echo it works!))).to eq("it works!\n")
+ expect(subject.run_command!(%w[echo it works!])).to eq("it works!\n")
end
it 'returns and exception when command exit with non zero code' do
diff --git a/spec/lib/gitlab/tracking/event_definition_spec.rb b/spec/lib/gitlab/tracking/event_definition_spec.rb
index b27aaa35695..ab0660147e4 100644
--- a/spec/lib/gitlab/tracking/event_definition_spec.rb
+++ b/spec/lib/gitlab/tracking/event_definition_spec.rb
@@ -15,8 +15,8 @@ RSpec.describe Gitlab::Tracking::EventDefinition do
product_stage: 'growth',
product_section: 'dev',
product_group: 'group::product analytics',
- distribution: %w(ee ce),
- tier: %w(free premium ultimate)
+ distribution: %w[ee ce],
+ tier: %w[free premium ultimate]
}
end
@@ -49,8 +49,8 @@ RSpec.describe Gitlab::Tracking::EventDefinition do
:product_stage | 1
:product_section | nil
:product_group | nil
- :distributions | %[be eb]
- :tiers | %[pro]
+ :distributions | %(be eb)
+ :tiers | %(pro)
end
with_them do
diff --git a/spec/lib/gitlab/url_builder_spec.rb b/spec/lib/gitlab/url_builder_spec.rb
index 68eb38a1335..81b70f85c3a 100644
--- a/spec/lib/gitlab/url_builder_spec.rb
+++ b/spec/lib/gitlab/url_builder_spec.rb
@@ -30,6 +30,7 @@ RSpec.describe Gitlab::UrlBuilder do
:project_snippet | ->(snippet) { "/#{snippet.project.full_path}/-/snippets/#{snippet.id}" }
:project_wiki | ->(wiki) { "/#{wiki.container.full_path}/-/wikis/home" }
:release | ->(release) { "/#{release.project.full_path}/-/releases/#{release.tag}" }
+ :organization | ->(organization) { "/-/organizations/#{organization.path}" }
:ci_build | ->(build) { "/#{build.project.full_path}/-/jobs/#{build.id}" }
:design | ->(design) { "/#{design.project.full_path}/-/design_management/designs/#{design.id}/raw_image" }
diff --git a/spec/lib/gitlab/url_sanitizer_spec.rb b/spec/lib/gitlab/url_sanitizer_spec.rb
index 2c2ef8f13fb..6a1521d9d72 100644
--- a/spec/lib/gitlab/url_sanitizer_spec.rb
+++ b/spec/lib/gitlab/url_sanitizer_spec.rb
@@ -8,10 +8,10 @@ RSpec.describe Gitlab::UrlSanitizer do
describe '.sanitize' do
def sanitize_url(url)
# We want to try with multi-line content because is how error messages are formatted
- described_class.sanitize(%{
+ described_class.sanitize(%(
remote: Not Found
fatal: repository `#{url}` not found
- })
+ ))
end
where(:input, :output) do
@@ -50,7 +50,7 @@ RSpec.describe Gitlab::UrlSanitizer do
false | '123://invalid:url'
false | 'valid@project:url.git'
false | 'valid:pass@project:url.git'
- false | %w(test array)
+ false | %w[test array]
true | 'ssh://example.com'
true | 'ssh://:@example.com'
true | 'ssh://foo@example.com'
@@ -74,7 +74,7 @@ RSpec.describe Gitlab::UrlSanitizer do
false | '123://invalid:url'
false | 'valid@project:url.git'
false | 'valid:pass@project:url.git'
- false | %w(test array)
+ false | %w[test array]
false | 'ssh://example.com'
false | 'ssh://:@example.com'
false | 'ssh://foo@example.com'
diff --git a/spec/lib/gitlab/usage/metric_definition_spec.rb b/spec/lib/gitlab/usage/metric_definition_spec.rb
index 51d3090c825..08adc031631 100644
--- a/spec/lib/gitlab/usage/metric_definition_spec.rb
+++ b/spec/lib/gitlab/usage/metric_definition_spec.rb
@@ -16,8 +16,8 @@ RSpec.describe Gitlab::Usage::MetricDefinition, feature_category: :service_ping
product_group: 'product_analytics',
time_frame: 'none',
data_source: 'database',
- distribution: %w(ee ce),
- tier: %w(free starter premium ultimate bronze silver gold),
+ distribution: %w[ee ce],
+ tier: %w[free starter premium ultimate bronze silver gold],
data_category: 'standard',
removed_by_url: 'http://gdk.test'
}
@@ -64,7 +64,7 @@ RSpec.describe Gitlab::Usage::MetricDefinition, feature_category: :service_ping
it 'includes metrics that are not removed' do
expect(described_class.not_removed.count).to eq(3)
- expect(described_class.not_removed.keys).to match_array(%w(metric1 metric2 metric3))
+ expect(described_class.not_removed.keys).to match_array(%w[metric1 metric2 metric3])
end
end
@@ -162,7 +162,7 @@ RSpec.describe Gitlab::Usage::MetricDefinition, feature_category: :service_ping
:data_source | nil
:distribution | nil
:distribution | 'test'
- :tier | %w(test ee)
+ :tier | %w[test ee]
:repair_issue_url | nil
:removed_by_url | 1
@@ -194,6 +194,156 @@ RSpec.describe Gitlab::Usage::MetricDefinition, feature_category: :service_ping
described_class.new(path, attributes).validate!
end
end
+
+ context 'when metric has removed status' do
+ before do
+ attributes[:status] = 'removed'
+ end
+
+ it 'raise dev exception when removed_by_url is not provided' do
+ attributes.delete(:removed_by_url)
+
+ expect(Gitlab::ErrorTracking).to receive(:track_and_raise_for_dev_exception).at_least(:once).with(instance_of(Gitlab::Usage::MetricDefinition::InvalidError))
+
+ described_class.new(path, attributes).validate!
+ end
+
+ it 'raises dev exception when milestone_removed is not provided' do
+ attributes.delete(:milestone_removed)
+
+ expect(Gitlab::ErrorTracking).to receive(:track_and_raise_for_dev_exception).at_least(:once).with(instance_of(Gitlab::Usage::MetricDefinition::InvalidError))
+
+ described_class.new(path, attributes).validate!
+ end
+ end
+
+ context 'internal metric' do
+ before do
+ attributes[:data_source] = 'internal_events'
+ end
+
+ where(:instrumentation_class, :options, :events, :is_valid) do
+ 'AnotherClass' | { events: ['a'] } | [{ name: 'a', unique: 'user.id' }] | false
+ nil | { events: ['a'] } | [{ name: 'a', unique: 'user.id' }] | false
+ 'RedisHLLMetric' | { events: ['a'] } | [{ name: 'a', unique: 'user.id' }] | true
+ 'RedisHLLMetric' | { events: ['a'] } | nil | false
+ 'RedisHLLMetric' | nil | [{ name: 'a', unique: 'user.id' }] | false
+ 'RedisHLLMetric' | { events: ['a'] } | [{ name: 'a', unique: 'a' }] | false
+ 'RedisHLLMetric' | { events: 'a' } | [{ name: 'a', unique: 'user.id' }] | false
+ 'RedisHLLMetric' | { events: [2] } | [{ name: 'a', unique: 'user.id' }] | false
+ 'RedisHLLMetric' | { events: ['a'], a: 'b' } | [{ name: 'a', unique: 'user.id' }] | false
+ 'RedisHLLMetric' | { events: ['a'] } | [{ name: 'a', unique: 'user.id', b: 'c' }] | false
+ 'RedisHLLMetric' | { events: ['a'] } | [{ name: 'a' }] | false
+ 'RedisHLLMetric' | { events: ['a'] } | [{ unique: 'user.id' }] | false
+ 'TotalCountMetric' | { events: ['a'] } | [{ name: 'a' }] | true
+ 'TotalCountMetric' | { events: ['a'] } | [{ name: 'a', unique: 'user.id' }] | false
+ 'TotalCountMetric' | { events: ['a'] } | nil | false
+ 'TotalCountMetric' | nil | [{ name: 'a' }] | false
+ 'TotalCountMetric' | { events: [2] } | [{ name: 'a' }] | false
+ 'TotalCountMetric' | { events: ['a'] } | [{}] | false
+ 'TotalCountMetric' | 'a' | [{ name: 'a' }] | false
+ 'TotalCountMetric' | { events: ['a'], a: 'b' } | [{ name: 'a' }] | false
+ end
+
+ with_them do
+ it 'raises dev exception when invalid' do
+ attributes[:instrumentation_class] = instrumentation_class if instrumentation_class
+ attributes[:options] = options if options
+ attributes[:events] = events if events
+
+ if is_valid
+ expect(Gitlab::ErrorTracking).not_to receive(:track_and_raise_for_dev_exception)
+ else
+ expect(Gitlab::ErrorTracking).to receive(:track_and_raise_for_dev_exception).at_least(:once).with(instance_of(Gitlab::Usage::MetricDefinition::InvalidError))
+ end
+
+ described_class.new(path, attributes).validate!
+ end
+ end
+ end
+
+ context 'Redis metric' do
+ before do
+ attributes[:data_source] = 'redis'
+ end
+
+ where(:instrumentation_class, :options, :is_valid) do
+ 'AnotherClass' | { event: 'a', widget: 'b' } | false
+ 'MergeRequestWidgetExtensionMetric' | { event: 'a', widget: 'b' } | true
+ 'MergeRequestWidgetExtensionMetric' | { event: 'a', widget: 2 } | false
+ 'MergeRequestWidgetExtensionMetric' | { event: 'a', widget: 'b', c: 'd' } | false
+ 'MergeRequestWidgetExtensionMetric' | { event: 'a' } | false
+ 'MergeRequestWidgetExtensionMetric' | { widget: 'b' } | false
+ 'RedisMetric' | { event: 'a', prefix: 'b', include_usage_prefix: true } | true
+ 'RedisMetric' | { event: 'a', prefix: nil, include_usage_prefix: true } | true
+ 'RedisMetric' | { event: 'a', prefix: 'b', include_usage_prefix: 2 } | false
+ 'RedisMetric' | { event: 'a', prefix: 'b', include_usage_prefix: true, c: 'd' } | false
+ 'RedisMetric' | { prefix: 'b', include_usage_prefix: true } | false
+ 'RedisMetric' | { event: 'a', include_usage_prefix: true } | false
+ 'RedisMetric' | { event: 'a', prefix: 'b' } | true
+ end
+
+ with_them do
+ it 'validates properly' do
+ attributes[:instrumentation_class] = instrumentation_class
+ attributes[:options] = options
+
+ if is_valid
+ expect(Gitlab::ErrorTracking).not_to receive(:track_and_raise_for_dev_exception)
+ else
+ expect(Gitlab::ErrorTracking).to receive(:track_and_raise_for_dev_exception).at_least(:once).with(instance_of(Gitlab::Usage::MetricDefinition::InvalidError))
+ end
+
+ described_class.new(path, attributes).validate!
+ end
+ end
+ end
+
+ context 'RedisHLL metric' do
+ before do
+ attributes[:data_source] = 'redis_hll'
+ end
+
+ where(:instrumentation_class, :options, :is_valid) do
+ 'AnotherClass' | { events: ['a'] } | false
+ 'RedisHLLMetric' | { events: ['a'] } | true
+ 'RedisHLLMetric' | nil | false
+ 'RedisHLLMetric' | {} | false
+ 'RedisHLLMetric' | { events: ['a'], b: 'c' } | false
+ 'RedisHLLMetric' | { events: [2] } | false
+ 'RedisHLLMetric' | { events: 'a' } | false
+ 'RedisHLLMetric' | { event: ['a'] } | false
+ 'AggregatedMetric' | { aggregate: { operator: 'OR', attribute: 'user_id' }, events: ['a'] } | true
+ 'AggregatedMetric' | { aggregate: { operator: 'AND', attribute: 'project_id' }, events: %w[b c] } | true
+ 'AggregatedMetric' | nil | false
+ 'AggregatedMetric' | {} | false
+ 'AggregatedMetric' | { aggregate: { operator: 'OR', attribute: 'user_id' }, events: ['a'], event: 'a' } | false
+ 'AggregatedMetric' | { aggregate: { operator: 'OR', attribute: 'user_id' } } | false
+ 'AggregatedMetric' | { events: ['a'] } | false
+ 'AggregatedMetric' | { aggregate: { operator: 'OR', attribute: 'user_id' }, events: 'a' } | false
+ 'AggregatedMetric' | { aggregate: 'a', events: ['a'] } | false
+ 'AggregatedMetric' | { aggregate: { operator: 'OR' }, events: ['a'] } | false
+ 'AggregatedMetric' | { aggregate: { attribute: 'user_id' }, events: ['a'] } | false
+ 'AggregatedMetric' | { aggregate: { operator: 'OR', attribute: 'user_id', a: 'b' }, events: ['a'] } | false
+ 'AggregatedMetric' | { aggregate: { operator: '???', attribute: 'user_id' }, events: ['a'] } | false
+ 'AggregatedMetric' | { aggregate: { operator: 'OR', attribute: ['user_id'] }, events: ['a'] } | false
+ end
+
+ with_them do
+ it 'validates properly' do
+ attributes[:instrumentation_class] = instrumentation_class
+ attributes[:options] = options
+
+ if is_valid
+ expect(Gitlab::ErrorTracking).not_to receive(:track_and_raise_for_dev_exception)
+ else
+ expect(Gitlab::ErrorTracking).to receive(:track_and_raise_for_dev_exception).at_least(:once).with(instance_of(Gitlab::Usage::MetricDefinition::InvalidError))
+ end
+
+ described_class.new(path, attributes).validate!
+ end
+ end
+ end
end
end
@@ -213,10 +363,10 @@ RSpec.describe Gitlab::Usage::MetricDefinition, feature_category: :service_ping
end
context 'when metric is using new format' do
- let(:attributes) { { events: [{ name: 'my_event', unique: 'user_id' }] } }
+ let(:attributes) { { events: [{ name: 'my_event', unique: 'user.id' }] } }
it 'returns a correct hash' do
- expect(definition.events).to eq({ 'my_event' => :user_id })
+ expect(definition.events).to eq({ 'my_event' => :'user.id' })
end
end
@@ -309,8 +459,8 @@ RSpec.describe Gitlab::Usage::MetricDefinition, feature_category: :service_ping
product_group: 'product_analytics',
time_frame: 'none',
data_source: 'database',
- distribution: %w(ee ce),
- tier: %w(free starter premium ultimate bronze silver gold),
+ distribution: %w[ee ce],
+ tier: %w[free starter premium ultimate bronze silver gold],
data_category: 'optional'
}
end
diff --git a/spec/lib/gitlab/usage/metric_spec.rb b/spec/lib/gitlab/usage/metric_spec.rb
index a4135b143dd..42d2f394ce3 100644
--- a/spec/lib/gitlab/usage/metric_spec.rb
+++ b/spec/lib/gitlab/usage/metric_spec.rb
@@ -18,8 +18,8 @@ RSpec.describe Gitlab::Usage::Metric do
time_frame: "all",
data_source: "database",
instrumentation_class: "CountIssuesMetric",
- distribution: %w(ce ee),
- tier: %w(free premium ultimate)
+ distribution: %w[ce ee],
+ tier: %w[free premium ultimate]
}
end
diff --git a/spec/lib/gitlab/usage/metrics/instrumentations/aggregated_metric_spec.rb b/spec/lib/gitlab/usage/metrics/instrumentations/aggregated_metric_spec.rb
index 3e7b13e21c1..f6b9da68184 100644
--- a/spec/lib/gitlab/usage/metrics/instrumentations/aggregated_metric_spec.rb
+++ b/spec/lib/gitlab/usage/metrics/instrumentations/aggregated_metric_spec.rb
@@ -2,7 +2,8 @@
require 'spec_helper'
-RSpec.describe Gitlab::Usage::Metrics::Instrumentations::AggregatedMetric, :clean_gitlab_redis_shared_state do
+RSpec.describe Gitlab::Usage::Metrics::Instrumentations::AggregatedMetric, :clean_gitlab_redis_shared_state,
+ feature_category: :service_ping do
using RSpec::Parameterized::TableSyntax
before do
# weekly AND 1 weekly OR 2
diff --git a/spec/lib/gitlab/usage/metrics/instrumentations/count_projects_with_jira_dvcs_integration_metric_spec.rb b/spec/lib/gitlab/usage/metrics/instrumentations/count_projects_with_jira_dvcs_integration_metric_spec.rb
deleted file mode 100644
index a2d86fc5044..00000000000
--- a/spec/lib/gitlab/usage/metrics/instrumentations/count_projects_with_jira_dvcs_integration_metric_spec.rb
+++ /dev/null
@@ -1,50 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-RSpec.describe Gitlab::Usage::Metrics::Instrumentations::CountProjectsWithJiraDvcsIntegrationMetric,
- feature_category: :integrations do
- describe 'metric value and query' do
- let_it_be_with_reload(:project_1) { create(:project) }
- let_it_be_with_reload(:project_2) { create(:project) }
- let_it_be_with_reload(:project_3) { create(:project) }
-
- before do
- project_1.feature_usage.log_jira_dvcs_integration_usage(cloud: false)
- project_2.feature_usage.log_jira_dvcs_integration_usage(cloud: false)
- project_3.feature_usage.log_jira_dvcs_integration_usage(cloud: true)
- end
-
- context 'when counting cloud integrations' do
- let(:expected_value) { 1 }
- let(:expected_query) do
- 'SELECT COUNT("project_feature_usages"."project_id") FROM "project_feature_usages" ' \
- 'WHERE "project_feature_usages"."jira_dvcs_cloud_last_sync_at" IS NOT NULL'
- end
-
- it_behaves_like 'a correct instrumented metric value and query', { time_frame: 'all', options: { cloud: true } }
- end
-
- context 'when counting non-cloud integrations' do
- let(:expected_value) { 2 }
- let(:expected_query) do
- 'SELECT COUNT("project_feature_usages"."project_id") FROM "project_feature_usages" ' \
- 'WHERE "project_feature_usages"."jira_dvcs_server_last_sync_at" IS NOT NULL'
- end
-
- it_behaves_like 'a correct instrumented metric value and query', { time_frame: 'all', options: { cloud: false } }
- end
- end
-
- it "raises an exception if option is not present" do
- expect do
- described_class.new(options: {}, time_frame: 'all')
- end.to raise_error(ArgumentError, %r{must be a boolean})
- end
-
- it "raises an exception if option has invalid value" do
- expect do
- described_class.new(options: { cloud: 'yes' }, time_frame: 'all')
- end.to raise_error(ArgumentError, %r{must be a boolean})
- end
-end
diff --git a/spec/lib/gitlab/usage/metrics/instrumentations/database_metric_spec.rb b/spec/lib/gitlab/usage/metrics/instrumentations/database_metric_spec.rb
index 8ca42a6f007..9fcec56d019 100644
--- a/spec/lib/gitlab/usage/metrics/instrumentations/database_metric_spec.rb
+++ b/spec/lib/gitlab/usage/metrics/instrumentations/database_metric_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Gitlab::Usage::Metrics::Instrumentations::DatabaseMetric do
+RSpec.describe Gitlab::Usage::Metrics::Instrumentations::DatabaseMetric, feature_category: :service_ping do
let(:database_metric_class) { Class.new(described_class) }
subject do
diff --git a/spec/lib/gitlab/usage/metrics/instrumentations/generic_metric_spec.rb b/spec/lib/gitlab/usage/metrics/instrumentations/generic_metric_spec.rb
index cc4df696b37..e65d5d30d9d 100644
--- a/spec/lib/gitlab/usage/metrics/instrumentations/generic_metric_spec.rb
+++ b/spec/lib/gitlab/usage/metrics/instrumentations/generic_metric_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Gitlab::Usage::Metrics::Instrumentations::GenericMetric do
+RSpec.describe Gitlab::Usage::Metrics::Instrumentations::GenericMetric, feature_category: :service_ping do
shared_examples 'custom fallback' do |custom_fallback|
subject do
Class.new(described_class) do
diff --git a/spec/lib/gitlab/usage/metrics/instrumentations/numbers_metric_spec.rb b/spec/lib/gitlab/usage/metrics/instrumentations/numbers_metric_spec.rb
index 180c76d56f3..008e30eca9c 100644
--- a/spec/lib/gitlab/usage/metrics/instrumentations/numbers_metric_spec.rb
+++ b/spec/lib/gitlab/usage/metrics/instrumentations/numbers_metric_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Gitlab::Usage::Metrics::Instrumentations::NumbersMetric do
+RSpec.describe Gitlab::Usage::Metrics::Instrumentations::NumbersMetric, feature_category: :service_ping do
subject do
described_class.tap do |metric_class|
metric_class.operation :add
diff --git a/spec/lib/gitlab/usage/metrics/instrumentations/redis_hll_metric_spec.rb b/spec/lib/gitlab/usage/metrics/instrumentations/redis_hll_metric_spec.rb
index 97306051533..33868d365a5 100644
--- a/spec/lib/gitlab/usage/metrics/instrumentations/redis_hll_metric_spec.rb
+++ b/spec/lib/gitlab/usage/metrics/instrumentations/redis_hll_metric_spec.rb
@@ -2,7 +2,8 @@
require 'spec_helper'
-RSpec.describe Gitlab::Usage::Metrics::Instrumentations::RedisHLLMetric, :clean_gitlab_redis_shared_state do
+RSpec.describe Gitlab::Usage::Metrics::Instrumentations::RedisHLLMetric, :clean_gitlab_redis_shared_state,
+ feature_category: :service_ping do
before do
Gitlab::UsageDataCounters::HLLRedisCounter.track_event(:i_quickactions_approve, values: 1, time: 1.week.ago)
Gitlab::UsageDataCounters::HLLRedisCounter.track_event(:i_quickactions_approve, values: 1, time: 2.weeks.ago)
diff --git a/spec/lib/gitlab/usage/metrics/instrumentations/redis_metric_spec.rb b/spec/lib/gitlab/usage/metrics/instrumentations/redis_metric_spec.rb
index c4d6edd43e1..90568f4731e 100644
--- a/spec/lib/gitlab/usage/metrics/instrumentations/redis_metric_spec.rb
+++ b/spec/lib/gitlab/usage/metrics/instrumentations/redis_metric_spec.rb
@@ -2,7 +2,8 @@
require 'spec_helper'
-RSpec.describe Gitlab::Usage::Metrics::Instrumentations::RedisMetric, :clean_gitlab_redis_shared_state do
+RSpec.describe Gitlab::Usage::Metrics::Instrumentations::RedisMetric, :clean_gitlab_redis_shared_state,
+ feature_category: :service_ping do
before do
4.times do
Gitlab::UsageDataCounters::SourceCodeCounter.count(:pushes)
diff --git a/spec/lib/gitlab/usage/service_ping/instrumented_payload_spec.rb b/spec/lib/gitlab/usage/service_ping/instrumented_payload_spec.rb
index 9d2711c49c6..51649e389e2 100644
--- a/spec/lib/gitlab/usage/service_ping/instrumented_payload_spec.rb
+++ b/spec/lib/gitlab/usage/service_ping/instrumented_payload_spec.rb
@@ -11,7 +11,7 @@ RSpec.describe Gitlab::Usage::ServicePing::InstrumentedPayload do
end
context 'when building service ping with values' do
- let(:metrics_key_paths) { %w(counts.boards uuid redis_hll_counters.search.i_search_total_monthly) }
+ let(:metrics_key_paths) { %w[counts.boards uuid redis_hll_counters.search.i_search_total_monthly] }
let(:expected_payload) do
{
counts: { boards: 0 },
@@ -26,7 +26,7 @@ RSpec.describe Gitlab::Usage::ServicePing::InstrumentedPayload do
end
context 'when building service ping with instrumentations' do
- let(:metrics_key_paths) { %w(counts.boards uuid redis_hll_counters.search.i_search_total_monthly) }
+ let(:metrics_key_paths) { %w[counts.boards uuid redis_hll_counters.search.i_search_total_monthly] }
let(:expected_payload) do
{
counts: { boards: "SELECT COUNT(\"boards\".\"id\") FROM \"boards\"" },
diff --git a/spec/lib/gitlab/usage_data_counters/hll_redis_counter_spec.rb b/spec/lib/gitlab/usage_data_counters/hll_redis_counter_spec.rb
index 7bef14d5f7a..a7dc0b6a060 100644
--- a/spec/lib/gitlab/usage_data_counters/hll_redis_counter_spec.rb
+++ b/spec/lib/gitlab/usage_data_counters/hll_redis_counter_spec.rb
@@ -113,73 +113,57 @@ RSpec.describe Gitlab::UsageDataCounters::HLLRedisCounter, :clean_gitlab_redis_s
end
end
- context 'when usage_ping is disabled' do
- it 'does not track the event' do
- allow(::ServicePing::ServicePingSettings).to receive(:enabled?).and_return(false)
+ it 'tracks event when using symbol' do
+ expect(Gitlab::Redis::HLL).to receive(:add)
- described_class.track_event(weekly_event, values: entity1, time: Date.current)
-
- expect(Gitlab::Redis::HLL).not_to receive(:add)
- end
+ described_class.track_event(:g_analytics_contribution, values: entity1)
end
- context 'when usage_ping is enabled' do
- before do
- allow(::ServicePing::ServicePingSettings).to receive(:enabled?).and_return(true)
- end
+ it 'tracks events with multiple values' do
+ values = [entity1, entity2]
+ expect(Gitlab::Redis::HLL).to receive(:add).with(key: /g_analytics_contribution/, value: values,
+ expiry: described_class::KEY_EXPIRY_LENGTH)
- it 'tracks event when using symbol' do
- expect(Gitlab::Redis::HLL).to receive(:add)
-
- described_class.track_event(:g_analytics_contribution, values: entity1)
- end
-
- it 'tracks events with multiple values' do
- values = [entity1, entity2]
- expect(Gitlab::Redis::HLL).to receive(:add).with(key: /g_analytics_contribution/, value: values,
- expiry: described_class::KEY_EXPIRY_LENGTH)
+ described_class.track_event(:g_analytics_contribution, values: values)
+ end
- described_class.track_event(:g_analytics_contribution, values: values)
- end
+ it 'raise error if metrics of unknown event' do
+ expect { described_class.track_event('unknown', values: entity1, time: Date.current) }.to raise_error(Gitlab::UsageDataCounters::HLLRedisCounter::UnknownEvent)
+ end
- it 'raise error if metrics of unknown event' do
- expect { described_class.track_event('unknown', values: entity1, time: Date.current) }.to raise_error(Gitlab::UsageDataCounters::HLLRedisCounter::UnknownEvent)
+ context 'when Rails environment is production' do
+ before do
+ allow(Rails.env).to receive(:development?).and_return(false)
+ allow(Rails.env).to receive(:test?).and_return(false)
end
- context 'when Rails environment is production' do
- before do
- allow(Rails.env).to receive(:development?).and_return(false)
- allow(Rails.env).to receive(:test?).and_return(false)
- end
-
- it 'reports only UnknownEvent exception' do
- expect(Gitlab::ErrorTracking).to receive(:track_and_raise_for_dev_exception)
- .with(Gitlab::UsageDataCounters::HLLRedisCounter::UnknownEvent)
- .once
- .and_call_original
+ it 'reports only UnknownEvent exception' do
+ expect(Gitlab::ErrorTracking).to receive(:track_and_raise_for_dev_exception)
+ .with(Gitlab::UsageDataCounters::HLLRedisCounter::UnknownEvent)
+ .once
+ .and_call_original
- expect { described_class.track_event('unknown', values: entity1, time: Date.current) }.not_to raise_error
- end
+ expect { described_class.track_event('unknown', values: entity1, time: Date.current) }.not_to raise_error
end
+ end
- it 'reports an error if Feature.enabled raise an error' do
- expect(Feature).to receive(:enabled?).and_raise(StandardError.new)
- expect(Gitlab::ErrorTracking).to receive(:track_and_raise_for_dev_exception)
+ it 'reports an error if Feature.enabled raise an error' do
+ expect(Feature).to receive(:enabled?).and_raise(StandardError.new)
+ expect(Gitlab::ErrorTracking).to receive(:track_and_raise_for_dev_exception)
- described_class.track_event(:g_analytics_contribution, values: entity1, time: Date.current)
- end
+ described_class.track_event(:g_analytics_contribution, values: entity1, time: Date.current)
+ end
- context 'for weekly events' do
- it 'sets the keys in Redis to expire' do
- described_class.track_event("g_compliance_dashboard", values: entity1)
+ context 'for weekly events' do
+ it 'sets the keys in Redis to expire' do
+ described_class.track_event("g_compliance_dashboard", values: entity1)
- Gitlab::Redis::SharedState.with do |redis|
- keys = redis.scan_each(match: "{#{described_class::REDIS_SLOT}}_g_compliance_dashboard-*").to_a
- expect(keys).not_to be_empty
+ Gitlab::Redis::SharedState.with do |redis|
+ keys = redis.scan_each(match: "{#{described_class::REDIS_SLOT}}_g_compliance_dashboard-*").to_a
+ expect(keys).not_to be_empty
- keys.each do |key|
- expect(redis.ttl(key)).to be_within(5.seconds).of(described_class::KEY_EXPIRY_LENGTH)
- end
+ keys.each do |key|
+ expect(redis.ttl(key)).to be_within(5.seconds).of(described_class::KEY_EXPIRY_LENGTH)
end
end
end
diff --git a/spec/lib/gitlab/usage_data_counters/redis_counter_spec.rb b/spec/lib/gitlab/usage_data_counters/redis_counter_spec.rb
index 753e09731bf..39d48b7b938 100644
--- a/spec/lib/gitlab/usage_data_counters/redis_counter_spec.rb
+++ b/spec/lib/gitlab/usage_data_counters/redis_counter_spec.rb
@@ -7,51 +7,19 @@ RSpec.describe Gitlab::UsageDataCounters::RedisCounter, :clean_gitlab_redis_shar
subject { Class.new.extend(described_class) }
- before do
- allow(::ServicePing::ServicePingSettings).to receive(:enabled?).and_return(service_ping_enabled)
- end
-
describe '.increment' do
- context 'when usage_ping is disabled' do
- let(:service_ping_enabled) { false }
-
- it 'counter is not increased' do
- expect do
- subject.increment(redis_key)
- end.not_to change { subject.total_count(redis_key) }
- end
- end
-
- context 'when usage_ping is enabled' do
- let(:service_ping_enabled) { true }
-
- it 'counter is increased' do
- expect do
- subject.increment(redis_key)
- end.to change { subject.total_count(redis_key) }.by(1)
- end
+ it 'counter is increased' do
+ expect do
+ subject.increment(redis_key)
+ end.to change { subject.total_count(redis_key) }.by(1)
end
end
describe '.increment_by' do
- context 'when usage_ping is disabled' do
- let(:service_ping_enabled) { false }
-
- it 'counter is not increased' do
- expect do
- subject.increment_by(redis_key, 3)
- end.not_to change { subject.total_count(redis_key) }
- end
- end
-
- context 'when usage_ping is enabled' do
- let(:service_ping_enabled) { true }
-
- it 'counter is increased' do
- expect do
- subject.increment_by(redis_key, 3)
- end.to change { subject.total_count(redis_key) }.by(3)
- end
+ it 'counter is increased' do
+ expect do
+ subject.increment_by(redis_key, 3)
+ end.to change { subject.total_count(redis_key) }.by(3)
end
end
end
diff --git a/spec/lib/gitlab/usage_data_spec.rb b/spec/lib/gitlab/usage_data_spec.rb
index 6f188aa408e..a1564318408 100644
--- a/spec/lib/gitlab/usage_data_spec.rb
+++ b/spec/lib/gitlab/usage_data_spec.rb
@@ -42,7 +42,7 @@ RSpec.describe Gitlab::UsageData, :aggregate_failures, feature_category: :servic
end
it 'ensures recorded_at is set before any other usage data calculation' do
- %i(alt_usage_data redis_usage_data distinct_count count).each do |method|
+ %i[alt_usage_data redis_usage_data distinct_count count].each do |method|
expect(described_class).not_to receive(method)
end
expect(described_class).to receive(:recorded_at).and_raise(Exception.new('Stopped calculating recorded_at'))
@@ -191,7 +191,7 @@ RSpec.describe Gitlab::UsageData, :aggregate_failures, feature_category: :servic
omniauth:
{ providers: omniauth_providers }
)
- allow(Devise).to receive(:omniauth_providers).and_return(%w(ldapmain ldapsecondary group_saml))
+ allow(Devise).to receive(:omniauth_providers).and_return(%w[ldapmain ldapsecondary group_saml])
for_defined_days_back do
user = create(:user)
@@ -268,7 +268,7 @@ RSpec.describe Gitlab::UsageData, :aggregate_failures, feature_category: :servic
for_defined_days_back do
user = create(:user)
- %w(gitlab_project github bitbucket bitbucket_server gitea git manifest fogbugz).each do |type|
+ %w[gitlab_project github bitbucket bitbucket_server gitea git manifest fogbugz].each do |type|
create(:project, import_type: type, creator_id: user.id)
end
@@ -734,7 +734,7 @@ RSpec.describe Gitlab::UsageData, :aggregate_failures, feature_category: :servic
subject { described_class.object_store_usage_data }
it 'fetches object store config of five components' do
- %w(artifacts external_diffs lfs uploads packages).each do |component|
+ %w[artifacts external_diffs lfs uploads packages].each do |component|
expect(described_class).to receive(:object_store_config).with(component).and_return("#{component}_object_store_config")
end
diff --git a/spec/lib/gitlab/utils/log_limited_array_spec.rb b/spec/lib/gitlab/utils/log_limited_array_spec.rb
index a55a176be48..23cca4fd791 100644
--- a/spec/lib/gitlab/utils/log_limited_array_spec.rb
+++ b/spec/lib/gitlab/utils/log_limited_array_spec.rb
@@ -13,7 +13,7 @@ RSpec.describe Gitlab::Utils::LogLimitedArray do
context 'when the argument is an array' do
context 'when the array is under the limit' do
it 'returns the array unchanged' do
- expect(described_class.log_limited_array(%w(a b))).to eq(%w(a b))
+ expect(described_class.log_limited_array(%w[a b])).to eq(%w[a b])
end
end
diff --git a/spec/lib/gitlab/webpack/graphql_known_operations_spec.rb b/spec/lib/gitlab/webpack/graphql_known_operations_spec.rb
index 89cade82fe6..6c3e3b4eb69 100644
--- a/spec/lib/gitlab/webpack/graphql_known_operations_spec.rb
+++ b/spec/lib/gitlab/webpack/graphql_known_operations_spec.rb
@@ -30,7 +30,7 @@ RSpec.describe Gitlab::Webpack::GraphqlKnownOperations do
2.times { ::Gitlab::Webpack::GraphqlKnownOperations.load }
- expect(::Gitlab::Webpack::GraphqlKnownOperations.load).to eq(%w(hello world test))
+ expect(::Gitlab::Webpack::GraphqlKnownOperations.load).to eq(%w[hello world test])
end
end
diff --git a/spec/lib/gitlab/wiki_pages/front_matter_parser_spec.rb b/spec/lib/gitlab/wiki_pages/front_matter_parser_spec.rb
index 3152dc2ad2f..3d165f7d830 100644
--- a/spec/lib/gitlab/wiki_pages/front_matter_parser_spec.rb
+++ b/spec/lib/gitlab/wiki_pages/front_matter_parser_spec.rb
@@ -24,7 +24,7 @@ RSpec.describe Gitlab::WikiPages::FrontMatterParser do
end
def have_correct_front_matter
- include(a: 1, b: 2, c: %w(foo bar))
+ include(a: 1, b: 2, c: %w[foo bar])
end
describe '#parse' do
diff --git a/spec/lib/gitlab/workhorse_spec.rb b/spec/lib/gitlab/workhorse_spec.rb
index cca18cb05c7..d77763f89be 100644
--- a/spec/lib/gitlab/workhorse_spec.rb
+++ b/spec/lib/gitlab/workhorse_spec.rb
@@ -226,7 +226,8 @@ RSpec.describe Gitlab::Workhorse, feature_category: :shared do
GL_ID: "user-#{user.id}",
GL_USERNAME: user.username,
GL_REPOSITORY: "project-#{project.id}",
- ShowAllRefs: false
+ ShowAllRefs: false,
+ NeedAudit: false
}
end
@@ -277,6 +278,12 @@ RSpec.describe Gitlab::Workhorse, feature_category: :shared do
it { is_expected.to include(ShowAllRefs: true) }
end
+ context 'need_audit enabled' do
+ subject { described_class.git_http_ok(repository, Gitlab::GlRepository::PROJECT, user, action, show_all_refs: true, need_audit: true) }
+
+ it { is_expected.to include(NeedAudit: true) }
+ end
+
context 'when a feature flag is set for a single project' do
before do
stub_feature_flags(gitaly_mep_mep: project)