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-03-20 18:19:03 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2023-03-20 18:19:03 +0300
commit14bd84b61276ef29b97d23642d698de769bacfd2 (patch)
treef9eba90140c1bd874211dea17750a0d422c04080 /qa
parent891c388697b2db0d8ee0c8358a9bdbf6dc56d581 (diff)
Add latest changes from gitlab-org/gitlab@15-10-stable-eev15.10.0-rc42
Diffstat (limited to 'qa')
-rw-r--r--qa/Gemfile8
-rw-r--r--qa/Gemfile.lock35
-rw-r--r--qa/lib/gitlab/page/group/settings/usage_quotas.rb3
-rw-r--r--qa/qa.rb3
-rw-r--r--qa/qa/fixtures/kubernetes_agent/agentk-manifest.yaml.erb111
-rw-r--r--qa/qa/fixtures/mocks/import/github.yml74
-rw-r--r--qa/qa/fixtures/package_managers/maven/group/consumer/request_forwarding/gitlab_ci.yaml.erb8
-rw-r--r--qa/qa/fixtures/package_managers/maven/group/consumer/request_forwarding/settings.xml.erb23
-rw-r--r--qa/qa/flow/login.rb4
-rw-r--r--qa/qa/flow/pipeline.rb8
-rw-r--r--qa/qa/flow/saml.rb2
-rw-r--r--qa/qa/page/component/dropdown.rb18
-rw-r--r--qa/qa/page/component/groups_filter.rb12
-rw-r--r--qa/qa/page/group/sub_menus/common.rb2
-rw-r--r--qa/qa/page/main/login.rb1
-rw-r--r--qa/qa/page/main/menu.rb60
-rw-r--r--qa/qa/page/merge_request/new.rb2
-rw-r--r--qa/qa/page/merge_request/show.rb26
-rw-r--r--qa/qa/page/profile/menu.rb24
-rw-r--r--qa/qa/page/project/job/show.rb8
-rw-r--r--qa/qa/page/project/monitor/alerts/index.rb12
-rw-r--r--qa/qa/page/project/monitor/alerts/show.rb25
-rw-r--r--qa/qa/page/project/monitor/incidents/index.rb12
-rw-r--r--qa/qa/page/project/pipeline/show.rb11
-rw-r--r--qa/qa/page/project/settings/alerts.rb5
-rw-r--r--qa/qa/page/project/show.rb2
-rw-r--r--qa/qa/page/project/sub_menus/common.rb2
-rw-r--r--qa/qa/page/project/sub_menus/monitor.rb16
-rw-r--r--qa/qa/page/project/sub_menus/repository.rb2
-rw-r--r--qa/qa/page/user/show.rb6
-rw-r--r--qa/qa/resource/api_fabricator.rb120
-rw-r--r--qa/qa/resource/base.rb35
-rw-r--r--qa/qa/resource/ci_cd_settings.rb47
-rw-r--r--qa/qa/resource/integrations/web_hook/smockerable.rb41
-rw-r--r--qa/qa/resource/project_web_hook.rb44
-rw-r--r--qa/qa/resource/runner_base.rb4
-rw-r--r--qa/qa/resource/snippet.rb4
-rw-r--r--qa/qa/resource/web_hook_base.rb46
-rw-r--r--qa/qa/runtime/allure_report.rb19
-rw-r--r--qa/qa/runtime/browser.rb1
-rw-r--r--qa/qa/runtime/env.rb18
-rw-r--r--qa/qa/service/cluster_provider/gcloud.rb10
-rw-r--r--qa/qa/service/docker_run/gitlab_runner.rb2
-rw-r--r--qa/qa/service/kubernetes_cluster.rb14
-rw-r--r--qa/qa/specs/features/api/1_manage/import/import_github_repo_spec.rb7
-rw-r--r--qa/qa/specs/features/api/1_manage/integrations/webhook_events_spec.rb129
-rw-r--r--qa/qa/specs/features/api/1_manage/migration/gitlab_migration_issue_spec.rb10
-rw-r--r--qa/qa/specs/features/api/1_manage/migration/gitlab_migration_large_project_spec.rb4
-rw-r--r--qa/qa/specs/features/api/1_manage/migration/gitlab_migration_mr_spec.rb6
-rw-r--r--qa/qa/specs/features/api/1_manage/migration/gitlab_migration_project_spec.rb2
-rw-r--r--qa/qa/specs/features/api/1_manage/user_inherited_access_spec.rb31
-rw-r--r--qa/qa/specs/features/api/3_create/repository/files_spec.rb1
-rw-r--r--qa/qa/specs/features/api/4_verify/api_variable_inheritance_with_forward_pipeline_variables_spec.rb2
-rw-r--r--qa/qa/specs/features/api/4_verify/file_variable_spec.rb2
-rw-r--r--qa/qa/specs/features/browser_ui/1_manage/import/import_github_repo_spec.rb5
-rw-r--r--qa/qa/specs/features/browser_ui/1_manage/user/follow_user_activity_spec.rb2
-rw-r--r--qa/qa/specs/features/browser_ui/3_create/merge_request/rebase_merge_request_spec.rb8
-rw-r--r--qa/qa/specs/features/browser_ui/3_create/project_wiki/project_based_content_creation_spec.rb8
-rw-r--r--qa/qa/specs/features/browser_ui/3_create/repository/push_mirroring_lfs_over_http_spec.rb6
-rw-r--r--qa/qa/specs/features/browser_ui/3_create/snippet/snippet_index_page_spec.rb4
-rw-r--r--qa/qa/specs/features/browser_ui/3_create/web_ide/add_file_template_spec.rb13
-rw-r--r--qa/qa/specs/features/browser_ui/3_create/web_ide/add_new_directory_in_web_ide_spec.rb11
-rw-r--r--qa/qa/specs/features/browser_ui/3_create/web_ide/create_first_file_in_web_ide_spec.rb11
-rw-r--r--qa/qa/specs/features/browser_ui/3_create/web_ide/link_to_line_in_web_ide_spec.rb8
-rw-r--r--qa/qa/specs/features/browser_ui/3_create/web_ide/open_fork_in_web_ide_spec.rb84
-rw-r--r--qa/qa/specs/features/browser_ui/3_create/web_ide/open_web_ide_from_diff_tab_spec.rb11
-rw-r--r--qa/qa/specs/features/browser_ui/3_create/web_ide/review_merge_request_spec.rb11
-rw-r--r--qa/qa/specs/features/browser_ui/3_create/web_ide/server_hooks_custom_error_message_spec.rb14
-rw-r--r--qa/qa/specs/features/browser_ui/3_create/web_ide/upload_new_file_in_web_ide_spec.rb10
-rw-r--r--qa/qa/specs/features/browser_ui/4_verify/ci_job_artifacts/unlocking_job_artifacts_across_parent_child_pipelines_spec.rb448
-rw-r--r--qa/qa/specs/features/browser_ui/4_verify/ci_job_artifacts/unlocking_job_artifacts_across_pipelines_spec.rb170
-rw-r--r--qa/qa/specs/features/browser_ui/4_verify/ci_variable/add_remove_ci_variable_spec.rb2
-rw-r--r--qa/qa/specs/features/browser_ui/4_verify/ci_variable/custom_variable_spec.rb7
-rw-r--r--qa/qa/specs/features/browser_ui/4_verify/ci_variable/pipeline_with_protected_variable_spec.rb2
-rw-r--r--qa/qa/specs/features/browser_ui/4_verify/ci_variable/prefill_variables_spec.rb7
-rw-r--r--qa/qa/specs/features/browser_ui/4_verify/ci_variable/raw_variables_defined_in_yaml_spec.rb2
-rw-r--r--qa/qa/specs/features/browser_ui/4_verify/ci_variable/ui_variable_inheritable_when_forward_pipeline_variables_true_spec.rb2
-rw-r--r--qa/qa/specs/features/browser_ui/4_verify/ci_variable/ui_variable_non_inheritable_when_forward_pipeline_variables_false_spec.rb2
-rw-r--r--qa/qa/specs/features/browser_ui/4_verify/pipeline/include_multiple_files_from_multiple_projects_spec.rb154
-rw-r--r--qa/qa/specs/features/browser_ui/4_verify/pipeline/locked_artifacts_spec.rb2
-rw-r--r--qa/qa/specs/features/browser_ui/4_verify/pipeline/pass_dotenv_variables_to_downstream_via_bridge_spec.rb2
-rw-r--r--qa/qa/specs/features/browser_ui/4_verify/testing/endpoint_coverage_spec.rb2
-rw-r--r--qa/qa/specs/features/browser_ui/4_verify/testing/view_code_coverage_spec.rb2
-rw-r--r--qa/qa/specs/features/browser_ui/5_package/package_registry/helm_registry_spec.rb7
-rw-r--r--qa/qa/specs/features/browser_ui/5_package/package_registry/maven/maven_group_level_spec.rb105
-rw-r--r--qa/qa/specs/features/browser_ui/5_package/package_registry/maven_gradle_repository_spec.rb7
-rw-r--r--qa/qa/specs/features/browser_ui/5_package/package_registry/nuget/nuget_group_level_spec.rb21
-rw-r--r--qa/qa/specs/features/browser_ui/6_release/deploy_key/clone_using_deploy_key_spec.rb1
-rw-r--r--qa/qa/specs/features/browser_ui/8_monitor/alert_management/recovery_alert_resolves_correct_alert_spec.rb48
-rw-r--r--qa/qa/specs/features/browser_ui/8_monitor/incident_management/recovery_alert_closes_correct_incident.rb49
-rw-r--r--qa/qa/specs/features/shared_contexts/import/github_import_shared_context.rb1
-rw-r--r--qa/qa/specs/features/shared_contexts/import/gitlab_project_migration_common.rb1
-rw-r--r--qa/qa/specs/features/shared_contexts/packages_registry_shared_context.rb14
-rw-r--r--qa/qa/specs/features/shared_contexts/sends_and_resolves_test_alerts.rb73
-rw-r--r--qa/qa/specs/helpers/context_selector.rb6
-rw-r--r--qa/qa/support/json_formatter.rb8
-rw-r--r--qa/qa/support/loglinking.rb22
-rw-r--r--qa/qa/support/matchers/have_matcher.rb3
-rw-r--r--qa/qa/tools/test_resource_data_processor.rb2
-rw-r--r--qa/qa/vendor/smocker/event_payload.rb61
-rw-r--r--qa/qa/vendor/smocker/history_response.rb7
-rw-r--r--qa/qa/vendor/smocker/smocker_api.rb8
-rw-r--r--qa/spec/fixtures/ff/async_commit_diff_files.yml (renamed from qa/spec/fixtures/ff/bulk_import_projects.yml)10
-rw-r--r--qa/spec/resource/api_fabricator_spec.rb2
-rw-r--r--qa/spec/resource/project_web_hook_spec.rb70
-rw-r--r--qa/spec/runtime/env_spec.rb16
-rw-r--r--qa/spec/specs/helpers/context_selector_spec.rb144
-rw-r--r--qa/spec/specs/helpers/feature_flag_spec.rb64
-rw-r--r--qa/spec/tools/ci/ff_changes_spec.rb8
-rw-r--r--qa/spec/vendor/smocker_api_spec.rb18
110 files changed, 2179 insertions, 731 deletions
diff --git a/qa/Gemfile b/qa/Gemfile
index 9e41b5ddeed..9e35c619c5b 100644
--- a/qa/Gemfile
+++ b/qa/Gemfile
@@ -2,14 +2,14 @@
source 'https://rubygems.org'
-gem 'gitlab-qa', '~> 9', require: 'gitlab/qa'
+gem 'gitlab-qa', '~> 9', '>= 9.1.2', require: 'gitlab/qa'
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.38.0'
gem 'capybara-screenshot', '~> 1.0.26'
gem 'rake', '~> 13', '>= 13.0.6'
gem 'rspec', '~> 3.12'
-gem 'selenium-webdriver', '~> 4.8'
+gem 'selenium-webdriver', '~> 4.8', '>= 4.8.1'
gem 'airborne', '~> 0.3.7', require: false # airborne is messing with rspec sandboxed mode so not requiring by default
gem 'rest-client', '~> 2.1.0'
gem 'rspec-retry', '~> 0.6.2', require: 'rspec/retry'
@@ -21,8 +21,8 @@ gem 'rotp', '~> 6.2.2'
gem 'parallel', '~> 1.22', '>= 1.22.1'
gem 'rainbow', '~> 3.1.1'
gem 'rspec-parameterized', '~> 1.0.0'
-gem 'octokit', '~> 6.0.1'
-gem "faraday-retry", "~> 2.0"
+gem 'octokit', '~> 6.1.0'
+gem "faraday-retry", "~> 2.1"
gem 'webdrivers', '~> 5.2'
gem 'zeitwerk', '~> 2.6', '>= 2.6.7'
gem 'influxdb-client', '~> 2.9'
diff --git a/qa/Gemfile.lock b/qa/Gemfile.lock
index d544aa685a5..c3faf5841fc 100644
--- a/qa/Gemfile.lock
+++ b/qa/Gemfile.lock
@@ -51,7 +51,7 @@ GEM
chemlab (~> 0.4)
coderay (1.1.2)
colorize (0.8.1)
- concurrent-ruby (1.1.10)
+ concurrent-ruby (1.2.2)
confiner (0.4.0)
gitlab (>= 4.17)
zeitwerk (>= 2.5, < 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.0.0)
+ faraday-retry (2.1.0)
faraday (~> 2.0)
ffi (1.15.5)
ffi-compiler (1.0.1)
@@ -102,11 +102,12 @@ GEM
gitlab (4.18.0)
httparty (~> 0.18)
terminal-table (>= 1.5.1)
- gitlab-qa (9.0.0)
+ gitlab-qa (9.1.2)
activesupport (~> 6.1)
gitlab (~> 4.18.0)
http (~> 5.0)
nokogiri (~> 1.10)
+ parallel (>= 1, < 2)
rainbow (>= 3, < 4)
table_print (= 1.5.7)
zeitwerk (>= 2, < 3)
@@ -151,8 +152,8 @@ GEM
http-cookie (1.0.5)
domain_name (~> 0.5)
http-form_data (2.3.0)
- httparty (0.20.0)
- mime-types (~> 3.0)
+ httparty (0.21.0)
+ mini_mime (>= 1.0.0)
multi_xml (>= 0.5.2)
httpclient (2.8.3)
i18n (1.12.0)
@@ -173,17 +174,17 @@ GEM
method_source (1.0.0)
mime-types (3.4.1)
mime-types-data (~> 3.2015)
- mime-types-data (3.2022.0105)
+ mime-types-data (3.2023.0218.1)
mini_mime (1.1.0)
mini_portile2 (2.8.1)
- minitest (5.17.0)
+ minitest (5.18.0)
multi_json (1.15.0)
multi_xml (0.6.0)
netrc (0.11.0)
nokogiri (1.14.2)
mini_portile2 (~> 2.8.0)
racc (~> 1.4)
- octokit (6.0.1)
+ octokit (6.1.0)
faraday (>= 1, < 3)
sawyer (~> 0.9)
oj (3.13.23)
@@ -203,7 +204,7 @@ GEM
pry-byebug (3.10.1)
byebug (~> 11.0)
pry (>= 0.13, < 0.15)
- public_suffix (5.0.0)
+ public_suffix (5.0.1)
racc (1.6.2)
rack (2.2.3.1)
rack-test (1.1.0)
@@ -259,7 +260,7 @@ GEM
sawyer (0.9.2)
addressable (>= 2.3.5)
faraday (>= 0.17.3, < 3)
- selenium-webdriver (4.8.0)
+ selenium-webdriver (4.8.1)
rexml (~> 3.2, >= 3.2.5)
rubyzip (>= 1.2.2, < 3.0)
websocket (~> 1.0)
@@ -274,13 +275,13 @@ GEM
terminal-table (3.0.2)
unicode-display_width (>= 1.1.1, < 3)
trailblazer-option (0.1.2)
- tzinfo (2.0.5)
+ tzinfo (2.0.6)
concurrent-ruby (~> 1.0)
uber (0.1.0)
unf (0.1.4)
unf_ext
unf_ext (0.0.8.2)
- unicode-display_width (2.3.0)
+ unicode-display_width (2.4.2)
unparser (0.6.5)
diff-lcs (~> 1.3)
parser (>= 3.1.0)
@@ -314,14 +315,14 @@ DEPENDENCIES
confiner (~> 0.4)
deprecation_toolkit (~> 2.0.3)
faker (~> 3.1, >= 3.1.1)
- faraday-retry (~> 2.0)
+ faraday-retry (~> 2.1)
fog-core (= 2.1.0)
fog-google (~> 1.19)
- gitlab-qa (~> 9)
+ gitlab-qa (~> 9, >= 9.1.2)
influxdb-client (~> 2.9)
knapsack (~> 4.0)
nokogiri (~> 1.14, >= 1.14.2)
- octokit (~> 6.0.1)
+ octokit (~> 6.1.0)
parallel (~> 1.22, >= 1.22.1)
parallel_tests (~> 4.2)
pry-byebug (~> 3.10.1)
@@ -334,7 +335,7 @@ DEPENDENCIES
rspec-retry (~> 0.6.2)
rspec_junit_formatter (~> 0.6.0)
ruby-debug-ide (~> 0.7.3)
- selenium-webdriver (~> 4.8)
+ selenium-webdriver (~> 4.8, >= 4.8.1)
slack-notifier (~> 2.4)
terminal-table (~> 3.0.2)
warning (~> 1.3)
@@ -342,4 +343,4 @@ DEPENDENCIES
zeitwerk (~> 2.6, >= 2.6.7)
BUNDLED WITH
- 2.4.6
+ 2.4.8
diff --git a/qa/lib/gitlab/page/group/settings/usage_quotas.rb b/qa/lib/gitlab/page/group/settings/usage_quotas.rb
index 3cb501efe13..22e61c97bdb 100644
--- a/qa/lib/gitlab/page/group/settings/usage_quotas.rb
+++ b/qa/lib/gitlab/page/group/settings/usage_quotas.rb
@@ -23,12 +23,11 @@ module Gitlab
# Storage section
link :storage_tab
link :purchase_more_storage
- div :used_storage_message
+ div :namespace_usage_total
div :group_usage_message
div :dependency_proxy_usage
span :dependency_proxy_size
div :container_registry_usage
- div :project_storage_used
div :project
div :storage_type_legend
span :container_registry_size
diff --git a/qa/qa.rb b/qa/qa.rb
index cb1278771d9..a395dc6e0b0 100644
--- a/qa/qa.rb
+++ b/qa/qa.rb
@@ -82,7 +82,8 @@ module QA
"jetbrains" => "JetBrains",
"vscode" => "VSCode",
"registry_with_cdn" => "RegistryWithCDN",
- "fips" => "FIPS"
+ "fips" => "FIPS",
+ "ci_cd_settings" => "CICDSettings"
)
loader.setup
diff --git a/qa/qa/fixtures/kubernetes_agent/agentk-manifest.yaml.erb b/qa/qa/fixtures/kubernetes_agent/agentk-manifest.yaml.erb
deleted file mode 100644
index e6ec4528d0d..00000000000
--- a/qa/qa/fixtures/kubernetes_agent/agentk-manifest.yaml.erb
+++ /dev/null
@@ -1,111 +0,0 @@
-apiVersion: v1
-kind: ServiceAccount
-metadata:
- name: gitlab-agent
----
-apiVersion: apps/v1
-kind: Deployment
-metadata:
- name: gitlab-agent
-spec:
- replicas: 1
- selector:
- matchLabels:
- app: gitlab-agent
- template:
- metadata:
- labels:
- app: gitlab-agent
- spec:
- serviceAccountName: gitlab-agent
- containers:
- - name: agent
- image: "registry.gitlab.com/gitlab-org/cluster-integration/gitlab-agent/agentk:<%= Runtime::Env.gitlab_agentk_version %>"
- args:
- - --token-file=/config/token
- - --kas-address
- - "<%= kas_wss_address %>"
- <% if QA::Runtime::Env.qa_cookies.to_s.include?("gitlab_canary=true") %>
- - --kas-header
- - "Cookie: gitlab_canary=true"
- <% end %>
- volumeMounts:
- - name: token-volume
- mountPath: /config
- env:
- - name: POD_NAMESPACE
- valueFrom:
- fieldRef:
- fieldPath: metadata.namespace
- - name: POD_NAME
- valueFrom:
- fieldRef:
- fieldPath: metadata.name
- - name: SERVICE_ACCOUNT_NAME
- valueFrom:
- fieldRef:
- fieldPath: spec.serviceAccountName
- volumes:
- - name: token-volume
- secret:
- secretName: gitlab-agent-token
- strategy:
- type: RollingUpdate
- rollingUpdate:
- maxSurge: 0
- maxUnavailable: 1
----
-apiVersion: rbac.authorization.k8s.io/v1
-kind: ClusterRole
-metadata:
- name: gitlab-agent-write
-rules:
- - resources:
- - "*"
- apiGroups:
- - "*"
- verbs:
- - create
- - update
- - delete
- - patch
----
-apiVersion: rbac.authorization.k8s.io/v1
-kind: ClusterRoleBinding
-metadata:
- name: gitlab-agent-write-binding
-roleRef:
- name: gitlab-agent-write
- kind: ClusterRole
- apiGroup: rbac.authorization.k8s.io
-subjects:
- - name: gitlab-agent
- kind: ServiceAccount
- namespace: default
----
-apiVersion: rbac.authorization.k8s.io/v1
-kind: ClusterRole
-metadata:
- name: gitlab-agent-read
-rules:
- - resources:
- - "*"
- apiGroups:
- - "*"
- verbs:
- - get
- - list
- - watch
----
-apiVersion: rbac.authorization.k8s.io/v1
-kind: ClusterRoleBinding
-metadata:
- name: gitlab-agent-read-binding
-roleRef:
- name: gitlab-agent-read
- kind: ClusterRole
- apiGroup: rbac.authorization.k8s.io
-subjects:
- - name: gitlab-agent
- kind: ServiceAccount
- namespace: default
diff --git a/qa/qa/fixtures/mocks/import/github.yml b/qa/qa/fixtures/mocks/import/github.yml
index 9cabdee1025..b8e137abfbb 100644
--- a/qa/qa/fixtures/mocks/import/github.yml
+++ b/qa/qa/fixtures/mocks/import/github.yml
@@ -2741,3 +2741,77 @@
},
"url": "https://api.github.com/repos/gitlab-qa-github/import-test/branches/release/protection"
}
+
+- request:
+ path: /repos/gitlab-qa-github/import-test/collaborators
+ method: GET
+ query_params:
+ page: '1'
+ per_page: '100'
+ headers:
+ Host: api.github.com
+ response:
+ status: 200
+ headers:
+ Content-Type: application/json; charset=utf-8
+ X-Ratelimit-Limit: '5000'
+ X-Ratelimit-Remaining: '5000'
+ body: |
+ [
+ {
+ "avatar_url": "https://avatars.githubusercontent.com/u/40021320?v=4",
+ "events_url": "https://api.github.com/users/gitlab-qa/events{/privacy}",
+ "followers_url": "https://api.github.com/users/gitlab-qa/followers",
+ "following_url": "https://api.github.com/users/gitlab-qa/following{/other_user}",
+ "gists_url": "https://api.github.com/users/gitlab-qa/gists{/gist_id}",
+ "gravatar_id": "",
+ "html_url": "https://github.com/gitlab-qa",
+ "id": 40021320,
+ "login": "gitlab-qa",
+ "node_id": "MDQ6VXNlcjQwMDIxMzIw",
+ "organizations_url": "https://api.github.com/users/gitlab-qa/orgs",
+ "permissions": {
+ "admin": false,
+ "maintain": false,
+ "pull": true,
+ "push": true,
+ "triage": true
+ },
+ "received_events_url": "https://api.github.com/users/gitlab-qa/received_events",
+ "repos_url": "https://api.github.com/users/gitlab-qa/repos",
+ "role_name": "write",
+ "site_admin": false,
+ "starred_url": "https://api.github.com/users/gitlab-qa/starred{/owner}{/repo}",
+ "subscriptions_url": "https://api.github.com/users/gitlab-qa/subscriptions",
+ "type": "User",
+ "url": "https://api.github.com/users/gitlab-qa"
+ },
+ {
+ "avatar_url": "https://avatars.githubusercontent.com/u/59606922?v=4",
+ "events_url": "https://api.github.com/users/gitlab-qa-github/events{/privacy}",
+ "followers_url": "https://api.github.com/users/gitlab-qa-github/followers",
+ "following_url": "https://api.github.com/users/gitlab-qa-github/following{/other_user}",
+ "gists_url": "https://api.github.com/users/gitlab-qa-github/gists{/gist_id}",
+ "gravatar_id": "",
+ "html_url": "https://github.com/gitlab-qa-github",
+ "id": 59606922,
+ "login": "gitlab-qa-github",
+ "node_id": "MDQ6VXNlcjU5NjA2OTIy",
+ "organizations_url": "https://api.github.com/users/gitlab-qa-github/orgs",
+ "permissions": {
+ "admin": true,
+ "maintain": true,
+ "pull": true,
+ "push": true,
+ "triage": true
+ },
+ "received_events_url": "https://api.github.com/users/gitlab-qa-github/received_events",
+ "repos_url": "https://api.github.com/users/gitlab-qa-github/repos",
+ "role_name": "admin",
+ "site_admin": false,
+ "starred_url": "https://api.github.com/users/gitlab-qa-github/starred{/owner}{/repo}",
+ "subscriptions_url": "https://api.github.com/users/gitlab-qa-github/subscriptions",
+ "type": "User",
+ "url": "https://api.github.com/users/gitlab-qa-github"
+ }
+ ]
diff --git a/qa/qa/fixtures/package_managers/maven/group/consumer/request_forwarding/gitlab_ci.yaml.erb b/qa/qa/fixtures/package_managers/maven/group/consumer/request_forwarding/gitlab_ci.yaml.erb
new file mode 100644
index 00000000000..394c6689eef
--- /dev/null
+++ b/qa/qa/fixtures/package_managers/maven/group/consumer/request_forwarding/gitlab_ci.yaml.erb
@@ -0,0 +1,8 @@
+install:
+ image: maven:3.6-jdk-11
+ script:
+ - "mvn install -U -s settings.xml"
+ only:
+ - "<%= imported_project.default_branch %>"
+ tags:
+ - "runner-for-<%= imported_project.group.name %>" \ No newline at end of file
diff --git a/qa/qa/fixtures/package_managers/maven/group/consumer/request_forwarding/settings.xml.erb b/qa/qa/fixtures/package_managers/maven/group/consumer/request_forwarding/settings.xml.erb
new file mode 100644
index 00000000000..4bcd63b3c6d
--- /dev/null
+++ b/qa/qa/fixtures/package_managers/maven/group/consumer/request_forwarding/settings.xml.erb
@@ -0,0 +1,23 @@
+<settings>
+ <servers>
+ <server>
+ <id>central-proxy</id>
+ <configuration>
+ <httpHeaders>
+ <property>
+ <name>Private-Token</name>
+ <value><%= personal_access_token %></value>
+ </property>
+ </httpHeaders>
+ </configuration>
+ </server>
+ </servers>
+ <mirrors>
+ <mirror>
+ <id>central-proxy</id>
+ <name>GitLab proxy of central repo</name>
+ <url><%= gitlab_address_with_port %>/api/v4/groups/<%= imported_project.group.id %>/-/packages/maven</url>
+ <mirrorOf>central</mirrorOf>
+ </mirror>
+ </mirrors>
+</settings> \ No newline at end of file
diff --git a/qa/qa/flow/login.rb b/qa/qa/flow/login.rb
index 564a51ee483..2702b52f2ef 100644
--- a/qa/qa/flow/login.rb
+++ b/qa/qa/flow/login.rb
@@ -21,8 +21,8 @@ module QA
def sign_in(as: nil, address: :gitlab, skip_page_validation: false, admin: false)
Page::Main::Login.perform { |p| p.redirect_to_login_page(address) }
- unless Page::Main::Login.perform(&:on_login_page?)
- Page::Main::Menu.perform(&:sign_out) if Page::Main::Menu.perform(&:signed_in?)
+ if !Page::Main::Login.perform(&:on_login_page?) && Page::Main::Menu.perform(&:signed_in?)
+ Page::Main::Menu.perform(&:sign_out)
end
Page::Main::Login.perform do |login|
diff --git a/qa/qa/flow/pipeline.rb b/qa/qa/flow/pipeline.rb
index fb6a5425a6e..0765a8758ec 100644
--- a/qa/qa/flow/pipeline.rb
+++ b/qa/qa/flow/pipeline.rb
@@ -24,6 +24,14 @@ module QA
index.wait_for_latest_pipeline(status: status, wait: wait)
end
end
+
+ def visit_pipeline_job_page(job_name:, pipeline: nil)
+ pipeline.visit! unless pipeline.nil?
+
+ Page::Project::Pipeline::Show.perform do |pipeline|
+ pipeline.click_job(job_name)
+ end
+ end
end
end
end
diff --git a/qa/qa/flow/saml.rb b/qa/qa/flow/saml.rb
index 8a0ebb9f551..1cf29e75c67 100644
--- a/qa/qa/flow/saml.rb
+++ b/qa/qa/flow/saml.rb
@@ -19,8 +19,6 @@ module QA
end
def enable_saml_sso(group, saml_idp_service, enforce_sso: false, default_membership_role: 'Guest')
- Runtime::Feature.enable(:group_administration_nav_item)
-
page.visit Runtime::Scenario.gitlab_address
Page::Main::Login.perform(&:sign_in_using_credentials) unless Page::Main::Menu.perform(&:signed_in?)
diff --git a/qa/qa/page/component/dropdown.rb b/qa/qa/page/component/dropdown.rb
index 01ef3533ff8..767cd40daa2 100644
--- a/qa/qa/page/component/dropdown.rb
+++ b/qa/qa/page/component/dropdown.rb
@@ -4,8 +4,18 @@ module QA
module Page
module Component
module Dropdown
- def select_item(item_text)
- find('li.gl-new-dropdown-item', text: item_text, match: :prefer_exact).click
+ # Find and click item using css selector and matching text
+ # If item_text is not provided, select the first item that matches the given css selector
+ #
+ # @param [String] item_text
+ # @param [String] css - css selector of the item
+ # @return [void]
+ def select_item(item_text, css: 'li.gl-new-dropdown-item')
+ if item_text
+ find(css, text: item_text, match: :prefer_exact).click
+ else
+ find(css, match: :first).click
+ end
end
def has_item?(item_text)
@@ -65,8 +75,8 @@ module QA
find('li.gl-new-dropdown-item span:nth-child(2)', text: item_text, exact_text: true).click
end
- def expand_select_list
- find('.gl-new-dropdown-toggle').click
+ def expand_select_list(css: '.gl-new-dropdown-toggle')
+ find(css).click
end
def wait_for_search_to_complete
diff --git a/qa/qa/page/component/groups_filter.rb b/qa/qa/page/component/groups_filter.rb
index ea91ced8679..14e49e53b75 100644
--- a/qa/qa/page/component/groups_filter.rb
+++ b/qa/qa/page/component/groups_filter.rb
@@ -16,10 +16,6 @@ module QA
base.view 'app/assets/javascripts/groups/components/groups.vue' do
element :groups_list_tree_container
end
-
- base.view 'app/views/dashboard/_groups_head.html.haml' do
- element :public_groups_tab
- end
end
private
@@ -29,14 +25,8 @@ module QA
# @return [Boolean] whether a group with given name exists
def has_filtered_group?(name)
filter_group(name)
- return true if page.has_link?(name, wait: 0) # element containing link to group
- return false unless has_element?(:public_groups_tab, wait: 0)
-
- # Check public groups
- click_element(:public_groups_tab)
- filter_group(name)
- page.has_link?(name, wait: 0)
+ page.has_link?(name, wait: 0) # element containing link to group
end
# Filter by group name
diff --git a/qa/qa/page/group/sub_menus/common.rb b/qa/qa/page/group/sub_menus/common.rb
index 2f8a3fdeb4e..3cbca3db359 100644
--- a/qa/qa/page/group/sub_menus/common.rb
+++ b/qa/qa/page/group/sub_menus/common.rb
@@ -21,7 +21,7 @@ module QA
private
def sidebar_element
- :group_sidebar
+ QA::Runtime::Env.super_sidebar_enabled? ? :navbar : :group_sidebar
end
end
end
diff --git a/qa/qa/page/main/login.rb b/qa/qa/page/main/login.rb
index f4f8820bc04..7532154f0cc 100644
--- a/qa/qa/page/main/login.rb
+++ b/qa/qa/page/main/login.rb
@@ -233,6 +233,7 @@ module QA
terms.accept_terms if terms.visible?
end
+ Page::Main::Menu.perform(&:enable_new_navigation) if Runtime::Env.super_sidebar_enabled?
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 1e050d79e23..f86849061e8 100644
--- a/qa/qa/page/main/menu.rb
+++ b/qa/qa/page/main/menu.rb
@@ -6,21 +6,35 @@ module QA
class Menu < Page::Base
prepend Mobile::Page::Main::Menu if Runtime::Env.mobile_layout?
- view 'app/views/layouts/header/_current_user_dropdown.html.haml' do
- element :sign_out_link
- element :edit_profile_link
- element :user_profile_link
- end
+ if QA::Runtime::Env.super_sidebar_enabled?
+ # 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: !QA::Runtime::Env.mobile_layout?
+ element :user_avatar_content, required: !QA::Runtime::Env.mobile_layout?
+ end
- view 'app/views/layouts/header/_default.html.haml' do
- element :navbar, required: true
- element :canary_badge_link
- element :user_avatar_content, required: !QA::Runtime::Env.mobile_layout?
- element :user_menu, required: !QA::Runtime::Env.mobile_layout?
- element :stop_impersonation_link
- element :issues_shortcut_button, required: !QA::Runtime::Env.mobile_layout?
- element :merge_requests_shortcut_button, required: !QA::Runtime::Env.mobile_layout?
- element :todos_shortcut_button, required: !QA::Runtime::Env.mobile_layout?
+ view 'app/assets/javascripts/super_sidebar/components/user_menu.vue' do
+ element :sign_out_link
+ element :edit_profile_link
+ end
+ else
+ view 'app/views/layouts/header/_default.html.haml' do
+ element :navbar, required: true
+ element :canary_badge_link
+ element :user_avatar_content, required: !QA::Runtime::Env.mobile_layout?
+ element :user_menu, required: !QA::Runtime::Env.mobile_layout?
+ element :stop_impersonation_link
+ element :issues_shortcut_button, required: !QA::Runtime::Env.mobile_layout?
+ element :merge_requests_shortcut_button, required: !QA::Runtime::Env.mobile_layout?
+ element :todos_shortcut_button, required: !QA::Runtime::Env.mobile_layout?
+ end
+
+ view 'app/views/layouts/header/_current_user_dropdown.html.haml' do
+ element :sign_out_link
+ element :edit_profile_link
+ element :user_profile_link
+ end
end
view 'app/assets/javascripts/nav/components/top_nav_app.vue' do
@@ -39,7 +53,6 @@ module QA
element :admin_area_link
element :projects_dropdown
element :groups_dropdown
- element :snippets_link
element :menu_item_link
end
@@ -64,6 +77,10 @@ module QA
element :global_new_project_link
end
+ view 'app/assets/javascripts/nav/components/new_nav_toggle.vue' do
+ element :new_navigation_toggle
+ end
+
def go_to_groups
within_groups_menu do
click_element(:menu_item_link, title: 'View all groups')
@@ -81,12 +98,18 @@ module QA
end
end
+ def go_to_snippets
+ click_element(:sidebar_menu_link, menu_item: 'Snippets')
+ end
+
def go_to_create_project
click_element(:new_menu_toggle)
click_element(:global_new_project_link)
end
def go_to_menu_dropdown_option(option_name)
+ return click_element(option_name) if QA::Runtime::Env.super_sidebar_enabled?
+
within_top_menu do
click_element(:navbar_dropdown, title: 'Menu')
click_element(option_name)
@@ -211,6 +234,13 @@ module QA
has_element?(:canary_badge_link)
end
+ def enable_new_navigation
+ Runtime::Logger.info("Enabling super sidebar!")
+ return Runtime::Logger.info("Super sidebar is already enabled") if has_css?('[data-testid="super-sidebar"]')
+
+ within_user_menu { click_element(:new_navigation_toggle) }
+ end
+
private
def within_top_menu(&block)
diff --git a/qa/qa/page/merge_request/new.rb b/qa/qa/page/merge_request/new.rb
index a1d91621090..90022616674 100644
--- a/qa/qa/page/merge_request/new.rb
+++ b/qa/qa/page/merge_request/new.rb
@@ -4,6 +4,8 @@ module QA
module Page
module MergeRequest
class New < Page::Issuable::New
+ include QA::Page::Component::Dropdown
+
view 'app/views/shared/issuable/_form.html.haml' do
element :issuable_create_button, required: true
end
diff --git a/qa/qa/page/merge_request/show.rb b/qa/qa/page/merge_request/show.rb
index df0c0ec4202..451a9c3ee6e 100644
--- a/qa/qa/page/merge_request/show.rb
+++ b/qa/qa/page/merge_request/show.rb
@@ -31,6 +31,7 @@ module QA
view 'app/assets/javascripts/diffs/components/tree_list.vue' do
element :file_tree_container
+ element :diff_tree_search
end
view 'app/assets/javascripts/diffs/components/diff_file_header.vue' do
@@ -215,14 +216,25 @@ module QA
def has_file?(file_name)
open_file_tree
+
+ return true if has_element?(:file_name_content, file_name: file_name)
+
+ # Since the file tree uses virtual scrolling, search for file in case it is outside of viewport
+ search_file_tree(file_name)
has_element?(:file_name_content, file_name: file_name)
end
def has_no_file?(file_name)
- open_file_tree
+ # Since the file tree uses virtual scrolling, search for file to ensure non-existence
+ search_file_tree(file_name)
has_no_element?(:file_name_content, file_name: file_name)
end
+ def search_file_tree(file_name)
+ open_file_tree
+ fill_element(:diff_tree_search, file_name)
+ end
+
def open_file_tree
click_element(:file_tree_button) unless has_element?(:file_tree_container)
end
@@ -233,6 +245,17 @@ module QA
has_element?(:merge_button)
end
+ def has_no_merge_button?
+ refresh
+
+ has_no_element?(:merge_button)
+ end
+
+ RSpec::Matchers.define :have_merge_button do
+ match(&:has_merge_button?)
+ match_when_negated(&:has_no_merge_button?)
+ end
+
def has_pipeline_status?(text)
# Pipelines can be slow, so we wait a bit longer than the usual 10 seconds
wait_until(max_duration: 120, sleep_interval: 5, reload: true) do
@@ -386,6 +409,7 @@ module QA
click_element(:dropdown_button)
click_element(:edit_in_ide_button)
end
+ page.driver.browser.switch_to.window(page.driver.browser.window_handles.last)
end
def add_suggestion_to_diff(suggestion, line)
diff --git a/qa/qa/page/profile/menu.rb b/qa/qa/page/profile/menu.rb
index 947fa2fec0f..651603a77db 100644
--- a/qa/qa/page/profile/menu.rb
+++ b/qa/qa/page/profile/menu.rb
@@ -8,25 +8,35 @@ module QA
# since tablets have the regular top navigation bar but still close the left nav
prepend QA::Mobile::Page::SubMenus::Common if QA::Runtime::Env.remote_mobile_device_name
- view 'app/views/layouts/nav/sidebar/_profile.html.haml' do
- element :access_token_link, 'link_to profile_personal_access_tokens_path' # rubocop:disable QA/ElementWithPattern
- element :access_token_title, 'Access Tokens' # rubocop:disable QA/ElementWithPattern
- element :top_level_items, '.sidebar-top-level-items' # rubocop:disable QA/ElementWithPattern
- element :ssh_keys, 'SSH Keys' # rubocop:disable QA/ElementWithPattern
+ view 'lib/sidebars/user_settings/menus/access_tokens_menu.rb' do
+ element :access_token_link
+ end
+
+ view 'lib/sidebars/user_settings/menus/ssh_keys_menu.rb' do
+ element :ssh_keys_link
+ end
+
+ view 'lib/sidebars/user_settings/menus/emails_menu.rb' do
element :profile_emails_link
+ end
+
+ view 'lib/sidebars/user_settings/menus/password_menu.rb' do
element :profile_password_link
+ end
+
+ view 'lib/sidebars/user_settings/menus/account_menu.rb' do
element :profile_account_link
end
def click_access_tokens
within_sidebar do
- click_link('Access Tokens')
+ click_element(:access_token_link)
end
end
def click_ssh_keys
within_sidebar do
- click_link('SSH Keys')
+ click_element(:ssh_keys_link)
end
end
diff --git a/qa/qa/page/project/job/show.rb b/qa/qa/page/project/job/show.rb
index 24fd34b4d22..444c67cfe4f 100644
--- a/qa/qa/page/project/job/show.rb
+++ b/qa/qa/page/project/job/show.rb
@@ -68,6 +68,14 @@ module QA
end
end
+ def has_locked_artifact?
+ has_text?('will not be deleted')
+ end
+
+ def has_unlocked_artifact?
+ has_text?('will be removed')
+ end
+
private
def loaded?(wait: 60)
diff --git a/qa/qa/page/project/monitor/alerts/index.rb b/qa/qa/page/project/monitor/alerts/index.rb
index 1363fb32498..1738ce170f2 100644
--- a/qa/qa/page/project/monitor/alerts/index.rb
+++ b/qa/qa/page/project/monitor/alerts/index.rb
@@ -13,6 +13,18 @@ module QA
def has_alert_with_title?(title)
has_link?(title, wait: 5)
end
+
+ def go_to_alert(title)
+ click_link_with_text(title)
+ end
+
+ def has_no_alert_with_title?(title)
+ has_no_link?(title, wait: 5)
+ end
+
+ def go_to_tab(name)
+ click_link_with_text(name)
+ end
end
end
end
diff --git a/qa/qa/page/project/monitor/alerts/show.rb b/qa/qa/page/project/monitor/alerts/show.rb
new file mode 100644
index 00000000000..1f3c52d8988
--- /dev/null
+++ b/qa/qa/page/project/monitor/alerts/show.rb
@@ -0,0 +1,25 @@
+# frozen_string_literal: true
+
+module QA
+ module Page
+ module Project
+ module Monitor
+ module Alerts
+ class Show < Page::Base
+ view 'app/assets/javascripts/vue_shared/alert_details/components/system_notes/system_note.vue' do
+ element :alert_system_note_container
+ end
+
+ def go_to_activity_feed_tab
+ click_link_with_text('Activity feed')
+ end
+
+ def has_system_note?(text)
+ has_element?(:alert_system_note_container, text: text)
+ end
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/qa/qa/page/project/monitor/incidents/index.rb b/qa/qa/page/project/monitor/incidents/index.rb
index 1b30e484723..04cb23da389 100644
--- a/qa/qa/page/project/monitor/incidents/index.rb
+++ b/qa/qa/page/project/monitor/incidents/index.rb
@@ -15,8 +15,16 @@ module QA
click_element :create_incident_button
end
- def has_incident?(wait: Support::Repeater::DEFAULT_MAX_WAIT_TIME)
- wait_until(max_duration: wait) { has_element?(:incident_link) }
+ def has_incident?(wait: Support::Repeater::DEFAULT_MAX_WAIT_TIME, title: nil)
+ wait_until(max_duration: wait) { has_element?(:incident_link, text: title) }
+ end
+
+ def has_no_incident?(title: nil)
+ has_no_element?(:incident_link, text: title)
+ end
+
+ def go_to_tab(tab)
+ click_link_with_text(tab)
end
end
end
diff --git a/qa/qa/page/project/pipeline/show.rb b/qa/qa/page/project/pipeline/show.rb
index e4511ababfd..25d62ac59af 100644
--- a/qa/qa/page/project/pipeline/show.rb
+++ b/qa/qa/page/project/pipeline/show.rb
@@ -44,6 +44,17 @@ module QA
element :jobs_dropdown_menu
end
+ view 'app/views/layouts/nav/_breadcrumbs.html.haml' do
+ element :breadcrumb_links_content
+ element :breadcrumb_current_link
+ end
+
+ def pipeline_id
+ within_element(:breadcrumb_links_content) do
+ find_element(:breadcrumb_current_link).text.delete_prefix('#')
+ end
+ end
+
def running?(wait: 0)
within_element(:pipeline_header) do
page.has_content?('running', wait: wait)
diff --git a/qa/qa/page/project/settings/alerts.rb b/qa/qa/page/project/settings/alerts.rb
index 901a668f082..3ff4ef20bde 100644
--- a/qa/qa/page/project/settings/alerts.rb
+++ b/qa/qa/page/project/settings/alerts.rb
@@ -5,11 +5,12 @@ module QA
module Project
module Settings
class Alerts < Page::Base
+ include ::QA::Page::Component::Dropdown
+
view 'app/assets/javascripts/alerts_settings/components/alerts_form.vue' do
element :create_incident_checkbox
element :incident_templates_dropdown
element :save_changes_button
- element :incident_templates_item
element :enable_email_notification_checkbox
end
@@ -42,7 +43,7 @@ module QA
def select_issue_template(template)
click_element(:incident_templates_dropdown)
within_element :incident_templates_dropdown do
- find_element(:incident_templates_item, text: template).click
+ select_item(template)
end
end
diff --git a/qa/qa/page/project/show.rb b/qa/qa/page/project/show.rb
index 3c2b8d56f1d..b89e17910c9 100644
--- a/qa/qa/page/project/show.rb
+++ b/qa/qa/page/project/show.rb
@@ -163,10 +163,12 @@ module QA
def open_web_ide!
click_element(:web_ide_button)
+ page.driver.browser.switch_to.window(page.driver.browser.window_handles.last)
end
def open_web_ide_via_shortcut
page.driver.send_keys('.')
+ page.driver.browser.switch_to.window(page.driver.browser.window_handles.last)
end
def has_edit_fork_button?
diff --git a/qa/qa/page/project/sub_menus/common.rb b/qa/qa/page/project/sub_menus/common.rb
index 112f49a90ee..79054ec9802 100644
--- a/qa/qa/page/project/sub_menus/common.rb
+++ b/qa/qa/page/project/sub_menus/common.rb
@@ -29,7 +29,7 @@ module QA
private
def sidebar_element
- :project_sidebar
+ QA::Runtime::Env.super_sidebar_enabled? ? :navbar : :project_sidebar
end
end
end
diff --git a/qa/qa/page/project/sub_menus/monitor.rb b/qa/qa/page/project/sub_menus/monitor.rb
index 27fb58fb146..00774261467 100644
--- a/qa/qa/page/project/sub_menus/monitor.rb
+++ b/qa/qa/page/project/sub_menus/monitor.rb
@@ -31,6 +31,22 @@ module QA
end
end
+ def go_to_monitor_on_call_schedules
+ hover_monitor do
+ within_submenu do
+ click_element(:sidebar_menu_item_link, menu_item: 'On-call Schedules')
+ end
+ end
+ end
+
+ def go_to_monitor_escalation_policies
+ hover_monitor do
+ within_submenu do
+ click_element(:sidebar_menu_item_link, menu_item: 'Escalation Policies')
+ end
+ end
+ end
+
private
def hover_monitor
diff --git a/qa/qa/page/project/sub_menus/repository.rb b/qa/qa/page/project/sub_menus/repository.rb
index f9d55c0009c..b8ebaa10a49 100644
--- a/qa/qa/page/project/sub_menus/repository.rb
+++ b/qa/qa/page/project/sub_menus/repository.rb
@@ -40,7 +40,7 @@ module QA
def go_to_repository_contributors
hover_repository do
within_submenu do
- click_element(:sidebar_menu_item_link, menu_item: 'Contributors')
+ click_element(:sidebar_menu_item_link, menu_item: 'Contributor statistics')
end
end
end
diff --git a/qa/qa/page/user/show.rb b/qa/qa/page/user/show.rb
index ad2de331ad9..9f5f0fae9bc 100644
--- a/qa/qa/page/user/show.rb
+++ b/qa/qa/page/user/show.rb
@@ -6,7 +6,7 @@ module QA
class Show < Page::Base
view 'app/views/users/show.html.haml' do
element :follow_user_link
- element :following_link
+ element :following_tab
end
view 'app/views/shared/users/_user.html.haml' do
@@ -21,8 +21,8 @@ module QA
click_element(:follow_user_link)
end
- def click_following_link
- click_element(:following_link)
+ def click_following_tab
+ click_element(:following_tab)
end
def click_user_link(username)
diff --git a/qa/qa/resource/api_fabricator.rb b/qa/qa/resource/api_fabricator.rb
index d7a220bc83f..cbb68cccdf1 100644
--- a/qa/qa/resource/api_fabricator.rb
+++ b/qa/qa/resource/api_fabricator.rb
@@ -10,6 +10,7 @@ module QA
include Support::API
include Errors
+ attr_reader :api_fabrication_http_method
attr_writer :api_client
attr_accessor :api_user, :api_resource, :api_response
@@ -49,22 +50,6 @@ module QA
end
end
- def api_put(body = api_put_body)
- response = put(
- Runtime::API::Request.new(api_client, api_put_path).url,
- body)
-
- unless response.code == HTTP_STATUS_OK
- raise ResourceFabricationFailedError, "Updating #{self.class.name} using the API failed (#{response.code}) with `#{response}`.\n#{QA::Support::Loglinking.failure_metadata(response.headers[:x_request_id])}"
- end
-
- process_api_response(parse_body(response))
- end
-
- def api_fabrication_http_method
- @api_fabrication_http_method ||= :post
- end
-
# Checks if a resource already exists
#
# @return [Boolean] true if the resource returns HTTP status code 200
@@ -84,14 +69,15 @@ module QA
private
- def resource_web_url(resource)
- resource.fetch(:web_url) do
- raise ResourceURLMissingError, "API resource for #{self.class.name} does not expose a `web_url` property: `#{resource}`."
- end
- end
-
+ # rubocop:disable Gitlab/ModuleWithInstanceVariables
def api_get
- process_api_response(parse_body(api_get_from(api_get_path)))
+ process_api_response(parse_body(api_get_from(api_get_path))).tap do
+ # Record method that was used to create certain resource
+ # :get - resource already existed in GitLab instance and was fetched via get request
+ # :post - resource was created from scratch using post request
+ # :put - resource was created from scratch using put request
+ @api_fabrication_http_method ||= :get
+ end
end
def api_get_from(get_path)
@@ -100,27 +86,24 @@ module QA
response = get(request.url)
if response.code == HTTP_STATUS_SERVER_ERROR
- raise InternalServerError, "Failed to GET #{request.mask_url} - (#{response.code}): `#{response}`.\n#{QA::Support::Loglinking.failure_metadata(response.headers[:x_request_id])}"
+ raise(InternalServerError, <<~MSG.strip)
+ Failed to GET #{request.mask_url} - (#{response.code}): `#{response}`.
+ #{QA::Support::Loglinking.failure_metadata(response.headers[:x_request_id])}
+ MSG
elsif response.code != HTTP_STATUS_OK
- raise ResourceNotFoundError, "Resource at #{request.mask_url} could not be found (#{response.code}): `#{response}`.\n#{QA::Support::Loglinking.failure_metadata(response.headers[:x_request_id])}"
+ raise(ResourceNotFoundError, <<~MSG.strip)
+ Resource at #{request.mask_url} could not be found (#{response.code}): `#{response}`.
+ #{QA::Support::Loglinking.failure_metadata(response.headers[:x_request_id])}
+ MSG
end
- @api_fabrication_http_method ||= :get # rubocop:disable Gitlab/ModuleWithInstanceVariables
-
response
end
- # Query parameters formatted as `?key1=value1&key2=value2...`
- #
- # @return [String]
- def query_parameters_to_string
- query_parameters.each_with_object([]) do |(k, v), arr|
- arr << "#{k}=#{v}"
- end.join('&').prepend('?').chomp('?') # prepend `?` unless the string is blank
- end
-
def api_post
- process_api_response(api_post_to(api_post_path, api_post_body))
+ process_api_response(api_post_to(api_post_path, api_post_body)).tap do
+ @api_fabrication_http_method ||= :post
+ end
end
def api_post_to(post_path, post_body, args = {})
@@ -131,7 +114,7 @@ module QA
body = flatten_hash(parse_body(graphql_response))
unless graphql_response.code == HTTP_STATUS_OK && (body[:errors].nil? || body[:errors].empty?)
- raise(ResourceFabricationFailedError, <<~MSG)
+ raise(ResourceFabricationFailedError, <<~MSG.strip)
Fabrication of #{self.class.name} using the API failed (#{graphql_response.code}) with `#{graphql_response}`.
#{QA::Support::Loglinking.failure_metadata(graphql_response.headers[:x_request_id])}
MSG
@@ -144,36 +127,64 @@ module QA
response = post(Runtime::API::Request.new(api_client, post_path).url, post_body, args)
unless response.code == HTTP_STATUS_CREATED
- raise(
- ResourceFabricationFailedError,
- "Fabrication of #{self.class.name} using the API failed (#{response.code}) with `#{response}`.\n#{QA::Support::Loglinking.failure_metadata(response.headers[:x_request_id])}"
- )
+ raise(ResourceFabricationFailedError, <<~MSG.strip)
+ Fabrication of #{self.class.name} using the API failed (#{response.code}) with `#{response}`.
+ #{QA::Support::Loglinking.failure_metadata(response.headers[:x_request_id])}
+ MSG
end
parse_body(response)
end
end
- def flatten_hash(param)
- param.each_pair.reduce({}) do |a, (k, v)|
- v.is_a?(Hash) ? a.merge(flatten_hash(v)) : a.merge(k.to_sym => v)
+ def api_put
+ process_api_response(api_put_to(api_put_path, api_put_body)).tap do
+ @api_fabrication_http_method ||= :put
end
end
+ def api_put_to(put_path, body)
+ response = put(Runtime::API::Request.new(api_client, put_path).url, body)
+
+ unless response.code == HTTP_STATUS_OK
+ raise(ResourceFabricationFailedError, <<~MSG.strip)
+ Updating #{self.class.name} using the API failed (#{response.code}) with `#{response}`.
+ #{QA::Support::Loglinking.failure_metadata(response.headers[:x_request_id])}
+ MSG
+ end
+
+ parse_body(response)
+ end
+
def api_delete
request = Runtime::API::Request.new(api_client, api_delete_path)
response = delete(request.url)
unless [HTTP_STATUS_NO_CONTENT, HTTP_STATUS_ACCEPTED].include? response.code
- raise ResourceNotDeletedError, "Resource at #{request.mask_url} could not be deleted (#{response.code}): `#{response}`.\n#{QA::Support::Loglinking.failure_metadata(response.headers[:x_request_id])}"
+ raise(ResourceNotDeletedError, <<~MSG.strip)
+ Resource at #{request.mask_url} could not be deleted (#{response.code}): `#{response}`.
+ #{QA::Support::Loglinking.failure_metadata(response.headers[:x_request_id])}
+ MSG
end
response
end
+ def resource_web_url(resource)
+ resource.fetch(:web_url) do
+ raise ResourceURLMissingError,
+ "API resource for #{self.class.name} does not expose a `web_url` property: `#{resource}`."
+ end
+ end
+
def api_client
- @api_client ||= Runtime::API::Client.new(:gitlab, is_new_session: !current_url.start_with?('http'), user: api_user)
+ @api_client ||= Runtime::API::Client.new(
+ :gitlab,
+ is_new_session: !current_url.start_with?('http'),
+ user: api_user
+ )
end
+ # rubocop:enable Gitlab/ModuleWithInstanceVariables
def process_api_response(parsed_response)
self.api_response = parsed_response
@@ -191,6 +202,21 @@ module QA
def request_url(path, **opts)
Runtime::API::Request.new(api_client, path, **opts).url
end
+
+ # Query parameters formatted as `?key1=value1&key2=value2...`
+ #
+ # @return [String]
+ def query_parameters_to_string
+ query_parameters.each_with_object([]) do |(k, v), arr|
+ arr << "#{k}=#{v}"
+ end.join('&').prepend('?').chomp('?') # prepend `?` unless the string is blank
+ end
+
+ def flatten_hash(param)
+ param.each_pair.reduce({}) do |a, (k, v)|
+ v.is_a?(Hash) ? a.merge(flatten_hash(v)) : a.merge(k.to_sym => v)
+ end
+ end
end
end
end
diff --git a/qa/qa/resource/base.rb b/qa/qa/resource/base.rb
index 2abe1904c92..6c03f45bdfd 100644
--- a/qa/qa/resource/base.rb
+++ b/qa/qa/resource/base.rb
@@ -45,7 +45,7 @@ module QA
resource = options.fetch(:resource) { new }
parents = options.fetch(:parents) { [] }
- do_fabricate!(resource: resource, prepare_block: prepare_block, parents: parents) do
+ do_fabricate!(resource: resource, prepare_block: prepare_block) do
log_and_record_fabrication(:browser_ui, resource, parents, args) { resource.fabricate!(*args) }
current_url
@@ -61,7 +61,7 @@ module QA
resource.eager_load_api_client!
- do_fabricate!(resource: resource, prepare_block: prepare_block, parents: parents) do
+ do_fabricate!(resource: resource, prepare_block: prepare_block) do
log_and_record_fabrication(:api, resource, parents, args) { resource.fabricate_via_api! }
end
end
@@ -73,14 +73,14 @@ module QA
resource.eager_load_api_client!
- do_fabricate!(resource: resource, prepare_block: prepare_block, parents: parents) do
+ do_fabricate!(resource: resource, prepare_block: prepare_block) do
log_and_record_fabrication(:api, resource, parents, args) { resource.remove_via_api! }
end
end
private
- def do_fabricate!(resource:, prepare_block:, parents: [])
+ def do_fabricate!(resource:, prepare_block:)
prepare_block.call(resource) if prepare_block
resource_web_url = yield
@@ -89,17 +89,12 @@ module QA
resource
end
- def log_and_record_fabrication(fabrication_method, resource, parents, args)
+ def log_and_record_fabrication(fabrication_method, resource, parents, _args)
start = Time.now
Support::FabricationTracker.start_fabrication
result = yield.tap do
fabrication_time = Time.now - start
- fabrication_http_method = if resource.api_fabrication_http_method == :get || resource.retrieved_from_cache
- "Retrieved"
- else
- "Built"
- end
Support::FabricationTracker.save_fabrication(:"#{fabrication_method}_fabrication", fabrication_time)
@@ -114,7 +109,7 @@ module QA
Runtime::Logger.info do
msg = ["==#{'=' * parents.size}>"]
- msg << "#{fabrication_http_method} a #{Rainbow(name).black.bg(:white)}"
+ msg << "#{fabrication_type(resource, fabrication_method)} a #{Rainbow(name).black.bg(:white)}"
msg << resource.identifier
msg << "as a dependency of #{parents.last}" if parents.any?
msg << "via #{resource.retrieved_from_cache ? 'cache' : fabrication_method}"
@@ -129,6 +124,19 @@ module QA
result
end
+ # Fetch type of fabrication, either resource was built or fetched
+ #
+ # @param [Resource] resource
+ # @param [Symbol] method
+ # @return [String]
+ def fabrication_type(resource, method)
+ return "Built" if method == :browser_ui || [:post, :put].include?(resource.api_fabrication_http_method)
+ return "Retrieved" if resource.api_fabrication_http_method == :get || resource.retrieved_from_cache
+
+ Runtime::Logger.warn("Resource fabrication http method has not been set properly, assuming :get value!")
+ "Built"
+ end
+
# Define custom attribute
#
# @param [Symbol] name
@@ -215,8 +223,7 @@ module QA
def diff(other)
return if self == other
- diff_values = self.comparable.to_a - other.comparable.to_a
- diff_values.to_h
+ (comparable.to_a - other.comparable.to_a).to_h
end
def identifier
@@ -271,7 +278,7 @@ module QA
def all_attributes
@all_attributes ||= self.class.ancestors
.select { |clazz| clazz <= QA::Resource::Base }
- .map { |clazz| clazz.instance_variable_get(:@attribute_names) }
+ .map { |clazz| clazz.instance_variable_get(:@attribute_names) } # rubocop:disable Performance/FlatMap
.flatten
.compact
end
diff --git a/qa/qa/resource/ci_cd_settings.rb b/qa/qa/resource/ci_cd_settings.rb
new file mode 100644
index 00000000000..8240321137b
--- /dev/null
+++ b/qa/qa/resource/ci_cd_settings.rb
@@ -0,0 +1,47 @@
+# rubocop:todo Naming/FileName
+# frozen_string_literal: true
+
+module QA
+ module Resource
+ class CICDSettings < QA::Resource::Base
+ attributes :project_path,
+ :inbound_job_token_scope_enabled
+
+ attribute :mutation_id do
+ SecureRandom.hex(6)
+ end
+
+ def resource_web_url(resource)
+ super
+ rescue ResourceURLMissingError
+ # this particular resource does not expose a web_url property
+ end
+
+ def api_get_path
+ '/graphql'
+ end
+
+ alias_method :api_post_path, :api_get_path
+
+ def api_post_body
+ <<~GQL
+ mutation {
+ projectCiCdSettingsUpdate(input: {
+ clientMutationId: "#{mutation_id}"
+ inboundJobTokenScopeEnabled: #{inbound_job_token_scope_enabled}
+ fullPath: "#{project_path}"
+ })
+ {
+ ciCdSettings {
+ inboundJobTokenScopeEnabled
+ }
+ errors
+ }
+ }
+ GQL
+ end
+ end
+ end
+end
+
+# rubocop:enable Naming/FileName
diff --git a/qa/qa/resource/integrations/web_hook/smockerable.rb b/qa/qa/resource/integrations/web_hook/smockerable.rb
new file mode 100644
index 00000000000..f1d2022477e
--- /dev/null
+++ b/qa/qa/resource/integrations/web_hook/smockerable.rb
@@ -0,0 +1,41 @@
+# frozen_string_literal: true
+
+module QA
+ module Resource
+ module Integrations
+ module WebHook
+ module Smockerable
+ def teardown!
+ Service::DockerRun::Smocker.teardown!
+ end
+
+ def setup(mock = Vendor::Smocker::SmockerApi::DEFAULT_MOCK, session: nil, **event_args)
+ Service::DockerRun::Smocker.init(wait: 10) do |smocker|
+ smocker.register(mock, session: session)
+
+ webhook = fabricate_via_api! do |hook|
+ hook.url = smocker.url
+
+ event_args.each do |event, bool|
+ hook.send("#{event}_events=", bool)
+ end
+
+ hook
+ end
+
+ def smocker.events(session_id = nil)
+ history(session_id).map do |history_response|
+ history_response.request.fetch(:body, {})
+ end
+ end
+
+ yield(webhook, smocker)
+
+ smocker.reset
+ end
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/qa/qa/resource/project_web_hook.rb b/qa/qa/resource/project_web_hook.rb
index 86e662932e1..c8b6c2a6332 100644
--- a/qa/qa/resource/project_web_hook.rb
+++ b/qa/qa/resource/project_web_hook.rb
@@ -2,7 +2,17 @@
module QA
module Resource
- class ProjectWebHook < Base
+ class ProjectWebHook < WebHookBase
+ extend Integrations::WebHook::Smockerable
+
+ attributes :disabled_until, :alert_status
+
+ attribute :project do
+ Project.fabricate_via_api! do |resource|
+ resource.name = 'project-with-webhooks'
+ end
+ end
+
EVENT_TRIGGERS = %i[
issues
job
@@ -10,24 +20,13 @@ module QA
note
pipeline
push
+ releases
tag_push
wiki_page
confidential_issues
confidential_note
].freeze
- attr_accessor :url, :enable_ssl
-
- attribute :disabled_until
- attribute :id
- attribute :alert_status
-
- attribute :project do
- Project.fabricate_via_api! do |resource|
- resource.name = 'project-with-webhooks'
- end
- end
-
EVENT_TRIGGERS.each do |trigger|
attribute "#{trigger}_events".to_sym do
false
@@ -35,18 +34,13 @@ module QA
end
def initialize
- @id = nil
- @enable_ssl = false
- @alert_status = nil
- @url = nil
- end
+ super
- def fabricate_via_api!
- resource_web_url = super
-
- @id = api_response[:id]
+ @push_events_branch_filter = []
+ end
- resource_web_url
+ def add_push_event_branch_filter(branch)
+ @push_events_branch_filter << branch
end
def resource_web_url(resource)
@@ -65,7 +59,9 @@ module QA
body = {
id: project.id,
url: url,
- enable_ssl_verification: enable_ssl
+ enable_ssl_verification: enable_ssl_verification,
+ token: token,
+ push_events_branch_filter: @push_events_branch_filter.join(',')
}
EVENT_TRIGGERS.each_with_object(body) do |trigger, memo|
attr = "#{trigger}_events"
diff --git a/qa/qa/resource/runner_base.rb b/qa/qa/resource/runner_base.rb
index 399d1153dc2..9e38ba9ab64 100644
--- a/qa/qa/resource/runner_base.rb
+++ b/qa/qa/resource/runner_base.rb
@@ -35,7 +35,6 @@ module QA
@config = nil
@run_untagged = nil
@name = "qa-runner-#{SecureRandom.hex(4)}"
- @image = 'registry.gitlab.com/gitlab-org/gitlab-runner:alpine-v15.8.3'
@executor = :shell
@executor_image = 'registry.gitlab.com/gitlab-org/gitlab-build-images:gitlab-qa-alpine-ruby-2.7'
end
@@ -95,6 +94,8 @@ module QA
def start_container_and_register
@docker_container ||= Service::DockerRun::GitlabRunner.new(name).tap do |runner|
+ runner.image = image if image
+
Support::Retrier.retry_on_exception(sleep_interval: 5) do
runner.pull
end
@@ -102,7 +103,6 @@ module QA
runner.token = token
runner.address = Runtime::Scenario.gitlab_address
runner.tags = tags if tags
- runner.image = image
runner.config = config if config
runner.executor = executor
runner.executor_image = executor_image if executor == :docker
diff --git a/qa/qa/resource/snippet.rb b/qa/qa/resource/snippet.rb
index a79e8c7de6b..84711075442 100644
--- a/qa/qa/resource/snippet.rb
+++ b/qa/qa/resource/snippet.rb
@@ -22,9 +22,7 @@ module QA
end
def fabricate!
- Page::Main::Menu.perform do |menu|
- menu.go_to_menu_dropdown_option(:snippets_link)
- end
+ Page::Main::Menu.perform(&:go_to_snippets)
Page::Dashboard::Snippet::Index.perform(&:go_to_new_snippet_page)
diff --git a/qa/qa/resource/web_hook_base.rb b/qa/qa/resource/web_hook_base.rb
new file mode 100644
index 00000000000..d7469466212
--- /dev/null
+++ b/qa/qa/resource/web_hook_base.rb
@@ -0,0 +1,46 @@
+# frozen_string_literal: true
+
+module QA
+ module Resource
+ class WebHookBase < Base
+ attributes :id, :url
+
+ attribute :token do
+ nil
+ end
+
+ attribute :enable_ssl_verification do
+ false
+ end
+
+ def fabricate_via_api!
+ resource_web_url = super
+
+ @id = api_response[:id]
+
+ resource_web_url
+ end
+
+ # @return [String] the api path to fetch the resource
+ def api_get_path
+ raise NotImplementedError, not_implemented_message(__callee__)
+ end
+
+ # @return [String] the api path to create the resource
+ def api_post_path
+ raise NotImplementedError, not_implemented_message(__callee__)
+ end
+
+ # @return [Hash] the payload needed to create the resource
+ def api_post_body
+ raise NotImplementedError, not_implemented_message(__callee__)
+ end
+
+ private
+
+ def not_implemented_message(callee)
+ "#{self.class} must implement ##{callee}"
+ end
+ end
+ end
+end
diff --git a/qa/qa/runtime/allure_report.rb b/qa/qa/runtime/allure_report.rb
index a9152a5555c..e726f7a316f 100644
--- a/qa/qa/runtime/allure_report.rb
+++ b/qa/qa/runtime/allure_report.rb
@@ -25,11 +25,8 @@ module QA
#
# @return [void]
def configure_allure
- # Match job names like ee:relative, ce:update etc. and set as execution environment
- env_matcher = /^(?<env>\w{2}:\S+)/
-
AllureRspec.configure do |config|
- config.results_directory = 'tmp/allure-results'
+ config.results_directory = ENV['QA_ALLURE_RESULTS_DIRECTORY'] || 'tmp/allure-results'
config.clean_results_directory = true
# automatically attach links to testcases and issues
@@ -38,11 +35,11 @@ module QA
config.issue_tag = :issue
config.link_issue_pattern = '{}'
- config.environment_properties = environment_info if Env.running_in_ci?
-
- # Set custom environment name to separate same specs executed on different environments
- if Env.running_in_ci? && Env.ci_job_name.match?(env_matcher)
- config.environment = Env.ci_job_name.match(env_matcher).named_captures['env']
+ if Env.running_in_ci?
+ config.environment_properties = environment_info
+ # Set custom environment name to separate same specs executed in different jobs
+ # Drop number postfixes from parallel jobs by only matching non whitespace characters
+ config.environment = Env.ci_job_name.match(/^\S+/)[0]
end
end
end
@@ -77,7 +74,7 @@ module QA
config.add_formatter(QA::Support::Formatters::AllureMetadataFormatter)
config.add_formatter(AllureRspecFormatter)
- config.append_after do |example|
+ config.append_after do
Allure.add_attachment(
name: 'browser.log',
source: Capybara.current_session.driver.browser.logs.get(:browser).map(&:to_s).join("\n\n"),
@@ -92,7 +89,7 @@ module QA
#
# @return [Hash]
def environment_info
- lambda do
+ -> do
return {} unless Env.admin_personal_access_token || Env.personal_access_token
client = Env.admin_personal_access_token ? API::Client.as_admin : API::Client.new
diff --git a/qa/qa/runtime/browser.rb b/qa/qa/runtime/browser.rb
index f01657c8deb..945823fb9c0 100644
--- a/qa/qa/runtime/browser.rb
+++ b/qa/qa/runtime/browser.rb
@@ -172,6 +172,7 @@ module QA
}
if QA::Runtime::Env.remote_grid
+ selenium_options[:browser] = :remote
selenium_options[:url] = QA::Runtime::Env.remote_grid
capabilities[:browserVersion] = 'latest'
capabilities['sauce:options'] = { tunnelIdentifier: QA::Runtime::Env.remote_tunnel_id }
diff --git a/qa/qa/runtime/env.rb b/qa/qa/runtime/env.rb
index b53c2320537..810912c7ccf 100644
--- a/qa/qa/runtime/env.rb
+++ b/qa/qa/runtime/env.rb
@@ -376,13 +376,13 @@ module QA
# Specifies the token that can be used for the GitHub API
def github_access_token
- ENV['GITHUB_ACCESS_TOKEN'].to_s.strip
+ ENV['QA_GITHUB_ACCESS_TOKEN'].to_s.strip
end
def require_github_access_token!
return unless github_access_token.empty?
- raise ArgumentError, "Please provide GITHUB_ACCESS_TOKEN"
+ raise ArgumentError, "Please provide QA_GITHUB_ACCESS_TOKEN"
end
def require_admin_access_token!
@@ -463,6 +463,16 @@ module QA
enabled?(ENV['QA_SAVE_TEST_METRICS'], default: false)
end
+ def ee_license
+ return ENV["QA_EE_LICENSE"] if ENV["QA_EE_LICENSE"]
+
+ ENV["EE_LICENSE"].tap do |license|
+ next unless license
+
+ Runtime::Logger.warn("EE_LICENSE environment variable is deprecated, please use QA_EE_LICENSE instead!")
+ end
+ end
+
def ee_activation_code
ENV['QA_EE_ACTIVATION_CODE']
end
@@ -514,6 +524,10 @@ module QA
ENV['DEFAULT_CHROME_DOWNLOAD_PATH'] || Dir.tmpdir
end
+ def super_sidebar_enabled?
+ enabled?(ENV['QA_SUPER_SIDEBAR_ENABLED'], default: false)
+ end
+
def require_slack_env!
missing_env = %i[slack_workspace slack_email slack_password].select do |method|
::QA::Runtime::Env.public_send(method).nil?
diff --git a/qa/qa/service/cluster_provider/gcloud.rb b/qa/qa/service/cluster_provider/gcloud.rb
index 749ebca8897..d33ae4915b5 100644
--- a/qa/qa/service/cluster_provider/gcloud.rb
+++ b/qa/qa/service/cluster_provider/gcloud.rb
@@ -33,8 +33,7 @@ module QA
delete_cluster
end
- # kas is hardcoded to staging since this test should only run in staging for now
- def install_kubernetes_agent(agent_token)
+ def install_kubernetes_agent(agent_token:, kas_address:)
install_helm
shell <<~CMD.tr("\n", ' ')
@@ -45,7 +44,8 @@ module QA
--create-namespace
--set image.tag=#{Runtime::Env.gitlab_agentk_version}
--set config.token=#{agent_token}
- --set config.kasAddress=wss://kas.staging.gitlab.com
+ --set config.kasAddress=#{kas_address}
+ --set config.kasHeaders="{Cookie: gitlab_canary=#{target_canary?}}"
CMD
end
@@ -59,6 +59,10 @@ module QA
CMD
end
+ def target_canary?
+ Runtime::Env.qa_cookies.to_s.include?("gitlab_canary=true")
+ end
+
def login_if_not_already_logged_in
if Runtime::Env.has_gcloud_credentials?
attempt_login_with_env_vars
diff --git a/qa/qa/service/docker_run/gitlab_runner.rb b/qa/qa/service/docker_run/gitlab_runner.rb
index a8fcf8f9332..d40517ae535 100644
--- a/qa/qa/service/docker_run/gitlab_runner.rb
+++ b/qa/qa/service/docker_run/gitlab_runner.rb
@@ -16,7 +16,7 @@ module QA
MSG
def initialize(name)
- @image = 'gitlab/gitlab-runner:alpine-v15.8.3'
+ @image = 'registry.gitlab.com/gitlab-org/gitlab-runner:alpine'
@name = name || "qa-runner-#{SecureRandom.hex(4)}"
@run_untagged = true
@executor = :shell
diff --git a/qa/qa/service/kubernetes_cluster.rb b/qa/qa/service/kubernetes_cluster.rb
index 5362124bee5..ed57d825643 100644
--- a/qa/qa/service/kubernetes_cluster.rb
+++ b/qa/qa/service/kubernetes_cluster.rb
@@ -5,6 +5,7 @@ require 'mkmf'
module QA
module Service
class KubernetesCluster
+ include Support::API
include Service::Shellout
attr_reader :api_url, :ca_certificate, :token, :rbac, :provider
@@ -36,7 +37,7 @@ module QA
end
def install_kubernetes_agent(agent_token)
- @provider.install_kubernetes_agent(agent_token)
+ @provider.install_kubernetes_agent(agent_token: agent_token, kas_address: fetch_kas_address)
end
def create_secret(secret, secret_name)
@@ -73,6 +74,17 @@ module QA
`kubectl config view --minify -o jsonpath='{.clusters[0].cluster.server}'`
end
+ def fetch_kas_address
+ api_client = Runtime::API::Client.new(:gitlab)
+
+ Support::Retrier.retry_until do
+ response = get(Runtime::API::Request.new(api_client, '/metadata').url)
+ body = parse_body(response)
+
+ body.dig(:kas, :externalUrl) || raise("Failed to fetch KAS address from #{body}")
+ end
+ end
+
def fetch_credentials
return global_credentials unless rbac
diff --git a/qa/qa/specs/features/api/1_manage/import/import_github_repo_spec.rb b/qa/qa/specs/features/api/1_manage/import/import_github_repo_spec.rb
index 9017aba8e4a..407e479bda2 100644
--- a/qa/qa/specs/features/api/1_manage/import/import_github_repo_spec.rb
+++ b/qa/qa/specs/features/api/1_manage/import/import_github_repo_spec.rb
@@ -1,12 +1,7 @@
# frozen_string_literal: true
module QA
- # https://github.com/gitlab-qa-github/import-test <- project under test
- #
- RSpec.describe 'Manage', product_group: :import, quarantine: {
- issue: 'https://gitlab.com/gitlab-org/gitlab/-/issues/391228',
- type: :waiting_on
- } do
+ RSpec.describe 'Manage', product_group: :import do
describe 'GitHub import' do
include_context 'with github import'
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 8439b881ed7..a6cdd737341 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
@@ -2,78 +2,57 @@
module QA
RSpec.describe 'Manage' do
- describe 'WebHooks integration', :requires_admin, :integrations, :orchestrated, product_group: :integrations do
+ describe(
+ 'WebHooks integration',
+ :requires_admin,
+ :integrations,
+ :orchestrated,
+ product_group: :integrations
+ ) do
before(:context) do
toggle_local_requests(true)
end
after(:context) do
- Service::DockerRun::Smocker.teardown!
+ Resource::ProjectWebHook.teardown!
end
let(:session) { SecureRandom.hex(5) }
let(:tag_name) { SecureRandom.hex(5) }
it 'sends a push event', testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/348945' do
- setup_webhook(push: true) do |webhook, smocker|
+ Resource::ProjectWebHook.setup(session: session, push: true) do |webhook, smocker|
Resource::Repository::ProjectPush.fabricate! do |project_push|
project_push.project = webhook.project
end
- wait_until do
- !smocker.history(session).empty?
- end
-
- events = smocker.history(session).map(&:as_hook_event)
- aggregate_failures do
- expect(events.size).to be(1), "Should have 1 event: \n#{events.map(&:raw).join("\n")}"
- expect(events[0].project_name).to eql(webhook.project.name)
- expect(events[0].push?).to be(true), "Not push event: \n#{events[0].raw}"
- end
+ expect_web_hook_single_event_success(webhook, smocker, type: 'push')
end
end
it 'sends a merge request event', testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/349720' do
- setup_webhook(merge_requests: true) do |webhook, smocker|
+ Resource::ProjectWebHook.setup(session: session, merge_requests: true) do |webhook, smocker|
Resource::MergeRequest.fabricate_via_api! do |merge_request|
merge_request.project = webhook.project
end
- wait_until do
- !smocker.history(session).empty?
- end
-
- events = smocker.history(session).map(&:as_hook_event)
- aggregate_failures do
- expect(events.size).to be(1), "Should have 1 event: \n#{events.map(&:raw).join("\n")}"
- expect(events[0].project_name).to eql(webhook.project.name)
- expect(events[0].mr?).to be(true), "Not MR event: \n#{events[0].raw}"
- end
+ expect_web_hook_single_event_success(webhook, smocker, type: 'merge_request')
end
end
it 'sends a wiki page event', testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/349722' do
- setup_webhook(wiki_page: true) do |webhook, smocker|
+ Resource::ProjectWebHook.setup(session: session, wiki_page: true) do |webhook, smocker|
Resource::Wiki::ProjectPage.fabricate_via_api! do |page|
page.project = webhook.project
end
- wait_until do
- !smocker.history(session).empty?
- end
-
- events = smocker.history(session).map(&:as_hook_event)
- aggregate_failures do
- expect(events.size).to be(1), "Should have 1 event: \n#{events.map(&:raw).join("\n")}"
- expect(events[0].project_name).to eql(webhook.project.name)
- expect(events[0].wiki?).to be(true), "Not wiki event: \n#{events[0].raw}"
- end
+ expect_web_hook_single_event_success(webhook, smocker, type: 'wiki_page')
end
end
it 'sends an issues and note event',
testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/349723' do
- setup_webhook(issues: true, note: true) do |webhook, smocker|
+ Resource::ProjectWebHook.setup(session: session, issues: true, note: true) do |webhook, smocker|
issue = Resource::Issue.fabricate_via_api! do |issue_init|
issue_init.project = webhook.project
end
@@ -83,25 +62,24 @@ module QA
note.issue = issue
end
- wait_until do
- smocker.history(session).size > 1
- end
+ expect { smocker.events(session).size }.to eventually_eq(2)
+ .within(max_duration: 30, sleep_interval: 2),
+ -> { "Should have 2 events, got: #{smocker.stringified_history(session)}" }
- events = smocker.history(session).map(&:as_hook_event)
- aggregate_failures do
- issue_event = events.find(&:issue?)
- note_event = events.find(&:note?)
+ events = smocker.events(session)
- expect(events.size).to be(2), "Should have 2 events: \n#{events.map(&:raw).join("\n")}"
- expect(issue_event).not_to be(nil), "Not issue event: \n#{events[0].raw}"
- expect(note_event).not_to be(nil), "Not note event: \n#{events[1].raw}"
+ aggregate_failures do
+ expect(events).to include(
+ a_hash_including(object_kind: 'note'),
+ a_hash_including(object_kind: 'issue')
+ )
end
end
end
it 'sends a tag event',
testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/383577' do
- setup_webhook(tag_push: true) do |webhook, smocker|
+ Resource::ProjectWebHook.setup(session: session, tag_push: true) do |webhook, smocker|
project_push = Resource::Repository::ProjectPush.fabricate! do |project_push|
project_push.project = webhook.project
end
@@ -112,16 +90,7 @@ module QA
tag.name = tag_name
end
- wait_until do
- smocker.history(session).size == 1
- end
-
- events = smocker.history(session).map(&:as_hook_event)
- aggregate_failures do
- expect(events.size).to be(1), "Should have 1 event: \n#{events.map(&:raw).join("\n")}"
- expect(events[0].project_name).to eql(webhook.project.name)
- expect(events[0].tag?).to be(true), "Not tag event: \n#{events[0].raw}"
- end
+ expect_web_hook_single_event_success(webhook, smocker, type: 'tag_push')
end
end
@@ -144,16 +113,19 @@ module QA
it 'hook is auto-disabled',
testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/389595' do
- setup_webhook(fail_mock, issues: true) do |webhook, smocker|
+ 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|
issue_init.project = webhook.project
end
+
+ # using sleep to give rate limiter a chance to activate.
+ sleep 0.5
end
- expect { smocker.history(session).size }.to eventually_eq(disabled_after)
+ expect { smocker.events(session).size }.to eventually_eq(disabled_after)
.within(max_duration: 30, sleep_interval: 2),
- -> { "Should have #{disabled_after} events, got: #{smocker.history(session).size}" }
+ -> { "Should have #{disabled_after} events, got: #{smocker.events(session).size}" }
webhook.reload!
@@ -161,34 +133,27 @@ module QA
end
end
end
+ end
- private
-
- def setup_webhook(mock = Vendor::Smocker::SmockerApi::DEFAULT_MOCK, **event_args)
- Service::DockerRun::Smocker.init(wait: 10) do |smocker|
- smocker.register(mock, session: session)
-
- webhook = Resource::ProjectWebHook.fabricate_via_api! do |hook|
- hook.url = smocker.url
-
- event_args.each do |event, bool|
- hook.send("#{event}_events=", bool)
- end
- end
+ private
- yield(webhook, smocker)
+ def expect_web_hook_single_event_success(webhook, smocker, type:)
+ expect { smocker.events(session).size }.to eventually_eq(1)
+ .within(max_duration: 30, sleep_interval: 2),
+ -> { "Should have 1 events, got: #{smocker.stringified_history(session)}" }
- smocker.reset
- end
- end
+ event = smocker.events(session).first
- def toggle_local_requests(on)
- Runtime::ApplicationSettings.set_application_settings(allow_local_requests_from_web_hooks_and_services: on)
+ aggregate_failures do
+ expect(event).to match(a_hash_including(
+ object_kind: type,
+ project: a_hash_including(name: webhook.project.name)
+ ))
end
+ end
- def wait_until(timeout = 120, &block)
- Support::Waiter.wait_until(max_duration: timeout, reload_page: false, raise_on_failure: false, &block)
- end
+ def toggle_local_requests(on)
+ Runtime::ApplicationSettings.set_application_settings(allow_local_requests_from_web_hooks_and_services: on)
end
end
end
diff --git a/qa/qa/specs/features/api/1_manage/migration/gitlab_migration_issue_spec.rb b/qa/qa/specs/features/api/1_manage/migration/gitlab_migration_issue_spec.rb
index 2dcbbadb4aa..bc057f948a8 100644
--- a/qa/qa/specs/features/api/1_manage/migration/gitlab_migration_issue_spec.rb
+++ b/qa/qa/specs/features/api/1_manage/migration/gitlab_migration_issue_spec.rb
@@ -15,7 +15,7 @@ module QA
let(:source_issue_comments) do
source_issue.comments.map do |note|
- { **note.except(:id, :noteable_id), author: note[:author].except(:web_url) }
+ { **note.except(:id, :noteable_id, :project_id), author: note[:author].except(:web_url) }
end
end
@@ -32,7 +32,7 @@ module QA
let(:imported_issue_comments) do
imported_issue.comments.map do |note|
- { **note.except(:id, :noteable_id), author: note[:author].except(:web_url) }
+ { **note.except(:id, :noteable_id, :project_id), author: note[:author].except(:web_url) }
end
end
@@ -67,11 +67,7 @@ module QA
it(
'preserves related merge request',
- testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/386305',
- quarantine: {
- type: :bug,
- issue: 'https://gitlab.com/gitlab-org/gitlab/-/issues/386308'
- }
+ testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/386305'
) do
expect_project_import_finished_successfully
expect(imported_related_mrs).to eq([source_mr.iid])
diff --git a/qa/qa/specs/features/api/1_manage/migration/gitlab_migration_large_project_spec.rb b/qa/qa/specs/features/api/1_manage/migration/gitlab_migration_large_project_spec.rb
index 9ce028318c3..d01adb5d5b4 100644
--- a/qa/qa/specs/features/api/1_manage/migration/gitlab_migration_large_project_spec.rb
+++ b/qa/qa/specs/features/api/1_manage/migration/gitlab_migration_large_project_spec.rb
@@ -65,10 +65,6 @@ module QA
let(:mrs) { fetch_mrs(imported_project, api_client) }
let(:issues) { fetch_issues(imported_project, api_client) }
- before do
- Runtime::Feature.enable(:bulk_import_projects) unless Runtime::Feature.enabled?(:bulk_import_projects)
- end
-
# rubocop:disable RSpec/InstanceVariable
after do |example|
next unless defined?(@import_time)
diff --git a/qa/qa/specs/features/api/1_manage/migration/gitlab_migration_mr_spec.rb b/qa/qa/specs/features/api/1_manage/migration/gitlab_migration_mr_spec.rb
index 127db36052f..8c20c2cc0e2 100644
--- a/qa/qa/specs/features/api/1_manage/migration/gitlab_migration_mr_spec.rb
+++ b/qa/qa/specs/features/api/1_manage/migration/gitlab_migration_mr_spec.rb
@@ -37,7 +37,7 @@ module QA
let!(:source_mr_approvers) { [source_admin_user.email] }
let(:source_mr_comments) do
source_mr.comments.map do |note|
- { **note.except(:id, :noteable_id), author: note[:author].except(:web_url) }
+ { **note.except(:id, :noteable_id, :project_id), author: note[:author].except(:web_url) }
end
end
@@ -52,11 +52,11 @@ module QA
let(:imported_mr_comments) do
imported_mr.comments.map do |note|
- { **note.except(:id, :noteable_id), author: note[:author].except(:web_url) }
+ { **note.except(:id, :noteable_id, :project_id), author: note[:author].except(:web_url) }
end
end
- let(:imported_mr_reviewers) { imported_mr.reviewers.map { |reviewer| reviewer[:username] } }
+ let(:imported_mr_reviewers) { imported_mr.reviewers.pluck(:username) }
let(:imported_mr_approvers) do
imported_mr.approval_configuration[:approved_by].map { |usr| usr.dig(:user, :username) }
end
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 60ece89844d..43701a6b740 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', :reliable, 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/1_manage/user_inherited_access_spec.rb b/qa/qa/specs/features/api/1_manage/user_inherited_access_spec.rb
index 124b6c9cd44..c50eb2f4fdf 100644
--- a/qa/qa/specs/features/api/1_manage/user_inherited_access_spec.rb
+++ b/qa/qa/specs/features/api/1_manage/user_inherited_access_spec.rb
@@ -79,19 +79,24 @@ module QA
'is allowed to commit to sub-group project via the API',
testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/363349'
) do
- expect do
- Resource::Repository::Commit.fabricate_via_api! do |commit|
- commit.api_client = parent_group_user_api_client
- commit.project = sub_group_project
- commit.branch = "new_branch_#{SecureRandom.hex(8)}"
- commit.start_branch = sub_group_project.default_branch
- commit.commit_message = 'Add new file'
- commit.add_files([{ file_path: 'test.txt', content: 'new file' }])
- end
- rescue StandardError => e
- QA::Runtime::Logger.error("Full failure message: #{e.message}")
- raise
- end.not_to raise_error
+ # Retry is needed due to delays with project authorization updates
+ # Long term solution to accessing the status of a project authorization update
+ # has been proposed in https://gitlab.com/gitlab-org/gitlab/-/issues/393369
+ QA::Support::Retrier.retry_on_exception(max_attempts: 5, sleep_interval: 2) do
+ expect do
+ Resource::Repository::Commit.fabricate_via_api! do |commit|
+ commit.api_client = parent_group_user_api_client
+ commit.project = sub_group_project
+ commit.branch = "new_branch_#{SecureRandom.hex(8)}"
+ commit.start_branch = sub_group_project.default_branch
+ commit.commit_message = 'Add new file'
+ commit.add_files([{ file_path: 'test.txt', content: 'new file' }])
+ end
+ rescue StandardError => e
+ QA::Runtime::Logger.error("Full failure message: #{e.message}")
+ raise
+ end.not_to raise_error
+ end
end
after do
diff --git a/qa/qa/specs/features/api/3_create/repository/files_spec.rb b/qa/qa/specs/features/api/3_create/repository/files_spec.rb
index 71bd03fab17..7e329371745 100644
--- a/qa/qa/specs/features/api/3_create/repository/files_spec.rb
+++ b/qa/qa/specs/features/api/3_create/repository/files_spec.rb
@@ -99,7 +99,6 @@ module QA
#
expect(response.headers[:cache_control]).to include("no-store")
expect(response.headers[:cache_control]).to include("no-cache")
- expect(response.headers[:pragma]).to eq("no-cache")
expect(response.headers[:expires]).to eq("Fri, 01 Jan 1990 00:00:00 GMT")
expect(response.headers[:content_disposition]).to include("attachment")
expect(response.headers[:content_disposition]).not_to include("inline")
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 8890b3ff317..c66bd16afe9 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
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module QA
- RSpec.describe 'Verify', :runner, product_group: :pipeline_authoring do
+ RSpec.describe 'Verify', :runner, product_group: :pipeline_security do
describe 'Pipeline API defined variable inheritance' do
include_context 'variable inheritance test prep'
diff --git a/qa/qa/specs/features/api/4_verify/file_variable_spec.rb b/qa/qa/specs/features/api/4_verify/file_variable_spec.rb
index bd0ec13b1f8..2d9deec399c 100644
--- a/qa/qa/specs/features/api/4_verify/file_variable_spec.rb
+++ b/qa/qa/specs/features/api/4_verify/file_variable_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module QA
- RSpec.describe 'Verify', :runner, product_group: :pipeline_authoring do
+ RSpec.describe 'Verify', :runner, product_group: :pipeline_security do
describe 'Pipeline with project file variables' do
let(:executor) { "qa-runner-#{Faker::Alphanumeric.alphanumeric(number: 8)}" }
diff --git a/qa/qa/specs/features/browser_ui/1_manage/import/import_github_repo_spec.rb b/qa/qa/specs/features/browser_ui/1_manage/import/import_github_repo_spec.rb
index 461928cbf1f..b5a8df15ddc 100644
--- a/qa/qa/specs/features/browser_ui/1_manage/import/import_github_repo_spec.rb
+++ b/qa/qa/specs/features/browser_ui/1_manage/import/import_github_repo_spec.rb
@@ -1,10 +1,7 @@
# frozen_string_literal: true
module QA
- RSpec.describe 'Manage', product_group: :import, quarantine: {
- issue: 'https://gitlab.com/gitlab-org/gitlab/-/issues/391230',
- type: :waiting_on
- } do
+ RSpec.describe 'Manage', product_group: :import do
describe 'GitHub import' do
include_context 'with github import'
diff --git a/qa/qa/specs/features/browser_ui/1_manage/user/follow_user_activity_spec.rb b/qa/qa/specs/features/browser_ui/1_manage/user/follow_user_activity_spec.rb
index 94b383a746d..ac08ecec786 100644
--- a/qa/qa/specs/features/browser_ui/1_manage/user/follow_user_activity_spec.rb
+++ b/qa/qa/specs/features/browser_ui/1_manage/user/follow_user_activity_spec.rb
@@ -82,7 +82,7 @@ module QA
Page::Main::Menu.perform(&:click_user_profile_link)
Page::User::Show.perform do |show|
- show.click_following_link
+ show.click_following_tab
show.click_user_link(followed_user.username)
aggregate_failures do
diff --git a/qa/qa/specs/features/browser_ui/3_create/merge_request/rebase_merge_request_spec.rb b/qa/qa/specs/features/browser_ui/3_create/merge_request/rebase_merge_request_spec.rb
index 236af93716f..349fa054ff0 100644
--- a/qa/qa/specs/features/browser_ui/3_create/merge_request/rebase_merge_request_spec.rb
+++ b/qa/qa/specs/features/browser_ui/3_create/merge_request/rebase_merge_request_spec.rb
@@ -17,11 +17,9 @@ module QA
settings.enable_ff_only
end
- Resource::Repository::ProjectPush.fabricate! do |push|
- push.project = merge_request.project
- push.file_name = "other.txt"
- push.file_content = "New file added!"
- push.new_branch = false
+ Resource::Repository::Commit.fabricate_via_api! do |commit|
+ commit.project = merge_request.project
+ commit.add_files([{ file_path: 'other.txt', content: 'New file added!' }])
end
merge_request.visit!
diff --git a/qa/qa/specs/features/browser_ui/3_create/project_wiki/project_based_content_creation_spec.rb b/qa/qa/specs/features/browser_ui/3_create/project_wiki/project_based_content_creation_spec.rb
index feb0f28763c..2b04ede25b0 100644
--- a/qa/qa/specs/features/browser_ui/3_create/project_wiki/project_based_content_creation_spec.rb
+++ b/qa/qa/specs/features/browser_ui/3_create/project_wiki/project_based_content_creation_spec.rb
@@ -15,7 +15,7 @@ module QA
end
it 'by adding a home page to the wiki',
-testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347809' do
+ testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347809' do
project.visit!
Page::Project::Menu.perform(&:click_wiki)
@@ -36,7 +36,7 @@ testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347809' do
end
it 'by adding a second page to the wiki',
-testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347808' do
+ testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347808' do
wiki.visit!
Page::Project::Wiki::Show.perform(&:click_new_page)
@@ -56,7 +56,7 @@ testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347808' do
end
it 'by adding a home page to the wiki using git push',
-testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347806' do
+ testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347806' do
empty_wiki = Resource::Wiki::ProjectPage.new do |empty_wiki|
empty_wiki.project = project
end
@@ -76,7 +76,7 @@ testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347806' do
end
it 'by adding a second page to the wiki using git push',
-testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347807' do
+ testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347807' do
Resource::Repository::WikiPush.fabricate! do |push|
push.file_name = "#{new_wiki_title}.md"
push.file_content = new_wiki_content
diff --git a/qa/qa/specs/features/browser_ui/3_create/repository/push_mirroring_lfs_over_http_spec.rb b/qa/qa/specs/features/browser_ui/3_create/repository/push_mirroring_lfs_over_http_spec.rb
index 815a8696ff7..b8a018552c6 100644
--- a/qa/qa/specs/features/browser_ui/3_create/repository/push_mirroring_lfs_over_http_spec.rb
+++ b/qa/qa/specs/features/browser_ui/3_create/repository/push_mirroring_lfs_over_http_spec.rb
@@ -1,11 +1,7 @@
# frozen_string_literal: true
module QA
- RSpec.describe 'Create', product_group: :source_code, quarantine: {
- issue: 'https://gitlab.com/gitlab-org/gitlab/-/issues/352525',
- type: :test_environment,
- only: { job: 'review-qa-*' }
- } do
+ RSpec.describe 'Create', product_group: :source_code do
describe 'Push mirror a repository over HTTP' do
it 'configures and syncs LFS objects for a (push) mirrored repository', :aggregate_failures, testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347847' do
Runtime::Browser.visit(:gitlab, Page::Main::Login)
diff --git a/qa/qa/specs/features/browser_ui/3_create/snippet/snippet_index_page_spec.rb b/qa/qa/specs/features/browser_ui/3_create/snippet/snippet_index_page_spec.rb
index 63e9fdbb881..a63c5cefff4 100644
--- a/qa/qa/specs/features/browser_ui/3_create/snippet/snippet_index_page_spec.rb
+++ b/qa/qa/specs/features/browser_ui/3_create/snippet/snippet_index_page_spec.rb
@@ -52,9 +52,7 @@ module QA
shared_examples 'displaying details on index page' do |snippet_type, testcase|
it "shows correct details of #{snippet_type} including file number", testcase: testcase do
send(snippet_type)
- Page::Main::Menu.perform do |menu|
- menu.go_to_menu_dropdown_option(:snippets_link)
- end
+ Page::Main::Menu.perform(&:go_to_snippets)
Page::Dashboard::Snippet::Index.perform do |snippet|
aggregate_failures 'file content verification' do
diff --git a/qa/qa/specs/features/browser_ui/3_create/web_ide/add_file_template_spec.rb b/qa/qa/specs/features/browser_ui/3_create/web_ide/add_file_template_spec.rb
index 6cbbfb9e7e5..cf1e4700863 100644
--- a/qa/qa/specs/features/browser_ui/3_create/web_ide/add_file_template_spec.rb
+++ b/qa/qa/specs/features/browser_ui/3_create/web_ide/add_file_template_spec.rb
@@ -1,12 +1,8 @@
# frozen_string_literal: true
+# TODO: remove this test when 'vscode_web_ide' feature flag is default enabled
module QA
- RSpec.describe 'Create', feature_flag: { name: 'vscode_web_ide', scope: :global },
- product_group: :editor,
- quarantine: {
- issue: 'https://gitlab.com/gitlab-org/gitlab/-/issues/387033',
- type: :stale
- } do
+ RSpec.describe 'Create', :skip_live_env, product_group: :editor do
describe 'Web IDE file templates' do
include Runtime::Fixtures
@@ -16,11 +12,6 @@ module QA
project.description = 'Add file templates via the Web IDE'
project.initialize_with_readme = true
end
- Runtime::Feature.disable(:vscode_web_ide)
- end
-
- after(:all) do
- Runtime::Feature.enable(:vscode_web_ide)
end
templates = [
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 ded1b1c9d7c..e5e3941e0cd 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
@@ -1,10 +1,8 @@
# frozen_string_literal: true
+# TODO: remove this test when 'vscode_web_ide' feature flag is default enabled
module QA
- RSpec.describe 'Create', feature_flag: { name: 'vscode_web_ide', scope: :global }, product_group: :editor, quarantine: {
- issue: 'https://gitlab.com/gitlab-org/gitlab/-/issues/387029',
- type: :stale
- } do
+ RSpec.describe 'Create', :skip_live_env, product_group: :editor do
describe 'Add a directory in Web IDE' do
let(:project) do
Resource::Project.fabricate_via_api! do |project|
@@ -14,15 +12,10 @@ module QA
end
before do
- Runtime::Feature.disable(:vscode_web_ide)
Flow::Login.sign_in
project.visit!
end
- after do
- Runtime::Feature.enable(:vscode_web_ide)
- end
-
context 'when a directory with the same name already exists' do
let(:directory_name) { 'first_directory' }
diff --git a/qa/qa/specs/features/browser_ui/3_create/web_ide/create_first_file_in_web_ide_spec.rb b/qa/qa/specs/features/browser_ui/3_create/web_ide/create_first_file_in_web_ide_spec.rb
index 45499ea1999..58afdfe7cd1 100644
--- a/qa/qa/specs/features/browser_ui/3_create/web_ide/create_first_file_in_web_ide_spec.rb
+++ b/qa/qa/specs/features/browser_ui/3_create/web_ide/create_first_file_in_web_ide_spec.rb
@@ -1,10 +1,8 @@
# frozen_string_literal: true
+# TODO: remove this test when 'vscode_web_ide' feature flag is default enabled
module QA
- RSpec.describe 'Create', feature_flag: { name: 'vscode_web_ide', scope: :global }, product_group: :editor, quarantine: {
- issue: 'https://gitlab.com/gitlab-org/gitlab/-/issues/387723',
- type: :stale
- } do
+ RSpec.describe 'Create', :skip_live_env, product_group: :editor do
describe 'First file using Web IDE' do
let(:project) do
Resource::Project.fabricate_via_api! do |project|
@@ -16,14 +14,9 @@ module QA
let(:file_name) { 'the very first file.txt' }
before do
- Runtime::Feature.disable(:vscode_web_ide)
Flow::Login.sign_in
end
- after do
- Runtime::Feature.enable(:vscode_web_ide)
- end
-
it "creates the first file in an empty project via Web IDE", testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347803' do
project.visit!
Page::Project::Show.perform(&:create_first_new_file!)
diff --git a/qa/qa/specs/features/browser_ui/3_create/web_ide/link_to_line_in_web_ide_spec.rb b/qa/qa/specs/features/browser_ui/3_create/web_ide/link_to_line_in_web_ide_spec.rb
index 3ea87d90c2d..9c40a3abe52 100644
--- a/qa/qa/specs/features/browser_ui/3_create/web_ide/link_to_line_in_web_ide_spec.rb
+++ b/qa/qa/specs/features/browser_ui/3_create/web_ide/link_to_line_in_web_ide_spec.rb
@@ -1,10 +1,8 @@
# frozen_string_literal: true
+# TODO: remove this test when 'vscode_web_ide' feature flag is default enabled
module QA
- RSpec.describe 'Create', feature_flag: { name: 'vscode_web_ide', scope: :global }, product_group: :editor, quarantine: {
- issue: 'https://gitlab.com/gitlab-org/gitlab/-/issues/387035',
- type: :stale
- } do
+ RSpec.describe 'Create', :skip_live_env, product_group: :editor do
describe 'Link to line in Web IDE' do
let(:user) { Resource::User.fabricate_or_use(Runtime::Env.gitlab_qa_username_1, Runtime::Env.gitlab_qa_password_1) }
let(:project) do
@@ -14,12 +12,10 @@ module QA
end
before do
- Runtime::Feature.disable(:vscode_web_ide)
Flow::Login.sign_in
end
after do
- Runtime::Feature.enable(:vscode_web_ide)
project.remove_via_api!
end
diff --git a/qa/qa/specs/features/browser_ui/3_create/web_ide/open_fork_in_web_ide_spec.rb b/qa/qa/specs/features/browser_ui/3_create/web_ide/open_fork_in_web_ide_spec.rb
deleted file mode 100644
index 7195dd5c970..00000000000
--- a/qa/qa/specs/features/browser_ui/3_create/web_ide/open_fork_in_web_ide_spec.rb
+++ /dev/null
@@ -1,84 +0,0 @@
-# frozen_string_literal: true
-
-module QA
- RSpec.describe 'Create', feature_flag: { name: 'vscode_web_ide', scope: :global }, product_group: :editor do
- describe 'Open a fork in Web IDE',
- skip: {
- issue: "https://gitlab.com/gitlab-org/gitlab/-/issues/351696",
- type: :flaky
- } do
- let(:parent_project) do
- Resource::Project.fabricate_via_api! do |project|
- project.name = 'parent-project'
- project.initialize_with_readme = true
- end
- end
-
- before do
- Runtime::Feature.disable(:vscode_web_ide)
- end
-
- after do
- Runtime::Feature.enable(:vscode_web_ide)
- end
-
- context 'when a user does not have permissions to commit to the project' do
- let(:user) { Resource::User.fabricate_or_use(Runtime::Env.gitlab_qa_username_2, Runtime::Env.gitlab_qa_password_2) }
-
- context 'when no fork is present' do
- it 'suggests to create a fork when a user clicks Web IDE in the main project', testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347823' do
- Flow::Login.sign_in(as: user)
-
- parent_project.visit!
- Page::Project::Show.perform(&:open_web_ide!)
-
- Page::Project::WebIDE::Edit.perform(&:fork_project!)
-
- submit_merge_request_upstream
- end
- end
-
- context 'when a fork is already created' do
- let(:fork_project) do
- Resource::Fork.fabricate_via_api! do |fork|
- fork.user = user
- fork.upstream = parent_project
- end
- end
-
- it 'opens the fork when a user clicks Web IDE in the main project', testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347824' do
- Flow::Login.sign_in(as: user)
- fork_project.upstream.visit!
- Page::Project::Show.perform do |project_page|
- expect(project_page).to have_edit_fork_button
-
- project_page.open_web_ide!
- end
-
- submit_merge_request_upstream
- end
-
- after do
- fork_project.project.remove_via_api!
- end
- end
-
- def submit_merge_request_upstream
- Page::Project::WebIDE::Edit.perform do |ide|
- ide.wait_until_ide_loads
- expect(ide).to have_project_path("#{user.username}/#{parent_project.name}")
-
- ide.add_file('new file', 'some random text')
- ide.commit_changes(open_merge_request: true)
- end
-
- Page::MergeRequest::New.perform(&:create_merge_request)
-
- parent_project.visit!
- Page::Project::Menu.perform(&:click_merge_requests)
- expect(page).to have_content('Update new file')
- end
- end
- end
- end
-end
diff --git a/qa/qa/specs/features/browser_ui/3_create/web_ide/open_web_ide_from_diff_tab_spec.rb b/qa/qa/specs/features/browser_ui/3_create/web_ide/open_web_ide_from_diff_tab_spec.rb
index 02d2710656d..bbfc3ba8ccd 100644
--- a/qa/qa/specs/features/browser_ui/3_create/web_ide/open_web_ide_from_diff_tab_spec.rb
+++ b/qa/qa/specs/features/browser_ui/3_create/web_ide/open_web_ide_from_diff_tab_spec.rb
@@ -1,10 +1,8 @@
# frozen_string_literal: true
+# TODO: remove this test when 'vscode_web_ide' feature flag is default enabled
module QA
- RSpec.describe 'Create', feature_flag: { name: 'vscode_web_ide', scope: :global }, product_group: :editor, quarantine: {
- issue: 'https://gitlab.com/gitlab-org/gitlab/-/issues/387031',
- type: :stale
- } do
+ RSpec.describe 'Create', :skip_live_env, product_group: :editor do
describe 'Open Web IDE from Diff Tab' do
files = [
{
@@ -47,15 +45,10 @@ module QA
end
before do
- Runtime::Feature.disable(:vscode_web_ide)
Flow::Login.sign_in
merge_request.visit!
end
- after do
- Runtime::Feature.enable(:vscode_web_ide)
- end
-
it 'opens and edits a multi-file merge request in Web IDE from Diff Tab', testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347724' do
Page::MergeRequest::Show.perform do |show|
show.click_diffs_tab
diff --git a/qa/qa/specs/features/browser_ui/3_create/web_ide/review_merge_request_spec.rb b/qa/qa/specs/features/browser_ui/3_create/web_ide/review_merge_request_spec.rb
index 4c21581781d..05c58b66b09 100644
--- a/qa/qa/specs/features/browser_ui/3_create/web_ide/review_merge_request_spec.rb
+++ b/qa/qa/specs/features/browser_ui/3_create/web_ide/review_merge_request_spec.rb
@@ -1,10 +1,8 @@
# frozen_string_literal: true
+# TODO: remove this test when 'vscode_web_ide' feature flag is default enabled
module QA
- RSpec.describe 'Create', feature_flag: { name: 'vscode_web_ide', scope: :global }, product_group: :editor, quarantine: {
- issue: 'https://gitlab.com/gitlab-org/gitlab/-/issues/387043',
- type: :stale
- } do
+ RSpec.describe 'Create', :skip_live_env, product_group: :editor do
describe 'Review a merge request in Web IDE' do
let(:new_file) { 'awesome_new_file.txt' }
let(:original_text) { 'Text' }
@@ -26,15 +24,10 @@ module QA
end
before do
- Runtime::Feature.disable(:vscode_web_ide)
Flow::Login.sign_in
merge_request.visit!
end
- after do
- Runtime::Feature.enable(:vscode_web_ide)
- end
-
it 'opens and edits a merge request in Web IDE', testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347786' do
Page::MergeRequest::Show.perform do |show|
show.click_open_in_web_ide
diff --git a/qa/qa/specs/features/browser_ui/3_create/web_ide/server_hooks_custom_error_message_spec.rb b/qa/qa/specs/features/browser_ui/3_create/web_ide/server_hooks_custom_error_message_spec.rb
index 080832990c9..8082c54a6ee 100644
--- a/qa/qa/specs/features/browser_ui/3_create/web_ide/server_hooks_custom_error_message_spec.rb
+++ b/qa/qa/specs/features/browser_ui/3_create/web_ide/server_hooks_custom_error_message_spec.rb
@@ -1,13 +1,8 @@
# frozen_string_literal: true
+# TODO: remove this test when 'vscode_web_ide' feature flag is default enabled
module QA
- RSpec.describe 'Create', :skip_live_env, except: { job: 'review-qa-*' },
- feature_flag: { name: 'vscode_web_ide', scope: :global },
- product_group: :editor,
- quarantine: {
- issue: 'https://gitlab.com/gitlab-org/gitlab/-/issues/387928',
- type: :stale
- } do
+ RSpec.describe 'Create', :skip_live_env, except: { job: 'review-qa-*' }, product_group: :editor do
describe 'Git Server Hooks' do
let(:file_path) { File.join(Runtime::Path.fixtures_path, 'web_ide', 'README.md') }
@@ -20,15 +15,10 @@ module QA
end
before do
- Runtime::Feature.disable(:vscode_web_ide)
Flow::Login.sign_in
project.visit!
end
- after do
- Runtime::Feature.enable(:vscode_web_ide)
- end
-
context 'with custom error messages' do
it 'renders preconfigured error message when user hook failed on commit in WebIDE',
testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/364751' do
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
index b83a95694de..abc7c37a1d4 100644
--- 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
@@ -1,9 +1,8 @@
# frozen_string_literal: true
+# TODO: remove this test when 'vscode_web_ide' feature flag is default enabled
module QA
- RSpec.describe 'Create', product_group: :editor,
- feature_flag: { name: 'vscode_web_ide', scope: :global },
- quarantine: { issue: 'https://gitlab.com/gitlab-org/gitlab/-/issues/387032', type: :stale } do
+ RSpec.describe 'Create', :skip_live_env, product_group: :editor do
describe 'Upload a file in Web IDE' do
let(:file_path) { File.join(Runtime::Path.fixtures_path, 'web_ide', file_name) }
@@ -15,17 +14,12 @@ module QA
end
before do
- Runtime::Feature.disable(:vscode_web_ide)
Flow::Login.sign_in
project.visit!
Page::Project::Show.perform(&:open_web_ide!)
end
- after do
- Runtime::Feature.enable(:vscode_web_ide)
- end
-
context 'when a file with the same name already exists' do
let(:file_name) { 'README.md' }
diff --git a/qa/qa/specs/features/browser_ui/4_verify/ci_job_artifacts/unlocking_job_artifacts_across_parent_child_pipelines_spec.rb b/qa/qa/specs/features/browser_ui/4_verify/ci_job_artifacts/unlocking_job_artifacts_across_parent_child_pipelines_spec.rb
new file mode 100644
index 00000000000..072c957f4dc
--- /dev/null
+++ b/qa/qa/specs/features/browser_ui/4_verify/ci_job_artifacts/unlocking_job_artifacts_across_parent_child_pipelines_spec.rb
@@ -0,0 +1,448 @@
+# frozen_string_literal: true
+
+module QA
+ RSpec.describe 'Verify', :runner, product_group: :pipeline_security, quarantine: {
+ issue: 'https://gitlab.com/gitlab-org/gitlab/-/issues/396855',
+ type: :flaky
+ } do
+ describe "Unlocking job artifacts across parent-child pipelines" do
+ let(:executor) { "qa-runner-#{Faker::Alphanumeric.alphanumeric(number: 8)}" }
+
+ let(:project) do
+ Resource::Project.fabricate_via_api! do |project|
+ project.name = 'unlock-job-artifacts-parent-child-project'
+ end
+ end
+
+ let!(:runner) do
+ Resource::ProjectRunner.fabricate! do |runner|
+ runner.project = project
+ runner.name = executor
+ runner.tags = [executor]
+ end
+ end
+
+ let(:parent_test_job_name) { 'test-job-parent' }
+ let(:child_test_job_name) { 'test-job-child' }
+
+ let(:previous_successful_pipeline) do
+ Resource::Pipeline.fabricate_via_api! do |pipeline|
+ pipeline.project = project
+ end
+ end
+
+ before do
+ Flow::Login.sign_in
+ project.visit!
+ end
+
+ context 'without strategy:depend' do
+ let(:strategy) { nil }
+
+ before do
+ add_parent_child_ci_files
+ Flow::Pipeline.wait_for_latest_pipeline(status: 'passed')
+ previous_successful_pipeline
+ Flow::Pipeline.wait_for_latest_pipeline(status: 'passed')
+ end
+
+ context 'when latest pipeline family is successful' do
+ before do
+ update_parent_child_ci_files
+ end
+
+ it 'unlocks job artifacts from previous successful pipeline family',
+ testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/395516' do
+ project.visit!
+
+ Flow::Pipeline.visit_latest_pipeline(status: 'passed')
+ Flow::Pipeline.visit_pipeline_job_page(job_name: parent_test_job_name)
+ Page::Project::Job::Show.perform do |job|
+ expect(job).to have_locked_artifact
+ end
+
+ Flow::Pipeline.visit_latest_pipeline(status: 'passed')
+ Page::Project::Pipeline::Show.perform do |pipeline|
+ pipeline.expand_child_pipeline
+ pipeline.click_job(child_test_job_name)
+ end
+ Page::Project::Job::Show.perform do |job|
+ expect(job).to have_locked_artifact
+ end
+
+ previous_successful_pipeline.visit!
+ Flow::Pipeline.visit_pipeline_job_page(job_name: parent_test_job_name)
+ Page::Project::Job::Show.perform do |job|
+ expect(job).to have_unlocked_artifact
+ end
+
+ previous_successful_pipeline.visit!
+ Page::Project::Pipeline::Show.perform do |pipeline|
+ pipeline.expand_child_pipeline
+ pipeline.click_job(child_test_job_name)
+ end
+ Page::Project::Job::Show.perform do |job|
+ expect(job).to have_unlocked_artifact
+ end
+ end
+ end
+
+ context 'when latest parent pipeline failed' do
+ before do
+ update_failed_parent_ci_file
+ end
+
+ it 'does not unlock job artifacts from previous successful pipeline family',
+ testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/396243' do
+ project.visit!
+
+ Flow::Pipeline.visit_latest_pipeline(status: 'failed')
+ Flow::Pipeline.visit_pipeline_job_page(job_name: parent_test_job_name)
+ Page::Project::Job::Show.perform do |job|
+ expect(job).to be_failed
+ # FIXME: this should be unlocked,
+ # to be fixed by https://gitlab.com/gitlab-org/gitlab/-/merge_requests/110575
+ expect(job).to have_locked_artifact
+ end
+
+ Flow::Pipeline.visit_latest_pipeline(status: 'failed')
+ Page::Project::Pipeline::Show.perform do |pipeline|
+ pipeline.expand_child_pipeline
+ pipeline.click_job(child_test_job_name)
+ end
+ Page::Project::Job::Show.perform do |job|
+ expect(job).to be_successful
+ expect(job).to have_locked_artifact
+ end
+
+ previous_successful_pipeline.visit!
+ Flow::Pipeline.visit_pipeline_job_page(job_name: parent_test_job_name)
+ Page::Project::Job::Show.perform do |job|
+ expect(job).to have_locked_artifact
+ end
+
+ previous_successful_pipeline.visit!
+ Page::Project::Pipeline::Show.perform do |pipeline|
+ pipeline.expand_child_pipeline
+ pipeline.click_job(child_test_job_name)
+ end
+ Page::Project::Job::Show.perform do |job|
+ expect(job).to have_locked_artifact
+ end
+ end
+ end
+
+ context 'when latest child pipeline failed' do
+ before do
+ update_failed_child_ci_file
+ end
+
+ it 'unlocks job artifacts from previous successful pipeline family because the latest parent is successful',
+ testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/396244' do
+ project.visit!
+
+ Flow::Pipeline.visit_latest_pipeline(status: 'passed')
+ Flow::Pipeline.visit_pipeline_job_page(job_name: parent_test_job_name)
+ Page::Project::Job::Show.perform do |job|
+ expect(job).to be_successful
+ expect(job).to have_locked_artifact
+ end
+
+ Flow::Pipeline.visit_latest_pipeline(status: 'passed')
+ Page::Project::Pipeline::Show.perform do |pipeline|
+ pipeline.expand_child_pipeline
+ pipeline.click_job(child_test_job_name)
+ end
+ Page::Project::Job::Show.perform do |job|
+ expect(job).to be_failed
+ expect(job).to have_locked_artifact
+ end
+
+ previous_successful_pipeline.visit!
+ Flow::Pipeline.visit_pipeline_job_page(job_name: parent_test_job_name)
+ Page::Project::Job::Show.perform do |job|
+ expect(job).to have_unlocked_artifact
+ end
+
+ previous_successful_pipeline.visit!
+ Page::Project::Pipeline::Show.perform do |pipeline|
+ pipeline.expand_child_pipeline
+ pipeline.click_job(child_test_job_name)
+ end
+ Page::Project::Job::Show.perform do |job|
+ expect(job).to have_unlocked_artifact
+ end
+ end
+ end
+ end
+
+ context 'with strategy:depend' do
+ let(:strategy) { 'depend' }
+
+ before do
+ add_parent_child_ci_files
+ Flow::Pipeline.wait_for_latest_pipeline(status: 'passed')
+ previous_successful_pipeline
+ Flow::Pipeline.wait_for_latest_pipeline(status: 'passed')
+ end
+
+ context 'when latest pipeline family is successful' do
+ before do
+ update_parent_child_ci_files
+ end
+
+ it 'unlocks job artifacts from previous successful pipeline family',
+ testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/396245' do
+ project.visit!
+
+ Flow::Pipeline.visit_latest_pipeline(status: 'passed')
+ Flow::Pipeline.visit_pipeline_job_page(job_name: parent_test_job_name)
+ Page::Project::Job::Show.perform do |job|
+ expect(job).to have_locked_artifact
+ end
+
+ Flow::Pipeline.visit_latest_pipeline(status: 'passed')
+ Page::Project::Pipeline::Show.perform do |pipeline|
+ pipeline.expand_child_pipeline
+ pipeline.click_job(child_test_job_name)
+ end
+ Page::Project::Job::Show.perform do |job|
+ expect(job).to have_locked_artifact
+ end
+
+ previous_successful_pipeline.visit!
+ Flow::Pipeline.visit_pipeline_job_page(job_name: parent_test_job_name)
+ Page::Project::Job::Show.perform do |job|
+ expect(job).to have_unlocked_artifact
+ end
+
+ previous_successful_pipeline.visit!
+ Page::Project::Pipeline::Show.perform do |pipeline|
+ pipeline.expand_child_pipeline
+ pipeline.click_job(child_test_job_name)
+ end
+ Page::Project::Job::Show.perform do |job|
+ expect(job).to have_unlocked_artifact
+ end
+ end
+ end
+
+ context 'when latest parent pipeline failed' do
+ before do
+ update_failed_parent_ci_file
+ end
+
+ it 'does not unlock job artifacts from previous successful pipeline family',
+ testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/396246' do
+ project.visit!
+
+ Flow::Pipeline.visit_latest_pipeline(status: 'failed')
+ Flow::Pipeline.visit_pipeline_job_page(job_name: parent_test_job_name)
+ Page::Project::Job::Show.perform do |job|
+ # FIXME: this should be unlocked,
+ # to be fixed by https://gitlab.com/gitlab-org/gitlab/-/merge_requests/110575
+ expect(job).to be_failed
+ expect(job).to have_locked_artifact
+ end
+
+ Flow::Pipeline.visit_latest_pipeline(status: 'failed')
+ Page::Project::Pipeline::Show.perform do |pipeline|
+ pipeline.expand_child_pipeline
+ pipeline.click_job(child_test_job_name)
+ end
+ Page::Project::Job::Show.perform do |job|
+ expect(job).to be_successful
+ expect(job).to have_locked_artifact
+ end
+
+ previous_successful_pipeline.visit!
+ Flow::Pipeline.visit_pipeline_job_page(job_name: parent_test_job_name)
+ Page::Project::Job::Show.perform do |job|
+ expect(job).to have_locked_artifact
+ end
+
+ previous_successful_pipeline.visit!
+ Page::Project::Pipeline::Show.perform do |pipeline|
+ pipeline.expand_child_pipeline
+ pipeline.click_job(child_test_job_name)
+ end
+ Page::Project::Job::Show.perform do |job|
+ expect(job).to have_locked_artifact
+ end
+ end
+ end
+
+ context 'when latest child pipeline failed' do
+ before do
+ update_failed_child_ci_file
+ end
+
+ it 'does not unlock job artifacts from previous successful pipeline family',
+ testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/396248' do
+ project.visit!
+
+ Flow::Pipeline.visit_latest_pipeline(status: 'failed')
+ Flow::Pipeline.visit_pipeline_job_page(job_name: parent_test_job_name)
+ Page::Project::Job::Show.perform do |job|
+ expect(job).to be_successful
+ # FIXME: this should be unlocked,
+ # to be fixed by https://gitlab.com/gitlab-org/gitlab/-/merge_requests/110575
+ expect(job).to have_locked_artifact
+ end
+
+ Flow::Pipeline.visit_latest_pipeline(status: 'failed')
+ Page::Project::Pipeline::Show.perform do |pipeline|
+ pipeline.expand_child_pipeline
+ pipeline.click_job(child_test_job_name)
+ end
+ Page::Project::Job::Show.perform do |job|
+ expect(job).to be_failed
+ # FIXME: this should be unlocked,
+ # to be fixed by https://gitlab.com/gitlab-org/gitlab/-/merge_requests/110575
+ expect(job).to have_locked_artifact
+ end
+
+ previous_successful_pipeline.visit!
+ Flow::Pipeline.visit_pipeline_job_page(job_name: parent_test_job_name)
+ Page::Project::Job::Show.perform do |job|
+ expect(job).to have_locked_artifact
+ end
+
+ previous_successful_pipeline.visit!
+ Page::Project::Pipeline::Show.perform do |pipeline|
+ pipeline.expand_child_pipeline
+ pipeline.click_job(child_test_job_name)
+ end
+ Page::Project::Job::Show.perform do |job|
+ expect(job).to have_locked_artifact
+ end
+ end
+ end
+ end
+
+ private
+
+ def update_parent_child_ci_files
+ Resource::Repository::Commit.fabricate_via_api! do |commit|
+ commit.project = project
+ commit.commit_message = 'Update parent and child pipelines CI files.'
+ commit.update_files(
+ [
+ parent_ci_file,
+ child_ci_file
+ ]
+ )
+ end
+ end
+
+ def update_failed_parent_ci_file
+ Resource::Repository::Commit.fabricate_via_api! do |commit|
+ commit.project = project
+ commit.commit_message = 'Fail parent pipeline.'
+ commit.update_files(
+ [
+ parent_failed_ci_file
+ ]
+ )
+ end
+ end
+
+ def update_failed_child_ci_file
+ Resource::Repository::Commit.fabricate_via_api! do |commit|
+ commit.project = project
+ commit.commit_message = 'Fail child pipeline.'
+ commit.update_files(
+ [
+ child_failed_ci_file
+ ]
+ )
+ end
+ end
+
+ def add_parent_child_ci_files
+ Resource::Repository::Commit.fabricate_via_api! do |commit|
+ commit.project = project
+ commit.commit_message = 'Add parent and child pipelines CI files.'
+ commit.add_files(
+ [
+ parent_ci_file,
+ child_ci_file
+ ]
+ )
+ end
+ end
+
+ def parent_ci_file
+ {
+ file_path: '.gitlab-ci.yml',
+ content: <<~YAML
+ trigger-child:
+ stage: test
+ trigger:
+ include: ".child-ci.yml"
+ strategy: #{strategy}
+
+ #{parent_test_job_name}:
+ stage: test
+ tags: ["#{executor}"]
+ script: echo "parent test"
+ artifacts:
+ paths: ['.gitlab-ci.yml']
+ when: always
+ YAML
+ }
+ end
+
+ def parent_failed_ci_file
+ {
+ file_path: '.gitlab-ci.yml',
+ content: <<~YAML
+ trigger-child:
+ stage: test
+ trigger:
+ include: ".child-ci.yml"
+ strategy: #{strategy}
+
+ #{parent_test_job_name}:
+ stage: test
+ tags: ["#{executor}"]
+ script: echo "parent test" && exit 1
+ artifacts:
+ paths: ['.gitlab-ci.yml']
+ when: always
+ YAML
+ }
+ end
+
+ def child_ci_file
+ {
+ file_path: '.child-ci.yml',
+ content: <<~YAML
+ #{child_test_job_name}:
+ stage: test
+ tags: ["#{executor}"]
+ script: echo "child test"
+ artifacts:
+ paths: ['.child-ci.yml']
+ when: always
+ YAML
+ }
+ end
+
+ def child_failed_ci_file
+ {
+ file_path: '.child-ci.yml',
+ content: <<~YAML
+ #{child_test_job_name}:
+ stage: test
+ tags: ["#{executor}"]
+ script: echo "child test" && exit 1
+ artifacts:
+ paths: ['.child-ci.yml']
+ when: always
+ YAML
+ }
+ end
+ end
+ end
+end
diff --git a/qa/qa/specs/features/browser_ui/4_verify/ci_job_artifacts/unlocking_job_artifacts_across_pipelines_spec.rb b/qa/qa/specs/features/browser_ui/4_verify/ci_job_artifacts/unlocking_job_artifacts_across_pipelines_spec.rb
new file mode 100644
index 00000000000..a954bd16386
--- /dev/null
+++ b/qa/qa/specs/features/browser_ui/4_verify/ci_job_artifacts/unlocking_job_artifacts_across_pipelines_spec.rb
@@ -0,0 +1,170 @@
+# frozen_string_literal: true
+
+module QA
+ RSpec.describe 'Verify', :runner, product_group: :pipeline_security do
+ describe "Unlocking job artifacts across pipelines" do
+ let(:executor) { "qa-runner-#{Faker::Alphanumeric.alphanumeric(number: 8)}" }
+
+ let(:project) do
+ Resource::Project.fabricate_via_api! do |project|
+ project.name = 'unlock-job-artifacts-project'
+ end
+ end
+
+ let!(:runner) do
+ Resource::ProjectRunner.fabricate! do |runner|
+ runner.project = project
+ runner.name = executor
+ runner.tags = [executor]
+ end
+ end
+
+ let(:test_job_name) { 'test-job' }
+
+ before do
+ Flow::Login.sign_in
+ end
+
+ context 'when latest pipeline is successful' do
+ it 'unlocks job artifacts from previous successful pipeline',
+ testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/394807' do
+ add_ci_file
+ project.visit!
+
+ previous_successful_pipeline = Resource::Pipeline.fabricate! do |pipeline|
+ pipeline.project = project
+ end
+
+ Flow::Pipeline.visit_latest_pipeline(status: 'passed')
+ Flow::Pipeline.visit_pipeline_job_page(job_name: test_job_name)
+
+ Page::Project::Job::Show.perform do |job|
+ expect(job).to have_locked_artifact
+ end
+
+ update_ci_script('echo bye')
+ project.visit!
+
+ Flow::Pipeline.visit_latest_pipeline(status: 'passed')
+ Flow::Pipeline.visit_pipeline_job_page(job_name: test_job_name)
+
+ Page::Project::Job::Show.perform do |job|
+ expect(job).to have_locked_artifact
+ end
+
+ Flow::Pipeline.visit_pipeline_job_page(pipeline: previous_successful_pipeline, job_name: test_job_name)
+
+ Page::Project::Job::Show.perform do |job|
+ expect(job).to have_unlocked_artifact
+ end
+ end
+ end
+
+ context 'when latest pipeline failed' do
+ it 'unlocks job artifacts from failed pipelines, keeps job artifacts from latest successful pipeline',
+ testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/394808',
+ quarantine: {
+ issue: 'https://gitlab.com/gitlab-org/gitlab/-/issues/266958',
+ type: :bug
+ } do
+ add_ci_file
+ project.visit!
+
+ successful_pipeline = Resource::Pipeline.fabricate! do |pipeline|
+ pipeline.project = project
+ end
+
+ Flow::Pipeline.visit_latest_pipeline(status: 'passed')
+ Flow::Pipeline.visit_pipeline_job_page(job_name: test_job_name)
+
+ Page::Project::Job::Show.perform do |job|
+ expect(job).to have_locked_artifact
+ end
+
+ update_ci_script('echo test && exit 1')
+
+ failed_pipeline_1 = Resource::Pipeline.fabricate! do |pipeline|
+ pipeline.project = project
+ end
+
+ Flow::Pipeline.visit_latest_pipeline(status: 'failed')
+ Flow::Pipeline.visit_pipeline_job_page(job_name: test_job_name)
+
+ Page::Project::Job::Show.perform do |job|
+ expect(job).to have_unlocked_artifact
+ end
+
+ update_ci_script('echo bye && exit 1')
+ project.visit!
+
+ Flow::Pipeline.visit_latest_pipeline(status: 'failed')
+ Flow::Pipeline.visit_pipeline_job_page(job_name: test_job_name)
+
+ Page::Project::Job::Show.perform do |job|
+ expect(job).to have_unlocked_artifact
+ end
+
+ Flow::Pipeline.visit_pipeline_job_page(pipeline: failed_pipeline_1, job_name: test_job_name)
+
+ Page::Project::Job::Show.perform do |job|
+ expect(job).to have_unlocked_artifact
+ end
+
+ Flow::Pipeline.visit_pipeline_job_page(pipeline: successful_pipeline, job_name: test_job_name)
+
+ Page::Project::Job::Show.perform do |job|
+ expect(job).to have_locked_artifact
+ end
+ end
+ end
+
+ private
+
+ def add_ci_file
+ script = 'echo test'
+ ci_file = ci_file_with_job_artifact(script)
+
+ Resource::Repository::Commit.fabricate_via_api! do |commit|
+ commit.project = project
+ commit.commit_message = "Set script #{script}"
+ commit.add_files([ci_file])
+ end
+ end
+
+ def update_ci_script(script)
+ ci_file = ci_file_with_job_artifact(script)
+
+ Resource::Repository::Commit.fabricate_via_api! do |commit|
+ commit.project = project
+ commit.commit_message = "Set script #{script}"
+ commit.update_files([ci_file])
+ end
+ end
+
+ def add_failing_ci_file
+ ci_file = ci_file_with_job_artifact('echo test && exit 1')
+
+ Resource::Repository::Commit.fabricate_via_api! do |commit|
+ commit.project = project
+ commit.commit_message = 'Add failing CI file.'
+ commit.add_files([ci_file])
+ end
+ end
+
+ def ci_file_with_job_artifact(script)
+ {
+ file_path: '.gitlab-ci.yml',
+ content: <<~YAML
+ #{test_job_name}:
+ stage: test
+ tags: ["#{executor}"]
+ script: #{script}
+ artifacts:
+ paths: ['.gitlab-ci.yml']
+ when: always
+ YAML
+ }
+ end
+ end
+ end
+end
diff --git a/qa/qa/specs/features/browser_ui/4_verify/ci_variable/add_remove_ci_variable_spec.rb b/qa/qa/specs/features/browser_ui/4_verify/ci_variable/add_remove_ci_variable_spec.rb
index aec0da99a5c..8474e5c1b37 100644
--- a/qa/qa/specs/features/browser_ui/4_verify/ci_variable/add_remove_ci_variable_spec.rb
+++ b/qa/qa/specs/features/browser_ui/4_verify/ci_variable/add_remove_ci_variable_spec.rb
@@ -2,7 +2,7 @@
module QA
RSpec.describe 'Verify' do
- describe 'Add or Remove CI variable via UI', :smoke, product_group: :pipeline_authoring do
+ describe 'Add or Remove CI variable via UI', :smoke, product_group: :pipeline_security do
let(:project) do
Resource::Project.fabricate_via_api_unless_fips! do |project|
project.name = 'project-with-ci-variables'
diff --git a/qa/qa/specs/features/browser_ui/4_verify/ci_variable/custom_variable_spec.rb b/qa/qa/specs/features/browser_ui/4_verify/ci_variable/custom_variable_spec.rb
index 2ae28d54242..4c1319da0cb 100644
--- a/qa/qa/specs/features/browser_ui/4_verify/ci_variable/custom_variable_spec.rb
+++ b/qa/qa/specs/features/browser_ui/4_verify/ci_variable/custom_variable_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module QA
- RSpec.describe 'Verify', :runner do
+ RSpec.describe 'Verify', :runner, product_group: :pipeline_security do
describe 'Pipeline with customizable variable' do
let(:executor) { "qa-runner-#{Time.now.to_i}" }
let(:pipeline_job_name) { 'customizable-variable' }
@@ -51,11 +51,6 @@ module QA
project.visit!
Page::Project::Menu.perform(&:click_ci_cd_pipelines)
Page::Project::Pipeline::Index.perform(&:click_run_pipeline_button)
-
- # Sometimes the variables will not be prefilled because of reactive cache so we revisit the page again.
- # TODO: Investigate alternatives to deal with cache implementation
- # Issue https://gitlab.com/gitlab-org/gitlab/-/issues/381233
- page.refresh
end
after do
diff --git a/qa/qa/specs/features/browser_ui/4_verify/ci_variable/pipeline_with_protected_variable_spec.rb b/qa/qa/specs/features/browser_ui/4_verify/ci_variable/pipeline_with_protected_variable_spec.rb
index a8ec0a1c835..e2d25e64687 100644
--- a/qa/qa/specs/features/browser_ui/4_verify/ci_variable/pipeline_with_protected_variable_spec.rb
+++ b/qa/qa/specs/features/browser_ui/4_verify/ci_variable/pipeline_with_protected_variable_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module QA
- RSpec.describe 'Verify', :runner, product_group: :pipeline_authoring do
+ RSpec.describe 'Verify', :runner, product_group: :pipeline_security do
describe 'Pipeline with protected variable' do
let(:executor) { "qa-runner-#{Faker::Alphanumeric.alphanumeric(number: 8)}" }
let(:protected_value) { Faker::Alphanumeric.alphanumeric(number: 8) }
diff --git a/qa/qa/specs/features/browser_ui/4_verify/ci_variable/prefill_variables_spec.rb b/qa/qa/specs/features/browser_ui/4_verify/ci_variable/prefill_variables_spec.rb
index 1878292015e..b79f8b5f1f4 100644
--- a/qa/qa/specs/features/browser_ui/4_verify/ci_variable/prefill_variables_spec.rb
+++ b/qa/qa/specs/features/browser_ui/4_verify/ci_variable/prefill_variables_spec.rb
@@ -2,7 +2,7 @@
module QA
RSpec.describe 'Verify' do
- describe 'Pipeline with prefill variables' do
+ describe 'Pipeline with prefill variables', product_group: :pipeline_security do
let(:prefill_variable_description1) { Faker::Lorem.sentence }
let(:prefill_variable_value1) { Faker::Lorem.word }
let(:prefill_variable_value5) { Faker::Lorem.word }
@@ -54,11 +54,6 @@ module QA
# Navigate to Run Pipeline page
Page::Project::Menu.perform(&:click_ci_cd_pipelines)
Page::Project::Pipeline::Index.perform(&:click_run_pipeline_button)
-
- # Sometimes the variables will not be prefilled because of reactive cache so we revisit the page again.
- # TODO: Investigate alternatives to deal with cache implementation
- # Issue https://gitlab.com/gitlab-org/gitlab/-/issues/381233
- page.refresh
end
it 'shows only variables with description as prefill variables on the run pipeline page',
diff --git a/qa/qa/specs/features/browser_ui/4_verify/ci_variable/raw_variables_defined_in_yaml_spec.rb b/qa/qa/specs/features/browser_ui/4_verify/ci_variable/raw_variables_defined_in_yaml_spec.rb
index 81ccd36c514..15959721935 100644
--- a/qa/qa/specs/features/browser_ui/4_verify/ci_variable/raw_variables_defined_in_yaml_spec.rb
+++ b/qa/qa/specs/features/browser_ui/4_verify/ci_variable/raw_variables_defined_in_yaml_spec.rb
@@ -2,7 +2,7 @@
module QA
RSpec.describe 'Verify', :runner do
- describe 'Pipeline with raw variables in YAML', product_group: :pipeline_authoring do
+ describe 'Pipeline with raw variables in YAML', product_group: :pipeline_security do
let(:executor) { "qa-runner-#{Time.now.to_i}" }
let(:pipeline_job_name) { 'rspec' }
diff --git a/qa/qa/specs/features/browser_ui/4_verify/ci_variable/ui_variable_inheritable_when_forward_pipeline_variables_true_spec.rb b/qa/qa/specs/features/browser_ui/4_verify/ci_variable/ui_variable_inheritable_when_forward_pipeline_variables_true_spec.rb
index a5ebd4004d2..12c29ac2363 100644
--- a/qa/qa/specs/features/browser_ui/4_verify/ci_variable/ui_variable_inheritable_when_forward_pipeline_variables_true_spec.rb
+++ b/qa/qa/specs/features/browser_ui/4_verify/ci_variable/ui_variable_inheritable_when_forward_pipeline_variables_true_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module QA
- RSpec.describe 'Verify', :runner, product_group: :pipeline_authoring do
+ RSpec.describe 'Verify', :runner, product_group: :pipeline_security do
describe 'UI defined variable' do
include_context 'variable inheritance test prep'
diff --git a/qa/qa/specs/features/browser_ui/4_verify/ci_variable/ui_variable_non_inheritable_when_forward_pipeline_variables_false_spec.rb b/qa/qa/specs/features/browser_ui/4_verify/ci_variable/ui_variable_non_inheritable_when_forward_pipeline_variables_false_spec.rb
index f53454b801c..1d354daaa5b 100644
--- a/qa/qa/specs/features/browser_ui/4_verify/ci_variable/ui_variable_non_inheritable_when_forward_pipeline_variables_false_spec.rb
+++ b/qa/qa/specs/features/browser_ui/4_verify/ci_variable/ui_variable_non_inheritable_when_forward_pipeline_variables_false_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module QA
- RSpec.describe 'Verify', :runner, product_group: :pipeline_authoring do
+ RSpec.describe 'Verify', :runner, product_group: :pipeline_security do
describe 'UI defined variable' do
include_context 'variable inheritance test prep'
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
new file mode 100644
index 00000000000..dc8db7ec387
--- /dev/null
+++ b/qa/qa/specs/features/browser_ui/4_verify/pipeline/include_multiple_files_from_multiple_projects_spec.rb
@@ -0,0 +1,154 @@
+# 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
+ describe 'Include multiple files from multiple projects' do
+ let(:executor) { "qa-runner-#{Faker::Alphanumeric.alphanumeric(number: 8)}" }
+
+ let(:main_project) do
+ Resource::Project.fabricate_via_api! do |project|
+ project.name = 'project-with-pipeline'
+ end
+ end
+
+ let(:project1) do
+ Resource::Project.fabricate_via_api! do |project|
+ project.name = 'external-project-1'
+ end
+ end
+
+ let(:project2) do
+ Resource::Project.fabricate_via_api! do |project|
+ project.name = 'external-project-2'
+ end
+ end
+
+ let!(:runner) do
+ Resource::ProjectRunner.fabricate! do |runner|
+ runner.project = main_project
+ runner.name = executor
+ runner.tags = [executor]
+ end
+ end
+
+ def before_do
+ Flow::Login.sign_in
+
+ add_included_files_for(main_project)
+ add_included_files_for(project1)
+ add_included_files_for(project2)
+ add_main_ci_file(main_project)
+
+ main_project.visit!
+ Flow::Pipeline.visit_latest_pipeline(status: 'passed')
+ end
+
+ after do
+ 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
+ end
+ end
+ end
+
+ private
+
+ def add_included_files_for(project)
+ files = [
+ {
+ file_path: 'file1.yml',
+ content: <<~YAML
+ test1_for_#{project.full_path}:
+ tags: ["#{executor}"]
+ script: echo hello1
+ YAML
+ },
+ {
+ file_path: 'file2.yml',
+ content: <<~YAML
+ test2_for_#{project.full_path}:
+ tags: ["#{executor}"]
+ script: echo hello2
+ YAML
+ }
+ ]
+
+ Resource::Repository::Commit.fabricate_via_api! do |commit|
+ commit.project = project
+ commit.commit_message = 'Add files'
+ commit.add_files(files)
+ end
+ end
+
+ def add_main_ci_file(project)
+ Resource::Repository::Commit.fabricate_via_api! do |commit|
+ commit.project = project
+ commit.commit_message = 'Add config file'
+ commit.add_files([main_ci_file])
+ end
+ end
+
+ def main_ci_file
+ {
+ file_path: '.gitlab-ci.yml',
+ content: <<~YAML
+ include:
+ - project: #{project1.full_path}
+ file: file1.yml
+ - project: #{project2.full_path}
+ file: file1.yml
+ - project: #{project1.full_path}
+ file: file2.yml
+ - project: #{main_project.full_path}
+ file: file2.yml
+
+ test_for_main:
+ tags: ["#{executor}"]
+ script: echo hello
+ YAML
+ }
+ end
+ end
+ end
+end
diff --git a/qa/qa/specs/features/browser_ui/4_verify/pipeline/locked_artifacts_spec.rb b/qa/qa/specs/features/browser_ui/4_verify/pipeline/locked_artifacts_spec.rb
index 588d22275df..5543e39e38c 100644
--- a/qa/qa/specs/features/browser_ui/4_verify/pipeline/locked_artifacts_spec.rb
+++ b/qa/qa/specs/features/browser_ui/4_verify/pipeline/locked_artifacts_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module QA
- RSpec.describe 'Verify', :runner, :requires_admin, product_group: :pipeline_insights do
+ RSpec.describe 'Verify', :runner, product_group: :pipeline_security do
describe 'Artifacts' do
context 'when locked' do
let(:file_name) { 'artifact.txt' }
diff --git a/qa/qa/specs/features/browser_ui/4_verify/pipeline/pass_dotenv_variables_to_downstream_via_bridge_spec.rb b/qa/qa/specs/features/browser_ui/4_verify/pipeline/pass_dotenv_variables_to_downstream_via_bridge_spec.rb
index 7d1339d2c2d..6295c596dda 100644
--- a/qa/qa/specs/features/browser_ui/4_verify/pipeline/pass_dotenv_variables_to_downstream_via_bridge_spec.rb
+++ b/qa/qa/specs/features/browser_ui/4_verify/pipeline/pass_dotenv_variables_to_downstream_via_bridge_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module QA
- RSpec.describe 'Verify', :runner, product_group: :pipeline_authoring do
+ RSpec.describe 'Verify', :runner, product_group: :pipeline_security do
describe 'Pass dotenv variables to downstream via bridge' do
let(:executor) { "qa-runner-#{Faker::Alphanumeric.alphanumeric(number: 8)}" }
let(:upstream_var) { Faker::Alphanumeric.alphanumeric(number: 8) }
diff --git a/qa/qa/specs/features/browser_ui/4_verify/testing/endpoint_coverage_spec.rb b/qa/qa/specs/features/browser_ui/4_verify/testing/endpoint_coverage_spec.rb
index d4fee70fbf3..e7ab515c672 100644
--- a/qa/qa/specs/features/browser_ui/4_verify/testing/endpoint_coverage_spec.rb
+++ b/qa/qa/specs/features/browser_ui/4_verify/testing/endpoint_coverage_spec.rb
@@ -9,7 +9,7 @@ module QA
# pipeline created (Sidekiq read/write) ->
# runner picks up pipeline (API read/write) ->
# User views pipeline succeeds (Web read)
- RSpec.describe 'Verify', :runner, product_group: :pipeline_insights do
+ RSpec.describe 'Verify', :runner, product_group: :pipeline_security do
context 'Endpoint Coverage' do
let!(:project) do
Resource::Project.fabricate_via_api! do |project|
diff --git a/qa/qa/specs/features/browser_ui/4_verify/testing/view_code_coverage_spec.rb b/qa/qa/specs/features/browser_ui/4_verify/testing/view_code_coverage_spec.rb
index b45ccfa5433..ee60483d4de 100644
--- a/qa/qa/specs/features/browser_ui/4_verify/testing/view_code_coverage_spec.rb
+++ b/qa/qa/specs/features/browser_ui/4_verify/testing/view_code_coverage_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module QA
- RSpec.describe 'Verify', :runner, product_group: :pipeline_insights do
+ RSpec.describe 'Verify', :runner, product_group: :pipeline_execution do
describe 'Code coverage statistics' do
let(:executor) { "qa-runner-#{Time.now.to_i}" }
let(:runner) do
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 f95bcc59db1..6252a287fd4 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
@@ -36,6 +36,8 @@ module QA
use_ci_variable(name: 'PERSONAL_ACCESS_TOKEN', value: personal_access_token, project: package_project)
use_ci_variable(name: 'PERSONAL_ACCESS_TOKEN', value: personal_access_token, project: client_project)
when :ci_job_token
+ package_project_inbound_job_token_disabled
+ client_project_inbound_job_token_disabled
'${CI_JOB_TOKEN}'
when :project_deploy_token
use_ci_variable(name: 'PROJECT_DEPLOY_TOKEN', value: project_deploy_token.token, project: package_project)
@@ -43,10 +45,7 @@ module QA
end
end
- it "pushes and pulls a helm chart", testcase: params[:testcase], quarantine: {
- type: :stale,
- issue: 'https://gitlab.com/gitlab-org/gitlab/-/issues/391649'
- } do
+ it "pushes and pulls a helm chart", testcase: params[:testcase] do
Support::Retrier.retry_on_exception(max_attempts: 3, sleep_interval: 2) do
Resource::Repository::Commit.fabricate_via_api! do |commit|
helm_upload_yaml = ERB.new(read_fixture('package_managers/helm', 'helm_upload_package.yaml.erb')).result(binding)
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 3fb5c921187..879bb7022c8 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, :packages, :object_storage, :reliable, product_group: :package_registry do
+ RSpec.describe 'Package', :orchestrated, :packages, :object_storage, :reliable, product_group: :package_registry, feature_flag: { name: 'maven_central_request_forwarding', scope: :global } do
describe 'Maven group level endpoint' do
include Runtime::Fixtures
include Support::Helpers::MaskToken
@@ -41,11 +41,7 @@ module QA
'using a ci job token' => {
authentication_token_type: :ci_job_token,
maven_header_name: 'Job-Token',
- testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347579',
- quarantine: {
- issue: 'https://gitlab.com/gitlab-org/gitlab/-/issues/373189',
- type: :stale
- }
+ testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347579'
}
}
end
@@ -57,6 +53,8 @@ module QA
use_ci_variable(name: 'PERSONAL_ACCESS_TOKEN', value: personal_access_token, project: package_project)
use_ci_variable(name: 'PERSONAL_ACCESS_TOKEN', value: personal_access_token, project: client_project)
when :ci_job_token
+ package_project_inbound_job_token_disabled
+ client_project_inbound_job_token_disabled
'${CI_JOB_TOKEN}'
when :project_deploy_token
use_ci_variable(name: 'GROUP_DEPLOY_TOKEN', value: group_deploy_token.token, project: package_project)
@@ -64,7 +62,7 @@ module QA
end
end
- it 'pushes and pulls a maven package', testcase: params[:testcase], quarantine: params[:quarantine] do
+ it 'pushes and pulls a maven package', testcase: params[:testcase] 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/group/producer', 'gitlab_ci.yaml.erb')).result(binding)
@@ -223,5 +221,98 @@ 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
+ 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_gradle_repository_spec.rb b/qa/qa/specs/features/browser_ui/5_package/package_registry/maven_gradle_repository_spec.rb
index d86ce09c4e1..9a418f11b1b 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
@@ -25,16 +25,15 @@ module QA
when :personal_access_token
"\"#{personal_access_token}\""
when :ci_job_token
+ package_project_inbound_job_token_disabled
+ client_project_inbound_job_token_disabled
'System.getenv("CI_JOB_TOKEN")'
when :project_deploy_token
"\"#{project_deploy_token.token}\""
end
end
- it 'pushes and pulls a maven package via gradle', testcase: params[:testcase], quarantine: {
- type: :stale,
- issue: 'https://gitlab.com/gitlab-org/gitlab/-/issues/391650'
- } do
+ it 'pushes and pulls a maven package via gradle', testcase: params[:testcase] do
Support::Retrier.retry_on_exception(max_attempts: 3, sleep_interval: 2) do
Resource::Repository::Commit.fabricate_via_api! do |commit|
gradle_upload_yaml = ERB.new(read_fixture('package_managers/maven/gradle', 'gradle_upload_package.yaml.erb')).result(binding)
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 c2cbec3fbb7..48b9fdec2e9 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
@@ -50,6 +50,20 @@ module QA
end
end
+ let(:package_project_inbound_job_token_disabled) do
+ Resource::CICDSettings.fabricate_via_api! do |settings|
+ settings.project_path = project.full_path
+ settings.inbound_job_token_scope_enabled = false
+ end
+ end
+
+ let(:client_project_inbound_job_token_disabled) do
+ Resource::CICDSettings.fabricate_via_api! do |settings|
+ settings.project_path = another_project.full_path
+ settings.inbound_job_token_scope_enabled = false
+ end
+ end
+
let!(:runner) do
Resource::GroupRunner.fabricate! do |runner|
runner.name = "qa-runner-#{Time.now.to_i}"
@@ -79,6 +93,8 @@ module QA
use_ci_variable(name: 'PERSONAL_ACCESS_TOKEN', value: personal_access_token.token, project: project)
use_ci_variable(name: 'PERSONAL_ACCESS_TOKEN', value: personal_access_token.token, project: another_project)
when :ci_job_token
+ package_project_inbound_job_token_disabled
+ client_project_inbound_job_token_disabled
'${CI_JOB_TOKEN}'
when :group_deploy_token
use_ci_variable(name: 'GROUP_DEPLOY_TOKEN', value: group_deploy_token.token, project: project)
@@ -97,10 +113,7 @@ module QA
end
end
- it 'publishes a nuget package at the project endpoint and installs it from the group endpoint', testcase: params[:testcase], quarantine: {
- type: :stale,
- issue: 'https://gitlab.com/gitlab-org/gitlab/-/issues/391648'
- } do
+ it 'publishes a nuget package at the project endpoint and installs it from the group endpoint', testcase: params[:testcase] do
Flow::Login.sign_in
Support::Retrier.retry_on_exception(max_attempts: 3, sleep_interval: 2) do
diff --git a/qa/qa/specs/features/browser_ui/6_release/deploy_key/clone_using_deploy_key_spec.rb b/qa/qa/specs/features/browser_ui/6_release/deploy_key/clone_using_deploy_key_spec.rb
index 0f6bee951a7..51006dd1e38 100644
--- a/qa/qa/specs/features/browser_ui/6_release/deploy_key/clone_using_deploy_key_spec.rb
+++ b/qa/qa/specs/features/browser_ui/6_release/deploy_key/clone_using_deploy_key_spec.rb
@@ -19,7 +19,6 @@ module QA
resource.project = project
resource.name = runner_name
resource.tags = [runner_name]
- resource.image = 'gitlab/gitlab-runner:alpine-v15.8.3'
end
end
diff --git a/qa/qa/specs/features/browser_ui/8_monitor/alert_management/recovery_alert_resolves_correct_alert_spec.rb b/qa/qa/specs/features/browser_ui/8_monitor/alert_management/recovery_alert_resolves_correct_alert_spec.rb
new file mode 100644
index 00000000000..433d286686b
--- /dev/null
+++ b/qa/qa/specs/features/browser_ui/8_monitor/alert_management/recovery_alert_resolves_correct_alert_spec.rb
@@ -0,0 +1,48 @@
+# frozen_string_literal: true
+
+module QA
+ RSpec.describe 'Monitor', product_group: :respond do
+ describe 'Recovery alert' do
+ shared_examples 'triggers recovery alert' do
+ it 'only resolves the correct alert', :aggregate_failures do
+ Page::Project::Menu.perform(&:go_to_monitor_alerts)
+ Page::Project::Monitor::Alerts::Index.perform do |index|
+ # Open tab is displayed by default
+ expect(index).to have_alert_with_title(unresolve_title)
+ expect(index).to have_no_alert_with_title(resolve_title)
+
+ index.go_to_tab('Resolved')
+ expect(index).to have_alert_with_title(resolve_title)
+ expect(index).to have_no_alert_with_title(unresolve_title)
+ end
+ end
+ end
+
+ before do
+ Flow::Login.sign_in
+ project.visit!
+ Flow::AlertSettings.go_to_monitor_settings
+ end
+
+ context(
+ 'when using HTTP endpoint integration',
+ testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/393589'
+ ) do
+ include_context 'sends and resolves test alerts'
+
+ it_behaves_like 'triggers recovery alert'
+ end
+
+ context(
+ 'when using Prometheus integration',
+ testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/393590'
+ ) do
+ include_context 'sends and resolves test alerts'
+
+ let(:http) { false }
+
+ it_behaves_like 'triggers recovery alert'
+ end
+ end
+ end
+end
diff --git a/qa/qa/specs/features/browser_ui/8_monitor/incident_management/recovery_alert_closes_correct_incident.rb b/qa/qa/specs/features/browser_ui/8_monitor/incident_management/recovery_alert_closes_correct_incident.rb
new file mode 100644
index 00000000000..fe3cd5a432b
--- /dev/null
+++ b/qa/qa/specs/features/browser_ui/8_monitor/incident_management/recovery_alert_closes_correct_incident.rb
@@ -0,0 +1,49 @@
+# frozen_string_literal: true
+
+module QA
+ RSpec.describe 'Monitor', product_group: :respond do
+ describe 'Recovery alert' do
+ shared_examples 'triggers recovery alert' do
+ it 'only closes the correct incident', :aggregate_failures do
+ Page::Project::Menu.perform(&:go_to_monitor_incidents)
+ Page::Project::Monitor::Incidents::Index.perform do |index|
+ # Open tab is displayed by default
+ expect(index).to have_incident(title: unresolve_title)
+ expect(index).to have_no_incident(title: resolve_title)
+
+ index.go_to_tab('Closed')
+ expect(index).to have_incident(title: resolve_title)
+ expect(index).to have_no_incident(title: unresolve_title)
+ end
+ end
+ end
+
+ before do
+ Flow::Login.sign_in
+ project.visit!
+ Flow::AlertSettings.go_to_monitor_settings
+ Flow::AlertSettings.enable_create_incident
+ end
+
+ context(
+ 'when using HTTP endpoint integration',
+ testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/393842'
+ ) do
+ include_context 'sends and resolves test alerts'
+
+ it_behaves_like 'triggers recovery alert'
+ end
+
+ context(
+ 'when using Prometheus integration',
+ testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/393843'
+ ) do
+ include_context 'sends and resolves test alerts'
+
+ let(:http) { false }
+
+ it_behaves_like 'triggers recovery alert'
+ end
+ end
+ end
+end
diff --git a/qa/qa/specs/features/shared_contexts/import/github_import_shared_context.rb b/qa/qa/specs/features/shared_contexts/import/github_import_shared_context.rb
index 481a09f601b..d72144cecec 100644
--- a/qa/qa/specs/features/shared_contexts/import/github_import_shared_context.rb
+++ b/qa/qa/specs/features/shared_contexts/import/github_import_shared_context.rb
@@ -26,6 +26,7 @@ module QA
let(:imported_project) do
Resource::ProjectImportedFromGithub.fabricate_via_api! do |project|
project.name = 'imported-project'
+ project.github_repo_id = '466994992'
project.group = group
project.github_personal_access_token = Runtime::Env.github_access_token
project.github_repository_path = github_repo
diff --git a/qa/qa/specs/features/shared_contexts/import/gitlab_project_migration_common.rb b/qa/qa/specs/features/shared_contexts/import/gitlab_project_migration_common.rb
index 728907c708f..900245deca3 100644
--- a/qa/qa/specs/features/shared_contexts/import/gitlab_project_migration_common.rb
+++ b/qa/qa/specs/features/shared_contexts/import/gitlab_project_migration_common.rb
@@ -25,7 +25,6 @@ module QA
end
before do
- Runtime::Feature.enable(:bulk_import_projects) unless Runtime::Feature.enabled?(:bulk_import_projects)
source_project # fabricate source group and project
end
end
diff --git a/qa/qa/specs/features/shared_contexts/packages_registry_shared_context.rb b/qa/qa/specs/features/shared_contexts/packages_registry_shared_context.rb
index a611a801b11..5ab7bb331c0 100644
--- a/qa/qa/specs/features/shared_contexts/packages_registry_shared_context.rb
+++ b/qa/qa/specs/features/shared_contexts/packages_registry_shared_context.rb
@@ -20,6 +20,20 @@ module QA
end
end
+ let(:package_project_inbound_job_token_disabled) do
+ Resource::CICDSettings.fabricate_via_api! do |settings|
+ settings.project_path = package_project.full_path
+ settings.inbound_job_token_scope_enabled = false
+ end
+ end
+
+ let(:client_project_inbound_job_token_disabled) do
+ Resource::CICDSettings.fabricate_via_api! do |settings|
+ settings.project_path = client_project.full_path
+ settings.inbound_job_token_scope_enabled = false
+ end
+ end
+
let(:package) do
Resource::Package.init do |package|
package.name = package_name
diff --git a/qa/qa/specs/features/shared_contexts/sends_and_resolves_test_alerts.rb b/qa/qa/specs/features/shared_contexts/sends_and_resolves_test_alerts.rb
new file mode 100644
index 00000000000..a72140f41e0
--- /dev/null
+++ b/qa/qa/specs/features/shared_contexts/sends_and_resolves_test_alerts.rb
@@ -0,0 +1,73 @@
+# frozen_string_literal: true
+
+module QA
+ RSpec.shared_context 'sends and resolves test alerts' do
+ let(:project) do
+ Resource::Project.fabricate_via_api! do |project|
+ project.name = 'project-for-alerts'
+ project.description = 'Project for alerts'
+ end
+ end
+
+ let(:resolve_title) { Faker::Lorem.sentence }
+ let(:unresolve_title) { Faker::Lorem.sentence }
+ let(:http) { true }
+
+ let(:payload_to_be_resolved) do
+ payload(resolve_title, http)
+ end
+
+ let(:unresolved_payload) do
+ payload(unresolve_title, http)
+ end
+
+ before do
+ http ? Flow::AlertSettings.setup_http_endpoint_integration : Flow::AlertSettings.setup_prometheus_integration
+
+ [payload_to_be_resolved, unresolved_payload].each do |payload|
+ Flow::AlertSettings.send_test_alert(payload: payload)
+ end
+
+ mark_as_resolved(payload_to_be_resolved, http)
+ Flow::AlertSettings.send_test_alert(payload: payload_to_be_resolved)
+ end
+
+ private
+
+ def mark_as_resolved(payload, http)
+ if http
+ payload[:end_time] = Time.now
+ else
+ payload[:alerts][0][:status] = 'resolved'
+ payload[:alerts][0][:endsAt] = Time.now
+ end
+ end
+
+ def payload(title, http)
+ if http
+ { title: title, description: title }
+ else
+ {
+ version: '4',
+ groupKey: nil,
+ status: 'firing',
+ receiver: '',
+ groupLabels: {},
+ commonLabels: {},
+ commonAnnotations: {},
+ externalURL: '',
+ alerts: [
+ {
+ startsAt: Time.now,
+ generatorURL: Faker::Internet.url,
+ endsAt: nil,
+ status: nil,
+ labels: { gitlab_environment_name: Faker::Lorem.word },
+ annotations: { title: title }
+ }
+ ]
+ }
+ end
+ end
+ end
+end
diff --git a/qa/qa/specs/helpers/context_selector.rb b/qa/qa/specs/helpers/context_selector.rb
index dfb00cb807b..59ab7c9722e 100644
--- a/qa/qa/specs/helpers/context_selector.rb
+++ b/qa/qa/specs/helpers/context_selector.rb
@@ -22,7 +22,7 @@ module QA
opts = {}
opts[:domain] = '.+'
- opts[:tld] = '.com'
+ opts[:tld] = opts_tld
uri = URI(Runtime::Scenario.gitlab_address)
@@ -79,6 +79,10 @@ module QA
def production_domain
GitlabEdition.jh? ? 'jihulab' : 'gitlab'
end
+
+ def opts_tld
+ GitlabEdition.jh? ? '(.com|.hk)' : '.com'
+ end
end
end
end
diff --git a/qa/qa/support/json_formatter.rb b/qa/qa/support/json_formatter.rb
index 252ccfe73d3..178b76e1974 100644
--- a/qa/qa/support/json_formatter.rb
+++ b/qa/qa/support/json_formatter.rb
@@ -26,6 +26,10 @@ module QA
class: exception.class.name,
message: exception.message,
message_lines: strip_ansi_codes(notification.message_lines),
+ correlation_id: exception.message[match_data_after(Loglinking::CORRELATION_ID_TITLE)],
+ sentry_url: exception.message[match_data_after(Loglinking::SENTRY_URL_TITLE)],
+ kibana_discover_url: exception.message[match_data_after(Loglinking::KIBANA_DISCOVER_URL_TITLE)],
+ kibana_dashboard_url: exception.message[match_data_after(Loglinking::KIBANA_DASHBOARD_URL_TITLE)],
backtrace: notification.formatted_backtrace
}
end
@@ -70,6 +74,10 @@ module QA
modified = Array(strings).map { |string| string.dup.gsub(/\x1b\[{1,2}[0-9;:?]*m/m, '') }
modified.size == 1 ? modified[0] : modified
end
+
+ def match_data_after(title)
+ /(?<=#{title} ).*/
+ end
end
end
end
diff --git a/qa/qa/support/loglinking.rb b/qa/qa/support/loglinking.rb
index e9202af3965..ac6e596ef6f 100644
--- a/qa/qa/support/loglinking.rb
+++ b/qa/qa/support/loglinking.rb
@@ -4,16 +4,22 @@ module QA
module Support
module Loglinking
# Static address variables declared for mapping environment to logging URLs
- STAGING_ADDRESS = 'https://staging.gitlab.com'
- STAGING_REF_ADDRESS = 'https://staging-ref.gitlab.com'
- PRODUCTION_ADDRESS = 'https://gitlab.com'
- PRE_PROD_ADDRESS = 'https://pre.gitlab.com'
+ STAGING_ADDRESS = 'https://staging.gitlab.com'
+ STAGING_REF_ADDRESS = 'https://staging-ref.gitlab.com'
+ PRODUCTION_ADDRESS = 'https://gitlab.com'
+ PRE_PROD_ADDRESS = 'https://pre.gitlab.com'
+
+ # Text titles used for labeling various IDs and URLs
+ CORRELATION_ID_TITLE = 'Correlation Id:'
+ SENTRY_URL_TITLE = 'Sentry Url:'
+ KIBANA_DISCOVER_URL_TITLE = 'Kibana - Discover Url:'
+ KIBANA_DASHBOARD_URL_TITLE = 'Kibana - Dashboard Url:'
class << self
def failure_metadata(correlation_id)
return if correlation_id.blank?
- errors = ["Correlation Id: #{correlation_id}"]
+ errors = ["#{CORRELATION_ID_TITLE} #{correlation_id}"]
env = logging_environment
@@ -24,9 +30,9 @@ module QA
kibana_discover_url = kibana.discover_url
kibana_dashboard_url = kibana.dashboard_url
- errors << "Sentry Url: #{sentry_url}" if sentry_url
- errors << "Kibana - Discover Url: #{kibana_discover_url}" if kibana_discover_url
- errors << "Kibana - Dashboard Url: #{kibana_dashboard_url}" if kibana_dashboard_url
+ errors << "#{SENTRY_URL_TITLE} #{sentry_url}" if sentry_url
+ errors << "#{KIBANA_DISCOVER_URL_TITLE} #{kibana_discover_url}" if kibana_discover_url
+ errors << "#{KIBANA_DASHBOARD_URL_TITLE} #{kibana_dashboard_url}" if kibana_dashboard_url
errors.join("\n")
end
diff --git a/qa/qa/support/matchers/have_matcher.rb b/qa/qa/support/matchers/have_matcher.rb
index 734a8890536..d843949e6b2 100644
--- a/qa/qa/support/matchers/have_matcher.rb
+++ b/qa/qa/support/matchers/have_matcher.rb
@@ -25,6 +25,9 @@ module QA
tag
label
variable
+ system_note
+ alert_with_title
+ incident
].each do |predicate|
RSpec::Matchers.define "have_#{predicate}" do |*args, **kwargs|
match do |page_object|
diff --git a/qa/qa/tools/test_resource_data_processor.rb b/qa/qa/tools/test_resource_data_processor.rb
index a86c94b4914..3312285ecc4 100644
--- a/qa/qa/tools/test_resource_data_processor.rb
+++ b/qa/qa/tools/test_resource_data_processor.rb
@@ -38,7 +38,7 @@ module QA
api_path: api_path,
fabrication_method: fabrication_method,
fabrication_time: fabrication_time,
- http_method: resource.api_fabrication_http_method,
+ http_method: resource.api_fabrication_http_method || :post,
timestamp: Time.now.to_s
}
end
diff --git a/qa/qa/vendor/smocker/event_payload.rb b/qa/qa/vendor/smocker/event_payload.rb
deleted file mode 100644
index 70998e055ea..00000000000
--- a/qa/qa/vendor/smocker/event_payload.rb
+++ /dev/null
@@ -1,61 +0,0 @@
-# frozen_string_literal: true
-
-module QA
- module Vendor
- module Smocker
- class EventPayload
- def initialize(hook_data)
- @hook_data = hook_data
- end
-
- def raw
- @hook_data
- end
-
- def event
- raw[:object_kind]&.to_sym
- end
-
- def event_name
- raw[:event_name]&.to_sym
- end
-
- def project_name
- raw.dig(:project, :name)
- end
-
- def mr?
- event == :merge_request
- end
-
- def issue?
- event == :issue
- end
-
- def note?
- event == :note
- end
-
- def push?
- event == :push
- end
-
- def tag?
- event == :tag_push
- end
-
- def wiki?
- event == :wiki_page
- end
-
- def subgroup_create?
- event_name == :subgroup_create
- end
-
- def subgroup_destroy?
- event_name == :subgroup_destroy
- end
- end
- end
- end
-end
diff --git a/qa/qa/vendor/smocker/history_response.rb b/qa/qa/vendor/smocker/history_response.rb
index 53d5759ef8b..426bbe024ae 100644
--- a/qa/qa/vendor/smocker/history_response.rb
+++ b/qa/qa/vendor/smocker/history_response.rb
@@ -1,6 +1,5 @@
# frozen_string_literal: true
-require_relative './event_payload'
require 'time'
module QA
@@ -23,12 +22,6 @@ module QA
payload[:request]
end
- # @return [EventPayload] the request body as a webhook event
- def as_hook_event
- body = request&.dig(:body)
- EventPayload.new body if body
- end
-
# @return [Time] Time request was recieved
def received
date = request&.dig(:date)
diff --git a/qa/qa/vendor/smocker/smocker_api.rb b/qa/qa/vendor/smocker/smocker_api.rb
index 359d1497825..111de84ffce 100644
--- a/qa/qa/vendor/smocker/smocker_api.rb
+++ b/qa/qa/vendor/smocker/smocker_api.rb
@@ -113,6 +113,14 @@ module QA
end
end
+ # Returns a stringfied version of the Smocker history
+ #
+ # @param session_name [String] the session name for the mock
+ # @return [String] stringified event payloads
+ def stringified_history(session_name = nil)
+ history(session_name).map(&:payload).join("\n")
+ end
+
private
attr_reader :host, :public_port, :admin_port, :scheme
diff --git a/qa/spec/fixtures/ff/bulk_import_projects.yml b/qa/spec/fixtures/ff/async_commit_diff_files.yml
index 853389577cf..0cadf592cc1 100644
--- a/qa/spec/fixtures/ff/bulk_import_projects.yml
+++ b/qa/spec/fixtures/ff/async_commit_diff_files.yml
@@ -1,8 +1,8 @@
---
-name: bulk_import_projects
-introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/68873
-rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/339941
-milestone: '14.3'
+name: async_commit_diff_files
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/38450
+rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/369439
+milestone: '13.3'
type: development
-group: group::import
+group: group::source code
default_enabled: false
diff --git a/qa/spec/resource/api_fabricator_spec.rb b/qa/spec/resource/api_fabricator_spec.rb
index 337c6772a06..96823ea7ada 100644
--- a/qa/spec/resource/api_fabricator_spec.rb
+++ b/qa/spec/resource/api_fabricator_spec.rb
@@ -116,7 +116,7 @@ RSpec.describe QA::Resource::ApiFabricator do
expect { subject.fabricate_via_api! }.to raise_error do |error|
expect(error.class).to eql(described_class::ResourceFabricationFailedError)
- expect(error.to_s).to eql(<<~ERROR.chomp)
+ expect(error.to_s).to eql(<<~ERROR.strip)
Fabrication of FooBarResource using the API failed (400) with `#{raw_post}`.\n
ERROR
end
diff --git a/qa/spec/resource/project_web_hook_spec.rb b/qa/spec/resource/project_web_hook_spec.rb
new file mode 100644
index 00000000000..bca95124c06
--- /dev/null
+++ b/qa/spec/resource/project_web_hook_spec.rb
@@ -0,0 +1,70 @@
+# frozen_string_literal: true
+
+module QA
+ RSpec.describe Resource::ProjectWebHook do
+ let(:smocker_api) { instance_double(Vendor::Smocker::SmockerApi) }
+ let(:smocker_docker) { class_double(Service::DockerRun::Smocker) }
+ let(:history_entries) do
+ [
+ {
+ request: {
+ body: {
+ object_kind: 'tag_push'
+ }
+ }
+ },
+ {
+ request: {
+ body: {
+ object_kind: 'merge_request'
+ }
+ }
+ }
+ ]
+ end
+
+ let(:history_response) { Struct.new(:body).new(history_entries.to_json) }
+
+ it 'configures the project hook events' do
+ setup_mocks
+
+ described_class.setup(pipeline: true, wiki_page: true) do |webhook, _|
+ expect(webhook.pipeline_events).to be(true)
+ expect(webhook.wiki_page_events).to be(true)
+ expect(webhook.push_events).to be(false)
+ end
+ end
+
+ it 'adds an #event method to the smocker object that returns webhook events' do
+ setup_mocks
+
+ # rubocop:disable RSpec/AnyInstanceOf
+ expect_any_instance_of(Vendor::Smocker::SmockerApi).to receive(:get_session_id)
+ .and_return('123')
+ expect_any_instance_of(Vendor::Smocker::SmockerApi).to receive(:get)
+ .with(/history/)
+ .and_return(history_response)
+ # rubocop:enable RSpec/AnyInstanceOf
+
+ described_class.setup do |_, smocker|
+ expect(smocker.events('123')).to include(
+ a_hash_including(object_kind: 'merge_request'),
+ a_hash_including(object_kind: 'tag_push')
+ )
+ end
+ end
+
+ def setup_mocks
+ # rubocop:disable RSpec/AnyInstanceOf
+ expect_any_instance_of(Vendor::Smocker::SmockerApi).to receive(:reset)
+ expect_any_instance_of(Vendor::Smocker::SmockerApi).to receive(:register)
+ # rubocop:enable RSpec/AnyInstanceOf
+
+ expect(Service::DockerRun::Smocker).to receive(:init)
+ .and_yield(Vendor::Smocker::SmockerApi.new(host: 'smocker.net'))
+ allow(subject).to receive(:project)
+ allow(described_class).to receive(:fabricate_via_api!)
+ .and_yield(subject)
+ end
+ end
+end
diff --git a/qa/spec/runtime/env_spec.rb b/qa/spec/runtime/env_spec.rb
index e9c2000681b..66720937007 100644
--- a/qa/spec/runtime/env_spec.rb
+++ b/qa/spec/runtime/env_spec.rb
@@ -189,14 +189,14 @@ RSpec.describe QA::Runtime::Env do
end
describe '.github_access_token' do
- it 'returns "" if GITHUB_ACCESS_TOKEN is not defined' do
- stub_env('GITHUB_ACCESS_TOKEN', nil)
+ it 'returns "" if QA_GITHUB_ACCESS_TOKEN is not defined' do
+ stub_env('QA_GITHUB_ACCESS_TOKEN', nil)
expect(described_class.github_access_token).to eq('')
end
- it 'returns stripped string if GITHUB_ACCESS_TOKEN is defined' do
- stub_env('GITHUB_ACCESS_TOKEN', ' abc123 ')
+ it 'returns stripped string if QA_GITHUB_ACCESS_TOKEN is defined' do
+ stub_env('QA_GITHUB_ACCESS_TOKEN', ' abc123 ')
expect(described_class.github_access_token).to eq('abc123')
end
end
@@ -229,14 +229,14 @@ RSpec.describe QA::Runtime::Env do
end
describe '.require_github_access_token!' do
- it 'raises ArgumentError if GITHUB_ACCESS_TOKEN is not defined' do
- stub_env('GITHUB_ACCESS_TOKEN', nil)
+ it 'raises ArgumentError if QA_GITHUB_ACCESS_TOKEN is not defined' do
+ stub_env('QA_GITHUB_ACCESS_TOKEN', nil)
expect { described_class.require_github_access_token! }.to raise_error(ArgumentError)
end
- it 'does not raise if GITHUB_ACCESS_TOKEN is defined' do
- stub_env('GITHUB_ACCESS_TOKEN', ' abc123 ')
+ it 'does not raise if QA_GITHUB_ACCESS_TOKEN is defined' do
+ stub_env('QA_GITHUB_ACCESS_TOKEN', ' abc123 ')
expect { described_class.require_github_access_token! }.not_to raise_error
end
diff --git a/qa/spec/specs/helpers/context_selector_spec.rb b/qa/spec/specs/helpers/context_selector_spec.rb
index 7541bb45d82..9e46933542e 100644
--- a/qa/spec/specs/helpers/context_selector_spec.rb
+++ b/qa/spec/specs/helpers/context_selector_spec.rb
@@ -43,6 +43,7 @@ RSpec.describe QA::Specs::Helpers::ContextSelector do
end
it 'matches multiple subdomains' do
+ allow(GitlabEdition).to receive(:jh?).and_return(false)
QA::Runtime::Scenario.define(:gitlab_address, "https://staging.gitlab.com")
aggregate_failures do
@@ -51,13 +52,35 @@ RSpec.describe QA::Specs::Helpers::ContextSelector do
end
end
+ it 'matches multiple subdomains on jh side' do
+ allow(GitlabEdition).to receive(:jh?).and_return(true)
+ QA::Runtime::Scenario.define(:gitlab_address, "https://staging.jihulab.com")
+
+ aggregate_failures do
+ expect(described_class.context_matches?(subdomain: [:release, :staging])).to be_truthy
+ expect(described_class.context_matches?(:production, subdomain: [:release, :staging])).to be_truthy
+ end
+ end
+
it 'matches :production' do
+ allow(GitlabEdition).to receive(:jh?).and_return(false)
QA::Runtime::Scenario.define(:gitlab_address, "https://gitlab.com/")
expect(described_class.context_matches?(:production)).to be_truthy
end
+ it 'matches :production on jh side' do
+ allow(GitlabEdition).to receive(:jh?).and_return(true)
+
+ QA::Runtime::Scenario.define(:gitlab_address, "https://jihulab.com/")
+ expect(described_class.context_matches?(:production)).to be_truthy
+
+ QA::Runtime::Scenario.define(:gitlab_address, "https://jihulab.hk/")
+ expect(described_class.context_matches?(:production)).to be_truthy
+ end
+
it 'matches domain' do
+ allow(GitlabEdition).to receive(:jh?).and_return(false)
QA::Runtime::Scenario.define(:gitlab_address, 'https://jihulab.com')
aggregate_failures do
@@ -67,6 +90,26 @@ RSpec.describe QA::Specs::Helpers::ContextSelector do
end
end
+ it 'matches domain on jh side' do
+ # To simulate run tests in JH
+ allow(GitlabEdition).to receive(:jh?).and_return(true)
+ QA::Runtime::Scenario.define(:gitlab_address, 'https://jihulab.com')
+
+ aggregate_failures do
+ expect(described_class.context_matches?(:production)).to be_truthy
+ expect(described_class.context_matches?(domain: 'gitlab')).to be_falsey
+ expect(described_class.context_matches?(domain: 'jihulab')).to be_truthy
+ end
+
+ QA::Runtime::Scenario.define(:gitlab_address, 'https://jihulab.hk')
+
+ aggregate_failures do
+ expect(described_class.context_matches?(:production)).to be_truthy
+ expect(described_class.context_matches?(domain: 'gitlab')).to be_falsey
+ expect(described_class.context_matches?(domain: 'jihulab')).to be_truthy
+ end
+ end
+
it 'matches tld' do
QA::Runtime::Scenario.define(:gitlab_address, 'https://gitlab.cn')
@@ -119,6 +162,7 @@ RSpec.describe QA::Specs::Helpers::ContextSelector do
context 'with different environment set' do
before do
+ allow(GitlabEdition).to receive(:jh?).and_return(false)
QA::Runtime::Scenario.define(:gitlab_address, 'https://gitlab.com')
end
@@ -140,6 +184,31 @@ RSpec.describe QA::Specs::Helpers::ContextSelector do
end
end
end
+
+ context 'with different environment set on jh side' do
+ before do
+ allow(GitlabEdition).to receive(:jh?).and_return(true)
+ QA::Runtime::Scenario.define(:gitlab_address, 'https://jihulab.com')
+ end
+
+ it 'does not run against production' do
+ group = describe_successfully 'Runs in staging', :something, only: { subdomain: :staging } do
+ it('runs in staging') {}
+ end
+
+ expect(group.examples[0].execution_result.status).to eq(:pending)
+ end
+
+ context 'when excluding contexts' do
+ it 'runs against production' do
+ group = describe_successfully 'Runs in staging', :something, except: { subdomain: :staging } do
+ it('runs in staging') {}
+ end
+
+ expect(group.examples[0].execution_result.status).to eq(:passed)
+ end
+ end
+ end
end
it 'runs only in staging' do
@@ -226,6 +295,7 @@ RSpec.describe QA::Specs::Helpers::ContextSelector do
context 'production' do
before do
+ allow(GitlabEdition).to receive(:jh?).and_return(false)
QA::Runtime::Scenario.define(:gitlab_address, 'https://gitlab.com/')
end
@@ -260,6 +330,80 @@ RSpec.describe QA::Specs::Helpers::ContextSelector do
end
end
+ context 'jh mainland production ' do
+ before do
+ allow(GitlabEdition).to receive(:jh?).and_return(true)
+ QA::Runtime::Scenario.define(:gitlab_address, 'https://jihulab.com/')
+ end
+
+ it 'runs on production' do
+ group = describe_successfully do
+ it('runs on prod', only: :production) {}
+ it('does not run in prod', only: { subdomain: :staging }) {}
+ it('runs in prod and staging', only: { subdomain: /(staging.)?/, domain: 'jihulab' }) {}
+ 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)
+ end
+ end
+
+ context 'when excluding contexts' do
+ it 'skips production' do
+ group = describe_successfully do
+ it('skips prod', except: :production) {}
+ it('runs on prod', except: { subdomain: :staging }) {}
+ it('skips prod and staging', except: { subdomain: /(staging.)?/, domain: 'jihulab' }) {}
+ 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)
+ end
+ end
+ end
+ end
+
+ context 'jh hk production ' do
+ before do
+ allow(GitlabEdition).to receive(:jh?).and_return(true)
+ QA::Runtime::Scenario.define(:gitlab_address, 'https://jihulab.hk/')
+ end
+
+ it 'runs on production' do
+ group = describe_successfully do
+ it('runs on prod', only: :production) {}
+ it('does not run in prod', only: { subdomain: :staging }) {}
+ it('runs in prod and staging', only: { subdomain: /(staging.)?/, domain: 'jihulab' }) {}
+ 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)
+ end
+ end
+
+ context 'when excluding contexts' do
+ it 'skips production' do
+ group = describe_successfully do
+ it('skips prod', except: :production) {}
+ it('runs on prod', except: { subdomain: :staging }) {}
+ it('skips prod and staging', except: { subdomain: /(staging.)?/, domain: 'jihulab' }) {}
+ 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)
+ end
+ end
+ end
+ end
+
it 'outputs a message for invalid environments' do
group = describe_successfully do
it('will skip', only: :production) {}
diff --git a/qa/spec/specs/helpers/feature_flag_spec.rb b/qa/spec/specs/helpers/feature_flag_spec.rb
index 491fc22f026..180890b2701 100644
--- a/qa/spec/specs/helpers/feature_flag_spec.rb
+++ b/qa/spec/specs/helpers/feature_flag_spec.rb
@@ -122,6 +122,10 @@ RSpec.describe QA::Specs::Helpers::FeatureFlag do
end
context 'when run on production' do
+ before do
+ allow(GitlabEdition).to receive(:jh?).and_return(false)
+ end
+
before(:context) do
QA::Runtime::Scenario.define(:gitlab_address, 'https://gitlab.com')
end
@@ -147,6 +151,66 @@ RSpec.describe QA::Specs::Helpers::FeatureFlag do
it_behaves_like 'skips with given feature flag metadata', { name: 'global_ff', scope: :global }
end
+ context 'when run on jh production mainland' do
+ before do
+ allow(GitlabEdition).to receive(:jh?).and_return(true)
+ end
+
+ before(:context) do
+ QA::Runtime::Scenario.define(:gitlab_address, 'https://jihulab.com')
+ end
+
+ context 'when no scope is defined' do
+ it_behaves_like 'skips with given feature flag metadata', { name: 'no_scope_ff' }
+
+ context 'for only one test in the example group' do
+ it 'only skips specified test and runs all others' do
+ group = describe_successfully 'Feature flag set for one test' do
+ it('is skipped', feature_flag: { name: 'single_test_ff' }) {}
+ it('passes') {}
+ end
+
+ expect(group.examples[0].execution_result.status).to eq(:pending)
+ expect(group.examples[1].execution_result.status).to eq(:passed)
+ end
+ end
+ end
+
+ it_behaves_like 'skips with given feature flag metadata', { name: 'actor_ff', scope: :project }
+
+ it_behaves_like 'skips with given feature flag metadata', { name: 'global_ff', scope: :global }
+ end
+
+ context 'when run on jh production hk' do
+ before do
+ allow(GitlabEdition).to receive(:jh?).and_return(true)
+ end
+
+ before(:context) do
+ QA::Runtime::Scenario.define(:gitlab_address, 'https://jihulab.hk')
+ end
+
+ context 'when no scope is defined' do
+ it_behaves_like 'skips with given feature flag metadata', { name: 'no_scope_ff' }
+
+ context 'for only one test in the example group' do
+ it 'only skips specified test and runs all others' do
+ group = describe_successfully 'Feature flag set for one test' do
+ it('is skipped', feature_flag: { name: 'single_test_ff' }) {}
+ it('passes') {}
+ end
+
+ expect(group.examples[0].execution_result.status).to eq(:pending)
+ expect(group.examples[1].execution_result.status).to eq(:passed)
+ end
+ end
+ end
+
+ it_behaves_like 'skips with given feature flag metadata', { name: 'actor_ff', scope: :project }
+
+ it_behaves_like 'skips with given feature flag metadata', { name: 'global_ff', scope: :global }
+ end
+
context 'when run on pre' do
before(:context) do
QA::Runtime::Scenario.define(:gitlab_address, 'https://pre.gitlab.com')
diff --git a/qa/spec/tools/ci/ff_changes_spec.rb b/qa/spec/tools/ci/ff_changes_spec.rb
index 71ca26867e0..d0bf6de148d 100644
--- a/qa/spec/tools/ci/ff_changes_spec.rb
+++ b/qa/spec/tools/ci/ff_changes_spec.rb
@@ -12,7 +12,7 @@ RSpec.describe QA::Tools::Ci::FfChanges do
let(:mr_diff) do
[
{
- path: "config/feature_flags/development/bulk_import_projects.yml",
+ path: "config/feature_flags/development/async_commit_diff_files.yml",
deleted_file: deleted_file
}
]
@@ -21,12 +21,12 @@ RSpec.describe QA::Tools::Ci::FfChanges do
before do
allow(File).to receive(:read)
.with(File.expand_path("../#{mr_diff.first[:path]}", QA::Runtime::Path.qa_root))
- .and_return(File.read("spec/fixtures/ff/bulk_import_projects.yml"))
+ .and_return(File.read("spec/fixtures/ff/async_commit_diff_files.yml"))
end
context "with changed feature flag" do
it "returns inverse ff state option" do
- expect(ff_changes.fetch).to eq("bulk_import_projects=enabled")
+ expect(ff_changes.fetch).to eq("async_commit_diff_files=enabled")
end
end
@@ -34,7 +34,7 @@ RSpec.describe QA::Tools::Ci::FfChanges do
let(:deleted_file) { true }
it "returns deleted ff state option" do
- expect(ff_changes.fetch).to eq("bulk_import_projects=deleted")
+ expect(ff_changes.fetch).to eq("async_commit_diff_files=deleted")
end
end
end
diff --git a/qa/spec/vendor/smocker_api_spec.rb b/qa/spec/vendor/smocker_api_spec.rb
new file mode 100644
index 00000000000..b54197b8b1f
--- /dev/null
+++ b/qa/spec/vendor/smocker_api_spec.rb
@@ -0,0 +1,18 @@
+# frozen_string_literal: true
+
+module QA
+ RSpec.describe Vendor::Smocker::SmockerApi do
+ let(:host) { 'smocker.bar' }
+
+ subject { described_class.new(host: host) }
+
+ it 'retries until the service is ready' do
+ expect(subject).to receive(:get)
+ .and_raise(StandardError)
+ .and_raise(StandardError)
+ .and_return(200)
+
+ expect { subject.wait_for_ready }.not_to raise_error
+ end
+ end
+end