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
path: root/qa
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2023-06-20 13:43:29 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2023-06-20 13:43:29 +0300
commit3b1af5cc7ed2666ff18b718ce5d30fa5a2756674 (patch)
tree3bc4a40e0ee51ec27eabf917c537033c0c5b14d4 /qa
parent9bba14be3f2c211bf79e15769cd9b77bc73a13bc (diff)
Add latest changes from gitlab-org/gitlab@16-1-stable-eev16.1.0-rc42
Diffstat (limited to 'qa')
-rw-r--r--qa/.confiner/master.yml19
-rw-r--r--qa/.confiner/nightly.yml19
-rw-r--r--qa/Dockerfile2
-rw-r--r--qa/Gemfile13
-rw-r--r--qa/Gemfile.lock51
-rw-r--r--qa/gdk/Dockerfile50
-rw-r--r--qa/gdk/Dockerfile.gdk145
-rw-r--r--qa/gdk/Dockerfile.gdk.dockerignore21
-rwxr-xr-xqa/gdk/entrypoint21
-rw-r--r--qa/gdk/gdk.yml3
-rwxr-xr-xqa/gdk/launch39
-rw-r--r--qa/lib/gitlab/page/group/settings/billing.rb9
-rw-r--r--qa/lib/gitlab/page/group/settings/usage_quotas.rb48
-rw-r--r--qa/lib/gitlab/page/group/settings/usage_quotas.stub.rb40
-rw-r--r--qa/lib/gitlab/page/trials/select.rb2
-rw-r--r--qa/qa/ce/strategy.rb17
-rw-r--r--qa/qa/fixtures/mocks/import/github.yml2
-rw-r--r--qa/qa/fixtures/package_managers/npm/npm_install_package_group.yaml.erb21
-rw-r--r--qa/qa/fixtures/package_managers/npm/npm_upload_package_group.yaml.erb14
-rw-r--r--qa/qa/fixtures/package_managers/npm/package.json.erb (renamed from qa/qa/fixtures/package_managers/npm/package_instance.json.erb)0
-rw-r--r--qa/qa/fixtures/package_managers/npm/package_project.json.erb8
-rw-r--r--qa/qa/flow/purchase.rb2
-rw-r--r--qa/qa/mobile/page/project/issue/show.rb6
-rw-r--r--qa/qa/page/base.rb13
-rw-r--r--qa/qa/page/component/blob_content.rb2
-rw-r--r--qa/qa/page/component/issuable/common.rb4
-rw-r--r--qa/qa/page/component/issuable/sidebar.rb8
-rw-r--r--qa/qa/page/component/note.rb2
-rw-r--r--qa/qa/page/component/snippet.rb10
-rw-r--r--qa/qa/page/dashboard/projects.rb8
-rw-r--r--qa/qa/page/element.rb24
-rw-r--r--qa/qa/page/file/edit.rb14
-rw-r--r--qa/qa/page/file/show.rb12
-rw-r--r--qa/qa/page/group/menu.rb7
-rw-r--r--qa/qa/page/group/sub_menus/super_sidebar/deploy.rb23
-rw-r--r--qa/qa/page/group/sub_menus/super_sidebar/main.rb2
-rw-r--r--qa/qa/page/main/login.rb20
-rw-r--r--qa/qa/page/main/menu.rb14
-rw-r--r--qa/qa/page/merge_request/show.rb15
-rw-r--r--qa/qa/page/project/branches/show.rb2
-rw-r--r--qa/qa/page/project/issue/show.rb24
-rw-r--r--qa/qa/page/project/menu.rb1
-rw-r--r--qa/qa/page/project/pipeline/show.rb16
-rw-r--r--qa/qa/page/project/pipeline_editor/show.rb13
-rw-r--r--qa/qa/page/project/secure/configuration_form.rb48
-rw-r--r--qa/qa/page/project/settings/ci_variables.rb6
-rw-r--r--qa/qa/page/project/settings/protected_branches.rb6
-rw-r--r--qa/qa/page/project/settings/services/slack.rb23
-rw-r--r--qa/qa/page/project/show.rb10
-rw-r--r--qa/qa/page/project/sub_menus/repository.rb2
-rw-r--r--qa/qa/page/project/sub_menus/super_sidebar/code.rb4
-rw-r--r--qa/qa/page/project/sub_menus/super_sidebar/deploy.rb31
-rw-r--r--qa/qa/page/project/sub_menus/super_sidebar/main.rb8
-rw-r--r--qa/qa/page/project/sub_menus/super_sidebar/plan.rb4
-rw-r--r--qa/qa/page/project/web_ide/edit.rb10
-rw-r--r--qa/qa/page/project/web_ide/vscode.rb177
-rw-r--r--qa/qa/page/search/results.rb2
-rw-r--r--qa/qa/page/sub_menus/super_sidebar/context_switcher.rb13
-rw-r--r--qa/qa/page/sub_menus/super_sidebar/deploy.rb27
-rw-r--r--qa/qa/page/sub_menus/super_sidebar/manage.rb4
-rw-r--r--qa/qa/page/sub_menus/super_sidebar/operate.rb10
-rw-r--r--qa/qa/page/sub_menus/super_sidebar/plan.rb4
-rw-r--r--qa/qa/resource/badge_base.rb5
-rw-r--r--qa/qa/resource/base.rb14
-rw-r--r--qa/qa/resource/bulk_import_group.rb4
-rw-r--r--qa/qa/resource/file.rb10
-rw-r--r--qa/qa/resource/group_base.rb28
-rw-r--r--qa/qa/resource/group_milestone.rb14
-rw-r--r--qa/qa/resource/group_runner.rb2
-rw-r--r--qa/qa/resource/issue.rb10
-rw-r--r--qa/qa/resource/job.rb3
-rw-r--r--qa/qa/resource/merge_request.rb28
-rw-r--r--qa/qa/resource/pipeline.rb10
-rw-r--r--qa/qa/resource/project.rb24
-rw-r--r--qa/qa/resource/protected_branch.rb8
-rw-r--r--qa/qa/resource/registry_repository.rb3
-rw-r--r--qa/qa/resource/repository/commit.rb12
-rw-r--r--qa/qa/resource/repository/push.rb4
-rw-r--r--qa/qa/resource/user.rb27
-rw-r--r--qa/qa/runtime/browser.rb121
-rw-r--r--qa/qa/runtime/env.rb31
-rw-r--r--qa/qa/scenario/test/instance/packages.rb13
-rw-r--r--qa/qa/scenario/test/instance/review_blocking.rb6
-rw-r--r--qa/qa/scenario/test/instance/review_non_blocking.rb6
-rw-r--r--qa/qa/service/docker_run/base.rb21
-rw-r--r--qa/qa/service/docker_run/video.rb123
-rw-r--r--qa/qa/service/praefect_manager.rb36
-rw-r--r--qa/qa/service/shellout.rb9
-rw-r--r--qa/qa/specs/features/api/12_systems/gitaly/changing_repository_storage_spec.rb6
-rw-r--r--qa/qa/specs/features/api/12_systems/gitaly/distributed_reads_spec.rb5
-rw-r--r--qa/qa/specs/features/api/12_systems/gitaly/praefect_connectivity_spec.rb45
-rw-r--r--qa/qa/specs/features/api/12_systems/gitaly/praefect_dataloss_spec.rb10
-rw-r--r--qa/qa/specs/features/api/12_systems/gitaly/praefect_replication_queue_spec.rb2
-rw-r--r--qa/qa/specs/features/api/12_systems/gitaly/praefect_repo_sync_spec.rb4
-rw-r--r--qa/qa/specs/features/api/1_manage/integrations/webhook_events_spec.rb8
-rw-r--r--qa/qa/specs/features/api/1_manage/migration/gitlab_migration_project_spec.rb2
-rw-r--r--qa/qa/specs/features/api/3_create/repository/project_archive_compare_spec.rb2
-rw-r--r--qa/qa/specs/features/api/3_create/repository/tag_revision_trigger_prereceive_hook_spec.rb13
-rw-r--r--qa/qa/specs/features/api/4_verify/api_variable_inheritance_with_forward_pipeline_variables_spec.rb6
-rw-r--r--qa/qa/specs/features/api/5_package/container_registry/saas/container_registry_spec.rb (renamed from qa/qa/specs/features/api/5_package/container_registry_spec.rb)39
-rw-r--r--qa/qa/specs/features/browser_ui/1_manage/integrations/jenkins/jenkins_build_status_spec.rb2
-rw-r--r--qa/qa/specs/features/browser_ui/1_manage/integrations/jira/jira_basic_integration_spec.rb4
-rw-r--r--qa/qa/specs/features/browser_ui/1_manage/integrations/slash_commands_spec.rb175
-rw-r--r--qa/qa/specs/features/browser_ui/1_manage/login/login_via_oauth_and_oidc_with_gitlab_as_idp_spec.rb154
-rw-r--r--qa/qa/specs/features/browser_ui/1_manage/login/login_via_oidc_with_gitlab_as_idp_spec.rb118
-rw-r--r--qa/qa/specs/features/browser_ui/1_manage/login/register_spec.rb2
-rw-r--r--qa/qa/specs/features/browser_ui/2_plan/issue/mentions_spec.rb2
-rw-r--r--qa/qa/specs/features/browser_ui/3_create/merge_request/revert/reverting_merge_request_spec.rb2
-rw-r--r--qa/qa/specs/features/browser_ui/3_create/merge_request/view_merge_request_diff_patch_spec.rb2
-rw-r--r--qa/qa/specs/features/browser_ui/3_create/repository/add_list_delete_branches_spec.rb9
-rw-r--r--qa/qa/specs/features/browser_ui/3_create/repository/add_new_branch_rule_spec.rb10
-rw-r--r--qa/qa/specs/features/browser_ui/3_create/repository/push_http_private_token_spec.rb2
-rw-r--r--qa/qa/specs/features/browser_ui/3_create/repository/push_over_http_spec.rb4
-rw-r--r--qa/qa/specs/features/browser_ui/3_create/repository/push_over_ssh_spec.rb4
-rw-r--r--qa/qa/specs/features/browser_ui/3_create/snippet/add_comment_to_snippet_spec.rb14
-rw-r--r--qa/qa/specs/features/browser_ui/3_create/source_editor/source_editor_toolbar_spec.rb20
-rw-r--r--qa/qa/specs/features/browser_ui/3_create/web_ide/add_new_directory_in_web_ide_spec.rb10
-rw-r--r--qa/qa/specs/features/browser_ui/3_create/web_ide/upload_new_file_in_web_ide_spec.rb71
-rw-r--r--qa/qa/specs/features/browser_ui/4_verify/pipeline/include_multiple_files_from_multiple_projects_spec.rb56
-rw-r--r--qa/qa/specs/features/browser_ui/4_verify/pipeline/merge_mr_when_pipline_is_blocked_spec.rb6
-rw-r--r--qa/qa/specs/features/browser_ui/4_verify/pipeline/pipeline_editor_branch_switcher_spec.rb91
-rw-r--r--qa/qa/specs/features/browser_ui/4_verify/pipeline/pipeline_editor_tabs_spec.rb6
-rw-r--r--qa/qa/specs/features/browser_ui/4_verify/pipeline/pipeline_with_image_pull_policy_spec.rb6
-rw-r--r--qa/qa/specs/features/browser_ui/4_verify/pipeline/run_pipeline_with_manual_jobs_spec.rb2
-rw-r--r--qa/qa/specs/features/browser_ui/5_package/container_registry/online_garbage_collection_spec.rb112
-rw-r--r--qa/qa/specs/features/browser_ui/5_package/container_registry/saas/container_registry_spec.rb (renamed from qa/qa/specs/features/browser_ui/5_package/container_registry/container_registry_spec.rb)18
-rw-r--r--qa/qa/specs/features/browser_ui/5_package/container_registry/saas/pull_container_registry_image_spec.rb31
-rw-r--r--qa/qa/specs/features/browser_ui/5_package/container_registry/self_managed/container_registry_spec.rb (renamed from qa/qa/specs/features/browser_ui/5_package/container_registry/container_registry_omnibus_spec.rb)58
-rw-r--r--qa/qa/specs/features/browser_ui/5_package/dependency_proxy/dependency_proxy_spec.rb59
-rw-r--r--qa/qa/specs/features/browser_ui/5_package/infrastructure_registry/terraform_module_registry_spec.rb2
-rw-r--r--qa/qa/specs/features/browser_ui/5_package/package_registry/composer_registry_spec.rb2
-rw-r--r--qa/qa/specs/features/browser_ui/5_package/package_registry/conan_repository_spec.rb2
-rw-r--r--qa/qa/specs/features/browser_ui/5_package/package_registry/generic_repository_spec.rb2
-rw-r--r--qa/qa/specs/features/browser_ui/5_package/package_registry/helm_registry_spec.rb2
-rw-r--r--qa/qa/specs/features/browser_ui/5_package/package_registry/maven/maven_group_level_spec.rb97
-rw-r--r--qa/qa/specs/features/browser_ui/5_package/package_registry/maven/maven_project_level_spec.rb110
-rw-r--r--qa/qa/specs/features/browser_ui/5_package/package_registry/maven_gradle_repository_spec.rb2
-rw-r--r--qa/qa/specs/features/browser_ui/5_package/package_registry/npm/npm_group_level_spec.rb174
-rw-r--r--qa/qa/specs/features/browser_ui/5_package/package_registry/npm/npm_instance_level_spec.rb4
-rw-r--r--qa/qa/specs/features/browser_ui/5_package/package_registry/npm/npm_project_level_spec.rb4
-rw-r--r--qa/qa/specs/features/browser_ui/5_package/package_registry/nuget/nuget_group_level_spec.rb2
-rw-r--r--qa/qa/specs/features/browser_ui/5_package/package_registry/nuget/nuget_project_level_spec.rb3
-rw-r--r--qa/qa/specs/features/browser_ui/5_package/package_registry/pypi_repository_spec.rb2
-rw-r--r--qa/qa/specs/features/browser_ui/5_package/package_registry/rubygems_registry_spec.rb4
-rw-r--r--qa/qa/specs/helpers/context_selector.rb8
-rw-r--r--qa/qa/specs/spec_helper.rb1
-rw-r--r--qa/qa/support/helpers/zuora.rb11
-rw-r--r--qa/qa/support/knapsack_report.rb22
-rw-r--r--qa/qa/support/wait_for_requests.rb6
-rw-r--r--qa/qa/tools/migrate_influx_data_to_gcs.rb124
-rw-r--r--qa/qa/tools/test_resources_handler.rb27
-rw-r--r--qa/qa/vendor/jira/jira_api.rb8
-rw-r--r--qa/spec/fixtures/knapsack_report/instance-selective-parallel.json5
-rw-r--r--qa/spec/fixtures/knapsack_report/instance.json7
-rw-r--r--qa/spec/page/element_spec.rb8
-rw-r--r--qa/spec/resource/base_spec.rb17
-rw-r--r--qa/spec/service/docker_run/video_spec.rb181
-rw-r--r--qa/spec/specs/helpers/context_selector_spec.rb41
-rw-r--r--qa/spec/support/knapsack_report_spec.rb39
-rw-r--r--qa/spec/support/loglinking_spec.rb21
-rw-r--r--qa/tasks/ci.rake12
-rw-r--r--qa/tasks/knapsack.rake13
-rw-r--r--qa/tasks/migrate_influx_data_to_gcs.rake6
-rw-r--r--qa/tasks/webdrivers.rake3
164 files changed, 2409 insertions, 1502 deletions
diff --git a/qa/.confiner/master.yml b/qa/.confiner/master.yml
index e6fc3e68747..f58ea5de017 100644
--- a/qa/.confiner/master.yml
+++ b/qa/.confiner/master.yml
@@ -13,22 +13,3 @@
ref: master
actions:
- quarantine
-
-- name: Dequarantine E2E tests in Master that pass consistently
- plugin:
- name: gitlab # https://gitlab.com/gitlab-org/quality/confiner/-/blob/main/doc/plugins/gitlab.md
- args:
- threshold: 10 # at least 10 passes consecutively with no failures to be a candidate for dequarantine
- private_token: $QA_GITLAB_CI_TOKEN
-
- # we do not run quarantined jobs automatically on master, but we still commit to master
- project_id: gitlab-org/quality/nightly # https://gitlab.com/gitlab-org/quality/nightly/
- target_project: gitlab-org/gitlab # https://gitlab.com/gitlab-org/gitlab
- failure_issue_labels: QA,Quality
- failure_issue_prefix: "Failure in "
- pwd: qa # E2E specs reside in the qa subdirectory
- timeout: 30
- ref: master
- job_pattern: '.+-quarantine'
- actions:
- - dequarantine
diff --git a/qa/.confiner/nightly.yml b/qa/.confiner/nightly.yml
deleted file mode 100644
index 78089525b0e..00000000000
--- a/qa/.confiner/nightly.yml
+++ /dev/null
@@ -1,19 +0,0 @@
-- name: Quarantine E2E tests in Nightly that fail consistently
- plugin:
- name: gitlab
- args:
- threshold: 3
- private_token: $QA_GITLAB_CI_TOKEN
- project_id: gitlab-org/quality/nightly # https://gitlab.com/gitlab-org/quality/nightly/
- target_project: gitlab-org/gitlab
- failure_issue_labels: QA,Quality,found:nightly
- failure_issue_prefix: "Failure in "
- pwd: qa
- timeout: 30
- ref: master
- environment:
- name: nightly
- pattern: 'pipeline: :nightly'
- job_pattern: '^((?!quarantine).)*$'
- actions:
- - quarantine
diff --git a/qa/Dockerfile b/qa/Dockerfile
index 2bf668abc49..bd9cd166701 100644
--- a/qa/Dockerfile
+++ b/qa/Dockerfile
@@ -9,8 +9,6 @@ LABEL maintainer="GitLab Quality Department <quality@gitlab.com>"
ENV DEBIAN_FRONTEND="noninteractive"
# Override config path to make sure local config doesn't override it when building image locally
ENV BUNDLE_APP_CONFIG=/home/gitlab/.bundle
-# Use webdriver preinstalled in the base image
-ENV WD_INSTALL_DIR=/usr/local/bin
##
# Install system libs
diff --git a/qa/Gemfile b/qa/Gemfile
index cc814a43c1c..a06914ca7de 100644
--- a/qa/Gemfile
+++ b/qa/Gemfile
@@ -2,11 +2,11 @@
source 'https://rubygems.org'
-gem 'gitlab-qa', '~> 10', '>= 10.4.1', require: 'gitlab/qa'
-gem 'gitlab_quality-test_tooling', '~> 0.4.0', require: false
+gem 'gitlab-qa', '~> 11', '>= 11.2.0', require: 'gitlab/qa'
+gem 'gitlab_quality-test_tooling', '~> 0.8.1', require: false
gem 'activesupport', '~> 6.1.7.2' # This should stay in sync with the root's Gemfile
gem 'allure-rspec', '~> 2.20.0'
-gem 'capybara', '~> 3.39.1'
+gem 'capybara', '~> 3.39.2'
gem 'capybara-screenshot', '~> 1.0.26'
gem 'rake', '~> 13', '>= 13.0.6'
gem 'rspec', '~> 3.12'
@@ -24,9 +24,8 @@ gem 'parallel', '~> 1.23'
gem 'rainbow', '~> 3.1.1'
gem 'rspec-parameterized', '~> 1.0.0'
gem 'octokit', '~> 6.1.1'
-gem "faraday-retry", "~> 2.1"
-gem 'webdrivers', '~> 5.2'
-gem 'zeitwerk', '~> 2.6', '>= 2.6.7'
+gem "faraday-retry", "~> 2.2"
+gem 'zeitwerk', '~> 2.6', '>= 2.6.8'
gem 'influxdb-client', '~> 2.9'
gem 'terminal-table', '~> 3.0.2', require: false
gem 'slack-notifier', '~> 2.4', require: false
@@ -40,7 +39,7 @@ gem 'chemlab', '~> 0.10'
gem 'chemlab-library-www-gitlab-com', '~> 0.1', '>= 0.1.1'
# dependencies for jenkins client
-gem 'nokogiri', '~> 1.14', '>= 1.14.4'
+gem 'nokogiri', '~> 1.15', '>= 1.15.2'
gem 'deprecation_toolkit', '~> 2.0.3', require: false
diff --git a/qa/Gemfile.lock b/qa/Gemfile.lock
index ae9b31386b4..e4e89e7e2e1 100644
--- a/qa/Gemfile.lock
+++ b/qa/Gemfile.lock
@@ -29,7 +29,7 @@ GEM
debug_inspector (>= 0.0.1)
builder (3.2.4)
byebug (11.1.3)
- capybara (3.39.1)
+ capybara (3.39.2)
addressable
matrix
mini_mime (>= 0.1.3)
@@ -69,7 +69,7 @@ GEM
faraday-net_http (>= 2.0, < 3.1)
ruby2_keywords (>= 0.0.4)
faraday-net_http (3.0.0)
- faraday-retry (2.1.0)
+ faraday-retry (2.2.0)
faraday (~> 2.0)
ffi (1.15.5)
ffi-compiler (1.0.1)
@@ -99,21 +99,21 @@ GEM
fog-core
nokogiri (>= 1.5.11, < 2.0.0)
formatador (0.3.0)
- gitlab (4.18.0)
- httparty (~> 0.18)
+ gitlab (4.19.0)
+ httparty (~> 0.20)
terminal-table (>= 1.5.1)
- gitlab-qa (10.4.1)
+ gitlab-qa (11.2.0)
activesupport (~> 6.1)
- gitlab (~> 4.18.0)
+ gitlab (~> 4.19)
http (~> 5.0)
nokogiri (~> 1.10)
parallel (>= 1, < 2)
rainbow (>= 3, < 4)
table_print (= 1.5.7)
zeitwerk (>= 2, < 3)
- gitlab_quality-test_tooling (0.4.0)
- activesupport (~> 6.1)
- gitlab (~> 4.18.0)
+ gitlab_quality-test_tooling (0.8.1)
+ activesupport (>= 6.1, < 7.1)
+ gitlab (~> 4.19)
http (~> 5.0)
nokogiri (~> 1.10)
parallel (>= 1, < 2)
@@ -141,8 +141,8 @@ GEM
google-apis-core (>= 0.7.2, < 2.a)
google-apis-sqladmin_v1beta4 (0.36.0)
google-apis-core (>= 0.7.2, < 2.a)
- google-apis-storage_v1 (0.18.0)
- google-apis-core (>= 0.7, < 2.a)
+ google-apis-storage_v1 (0.19.0)
+ google-apis-core (>= 0.9.0, < 2.a)
google-cloud-env (1.6.0)
faraday (>= 0.17.3, < 3.0)
googleauth (1.2.0)
@@ -185,13 +185,13 @@ GEM
mime-types-data (~> 3.2015)
mime-types-data (3.2023.0218.1)
mini_mime (1.1.0)
- mini_portile2 (2.8.1)
+ mini_portile2 (2.8.2)
minitest (5.18.0)
multi_json (1.15.0)
multi_xml (0.6.0)
netrc (0.11.0)
- nokogiri (1.14.4)
- mini_portile2 (~> 2.8.0)
+ nokogiri (1.15.2)
+ mini_portile2 (~> 2.8.2)
racc (~> 1.4)
octokit (6.1.1)
faraday (>= 1, < 3)
@@ -201,7 +201,7 @@ GEM
parallel (1.23.0)
parallel_tests (4.2.1)
parallel
- parser (3.1.3.0)
+ parser (3.2.2.1)
ast (~> 2.4.1)
proc_to_ast (0.1.0)
coderay
@@ -300,15 +300,11 @@ GEM
watir (7.1.0)
regexp_parser (>= 1.2, < 3)
selenium-webdriver (~> 4.0)
- webdrivers (5.2.0)
- nokogiri (~> 1.6)
- rubyzip (>= 1.3.0)
- selenium-webdriver (~> 4.0)
webrick (1.7.0)
websocket (1.2.9)
xpath (3.2.0)
nokogiri (~> 1.8)
- zeitwerk (2.6.7)
+ zeitwerk (2.6.8)
PLATFORMS
ruby
@@ -317,21 +313,21 @@ DEPENDENCIES
activesupport (~> 6.1.7.2)
airborne (~> 0.3.7)
allure-rspec (~> 2.20.0)
- capybara (~> 3.39.1)
+ capybara (~> 3.39.2)
capybara-screenshot (~> 1.0.26)
chemlab (~> 0.10)
chemlab-library-www-gitlab-com (~> 0.1, >= 0.1.1)
confiner (~> 0.4)
deprecation_toolkit (~> 2.0.3)
faker (~> 3.2)
- faraday-retry (~> 2.1)
+ faraday-retry (~> 2.2)
fog-core (= 2.1.0)
fog-google (~> 1.19)
- gitlab-qa (~> 10, >= 10.4.1)
- gitlab_quality-test_tooling (~> 0.4.0)
+ gitlab-qa (~> 11, >= 11.2.0)
+ gitlab_quality-test_tooling (~> 0.8.1)
influxdb-client (~> 2.9)
knapsack (~> 4.0)
- nokogiri (~> 1.14, >= 1.14.4)
+ nokogiri (~> 1.15, >= 1.15.2)
octokit (~> 6.1.1)
parallel (~> 1.23)
parallel_tests (~> 4.2, >= 4.2.1)
@@ -349,8 +345,7 @@ DEPENDENCIES
slack-notifier (~> 2.4)
terminal-table (~> 3.0.2)
warning (~> 1.3)
- webdrivers (~> 5.2)
- zeitwerk (~> 2.6, >= 2.6.7)
+ zeitwerk (~> 2.6, >= 2.6.8)
BUNDLED WITH
- 2.4.13
+ 2.4.14
diff --git a/qa/gdk/Dockerfile b/qa/gdk/Dockerfile
deleted file mode 100644
index ed8f3f317eb..00000000000
--- a/qa/gdk/Dockerfile
+++ /dev/null
@@ -1,50 +0,0 @@
-FROM registry.gitlab.com/gitlab-org/gitlab-development-kit/asdf-bootstrapped-gdk-installed-gitlab-e2e:ml-create-image-for-gitlab-qa-tests
-
-ENV CHROME_DRIVER_VERSION="107.0.5304.62"
-ENV CHROME_VERSION="107.0.5304.87-1"
-ENV CHROME_DEB="google-chrome-stable_${CHROME_VERSION}_amd64.deb"
-ENV CHROME_URL="https://gitlab.com/api/v4/projects/gitlab-org%2Fgitlab-build-images/packages/generic/google-chrome-stable/${CHROME_VERSION}/${CHROME_DEB}"
-
-WORKDIR /home/gdk/gdk
-
-COPY --chown=gdk qa/gdk/gdk.yml .
-
-RUN cat gdk.yml && \
- gdk update && \
- gdk restart && \
- ./support/test_url http://gdk.test:3000 && \
- gdk stop && sleep 5 && \
- GDK_KILL_CONFIRM=true gdk kill && \
- ps -ef && \
- cd gitlab && git reset --hard && \
- sudo rm -rf "$HOME/gdk/gitaly/_build/deps/git/source" \
- "$HOME/gdk/gitaly/_build/deps/libgit2/source" \
- "$HOME/gdk/gitaly/_build/cache" \
- "$HOME/gdk/gitaly/_build/deps" \
- "$HOME/gdk/gitaly/_build/intermediate" \
- "$HOME/.cache/" \
- "$HOME/gdk/gdk/gitlab" \
- /tmp/*
-
-# Install Google Chrome version with headless support
-# Download from our local S3 bucket, populated by https://gitlab.com/gitlab-org/gitlab-build-images/-/blob/master/scripts/cache-google-chrome
-#
-RUN echo "${CHROME_URL}" && \
- curl --silent --show-error --fail -O "${CHROME_URL}" && \
- sudo apt update && \
- sudo dpkg -i "./${CHROME_DEB}" || true && \
- sudo apt install -f -y && \
- rm -f "./${CHROME_DEB}"
-
-WORKDIR /home/gdk/gdk/gitlab
-
-RUN bundle install --jobs=$(nproc) --retry=3 --quiet
-RUN cd qa && \
- bundle install --jobs=$(nproc) --retry=3 --quiet && \
- bundle exec rake -f tasks/webdrivers.rake webdrivers:chromedriver:update[${CHROME_DRIVER_VERSION}]
-
-RUN git config remote.origin.fetch "+refs/heads/*:refs/remotes/origin/*"
-
-COPY --chown=gdk qa/gdk/launch .
-
-ENTRYPOINT ["./launch"]
diff --git a/qa/gdk/Dockerfile.gdk b/qa/gdk/Dockerfile.gdk
new file mode 100644
index 00000000000..cf9cea69056
--- /dev/null
+++ b/qa/gdk/Dockerfile.gdk
@@ -0,0 +1,145 @@
+# Multi-stage Dockerfile for packaging gdk as executable docker image
+# Each stage can be executed in parallel and cached separately based on changes for respective component
+# Caches are cleaned for each stage to reduce the footprint of exported cache layers
+
+ARG BASE_TAG=master
+
+FROM registry.gitlab.com/gitlab-org/gitlab-build-images/debian-bullseye-slim-ruby-3.1-golang-1.19-rust-1.65-node-16.14-postgresql-13:rubygems-3.4-git-2.36-lfs-2.9-yarn-1.22 as gdk-base
+
+RUN set -eux; \
+ groupadd gdk -g 1000; \
+ useradd gdk -m -s /bin/bash -u 1000 -g 1000
+
+ENV GEM_HOME=/home/gdk/.gem \
+ GEM_PATH=/home/gdk/.gem \
+ PATH=$PATH:/home/gdk/.gem/bin
+
+WORKDIR /home/gdk
+
+# Reinstall libpcre2 and install postgresql
+# See: https://gitlab.com/gitlab-org/gitaly/-/issues/4085
+RUN set -eux; \
+ rm -f /usr/lib/libpcre2*; \
+ apt-get update && apt-get install -y --reinstall --no-install-recommends \
+ libpcre2-16-0 \
+ libpcre2-32-0 \
+ libpcre2-8-0 \
+ libpcre2-dev \
+ libpcre2-posix2 \
+ && apt-get install -y --no-install-recommends postgresql-13; \
+ apt-get autoclean -y
+
+# Clone GDK and install system dependencies, purge system git
+ARG GDK_SHA
+ENV GDK_SHA=${GDK_SHA:-main}
+RUN set -eux; \
+ git -c advice.detachedHead=false clone --depth 1 https://gitlab.com/gitlab-org/gitlab-development-kit.git; \
+ git -C gitlab-development-kit fetch --depth 1 origin ${GDK_SHA}; \
+ git -C gitlab-development-kit -c advice.detachedHead=false checkout ${GDK_SHA}; \
+ mkdir -p gitlab-development-kit/gitlab && chown -R gdk:gdk gitlab-development-kit; \
+ apt-get update && apt-get install -y --no-install-recommends $(grep -o '^[^#]*' gitlab-development-kit/packages_debian.txt); \
+ apt-get remove -y git git-lfs; \
+ apt-get autoclean -y && apt-get autoremove -y
+
+# Allow passwordless /etc/hosts update by gdk user
+RUN echo "gdk ALL=(ALL) NOPASSWD: /usr/bin/tee -a /etc/hosts" >> /etc/sudoers
+
+USER gdk
+WORKDIR /home/gdk/gitlab-development-kit
+
+# Install GDK and gem dependencies
+ARG GDK_VERSION
+ENV GDK_VERSION=${GDK_VERSION:-0.2.16}
+RUN set -eux; \
+ gem install gitlab-development-kit -v ${GDK_VERSION} && touch .gitlab-gdk-gem; \
+ bundle install; \
+ rm -rf ${GEM_HOME}/cache
+
+COPY --chown=gdk:gdk qa/gdk/gdk.yml ./
+
+# Build gitaly
+#
+COPY --chown=gdk:gdk GITALY_SERVER_VERSION ./gitlab/
+RUN set -eux; \
+ make gitaly-setup; \
+ rm -rf gitaly/_build/cache \
+ gitaly/_build/deps/git/source \
+ gitaly/_build/deps/libgit2/source \
+ gitaly/_build/deps \
+ gitaly/_build/intermediate \
+ ${GEM_HOME}/cache \
+ && go clean -cache
+
+# Build gitlab-shell
+#
+COPY --chown=gdk:gdk GITLAB_SHELL_VERSION ./gitlab/
+RUN set -eux; \
+ make gitlab-shell-setup; \
+ rm -rf ${GEM_HOME}/cache \
+ && go clean -cache
+
+# Build gitlab-workhorse
+#
+COPY --chown=gdk:gdk VERSION GITLAB_WORKHORSE_VERSION ./gitlab/
+COPY --chown=gdk:gdk workhorse ./gitlab/workhorse
+RUN set -eux; \
+ make gitlab-workhorse-setup \
+ && mv gitlab/workhorse ./; \
+ rm -rf ${GEM_HOME}/cache \
+ && go clean -cache
+
+# Build metrics-exporter
+#
+COPY --chown=gdk:gdk GITLAB_METRICS_EXPORTER_VERSION ./gitlab/
+RUN set -eux; \
+ make gitlab-metrics-exporter-setup; \
+ go clean -cache
+
+# Install gitlab gem dependencies
+#
+COPY --chown=gdk:gdk Gemfile Gemfile.lock ./gitlab/
+COPY --chown=gdk:gdk vendor/gems ./gitlab/vendor/gems
+RUN make .gitlab-bundle && rm -rf ${GEM_HOME}/cache
+
+# Install gitlab npm dependencies
+#
+COPY --chown=gdk:gdk package.json yarn.lock ./gitlab/
+COPY --chown=gdk:gdk scripts/frontend/postinstall.js ./gitlab/scripts/frontend/postinstall.js
+RUN make .gitlab-yarn && yarn cache clean
+
+# Executable gdk image
+#
+FROM registry.gitlab.com/gitlab-org/gitlab/gitlab-qa-gdk-base:${BASE_TAG} as gdk
+
+ENV GITLAB_LICENSE_MODE=test \
+ GDK_KILL_CONFIRM=true
+
+# Copy code
+COPY --chown=gdk:gdk ./ ./gitlab/
+COPY --chown=gdk:gdk qa/gdk/entrypoint ../
+
+# Create missing pids folder and sync compiled workhorse
+RUN mkdir -p gitlab/tmp/pids \
+ && rsync -a --remove-source-files workhorse/ gitlab/workhorse/
+
+# Set up GDK
+RUN make \
+ redis/redis.conf \
+ all \
+ && gdk kill \
+ && rm -rf ${GEM_HOME}/cache \
+ gitaly/_build/cache \
+ gitaly/_build/deps/git/source \
+ gitaly/_build/deps/libgit2/source \
+ gitaly/_build/deps \
+ gitaly/_build/intermediate \
+ && go clean -modcache \
+ && go clean -cache
+
+ENTRYPOINT [ "/home/gdk/entrypoint" ]
+CMD [ "gdk", "tail" ]
+
+HEALTHCHECK --interval=10s --timeout=1s --start-period=5s --retries=17 \
+ CMD curl --fail http://0.0.0.0:3000/users/sign_in || exit 1
+
+EXPOSE 3000
diff --git a/qa/gdk/Dockerfile.gdk.dockerignore b/qa/gdk/Dockerfile.gdk.dockerignore
new file mode 100644
index 00000000000..ef1074ed833
--- /dev/null
+++ b/qa/gdk/Dockerfile.gdk.dockerignore
@@ -0,0 +1,21 @@
+.bundle/
+danger/
+doc/
+log/*.log
+node_modules/
+rubocop/
+tmp/*
+
+db/fixtures/
+!db/fixtures/development/01_admin.rb
+!db/fixtures/development/02_application_settings.rb
+!db/fixtures/development/25_api_personal_access_token.rb
+
+ee/db/fixtures/
+!ee/db/fixtures/development/10_license_file.rb
+
+scripts/
+!scripts/frontend
+
+qa/
+!qa/gdk
diff --git a/qa/gdk/entrypoint b/qa/gdk/entrypoint
new file mode 100755
index 00000000000..3b86f19b9b2
--- /dev/null
+++ b/qa/gdk/entrypoint
@@ -0,0 +1,21 @@
+#!/bin/bash
+
+set -e
+
+# host file can't be modified during docker build because it is created on container start
+# this makes for a more portable solution as other alternative is to use `--add-host` option for 'docker run' command
+# We want a non-loopback ip otherwise some services (maybe just workhorse?) bind to localhost and can't be accessed
+# from outside the container
+echo "$(hostname -i) gdk.test" | sudo tee -a /etc/hosts > /dev/null
+
+# make sure we don't override existing BUNDLE_PATH which happens on CI where all job variables are also passed in to service
+unset BUNDLE_PATH
+
+gdk start
+
+# /builds folder is present when running as a service on CI
+if [ -d /builds ]; then
+ exec "$@" | tee -a /builds/gdk.log
+else
+ exec "$@" | tee -a ${HOME}/gitlab-development-kit/gitlab/log/gdk.log
+fi
diff --git a/qa/gdk/gdk.yml b/qa/gdk/gdk.yml
index 0494cd0d3c1..649ac9a60c6 100644
--- a/qa/gdk/gdk.yml
+++ b/qa/gdk/gdk.yml
@@ -6,12 +6,15 @@ webpack:
live_reload: false
sourcemaps: false
incremental: false
+ static: true
gdk:
ask_to_restart_after_update: false
auto_reconfigure: false
overwrite_changes: true
quiet: false
gitlab:
+ cache_classes: true
+ lefthook_enabled: false
rails:
bootsnap: false
hostname: gdk.test
diff --git a/qa/gdk/launch b/qa/gdk/launch
deleted file mode 100755
index 249484b417c..00000000000
--- a/qa/gdk/launch
+++ /dev/null
@@ -1,39 +0,0 @@
-#!/bin/bash
-
-COMMIT_REF=${1:-$CI_COMMIT_SHA}
-RSPEC_ARGS=$2
-
-if [ -z "${COMMIT_REF}" ]; then
- echo "Please provide a commit ref with the code to be tested as the first argument"
- exit 1
-fi
-
-# Set the GitLab license mode to "test" so that GitLab uses the appropriate encryption key
-export GITLAB_LICENSE_MODE="test"
-
-# Create the temporary directory that screenshots are saved to
-sudo install -m 777 -d /home/gdk/gdk/gitlab/qa/tmp
-
-# Update GDK
-(cd .. ; gdk update ; cat gdk.yml)
-
-# Reset, fetch, and checkout the GitLab repository with the code from the ref to be tested
-git reset --hard
-git fetch origin $COMMIT_REF
-git checkout $COMMIT_REF
-
-# Install the required gems
-bundle install --jobs=$(nproc) --retry=3 --quiet
-
-# Run the database migrations
-bundle exec rake db:migrate
-
-# Restart GDK to be sure any changes are accounted for in running services, start any stopped services, and wait until the GDK is reachable
-(cd .. ; gdk restart ; ./support/test_url http://gdk.test:3000)
-
-# Install the required gems in the QA directory
-cd qa
-bundle install --jobs=$(nproc) --retry=3 --quiet
-
-# Run the tests
-bundle exec bin/qa Test::Instance::All http://gdk.test:3000 -- $RSPEC_ARGS
diff --git a/qa/lib/gitlab/page/group/settings/billing.rb b/qa/lib/gitlab/page/group/settings/billing.rb
index 1cb31c995f6..0d25a012db3 100644
--- a/qa/lib/gitlab/page/group/settings/billing.rb
+++ b/qa/lib/gitlab/page/group/settings/billing.rb
@@ -33,8 +33,13 @@ module Gitlab
# Waits for subscription to be synced and UI to be updated
#
# @param subscription_plan [String]
- def wait_for_subscription(subscription_plan, page:)
- ::QA::Support::Waiter.wait_until(max_duration: 30, sleep_interval: 3, reload_page: page) do
+ def wait_for_subscription(subscription_plan)
+ ::QA::Support::Waiter.wait_until(
+ max_duration: ::QA::Support::Helpers::Zuora::ZUORA_TIMEOUT,
+ sleep_interval: 2,
+ reload_page: Chemlab.configuration.browser.session,
+ message: "Subscription plan '#{subscription_plan}' failed to appear"
+ ) do
billing_plan_header.match?(/currently using the #{subscription_plan} saas plan/i)
end
end
diff --git a/qa/lib/gitlab/page/group/settings/usage_quotas.rb b/qa/lib/gitlab/page/group/settings/usage_quotas.rb
index a6d9cfa7846..11d1dd78dbe 100644
--- a/qa/lib/gitlab/page/group/settings/usage_quotas.rb
+++ b/qa/lib/gitlab/page/group/settings/usage_quotas.rb
@@ -33,9 +33,8 @@ module Gitlab
div :project
div :storage_type_legend
span :container_registry_size
- div :purchased_usage_total
+ div :storage_purchased, 'data-testid': 'storage-purchased'
div :storage_purchase_successful_alert, text: /You have successfully purchased a storage/
- div :additional_storage_alert, text: /purchase additional storage/
# Pending members
div :pending_members
@@ -50,13 +49,10 @@ module Gitlab
additional_ci_minutes[/(\d+){2}/]
end
- # Waits and Checks if storage available alert presents on the page
- #
- # @return [Boolean] True if the alert presents, false if not after 5 second wait
- def additional_storage_available?
- additional_storage_alert_element.wait_until(timeout: 5, &:present?)
- rescue Watir::Wait::TimeoutError
- false
+ def additional_ci_minutes_added?
+ # When opening the Usage quotas page, Seats quota tab is opened briefly even when url is to a different tab
+ ::QA::Support::WaitForRequests.wait_for_requests
+ additional_ci_minutes?
end
# Waits and Checks if storage project data loaded
@@ -72,15 +68,37 @@ module Gitlab
#
# @return [Float] Total purchased storage value in GiB
def total_purchased_storage
- additional_storage_alert_element.wait_until(&:present?)
+ ::QA::Support::WaitForRequests.wait_for_requests
- purchased_usage_total[/(\d+){2}.\d+/].to_f
+ storage_purchased[/(\d+){2}.\d+/].to_f
end
- def additional_ci_minutes_added?
- # When opening the Usage quotas page, Seats quota tab is opened briefly even when url is to a different tab
- ::QA::Support::WaitForRequests.wait_for_requests
- additional_ci_minutes?
+ # Waits for additional CI minutes to be available on the page
+ def wait_for_additional_ci_minutes_available
+ ::QA::Support::Waiter.wait_until(
+ max_duration: ::QA::Support::Helpers::Zuora::ZUORA_TIMEOUT,
+ sleep_interval: 2,
+ reload_page: Chemlab.configuration.browser.session,
+ message: 'Expected additional CI minutes but they did not appear.'
+ ) do
+ additional_ci_minutes_added?
+ end
+ end
+
+ # Waits for additional CI minutes amount to match the expected number of minutes
+ #
+ # @param [String] minutes
+ def wait_for_additional_ci_minute_limits(minutes)
+ wait_for_additional_ci_minutes_available
+
+ ::QA::Support::Waiter.wait_until(
+ max_duration: ::QA::Support::Helpers::Zuora::ZUORA_TIMEOUT,
+ sleep_interval: 2,
+ reload_page: Chemlab.configuration.browser.session,
+ message: "Expected additional CI minutes to equal #{minutes}"
+ ) do
+ additional_ci_limits == minutes
+ end
end
end
end
diff --git a/qa/lib/gitlab/page/group/settings/usage_quotas.stub.rb b/qa/lib/gitlab/page/group/settings/usage_quotas.stub.rb
index 6c38625bb3b..8099d1cf53a 100644
--- a/qa/lib/gitlab/page/group/settings/usage_quotas.stub.rb
+++ b/qa/lib/gitlab/page/group/settings/usage_quotas.stub.rb
@@ -533,51 +533,27 @@ module Gitlab
# This is a stub, used for indexing. The method is dynamically generated.
end
- # @note Defined as +div :purchased_usage_total_free+
- # @return [String] The text content or value of +purchased_usage_total_free+
- def purchased_usage_total_free
+ # @note Defined as +div :storage_purchased+
+ # @return [String] The text content or value of +storage_purchased+
+ def storage_purchased
# This is a stub, used for indexing. The method is dynamically generated.
end
# @example
# Gitlab::Page::Group::Settings::UsageQuotas.perform do |usage_quotas|
- # expect(usage_quotas.purchased_usage_total_free_element).to exist
+ # expect(usage_quotas.storage_purchased_element).to exist
# end
# @return [Watir::Div] The raw +Div+ element
- def purchased_usage_total_free_element
+ def storage_purchased_element
# This is a stub, used for indexing. The method is dynamically generated.
end
# @example
# Gitlab::Page::Group::Settings::UsageQuotas.perform do |usage_quotas|
- # expect(usage_quotas).to be_purchased_usage_total_free
+ # expect(usage_quotas).to be_storage_purchased
# end
- # @return [Boolean] true if the +purchased_usage_total_free+ element is present on the page
- def purchased_usage_total_free?
- # This is a stub, used for indexing. The method is dynamically generated.
- end
-
- # @note Defined as +span :purchased_usage_total+
- # @return [String] The text content or value of +purchased_usage_total+
- def purchased_usage_total
- # This is a stub, used for indexing. The method is dynamically generated.
- end
-
- # @example
- # Gitlab::Page::Group::Settings::UsageQuotas.perform do |usage_quotas|
- # expect(usage_quotas.purchased_usage_total_element).to exist
- # end
- # @return [Watir::Span] The raw +Span+ element
- def purchased_usage_total_element
- # This is a stub, used for indexing. The method is dynamically generated.
- end
-
- # @example
- # Gitlab::Page::Group::Settings::UsageQuotas.perform do |usage_quotas|
- # expect(usage_quotas).to be_purchased_usage_total
- # end
- # @return [Boolean] true if the +purchased_usage_total+ element is present on the page
- def purchased_usage_total?
+ # @return [Boolean] true if the +storage_purchased+ element is present on the page
+ def storage_purchased?
# This is a stub, used for indexing. The method is dynamically generated.
end
diff --git a/qa/lib/gitlab/page/trials/select.rb b/qa/lib/gitlab/page/trials/select.rb
index 6eaf6003837..d4cf54805ea 100644
--- a/qa/lib/gitlab/page/trials/select.rb
+++ b/qa/lib/gitlab/page/trials/select.rb
@@ -4,7 +4,7 @@ module Gitlab
module Page
module Trials
class Select < Chemlab::Page
- path '/-/trials/select'
+ path '/-/trials/new?step=trial'
button :select_group, 'data-testid': 'base-dropdown-toggle'
div :group_dropdown, 'data-testid': 'base-dropdown-menu'
diff --git a/qa/qa/ce/strategy.rb b/qa/qa/ce/strategy.rb
index 2587da17739..24398e8eace 100644
--- a/qa/qa/ce/strategy.rb
+++ b/qa/qa/ce/strategy.rb
@@ -7,17 +7,24 @@ module QA
def perform_before_hooks
if QA::Runtime::Env.admin_personal_access_token.present?
- QA::Resource::PersonalAccessTokenCache.set_token_for_username(QA::Runtime::User.admin_username,
- QA::Runtime::Env.admin_personal_access_token)
+ QA::Resource::PersonalAccessTokenCache.set_token_for_username(
+ QA::Runtime::User.admin_username,
+ QA::Runtime::Env.admin_personal_access_token
+ )
end
if QA::Runtime::Env.personal_access_token.present? && QA::Runtime::Env.user_username.present?
- QA::Resource::PersonalAccessTokenCache.set_token_for_username(QA::Runtime::Env.user_username,
- QA::Runtime::Env.personal_access_token)
+ QA::Resource::PersonalAccessTokenCache.set_token_for_username(
+ QA::Runtime::Env.user_username,
+ QA::Runtime::Env.personal_access_token
+ )
end
QA::Runtime::Logger.info("Browser: #{QA::Runtime::Env.browser}")
- QA::Runtime::Logger.info("Browser version: #{QA::Runtime::Env.browser_version}")
+
+ if QA::Runtime::Env.use_selenoid?
+ QA::Runtime::Logger.info("Browser version: #{QA::Runtime::Env.selenoid_browser_version}")
+ end
# The login page could take some time to load the first time it is visited.
# We visit the login page and wait for it to properly load only once before the tests.
diff --git a/qa/qa/fixtures/mocks/import/github.yml b/qa/qa/fixtures/mocks/import/github.yml
index 6ee6be471c4..16d038ed091 100644
--- a/qa/qa/fixtures/mocks/import/github.yml
+++ b/qa/qa/fixtures/mocks/import/github.yml
@@ -575,8 +575,6 @@
path: /repos/gitlab-qa-github/import-test/pulls
method: GET
query_params:
- per_page: '100'
- sort: created
state: all
headers:
Host: api.github.com
diff --git a/qa/qa/fixtures/package_managers/npm/npm_install_package_group.yaml.erb b/qa/qa/fixtures/package_managers/npm/npm_install_package_group.yaml.erb
new file mode 100644
index 00000000000..a5ec4f298e2
--- /dev/null
+++ b/qa/qa/fixtures/package_managers/npm/npm_install_package_group.yaml.erb
@@ -0,0 +1,21 @@
+image: node:latest
+
+stages:
+ - install
+
+install:
+ stage: install
+ script:
+ - "npm config set @<%= registry_scope %>:registry <%= gitlab_address_with_port %>/api/v4/groups/<%= another_project.group.id %>/-/packages/npm/"
+ - "npm install <%= package.name %>"
+ cache:
+ key: ${CI_COMMIT_REF_NAME}
+ paths:
+ - node_modules/
+ artifacts:
+ paths:
+ - node_modules/
+ only:
+ - "<%= another_project.default_branch %>"
+ tags:
+ - "runner-for-<%= another_project.group.name %>" \ No newline at end of file
diff --git a/qa/qa/fixtures/package_managers/npm/npm_upload_package_group.yaml.erb b/qa/qa/fixtures/package_managers/npm/npm_upload_package_group.yaml.erb
new file mode 100644
index 00000000000..13c00cd17c4
--- /dev/null
+++ b/qa/qa/fixtures/package_managers/npm/npm_upload_package_group.yaml.erb
@@ -0,0 +1,14 @@
+image: node:latest
+
+stages:
+ - deploy
+
+deploy:
+ stage: deploy
+ script:
+ - echo "//${CI_SERVER_HOST}/api/v4/projects/${CI_PROJECT_ID}/packages/npm/:_authToken=<%= auth_token %>">.npmrc
+ - npm publish
+ only:
+ - "<%= project.default_branch %>"
+ tags:
+ - "runner-for-<%= project.group.name %>" \ No newline at end of file
diff --git a/qa/qa/fixtures/package_managers/npm/package_instance.json.erb b/qa/qa/fixtures/package_managers/npm/package.json.erb
index 46fecf97e2c..46fecf97e2c 100644
--- a/qa/qa/fixtures/package_managers/npm/package_instance.json.erb
+++ b/qa/qa/fixtures/package_managers/npm/package.json.erb
diff --git a/qa/qa/fixtures/package_managers/npm/package_project.json.erb b/qa/qa/fixtures/package_managers/npm/package_project.json.erb
deleted file mode 100644
index 46fecf97e2c..00000000000
--- a/qa/qa/fixtures/package_managers/npm/package_project.json.erb
+++ /dev/null
@@ -1,8 +0,0 @@
-{
- "name": "<%= package.name %>",
- "version": "1.0.0",
- "description": "Example package for GitLab npm registry",
- "publishConfig": {
- "@<%= registry_scope %>:registry": "<%= gitlab_address_with_port %>/api/v4/projects/<%= project.id %>/packages/npm/"
- }
-} \ No newline at end of file
diff --git a/qa/qa/flow/purchase.rb b/qa/qa/flow/purchase.rb
index 32c4f469207..2eee15b874c 100644
--- a/qa/qa/flow/purchase.rb
+++ b/qa/qa/flow/purchase.rb
@@ -3,7 +3,7 @@
module QA
module Flow
module Purchase
- include QA::Support::Helpers::Plan
+ include Support::Helpers::Plan
extend self
diff --git a/qa/qa/mobile/page/project/issue/show.rb b/qa/qa/mobile/page/project/issue/show.rb
index df96a318806..4184c9871cc 100644
--- a/qa/qa/mobile/page/project/issue/show.rb
+++ b/qa/qa/mobile/page/project/issue/show.rb
@@ -13,7 +13,7 @@ module QA
base.class_eval do
view 'app/assets/javascripts/issues/show/components/header_actions.vue' do
- element :issue_actions_dropdown
+ element :mobile_dropdown
element :mobile_close_issue_button
element :mobile_reopen_issue_button
end
@@ -21,12 +21,12 @@ module QA
end
def click_close_issue_button
- find('[data-qa-selector="issue_actions_dropdown"] > button').click
+ find('[data-testid="mobile-dropdown"] > button').click
find_element(:mobile_close_issue_button, visible: false).click
end
def has_reopen_issue_button?
- find('[data-qa-selector="issue_actions_dropdown"] > button').click
+ find('[data-testid="mobile-dropdown"] > button').click
has_element?(:mobile_reopen_issue_button)
end
end
diff --git a/qa/qa/page/base.rb b/qa/qa/page/base.rb
index 7452077de67..6c01fa9f344 100644
--- a/qa/qa/page/base.rb
+++ b/qa/qa/page/base.rb
@@ -5,6 +5,14 @@ require 'capybara/dsl'
module QA
module Page
class Base
+ # Generic matcher for common css selectors like:
+ # - class name '.someclass'
+ # - id '#someid'
+ # - selection by attributes 'input[attribute=name][value=value]'
+ #
+ # @return [Regex]
+ CSS_SELECTOR_PATTERN = /^(\.[a-z-]+|\#[a-z-]+)+|([a-z]+\[.*\])$/i
+
prepend Support::Page::Logging
prepend Mobile::Page::Base if QA::Runtime::Env.mobile_layout?
@@ -386,6 +394,7 @@ module QA
def element_selector_css(name, *attributes)
return name.selector_css if name.is_a? Page::Element
+ return name if name.is_a?(String) && name.match?(CSS_SELECTOR_PATTERN)
Page::Element.new(name, *attributes).selector_css
end
@@ -506,8 +515,8 @@ module QA
return element_when_flag_disabled if has_element?(element_when_flag_disabled, visible: visibility)
raise ElementNotFound,
- "Could not find the expected element as #{element_when_flag_enabled} or #{element_when_flag_disabled}." \
- "The relevant feature flag is #{feature_flag}"
+ "Could not find the expected element as #{element_when_flag_enabled} or #{element_when_flag_disabled}." \
+ "The relevant feature flag is #{feature_flag}"
end
end
end
diff --git a/qa/qa/page/component/blob_content.rb b/qa/qa/page/component/blob_content.rb
index 5ee5d4978e5..a57ef38f768 100644
--- a/qa/qa/page/component/blob_content.rb
+++ b/qa/qa/page/component/blob_content.rb
@@ -22,7 +22,7 @@ module QA
element :copy_contents_button
end
- base.view 'app/assets/javascripts/vue_shared/components/source_viewer/source_viewer_deprecated.vue' do
+ base.view 'app/assets/javascripts/vue_shared/components/source_viewer/source_viewer.vue' do
element :blob_viewer_file_content
end
end
diff --git a/qa/qa/page/component/issuable/common.rb b/qa/qa/page/component/issuable/common.rb
index 768a15a4551..2f116822a12 100644
--- a/qa/qa/page/component/issuable/common.rb
+++ b/qa/qa/page/component/issuable/common.rb
@@ -10,8 +10,8 @@ module QA
def self.included(base)
super
- base.view 'app/assets/javascripts/vue_shared/issuable/show/components/issuable_title.vue' do
- element :title_content, required: true
+ base.view 'app/assets/javascripts/issues/show/components/title.vue' do
+ element :issue_title, required: true
end
end
end
diff --git a/qa/qa/page/component/issuable/sidebar.rb b/qa/qa/page/component/issuable/sidebar.rb
index 0a31dee2b4f..06a3c6a8845 100644
--- a/qa/qa/page/component/issuable/sidebar.rb
+++ b/qa/qa/page/component/issuable/sidebar.rb
@@ -49,7 +49,7 @@ module QA
end
base.view 'app/assets/javascripts/sidebar/components/sidebar_editable_item.vue' do
- element :edit_link
+ element :edit_button
end
base.view 'app/helpers/dropdowns_helper.rb' do
@@ -59,7 +59,7 @@ module QA
def assign_milestone(milestone)
wait_milestone_block_finish_loading do
- click_element(:edit_link)
+ click_element(:edit_button)
click_on(milestone.title)
end
@@ -134,7 +134,7 @@ module QA
def select_labels(labels)
within_element(:labels_block) do
- click_element(:edit_link)
+ click_element(:edit_button)
labels.each do |label|
within_element(:labels_dropdown_content) do
@@ -144,7 +144,7 @@ module QA
end
end
- click_element(:title_content) # to blur dropdown
+ click_element(:issue_title) # to blur dropdown
end
def toggle_more_assignees_link
diff --git a/qa/qa/page/component/note.rb b/qa/qa/page/component/note.rb
index db9492ea516..84cc481945f 100644
--- a/qa/qa/page/component/note.rb
+++ b/qa/qa/page/component/note.rb
@@ -168,7 +168,7 @@ module QA
def select_filter_with_text(text)
retry_on_exception do
- click_element(:title_content)
+ click_element(:issue_title)
click_element :discussion_preferences_dropdown
find_element(:filter_menu_item, text: text).click
diff --git a/qa/qa/page/component/snippet.rb b/qa/qa/page/component/snippet.rb
index 05d59acd8e8..12695ddd5b0 100644
--- a/qa/qa/page/component/snippet.rb
+++ b/qa/qa/page/component/snippet.rb
@@ -43,7 +43,7 @@ module QA
element :snippet_embed_dropdown
end
- base.view 'app/assets/javascripts/vue_shared/components/clone_dropdown.vue' do
+ base.view 'app/assets/javascripts/vue_shared/components/clone_dropdown/clone_dropdown.vue' do
element :copy_http_url_button
element :copy_ssh_url_button
end
@@ -70,6 +70,10 @@ module QA
element :note_author_content
end
+ base.view 'app/views/shared/notes/_notes_with_form.html.haml' do
+ element :notes_list
+ end
+
base.view 'app/views/projects/notes/_more_actions_dropdown.html.haml' do
element :more_actions_dropdown
element :delete_comment_button
@@ -216,6 +220,10 @@ module QA
end
end
+ def within_notes_list(&block)
+ within_element :notes_list, &block
+ end
+
def has_syntax_highlighting?(language)
within_element(:blob_viewer_file_content) do
find('.line')['lang'].to_s == language
diff --git a/qa/qa/page/dashboard/projects.rb b/qa/qa/page/dashboard/projects.rb
index 10529ed69e1..4a81d34b32e 100644
--- a/qa/qa/page/dashboard/projects.rb
+++ b/qa/qa/page/dashboard/projects.rb
@@ -17,6 +17,14 @@ module QA
element :new_project_button
end
+ view 'app/views/dashboard/projects/_blank_state_welcome.html.haml' do
+ element :new_project_button
+ end
+
+ view 'app/views/dashboard/projects/_blank_state_admin_welcome.html.haml' do
+ element :new_project_button
+ end
+
def has_project_with_access_role?(project_name, access_role)
within_element(:project_content, text: project_name) do
has_element?(:user_role_content, text: access_role)
diff --git a/qa/qa/page/element.rb b/qa/qa/page/element.rb
index 6bfdf98587b..f0e67627dca 100644
--- a/qa/qa/page/element.rb
+++ b/qa/qa/page/element.rb
@@ -4,6 +4,8 @@ require 'active_support/core_ext/array/extract_options'
module QA
module Page
+ # Gitlab element css selector builder using data-testid attribute
+ #
class Element
attr_reader :name, :attributes
@@ -13,9 +15,7 @@ module QA
@attributes[:pattern] ||= selector
options.each do |option|
- if option.is_a?(String) || option.is_a?(Regexp)
- @attributes[:pattern] = option
- end
+ @attributes[:pattern] = option if option.is_a?(String) || option.is_a?(Regexp)
end
end
@@ -28,7 +28,7 @@ module QA
end
def selector_css
- %Q([data-qa-selector="#{@name}"]#{additional_selectors},.#{selector})
+ %(#{qa_selector}#{additional_selectors},.#{selector})
end
def expression
@@ -40,14 +40,26 @@ module QA
end
def matches?(line)
- !!(line =~ /["']#{name}['"]|#{expression}/)
+ !!(line =~ /["']#{name}['"]|["']#{convert_to_kebabcase(name)}['"]|#{expression}/)
end
private
+ def convert_to_kebabcase(text)
+ text.to_s.tr('_', '-')
+ end
+
+ def qa_selector
+ [
+ %([data-testid="#{name}"]#{additional_selectors}),
+ %([data-testid="#{convert_to_kebabcase(name)}"]#{additional_selectors}),
+ %([data-qa-selector="#{name}"]#{additional_selectors})
+ ].join(',')
+ end
+
def additional_selectors
@attributes.dup.delete_if { |attr| attr == :pattern || attr == :required }.map do |key, value|
- %Q([data-qa-#{key.to_s.tr('_', '-')}="#{value}"])
+ %([data-qa-#{key.to_s.tr('_', '-')}="#{value}"])
end.join
end
end
diff --git a/qa/qa/page/file/edit.rb b/qa/qa/page/file/edit.rb
index e66019279ce..665fef0d794 100644
--- a/qa/qa/page/file/edit.rb
+++ b/qa/qa/page/file/edit.rb
@@ -8,24 +8,14 @@ module QA
include Shared::CommitButton
include Shared::Editor
- view 'app/assets/javascripts/editor/extensions/source_editor_markdown_livepreview_ext.js' do
- element :editor_toolbar_button, "qaSelector: 'editor_toolbar_button'" # rubocop:disable QA/ElementWithPattern
- end
-
def has_markdown_preview?(component, content)
within_element(:source_editor_preview_container) do
has_css?(component, exact_text: content)
end
end
- def wait_for_markdown_preview(component, content)
- return if has_markdown_preview?(component, content)
-
- raise ElementNotFound, %("Couldn't find #{component} element with content '#{content}')
- end
-
- def click_editor_toolbar
- click_element(:editor_toolbar_button)
+ def preview
+ click_link('Preview')
end
end
end
diff --git a/qa/qa/page/file/show.rb b/qa/qa/page/file/show.rb
index 011b1ea5d81..173baa21160 100644
--- a/qa/qa/page/file/show.rb
+++ b/qa/qa/page/file/show.rb
@@ -12,21 +12,15 @@ module QA
element :lock_button
end
- view 'app/assets/javascripts/vue_shared/components/web_ide_link.vue' do
- element :edit_button
- end
-
view 'app/assets/javascripts/vue_shared/components/actions_button.vue' do
element :action_dropdown
element :edit_menu_item, ':data-qa-selector="`${action.key}_menu_item`"' # rubocop:disable QA/ElementWithPattern
+ element :webide_menu_item, ':data-qa-selector="`${action.key}_menu_item`"' # rubocop:disable QA/ElementWithPattern
end
def click_edit
- within_element(:action_dropdown) do
- click_button(class: 'dropdown-toggle-split')
- click_element(:edit_menu_item)
- click_element(:edit_button)
- end
+ click_element(:action_dropdown)
+ click_element(:edit_menu_item)
end
def click_delete
diff --git a/qa/qa/page/group/menu.rb b/qa/qa/page/group/menu.rb
index 157bc3abaf6..c166023a620 100644
--- a/qa/qa/page/group/menu.rb
+++ b/qa/qa/page/group/menu.rb
@@ -13,9 +13,12 @@ module QA
prepend SubMenus::SuperSidebar::Main
prepend SubMenus::SuperSidebar::Build
prepend SubMenus::SuperSidebar::Operate
+ prepend SubMenus::SuperSidebar::Deploy
end
def click_group_members_item
+ return go_to_members if Runtime::Env.super_sidebar_enabled?
+
hover_group_information do
within_submenu do
click_element(:sidebar_menu_item_link, menu_item: 'Members')
@@ -83,7 +86,9 @@ module QA
end
end
- def go_to_dependency_proxy
+ def go_to_group_dependency_proxy
+ return go_to_dependency_proxy if Runtime::Env.super_sidebar_enabled?
+
hover_group_packages do
within_submenu do
click_element(:sidebar_menu_item_link, menu_item: 'Dependency Proxy')
diff --git a/qa/qa/page/group/sub_menus/super_sidebar/deploy.rb b/qa/qa/page/group/sub_menus/super_sidebar/deploy.rb
new file mode 100644
index 00000000000..4d205898bf6
--- /dev/null
+++ b/qa/qa/page/group/sub_menus/super_sidebar/deploy.rb
@@ -0,0 +1,23 @@
+# frozen_string_literal: true
+
+module QA
+ module Page
+ module Group
+ module SubMenus
+ module SuperSidebar
+ module Deploy
+ extend QA::Page::PageConcern
+
+ def self.prepended(base)
+ super
+
+ base.class_eval do
+ include QA::Page::SubMenus::SuperSidebar::Deploy
+ end
+ end
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/qa/qa/page/group/sub_menus/super_sidebar/main.rb b/qa/qa/page/group/sub_menus/super_sidebar/main.rb
index e470c03b9e5..1bc6fa84935 100644
--- a/qa/qa/page/group/sub_menus/super_sidebar/main.rb
+++ b/qa/qa/page/group/sub_menus/super_sidebar/main.rb
@@ -8,7 +8,7 @@ module QA
module Main
extend QA::Page::PageConcern
- def self.included(base)
+ def self.prepended(base)
super
base.class_eval do
diff --git a/qa/qa/page/main/login.rb b/qa/qa/page/main/login.rb
index bea01a5bbc7..3a836210dea 100644
--- a/qa/qa/page/main/login.rb
+++ b/qa/qa/page/main/login.rb
@@ -42,6 +42,7 @@ module QA
element :saml_login_button
element :github_login_button
element :oidc_login_button
+ element :gitlab_oauth_login_button
end
view 'app/views/layouts/devise.html.haml' do
@@ -108,6 +109,7 @@ module QA
# Happens on clean GDK installations when seeded root admin password is expired
#
def set_up_new_password_if_required(user:, skip_page_validation:)
+ Support::WaitForRequests.wait_for_requests
return unless has_content?('Set up new password', wait: 1)
Profile::Password.perform do |new_password_page|
@@ -189,11 +191,16 @@ module QA
click_element :saml_login_button
end
- def sign_in_with_oidc
+ def sign_in_with_gitlab_oidc
set_initial_password_if_present
click_element :oidc_login_button
end
+ def sign_in_with_gitlab_oauth
+ set_initial_password_if_present
+ click_element :gitlab_oauth_login_button
+ end
+
def sign_out_and_sign_in_as(user:)
Menu.perform(&:sign_out_if_signed_in)
has_sign_in_tab?
@@ -238,9 +245,7 @@ module QA
Support::WaitForRequests.wait_for_requests
- wait_until(sleep_interval: 5, message: '502 - GitLab is taking too much time to respond') do
- has_no_text?('GitLab is taking too much time to respond')
- end
+ wait_for_gitlab_to_respond
# For debugging invalid login attempts
has_notice?('Invalid login or password')
@@ -249,7 +254,14 @@ module QA
terms.accept_terms if terms.visible?
end
+ Flow::UserOnboarding.onboard_user
+
+ wait_for_gitlab_to_respond
+
Page::Main::Menu.perform(&:enable_new_navigation) if Runtime::Env.super_sidebar_enabled?
+
+ wait_for_gitlab_to_respond
+
Page::Main::Menu.validate_elements_present! unless skip_page_validation
end
diff --git a/qa/qa/page/main/menu.rb b/qa/qa/page/main/menu.rb
index 934aa182b12..7e0337035e3 100644
--- a/qa/qa/page/main/menu.rb
+++ b/qa/qa/page/main/menu.rb
@@ -17,11 +17,11 @@ module QA
# Define alternative navbar (super sidebar) which does not yet implement all the same elements
view 'app/assets/javascripts/super_sidebar/components/super_sidebar.vue' do
element :navbar, required: true # TODO: rename to sidebar once it's default implementation
- element :user_menu, required: !Runtime::Env.phone_layout?
- element :user_avatar_content, required: !Runtime::Env.phone_layout?
end
view 'app/assets/javascripts/super_sidebar/components/user_menu.vue' do
+ element :user_menu, required: !Runtime::Env.phone_layout?
+ element :user_avatar_content, required: !Runtime::Env.phone_layout?
element :sign_out_link
element :edit_profile_link
end
@@ -32,6 +32,7 @@ module QA
view 'app/assets/javascripts/super_sidebar/components/user_bar.vue' do
element :global_search_button
+ element :stop_impersonation_link
end
view 'app/assets/javascripts/super_sidebar/components/global_search/components/global_search.vue' do
@@ -252,16 +253,11 @@ module QA
end
def has_admin_area_link?(wait: Capybara.default_max_wait_time)
- within_top_menu do
- click_element(:navbar_dropdown, title: 'Menu')
- has_element?(:admin_area_link, wait: wait)
- end
- end
+ return super if Runtime::Env.super_sidebar_enabled?
- def has_no_admin_area_link?(wait: Capybara.default_max_wait_time)
within_top_menu do
click_element(:navbar_dropdown, title: 'Menu')
- has_no_element?(:admin_area_link, wait: wait)
+ has_element?(:admin_area_link, wait: wait)
end
end
diff --git a/qa/qa/page/merge_request/show.rb b/qa/qa/page/merge_request/show.rb
index e10db796f8e..e0ec5d50bc5 100644
--- a/qa/qa/page/merge_request/show.rb
+++ b/qa/qa/page/merge_request/show.rb
@@ -118,7 +118,7 @@ module QA
end
view 'app/views/projects/merge_requests/_mr_title.html.haml' do
- element :edit_button
+ element :edit_title_button
element :title_content, required: true
end
@@ -201,13 +201,6 @@ module QA
def click_diffs_tab
# Do not wait for spinner due to https://gitlab.com/gitlab-org/gitlab/-/issues/398584
click_element(:diffs_tab, skip_finished_loading_check: true)
-
- # If the diff isn't available when we navigate to the Changes tab
- # we must reload the page. https://gitlab.com/gitlab-org/gitlab/-/issues/398557
- wait_until(reload: true, skip_finished_loading_check_on_refresh: true) do
- QA::Runtime::Logger.debug('Ensuring that diff has loaded async')
- has_element?(:file_tree_button, skip_finished_loading_check: true, wait: 5)
- end
end
def click_pipeline_link
@@ -218,7 +211,7 @@ module QA
# Click by JS is needed to bypass the Moved MR actions popover
# Change back to regular click_element when moved_mr_sidebar FF is removed
# Rollout issue: https://gitlab.com/gitlab-org/gitlab/-/issues/385460
- click_by_javascript(find_element(:edit_button))
+ click_by_javascript(find_element(:edit_title_button, skip_finished_loading_check: true))
end
def fast_forward_not_possible?
@@ -474,10 +467,6 @@ module QA
click_element(:submit_commit_button)
end
- def cancel_auto_merge!
- click_element(:cancel_auto_merge_button)
- end
-
def mr_widget_text
find_element(:mr_widget_content).text
end
diff --git a/qa/qa/page/project/branches/show.rb b/qa/qa/page/project/branches/show.rb
index a97d0afd160..af328f876f7 100644
--- a/qa/qa/page/project/branches/show.rb
+++ b/qa/qa/page/project/branches/show.rb
@@ -5,7 +5,7 @@ module QA
module Project
module Branches
class Show < Page::Base
- view 'app/assets/javascripts/branches/components/delete_branch_button.vue' do
+ view 'app/assets/javascripts/branches/components/branch_more_actions.vue' do
element :delete_branch_button
end
diff --git a/qa/qa/page/project/issue/show.rb b/qa/qa/page/project/issue/show.rb
index 05f38968718..c2f334c930a 100644
--- a/qa/qa/page/project/issue/show.rb
+++ b/qa/qa/page/project/issue/show.rb
@@ -8,6 +8,7 @@ module QA
include Page::Component::Note
include Page::Component::DesignManagement
include Page::Component::Issuable::Sidebar
+ include Page::Component::Issuable::Common
# We need to check phone_layout? instead of mobile_layout? here
# since tablets have the regular top navigation bar
prepend Mobile::Page::Project::Issue::Show if Runtime::Env.phone_layout?
@@ -17,16 +18,11 @@ module QA
end
view 'app/assets/javascripts/issues/show/components/header_actions.vue' do
- element :close_issue_button
- element :reopen_issue_button
- element :issue_actions_ellipsis_dropdown
+ element :toggle_issue_state_button
+ element :desktop_dropdown
element :delete_issue_button
end
- view 'app/assets/javascripts/issues/show/components/title.vue' do
- element :title_content, required: true
- end
-
view 'app/assets/javascripts/related_issues/components/add_issuable_form.vue' do
element :add_issue_button
end
@@ -69,27 +65,29 @@ module QA
# Click by JS is needed to bypass the Moved MR actions popover
# Change back to regular click_element when moved_mr_sidebar FF is removed
# Rollout issue: https://gitlab.com/gitlab-org/gitlab/-/issues/385460
- click_by_javascript(find_element(:close_issue_button))
+ click_by_javascript(find_element(:toggle_issue_state_button, text: 'Close issue'))
end
def has_reopen_issue_button?
- has_element?(:reopen_issue_button)
+ has_element?(:toggle_issue_state_button, text: 'Reopen issue')
end
def has_delete_issue_button?
# Click by JS is needed to bypass the Moved MR actions popover
# Change back to regular click_element when moved_mr_sidebar FF is removed
# Rollout issue: https://gitlab.com/gitlab-org/gitlab/-/issues/385460
- click_by_javascript(find('[data-qa-selector="issue_actions_ellipsis_dropdown"] > button'))
+ click_by_javascript(find('[data-testid="desktop-dropdown"] > button'))
has_element?(:delete_issue_button)
end
def delete_issue
has_delete_issue_button?
- click_element(:delete_issue_button,
- Page::Modal::DeleteIssue,
- wait: Support::Repeater::DEFAULT_MAX_WAIT_TIME)
+ click_element(
+ :delete_issue_button,
+ Page::Modal::DeleteIssue,
+ wait: Support::Repeater::DEFAULT_MAX_WAIT_TIME
+ )
Page::Modal::DeleteIssue.perform(&:confirm_delete_issue)
diff --git a/qa/qa/page/project/menu.rb b/qa/qa/page/project/menu.rb
index 23b3ee61077..534a4da8426 100644
--- a/qa/qa/page/project/menu.rb
+++ b/qa/qa/page/project/menu.rb
@@ -18,6 +18,7 @@ module QA
if Runtime::Env.super_sidebar_enabled?
include Page::SubMenus::SuperSidebar::Manage
+ include Page::SubMenus::SuperSidebar::Deploy
include SubMenus::SuperSidebar::Plan
include SubMenus::SuperSidebar::Settings
include SubMenus::SuperSidebar::Code
diff --git a/qa/qa/page/project/pipeline/show.rb b/qa/qa/page/project/pipeline/show.rb
index 2455555f06c..41c61aaecc8 100644
--- a/qa/qa/page/project/pipeline/show.rb
+++ b/qa/qa/page/project/pipeline/show.rb
@@ -7,8 +7,15 @@ module QA
class Show < QA::Page::Base
include Component::CiBadgeLink
+ # TODO: remove element with FF pipeline_details_header_vue removal
view 'app/assets/javascripts/vue_shared/components/header_ci_component.vue' do
- element :pipeline_header, required: true
+ element :pipeline_header
+ end
+
+ # TODO: make this a requirement at page render - `required: true`
+ # together with FF pipeline_details_header_vue removal
+ view 'app/assets/javascripts/pipelines/components/pipeline_details_header.vue' do
+ element :pipeline_details_header
end
view 'app/views/projects/pipelines/_info.html.haml' do
@@ -56,7 +63,12 @@ module QA
end
def running?(wait: 0)
- within_element(:pipeline_header) do
+ # TODO: remove condition check together with FF pipeline_details_header_vue removal
+ # issue: https://gitlab.com/gitlab-org/gitlab/-/issues/411442
+
+ element = has_element?(:pipeline_details_header) ? :pipeline_details_header : :pipeline_header
+
+ within_element(element) do
page.has_content?('running', wait: wait)
end
end
diff --git a/qa/qa/page/project/pipeline_editor/show.rb b/qa/qa/page/project/pipeline_editor/show.rb
index 6a95d461639..c70b6e76cfe 100644
--- a/qa/qa/page/project/pipeline_editor/show.rb
+++ b/qa/qa/page/project/pipeline_editor/show.rb
@@ -11,8 +11,6 @@ module QA
view 'app/assets/javascripts/ci/pipeline_editor/components/file_nav/branch_switcher.vue' do
element :branch_selector_button, required: true
- element :branch_menu_item_button
- element :branch_menu_container
end
view 'app/assets/javascripts/ci/pipeline_editor/components/commit/commit_form.vue' do
@@ -70,17 +68,6 @@ module QA
click_element(:pipeline_editor_app)
end
- def open_branch_selector_dropdown
- click_element(:branch_selector_button)
- end
-
- def select_branch_from_dropdown(branch_name)
- wait_for_animated_element(:branch_menu_container)
- click_element(:branch_menu_item_button, text: branch_name)
-
- wait_for_requests
- end
-
def source_branch_name
find_element(:source_branch_field).value
end
diff --git a/qa/qa/page/project/secure/configuration_form.rb b/qa/qa/page/project/secure/configuration_form.rb
index 493ec08d023..70eff31bfa9 100644
--- a/qa/qa/page/project/secure/configuration_form.rb
+++ b/qa/qa/page/project/secure/configuration_form.rb
@@ -9,15 +9,13 @@ module QA
view 'app/assets/javascripts/security_configuration/components/app.vue' do
element :security_configuration_container
- element :security_configuration_history_link
+ element :security_view_history_link
end
view 'app/assets/javascripts/security_configuration/components/feature_card.vue' do
- element :dependency_scanning_status, "`${feature.type}_status`" # rubocop:disable QA/ElementWithPattern
- element :sast_status, "`${feature.type}_status`" # rubocop:disable QA/ElementWithPattern
+ element :feature_status
element :sast_enable_button, "`${feature.type}_enable_button`" # rubocop:disable QA/ElementWithPattern
element :dependency_scanning_mr_button, "`${feature.type}_mr_button`" # rubocop:disable QA/ElementWithPattern
- element :license_scanning_status, "`${feature.type}_status`" # rubocop:disable QA/ElementWithPattern
end
view 'app/assets/javascripts/security_configuration/components/auto_dev_ops_alert.vue' do
@@ -25,15 +23,15 @@ module QA
end
def has_security_configuration_history_link?
- has_element?(:security_configuration_history_link)
+ has_element?(:security_view_history_link)
end
def has_no_security_configuration_history_link?
- has_no_element?(:security_configuration_history_link)
+ has_no_element?(:security_view_history_link)
end
def click_security_configuration_history_link
- click_element(:security_configuration_history_link)
+ click_element(:security_view_history_link)
end
def click_sast_enable_button
@@ -44,40 +42,20 @@ module QA
click_element(:dependency_scanning_mr_button)
end
- def has_sast_status?(status_text)
- within_element(:sast_status) do
- has_text?(status_text)
- end
- end
-
- def has_no_sast_status?(status_text)
- within_element(:sast_status) do
- has_no_text?(status_text)
- end
- end
-
- def has_dependency_scanning_status?(status_text)
- within_element(:dependency_scanning_status) do
- has_text?(status_text)
- end
+ def has_true_sast_status?
+ has_element?(:feature_status, feature: 'sast_true_status')
end
- def has_no_dependency_scanning_status?(status_text)
- within_element(:dependency_scanning_status) do
- has_no_text?(status_text)
- end
+ def has_false_sast_status?
+ has_element?(:feature_status, feature: 'sast_false_status')
end
- def has_license_compliance_status?(status_text)
- within_element(:license_scanning_status) do
- has_text?(status_text)
- end
+ def has_true_dependency_scanning_status?
+ has_element?(:feature_status, feature: 'dependency_scanning_true_status')
end
- def has_no_license_compliance_status?(status_text)
- within_element(:license_scanning_status) do
- has_no_text?(status_text)
- end
+ def has_false_dependency_scanning_status?
+ has_element?(:feature_status, feature: 'dependency_scanning_false_status')
end
def has_auto_devops_container?
diff --git a/qa/qa/page/project/settings/ci_variables.rb b/qa/qa/page/project/settings/ci_variables.rb
index 1315ed8ca73..4b587e28382 100644
--- a/qa/qa/page/project/settings/ci_variables.rb
+++ b/qa/qa/page/project/settings/ci_variables.rb
@@ -19,7 +19,8 @@ module QA
click_ci_variable_save_button
wait_until(reload: false) do
- within_element(:ci_variable_table_content) { has_element?(:edit_ci_variable_button) }
+ # Using data-testid="ci-variable-table"
+ within_element(:ci_variable_table) { has_element?(:edit_ci_variable_button) }
end
end
@@ -28,7 +29,8 @@ module QA
end
def click_edit_ci_variable
- within_element(:ci_variable_table_content) do
+ # Using data-testid="ci-variable-table"
+ within_element(:ci_variable_table) do
click_element :edit_ci_variable_button
end
end
diff --git a/qa/qa/page/project/settings/protected_branches.rb b/qa/qa/page/project/settings/protected_branches.rb
index 3eddd0fd33a..e6b13ed77a0 100644
--- a/qa/qa/page/project/settings/protected_branches.rb
+++ b/qa/qa/page/project/settings/protected_branches.rb
@@ -11,9 +11,9 @@ module QA
end
view 'app/views/protected_branches/_create_protected_branch.html.haml' do
- element :allowed_to_push_dropdown
+ element :select_allowed_to_push_dropdown
element :allowed_to_push_dropdown_content
- element :allowed_to_merge_dropdown
+ element :select_allowed_to_merge_dropdown
element :allowed_to_merge_dropdown_content
end
@@ -45,7 +45,7 @@ module QA
private
def select_allowed(action, allowed)
- click_element :"allowed_to_#{action}_dropdown"
+ click_element :"select_allowed_to_#{action}_dropdown"
allowed[:roles] = Resource::ProtectedBranch::Roles::NO_ONE unless allowed.key?(:roles)
diff --git a/qa/qa/page/project/settings/services/slack.rb b/qa/qa/page/project/settings/services/slack.rb
new file mode 100644
index 00000000000..aaf01bbd6e8
--- /dev/null
+++ b/qa/qa/page/project/settings/services/slack.rb
@@ -0,0 +1,23 @@
+# frozen_string_literal: true
+
+module QA
+ module Page
+ module Project
+ module Settings
+ module Services
+ class Slack < Chemlab::Page
+ strong :slack_text, visible_text: /install/i
+
+ def start_slack_install
+ slack_link.click
+ end
+
+ def slack_link
+ slack_text_element.parent
+ end
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/qa/qa/page/project/show.rb b/qa/qa/page/project/show.rb
index daaee280b84..95a6c840684 100644
--- a/qa/qa/page/project/show.rb
+++ b/qa/qa/page/project/show.rb
@@ -62,10 +62,6 @@ module QA
element :new_file_menu_item
end
- view 'app/assets/javascripts/vue_shared/components/web_ide_link.vue' do
- element :web_ide_button
- end
-
view 'app/views/projects/blob/viewers/_loading.html.haml' do
element :spinner_placeholder
end
@@ -154,7 +150,8 @@ module QA
end
def open_web_ide!
- click_element(:web_ide_button)
+ click_element(:action_dropdown)
+ click_element(:webide_menu_item)
page.driver.browser.switch_to.window(page.driver.browser.window_handles.last)
end
@@ -164,7 +161,8 @@ module QA
end
def has_edit_fork_button?
- has_element?(:web_ide_button, text: 'Edit fork in Web IDE')
+ click_element(:action_dropdown)
+ has_element?(:webide_menu_item, text: 'Edit fork in Web IDE')
end
def project_name
diff --git a/qa/qa/page/project/sub_menus/repository.rb b/qa/qa/page/project/sub_menus/repository.rb
index b8ebaa10a49..274dd3a58c8 100644
--- a/qa/qa/page/project/sub_menus/repository.rb
+++ b/qa/qa/page/project/sub_menus/repository.rb
@@ -38,6 +38,8 @@ module QA
end
def go_to_repository_contributors
+ return go_to_contributor_statistics if Runtime::Env.super_sidebar_enabled?
+
hover_repository do
within_submenu do
click_element(:sidebar_menu_item_link, menu_item: 'Contributor statistics')
diff --git a/qa/qa/page/project/sub_menus/super_sidebar/code.rb b/qa/qa/page/project/sub_menus/super_sidebar/code.rb
index 44d46725b47..fae7210e3c8 100644
--- a/qa/qa/page/project/sub_menus/super_sidebar/code.rb
+++ b/qa/qa/page/project/sub_menus/super_sidebar/code.rb
@@ -36,6 +36,10 @@ module QA
open_code_submenu('Compare revisions')
end
+ def go_to_merge_requests
+ open_code_submenu('Merge requests')
+ end
+
private
def open_code_submenu(sub_menu)
diff --git a/qa/qa/page/project/sub_menus/super_sidebar/deploy.rb b/qa/qa/page/project/sub_menus/super_sidebar/deploy.rb
new file mode 100644
index 00000000000..f19e18b11d7
--- /dev/null
+++ b/qa/qa/page/project/sub_menus/super_sidebar/deploy.rb
@@ -0,0 +1,31 @@
+# frozen_string_literal: true
+
+module QA
+ module Page
+ module Project
+ module SubMenus
+ module SuperSidebar
+ module Deploy
+ extend QA::Page::PageConcern
+
+ def self.included(base)
+ super
+
+ base.class_eval do
+ include QA::Page::SubMenus::SuperSidebar::Deploy
+ end
+ end
+
+ def go_to_releases
+ open_deploy_submenu("Releases")
+ end
+
+ def go_to_feature_flags
+ open_deploy_submenu("Feature flags")
+ end
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/qa/qa/page/project/sub_menus/super_sidebar/main.rb b/qa/qa/page/project/sub_menus/super_sidebar/main.rb
index 63641248b15..bf2619737ab 100644
--- a/qa/qa/page/project/sub_menus/super_sidebar/main.rb
+++ b/qa/qa/page/project/sub_menus/super_sidebar/main.rb
@@ -8,14 +8,6 @@ module QA
module Main
extend QA::Page::PageConcern
- def self.included(base)
- super
-
- base.class_eval do
- include QA::Page::SubMenus::SuperSidebar::Main
- end
- end
-
def click_project
click_element(:nav_item_link, submenu_item: 'Project overview')
end
diff --git a/qa/qa/page/project/sub_menus/super_sidebar/plan.rb b/qa/qa/page/project/sub_menus/super_sidebar/plan.rb
index fe45bb6bb65..fe77789f371 100644
--- a/qa/qa/page/project/sub_menus/super_sidebar/plan.rb
+++ b/qa/qa/page/project/sub_menus/super_sidebar/plan.rb
@@ -25,6 +25,10 @@ module QA
def go_to_open_jira
open_plan_submenu("Open Jira")
end
+
+ def go_to_issues
+ open_plan_submenu("Issues")
+ end
end
end
end
diff --git a/qa/qa/page/project/web_ide/edit.rb b/qa/qa/page/project/web_ide/edit.rb
index dda329ab582..8432edff046 100644
--- a/qa/qa/page/project/web_ide/edit.rb
+++ b/qa/qa/page/project/web_ide/edit.rb
@@ -68,7 +68,7 @@ module QA
element :delete_button
end
- view 'app/assets/javascripts/vue_shared/components/confirm_fork_modal.vue' do
+ view 'app/assets/javascripts/vue_shared/components/web_ide/confirm_fork_modal.vue' do
element :fork_project_button
element :confirm_fork_modal
end
@@ -111,8 +111,12 @@ module QA
# Used for stablility, due to feature_caching of vscode_web_ide
def wait_until_ide_loads
- Support::Waiter.wait_until(sleep_interval: 2, max_duration: 120, reload_page: page,
- retry_on_exception: true) do
+ Support::Waiter.wait_until(
+ sleep_interval: 2,
+ max_duration: 120,
+ reload_page: page,
+ retry_on_exception: true
+ ) do
has_element?(:commit_mode_tab)
end
end
diff --git a/qa/qa/page/project/web_ide/vscode.rb b/qa/qa/page/project/web_ide/vscode.rb
index 1a9fad56a10..6a570978dbe 100644
--- a/qa/qa/page/project/web_ide/vscode.rb
+++ b/qa/qa/page/project/web_ide/vscode.rb
@@ -1,64 +1,183 @@
# frozen_string_literal: true
-# VSCode WebIDE is built off an iFrame application therefore we are uanble to use `qa-selectors`
+# VSCode WebIDE is built off an iFrame application therefore we are unable to use `qa-selectors`
module QA
module Page
module Project
module WebIDE
class VSCode < Page::Base
- # Use to Pass Test::Sanity::Selectors temporarily until iframe [data-qa-* selector added
view 'app/views/shared/_broadcast_message.html.haml' do
element :broadcast_notification_container
element :close_button
end
- # Used for stablility, due to feature_caching of vscode_web_ide
- def wait_for_ide_to_load
- page.driver.browser.switch_to.window(page.driver.browser.window_handles.last)
- wait_for_requests
- Support::Waiter.wait_until(max_duration: 60, reload_page: page, retry_on_exception: true) do
+ def has_file_explorer?
+ page.has_css?('.explorer-folders-view', visible: true)
+ end
+
+ def right_click_file_explorer
+ page.find('.explorer-folders-view', visible: true).right_click
+ end
+
+ def has_new_folder_menu_item?
+ page.has_css?('[aria-label="New Folder..."]', visible: true)
+ end
+
+ def click_new_folder_menu_item
+ page.find('[aria-label="New Folder..."]').click
+ end
+
+ def enter_new_folder_text_input(name)
+ page.find('.explorer-item-edited', visible: true)
+ send_keys(name, :enter)
+ end
+
+ def has_upload_menu_item?
+ page.has_css?('[aria-label="Upload..."]', visible: true)
+ end
+
+ def click_upload_menu_item
+ page.find('[aria-label="Upload..."]').click
+ end
+
+ def enter_file_input(file)
+ page.find('input[type="file"]', visible: false).send_keys(file)
+ end
+
+ def has_commit_pending_tab?
+ page.has_css?('.scm-viewlet-label', visible: true)
+ end
+
+ def click_commit_pending_tab
+ page.find('.scm-viewlet-label', visible: true).click
+ end
+
+ def click_commit_tab
+ page.find('a.codicon-source-control-view-icon', visible: true).click
+ end
+
+ def has_commit_message_box?
+ page.has_css?('div.view-lines.monaco-mouse-cursor-text', visible: true)
+ end
+
+ def enter_commit_message(message)
+ page.find('div.view-lines.monaco-mouse-cursor-text', visible: true).send_keys(message)
+ end
+
+ def click_commit_button
+ page.find('a.monaco-text-button', visible: true).click
+ end
+
+ def has_notification_box?
+ page.has_css?('a.monaco-text-button', visible: true)
+ end
+
+ def create_merge_request
+ Support::Waiter.wait_until(max_duration: 10, retry_on_exception: true) do
within_vscode_editor do
- # vscode file_explorer element
- page.has_css?('.explorer-folders-view', visible: true)
+ page.find('.monaco-button[title="Create MR"]').click
end
end
end
+ def click_new_branch
+ page.find('.monaco-button[title="Create new branch"]').click
+ end
+
+ def has_branch_input_field?
+ page.has_css?('.monaco-findInput', visible: true)
+ end
+
+ def has_message?(content)
+ within_vscode_editor do
+ page.has_content?(content)
+ end
+ end
+
def within_vscode_editor(&block)
iframe = find('#ide iframe')
page.within_frame(iframe, &block)
end
+ # Used for stablility, due to feature_caching of vscode_web_ide
+ def wait_for_ide_to_load
+ page.driver.browser.switch_to.window(page.driver.browser.window_handles.last)
+ # On test environments we have a broadcast message that can cover the buttons
+ if has_element?(:broadcast_notification_container, wait: 5)
+ within_element(:broadcast_notification_container) do
+ click_element(:close_button)
+ end
+ end
+
+ wait_for_requests
+ Support::Waiter.wait_until(max_duration: 10, reload_page: page, retry_on_exception: true) do
+ within_vscode_editor do
+ # Check for webide file_explorer element
+ has_file_explorer?
+ end
+ end
+ end
+
def create_new_folder(name)
within_vscode_editor do
- # Use for stability, WebIDE inside an iframe is finnicky
- Support::Waiter.wait_until(max_duration: 60, retry_on_exception: true) do
- page.find('.explorer-folders-view').right_click
- # new_folder_button
- page.has_css?('[aria-label="New Folder..."]', visible: true)
- end
+ right_click_file_explorer
+ has_new_folder_menu_item?
- # Additonal wait for stability, webdriver sometimes moves too fast
- Support::Waiter.wait_until(max_duration: 60, retry_on_exception: true) do
- page.find('[aria-label="New Folder..."]').click
+ # Use for stability, WebIDE inside an iframe is finnicky, webdriver sometimes moves too fast
+ Support::Waiter.wait_until(max_duration: 20, retry_on_exception: true) do
+ click_new_folder_menu_item
# Verify New Folder button is triggered and textbox is waiting for input
- page.find('.explorer-item-edited', visible: true)
- send_keys(name, :enter)
+ enter_new_folder_text_input(name)
page.has_content?(name)
end
end
end
- def commit_and_push(folder_name)
+ def commit_and_push(file_name)
+ commit_toggle(file_name)
+ push_to_new_branch
+ end
+
+ def commit_toggle(message)
within_vscode_editor do
- # Commit Tab
- page.find('a.codicon-source-control-view-icon').click
- send_keys(folder_name)
- page.has_content?(folder_name)
-
- # Commit Button
- page.find('a.monaco-text-button').click
- page.has_css?('.notification-list-item-details-row', visible: true)
+ if has_commit_pending_tab?
+ click_commit_pending_tab
+ else
+ click_commit_tab
+ end
+
+ has_commit_message_box?
+ send_keys(message)
+ page.has_content?(message)
+ click_commit_button
+ has_notification_box?
+ end
+ end
+
+ def push_to_new_branch
+ within_vscode_editor do
+ click_new_branch
+ has_branch_input_field?
+ # Typing enter to 'New branch name' popup to take the default branch name
+ send_keys(:enter)
+ end
+ end
+
+ def upload_file(file_path)
+ wait_for_ide_to_load
+ within_vscode_editor do
+ # VSCode eagerly removes the input[type='file'] from click on Upload.
+ # We need to execute a script on the iframe to stub out the iframes body.removeChild to add it back in.
+ page.execute_script("document.body.removeChild = function(){};")
+
+ right_click_file_explorer
+ has_upload_menu_item?
+
+ # Use for stability, WebIDE inside an iframe is finnicky, webdriver sometimes moves too fast
+ Support::Waiter.wait_until(max_duration: 20, retry_on_exception: true) do
+ click_upload_menu_item
+ enter_file_input(file_path)
+ end
end
end
end
diff --git a/qa/qa/page/search/results.rb b/qa/qa/page/search/results.rb
index 769f8accfca..a04fd9092d1 100644
--- a/qa/qa/page/search/results.rb
+++ b/qa/qa/page/search/results.rb
@@ -4,7 +4,7 @@ module QA
module Page
module Search
class Results < QA::Page::Base
- view 'app/assets/javascripts/search/sidebar/components/scope_navigation.vue' do
+ view 'app/assets/javascripts/search/sidebar/components/scope_legacy_navigation.vue' do
element :code_tab, ':data-qa-selector="qaSelectorValue(item)"' # rubocop:disable QA/ElementWithPattern
element :projects_tab, ':data-qa-selector="qaSelectorValue(item)"' # rubocop:disable QA/ElementWithPattern
end
diff --git a/qa/qa/page/sub_menus/super_sidebar/context_switcher.rb b/qa/qa/page/sub_menus/super_sidebar/context_switcher.rb
index 1fd35e57dc2..e5f2e702e60 100644
--- a/qa/qa/page/sub_menus/super_sidebar/context_switcher.rb
+++ b/qa/qa/page/sub_menus/super_sidebar/context_switcher.rb
@@ -30,13 +30,22 @@ module QA
go_to_context("Admin Area")
end
+ def has_admin_area_link?(wait: Capybara.default_max_wait_time)
+ open_context_switcher
+
+ has_element?(:nav_item_link, submenu_item: "Admin Area", wait: wait)
+ end
+
private
def go_to_context(sub_menu)
- click_element(:context_switcher) unless has_element?(:context_navigation, wait: 0)
-
+ open_context_switcher
click_element(:nav_item_link, submenu_item: sub_menu)
end
+
+ def open_context_switcher
+ click_element(:context_switcher) unless has_element?(:context_navigation, wait: 0)
+ end
end
end
end
diff --git a/qa/qa/page/sub_menus/super_sidebar/deploy.rb b/qa/qa/page/sub_menus/super_sidebar/deploy.rb
new file mode 100644
index 00000000000..30e41b82c79
--- /dev/null
+++ b/qa/qa/page/sub_menus/super_sidebar/deploy.rb
@@ -0,0 +1,27 @@
+# frozen_string_literal: true
+
+module QA
+ module Page
+ module SubMenus
+ module SuperSidebar
+ module Deploy
+ extend QA::Page::PageConcern
+
+ def go_to_package_registry
+ open_deploy_submenu("Package Registry")
+ end
+
+ def go_to_container_registry
+ open_deploy_submenu('Container Registry')
+ end
+
+ private
+
+ def open_deploy_submenu(sub_menu)
+ open_submenu("Deploy", sub_menu)
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/qa/qa/page/sub_menus/super_sidebar/manage.rb b/qa/qa/page/sub_menus/super_sidebar/manage.rb
index 535b29e607f..369171299b2 100644
--- a/qa/qa/page/sub_menus/super_sidebar/manage.rb
+++ b/qa/qa/page/sub_menus/super_sidebar/manage.rb
@@ -19,10 +19,6 @@ module QA
open_manage_submenu('Labels')
end
- def go_to_milestones
- open_manage_submenu('Milestones')
- end
-
private
def open_manage_submenu(sub_menu)
diff --git a/qa/qa/page/sub_menus/super_sidebar/operate.rb b/qa/qa/page/sub_menus/super_sidebar/operate.rb
index 1ffbb6872da..29f23d74307 100644
--- a/qa/qa/page/sub_menus/super_sidebar/operate.rb
+++ b/qa/qa/page/sub_menus/super_sidebar/operate.rb
@@ -7,16 +7,8 @@ module QA
module Operate
extend QA::Page::PageConcern
- def go_to_package_registry
- open_operate_submenu('Package Registry')
- end
-
- def go_to_container_registry
- open_operate_submenu('Container Registry')
- end
-
def go_to_dependency_proxy
- open_operate_submenu('Dependency proxy')
+ open_operate_submenu('Dependency Proxy')
end
private
diff --git a/qa/qa/page/sub_menus/super_sidebar/plan.rb b/qa/qa/page/sub_menus/super_sidebar/plan.rb
index e4b9fcf099c..839ba89cedb 100644
--- a/qa/qa/page/sub_menus/super_sidebar/plan.rb
+++ b/qa/qa/page/sub_menus/super_sidebar/plan.rb
@@ -19,6 +19,10 @@ module QA
open_plan_submenu("Wiki")
end
+ def go_to_milestones
+ open_plan_submenu('Milestones')
+ end
+
private
def open_plan_submenu(sub_menu)
diff --git a/qa/qa/resource/badge_base.rb b/qa/qa/resource/badge_base.rb
index 5bb7eb98d4e..bc0adf0857d 100644
--- a/qa/qa/resource/badge_base.rb
+++ b/qa/qa/resource/badge_base.rb
@@ -3,10 +3,7 @@
module QA
module Resource
class BadgeBase < Base
- attributes :id,
- :name,
- :link_url,
- :image_url
+ attributes :id, :name, :link_url, :image_url
def initialize
@name = "qa-badge-#{SecureRandom.hex(8)}"
diff --git a/qa/qa/resource/base.rb b/qa/qa/resource/base.rb
index 6c03f45bdfd..e12a8f97d95 100644
--- a/qa/qa/resource/base.rb
+++ b/qa/qa/resource/base.rb
@@ -182,11 +182,12 @@ module QA
raise NotImplementedError
end
- def visit!(skip_resp_code_check: false)
+ def visit!(skip_finished_loading_check: false, skip_resp_code_check: false)
Runtime::Logger.info("Visiting #{Rainbow(self.class.name).black.bg(:white)} at #{web_url}")
# Just in case an async action is not yet complete
- Support::WaitForRequests.wait_for_requests(skip_resp_code_check: skip_resp_code_check)
+ Support::WaitForRequests.wait_for_requests(skip_finished_loading_check: skip_finished_loading_check,
+ skip_resp_code_check: skip_resp_code_check)
Support::Retrier.retry_until do
visit(web_url)
@@ -194,15 +195,18 @@ module QA
end
# Wait until the new page is ready for us to interact with it
- Support::WaitForRequests.wait_for_requests(skip_resp_code_check: skip_resp_code_check)
+ Support::WaitForRequests.wait_for_requests(skip_finished_loading_check: skip_finished_loading_check,
+ skip_resp_code_check: skip_resp_code_check)
end
def populate(*attribute_names)
attribute_names.each { |attribute_name| public_send(attribute_name) }
end
- def wait_until(max_duration: 60, sleep_interval: 0.1, &block)
- QA::Support::Waiter.wait_until(max_duration: max_duration, sleep_interval: sleep_interval, &block)
+ def wait_until(max_duration: 60, sleep_interval: 0.1, message: nil, &block)
+ QA::Support::Waiter.wait_until(
+ max_duration: max_duration, sleep_interval: sleep_interval, message: message, &block
+ )
end
# Object comparison
diff --git a/qa/qa/resource/bulk_import_group.rb b/qa/qa/resource/bulk_import_group.rb
index 19ad5f1faf2..5196be39a12 100644
--- a/qa/qa/resource/bulk_import_group.rb
+++ b/qa/qa/resource/bulk_import_group.rb
@@ -3,9 +3,7 @@
module QA
module Resource
class BulkImportGroup < Group
- attributes :source_group,
- :destination_group,
- :import_id
+ attributes :source_group, :destination_group, :import_id
attribute :import_access_token do
api_client.personal_access_token
diff --git a/qa/qa/resource/file.rb b/qa/qa/resource/file.rb
index 253b63e4260..7a180bb189d 100644
--- a/qa/qa/resource/file.rb
+++ b/qa/qa/resource/file.rb
@@ -4,11 +4,11 @@ module QA
module Resource
class File < Base
attr_accessor :author_email,
- :author_name,
- :content,
- :commit_message,
- :name,
- :start_branch
+ :author_name,
+ :content,
+ :commit_message,
+ :name,
+ :start_branch
attr_writer :branch
attribute :project do
diff --git a/qa/qa/resource/group_base.rb b/qa/qa/resource/group_base.rb
index 5e2a567119d..263c2ca2aeb 100644
--- a/qa/qa/resource/group_base.rb
+++ b/qa/qa/resource/group_base.rb
@@ -12,12 +12,12 @@ module QA
attr_accessor :path, :avatar
attributes :id,
- :runners_token,
- :name,
- :full_path,
- # Add visibility to enable create private group
- :visibility,
- :shared_with_groups
+ :runners_token,
+ :name,
+ :full_path,
+ # Add visibility to enable create private group
+ :visibility,
+ :shared_with_groups
# Get group projects
#
@@ -84,6 +84,14 @@ module QA
end
end
+ # Get group runners
+ #
+ # @param [Hash] **kwargs optional query arguments, see: https://docs.gitlab.com/ee/api/runners.html#list-groups-runners
+ # @return [Array]
+ def runners(**kwargs)
+ auto_paginated_response(request_url(api_runners_path, **kwargs))
+ end
+
# API get path
#
# @return [String]
@@ -112,6 +120,14 @@ module QA
"/groups/#{id}"
end
+ # API path to GET runners
+ # See https://docs.gitlab.com/ee/api/runners.html#list-groups-runners
+ #
+ # @return [String]
+ def api_runners_path
+ "#{api_get_path}/runners"
+ end
+
# Object comparison
# Override to make sure we are comparing descendands of GroupBase
#
diff --git a/qa/qa/resource/group_milestone.rb b/qa/qa/resource/group_milestone.rb
index c208270658e..b6dd9ee2dbf 100644
--- a/qa/qa/resource/group_milestone.rb
+++ b/qa/qa/resource/group_milestone.rb
@@ -4,13 +4,13 @@ module QA
module Resource
class GroupMilestone < Base
attributes :id,
- :iid,
- :title,
- :description,
- :start_date,
- :due_date,
- :updated_at,
- :created_at
+ :iid,
+ :title,
+ :description,
+ :start_date,
+ :due_date,
+ :updated_at,
+ :created_at
attribute :group do
Group.fabricate_via_api! do |resource|
diff --git a/qa/qa/resource/group_runner.rb b/qa/qa/resource/group_runner.rb
index d7fa26a1d53..fc08910c73e 100644
--- a/qa/qa/resource/group_runner.rb
+++ b/qa/qa/resource/group_runner.rb
@@ -21,7 +21,7 @@ module QA
def runner(**kwargs)
fail_msg = "Wait for runner '#{name}' to register in group '#{group.name}'"
Support::Retrier.retry_until(max_duration: 60, sleep_interval: 1, message: fail_msg) do
- auto_paginated_response(request_url("/runners", **kwargs)).find { |runner| runner[:description] == name }
+ group.runners(**kwargs).find { |runner| runner[:description] == name }
end
end
end
diff --git a/qa/qa/resource/issue.rb b/qa/qa/resource/issue.rb
index fb957ccf285..a5d5795b0de 100644
--- a/qa/qa/resource/issue.rb
+++ b/qa/qa/resource/issue.rb
@@ -14,11 +14,11 @@ module QA
end
attributes :id,
- :iid,
- :assignee_ids,
- :labels,
- :title,
- :description
+ :iid,
+ :assignee_ids,
+ :labels,
+ :title,
+ :description
def initialize
@assignee_ids = []
diff --git a/qa/qa/resource/job.rb b/qa/qa/resource/job.rb
index 5b0dac9b2df..dc425cc174c 100644
--- a/qa/qa/resource/job.rb
+++ b/qa/qa/resource/job.rb
@@ -5,8 +5,7 @@ module QA
class Job < Base
attr_accessor :id, :name, :project
- attributes :id,
- :project
+ attributes :id, :project
def fabricate_via_api!
resource_web_url(api_get)
diff --git a/qa/qa/resource/merge_request.rb b/qa/qa/resource/merge_request.rb
index 50ef9538fb0..0d1a0bb2cd4 100644
--- a/qa/qa/resource/merge_request.rb
+++ b/qa/qa/resource/merge_request.rb
@@ -24,7 +24,7 @@ module QA
:title,
:description,
:merge_when_pipeline_succeeds,
- :merge_status,
+ :detailed_merge_status,
:state,
:reviewers
@@ -151,13 +151,11 @@ module QA
end
def merge_via_api!
- Support::Waiter.wait_until(sleep_interval: 1) do
- QA::Runtime::Logger.debug("Waiting until merge request with id '#{iid}' can be merged")
+ QA::Runtime::Logger.info("Merging via PUT #{api_merge_path}")
- reload!.merge_status == 'can_be_merged'
- end
+ wait_until_mergable
- Support::Retrier.retry_on_exception do
+ Support::Retrier.retry_on_exception(max_attempts: 10, sleep_interval: 5) do
response = put(Runtime::API::Request.new(api_client, api_merge_path).url)
unless response.code == HTTP_STATUS_OK
@@ -184,6 +182,10 @@ module QA
end
def fabricate_large_merge_request
+ # requires admin access
+ QA::Support::Helpers::ImportSource.enable(%w[gitlab_project])
+ Flow::Login.sign_in
+
@project = Resource::ImportProject.fabricate_via_browser_ui!
# Setting the name here, since otherwise some tests will look for an existing file in
# the project without ever knowing what is in it.
@@ -205,7 +207,7 @@ module QA
:project_id,
:source_project_id,
:target_project_id,
- :merge_status,
+ :detailed_merge_status,
# we consider mr to still be the same even if users changed
:author,
:reviewers,
@@ -250,6 +252,18 @@ module QA
def create_target?
!(project.initialize_with_readme && target_branch == project.default_branch) && target_new_branch
end
+
+ # Wait until the merge request can be merged. Raises WaitExceededError if the MR can't be merged within 60 seconds
+ #
+ # @return [void]
+ def wait_until_mergable
+ return if Support::Waiter.wait_until(sleep_interval: 1, raise_on_failure: false, log: false) do
+ reload!.detailed_merge_status == 'mergeable'
+ end
+
+ raise Support::Repeater::WaitExceededError,
+ "Timed out waiting for merge of MR with id '#{iid}'. Final status was '#{detailed_merge_status}'"
+ end
end
end
end
diff --git a/qa/qa/resource/pipeline.rb b/qa/qa/resource/pipeline.rb
index e57784ca3b5..41c9d5b30f6 100644
--- a/qa/qa/resource/pipeline.rb
+++ b/qa/qa/resource/pipeline.rb
@@ -35,9 +35,7 @@ module QA
def fabricate_via_api!
resource_web_url(api_get)
- rescue ResourceNotFoundError
- super
- rescue NoValueError
+ rescue ResourceNotFoundError, NoValueError
super
end
@@ -49,7 +47,7 @@ module QA
"/projects/#{project.id}/pipelines/#{id}"
end
- def api_pipeline_jobs_path
+ def api_jobs_path
"#{api_get_path}/jobs"
end
@@ -98,8 +96,8 @@ module QA
result[:downstream_pipeline][:id]
end
- def pipeline_jobs
- parse_body(api_get_from(api_pipeline_jobs_path))
+ def jobs
+ parse_body(api_get_from(api_jobs_path))
end
end
end
diff --git a/qa/qa/resource/project.rb b/qa/qa/resource/project.rb
index 37ff2315329..9032777dcaa 100644
--- a/qa/qa/resource/project.rb
+++ b/qa/qa/resource/project.rb
@@ -128,7 +128,12 @@ module QA
# If a project is being imported, wait until it completes before we let the test continue.
# Otherwise we see Git repository errors
# See https://gitlab.com/gitlab-org/gitlab/-/issues/356101
- Support::Retrier.retry_until(max_duration: 60, sleep_interval: 5, retry_on_exception: true) do
+ Support::Retrier.retry_until(
+ max_duration: 60,
+ sleep_interval: 5,
+ retry_on_exception: true,
+ message: "Wait for project to be imported"
+ ) do
reload!.api_resource[:import_status] == "finished"
end
@@ -399,16 +404,29 @@ module QA
parse_body(response)
end
- def pipelines(auto_paginate: false, attempts: 0)
+ def pipelines(auto_paginate: false, attempts: 0, **kwargs)
return parse_body(api_get_from(api_pipelines_path)) unless auto_paginate
- auto_paginated_response(request_url(api_pipelines_path, per_page: '100'), attempts: attempts)
+ auto_paginated_response(request_url(api_pipelines_path, per_page: '100', **kwargs), attempts: attempts)
end
def latest_pipeline
parse_body(api_get_from(api_latest_pipeline_path))
end
+ # Waits for a pipeline to be available with the attributes as specified.
+ #
+ # @param [Hash] **kwargs optional query arguments, see: https://docs.gitlab.com/ee/api/pipelines.html#list-project-pipelines
+ # @return [Hash] the pipeline
+ def wait_for_pipeline(**kwargs)
+ wait_until(sleep_interval: 1, message: "Wait for pipeline with '#{kwargs}' to be available") do
+ result = pipelines(auto_paginate: true, **kwargs)
+ next unless result.present? && result.size == 1
+
+ result.first
+ end
+ end
+
def jobs
response = get(request_url(api_jobs_path))
parse_body(response)
diff --git a/qa/qa/resource/protected_branch.rb b/qa/qa/resource/protected_branch.rb
index 879c3a4282c..729171c7cfd 100644
--- a/qa/qa/resource/protected_branch.rb
+++ b/qa/qa/resource/protected_branch.rb
@@ -4,10 +4,10 @@ module QA
module Resource
class ProtectedBranch < Base
attr_accessor :branch_name,
- :allowed_to_push,
- :allowed_to_merge,
- :new_branch,
- :require_code_owner_approval
+ :allowed_to_push,
+ :allowed_to_merge,
+ :new_branch,
+ :require_code_owner_approval
attribute :project do
Project.fabricate_via_api! do |resource|
diff --git a/qa/qa/resource/registry_repository.rb b/qa/qa/resource/registry_repository.rb
index 148af353a25..66ccc92bf4c 100644
--- a/qa/qa/resource/registry_repository.rb
+++ b/qa/qa/resource/registry_repository.rb
@@ -3,8 +3,7 @@
module QA
module Resource
class RegistryRepository < Base
- attr_accessor :name,
- :tag_name
+ attr_accessor :name, :tag_name
attribute :project do
Project.fabricate_via_api! do |resource|
diff --git a/qa/qa/resource/repository/commit.rb b/qa/qa/resource/repository/commit.rb
index 1fe35f7a77d..f84ffa6aac3 100644
--- a/qa/qa/resource/repository/commit.rb
+++ b/qa/qa/resource/repository/commit.rb
@@ -5,12 +5,12 @@ module QA
module Repository
class Commit < Base
attr_accessor :author_email,
- :author_name,
- :branch,
- :commit_message,
- :file_path,
- :sha,
- :start_branch
+ :author_name,
+ :branch,
+ :commit_message,
+ :file_path,
+ :sha,
+ :start_branch
attribute :short_id
diff --git a/qa/qa/resource/repository/push.rb b/qa/qa/resource/repository/push.rb
index 00bed7ed546..93b820e91c8 100644
--- a/qa/qa/resource/repository/push.rb
+++ b/qa/qa/resource/repository/push.rb
@@ -5,8 +5,8 @@ module QA
module Repository
class Push < Base
attr_accessor :file_name, :file_content, :commit_message,
- :branch_name, :new_branch, :output, :repository_http_uri,
- :repository_ssh_uri, :ssh_key, :user, :use_lfs, :tag_name
+ :branch_name, :new_branch, :output, :repository_http_uri,
+ :repository_ssh_uri, :ssh_key, :user, :use_lfs, :tag_name
attr_writer :remote_branch, :gpg_key_id, :merge_request_push_options
diff --git a/qa/qa/resource/user.rb b/qa/qa/resource/user.rb
index 16d0f6ad380..abee46c41ab 100644
--- a/qa/qa/resource/user.rb
+++ b/qa/qa/resource/user.rb
@@ -8,18 +8,18 @@ module QA
attr_reader :unique_id
attr_writer :username, :password
attr_accessor :admin,
- :provider,
- :extern_uid,
- :expect_fabrication_success,
- :hard_delete_on_api_removal,
- :access_level,
- :email_domain
+ :provider,
+ :extern_uid,
+ :expect_fabrication_success,
+ :hard_delete_on_api_removal,
+ :access_level,
+ :email_domain
attributes :id,
- :name,
- :first_name,
- :last_name,
- :email
+ :name,
+ :first_name,
+ :last_name,
+ :email
def initialize
@admin = false
@@ -177,9 +177,10 @@ module QA
def self.all(per_page: 100)
response = nil
Resource::User.init do |user|
- response = user.get(Runtime::API::Request.new(Runtime::API::Client.as_admin,
- '/users',
- per_page: per_page.to_s).url)
+ response = user.get(Runtime::API::Request.new(
+ Runtime::API::Client.as_admin, '/users', per_page: per_page.to_s
+ ).url)
+
raise ResourceQueryError unless response.code == 200
end.parse_body(response)
end
diff --git a/qa/qa/runtime/browser.rb b/qa/qa/runtime/browser.rb
index b67db792419..7bc4530287c 100644
--- a/qa/qa/runtime/browser.rb
+++ b/qa/qa/runtime/browser.rb
@@ -4,8 +4,6 @@ require 'rspec/core'
require 'rspec/expectations'
require 'capybara/rspec'
require 'capybara-screenshot/rspec'
-require 'webdrivers/chromedriver'
-require 'webdrivers/geckodriver'
require 'gitlab_handbook'
@@ -18,8 +16,6 @@ module QA
CAPYBARA_MAX_WAIT_TIME = Env.max_capybara_wait_time
DEFAULT_WINDOW_SIZE = '1480,2200'
- PHONE_VIDEO_SIZE = '500x900'
- TABLET_VIDEO_SIZE = '800x1100'
def self.blank_page?
['', 'about:blank', 'data:,'].include?(Capybara.current_session.driver.browser.current_url)
@@ -46,8 +42,7 @@ module QA
new.visit(address, page_class, &block)
end
- # rubocop: disable Metrics/AbcSize
- def self.configure!
+ def self.configure! # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
return if @configured
RSpec.configure do |config|
@@ -64,45 +59,31 @@ module QA
end
Capybara.server_port = 9887 + ENV['TEST_ENV_NUMBER'].to_i
-
Capybara.register_driver QA::Runtime::Env.browser do |app|
- capabilities = Selenium::WebDriver::Remote::Capabilities.send(QA::Runtime::Env.browser)
+ webdriver_options = Selenium::WebDriver::Options.send(QA::Runtime::Env.browser)
case QA::Runtime::Env.browser
when :chrome
- capabilities['acceptInsecureCerts'] = true if QA::Runtime::Env.accept_insecure_certs?
-
- # set logging preferences
- # this enables access to logs with `page.driver.manage.get_log(:browser)`
- capabilities['goog:loggingPrefs'] = {
- browser: 'ALL',
- client: 'ALL',
- driver: 'ALL',
- server: 'ALL'
- }
-
# Chrome won't work properly in a Docker container in sandbox mode
- capabilities['goog:chromeOptions'] = {
- args: %w[no-sandbox]
- }
+ chrome_options = { args: %w[no-sandbox] }
# Run headless by default unless WEBDRIVER_HEADLESS is false
if QA::Runtime::Env.webdriver_headless?
- capabilities['goog:chromeOptions'][:args] << 'headless'
+ chrome_options[:args] << 'headless'
# Chrome documentation says this flag is needed for now
# https://developers.google.com/web/updates/2017/04/headless-chrome#cli
- capabilities['goog:chromeOptions'][:args] << 'disable-gpu'
+ chrome_options[:args] << 'disable-gpu'
end
# Disable /dev/shm use in CI. See https://gitlab.com/gitlab-org/gitlab/issues/4252
- capabilities['goog:chromeOptions'][:args] << 'disable-dev-shm-usage' if QA::Runtime::Env.disable_dev_shm?
+ chrome_options[:args] << 'disable-dev-shm-usage' if QA::Runtime::Env.disable_dev_shm?
# Set chrome default download path
# TODO: Set for remote grid as well once Sauce Labs tests are deprecated and Options.chrome is added
# See https://gitlab.com/gitlab-org/gitlab/-/merge_requests/112258
unless QA::Runtime::Env.remote_grid
- capabilities['goog:chromeOptions'][:prefs] = {
+ chrome_options[:prefs] = {
'download.default_directory' => File.expand_path(QA::Runtime::Env.chrome_default_download_path),
'download.prompt_for_download' => false
}
@@ -111,16 +92,16 @@ module QA
# Specify the user-agent to allow challenges to be bypassed
# See https://gitlab.com/gitlab-com/gl-infra/infrastructure/-/issues/11938
unless QA::Runtime::Env.user_agent.blank?
- capabilities['goog:chromeOptions'][:args] << "user-agent=#{QA::Runtime::Env.user_agent}"
+ chrome_options[:args] << "user-agent=#{QA::Runtime::Env.user_agent}"
end
if QA::Runtime::Env.remote_mobile_device_name
- capabilities['platformName'] = 'Android'
- capabilities['appium:automationName'] = 'UiAutomator2'
- capabilities['appium:deviceName'] = QA::Runtime::Env.remote_mobile_device_name
- capabilities['appium:platformVersion'] = 'latest'
+ webdriver_options.platform_name = 'Android'
+ webdriver_options.add_option('appium:automationName', 'UiAutomator2')
+ webdriver_options.add_option('appium:deviceName', QA::Runtime::Env.remote_mobile_device_name)
+ webdriver_options.add_option('appium:platformVersion', 'latest')
else
- capabilities['goog:chromeOptions'][:args] << "window-size=#{DEFAULT_WINDOW_SIZE}"
+ chrome_options[:args] << "window-size=#{DEFAULT_WINDOW_SIZE}"
end
# Slack tries to open an external URL handler
@@ -138,7 +119,7 @@ module QA
}
default_profile = File.join("#{chrome_profile_location}/Default")
- FileUtils.mkdir_p(default_profile) unless Dir.exist?(default_profile)
+ FileUtils.mkdir_p(default_profile)
preferences = slack_default_preference
# mutate the preferences if it exists
@@ -152,56 +133,61 @@ module QA
end
File.write("#{default_profile}/Preferences", preferences.to_json)
- append_chrome_profile_to_capabilities(capabilities)
+ append_chrome_profile_to_capabilities(chrome_options)
end
+ # Use the same profile on QA runs if CHROME_REUSE_PROFILE is true.
+ # Useful to speed up local QA.
+ append_chrome_profile_to_capabilities(chrome_options) if QA::Runtime::Env.reuse_chrome_profile?
+
+ webdriver_options.args = chrome_options[:args]
+ webdriver_options.prefs = chrome_options[:prefs]
+ webdriver_options.accept_insecure_certs = true if QA::Runtime::Env.accept_insecure_certs?
+ # set logging preferences
+ # this enables access to logs with `page.driver.manage.get_log(:browser)`
+ webdriver_options.logging_prefs = {
+ browser: 'ALL',
+ client: 'ALL',
+ driver: 'ALL',
+ server: 'ALL'
+ }
when :safari
if QA::Runtime::Env.remote_mobile_device_name
- capabilities['platformName'] = 'iOS'
- capabilities['appium:automationName'] = 'XCUITest'
- capabilities['appium:deviceName'] = QA::Runtime::Env.remote_mobile_device_name
- capabilities['appium:platformVersion'] = 'latest'
+ webdriver_options.platform_name = 'iOS'
+ webdriver_options.add_option('appium:automationName', 'XCUITest')
+ webdriver_options.add_option('appium:deviceName', QA::Runtime::Env.remote_mobile_device_name)
+ webdriver_options.add_option('appium:platformVersion', 'latest')
end
-
when :firefox
- capabilities['acceptInsecureCerts'] = true if QA::Runtime::Env.accept_insecure_certs?
-
+ webdriver_options.add_option('acceptInsecureCerts', true) if QA::Runtime::Env.accept_insecure_certs?
when :edge
- capabilities['ms:edgeOptions'] = { args: ["--window-size=#{DEFAULT_WINDOW_SIZE}"] }
+ webdriver_options.args << "--window-size=#{DEFAULT_WINDOW_SIZE}"
end
- # Use the same profile on QA runs if CHROME_REUSE_PROFILE is true.
- # Useful to speed up local QA.
- append_chrome_profile_to_capabilities(capabilities) if QA::Runtime::Env.reuse_chrome_profile?
-
selenium_options = {
browser: QA::Runtime::Env.browser,
- clear_local_storage: true,
- capabilities: capabilities
+ clear_local_storage: true
}
if QA::Runtime::Env.remote_grid
selenium_options[:browser] = :remote
selenium_options[:url] = QA::Runtime::Env.remote_grid
- capabilities[:browserVersion] = QA::Runtime::Env.browser_version
+ webdriver_options.browser_version = QA::Runtime::Env.selenoid_browser_version
end
if QA::Runtime::Env.remote_tunnel_id
- capabilities['sauce:options'] = { tunnelIdentifier: QA::Runtime::Env.remote_tunnel_id }
+ webdriver_options.add_option('sauce:options', {
+ tunnelIdentifier: QA::Runtime::Env.remote_tunnel_id
+ })
end
if QA::Runtime::Env.record_video?
- capabilities['selenoid:options'] = {
- enableVideo: true,
- videoScreenSize: video_screen_size,
- videoName: "#{QA::Runtime::Env.browser}-#{QA::Runtime::Env.browser_version}-#{Time.now}.mp4"
- }
+ webdriver_options.add_option('selenoid:options', {
+ enableVideo: true
+ })
end
- Capybara::Selenium::Driver.new(
- app,
- **selenium_options
- )
+ Capybara::Selenium::Driver.new(app, options: webdriver_options, **selenium_options)
end
# Keep only the screenshots generated from the last failing test suite
@@ -241,28 +227,17 @@ module QA
@configured = true
end
- # rubocop: enable Metrics/AbcSize
- def self.append_chrome_profile_to_capabilities(capabilities)
- return if capabilities['goog:chromeOptions'][:args].include?(chrome_profile_location)
+ def self.append_chrome_profile_to_capabilities(chrome_options)
+ return if chrome_options[:args].include?(chrome_profile_location)
- capabilities['goog:chromeOptions'][:args] << "user-data-dir=#{chrome_profile_location}"
+ chrome_options[:args] << "user-data-dir=#{chrome_profile_location}"
end
def self.chrome_profile_location
::File.expand_path('../../tmp/qa-profile', __dir__)
end
- def self.video_screen_size
- if QA::Runtime::Env.phone_layout?
- PHONE_VIDEO_SIZE
- elsif QA::Runtime::Env.tablet_layout?
- TABLET_VIDEO_SIZE
- else
- ''
- end
- end
-
class Session
include Capybara::DSL
diff --git a/qa/qa/runtime/env.rb b/qa/qa/runtime/env.rb
index cde36ba80c4..54f9db65afb 100644
--- a/qa/qa/runtime/env.rb
+++ b/qa/qa/runtime/env.rb
@@ -86,6 +86,10 @@ module QA
ENV['CI_PROJECT_NAME']
end
+ def schedule_type
+ ENV['SCHEDULE_TYPE']
+ end
+
def generate_allure_report?
enabled?(ENV['QA_GENERATE_ALLURE_REPORT'], default: false)
end
@@ -203,8 +207,16 @@ module QA
ENV['QA_BROWSER'].nil? ? :chrome : ENV['QA_BROWSER'].to_sym
end
- def browser_version
- ENV['QA_BROWSER_VERSION'] || 'latest'
+ def selenoid_browser_version
+ ENV['QA_SELENOID_BROWSER_VERSION']
+ end
+
+ def selenoid_browser_image
+ ENV['QA_SELENOID_BROWSER_IMAGE']
+ end
+
+ def video_recorder_image
+ ENV['QA_VIDEO_RECORDER_IMAGE']
end
def remote_mobile_device_name
@@ -237,6 +249,19 @@ module QA
enabled?(ENV['QA_RECORD_VIDEO'], default: false)
end
+ def use_selenoid?
+ enabled?(ENV['USE_SELENOID'], default: false)
+ end
+
+ def require_video_variables!
+ docs_link = 'https://gitlab.com/gitlab-org/gitlab-qa/-/blob/master/docs/running_against_remote_grid.md#testing-with-selenoid'
+ use_selenoid? || (raise ArgumentError, "USE_SELENOID is required! See docs: #{docs_link}")
+ remote_grid || (raise ArgumentError, "QA_REMOTE_GRID is required! See docs: #{docs_link}")
+ video_recorder_image || (raise ArgumentError, "QA_VIDEO_RECORDER_IMAGE is required! See docs: #{docs_link}")
+ selenoid_browser_image || (raise ArgumentError, "QA_SELENOID_BROWSER_IMAGE is required! See docs: #{docs_link}")
+ selenoid_browser_version || (raise ArgumentError, "QA_SELENOID_BROWSER_VERSION is required! See docs: #{docs_link}")
+ end
+
def user_username
ENV['GITLAB_USERNAME']
end
@@ -569,7 +594,7 @@ module QA
end
def super_sidebar_enabled?
- enabled?(ENV['QA_SUPER_SIDEBAR_ENABLED'], default: false)
+ enabled?(ENV['QA_SUPER_SIDEBAR_ENABLED'], default: true)
end
def require_slack_env!
diff --git a/qa/qa/scenario/test/instance/packages.rb b/qa/qa/scenario/test/instance/packages.rb
deleted file mode 100644
index 7648a2b5e80..00000000000
--- a/qa/qa/scenario/test/instance/packages.rb
+++ /dev/null
@@ -1,13 +0,0 @@
-# frozen_string_literal: true
-
-module QA
- module Scenario
- module Test
- module Instance
- class Packages < All
- tags :packages
- end
- end
- end
- end
-end
diff --git a/qa/qa/scenario/test/instance/review_blocking.rb b/qa/qa/scenario/test/instance/review_blocking.rb
index cb1b6c9cf10..41e760baf45 100644
--- a/qa/qa/scenario/test/instance/review_blocking.rb
+++ b/qa/qa/scenario/test/instance/review_blocking.rb
@@ -6,9 +6,9 @@ module QA
module Instance
class ReviewBlocking < All
tags :reliable,
- :sanity_feature_flags,
- :"~orchestrated",
- :"~skip_signup_disabled"
+ :sanity_feature_flags,
+ :"~orchestrated",
+ :"~skip_signup_disabled"
end
end
end
diff --git a/qa/qa/scenario/test/instance/review_non_blocking.rb b/qa/qa/scenario/test/instance/review_non_blocking.rb
index e295171eb0b..7c1b27617d7 100644
--- a/qa/qa/scenario/test/instance/review_non_blocking.rb
+++ b/qa/qa/scenario/test/instance/review_non_blocking.rb
@@ -6,9 +6,9 @@ module QA
module Instance
class ReviewNonBlocking < All
tags :"~reliable",
- :"~smoke",
- :"~skip_signup_disabled",
- *Specs::Runner::DEFAULT_SKIPPED_TAGS.map { |tag| :"~#{tag}" }
+ :"~smoke",
+ :"~skip_signup_disabled",
+ *Specs::Runner::DEFAULT_SKIPPED_TAGS.map { |tag| :"~#{tag}" }
end
end
end
diff --git a/qa/qa/service/docker_run/base.rb b/qa/qa/service/docker_run/base.rb
index ce558849abd..1a25aeb4c19 100644
--- a/qa/qa/service/docker_run/base.rb
+++ b/qa/qa/service/docker_run/base.rb
@@ -39,19 +39,20 @@ module QA
end
def network
- shell "docker network inspect #{@network}"
- rescue CommandError
- 'bridge'
- else
- @network
+ network_exists?(@network) ? @network : 'bridge'
end
def runner_network
- shell "docker network inspect #{@runner_network}"
- rescue CommandError
- network
- else
- @runner_network
+ network_exists?(@runner_network) ? @runner_network : network
+ end
+
+ def inspect_network(name)
+ shell("docker network inspect #{name}", fail_on_exception: false, return_exit_status: true)
+ end
+
+ def network_exists?(name)
+ _, status = inspect_network(name)
+ status == 0
end
def pull
diff --git a/qa/qa/service/docker_run/video.rb b/qa/qa/service/docker_run/video.rb
new file mode 100644
index 00000000000..c75280b1282
--- /dev/null
+++ b/qa/qa/service/docker_run/video.rb
@@ -0,0 +1,123 @@
+# frozen_string_literal: true
+
+module QA
+ module Service
+ module DockerRun
+ class Video < Base
+ class << self
+ include Service::Shellout
+
+ PHONE_VIDEO_SIZE = '500x900'
+ TABLET_VIDEO_SIZE = '800x1100'
+ DESKTOP_VIDEO_SIZE = '1920x1080'
+
+ def configure!
+ return unless QA::Runtime::Env.record_video?
+
+ begin
+ QA::Runtime::Env.require_video_variables!
+ rescue ArgumentError => e
+ return QA::Runtime::Logger.warn("Aborting video recording setup! Missing variables: #{e}")
+ end
+
+ @recorder_container_name = get_container_name(QA::Runtime::Env.video_recorder_image)
+ @browser_image_version =
+ "#{QA::Runtime::Env.selenoid_browser_image}:#{QA::Runtime::Env.selenoid_browser_version}"
+ @recorder_container_cmd = "docker exec -d #{@recorder_container_name} sh -c".freeze
+ set_browser_container_hostname
+ set_video_screen_size
+
+ if @recorder_container_name.present? && @browser_container_hostname
+ configure_rspec
+
+ QA::Runtime::Logger.info("Test failure video recording setup complete!")
+ else
+ QA::Runtime::Logger.warn("Test failure video recording setup failed!")
+ end
+ end
+
+ def start_recording(example)
+ @current_recording_name = create_recording_name(example)
+
+ ffmpeg_cmd = <<~CMD.tr("\n", ' ')
+ ffmpeg -y
+ -f x11grab
+ -video_size #{@video_size}
+ -r 15
+ -i #{@browser_container_hostname}:99
+ -vcodec 'libx264'
+ -pix_fmt 'yuv420p'
+ "/data/#{@current_recording_name}.mp4"
+ CMD
+
+ begin
+ shell("#{@recorder_container_cmd} '#{ffmpeg_cmd}'")
+ rescue StandardError => e
+ QA::Runtime::Logger.warn("Video recording start error: #{e}")
+ end
+ end
+
+ def stop_recording
+ shell("#{@recorder_container_cmd} 'pkill -INT -f ffmpeg'")
+ rescue StandardError => e
+ QA::Runtime::Logger.warn("Video recording stop error: #{e}")
+ end
+
+ def delete_video
+ shell("#{@recorder_container_cmd} 'rm /data/#{@current_recording_name}.mp4'")
+ rescue StandardError => e
+ QA::Runtime::Logger.warn("Video deletion error: #{e}")
+ end
+
+ private
+
+ def configure_rspec
+ RSpec.configure do |config|
+ config.prepend_before do |example|
+ QA::Service::DockerRun::Video.start_recording(example)
+ end
+
+ config.append_after do |example|
+ QA::Service::DockerRun::Video.stop_recording
+ QA::Service::DockerRun::Video.delete_video unless example.exception
+ end
+ end
+ end
+
+ def create_recording_name(example)
+ test_name = example.full_description.downcase.parameterize(separator: "_")[0..56]
+ test_time = Time.now.strftime "%Y-%m-%d-%H-%M-%S-%L"
+
+ "#{test_name}-#{test_time}"
+ end
+
+ def get_container_name(image)
+ name = shell("docker ps -f ancestor='#{image}' --format '{{.Names}}'")
+
+ QA::Runtime::Logger.warn("Getting container name for #{image} failed!") if name.empty?
+
+ name
+ end
+
+ def set_browser_container_hostname
+ container_name = get_container_name(@browser_image_version)
+ @browser_container_hostname = shell("docker inspect #{container_name} --format '{{.Config.Hostname}}'")
+ rescue StandardError => e
+ QA::Runtime::Logger.warn("Video recording browser container setup error: #{e}")
+ end
+
+ def set_video_screen_size
+ @video_size =
+ if QA::Runtime::Env.phone_layout?
+ PHONE_VIDEO_SIZE
+ elsif QA::Runtime::Env.tablet_layout?
+ TABLET_VIDEO_SIZE
+ else
+ DESKTOP_VIDEO_SIZE
+ end
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/qa/qa/service/praefect_manager.rb b/qa/qa/service/praefect_manager.rb
index 57f5310901b..684b18a97a7 100644
--- a/qa/qa/service/praefect_manager.rb
+++ b/qa/qa/service/praefect_manager.rb
@@ -198,42 +198,6 @@ module QA
destination_storage[:type] == :praefect ? verify_storage_move_to_praefect(repo_path, destination_storage[:name]) : verify_storage_move_to_gitaly(repo_path, destination_storage[:name])
end
- def praefect_sql_ping_healthy?
- cmd = "docker exec #{@praefect} bash -c '/opt/gitlab/embedded/bin/praefect -config /var/opt/gitlab/praefect/config.toml sql-ping'"
- wait_until_shell_command(cmd) do |line|
- QA::Runtime::Logger.debug(line.chomp)
- break line.include?('praefect sql-ping: OK')
- end
- end
-
- def wait_for_dial_nodes_successful
- Support::Waiter.repeat_until(max_attempts: 3, max_duration: 120, sleep_interval: 1) do
- nodes_confirmed = {
- @primary_node => false,
- @secondary_node => false,
- @tertiary_node => false
- }
-
- nodes_confirmed.each_key do |node|
- nodes_confirmed[node] = true if praefect_dial_nodes_status?(node)
- end
-
- nodes_confirmed.values.all?
- end
- end
-
- def praefect_dial_nodes_status?(node, expect_healthy = true)
- cmd = "docker exec #{@praefect} bash -c '/opt/gitlab/embedded/bin/praefect -config /var/opt/gitlab/praefect/config.toml dial-nodes -timeout 1s'"
- if expect_healthy
- wait_until_shell_command_matches(cmd, /SUCCESS: confirmed Gitaly storage "#{node}" in virtual storages \[#{@virtual_storage}\] is served/)
- else
- wait_until_shell_command(cmd, raise_on_failure: false) do |line|
- QA::Runtime::Logger.debug(line.chomp)
- break true if line.include?('the following nodes are not healthy') && line.include?(node)
- end
- end
- end
-
def praefect_dataloss_information(project_id)
dataloss_info = []
cmd = "docker exec #{@praefect} praefect -config /var/opt/gitlab/praefect/config.toml dataloss --partially-unavailable=true"
diff --git a/qa/qa/service/shellout.rb b/qa/qa/service/shellout.rb
index 218d5eecc85..c825793cc3c 100644
--- a/qa/qa/service/shellout.rb
+++ b/qa/qa/service/shellout.rb
@@ -11,9 +11,10 @@ module QA
module_function
- def shell(command, stdin_data: nil, fail_on_exception: true, stream_progress: true, mask_secrets: []) # rubocop:disable Metrics/CyclomaticComplexity
+ def shell(command, stdin_data: nil, fail_on_exception: true, stream_progress: true, mask_secrets: [], return_exit_status: false) # rubocop:disable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
cmd_string = Array(command).join(' ')
cmd_output = ''
+ exit_status = 0
QA::Runtime::Logger.info("Executing: `#{mask_secrets_on_string(cmd_string, mask_secrets).cyan}`")
@@ -36,7 +37,9 @@ module QA
# add newline after progress dots
puts if print_progress_dots && !cmd_output.empty?
- if wait.value.exited? && wait.value.exitstatus.nonzero? && fail_on_exception
+ exit_status = wait.value.exitstatus if wait.value.exited?
+
+ if exit_status.nonzero? && fail_on_exception
Runtime::Logger.error("Command output:\n#{cmd_output.strip}") unless cmd_output.empty?
raise CommandError, "Command: `#{mask_secrets_on_string(cmd_string, mask_secrets)}` failed! ✘"
end
@@ -44,7 +47,7 @@ module QA
Runtime::Logger.debug("Command output:\n#{cmd_output.strip}") unless cmd_output.empty?
end
- cmd_output.strip
+ return_exit_status ? [cmd_output.strip, exit_status] : cmd_output.strip
end
def sql_to_docker_exec_cmd(sql, username, password, database, host, container)
diff --git a/qa/qa/specs/features/api/12_systems/gitaly/changing_repository_storage_spec.rb b/qa/qa/specs/features/api/12_systems/gitaly/changing_repository_storage_spec.rb
index 01c50c0cd6a..425ab0fa162 100644
--- a/qa/qa/specs/features/api/12_systems/gitaly/changing_repository_storage_spec.rb
+++ b/qa/qa/specs/features/api/12_systems/gitaly/changing_repository_storage_spec.rb
@@ -30,7 +30,7 @@ module QA
end
context 'when moving from one Gitaly storage to another', :orchestrated, :repository_storage,
- testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347827' do
+ testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347827' do
let(:source_storage) { { type: :gitaly, name: 'default' } }
let(:destination_storage) { { type: :gitaly, name: QA::Runtime::Env.additional_repository_storage } }
let(:project) do
@@ -52,7 +52,7 @@ module QA
# scenario with other tests that aren't considered orchestrated.
# It also runs on staging using nfs-file07 as non-cluster storage and nfs-file22 as cluster/praefect storage
context 'when moving from Gitaly to Gitaly Cluster', :requires_praefect,
- testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347828' do
+ testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347828' do
let(:source_storage) { { type: :gitaly, name: QA::Runtime::Env.non_cluster_repository_storage } }
let(:destination_storage) { { type: :praefect, name: QA::Runtime::Env.praefect_repository_storage } }
let(:project) do
@@ -75,7 +75,7 @@ module QA
# scenario with other tests that aren't considered orchestrated.
# It also runs on staging using nfs-file07 as non-cluster storage and nfs-file22 as cluster/praefect storage
context 'when moving from Gitaly Cluster to Gitaly', :requires_praefect,
- testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/369204' do
+ testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/369204' do
let(:source_storage) { { type: :praefect, name: QA::Runtime::Env.praefect_repository_storage } }
let(:destination_storage) { { type: :gitaly, name: QA::Runtime::Env.non_cluster_repository_storage } }
let(:project) do
diff --git a/qa/qa/specs/features/api/12_systems/gitaly/distributed_reads_spec.rb b/qa/qa/specs/features/api/12_systems/gitaly/distributed_reads_spec.rb
index 60ce2a65fd1..a3d0fc7f72f 100644
--- a/qa/qa/specs/features/api/12_systems/gitaly/distributed_reads_spec.rb
+++ b/qa/qa/specs/features/api/12_systems/gitaly/distributed_reads_spec.rb
@@ -28,8 +28,7 @@ module QA
praefect_manager.query_read_distribution.each_with_index do |data, index|
pre_read_count = praefect_manager.value_for_node(pre_read_data, data[:node])
QA::Runtime::Logger.debug("Node: #{data[:node]}; before: #{pre_read_count}; now: #{data[:value]}")
- expect(data[:value]).to be > pre_read_count,
- "Read counts did not differ for node #{data[:node]}"
+ expect(data[:value]).to be > pre_read_count, "Read counts did not differ for node #{data[:node]}"
end
end
end
@@ -45,7 +44,7 @@ module QA
end
it 'does not read from the unhealthy node',
- testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347834' do
+ testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347834' do
pre_read_data = praefect_manager.query_read_distribution
read_from_project(project, number_of_reads_per_loop * 10)
diff --git a/qa/qa/specs/features/api/12_systems/gitaly/praefect_connectivity_spec.rb b/qa/qa/specs/features/api/12_systems/gitaly/praefect_connectivity_spec.rb
deleted file mode 100644
index bd00b3781f7..00000000000
--- a/qa/qa/specs/features/api/12_systems/gitaly/praefect_connectivity_spec.rb
+++ /dev/null
@@ -1,45 +0,0 @@
-# frozen_string_literal: true
-
-module QA
- RSpec.describe 'Systems' do
- describe 'Praefect connectivity commands', :orchestrated, :gitaly_cluster, product_group: :gitaly do
- praefect_manager = Service::PraefectManager.new
-
- before do
- praefect_manager.start_all_nodes
- end
-
- context 'in a healthy environment' do
- it 'confirms healthy connection to database',
- testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/349937' do
- expect(praefect_manager.praefect_sql_ping_healthy?).to be true
- end
-
- it 'confirms healthy connection to gitaly nodes',
- testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/349938' do
- expect(praefect_manager.wait_for_dial_nodes_successful).to be true
- end
- end
-
- context 'in an unhealthy environment' do
- it 'diagnoses unhealthy connection to database',
- testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/349939' do
- praefect_manager.stop_node(praefect_manager.postgres)
- expect(praefect_manager.praefect_sql_ping_healthy?).to be false
- end
-
- it 'diagnoses connection issues to gitaly nodes',
- testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/349940' do
- praefect_manager.stop_node(praefect_manager.primary_node)
- praefect_manager.stop_node(praefect_manager.tertiary_node)
- expect(praefect_manager.praefect_dial_nodes_status?(praefect_manager.primary_node, false)).to be true
- expect(praefect_manager.praefect_dial_nodes_status?(praefect_manager.secondary_node)).to be true
- expect(praefect_manager.praefect_dial_nodes_status?(praefect_manager.tertiary_node, false)).to be true
-
- praefect_manager.stop_node(praefect_manager.secondary_node)
- expect(praefect_manager.praefect_dial_nodes_status?(praefect_manager.secondary_node, false)).to be true
- end
- end
- end
- end
-end
diff --git a/qa/qa/specs/features/api/12_systems/gitaly/praefect_dataloss_spec.rb b/qa/qa/specs/features/api/12_systems/gitaly/praefect_dataloss_spec.rb
index cf387c14006..7b9164c1fc9 100644
--- a/qa/qa/specs/features/api/12_systems/gitaly/praefect_dataloss_spec.rb
+++ b/qa/qa/specs/features/api/12_systems/gitaly/praefect_dataloss_spec.rb
@@ -17,14 +17,14 @@ module QA
end
it 'confirms that changes are synced across all storages',
- testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/352691' do
+ testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/352691' do
expect { praefect_manager.praefect_dataloss_information(project.id) }
- .to(eventually_include('All repositories are fully available on all assigned storages!')
- .within(max_duration: 60))
+ .to(eventually_include('All repositories are fully available on all assigned storages!')
+ .within(max_duration: 60))
end
it 'identifies how many changes are not in sync across storages',
- testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/352692' do
+ testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/352692' do
# Ensure our test repository is replicated and in a consistent state prior to test
praefect_manager.wait_for_project_synced_across_all_storages(project.id)
@@ -59,7 +59,7 @@ module QA
end
it 'allows admin resolve scenario where data cannot be recovered',
- testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/352708' do
+ testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/352708' do
# Ensure everything is in sync before begining test
praefect_manager.wait_for_project_synced_across_all_storages(project.id)
diff --git a/qa/qa/specs/features/api/12_systems/gitaly/praefect_replication_queue_spec.rb b/qa/qa/specs/features/api/12_systems/gitaly/praefect_replication_queue_spec.rb
index f88372c0b59..88e746bfefe 100644
--- a/qa/qa/specs/features/api/12_systems/gitaly/praefect_replication_queue_spec.rb
+++ b/qa/qa/specs/features/api/12_systems/gitaly/praefect_replication_queue_spec.rb
@@ -23,7 +23,7 @@ module QA
end
it 'allows replication of different repository after interruption',
- testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347829' do
+ testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347829' do
# We want to fill the replication queue with 10 `in_progress` jobs,
# while a lock has been acquired, which is when the problem occurred
# as reported in https://gitlab.com/gitlab-org/gitaly/-/issues/2801
diff --git a/qa/qa/specs/features/api/12_systems/gitaly/praefect_repo_sync_spec.rb b/qa/qa/specs/features/api/12_systems/gitaly/praefect_repo_sync_spec.rb
index 40fc6bf2637..4f916300ee3 100644
--- a/qa/qa/specs/features/api/12_systems/gitaly/praefect_repo_sync_spec.rb
+++ b/qa/qa/specs/features/api/12_systems/gitaly/praefect_repo_sync_spec.rb
@@ -27,7 +27,7 @@ module QA
end
it 'allows admin to manage difference between praefect database and disk state',
- testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347606' do
+ testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347606' do
# Some repos are on disk that praefect is not aware of
untracked_repositories = praefect_manager.list_untracked_repositories
expect(untracked_repositories).to include(repo1)
@@ -77,7 +77,7 @@ module QA
end
it 'allows admin to control the number of replicas of data',
- testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347566' do
+ testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347566' do
praefect_manager
.track_repository_in_praefect(repo1['relative_path'], repo1['storage'], repo1['virtual_storage'])
diff --git a/qa/qa/specs/features/api/1_manage/integrations/webhook_events_spec.rb b/qa/qa/specs/features/api/1_manage/integrations/webhook_events_spec.rb
index 53c81b0e187..783c3a65c7d 100644
--- a/qa/qa/specs/features/api/1_manage/integrations/webhook_events_spec.rb
+++ b/qa/qa/specs/features/api/1_manage/integrations/webhook_events_spec.rb
@@ -112,10 +112,10 @@ module QA
let(:disabled_after) { 4 }
it 'hook is auto-disabled',
- testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/389595', quarantine: {
- issue: 'https://gitlab.com/gitlab-org/gitlab/-/issues/393274',
- type: :investigating
- } do
+ testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/389595', quarantine: {
+ issue: 'https://gitlab.com/gitlab-org/gitlab/-/issues/393274',
+ type: :investigating
+ } do
Resource::ProjectWebHook.setup(fail_mock, session: session, issues: true) do |webhook, smocker|
hook_trigger_times.times do
Resource::Issue.fabricate_via_api! do |issue_init|
diff --git a/qa/qa/specs/features/api/1_manage/migration/gitlab_migration_project_spec.rb b/qa/qa/specs/features/api/1_manage/migration/gitlab_migration_project_spec.rb
index b74ac89917f..0c94d6e64d5 100644
--- a/qa/qa/specs/features/api/1_manage/migration/gitlab_migration_project_spec.rb
+++ b/qa/qa/specs/features/api/1_manage/migration/gitlab_migration_project_spec.rb
@@ -6,7 +6,7 @@ module QA
include_context 'with gitlab project migration'
# this spec is used as a sanity test for gitlab migration because it can run outside of orchestrated setup
- context 'with import within same instance', orchestrated: false, import: false do
+ context 'with import within same instance', :skip_live_env, orchestrated: false, import: false do
let!(:source_project_with_readme) { true }
let!(:source_gitlab_address) { Runtime::Scenario.gitlab_address }
let!(:source_admin_api_client) { admin_api_client }
diff --git a/qa/qa/specs/features/api/3_create/repository/project_archive_compare_spec.rb b/qa/qa/specs/features/api/3_create/repository/project_archive_compare_spec.rb
index a211eb6042d..d72672e2104 100644
--- a/qa/qa/specs/features/api/3_create/repository/project_archive_compare_spec.rb
+++ b/qa/qa/specs/features/api/3_create/repository/project_archive_compare_spec.rb
@@ -6,7 +6,7 @@ require 'digest'
module QA
RSpec.describe 'Create' do
describe 'Compare archives of different user projects with the same name and check they\'re different',
- product_group: :source_code do
+ product_group: :source_code do
include Support::API
let(:project_name) { "project-archive-download-#{SecureRandom.hex(8)}" }
diff --git a/qa/qa/specs/features/api/3_create/repository/tag_revision_trigger_prereceive_hook_spec.rb b/qa/qa/specs/features/api/3_create/repository/tag_revision_trigger_prereceive_hook_spec.rb
index b34b4208337..700cf69da80 100644
--- a/qa/qa/specs/features/api/3_create/repository/tag_revision_trigger_prereceive_hook_spec.rb
+++ b/qa/qa/specs/features/api/3_create/repository/tag_revision_trigger_prereceive_hook_spec.rb
@@ -19,14 +19,13 @@ module QA
end
it 'returns a custom server hook error',
- :skip_live_env,
- except: { job: 'review-qa-*' },
- testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/369053' do
+ :skip_live_env,
+ except: { job: 'review-qa-*' },
+ testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/369053' do
expect { project.create_repository_tag('v1.2.3') }
- .to raise_error
- .with_message(
- /rejecting prereceive hook for projects with GL_PROJECT_PATH matching pattern reject-prereceive/
- )
+ .to raise_error.with_message(
+ /rejecting prereceive hook for projects with GL_PROJECT_PATH matching pattern reject-prereceive/
+ )
end
end
end
diff --git a/qa/qa/specs/features/api/4_verify/api_variable_inheritance_with_forward_pipeline_variables_spec.rb b/qa/qa/specs/features/api/4_verify/api_variable_inheritance_with_forward_pipeline_variables_spec.rb
index c66bd16afe9..79974828a2b 100644
--- a/qa/qa/specs/features/api/4_verify/api_variable_inheritance_with_forward_pipeline_variables_spec.rb
+++ b/qa/qa/specs/features/api/4_verify/api_variable_inheritance_with_forward_pipeline_variables_spec.rb
@@ -70,15 +70,13 @@ module QA
def expect_downstream_pipeline_to_inherit_variable
pipeline = downstream_pipeline(upstream_project, 'child1_trigger')
expect(pipeline).to have_variable(key: key, value: value),
- "Expected to find `{key: 'TEST_VAR', value: 'This is great!'}`" \
- " but got #{pipeline.pipeline_variables}"
+ "Expected to find `{key: 'TEST_VAR', value: 'This is great!'}` but got #{pipeline.pipeline_variables}"
end
def expect_downstream_pipeline_not_to_inherit_variable(project, bridge_name)
pipeline = downstream_pipeline(project, bridge_name)
expect(pipeline).not_to have_variable(key: key, value: value),
- "Did not expect to find `{key: 'TEST_VAR', value: 'This is great!'}`" \
- " but got #{pipeline.pipeline_variables}"
+ "Did not expect to find `{key: 'TEST_VAR', value: 'This is great!'}` but got #{pipeline.pipeline_variables}"
end
end
end
diff --git a/qa/qa/specs/features/api/5_package/container_registry_spec.rb b/qa/qa/specs/features/api/5_package/container_registry/saas/container_registry_spec.rb
index 0264b8b1ff2..d5073863dff 100644
--- a/qa/qa/specs/features/api/5_package/container_registry_spec.rb
+++ b/qa/qa/specs/features/api/5_package/container_registry/saas/container_registry_spec.rb
@@ -3,11 +3,12 @@
require 'airborne'
module QA
- RSpec.describe 'Package', :reliable, only: { subdomain: %i[staging staging-canary pre] }, product_group: :container_registry do
+ RSpec.describe 'Package', only: { subdomain: %i[staging staging-canary pre] },
+ product_group: :container_registry do
include Support::API
include Support::Helpers::MaskToken
- describe 'Container Registry' do
+ describe 'SaaS Container Registry API' do
let(:api_client) { Runtime::API::Client.new(:gitlab) }
let(:project) do
@@ -43,10 +44,10 @@ module QA
- test
build:
- image: docker:19.03.12
+ image: docker:24.0.1
stage: build
services:
- - docker:19.03.12-dind
+ - docker:24.0.1-dind
variables:
IMAGE_TAG: $CI_REGISTRY_IMAGE:$CI_COMMIT_REF_SLUG
DOCKER_HOST: tcp://docker:2376
@@ -76,26 +77,32 @@ module QA
YAML
end
- after do
- registry&.remove_via_api!
- end
-
- it 'pushes, pulls image to the registry and deletes tag', testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/348001' do
- Support::Retrier.retry_on_exception(max_attempts: 3, sleep_interval: 2) do
+ it 'pushes, pulls image to the registry and deletes tag',
+ testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/348001' do
+ Support::Retrier.retry_on_exception(max_attempts: 3, sleep_interval: 2, message: "Commit push") do
Resource::Repository::Commit.fabricate_via_api! do |commit|
commit.api_client = api_client
commit.commit_message = 'Add .gitlab-ci.yml'
commit.project = project
commit.add_files([{
- file_path: '.gitlab-ci.yml',
- content: gitlab_ci_yaml
- }])
+ file_path: '.gitlab-ci.yml',
+ content: gitlab_ci_yaml
+ }])
end
end
- Support::Waiter.wait_until(max_duration: 10) { pipeline_is_triggered? }
-
- Support::Retrier.retry_until(max_duration: 300, sleep_interval: 5) do
+ Support::Retrier.retry_until(
+ max_duration: 10,
+ sleep_interval: 1,
+ message: "Waiting for pipeline to start"
+ ) do
+ pipeline_is_triggered?
+ end
+ Support::Retrier.retry_until(
+ max_duration: 300,
+ sleep_interval: 5,
+ message: "Waiting for pipeline to succeed"
+ ) do
latest_pipeline_succeed?
end
end
diff --git a/qa/qa/specs/features/browser_ui/1_manage/integrations/jenkins/jenkins_build_status_spec.rb b/qa/qa/specs/features/browser_ui/1_manage/integrations/jenkins/jenkins_build_status_spec.rb
index 913317afc70..63c57ad455b 100644
--- a/qa/qa/specs/features/browser_ui/1_manage/integrations/jenkins/jenkins_build_status_spec.rb
+++ b/qa/qa/specs/features/browser_ui/1_manage/integrations/jenkins/jenkins_build_status_spec.rb
@@ -49,7 +49,7 @@ module QA
end
it 'integrates and displays build status for MR pipeline in GitLab',
- testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347788' do
+ testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347788' do
setup_project_integration
jenkins_integration = project.find_integration('jenkins')
diff --git a/qa/qa/specs/features/browser_ui/1_manage/integrations/jira/jira_basic_integration_spec.rb b/qa/qa/specs/features/browser_ui/1_manage/integrations/jira/jira_basic_integration_spec.rb
index f6f4a6b3786..1bd819ad87d 100644
--- a/qa/qa/specs/features/browser_ui/1_manage/integrations/jira/jira_basic_integration_spec.rb
+++ b/qa/qa/specs/features/browser_ui/1_manage/integrations/jira/jira_basic_integration_spec.rb
@@ -38,7 +38,7 @@ module QA
end
it 'closes an issue via pushing a commit',
- testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347794' do
+ testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347794' do
issue_key = Vendor::Jira::JiraAPI.perform do |jira_api|
jira_api.create_issue(jira_project_key)
end
@@ -49,7 +49,7 @@ module QA
end
it 'closes an issue via a merge request',
- testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347795' do
+ testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347795' do
issue_key = Vendor::Jira::JiraAPI.perform do |jira_api|
jira_api.create_issue(jira_project_key)
end
diff --git a/qa/qa/specs/features/browser_ui/1_manage/integrations/slash_commands_spec.rb b/qa/qa/specs/features/browser_ui/1_manage/integrations/slash_commands_spec.rb
new file mode 100644
index 00000000000..f5e33cb5b1e
--- /dev/null
+++ b/qa/qa/specs/features/browser_ui/1_manage/integrations/slash_commands_spec.rb
@@ -0,0 +1,175 @@
+# frozen_string_literal: true
+
+module QA
+ RSpec.describe 'Create', only: { subdomain: "staging-ref" } do
+ describe 'Slack app integration', :slack, product_group: :import_and_integrate do
+ context 'when using Slash commands' do
+ # state to be seeded in the Slack UI
+ let(:title) { "Issue - #{SecureRandom.hex(5)}" }
+ let(:description) { "Description - #{SecureRandom.hex(6)}" }
+
+ # state to be used in the GitLab API
+ let(:project_name) { "project_with_slack" }
+
+ let(:project) do
+ Resource::Project.fabricate_via_api! do |project|
+ project.name = project_name
+ project.initialize_with_readme = true
+ end
+ end
+
+ before(:context) do
+ Runtime::Env.require_slack_env!
+ end
+
+ before do
+ authenticate_slack
+
+ Flow::Login.sign_in_unless_signed_in
+ Flow::Integrations::Slack.start_slack_install(project)
+
+ with_slack_tab do
+ break if Flow::Integrations::Slack.start_gitlab_connect(project, channel: 'test')
+
+ with_tab(2) do
+ Page::Profile::ChatNames::New.perform(&:authorize)
+ end
+ close_tab(2)
+ end
+ end
+
+ after do
+ project.remove_via_api!
+ end
+
+ it 'creates an issue', testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/377890' do
+ with_slack_tab do
+ ::Slack::Page::Chat.perform do |chat_page|
+ chat_page.create_issue(project, channel: 'test', title: title, description: description)
+ end
+
+ aggregate_failures do
+ expect { project.issues.size }.to eventually_be(1).within(max_duration: 10)
+
+ issue = project.issues.last
+
+ expect(issue.dig(:author, :username)).to eql(Runtime::User.username)
+ expect(issue[:title]).to eql(title)
+ expect(issue[:description]).to eql(description)
+ end
+ end
+ end
+
+ context 'with gitlab issue' do
+ let!(:issue) do
+ Resource::Issue.fabricate_via_api! do |issue|
+ issue.project = project
+ end
+ end
+
+ let(:comment) { "Comment #{SecureRandom.hex(6)}" }
+
+ it 'displays an issue', testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/377891' do
+ with_slack_tab do
+ ::Slack::Page::Chat.perform do |chat_page|
+ chat_page.show_issue(project, channel: 'test', id: issue.iid)
+
+ expect { chat_page.browser.text }.to eventually_include(issue.title).within(max_duration: 10)
+ end
+ end
+ end
+
+ it 'closes an issue', testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/377892' do
+ with_slack_tab do
+ ::Slack::Page::Chat.perform do |chat_page|
+ chat_page.close_issue(project, channel: 'test', id: issue.iid)
+ end
+
+ expect { issue.state_events.last&.dig(:state) }.to eventually_eq('closed').within(max_duration: 10)
+ end
+ end
+
+ it 'comments on an issue', testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/377893' do
+ with_slack_tab do
+ ::Slack::Page::Chat.perform do |chat_page|
+ chat_page.comment_on_issue(project, channel: 'test', id: issue.iid, comment: comment)
+ end
+
+ expect { issue.comments.size }.to eventually_be(1).within(max_duration: 10)
+ expect(issue.comments.first&.dig(:body)).to eql(comment), "Comments don't match: #{issue.comments}"
+ end
+ end
+
+ context 'with target project' do
+ let(:target) do
+ Resource::Project.fabricate_via_api! do |project|
+ project.name = 'target_slack_project'
+ project.initialize_with_readme = true
+ end
+ end
+
+ after do
+ target.remove_via_api!
+ end
+
+ it 'moves an issue', testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/377894' do
+ with_slack_tab do
+ ::Slack::Page::Chat.perform do |chat_page|
+ chat_page.move_issue(project, target, channel: 'test', id: issue.iid)
+ end
+
+ expect { target.issues.size }.to eventually_be(1).within(max_duration: 10)
+
+ target_issue = target.issues.first
+
+ expect(target_issue&.dig(:title)).to eql(issue.title)
+ expect(target_issue&.dig(:description)).to eql(issue.description)
+ end
+ end
+ end
+ end
+
+ private
+
+ def wait_until(timeout = 15, &block)
+ Support::Waiter.wait_until(max_duration: timeout, reload_page: false, raise_on_failure: false, &block)
+ end
+
+ def with_slack_tab
+ switch_to_tab(1)
+ yield
+ switch_to_tab(0)
+ end
+
+ def with_tab(idx)
+ switch_to_tab(idx)
+ page.refresh
+ yield
+ end
+
+ def close_tab(idx)
+ page.windows[idx].close
+ end
+
+ def switch_to_tab(idx)
+ browser.switch_to.window(browser.window_handles[idx])
+ end
+
+ def authenticate_slack
+ page.open_new_window
+
+ with_slack_tab do
+ ::Slack::Page::Login.perform do |slack_page|
+ slack_page.visit
+ slack_page.sign_in
+ end
+ end
+ end
+
+ def browser
+ page.driver.browser
+ end
+ end
+ end
+ end
+end
diff --git a/qa/qa/specs/features/browser_ui/1_manage/login/login_via_oauth_and_oidc_with_gitlab_as_idp_spec.rb b/qa/qa/specs/features/browser_ui/1_manage/login/login_via_oauth_and_oidc_with_gitlab_as_idp_spec.rb
new file mode 100644
index 00000000000..b2aa3166b9d
--- /dev/null
+++ b/qa/qa/specs/features/browser_ui/1_manage/login/login_via_oauth_and_oidc_with_gitlab_as_idp_spec.rb
@@ -0,0 +1,154 @@
+# frozen_string_literal: true
+
+module QA
+ RSpec.describe 'Manage', :skip_live_env, requires_admin: 'creates users and instance OAuth application',
+ product_group: :authentication_and_authorization do
+ let!(:user) { Resource::User.fabricate_via_api! }
+ let(:consumer_host) { "http://#{consumer_name}.#{Runtime::Env.running_in_ci? ? 'test' : 'bridge'}" }
+ let(:instance_oauth_app) do
+ Resource::InstanceOauthApplication.fabricate! do |application|
+ application.redirect_uri = redirect_uri
+ application.scopes = scopes
+ end
+ end
+
+ after do
+ instance_oauth_app.remove_via_api!
+ remove_gitlab_service(consumer_name)
+ end
+
+ def run_gitlab_service(name:, app_id:, app_secret:)
+ Service::DockerRun::Gitlab.new(
+ image: Runtime::Env.release,
+ name: name,
+ omnibus_config: omnibus_configuration(app_id: app_id, app_secret: app_secret)).tap do |gitlab|
+ gitlab.login
+ gitlab.pull
+ gitlab.register!
+ end
+ end
+
+ def remove_gitlab_service(name)
+ Service::DockerRun::Gitlab.new(name: name).remove!
+ end
+
+ def wait_for_service(service)
+ Support::Waiter.wait_until(max_duration: 900, sleep_interval: 5, raise_on_failure: true) do
+ service.health == "healthy"
+ end
+ end
+
+ shared_examples 'Instance OAuth Application' do |app_type, testcase|
+ it "creates #{app_type} application and uses it to login", testcase: testcase do
+ instance_oauth_app
+
+ Page::Main::Menu.perform(&:sign_out_if_signed_in)
+
+ app_id = instance_oauth_app.application_id
+ app_secret = instance_oauth_app.application_secret
+
+ consumer_gitlab_service = run_gitlab_service(name: consumer_name, app_id: app_id, app_secret: app_secret)
+
+ wait_for_service(consumer_gitlab_service)
+
+ page.visit consumer_host
+
+ expect(page.driver.current_url).to include(consumer_host)
+
+ Page::Main::Login.perform do |login_page|
+ login_page.public_send("sign_in_with_gitlab_#{app_type}")
+ end
+
+ expect(page.driver.current_url).to include(Runtime::Scenario.gitlab_address)
+
+ Flow::Login.sign_in(as: user, skip_page_validation: true)
+
+ expect(page.driver.current_url).to include(consumer_host)
+
+ Page::Dashboard::Welcome.perform do |welcome|
+ expect(welcome).to have_welcome_title("Welcome to GitLab")
+ end
+ end
+ end
+
+ describe 'OIDC' do
+ let(:consumer_name) { 'gitlab-oidc-consumer' }
+ let(:redirect_uri) { "#{consumer_host}/users/auth/openid_connect/callback" }
+ let(:scopes) { %w[openid profile email] }
+
+ def omnibus_configuration(app_id:, app_secret:)
+ <<~OMNIBUS
+ gitlab_rails['initial_root_password']='5iveL\!fe';
+ gitlab_rails['omniauth_enabled'] = true;
+ gitlab_rails['omniauth_allow_single_sign_on'] = true;
+ gitlab_rails['omniauth_block_auto_created_users'] = false;
+ gitlab_rails['omniauth_providers'] = [
+ {
+ name: 'openid_connect',
+ label: 'GitLab OIDC',
+ args: {
+ name: 'openid_connect',
+ scope: ['openid','profile','email'],
+ response_type: 'code',
+ issuer: '#{Runtime::Scenario.gitlab_address}',
+ discovery: false,
+ uid_field: 'preferred_username',
+ send_scope_to_token_endpoint: 'false',
+ client_options: {
+ identifier: '#{app_id}',
+ secret: '#{app_secret}',
+ redirect_uri: '#{consumer_host}/users/auth/openid_connect/callback',
+ jwks_uri: '#{Runtime::Scenario.gitlab_address}/oauth/discovery/keys',
+ userinfo_endpoint: '#{Runtime::Scenario.gitlab_address}/oauth/userinfo',
+ token_endpoint: '#{Runtime::Scenario.gitlab_address}/oauth/token',
+ authorization_endpoint: '#{Runtime::Scenario.gitlab_address}/oauth/authorize'
+ }
+ }
+ }
+ ];
+ OMNIBUS
+ end
+
+ # The host GitLab instance with address Runtime::Scenario.gitlab_address is the OIDC idP - OIDC application will
+ # be created here.
+ # GitLab instance stood up in docker with address gitlab-oidc-consumer.test (or gitlab-oidc-consumer.bridge) is
+ # the consumer - The GitLab OIDC Login button will be displayed here.
+ it_behaves_like 'Instance OAuth Application', :oidc, 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/405137'
+ end
+
+ describe 'OAuth' do
+ let(:consumer_name) { 'gitlab-oauth-consumer' }
+ let(:redirect_uri) { "#{consumer_host}/users/auth/gitlab/callback" }
+ let(:scopes) { %w[read_user] }
+
+ def omnibus_configuration(app_id:, app_secret:)
+ <<~OMNIBUS
+ gitlab_rails['initial_root_password']='5iveL\!fe';
+ gitlab_rails['omniauth_enabled'] = true;
+ gitlab_rails['omniauth_allow_single_sign_on'] = true;
+ gitlab_rails['omniauth_block_auto_created_users'] = false;
+ gitlab_rails['omniauth_providers'] = [
+ {
+ name: 'gitlab',
+ label: 'GitLab OAuth',
+ app_id: '#{app_id}',
+ app_secret: '#{app_secret}',
+ args: {
+ scope: 'read_user',
+ client_options: {
+ site: '#{Runtime::Scenario.gitlab_address}'
+ }
+ }
+ }
+ ];
+ OMNIBUS
+ end
+
+ # The host GitLab instance with address Runtime::Scenario.gitlab_address is the OAuth idP - OAuth application will
+ # be created here.
+ # GitLab instance stood up in docker with address gitlab-oauth-consumer.test (or gitlab-oauth-consumer.bridge) is
+ # the consumer - The GitLab OAuth Login button will be displayed here.
+ it_behaves_like 'Instance OAuth Application', :oauth, 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/412111'
+ end
+ end
+end
diff --git a/qa/qa/specs/features/browser_ui/1_manage/login/login_via_oidc_with_gitlab_as_idp_spec.rb b/qa/qa/specs/features/browser_ui/1_manage/login/login_via_oidc_with_gitlab_as_idp_spec.rb
deleted file mode 100644
index 1be51f40f0e..00000000000
--- a/qa/qa/specs/features/browser_ui/1_manage/login/login_via_oidc_with_gitlab_as_idp_spec.rb
+++ /dev/null
@@ -1,118 +0,0 @@
-# frozen_string_literal: true
-
-module QA
- RSpec.describe 'Manage', :skip_live_env, requires_admin: 'creates users and instance OAuth application',
- product_group: :authentication_and_authorization do
- let!(:user) { Resource::User.fabricate_via_api! }
- let(:oidc_consumer_name) { 'gitlab-oidc-consumer' }
- let(:oidc_consumer_host) { "http://#{oidc_consumer_name}.#{Runtime::Env.running_in_ci? ? 'test' : 'bridge'}" }
- let(:instance_oauth_app) do
- Resource::InstanceOauthApplication.fabricate! do |application|
- application.redirect_uri = "#{oidc_consumer_host}/users/auth/openid_connect/callback"
- application.scopes = %w[openid profile email]
- end
- end
-
- after do
- instance_oauth_app.remove_via_api!
- remove_gitlab_service(oidc_consumer_name)
- end
-
- # The host GitLab instance with address Runtime::Scenario.gitlab_address is the OIDC idP - OIDC application will be
- # created here.
- # GitLab instance stood up in docker with address gitlab-oidc-consumer.test (or gitlab-oidc-consumer.bridge) is
- # the consumer - The GitLab OIDC Login button will be displayed here.
- describe 'OIDC' do
- it(
- 'creates GitLab OIDC application and uses it to login',
- testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/405137',
- quarantine: {
- only: { pipeline: :nightly },
- type: :investigating,
- issue: 'https://gitlab.com/gitlab-org/gitlab/-/issues/408317'
- }
- ) do
- instance_oauth_app
-
- Page::Main::Menu.perform(&:sign_out_if_signed_in)
-
- app_id = instance_oauth_app.application_id
- app_secret = instance_oauth_app.application_secret
-
- consumer_gitlab_service = run_gitlab_service(name: oidc_consumer_name, app_id: app_id, app_secret: app_secret)
-
- wait_for_service(consumer_gitlab_service)
-
- page.visit oidc_consumer_host
-
- expect(page.driver.current_url).to include(oidc_consumer_host)
-
- Page::Main::Login.perform(&:sign_in_with_oidc)
-
- expect(page.driver.current_url).to include(Runtime::Scenario.gitlab_address)
-
- Flow::Login.sign_in(as: user)
-
- expect(page.driver.current_url).to include(oidc_consumer_host)
-
- Page::Dashboard::Welcome.perform do |welcome|
- expect(welcome).to have_welcome_title("Welcome to GitLab")
- end
- end
-
- def run_gitlab_service(name:, app_id:, app_secret:)
- Service::DockerRun::Gitlab.new(
- image: Runtime::Env.release,
- name: name,
- omnibus_config: omnibus_configuration(app_id: app_id, app_secret: app_secret)).tap do |gitlab|
- gitlab.login
- gitlab.pull
- gitlab.register!
- end
- end
-
- def remove_gitlab_service(name)
- Service::DockerRun::Gitlab.new(name: name).remove!
- end
-
- def wait_for_service(service)
- Support::Waiter.wait_until(max_duration: 900, sleep_interval: 5, raise_on_failure: true) do
- service.health == "healthy"
- end
- end
-
- def omnibus_configuration(app_id:, app_secret:)
- <<~OMNIBUS
- gitlab_rails['initial_root_password']='5iveL\!fe';
- gitlab_rails['omniauth_enabled'] = true;
- gitlab_rails['omniauth_allow_single_sign_on'] = true;
- gitlab_rails['omniauth_block_auto_created_users'] = false;
- gitlab_rails['omniauth_providers'] = [
- {
- name: 'openid_connect',
- label: 'GitLab OIDC',
- args: {
- name: 'openid_connect',
- scope: ['openid','profile','email'],
- response_type: 'code',
- issuer: '#{Runtime::Scenario.gitlab_address}',
- discovery: false,
- uid_field: 'preferred_username',
- send_scope_to_token_endpoint: 'false',
- client_options: {
- identifier: '#{app_id}',
- secret: '#{app_secret}',
- redirect_uri: '#{oidc_consumer_host}/users/auth/openid_connect/callback',
- jwks_uri: '#{Runtime::Scenario.gitlab_address}/oauth/discovery/keys',
- userinfo_endpoint: '#{Runtime::Scenario.gitlab_address}/oauth/userinfo',
- token_endpoint: '#{Runtime::Scenario.gitlab_address}/oauth/token',
- authorization_endpoint: '#{Runtime::Scenario.gitlab_address}/oauth/authorize'
- }
- }
- }
- ];
- OMNIBUS
- end
- end
- end
-end
diff --git a/qa/qa/specs/features/browser_ui/1_manage/login/register_spec.rb b/qa/qa/specs/features/browser_ui/1_manage/login/register_spec.rb
index f257f1edbc1..5f31ac412d6 100644
--- a/qa/qa/specs/features/browser_ui/1_manage/login/register_spec.rb
+++ b/qa/qa/specs/features/browser_ui/1_manage/login/register_spec.rb
@@ -112,6 +112,7 @@ module QA
let(:user) do
Resource::User.fabricate_via_browser_ui! do |user|
+ user.email_domain = 'gitlab.com'
user.expect_fabrication_success = false
end
end
@@ -122,7 +123,6 @@ module QA
after do
set_require_admin_approval_after_user_signup(false)
- user.remove_via_api! if user
end
it 'allows user login after approval',
diff --git a/qa/qa/specs/features/browser_ui/2_plan/issue/mentions_spec.rb b/qa/qa/specs/features/browser_ui/2_plan/issue/mentions_spec.rb
index fd818c3797b..b2dca4fc312 100644
--- a/qa/qa/specs/features/browser_ui/2_plan/issue/mentions_spec.rb
+++ b/qa/qa/specs/features/browser_ui/2_plan/issue/mentions_spec.rb
@@ -43,7 +43,7 @@ module QA
end
it 'mentions another user in an issue',
-testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347988' do
+ testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347988' do
Page::Project::Issue::Show.perform do |show|
at_username = "@#{user.username}"
diff --git a/qa/qa/specs/features/browser_ui/3_create/merge_request/revert/reverting_merge_request_spec.rb b/qa/qa/specs/features/browser_ui/3_create/merge_request/revert/reverting_merge_request_spec.rb
index 54e9d3ed6c8..a7071d5fe1b 100644
--- a/qa/qa/specs/features/browser_ui/3_create/merge_request/revert/reverting_merge_request_spec.rb
+++ b/qa/qa/specs/features/browser_ui/3_create/merge_request/revert/reverting_merge_request_spec.rb
@@ -16,8 +16,6 @@ module QA
end
before do
- QA::Support::Helpers::ImportSource.enable(%w[gitlab_project])
-
Flow::Login.sign_in
end
diff --git a/qa/qa/specs/features/browser_ui/3_create/merge_request/view_merge_request_diff_patch_spec.rb b/qa/qa/specs/features/browser_ui/3_create/merge_request/view_merge_request_diff_patch_spec.rb
index 994baea7ad9..3b332e6b9f5 100644
--- a/qa/qa/specs/features/browser_ui/3_create/merge_request/view_merge_request_diff_patch_spec.rb
+++ b/qa/qa/specs/features/browser_ui/3_create/merge_request/view_merge_request_diff_patch_spec.rb
@@ -11,8 +11,6 @@ module QA
end
before do
- QA::Support::Helpers::ImportSource.enable(%w[gitlab_project])
-
Flow::Login.sign_in
merge_request.visit!
end
diff --git a/qa/qa/specs/features/browser_ui/3_create/repository/add_list_delete_branches_spec.rb b/qa/qa/specs/features/browser_ui/3_create/repository/add_list_delete_branches_spec.rb
index 866c6a146de..631b4ae099d 100644
--- a/qa/qa/specs/features/browser_ui/3_create/repository/add_list_delete_branches_spec.rb
+++ b/qa/qa/specs/features/browser_ui/3_create/repository/add_list_delete_branches_spec.rb
@@ -59,7 +59,14 @@ module QA
project.visit!
end
- it 'lists branches correctly after CRUD operations', testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347740' do
+ it(
+ 'lists branches correctly after CRUD operations',
+ testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347740',
+ quarantine: {
+ issue: 'https://gitlab.com/gitlab-org/gitlab/-/issues/414026',
+ type: :stale
+ }
+ ) do
Page::Project::Menu.perform(&:go_to_repository_branches)
expect(page).to have_content(master_branch)
diff --git a/qa/qa/specs/features/browser_ui/3_create/repository/add_new_branch_rule_spec.rb b/qa/qa/specs/features/browser_ui/3_create/repository/add_new_branch_rule_spec.rb
index 3d68de30d57..82074919ad4 100644
--- a/qa/qa/specs/features/browser_ui/3_create/repository/add_new_branch_rule_spec.rb
+++ b/qa/qa/specs/features/browser_ui/3_create/repository/add_new_branch_rule_spec.rb
@@ -3,10 +3,6 @@
module QA
RSpec.describe 'Create' do
describe 'Branch Rules Overview', product_group: :source_code,
- feature_flag: {
- name: 'branch_rules',
- scope: :project
- },
quarantine: {
issue: 'https://gitlab.com/gitlab-org/gitlab/-/issues/403583',
type: :flaky
@@ -22,8 +18,6 @@ module QA
end
before do
- Runtime::Feature.enable(:branch_rules, project: project)
-
Flow::Login.sign_in
Resource::Repository::Commit.fabricate_via_api! do |commit|
@@ -35,10 +29,6 @@ module QA
end
end
- after do
- Runtime::Feature.disable(:branch_rules, project: project)
- end
-
it 'adds a new branch rule', testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/397587' do
project.visit!
diff --git a/qa/qa/specs/features/browser_ui/3_create/repository/push_http_private_token_spec.rb b/qa/qa/specs/features/browser_ui/3_create/repository/push_http_private_token_spec.rb
index 0ec231ed66e..41ef38d2d66 100644
--- a/qa/qa/specs/features/browser_ui/3_create/repository/push_http_private_token_spec.rb
+++ b/qa/qa/specs/features/browser_ui/3_create/repository/push_http_private_token_spec.rb
@@ -4,7 +4,7 @@ module QA
RSpec.describe 'Create' do
describe 'Git push over HTTP', :smoke, :skip_fips_env, product_group: :source_code do
it 'user using a personal access token pushes code to the repository',
-testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347749' do
+ testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347749' do
Flow::Login.sign_in
access_token = Resource::PersonalAccessToken.fabricate!.token
diff --git a/qa/qa/specs/features/browser_ui/3_create/repository/push_over_http_spec.rb b/qa/qa/specs/features/browser_ui/3_create/repository/push_over_http_spec.rb
index efa1f9fe2c9..edc85849356 100644
--- a/qa/qa/specs/features/browser_ui/3_create/repository/push_over_http_spec.rb
+++ b/qa/qa/specs/features/browser_ui/3_create/repository/push_over_http_spec.rb
@@ -4,7 +4,7 @@ module QA
RSpec.describe 'Create' do
describe 'Git push over HTTP', product_group: :source_code do
it 'user pushes code to the repository', :smoke, :skip_fips_env,
- testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347747' do
+ testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347747' do
Flow::Login.sign_in
Resource::Repository::ProjectPush.fabricate! do |push|
@@ -20,7 +20,7 @@ module QA
end
it 'pushes to a project using a specific Praefect repository storage', :smoke, :skip_fips_env, :requires_admin,
- :requires_praefect, testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347789' do
+ :requires_praefect, testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347789' do
Flow::Login.sign_in_as_admin
project = Resource::Project.fabricate_via_api! do |storage_project|
diff --git a/qa/qa/specs/features/browser_ui/3_create/repository/push_over_ssh_spec.rb b/qa/qa/specs/features/browser_ui/3_create/repository/push_over_ssh_spec.rb
index f281f441e8a..dcee723a1c4 100644
--- a/qa/qa/specs/features/browser_ui/3_create/repository/push_over_ssh_spec.rb
+++ b/qa/qa/specs/features/browser_ui/3_create/repository/push_over_ssh_spec.rb
@@ -27,7 +27,7 @@ module QA
end
it 'pushes code to the repository via SSH', :smoke, :skip_fips_env,
- testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347825' do
+ testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347825' do
Resource::Repository::ProjectPush.fabricate! do |push|
push.project = project
push.ssh_key = @key
@@ -43,7 +43,7 @@ module QA
end
it 'pushes multiple branches and tags together', :smoke, :skip_fips_env,
- testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347826' do
+ testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347826' do
branches = []
tags = []
Git::Repository.perform do |repository|
diff --git a/qa/qa/specs/features/browser_ui/3_create/snippet/add_comment_to_snippet_spec.rb b/qa/qa/specs/features/browser_ui/3_create/snippet/add_comment_to_snippet_spec.rb
index c971ab869cd..c88bd808299 100644
--- a/qa/qa/specs/features/browser_ui/3_create/snippet/add_comment_to_snippet_spec.rb
+++ b/qa/qa/specs/features/browser_ui/3_create/snippet/add_comment_to_snippet_spec.rb
@@ -66,15 +66,19 @@ module QA
end
def verify_comment_content(author, comment_content)
- Page::Dashboard::Snippet::Show.perform do |comment|
- expect(comment).to have_comment_author(author)
- expect(comment).to have_comment_content(comment_content)
+ Page::Dashboard::Snippet::Show.perform do |snippet|
+ expect(snippet).to have_comment_author(author)
+ expect(snippet).to have_comment_content(comment_content)
end
end
def verify_comment_deleted
- expect(page).not_to have_content(comment_author.username)
- expect(page).not_to have_content(edited_comment_content)
+ Page::Dashboard::Snippet::Show.perform do |snippet|
+ snippet.within_notes_list do
+ expect(snippet).not_to have_content(comment_author.username)
+ expect(snippet).not_to have_content(edited_comment_content)
+ end
+ end
end
end
end
diff --git a/qa/qa/specs/features/browser_ui/3_create/source_editor/source_editor_toolbar_spec.rb b/qa/qa/specs/features/browser_ui/3_create/source_editor/source_editor_toolbar_spec.rb
index 435b9321601..9b1df337065 100644
--- a/qa/qa/specs/features/browser_ui/3_create/source_editor/source_editor_toolbar_spec.rb
+++ b/qa/qa/specs/features/browser_ui/3_create/source_editor/source_editor_toolbar_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
-# tagged transient due to feature-flag caching flakiness. Remove tag along with feature flag removal.
+
module QA
- RSpec.describe 'Create', feature_flag: { name: 'source_editor_toolbar', scope: :global } do
+ RSpec.describe 'Create' do
describe 'Source editor toolbar preview', product_group: :source_code do
let(:project) do
Resource::Project.fabricate_via_api! do |project|
@@ -13,16 +13,11 @@ module QA
let(:edited_readme_content) { 'Here is the edited content.' }
before do
- Runtime::Feature.enable(:source_editor_toolbar)
Flow::Login.sign_in
end
- after do
- Runtime::Feature.disable(:source_editor_toolbar)
- end
-
it 'can preview markdown side-by-side while editing',
- testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/367749' do
+ testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/367749' do
project.visit!
Page::Project::Show.perform do |project|
project.click_file('README.md')
@@ -30,16 +25,11 @@ module QA
Page::File::Show.perform(&:click_edit)
- # wait_until required due to feature_caching. Remove along with feature flag removal.
Page::File::Edit.perform do |file|
- Support::Waiter.wait_until(sleep_interval: 2, max_duration: 60, reload_page: page,
- retry_on_exception: true) do
- expect(file).to have_element(:editor_toolbar_button)
- end
file.remove_content
- file.click_editor_toolbar
file.add_content('# ' + edited_readme_content)
- file.wait_for_markdown_preview('h1', edited_readme_content)
+ file.preview
+ expect(file.has_markdown_preview?('h1', edited_readme_content)).to be true
file.commit_changes
end
diff --git a/qa/qa/specs/features/browser_ui/3_create/web_ide/add_new_directory_in_web_ide_spec.rb b/qa/qa/specs/features/browser_ui/3_create/web_ide/add_new_directory_in_web_ide_spec.rb
index af3d064a37c..3e8f9307cec 100644
--- a/qa/qa/specs/features/browser_ui/3_create/web_ide/add_new_directory_in_web_ide_spec.rb
+++ b/qa/qa/specs/features/browser_ui/3_create/web_ide/add_new_directory_in_web_ide_spec.rb
@@ -42,9 +42,7 @@ module QA
Page::Project::WebIDE::VSCode.perform do |ide|
ide.wait_for_ide_to_load
ide.create_new_folder(directory_name)
- ide.within_vscode_editor do
- expect(page).to have_content('A file or folder first_directory already exists at this location.')
- end
+ ide.has_message?('A file or folder first_directory already exists at this location.')
end
end
end
@@ -61,10 +59,8 @@ module QA
Page::Project::WebIDE::VSCode.perform do |ide|
ide.wait_for_ide_to_load
ide.create_new_folder(directory_name)
- ide.commit_and_push(directory_name)
- ide.within_vscode_editor do
- expect(page).to have_content('No changes found. Not able to commit.')
- end
+ ide.commit_toggle(directory_name)
+ ide.has_message?('No changes found. Not able to commit.')
end
end
end
diff --git a/qa/qa/specs/features/browser_ui/3_create/web_ide/upload_new_file_in_web_ide_spec.rb b/qa/qa/specs/features/browser_ui/3_create/web_ide/upload_new_file_in_web_ide_spec.rb
new file mode 100644
index 00000000000..336d32bcc35
--- /dev/null
+++ b/qa/qa/specs/features/browser_ui/3_create/web_ide/upload_new_file_in_web_ide_spec.rb
@@ -0,0 +1,71 @@
+# frozen_string_literal: true
+
+module QA
+ RSpec.describe 'Create', product_group: :ide,
+ quarantine: {
+ only: { job: 'slow-network' },
+ issue: 'https://gitlab.com/gitlab-org/gitlab/-/issues/387609',
+ type: :flaky
+ } do
+ describe 'Upload a file in Web IDE' do
+ let(:file_path) { File.absolute_path(File.join('qa', 'fixtures', 'web_ide', file_name)) }
+
+ let(:project) do
+ Resource::Project.fabricate_via_api! do |project|
+ project.name = 'upload-file-project'
+ project.initialize_with_readme = true
+ end
+ end
+
+ before do
+ Flow::Login.sign_in
+ project.visit!
+ end
+
+ context 'when a file with the same name already exists' do
+ let(:file_name) { 'README.md' }
+
+ it 'throws an error', testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/390005' do
+ Page::Project::Show.perform(&:open_web_ide!)
+ Page::Project::WebIDE::VSCode.perform do |ide|
+ ide.upload_file(file_path)
+ ide.has_message?("A file or folder with the name 'README.md' already exists in the destination folder")
+ end
+ end
+ end
+
+ shared_examples 'upload a file' do
+ it "verifies it successfully uploads and commits to a MR" do
+ Page::Project::Show.perform(&:open_web_ide!)
+ Page::Project::WebIDE::VSCode.perform do |ide|
+ ide.upload_file(file_path)
+ ide.has_message?(file_name)
+ ide.commit_and_push(file_name)
+ ide.has_message?('Success! Your changes have been committed.')
+ ide.create_merge_request
+ end
+
+ # Opens the MR in new tab and verify the file is in the MR
+ page.driver.browser.switch_to.window(page.driver.browser.window_handles.last)
+ Page::MergeRequest::Show.perform do |merge_request|
+ expect(merge_request).to have_content(file_name)
+ end
+ end
+ end
+
+ context 'when the file is a text file',
+ testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/390006' do
+ let(:file_name) { 'text_file.txt' }
+
+ it_behaves_like 'upload a file'
+ end
+
+ context 'when the file is an image',
+ testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/390007' do
+ let(:file_name) { 'dk.png' }
+
+ it_behaves_like 'upload a file'
+ end
+ end
+ end
+end
diff --git a/qa/qa/specs/features/browser_ui/4_verify/pipeline/include_multiple_files_from_multiple_projects_spec.rb b/qa/qa/specs/features/browser_ui/4_verify/pipeline/include_multiple_files_from_multiple_projects_spec.rb
index dc8db7ec387..59591fbe1cd 100644
--- a/qa/qa/specs/features/browser_ui/4_verify/pipeline/include_multiple_files_from_multiple_projects_spec.rb
+++ b/qa/qa/specs/features/browser_ui/4_verify/pipeline/include_multiple_files_from_multiple_projects_spec.rb
@@ -1,10 +1,7 @@
# frozen_string_literal: true
module QA
- RSpec.describe 'Verify', :runner, product_group: :pipeline_authoring, feature_flag: {
- name: 'ci_batch_project_includes_context',
- scope: :global
- } do
+ RSpec.describe 'Verify', :runner, product_group: :pipeline_authoring do
describe 'Include multiple files from multiple projects' do
let(:executor) { "qa-runner-#{Faker::Alphanumeric.alphanumeric(number: 8)}" }
@@ -34,7 +31,7 @@ module QA
end
end
- def before_do
+ before do
Flow::Login.sign_in
add_included_files_for(main_project)
@@ -50,44 +47,17 @@ module QA
runner.remove_via_api!
end
- context 'when FF is on', testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/396374' do
- before do
- Runtime::Feature.enable(:ci_batch_project_includes_context, project: main_project)
- sleep 60
-
- before_do
- end
-
- it 'runs the pipeline with composed config' do
- Page::Project::Pipeline::Show.perform do |pipeline|
- aggregate_failures 'pipeline has all expected jobs' do
- expect(pipeline).to have_job('test_for_main')
- expect(pipeline).to have_job("test1_for_#{project1.full_path}")
- expect(pipeline).to have_job("test1_for_#{project2.full_path}")
- expect(pipeline).to have_job("test2_for_#{project1.full_path}")
- expect(pipeline).to have_job("test2_for_#{main_project.full_path}")
- end
- end
- end
- end
-
- context 'when FF is off', testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/396375' do
- before do
- Runtime::Feature.disable(:ci_batch_project_includes_context, project: main_project)
- sleep 60
-
- before_do
- end
-
- it 'runs the pipeline with composed config' do
- Page::Project::Pipeline::Show.perform do |pipeline|
- aggregate_failures 'pipeline has all expected jobs' do
- expect(pipeline).to have_job('test_for_main')
- expect(pipeline).to have_job("test1_for_#{project1.full_path}")
- expect(pipeline).to have_job("test1_for_#{project2.full_path}")
- expect(pipeline).to have_job("test2_for_#{project1.full_path}")
- expect(pipeline).to have_job("test2_for_#{main_project.full_path}")
- end
+ it(
+ 'runs the pipeline with composed config',
+ testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/396374'
+ ) do
+ Page::Project::Pipeline::Show.perform do |pipeline|
+ aggregate_failures 'pipeline has all expected jobs' do
+ expect(pipeline).to have_job('test_for_main')
+ expect(pipeline).to have_job("test1_for_#{project1.full_path}")
+ expect(pipeline).to have_job("test1_for_#{project2.full_path}")
+ expect(pipeline).to have_job("test2_for_#{project1.full_path}")
+ expect(pipeline).to have_job("test2_for_#{main_project.full_path}")
end
end
end
diff --git a/qa/qa/specs/features/browser_ui/4_verify/pipeline/merge_mr_when_pipline_is_blocked_spec.rb b/qa/qa/specs/features/browser_ui/4_verify/pipeline/merge_mr_when_pipline_is_blocked_spec.rb
index 379499662c2..ecf4826262b 100644
--- a/qa/qa/specs/features/browser_ui/4_verify/pipeline/merge_mr_when_pipline_is_blocked_spec.rb
+++ b/qa/qa/specs/features/browser_ui/4_verify/pipeline/merge_mr_when_pipline_is_blocked_spec.rb
@@ -1,7 +1,11 @@
# frozen_string_literal: true
module QA
- RSpec.describe 'Verify', :runner, product_group: :pipeline_execution do
+ RSpec.describe 'Verify', :runner, product_group: :pipeline_execution,
+ quarantine: {
+ issue: 'https://gitlab.com/gitlab-org/gitlab/-/issues/411510',
+ type: :flaky
+ } do
context 'when pipeline is blocked' do
let(:executor) { "qa-runner-#{Faker::Alphanumeric.alphanumeric(number: 8)}" }
diff --git a/qa/qa/specs/features/browser_ui/4_verify/pipeline/pipeline_editor_branch_switcher_spec.rb b/qa/qa/specs/features/browser_ui/4_verify/pipeline/pipeline_editor_branch_switcher_spec.rb
deleted file mode 100644
index 30c71bc590c..00000000000
--- a/qa/qa/specs/features/browser_ui/4_verify/pipeline/pipeline_editor_branch_switcher_spec.rb
+++ /dev/null
@@ -1,91 +0,0 @@
-# frozen_string_literal: true
-
-module QA
- RSpec.describe 'Verify' do
- describe 'Pipeline editor', product_group: :pipeline_authoring do
- let(:random_test_string) { SecureRandom.hex(10) }
-
- let(:project) do
- Resource::Project.fabricate_via_api! do |project|
- project.name = 'pipeline-editor-project'
- end
- end
-
- let!(:commit) do
- Resource::Repository::Commit.fabricate_via_api! do |commit|
- commit.project = project
- commit.commit_message = 'Add .gitlab-ci.yml'
- commit.add_files(
- [
- {
- file_path: '.gitlab-ci.yml',
- content: <<~YAML
- stages:
- - test
-
- initialize:
- stage: test
- script:
- - echo "I am now on branch #{project.default_branch}"
- YAML
- }
- ]
- )
- end
- end
-
- let!(:test_branch) do
- Resource::Repository::ProjectPush.fabricate! do |resource|
- resource.project = project
- resource.branch_name = random_test_string
- resource.file_name = '.gitlab-ci.yml'
- resource.file_content = <<~YAML
- stages:
- - test
-
- initialize:
- stage: test
- script:
- - echo "I am now on branch #{random_test_string}"
- YAML
- end
- end
-
- before do
- Flow::Login.sign_in
- project.visit!
-
- # Project push sometimes takes a while to complete
- # Making sure new branch is pushed successfully prior to interacting
- Support::Retrier.retry_until(max_duration: 15, sleep_interval: 3, reload_page: false, message: 'Ensuring project has branch') do
- project.has_branch?(random_test_string)
- end
- end
-
- after do
- project.remove_via_api!
- end
-
- it 'can switch branches and target branch field updates accordingly', testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347661' do
- Page::Project::Menu.perform(&:go_to_pipeline_editor)
- Page::Project::PipelineEditor::Show.perform do |show|
- show.open_branch_selector_dropdown
- show.select_branch_from_dropdown(random_test_string)
-
- aggregate_failures do
- expect(show.source_branch_name).to eq(random_test_string), 'Branch field is not showing expected branch name.'
- expect(show.editing_content).to have_content(random_test_string), 'Editor content does not include expected test string.'
- end
-
- show.open_branch_selector_dropdown
- show.select_branch_from_dropdown(project.default_branch)
-
- aggregate_failures do
- expect(show.source_branch_name).to eq(project.default_branch), 'Branch field is not showing expected branch name.'
- expect(show.editing_content).to have_content(project.default_branch), 'Editor content does not include expected test string.'
- end
- end
- end
- end
- end
-end
diff --git a/qa/qa/specs/features/browser_ui/4_verify/pipeline/pipeline_editor_tabs_spec.rb b/qa/qa/specs/features/browser_ui/4_verify/pipeline/pipeline_editor_tabs_spec.rb
index 745879cf12f..a9f46e394f7 100644
--- a/qa/qa/specs/features/browser_ui/4_verify/pipeline/pipeline_editor_tabs_spec.rb
+++ b/qa/qa/specs/features/browser_ui/4_verify/pipeline/pipeline_editor_tabs_spec.rb
@@ -103,10 +103,10 @@ module QA
show.go_to_full_configuration_tab
- # TODO: remove this retry when
+ # TODO: remove page reload when
# https://gitlab.com/gitlab-org/gitlab/-/issues/378536 is resolved
- show.retry_until(max_attempts: 2, reload: true, sleep_interval: 1) { show.has_no_alert? }
- expect(show).to have_source_editor
+ expect { show.has_source_editor? }
+ .to eventually_be_truthy.within(max_attempts: 2, reload_page: show, sleep_interval: 1)
expect(show.ci_syntax_validate_message).to have_content('CI configuration is invalid')
end
diff --git a/qa/qa/specs/features/browser_ui/4_verify/pipeline/pipeline_with_image_pull_policy_spec.rb b/qa/qa/specs/features/browser_ui/4_verify/pipeline/pipeline_with_image_pull_policy_spec.rb
index aaaa11ef867..c693a57605e 100644
--- a/qa/qa/specs/features/browser_ui/4_verify/pipeline/pipeline_with_image_pull_policy_spec.rb
+++ b/qa/qa/specs/features/browser_ui/4_verify/pipeline/pipeline_with_image_pull_policy_spec.rb
@@ -71,10 +71,10 @@ module QA
if pull_image
expect(job_log).to have_content(message),
- "Expected to find #{message} in #{job_log}, but didn't."
+ "Expected to find #{message} in #{job_log}, but didn't."
else
expect(job_log).not_to have_content(message),
- "Found #{message} in #{job_log}, but didn't expect to."
+ "Found #{message} in #{job_log}, but didn't expect to."
end
end
end
@@ -96,7 +96,7 @@ module QA
visit_job
expect(job_log).to include(text1, text2),
- "Expected to find contents #{text1} and #{text2} in #{job_log}, but didn't."
+ "Expected to find contents #{text1} and #{text2} in #{job_log}, but didn't."
end
end
diff --git a/qa/qa/specs/features/browser_ui/4_verify/pipeline/run_pipeline_with_manual_jobs_spec.rb b/qa/qa/specs/features/browser_ui/4_verify/pipeline/run_pipeline_with_manual_jobs_spec.rb
index 37d1e20111d..d733ac9ba72 100644
--- a/qa/qa/specs/features/browser_ui/4_verify/pipeline/run_pipeline_with_manual_jobs_spec.rb
+++ b/qa/qa/specs/features/browser_ui/4_verify/pipeline/run_pipeline_with_manual_jobs_spec.rb
@@ -142,7 +142,7 @@ module QA
end
acceptable_statuses = %w[skipped manual]
- pipeline.pipeline_jobs.select { |job| !(acceptable_statuses.include? job[:status]) }
+ pipeline.jobs.select { |job| !(acceptable_statuses.include? job[:status]) }
end
end
end
diff --git a/qa/qa/specs/features/browser_ui/5_package/container_registry/online_garbage_collection_spec.rb b/qa/qa/specs/features/browser_ui/5_package/container_registry/online_garbage_collection_spec.rb
deleted file mode 100644
index 1e076117e4e..00000000000
--- a/qa/qa/specs/features/browser_ui/5_package/container_registry/online_garbage_collection_spec.rb
+++ /dev/null
@@ -1,112 +0,0 @@
-# frozen_string_literal: true
-
-module QA
- RSpec.describe 'Package', :requires_admin, product_group: :container_registry do
- describe 'Container Registry Online Garbage Collection', :registry_gc, only: { subdomain: %i[pre] } do
- let(:group) { Resource::Group.fabricate_via_api! }
-
- let(:imported_project) do
- Resource::ProjectImportedFromURL.fabricate_via_browser_ui! do |project|
- project.name = 'container-registry'
- project.group = group
- project.gitlab_repository_path = 'https://gitlab.com/gitlab-org/container-registry.git'
- end
- end
-
- let!(:gitlab_ci_yaml) do
- <<~YAML
- variables:
- GOPATH: $CI_PROJECT_DIR/.go
- BUILD_CACHE: $CI_PROJECT_DIR/.online-gc-tester
- STAGE_ONE_VALIDATION_DELAY: "6m"
- STAGE_TWO_VALIDATION_DELAY: "12m"
- STAGE_THREE_VALIDATION_DELAY: "6m"
- STAGE_FOUR_VALIDATION_DELAY: "12m"
- STAGE_FIVE_VALIDATION_DELAY: "12m"
-
- stages:
- - generate
- - build
- - test
-
- .base: &base
- image: docker:19
- services:
- - docker:19-dind
- variables:
- DOCKER_HOST: tcp://docker:2376
- DOCKER_TLS_CERTDIR: "/certs"
- DOCKER_TLS_VERIFY: 1
- DOCKER_CERT_PATH: "$DOCKER_TLS_CERTDIR/client"
- before_script:
- - until docker info; do sleep 1; done
- - mkdir -p $GOPATH
- - mkdir -p $BUILD_CACHE
- - docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
-
- test:
- stage: generate
- extends: .base
- script:
- - apk add go make git
- - make binaries
- - ./bin/online-gc-tester generate --base-dir=$BUILD_CACHE
- - ./bin/online-gc-tester build --base-dir=$BUILD_CACHE
- - ./bin/online-gc-tester push --base-dir=$BUILD_CACHE
- - ./bin/online-gc-tester pull --base-dir=$BUILD_CACHE
- - ./bin/online-gc-tester test --base-dir=$BUILD_CACHE --stage=1 --delay=$STAGE_ONE_VALIDATION_DELAY
- - ./bin/online-gc-tester test --base-dir=$BUILD_CACHE --stage=2 --delay=$STAGE_TWO_VALIDATION_DELAY
- - ./bin/online-gc-tester test --base-dir=$BUILD_CACHE --stage=3 --delay=$STAGE_THREE_VALIDATION_DELAY
- - ./bin/online-gc-tester test --base-dir=$BUILD_CACHE --stage=4 --delay=$STAGE_FOUR_VALIDATION_DELAY
- - ./bin/online-gc-tester test --base-dir=$BUILD_CACHE --stage=5 --delay=$STAGE_FIVE_VALIDATION_DELAY
- timeout: 1h 30m
- YAML
- end
-
- before do
- QA::Support::Helpers::ImportSource.enable('git')
-
- Flow::Login.sign_in
-
- imported_project
-
- Page::Project::Menu.perform(&:go_to_repository_settings)
-
- Page::Project::Settings::Repository.perform do |setting|
- setting.expand_default_branch
- end
-
- Page::Project::Settings::DefaultBranch.perform do |setting|
- setting.set_default_branch('online-gc-test-builder-poc')
- setting.click_save_changes_button
- end
-
- Support::Retrier.retry_on_exception(max_attempts: 3, sleep_interval: 2) do
- Resource::Repository::Commit.fabricate_via_api! do |commit|
- commit.project = imported_project
- commit.branch = 'online-gc-test-builder-poc'
- commit.commit_message = 'Update .gitlab-ci.yml'
- commit.update_files([{
- file_path: '.gitlab-ci.yml',
- content: gitlab_ci_yaml
- }])
- end
- end
- end
-
- it 'runs the online garbage collector tool', testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347663' do
- imported_project.visit!
-
- Flow::Pipeline.visit_latest_pipeline
-
- Page::Project::Pipeline::Show.perform do |pipeline|
- pipeline.click_job('test')
- end
-
- Page::Project::Job::Show.perform do |job|
- expect(job).to be_successful(timeout: 3900)
- end
- end
- end
- end
-end
diff --git a/qa/qa/specs/features/browser_ui/5_package/container_registry/container_registry_spec.rb b/qa/qa/specs/features/browser_ui/5_package/container_registry/saas/container_registry_spec.rb
index 680b722edb7..4b2d9f96cd2 100644
--- a/qa/qa/specs/features/browser_ui/5_package/container_registry/container_registry_spec.rb
+++ b/qa/qa/specs/features/browser_ui/5_package/container_registry/saas/container_registry_spec.rb
@@ -2,7 +2,8 @@
module QA
RSpec.describe 'Package' do
- describe 'Container Registry', only: { subdomain: %i[staging staging-canary pre] }, product_group: :container_registry do
+ describe 'SaaS Container Registry', only: { subdomain: %i[staging staging-canary pre] },
+ product_group: :container_registry do
let(:project) do
Resource::Project.fabricate_via_api! do |project|
project.name = 'project-with-registry'
@@ -12,7 +13,7 @@ module QA
let(:registry_repository) do
Resource::RegistryRepository.fabricate! do |repository|
- repository.name = "#{project.path_with_namespace}"
+ repository.name = project.path_with_namespace.to_s
repository.project = project
end
end
@@ -20,10 +21,10 @@ module QA
let!(:gitlab_ci_yaml) do
<<~YAML
build:
- image: docker:19.03.12
+ image: docker:24.0.1
stage: build
services:
- - docker:19.03.12-dind
+ - docker:24.0.1-dind
variables:
IMAGE_TAG: $CI_REGISTRY_IMAGE:$CI_COMMIT_REF_SLUG
DOCKER_HOST: tcp://docker:2376
@@ -49,7 +50,8 @@ module QA
registry_repository&.remove_via_api!
end
- it 'pushes project image to the container registry and deletes tag', testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347687' do
+ it 'pushes project image to the container registry and deletes tag',
+ testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/412806' do
Flow::Login.sign_in
project.visit!
@@ -58,9 +60,9 @@ module QA
commit.project = project
commit.commit_message = 'Add .gitlab-ci.yml'
commit.add_files([{
- file_path: '.gitlab-ci.yml',
- content: gitlab_ci_yaml
- }])
+ file_path: '.gitlab-ci.yml',
+ content: gitlab_ci_yaml
+ }])
end
end
diff --git a/qa/qa/specs/features/browser_ui/5_package/container_registry/saas/pull_container_registry_image_spec.rb b/qa/qa/specs/features/browser_ui/5_package/container_registry/saas/pull_container_registry_image_spec.rb
new file mode 100644
index 00000000000..85a88b54cc2
--- /dev/null
+++ b/qa/qa/specs/features/browser_ui/5_package/container_registry/saas/pull_container_registry_image_spec.rb
@@ -0,0 +1,31 @@
+# frozen_string_literal: true
+
+module QA
+ RSpec.describe 'Package' do
+ describe 'SaaS Container Registry', only: { subdomain: %i[staging] }, product_group: :container_registry do
+ let(:project) do
+ Resource::Project.init do |project|
+ project.path_with_namespace = 'gitlab-qa/container-registry-sanity'
+ end.reload!
+ end
+
+ it 'pulls an image from an existing repository',
+ testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/412799' do
+ Flow::Login.sign_in
+ project.visit!
+
+ Page::Project::Menu.perform(&:go_to_pipelines)
+ Page::Project::Pipeline::Index.perform(&:click_run_pipeline_button)
+ Page::Project::Pipeline::New.perform(&:click_run_pipeline_button)
+
+ Page::Project::Pipeline::Show.perform do |pipeline|
+ pipeline.click_job('test')
+ end
+
+ Page::Project::Job::Show.perform do |job|
+ expect(job).to be_successful(timeout: 800)
+ end
+ end
+ end
+ end
+end
diff --git a/qa/qa/specs/features/browser_ui/5_package/container_registry/container_registry_omnibus_spec.rb b/qa/qa/specs/features/browser_ui/5_package/container_registry/self_managed/container_registry_spec.rb
index b39475b481d..800b3a01dc6 100644
--- a/qa/qa/specs/features/browser_ui/5_package/container_registry/container_registry_omnibus_spec.rb
+++ b/qa/qa/specs/features/browser_ui/5_package/container_registry/self_managed/container_registry_spec.rb
@@ -50,59 +50,59 @@ module QA
context "when tls is disabled" do
where do
{
- 'using docker:18.09.9 and a personal access token' => {
- docker_client_version: 'docker:18.09.9',
+ 'using docker:20.10.23 and a personal access token' => {
+ docker_client_version: 'docker:20.10.23',
authentication_token_type: :personal_access_token,
token_name: 'Personal Access Token',
- testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/348499'
+ testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/412807'
},
- 'using docker:18.09.9 and a project deploy token' => {
- docker_client_version: 'docker:18.09.9',
+ 'using docker:20.10.23 and a project deploy token' => {
+ docker_client_version: 'docker:20.10.23',
authentication_token_type: :project_deploy_token,
token_name: 'Deploy Token',
- testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/348852'
+ testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/412808'
},
- 'using docker:18.09.9 and a ci job token' => {
- docker_client_version: 'docker:18.09.9',
+ 'using docker:20.10.23 and a ci job token' => {
+ docker_client_version: 'docker:20.10.23',
authentication_token_type: :ci_job_token,
token_name: 'Job Token',
- testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/348765'
+ testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/412809'
},
- 'using docker:19.03.12 and a personal access token' => {
- docker_client_version: 'docker:19.03.12',
+ 'using docker:23.0.6 and a personal access token' => {
+ docker_client_version: 'docker:23.0.6',
authentication_token_type: :personal_access_token,
token_name: 'Personal Access Token',
- testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/348507'
+ testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/412810'
},
- 'using docker:19.03.12 and a project deploy token' => {
- docker_client_version: 'docker:19.03.12',
+ 'using docker:23.0.6 and a project deploy token' => {
+ docker_client_version: 'docker:23.0.6',
authentication_token_type: :project_deploy_token,
token_name: 'Deploy Token',
- testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/348859'
+ testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/412813'
},
- 'using docker:19.03.12 and a ci job token' => {
- docker_client_version: 'docker:19.03.12',
+ 'using docker:23.0.6 and a ci job token' => {
+ docker_client_version: 'docker:23.0.6',
authentication_token_type: :ci_job_token,
token_name: 'Job Token',
- testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/348654'
+ testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/412814'
},
- 'using docker:20.10 and a personal access token' => {
- docker_client_version: 'docker:20.10',
+ 'using docker:24.0.1 and a personal access token' => {
+ docker_client_version: 'docker:24.0.1',
authentication_token_type: :personal_access_token,
token_name: 'Personal Access Token',
- testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/348754'
+ testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/412817'
},
- 'using docker:20.10 and a project deploy token' => {
- docker_client_version: 'docker:20.10',
+ 'using docker:24.0.1 and a project deploy token' => {
+ docker_client_version: 'docker:24.0.1',
authentication_token_type: :project_deploy_token,
token_name: 'Deploy Token',
- testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/348856'
+ testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/412818'
},
- 'using docker:20.10 and a ci job token' => {
- docker_client_version: 'docker:20.10',
+ 'using docker:24.0.1 and a ci job token' => {
+ docker_client_version: 'docker:24.0.1',
authentication_token_type: :ci_job_token,
token_name: 'Job Token',
- testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/348766'
+ testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/412819'
}
}
end
@@ -201,10 +201,10 @@ module QA
content:
<<~YAML
build:
- image: docker:19.03.12
+ image: docker:23.0.6
stage: build
services:
- - name: docker:19.03.12-dind
+ - name: docker:23.0.6-dind
command:
- /bin/sh
- -c
diff --git a/qa/qa/specs/features/browser_ui/5_package/dependency_proxy/dependency_proxy_spec.rb b/qa/qa/specs/features/browser_ui/5_package/dependency_proxy/dependency_proxy_spec.rb
index a0d283fd7ad..235c3604523 100644
--- a/qa/qa/specs/features/browser_ui/5_package/dependency_proxy/dependency_proxy_spec.rb
+++ b/qa/qa/specs/features/browser_ui/5_package/dependency_proxy/dependency_proxy_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module QA
- RSpec.describe 'Package', :orchestrated, :registry, only: { pipeline: :main }, product_group: :container_registry do
+ RSpec.describe 'Package', :orchestrated, :registry, :skip_live_env, product_group: :container_registry do
describe 'Dependency Proxy' do
using RSpec::Parameterized::TableSyntax
include Support::Helpers::MaskToken
@@ -53,65 +53,28 @@ module QA
end
after do
- project.remove_via_api!
runner.remove_via_api!
end
where do
{
- 'using docker:18.09.9 and a personal access token' => {
- docker_client_version: 'docker:18.09.9',
+ 'using docker:24.0.1 and a personal access token' => {
+ docker_client_version: 'docker:24.0.1',
authentication_token_type: :personal_access_token,
token_name: 'Personal Access Token',
- testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/370195'
+ testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/412820'
},
- 'using docker:18.09.9 and a group deploy token' => {
- docker_client_version: 'docker:18.09.9',
+ 'using docker:24.0.1 and a group deploy token' => {
+ docker_client_version: 'docker:24.0.1',
authentication_token_type: :group_deploy_token,
token_name: 'Deploy Token',
- testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/370196'
+ testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/412821'
},
- 'using docker:18.09.9 and a ci job token' => {
- docker_client_version: 'docker:18.09.9',
+ 'using docker:24.0.1 and a ci job token' => {
+ docker_client_version: 'docker:24.0.1',
authentication_token_type: :ci_job_token,
token_name: 'Job Token',
- testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/370198'
- },
- 'using docker:19.03.12 and a personal access token' => {
- docker_client_version: 'docker:19.03.12',
- authentication_token_type: :personal_access_token,
- token_name: 'Personal Access Token',
- testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/370189'
- },
- 'using docker:19.03.12 and a group deploy token' => {
- docker_client_version: 'docker:19.03.12',
- authentication_token_type: :group_deploy_token,
- token_name: 'Deploy Token',
- testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/370190'
- },
- 'using docker:19.03.12 and a ci job token' => {
- docker_client_version: 'docker:19.03.12',
- authentication_token_type: :ci_job_token,
- token_name: 'Job Token',
- testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/370191'
- },
- 'using docker:20.10 and a personal access token' => {
- docker_client_version: 'docker:20.10',
- authentication_token_type: :personal_access_token,
- token_name: 'Personal Access Token',
- testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/370192'
- },
- 'using docker:20.10 and a group deploy token' => {
- docker_client_version: 'docker:20.10',
- authentication_token_type: :group_deploy_token,
- token_name: 'Deploy Token',
- testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/370193'
- },
- 'using docker:20.10 and a ci job token' => {
- docker_client_version: 'docker:20.10',
- authentication_token_type: :ci_job_token,
- token_name: 'Job Token',
- testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/370194'
+ testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/412822'
}
}
end
@@ -186,7 +149,7 @@ module QA
project.group.visit!
- Page::Group::Menu.perform(&:go_to_dependency_proxy)
+ Page::Group::Menu.perform(&:go_to_group_dependency_proxy)
Page::Group::DependencyProxy.perform do |index|
expect(index).to have_blob_count("Contains 1 blobs of images")
diff --git a/qa/qa/specs/features/browser_ui/5_package/infrastructure_registry/terraform_module_registry_spec.rb b/qa/qa/specs/features/browser_ui/5_package/infrastructure_registry/terraform_module_registry_spec.rb
index 8d80e314d71..312c5a13a61 100644
--- a/qa/qa/specs/features/browser_ui/5_package/infrastructure_registry/terraform_module_registry_spec.rb
+++ b/qa/qa/specs/features/browser_ui/5_package/infrastructure_registry/terraform_module_registry_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module QA
- RSpec.describe 'Package', :requires_admin, :orchestrated, :packages, product_group: :package_registry do
+ RSpec.describe 'Package', product_group: :package_registry do
describe 'Terraform Module Registry' do
include Runtime::Fixtures
diff --git a/qa/qa/specs/features/browser_ui/5_package/package_registry/composer_registry_spec.rb b/qa/qa/specs/features/browser_ui/5_package/package_registry/composer_registry_spec.rb
index d0bae3cfa98..58eb63de21d 100644
--- a/qa/qa/specs/features/browser_ui/5_package/package_registry/composer_registry_spec.rb
+++ b/qa/qa/specs/features/browser_ui/5_package/package_registry/composer_registry_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module QA
- RSpec.describe 'Package', :orchestrated, :packages, :object_storage, product_group: :package_registry do
+ RSpec.describe 'Package', :object_storage, except: { job: 'relative-url' }, product_group: :package_registry do
describe 'Composer Repository' do
include Runtime::Fixtures
diff --git a/qa/qa/specs/features/browser_ui/5_package/package_registry/conan_repository_spec.rb b/qa/qa/specs/features/browser_ui/5_package/package_registry/conan_repository_spec.rb
index bedd447f6ec..4179b65d930 100644
--- a/qa/qa/specs/features/browser_ui/5_package/package_registry/conan_repository_spec.rb
+++ b/qa/qa/specs/features/browser_ui/5_package/package_registry/conan_repository_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module QA
- RSpec.describe 'Package', :orchestrated, :packages, :object_storage, product_group: :package_registry, quarantine: {
+ RSpec.describe 'Package', :object_storage, except: { job: 'relative-url' }, product_group: :package_registry, quarantine: {
only: { job: 'object_storage' },
issue: 'https://gitlab.com/gitlab-org/gitlab/-/issues/335981',
type: :bug
diff --git a/qa/qa/specs/features/browser_ui/5_package/package_registry/generic_repository_spec.rb b/qa/qa/specs/features/browser_ui/5_package/package_registry/generic_repository_spec.rb
index c4a1663f36e..1253dc91ca3 100644
--- a/qa/qa/specs/features/browser_ui/5_package/package_registry/generic_repository_spec.rb
+++ b/qa/qa/specs/features/browser_ui/5_package/package_registry/generic_repository_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module QA
- RSpec.describe 'Package', :orchestrated, :packages, :object_storage, :reliable, product_group: :package_registry do
+ RSpec.describe 'Package', :object_storage, except: { job: 'relative-url' }, product_group: :package_registry do
describe 'Generic Repository' do
include Runtime::Fixtures
diff --git a/qa/qa/specs/features/browser_ui/5_package/package_registry/helm_registry_spec.rb b/qa/qa/specs/features/browser_ui/5_package/package_registry/helm_registry_spec.rb
index 6cf6a77ab74..19d0a4a816f 100644
--- a/qa/qa/specs/features/browser_ui/5_package/package_registry/helm_registry_spec.rb
+++ b/qa/qa/specs/features/browser_ui/5_package/package_registry/helm_registry_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module QA
- RSpec.describe 'Package', :skip_live_env, :orchestrated, :packages, :object_storage, product_group: :package_registry do
+ RSpec.describe 'Package', :object_storage, except: { job: 'relative-url' }, product_group: :package_registry do
describe 'Helm Registry' do
using RSpec::Parameterized::TableSyntax
include Runtime::Fixtures
diff --git a/qa/qa/specs/features/browser_ui/5_package/package_registry/maven/maven_group_level_spec.rb b/qa/qa/specs/features/browser_ui/5_package/package_registry/maven/maven_group_level_spec.rb
index f5dff1b3e0b..3553e67eb2c 100644
--- a/qa/qa/specs/features/browser_ui/5_package/package_registry/maven/maven_group_level_spec.rb
+++ b/qa/qa/specs/features/browser_ui/5_package/package_registry/maven/maven_group_level_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module QA
- RSpec.describe 'Package', :orchestrated, :requires_admin, :packages, :object_storage, :reliable, product_group: :package_registry, feature_flag: { name: 'maven_central_request_forwarding', scope: :global } do
+ RSpec.describe 'Package', :object_storage, except: { job: 'relative-url' }, product_group: :package_registry do
describe 'Maven group level endpoint' do
include Runtime::Fixtures
include Support::Helpers::MaskToken
@@ -221,100 +221,5 @@ module QA
end
end
end
-
- describe 'Maven request forwarding' do
- include Runtime::Fixtures
-
- let(:group_id) { 'com.gitlab.qa' }
- let(:artifact_id) { "maven-#{SecureRandom.hex(8)}" }
- let(:package_name) { "#{group_id}/#{artifact_id}".tr('.', '/') }
- let(:package_version) { '1.3.7' }
- let(:personal_access_token) { Runtime::Env.personal_access_token }
- let(:group) { Resource::Group.fabricate_via_api! }
-
- let(:imported_project) do
- Resource::ProjectImportedFromURL.fabricate_via_browser_ui! do |project|
- project.name = "maven_imported_project"
- project.group = group
- project.gitlab_repository_path = 'https://gitlab.com/gitlab-org/quality/imported-projects/maven.git'
- end
- end
-
- let(:gitlab_address_with_port) do
- uri = URI.parse(Runtime::Scenario.gitlab_address)
- "#{uri.scheme}://#{uri.host}:#{uri.port}"
- end
-
- let(:package) do
- Resource::Package.init do |package|
- package.name = package_name
- package.project = imported_project
- end
- end
-
- let(:runner) do
- Resource::ProjectRunner.fabricate! do |runner|
- runner.name = "qa-runner-#{Time.now.to_i}"
- runner.tags = ["runner-for-#{imported_project.group.name}"]
- runner.executor = :docker
- runner.token = imported_project.group.reload!.runners_token
- end
- end
-
- before do
- QA::Support::Helpers::ImportSource.enable('git')
-
- Runtime::Feature.enable(:maven_central_request_forwarding)
- Flow::Login.sign_in_unless_signed_in
-
- imported_project
- runner
- end
-
- after do
- Runtime::Feature.disable(:maven_central_request_forwarding)
-
- runner.remove_via_api!
- package.remove_via_api!
- imported_project.remove_via_api!
- end
-
- it(
- 'uses GitLab as a mirror of the central proxy',
- :skip_live_env,
- testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/375988',
- quarantine: {
- type: :investigating,
- issue: 'https://gitlab.com/gitlab-org/gitlab/-/issues/378221'
- }
- ) do
- Support::Retrier.retry_on_exception(max_attempts: 3, sleep_interval: 2) do
- Resource::Repository::Commit.fabricate_via_api! do |commit|
- settings_xml = ERB.new(read_fixture('package_managers/maven/group/consumer/request_forwarding', 'settings.xml.erb')).result(binding)
- gitlab_ci_yaml = ERB.new(read_fixture('package_managers/maven/group/consumer/request_forwarding', 'gitlab_ci.yaml.erb')).result(binding)
-
- commit.project = imported_project
- commit.commit_message = 'Add files'
- commit.add_files(
- [
- { file_path: '.gitlab-ci.yml', content: gitlab_ci_yaml },
- { file_path: 'settings.xml', content: settings_xml }
- ])
- end
- end
-
- imported_project.visit!
-
- Flow::Pipeline.visit_latest_pipeline
-
- Page::Project::Pipeline::Show.perform do |pipeline|
- pipeline.click_job('install')
- end
-
- Page::Project::Job::Show.perform do |job|
- expect(job).to be_successful(timeout: 800)
- end
- end
- end
end
end
diff --git a/qa/qa/specs/features/browser_ui/5_package/package_registry/maven/maven_project_level_spec.rb b/qa/qa/specs/features/browser_ui/5_package/package_registry/maven/maven_project_level_spec.rb
index 27bca6c17a2..91d8f0dc181 100644
--- a/qa/qa/specs/features/browser_ui/5_package/package_registry/maven/maven_project_level_spec.rb
+++ b/qa/qa/specs/features/browser_ui/5_package/package_registry/maven/maven_project_level_spec.rb
@@ -1,11 +1,7 @@
# frozen_string_literal: true
module QA
- RSpec.describe 'Package', :orchestrated, :requires_admin, :packages, :object_storage, :reliable,
- feature_flag: {
- name: 'maven_central_request_forwarding',
- scope: :global
- } do
+ RSpec.describe 'Package', :object_storage, except: { job: 'relative-url' } do
describe 'Maven project level endpoint', product_group: :package_registry do
include Runtime::Fixtures
include Support::Helpers::MaskToken
@@ -148,109 +144,5 @@ module QA
end
end
end
-
- describe 'Maven request forwarding' do
- include Runtime::Fixtures
-
- let(:group_id) { 'com.gitlab.qa' }
- let(:artifact_id) { "maven-#{SecureRandom.hex(8)}" }
- let(:package_name) { "#{group_id}/#{artifact_id}".tr('.', '/') }
- let(:package_version) { '1.3.7' }
- let(:package_type) { 'maven' }
- let(:personal_access_token) { Runtime::Env.personal_access_token }
- let(:group) { Resource::Group.fabricate_via_api! }
-
- let(:gitlab_address_with_port) do
- uri = URI.parse(Runtime::Scenario.gitlab_address)
- "#{uri.scheme}://#{uri.host}:#{uri.port}"
- end
-
- let(:package) do
- Resource::Package.init do |package|
- package.name = package_name
- package.project = imported_project
- end
- end
-
- let(:runner) do
- Resource::GroupRunner.fabricate! do |runner|
- runner.name = "qa-runner-#{Time.now.to_i}"
- runner.tags = ["runner-for-#{imported_project.name}"]
- runner.executor = :docker
- runner.group = group
- end
- end
-
- let(:imported_project) do
- Resource::ProjectImportedFromURL.fabricate_via_browser_ui! do |project|
- project.name = "#{package_type}_imported_project"
- project.group = group
- project.gitlab_repository_path = 'https://gitlab.com/gitlab-org/quality/imported-projects/maven.git'
- end
- end
-
- before do
- QA::Support::Helpers::ImportSource.enable('git')
-
- Runtime::Feature.enable(:maven_central_request_forwarding)
- Flow::Login.sign_in_unless_signed_in
-
- imported_project
- runner
- end
-
- after do
- Runtime::Feature.disable(:maven_central_request_forwarding)
-
- runner.remove_via_api!
- package.remove_via_api!
- imported_project.remove_via_api!
- end
-
- it(
- 'uses GitLab as a mirror of the central proxy',
- :skip_live_env,
- quarantine: {
- issue: 'https://gitlab.com/gitlab-org/gitlab/-/issues/378221',
- type: :investigating
- },
- testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/375767'
- ) do
- Support::Retrier.retry_on_exception(max_attempts: 3, sleep_interval: 2) do
- Resource::Repository::Commit.fabricate_via_api! do |commit|
- gitlab_ci_yaml = ERB.new(read_fixture('package_managers/maven/project/request_forwarding',
- 'gitlab_ci.yaml.erb'
- )
- )
- .result(binding)
- settings_xml = ERB.new(read_fixture('package_managers/maven/project/request_forwarding',
- 'settings.xml.erb'
- )
- )
- .result(binding)
-
- commit.project = imported_project
- commit.commit_message = 'Add files'
- commit.add_files(
- [
- { file_path: '.gitlab-ci.yml', content: gitlab_ci_yaml },
- { file_path: 'settings.xml', content: settings_xml }
- ])
- end
- end
-
- imported_project.visit!
-
- Flow::Pipeline.visit_latest_pipeline
-
- Page::Project::Pipeline::Show.perform do |pipeline|
- pipeline.click_job('install')
- end
-
- Page::Project::Job::Show.perform do |job|
- expect(job).to be_successful(timeout: 800)
- end
- end
- end
end
end
diff --git a/qa/qa/specs/features/browser_ui/5_package/package_registry/maven_gradle_repository_spec.rb b/qa/qa/specs/features/browser_ui/5_package/package_registry/maven_gradle_repository_spec.rb
index 423304051a2..032c77b2519 100644
--- a/qa/qa/specs/features/browser_ui/5_package/package_registry/maven_gradle_repository_spec.rb
+++ b/qa/qa/specs/features/browser_ui/5_package/package_registry/maven_gradle_repository_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module QA
- RSpec.describe 'Package', :skip_live_env, :orchestrated, :packages, :object_storage, product_group: :package_registry do
+ RSpec.describe 'Package', :object_storage, except: { job: 'relative-url' }, product_group: :package_registry do
describe 'Maven Repository with Gradle' do
using RSpec::Parameterized::TableSyntax
include Runtime::Fixtures
diff --git a/qa/qa/specs/features/browser_ui/5_package/package_registry/npm/npm_group_level_spec.rb b/qa/qa/specs/features/browser_ui/5_package/package_registry/npm/npm_group_level_spec.rb
new file mode 100644
index 00000000000..1b97f7d0a6a
--- /dev/null
+++ b/qa/qa/specs/features/browser_ui/5_package/package_registry/npm/npm_group_level_spec.rb
@@ -0,0 +1,174 @@
+# frozen_string_literal: true
+
+module QA
+ RSpec.describe 'Package' do
+ describe 'Package Registry', :object_storage, except: { job: 'relative-url' }, product_group: :package_registry do
+ describe 'npm group level endpoint' do
+ using RSpec::Parameterized::TableSyntax
+ include Runtime::Fixtures
+ include Support::Helpers::MaskToken
+
+ let!(:registry_scope) { Runtime::Namespace.sandbox_name }
+ let!(:personal_access_token) do
+ Flow::Login.sign_in unless Page::Main::Menu.perform(&:signed_in?)
+
+ Resource::PersonalAccessToken.fabricate!.token
+ end
+
+ let(:project_deploy_token) do
+ Resource::ProjectDeployToken.fabricate_via_api! do |deploy_token|
+ deploy_token.name = 'npm-deploy-token'
+ deploy_token.project = project
+ deploy_token.scopes = %w[
+ read_repository
+ read_package_registry
+ write_package_registry
+ ]
+ end
+ end
+
+ let(:uri) { URI.parse(Runtime::Scenario.gitlab_address) }
+ let(:gitlab_address_with_port) { "#{uri.scheme}://#{uri.host}:#{uri.port}" }
+ let(:gitlab_host_with_port) { "#{uri.host}:#{uri.port}" }
+
+ let!(:project) do
+ Resource::Project.fabricate_via_api! do |project|
+ project.name = 'npm-group-level-publish'
+ end
+ end
+
+ let!(:another_project) do
+ Resource::Project.fabricate_via_api! do |another_project|
+ another_project.name = 'npm-group-level-install'
+ another_project.group = project.group
+ end
+ end
+
+ let!(:runner) do
+ Resource::GroupRunner.fabricate! do |runner|
+ runner.name = "qa-runner-#{Time.now.to_i}"
+ runner.tags = ["runner-for-#{project.group.name}"]
+ runner.executor = :docker
+ runner.group = project.group
+ end
+ end
+
+ let(:package) do
+ Resource::Package.init do |package|
+ package.name = "@#{registry_scope}/#{project.name}-#{SecureRandom.hex(8)}"
+ package.project = project
+ end
+ end
+
+ after do
+ package.remove_via_api!
+ runner.remove_via_api!
+ project.remove_via_api!
+ another_project.remove_via_api!
+ end
+
+ where(:case_name, :authentication_token_type, :token_name, :testcase) do
+ 'using personal access token' | :personal_access_token | 'Personal Access Token' | 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/413760'
+ 'using ci job token' | :ci_job_token | 'CI Job Token' | 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/413761'
+ 'using project deploy token' | :project_deploy_token | 'Deploy Token' | 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/413762'
+ end
+
+ with_them do
+ let(:auth_token) do
+ case authentication_token_type
+ when :personal_access_token
+ use_ci_variable(name: 'PERSONAL_ACCESS_TOKEN', value: personal_access_token, project: project)
+ use_ci_variable(name: 'PERSONAL_ACCESS_TOKEN', value: personal_access_token, project: another_project)
+ when :ci_job_token
+ '${CI_JOB_TOKEN}'
+ when :project_deploy_token
+ use_ci_variable(name: 'PROJECT_DEPLOY_TOKEN', value: project_deploy_token.token, project: project)
+ use_ci_variable(name: 'PROJECT_DEPLOY_TOKEN', value: project_deploy_token.token, project: another_project)
+ end
+ end
+
+ it 'push and pull a npm package via CI', testcase: params[:testcase] do
+ Support::Retrier.retry_on_exception(max_attempts: 3, sleep_interval: 2) do
+ npm_upload_yaml = ERB.new(read_fixture('package_managers/npm',
+ 'npm_upload_package_group.yaml.erb')).result(binding)
+ package_json = ERB.new(read_fixture('package_managers/npm', 'package.json.erb')).result(binding)
+
+ Resource::Repository::Commit.fabricate_via_api! do |commit|
+ commit.project = project
+ commit.commit_message = 'Add files'
+ commit.add_files([
+ {
+ file_path: '.gitlab-ci.yml',
+ content: npm_upload_yaml
+ },
+ {
+ file_path: 'package.json',
+ content: package_json
+ }
+ ])
+ end
+ end
+
+ project.visit!
+ Flow::Pipeline.visit_latest_pipeline
+
+ Page::Project::Pipeline::Show.perform do |pipeline|
+ pipeline.click_job('deploy')
+ end
+
+ Page::Project::Job::Show.perform do |job|
+ expect(job).to be_successful(timeout: 800)
+ end
+
+ Support::Retrier.retry_on_exception(max_attempts: 3, sleep_interval: 2) do
+ Resource::Repository::Commit.fabricate_via_api! do |commit|
+ npm_install_yaml = ERB.new(read_fixture('package_managers/npm',
+ 'npm_install_package_group.yaml.erb')).result(binding)
+
+ commit.project = another_project
+ commit.commit_message = 'Add .gitlab-ci.yml'
+ commit.add_files([
+ {
+ file_path: '.gitlab-ci.yml',
+ content: npm_install_yaml
+ }
+ ])
+ end
+ end
+
+ another_project.visit!
+ Flow::Pipeline.visit_latest_pipeline
+
+ Page::Project::Pipeline::Show.perform do |pipeline|
+ pipeline.click_job('install')
+ end
+
+ Page::Project::Job::Show.perform do |job|
+ expect(job).to be_successful(timeout: 800)
+ job.click_browse_button
+ end
+
+ Page::Project::Artifact::Show.perform do |artifacts|
+ artifacts.go_to_directory('node_modules')
+ artifacts.go_to_directory("@#{registry_scope}")
+ expect(artifacts).to have_content(project.name.to_s)
+ end
+
+ project.visit!
+ Page::Project::Menu.perform(&:go_to_package_registry)
+
+ Page::Project::Packages::Index.perform do |index|
+ expect(index).to have_package(package.name)
+
+ index.click_package(package.name)
+ end
+
+ Page::Project::Packages::Show.perform do |show|
+ expect(show).to have_package_info(package.name, "1.0.0")
+ end
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/qa/qa/specs/features/browser_ui/5_package/package_registry/npm/npm_instance_level_spec.rb b/qa/qa/specs/features/browser_ui/5_package/package_registry/npm/npm_instance_level_spec.rb
index 4a8b95717d0..b0702b3f089 100644
--- a/qa/qa/specs/features/browser_ui/5_package/package_registry/npm/npm_instance_level_spec.rb
+++ b/qa/qa/specs/features/browser_ui/5_package/package_registry/npm/npm_instance_level_spec.rb
@@ -2,7 +2,7 @@
module QA
RSpec.describe 'Package' do
- describe 'Package Registry', :skip_live_env, :orchestrated, :reliable, :packages, :object_storage, product_group: :package_registry do
+ describe 'Package Registry', :object_storage, except: { job: 'relative-url' }, product_group: :package_registry do
describe 'npm instance level endpoint' do
using RSpec::Parameterized::TableSyntax
include Runtime::Fixtures
@@ -90,7 +90,7 @@ module QA
it 'push and pull a npm package via CI', testcase: params[:testcase] do
Support::Retrier.retry_on_exception(max_attempts: 3, sleep_interval: 2) do
npm_upload_yaml = ERB.new(read_fixture('package_managers/npm', 'npm_upload_package_instance.yaml.erb')).result(binding)
- package_json = ERB.new(read_fixture('package_managers/npm', 'package_instance.json.erb')).result(binding)
+ package_json = ERB.new(read_fixture('package_managers/npm', 'package.json.erb')).result(binding)
Resource::Repository::Commit.fabricate_via_api! do |commit|
commit.project = project
diff --git a/qa/qa/specs/features/browser_ui/5_package/package_registry/npm/npm_project_level_spec.rb b/qa/qa/specs/features/browser_ui/5_package/package_registry/npm/npm_project_level_spec.rb
index e913df0957d..1eed68d1b88 100644
--- a/qa/qa/specs/features/browser_ui/5_package/package_registry/npm/npm_project_level_spec.rb
+++ b/qa/qa/specs/features/browser_ui/5_package/package_registry/npm/npm_project_level_spec.rb
@@ -2,7 +2,7 @@
module QA
RSpec.describe 'Package' do
- describe 'Package Registry', :skip_live_env, :orchestrated, :reliable, :packages, :object_storage, product_group: :package_registry do
+ describe 'Package Registry', :object_storage, except: { job: 'relative-url' }, product_group: :package_registry do
describe 'npm project level endpoint' do
using RSpec::Parameterized::TableSyntax
include Runtime::Fixtures
@@ -81,7 +81,7 @@ module QA
it 'push and pull a npm package via CI', testcase: params[:testcase] do
Resource::Repository::Commit.fabricate_via_api! do |commit|
npm_upload_install_yaml = ERB.new(read_fixture('package_managers/npm', 'npm_upload_install_package_project.yaml.erb')).result(binding)
- package_json = ERB.new(read_fixture('package_managers/npm', 'package_project.json.erb')).result(binding)
+ package_json = ERB.new(read_fixture('package_managers/npm', 'package.json.erb')).result(binding)
commit.project = project
commit.commit_message = 'Add .gitlab-ci.yml'
diff --git a/qa/qa/specs/features/browser_ui/5_package/package_registry/nuget/nuget_group_level_spec.rb b/qa/qa/specs/features/browser_ui/5_package/package_registry/nuget/nuget_group_level_spec.rb
index 48b9fdec2e9..5413ae85dcd 100644
--- a/qa/qa/specs/features/browser_ui/5_package/package_registry/nuget/nuget_group_level_spec.rb
+++ b/qa/qa/specs/features/browser_ui/5_package/package_registry/nuget/nuget_group_level_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module QA
- RSpec.describe 'Package', :skip_live_env, :orchestrated, :packages, :object_storage, :reliable, product_group: :package_registry do
+ RSpec.describe 'Package', :object_storage, except: { job: 'relative-url' }, product_group: :package_registry do
describe 'NuGet group level endpoint' do
using RSpec::Parameterized::TableSyntax
include Runtime::Fixtures
diff --git a/qa/qa/specs/features/browser_ui/5_package/package_registry/nuget/nuget_project_level_spec.rb b/qa/qa/specs/features/browser_ui/5_package/package_registry/nuget/nuget_project_level_spec.rb
index ad5835d8c9d..9a192bc005f 100644
--- a/qa/qa/specs/features/browser_ui/5_package/package_registry/nuget/nuget_project_level_spec.rb
+++ b/qa/qa/specs/features/browser_ui/5_package/package_registry/nuget/nuget_project_level_spec.rb
@@ -1,8 +1,7 @@
# frozen_string_literal: true
module QA
- RSpec.describe 'Package', :skip_live_env, :orchestrated, :packages, :object_storage,
-product_group: :package_registry do
+ RSpec.describe 'Package', :object_storage, except: { job: 'relative-url' }, product_group: :package_registry do
describe 'NuGet project level endpoint' do
include Support::Helpers::MaskToken
diff --git a/qa/qa/specs/features/browser_ui/5_package/package_registry/pypi_repository_spec.rb b/qa/qa/specs/features/browser_ui/5_package/package_registry/pypi_repository_spec.rb
index 4e072412bd4..63549113517 100644
--- a/qa/qa/specs/features/browser_ui/5_package/package_registry/pypi_repository_spec.rb
+++ b/qa/qa/specs/features/browser_ui/5_package/package_registry/pypi_repository_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module QA
- RSpec.describe 'Package', :skip_live_env, :orchestrated, :packages, :object_storage, product_group: :package_registry do
+ RSpec.describe 'Package', :object_storage, except: { job: 'relative-url' }, product_group: :package_registry do
describe 'PyPI Repository' do
include Runtime::Fixtures
include Support::Helpers::MaskToken
diff --git a/qa/qa/specs/features/browser_ui/5_package/package_registry/rubygems_registry_spec.rb b/qa/qa/specs/features/browser_ui/5_package/package_registry/rubygems_registry_spec.rb
index 1af1fc7c231..0c58d41d96e 100644
--- a/qa/qa/specs/features/browser_ui/5_package/package_registry/rubygems_registry_spec.rb
+++ b/qa/qa/specs/features/browser_ui/5_package/package_registry/rubygems_registry_spec.rb
@@ -1,8 +1,8 @@
# frozen_string_literal: true
module QA
- RSpec.describe 'Package', :orchestrated, :packages, :object_storage,
- feature_flag: { name: 'rubygem_packages', scope: :project } do
+ RSpec.describe 'Package', :object_storage, except: { job: 'relative-url' },
+ feature_flag: { name: 'rubygem_packages', scope: :project } do
describe 'RubyGems Repository', product_group: :package_registry do
include Runtime::Fixtures
diff --git a/qa/qa/specs/helpers/context_selector.rb b/qa/qa/specs/helpers/context_selector.rb
index ab8e9bc3639..88b3efb84cb 100644
--- a/qa/qa/specs/helpers/context_selector.rb
+++ b/qa/qa/specs/helpers/context_selector.rb
@@ -101,7 +101,13 @@ module QA
end
def pipeline_from_project_name(project_name)
- project_name.to_s.start_with?('gitlab-qa') ? Runtime::Env.default_branch : project_name
+ if project_name.to_s.start_with?('gitlab-qa')
+ Runtime::Env.default_branch
+ elsif project_name.to_s == 'gitlab' && Runtime::Env.schedule_type == 'nightly'
+ 'nightly'
+ else
+ project_name
+ end
end
# Get production domain value based on GitLab edition and URI's top level domain
diff --git a/qa/qa/specs/spec_helper.rb b/qa/qa/specs/spec_helper.rb
index aa274a4e101..1601dd46c62 100644
--- a/qa/qa/specs/spec_helper.rb
+++ b/qa/qa/specs/spec_helper.rb
@@ -12,6 +12,7 @@ QA::Runtime::Browser.configure! unless QA::Runtime::Env.dry_run
QA::Runtime::AllureReport.configure!
QA::Runtime::Scenario.from_env(QA::Runtime::Env.runtime_scenario_attributes)
QA::Support::KnapsackReport.configure!
+QA::Service::DockerRun::Video.configure!
# Enable zero monkey patching mode before loading any other RSpec code.
RSpec.configure(&:disable_monkey_patching!)
diff --git a/qa/qa/support/helpers/zuora.rb b/qa/qa/support/helpers/zuora.rb
new file mode 100644
index 00000000000..0f75d9bb1e6
--- /dev/null
+++ b/qa/qa/support/helpers/zuora.rb
@@ -0,0 +1,11 @@
+# frozen_string_literal: true
+
+module QA
+ module Support
+ module Helpers
+ module Zuora
+ ZUORA_TIMEOUT = 60
+ end
+ end
+ end
+end
diff --git a/qa/qa/support/knapsack_report.rb b/qa/qa/support/knapsack_report.rb
index 27d8b144f3b..d7bf8b76924 100644
--- a/qa/qa/support/knapsack_report.rb
+++ b/qa/qa/support/knapsack_report.rb
@@ -46,6 +46,28 @@ module QA
logger.warn("Falling back to '#{FALLBACK_REPORT}'")
end
+ # Create a copy of the report that contains the selective tests and has '-selective' suffix
+ #
+ # @param [String] qa_tests
+ # @return [void]
+ def create_for_selective(qa_tests)
+ timed_specs = JSON.parse(File.read(report_path))
+
+ qa_tests_array = qa_tests.split(' ')
+ filtered_timed_specs = timed_specs.select { |k, _| qa_tests_array.any? { |qa_test| k.include? qa_test } }
+ File.write(selective_path, filtered_timed_specs.to_json)
+ end
+
+ # Add '-selective-parallel' suffix to report name
+ #
+ # @return [String]
+ def selective_path
+ extension = File.extname(report_path)
+ directory = File.dirname(report_path)
+ file_name = File.basename(report_path, extension)
+ File.join(directory, "#{file_name}-selective-parallel#{extension}")
+ end
+
# Rename and move new regenerated report to a separate folder used to indicate report name
#
# @return [void]
diff --git a/qa/qa/support/wait_for_requests.rb b/qa/qa/support/wait_for_requests.rb
index 2856602629a..ef7875eb838 100644
--- a/qa/qa/support/wait_for_requests.rb
+++ b/qa/qa/support/wait_for_requests.rb
@@ -39,6 +39,12 @@ module QA
Capybara.page.has_no_css?('.gl-spinner', wait: wait)
end
end
+
+ def wait_for_gitlab_to_respond
+ Waiter.wait_until(sleep_interval: 5, message: '502 - GitLab is taking too much time to respond') do
+ Capybara.page.has_no_text?('GitLab is taking too much time to respond')
+ end
+ end
end
end
end
diff --git a/qa/qa/tools/migrate_influx_data_to_gcs.rb b/qa/qa/tools/migrate_influx_data_to_gcs.rb
new file mode 100644
index 00000000000..4933251511b
--- /dev/null
+++ b/qa/qa/tools/migrate_influx_data_to_gcs.rb
@@ -0,0 +1,124 @@
+# frozen_string_literal: true
+
+require 'csv'
+require "fog/google"
+
+module QA
+ module Tools
+ class MigrateInfluxDataToGcs
+ include Support::InfluxdbTools
+
+ # Google Cloud Storage bucket from which Snowpipe would pull data into Snowflake
+ QA_GCS_BUCKET_NAME = ENV["QA_GCS_BUCKET_NAME"] || raise("Missing QA_GCS_BUCKET_NAME env variable")
+ QA_GCS_PROJECT_ID = ENV["QA_GCS_PROJECT_ID"] || raise("Missing QA_GCS_PROJECT_ID env variable")
+ QA_GCS_JSON_KEY_FILE = ENV["QA_GCS_JSON_KEY_FILE"] || raise("Missing QA_GCS_JSON_KEY_FILE env variable")
+ INFLUX_STATS_TYPE = %w[test-stats fabrication-stats].freeze
+ INFLUX_BUCKETS = [Support::InfluxdbTools::INFLUX_TEST_METRICS_BUCKET,
+ Support::InfluxdbTools::INFLUX_MAIN_TEST_METRICS_BUCKET].freeze
+ TEST_STATS_FIELDS = %w[id testcase file_path name product_group stage job_id job_name
+ job_url pipeline_id pipeline_url merge_request merge_request_iid smoke reliable quarantined
+ retried retry_attempts run_time run_type status ui_fabrication api_fabrication total_fabrication].freeze
+ FABRICATION_STATS_FIELDS = %w[timestamp resource fabrication_method http_method run_type
+ merge_request fabrication_time info job_url].freeze
+
+ def initialize(range)
+ @range = range.to_i
+ end
+
+ # Run Influx Migrator
+ # @param [Integer] the last x hours for which data is required
+ # @return [void]
+ def self.run(range: 1)
+ migrator = new(range)
+
+ QA::Runtime::Logger.info("Fetching Influx data for the last #{range} hours")
+ migrator.migrate_data
+ end
+
+ # Fetch data from Influx DB , store as CSV and upload to GCS
+ # @return [void]
+ def migrate_data
+ INFLUX_BUCKETS.each do |bucket|
+ INFLUX_STATS_TYPE.each do |stats_type|
+ if bucket == Support::InfluxdbTools::INFLUX_MAIN_TEST_METRICS_BUCKET && stats_type == "fabrication-stats"
+ break
+ end
+
+ file_name = "#{bucket.end_with?('main') ? 'main' : 'all'}-#{stats_type}_#{Time.now.to_i}.csv"
+ influx_to_csv(bucket, stats_type, file_name)
+
+ # Upload to Google Cloud Storage
+ upload_to_gcs(QA_GCS_BUCKET_NAME, file_name)
+ end
+ end
+ end
+
+ private
+
+ # FluxQL query used to fetch data
+ # @param [String] influx bucket to fetch data
+ # @param [String] Type of data to fetch
+ # @return [String] query string
+ def query(influx_bucket, stats_type)
+ <<~QUERY
+ from(bucket: "#{influx_bucket}")
+ |> range(start: -#{@range}h)
+ |> filter(fn: (r) => r["_measurement"] == "#{stats_type}")
+ |> pivot(rowKey:["_time"], columnKey: ["_field"], valueColumn: "_value")
+ |> drop(columns: ["_start", "_stop", "result", "table", "_time", "_measurement"])
+ QUERY
+ end
+
+ # Query InfluxDB and store in CSV
+ # @param [String] influx bucket to fetch data
+ # @param [String] Type of data to fetch
+ # @param [String] CSV filename to store data
+ # @return void
+ def influx_to_csv(influx_bucket, stats_type, data_file_name)
+ all_runs = query_api.query(query: query(influx_bucket, stats_type))
+ CSV.open(data_file_name, "wb") do |csv|
+ stats_array = stats_type == "test-stats" ? TEST_STATS_FIELDS : FABRICATION_STATS_FIELDS
+ csv << stats_array.flatten
+ all_runs.each do |table|
+ table.records.each do |record|
+ csv << stats_array.map { |key| record.values[key] }
+ end
+ end
+ QA::Runtime::Logger.info("File #{data_file_name} contains #{all_runs.count} rows")
+ end
+ end
+
+ # Fetch GCS Credentials
+ # @return [Hash] GCS Credentials
+ def gcs_credentials
+ json_key = ENV["QA_GCS_JSON_KEY_FILE"] || raise(
+ "QA_GCS_JSON_KEY_FILE env variable is required!"
+ )
+ return { google_json_key_location: json_key } if File.exist?(json_key)
+
+ { google_json_key_string: json_key }
+ end
+
+ # Upload file to GCS
+ # @param [String] bucket to be uploaded to
+ # @param [String] path of file to be uploaded
+ # return void
+ def upload_to_gcs(bucket, backup_file_path)
+ client = Fog::Storage::Google.new(google_project: QA_GCS_PROJECT_ID, **gcs_credentials)
+ file_path = backup_file_path.tr('_0-9', '')
+
+ # Backup older file
+ begin
+ QA::Runtime::Logger.info("Backing up older file to #{backup_file_path}")
+ client.copy_object(bucket, file_path, bucket, backup_file_path)
+ rescue Google::Apis::ClientError
+ QA::Runtime::Logger.warn("File #{file_path} is not found in GCS bucket, continuing with upload...")
+ end
+
+ # Upload new file
+ file = client.put_object(bucket, file_path, File.new(backup_file_path, "r"), force: true)
+ QA::Runtime::Logger.info("File #{file_path} uploaded to gs://#{bucket}/#{file.name}")
+ end
+ end
+ end
+end
diff --git a/qa/qa/tools/test_resources_handler.rb b/qa/qa/tools/test_resources_handler.rb
index 7f4b8f78618..fd76cc3d1a8 100644
--- a/qa/qa/tools/test_resources_handler.rb
+++ b/qa/qa/tools/test_resources_handler.rb
@@ -93,17 +93,18 @@ module QA
# Download files from GCS bucket by environment name
# Delete the files afterward
def download(ci_project_name)
- bucket_items = gcs_storage.list_objects(BUCKET, prefix: ci_project_name).items
+ logger.info("Downloading resource files from GCS for #{ci_project_name}...")
+ bucket_items = gcs_storage.list_objects(BUCKET, prefix: "#{ci_project_name}/").items
- files_list = bucket_items&.each_with_object([]) do |obj, arr|
- arr << obj.name
- end
-
- if files_list.blank?
+ if bucket_items.blank?
logger.info("\nNothing to download!")
return
end
+ files_list = bucket_items.each_with_object([]) do |obj, arr|
+ arr << obj.name
+ end
+
FileUtils.mkdir_p('tmp/')
files_list.each do |file_name|
@@ -217,11 +218,10 @@ module QA
def api_client
abort("\nPlease provide GITLAB_ADDRESS") unless ENV['GITLAB_ADDRESS']
- abort("\nPlease provide GITLAB_QA_ACCESS_TOKEN") unless ENV['GITLAB_QA_ACCESS_TOKEN']
@api_client ||= Runtime::API::Client.new(
ENV['GITLAB_ADDRESS'],
- personal_access_token: ENV['GITLAB_QA_ACCESS_TOKEN']
+ personal_access_token: personal_access_token
)
end
@@ -243,6 +243,17 @@ module QA
@json_key ||= ENV["QA_FAILED_TEST_RESOURCES_GCS_CREDENTIALS"]
end
+
+ # In environments that we can run tests with admin scope,
+ # we should use GITLAB_QA_ADMIN_ACCESS_TOKEN to clean up resources.
+ # This is necessary for cleaning up User resources.
+ def personal_access_token
+ if ENV['GITLAB_QA_ADMIN_ACCESS_TOKEN'].blank? && ENV['GITLAB_QA_ACCESS_TOKEN'].blank?
+ abort("\nPlease provide either GITLAB_QA_ADMIN_ACCESS_TOKEN or GITLAB_QA_ACCESS_TOKEN")
+ end
+
+ @personal_access_token ||= ENV['GITLAB_QA_ADMIN_ACCESS_TOKEN'] || ENV['GITLAB_QA_ACCESS_TOKEN']
+ end
end
end
end
diff --git a/qa/qa/vendor/jira/jira_api.rb b/qa/qa/vendor/jira/jira_api.rb
index 15039ac244e..4248ee589b5 100644
--- a/qa/qa/vendor/jira/jira_api.rb
+++ b/qa/qa/vendor/jira/jira_api.rb
@@ -21,9 +21,11 @@ module QA
end
def fetch_issue(issue_key)
- response = get("#{api_url}/issue/#{issue_key}",
- user: Runtime::Env.jira_admin_username,
- password: Runtime::Env.jira_admin_password)
+ response = get(
+ "#{api_url}/issue/#{issue_key}",
+ user: Runtime::Env.jira_admin_username,
+ password: Runtime::Env.jira_admin_password
+ )
parse_body(response)
end
diff --git a/qa/spec/fixtures/knapsack_report/instance-selective-parallel.json b/qa/spec/fixtures/knapsack_report/instance-selective-parallel.json
new file mode 100644
index 00000000000..adf506c9d30
--- /dev/null
+++ b/qa/spec/fixtures/knapsack_report/instance-selective-parallel.json
@@ -0,0 +1,5 @@
+{
+ "qa/specs/features/ee/browser_ui/3_create/repository/code_owners_with_protected_branch_and_squashed_commits_spec.rb": 18.85673829499956,
+ "qa/specs/features/api/3_create/repository/files_spec.rb": 3.180753622999873,
+ "qa/specs/features/browser_ui/3_create/web_ide_old/server_hooks_custom_error_message_spec.rb": 0.010764157999801682
+}
diff --git a/qa/spec/fixtures/knapsack_report/instance.json b/qa/spec/fixtures/knapsack_report/instance.json
new file mode 100644
index 00000000000..3d659bc53fb
--- /dev/null
+++ b/qa/spec/fixtures/knapsack_report/instance.json
@@ -0,0 +1,7 @@
+{
+ "qa/specs/features/ee/browser_ui/3_create/repository/code_owners_with_protected_branch_and_squashed_commits_spec.rb": 18.85673829499956,
+ "qa/specs/features/api/3_create/repository/files_spec.rb": 3.180753622999873,
+ "qa/specs/features/browser_ui/3_create/web_ide_old/server_hooks_custom_error_message_spec.rb": 0.010764157999801682,
+ "qa/specs/features/api/9_data_stores/users_spec.rb": 0.2808277129997805,
+ "qa/specs/features/api/2_plan/closes_issue_via_pushing_a_commit_spec.rb": 4.882168451000325
+}
diff --git a/qa/spec/page/element_spec.rb b/qa/spec/page/element_spec.rb
index fbf58b5e18a..da1fd224564 100644
--- a/qa/spec/page/element_spec.rb
+++ b/qa/spec/page/element_spec.rb
@@ -73,7 +73,7 @@ RSpec.describe QA::Page::Element do
subject { described_class.new(:something, /link_to 'something'/) }
it 'has an attribute[pattern] of the pattern' do
- expect(subject.attributes[:pattern]).to eq /link_to 'something'/
+ expect(subject.attributes[:pattern]).to eq(/link_to 'something'/)
end
it 'is not required by default' do
@@ -98,7 +98,7 @@ RSpec.describe QA::Page::Element do
subject { described_class.new(:something, /link_to 'something_else_entirely'/, required: true) }
it 'has an attribute[pattern] of the passed pattern' do
- expect(subject.attributes[:pattern]).to eq /link_to 'something_else_entirely'/
+ expect(subject.attributes[:pattern]).to eq(/link_to 'something_else_entirely'/)
end
it 'is required' do
@@ -118,6 +118,10 @@ RSpec.describe QA::Page::Element do
expect(subject.selector_css).to include(%q([data-qa-selector="my_element"]))
end
+ it 'properly translates to a data-testid' do
+ expect(subject.selector_css).to include(%q([data-testid="my_element"]))
+ end
+
context 'additional selectors' do
let(:element) { described_class.new(:my_element, index: 3, another_match: 'something') }
let(:required_element) { described_class.new(:my_element, required: true, index: 3) }
diff --git a/qa/spec/resource/base_spec.rb b/qa/spec/resource/base_spec.rb
index e0bfccf5e78..d7e16c1f84b 100644
--- a/qa/spec/resource/base_spec.rb
+++ b/qa/spec/resource/base_spec.rb
@@ -362,7 +362,8 @@ RSpec.describe QA::Resource::Base do
it 'calls #visit with the underlying #web_url' do
allow(resource).to receive(:current_url).and_return(subject.current_url)
- expect(wait_for_requests_class).to receive(:wait_for_requests).with({ skip_resp_code_check: false }).twice
+ expect(wait_for_requests_class).to receive(:wait_for_requests).with({ skip_finished_loading_check: false,
+ skip_resp_code_check: false }).twice
resource.web_url = subject.current_url
resource.visit!
@@ -372,12 +373,24 @@ RSpec.describe QA::Resource::Base do
it 'calls #visit with the underlying #web_url with skip_resp_code_check specified as true' do
allow(resource).to receive(:current_url).and_return(subject.current_url)
- expect(wait_for_requests_class).to receive(:wait_for_requests).with({ skip_resp_code_check: true }).twice
+ expect(wait_for_requests_class).to receive(:wait_for_requests).with({ skip_finished_loading_check: false,
+ skip_resp_code_check: true }).twice
resource.web_url = subject.current_url
resource.visit!(skip_resp_code_check: true)
expect(resource).to have_received(:visit).with(subject.current_url)
end
+
+ it 'calls #visit with the underlying #web_url with skip_finished_loading_check specified as true' do
+ allow(resource).to receive(:current_url).and_return(subject.current_url)
+ expect(wait_for_requests_class).to receive(:wait_for_requests).with({ skip_finished_loading_check: true,
+ skip_resp_code_check: false }).twice
+
+ resource.web_url = subject.current_url
+ resource.visit!(skip_finished_loading_check: true)
+
+ expect(resource).to have_received(:visit).with(subject.current_url)
+ end
end
end
diff --git a/qa/spec/service/docker_run/video_spec.rb b/qa/spec/service/docker_run/video_spec.rb
new file mode 100644
index 00000000000..81be5ccffae
--- /dev/null
+++ b/qa/spec/service/docker_run/video_spec.rb
@@ -0,0 +1,181 @@
+# frozen_string_literal: true
+
+module QA
+ RSpec.describe Service::DockerRun::Video do
+ include QA::Support::Helpers::StubEnv
+
+ let(:rspec_config) { instance_double('RSpec::Core::Configuration', append_after: nil, prepend_before: nil) }
+ let(:video_recorder_image) { 'presidenten/selenoid-manual-video-recorder' }
+ let(:video_recorder_version) { 'latest' }
+ let(:selenoid_browser_image) { 'selenoid/chrome' }
+ let(:selenoid_browser_version) { '111.0' }
+ let(:remote_grid) { 'selenoid:4444' }
+ let(:record_video) { 'true' }
+ let(:use_selenoid) { 'true' }
+ let(:docs_link) do
+ 'https://gitlab.com/gitlab-org/gitlab-qa/-/blob/master/docs/running_against_remote_grid.md#testing-with-selenoid'
+ end
+
+ shared_examples 'video set up fails' do
+ it 'does not perform configuration' do
+ aggregate_failures do
+ expect(QA::Runtime::Logger).to have_received(:warn)
+ .with(/Test failure video recording setup failed!/)
+
+ expect(RSpec).not_to have_received(:configure)
+ end
+ end
+ end
+
+ shared_examples 'video set up missing variable' do |missing_variable|
+ let(:failure_message) do
+ <<~FAIL.tr("\n", ' ').strip
+ Aborting video recording setup!
+ Missing variables: #{missing_variable} is required!
+ See docs: #{docs_link}
+ FAIL
+ end
+
+ it 'aborts video setup with warning' do
+ aggregate_failures do
+ expect(QA::Runtime::Logger).to have_received(:warn)
+ .with(failure_message)
+
+ expect(described_class).not_to have_received(:get_container_name)
+ expect(RSpec).not_to have_received(:configure)
+ end
+ end
+ end
+
+ before do
+ stub_env('QA_VIDEO_RECORDER_IMAGE', video_recorder_image)
+ stub_env('QA_VIDEO_RECORDER_VERSION', video_recorder_version)
+ stub_env('QA_SELENOID_BROWSER_IMAGE', selenoid_browser_image)
+ stub_env('QA_SELENOID_BROWSER_VERSION', selenoid_browser_version)
+ stub_env('QA_REMOTE_GRID', remote_grid)
+ stub_env('USE_SELENOID', use_selenoid)
+ stub_env('QA_RECORD_VIDEO', record_video)
+
+ allow(RSpec).to receive(:configure).and_yield(rspec_config)
+ allow(described_class).to receive(:get_container_name)
+ allow(described_class).to receive(:shell)
+ allow(QA::Runtime::Logger).to receive(:warn)
+ allow(QA::Runtime::Logger).to receive(:info)
+ end
+
+ context 'with video disabled' do
+ let(:record_video) { 'false' }
+
+ before do
+ described_class.configure!
+ end
+
+ it 'skips configuration' do
+ aggregate_failures do
+ expect(described_class).not_to have_received(:get_container_name)
+ expect(described_class).not_to have_received(:shell)
+ expect(RSpec).not_to have_received(:configure)
+ end
+ end
+ end
+
+ context 'with use_selenoid disabled' do
+ let(:use_selenoid) { 'false' }
+
+ before do
+ described_class.configure!
+ end
+
+ it_behaves_like 'video set up missing variable', 'USE_SELENOID'
+ end
+
+ context 'without video_recorder_image set' do
+ let(:video_recorder_image) { nil }
+
+ before do
+ described_class.configure!
+ end
+
+ it_behaves_like 'video set up missing variable', 'QA_VIDEO_RECORDER_IMAGE'
+ end
+
+ context 'without selenoid_browser_image set' do
+ let(:selenoid_browser_image) { nil }
+
+ before do
+ described_class.configure!
+ end
+
+ it_behaves_like 'video set up missing variable', 'QA_SELENOID_BROWSER_IMAGE'
+ end
+
+ context 'without selenoid_browser_version set' do
+ let(:selenoid_browser_version) { nil }
+
+ before do
+ described_class.configure!
+ end
+
+ it_behaves_like 'video set up missing variable', 'QA_SELENOID_BROWSER_VERSION'
+ end
+
+ context 'without browser_container_hostname' do
+ before do
+ allow(described_class).to receive(:get_container_name)
+ .with(video_recorder_image)
+ .and_return('recorder_container_name')
+ allow(described_class).to receive(:get_container_name)
+ .with("#{selenoid_browser_image}:#{selenoid_browser_version}")
+ .and_return('browser_image_hostname')
+ allow(described_class).to receive(:shell)
+ .and_return(false)
+
+ described_class.configure!
+ end
+
+ it_behaves_like 'video set up fails'
+ end
+
+ context 'without recorder_container_name' do
+ before do
+ allow(described_class).to receive(:get_container_name)
+ .with(video_recorder_image)
+ .and_return('')
+ allow(described_class).to receive(:get_container_name)
+ .with("#{selenoid_browser_image}:#{selenoid_browser_version}")
+ .and_return('browser_image_hostname')
+ allow(described_class).to receive(:shell)
+ .and_return('browser_container_hostname')
+
+ described_class.configure!
+ end
+
+ it_behaves_like 'video set up fails'
+ end
+
+ context 'with recorder_container_name and browser_container_hostname' do
+ before do
+ allow(described_class).to receive(:get_container_name)
+ .with(video_recorder_image)
+ .and_return('recorder_container_name')
+ allow(described_class).to receive(:get_container_name)
+ .with("#{selenoid_browser_image}:#{selenoid_browser_version}")
+ .and_return('browser_image_hostname')
+ allow(described_class).to receive(:shell)
+ .and_return('browser_container_hostname')
+
+ described_class.configure!
+ end
+
+ it 'performs configuration' do
+ aggregate_failures do
+ expect(QA::Runtime::Logger).to have_received(:info)
+ .with(/Test failure video recording setup complete!/)
+ expect(RSpec).to have_received(:configure)
+ expect(rspec_config).to have_received(:prepend_before)
+ expect(rspec_config).to have_received(:append_after)
+ end
+ end
+ end
+ end
+end
diff --git a/qa/spec/specs/helpers/context_selector_spec.rb b/qa/spec/specs/helpers/context_selector_spec.rb
index f6134cc6177..3550e78d9e3 100644
--- a/qa/spec/specs/helpers/context_selector_spec.rb
+++ b/qa/spec/specs/helpers/context_selector_spec.rb
@@ -535,6 +535,47 @@ RSpec.describe QA::Specs::Helpers::ContextSelector do
end
end
end
+
+ context 'with CI_PROJECT_NAME set to gitlab and SCHEDULE_TYPE set to nightly' do
+ before do
+ stub_env('CI_PROJECT_NAME', 'gitlab')
+ stub_env('SCHEDULE_TYPE', 'nightly')
+ end
+
+ it 'runs on designated pipeline' do
+ group = describe_successfully do
+ it('runs on nightly', only: { pipeline: :nightly }) {}
+ it('does not run in not_nightly', only: { pipeline: :not_nightly }) {}
+ it('runs on nightly given an array', only: { pipeline: [:canary, :nightly] }) {}
+ it('does not run in not_nightly given an array', only: { pipeline: [:not_nightly, :canary] }) {}
+ end
+
+ aggregate_failures do
+ expect(group.examples[0].execution_result.status).to eq(:passed)
+ expect(group.examples[1].execution_result.status).to eq(:pending)
+ expect(group.examples[2].execution_result.status).to eq(:passed)
+ expect(group.examples[3].execution_result.status).to eq(:pending)
+ end
+ end
+
+ context 'when excluding contexts' do
+ it 'skips designated pipeline' do
+ group = describe_successfully do
+ it('skips nightly', except: { pipeline: :nightly }) {}
+ it('runs in not_nightly', except: { pipeline: :not_nightly }) {}
+ it('skips on nightly given an array', except: { pipeline: [:canary, :nightly] }) {}
+ it('runs in not_nightly given an array', except: { pipeline: [:not_nightly, :canary] }) {}
+ end
+
+ aggregate_failures do
+ expect(group.examples[0].execution_result.status).to eq(:pending)
+ expect(group.examples[1].execution_result.status).to eq(:passed)
+ expect(group.examples[2].execution_result.status).to eq(:pending)
+ expect(group.examples[3].execution_result.status).to eq(:passed)
+ end
+ end
+ end
+ end
end
context 'with job constraints' do
diff --git a/qa/spec/support/knapsack_report_spec.rb b/qa/spec/support/knapsack_report_spec.rb
new file mode 100644
index 00000000000..914a30513e5
--- /dev/null
+++ b/qa/spec/support/knapsack_report_spec.rb
@@ -0,0 +1,39 @@
+# frozen_string_literal: true
+
+RSpec.describe QA::Support::KnapsackReport do
+ subject(:knapsack_report) { described_class.new('instance') }
+
+ describe '#create_for_selective' do
+ let(:qa_tests) do
+ <<~CMD
+ qa/specs/features/api/3_create
+ qa/specs/features/browser_ui/3_create/
+ qa/specs/features/ee/api/3_create/
+ qa/specs/features/ee/browser_ui/3_create/
+ CMD
+ end
+
+ let(:fixtures_path) { 'spec/fixtures/knapsack_report' }
+ let(:expected_output) { JSON.parse(File.read(File.join(fixtures_path, 'instance-selective-parallel.json'))) }
+
+ before do
+ allow(File).to receive(:read).and_call_original
+ allow(File).to receive(:read)
+ .with('knapsack/instance.json')
+ .and_return(File.read(File.join(fixtures_path, 'instance.json')))
+ end
+
+ it 'creates a filtered file based on qa_tests' do
+ expect(File).to receive(:write)
+ .with('knapsack/instance-selective-parallel.json', expected_output.to_json)
+
+ knapsack_report.create_for_selective(qa_tests)
+ end
+ end
+
+ describe '#selective_path' do
+ it 'returns the path with file name suffixed with -selective-parallel' do
+ expect(knapsack_report.selective_path).to eq('knapsack/instance-selective-parallel.json')
+ end
+ end
+end
diff --git a/qa/spec/support/loglinking_spec.rb b/qa/spec/support/loglinking_spec.rb
index 79004630253..2bea528028f 100644
--- a/qa/spec/support/loglinking_spec.rb
+++ b/qa/spec/support/loglinking_spec.rb
@@ -26,8 +26,11 @@ RSpec.describe QA::Support::Loglinking do
context 'and both Sentry and Kibana exist for the logging environment' do
let(:sentry) { instance_double(QA::Support::SystemLogs::Sentry, url: sentry_url) }
let(:kibana) do
- instance_double(QA::Support::SystemLogs::Kibana,
- discover_url: discover_url, dashboard_url: dashboard_url)
+ instance_double(
+ QA::Support::SystemLogs::Kibana,
+ discover_url: discover_url,
+ dashboard_url: dashboard_url
+ )
end
it 'returns both Sentry and Kibana URLs' do
@@ -43,8 +46,11 @@ RSpec.describe QA::Support::Loglinking do
context 'and only Sentry exists for the logging environment' do
let(:sentry) { instance_double(QA::Support::SystemLogs::Sentry, url: sentry_url) }
let(:kibana) do
- instance_double(QA::Support::SystemLogs::Kibana,
- discover_url: nil, dashboard_url: nil)
+ instance_double(
+ QA::Support::SystemLogs::Kibana,
+ discover_url: nil,
+ dashboard_url: nil
+ )
end
it 'returns only Sentry URL' do
@@ -58,8 +64,11 @@ RSpec.describe QA::Support::Loglinking do
context 'and only Kibana exists for the logging environment' do
let(:sentry) { instance_double(QA::Support::SystemLogs::Sentry, url: nil) }
let(:kibana) do
- instance_double(QA::Support::SystemLogs::Kibana,
- discover_url: discover_url, dashboard_url: dashboard_url)
+ instance_double(
+ QA::Support::SystemLogs::Kibana,
+ discover_url: discover_url,
+ dashboard_url: dashboard_url
+ )
end
it 'returns only Kibana Discover and Dashboard URLs' do
diff --git a/qa/tasks/ci.rake b/qa/tasks/ci.rake
index e5f4acb158b..3dfad6a82fd 100644
--- a/qa/tasks/ci.rake
+++ b/qa/tasks/ci.rake
@@ -30,6 +30,18 @@ namespace :ci do
# on run-all label of framework changes do not infer specific tests
tests = run_all_label_present || qa_changes.framework_changes? ? nil : qa_changes.qa_tests
+ # When QA_TESTS only contain folders and no specific specs, populate KNAPSACK_TEST_FILE_PATTERN
+ if tests && tests.split(' ').none? { |item| item.include?('_spec') }
+ test_paths = tests.split(' ').map { |item| "#{item}**/*" }
+
+ files_pattern = "{#{test_paths.join(',')}}"
+
+ logger.info(" Files pattern for tests: #{files_pattern}")
+ append_to_file(env_file, <<~TXT)
+ KNAPSACK_TEST_FILE_PATTERN='#{files_pattern}'
+ TXT
+ end
+
if run_all_label_present
logger.info(" merge request has pipeline:run-all-e2e label, full test suite will be executed")
append_to_file(env_file, "QA_RUN_ALL_E2E_LABEL=true\n")
diff --git a/qa/tasks/knapsack.rake b/qa/tasks/knapsack.rake
index 5e60703ced3..b8a8d6e1145 100644
--- a/qa/tasks/knapsack.rake
+++ b/qa/tasks/knapsack.rake
@@ -42,6 +42,19 @@ namespace :knapsack do
end
end
+ desc "Create knapsack reports from existing reports for selective jobs"
+ task :create_reports_for_selective do
+ reports = Dir.glob("knapsack/*").map { |file| file.match(%r{.*/(.*)?\.json})[1] }
+
+ reports.each do |report_name|
+ unless report_name.include?('-selective-parallel')
+ QA::Support::KnapsackReport.new(report_name).create_for_selective(ENV['QA_TESTS'])
+ end
+ rescue StandardError => e
+ QA::Runtime::Logger.error(e)
+ end
+ end
+
desc "Merge and upload knapsack report"
task :upload, [:glob] do |_task, args|
QA::Support::KnapsackReport.configure!
diff --git a/qa/tasks/migrate_influx_data_to_gcs.rake b/qa/tasks/migrate_influx_data_to_gcs.rake
new file mode 100644
index 00000000000..d6ac6e962f4
--- /dev/null
+++ b/qa/tasks/migrate_influx_data_to_gcs.rake
@@ -0,0 +1,6 @@
+# frozen_string_literal: true
+
+desc "Migrate the test results data from InfluxDB to GCS to visualise in Sisense/Tableau"
+task :influx_to_gcs, [:range] do |_task, args|
+ QA::Tools::MigrateInfluxDataToGcs.run(**args)
+end
diff --git a/qa/tasks/webdrivers.rake b/qa/tasks/webdrivers.rake
deleted file mode 100644
index cd2a36ddf6b..00000000000
--- a/qa/tasks/webdrivers.rake
+++ /dev/null
@@ -1,3 +0,0 @@
-# frozen_string_literal: true
-
-load 'webdrivers/Rakefile'