diff options
Diffstat (limited to 'qa')
253 files changed, 2268 insertions, 1325 deletions
diff --git a/qa/Dockerfile b/qa/Dockerfile index 341732ab56f..7f236a25288 100644 --- a/qa/Dockerfile +++ b/qa/Dockerfile @@ -1,8 +1,9 @@ ARG DOCKER_VERSION=20.10.14 -ARG CHROME_VERSION=103 +ARG CHROME_VERSION=106 ARG QA_BUILD_TARGET=qa +ARG RUBY_VERSION=2.7 -FROM registry.gitlab.com/gitlab-org/gitlab-build-images/debian-bullseye-ruby-2.7:bundler-2.3-git-2.33-lfs-2.9-chrome-${CHROME_VERSION}-docker-${DOCKER_VERSION}-gcloud-383-kubectl-1.23 AS qa +FROM registry.gitlab.com/gitlab-org/gitlab-build-images/debian-bullseye-ruby-${RUBY_VERSION}:bundler-2.3-git-2.36-lfs-2.9-chrome-${CHROME_VERSION}-docker-${DOCKER_VERSION}-gcloud-383-kubectl-1.23 AS qa LABEL maintainer="GitLab Quality Department <quality@gitlab.com>" ENV DEBIAN_FRONTEND="noninteractive" diff --git a/qa/Gemfile b/qa/Gemfile index 12e5d66fc6b..b84a22883d1 100644 --- a/qa/Gemfile +++ b/qa/Gemfile @@ -2,31 +2,30 @@ source 'https://rubygems.org' -gem 'gitlab-qa', '~> 8', '>= 8.8.0', require: 'gitlab/qa' +gem 'gitlab-qa', '~> 8', '>= 8.11.0', require: 'gitlab/qa' gem 'activesupport', '~> 6.1.4.7' # This should stay in sync with the root's Gemfile -gem 'allure-rspec', '~> 2.18.0' -gem 'capybara', '~> 3.37.1' +gem 'allure-rspec', '~> 2.19.0' +gem 'capybara', '~> 3.38.0' gem 'capybara-screenshot', '~> 1.0.26' -gem 'rake', '~> 13' -gem 'rspec', '~> 3.11' -gem 'selenium-webdriver', '~> 4.5' +gem 'rake', '~> 13', '>= 13.0.6' +gem 'rspec', '~> 3.12' +gem 'selenium-webdriver', '~> 4.6', '>= 4.6.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.1', require: 'rspec/retry' +gem 'rspec-retry', '~> 0.6.2', require: 'rspec/retry' gem 'rspec_junit_formatter', '~> 0.6.0' -gem 'faker', '~> 2.23' +gem 'faker', '~> 3.0' gem 'knapsack', '~> 4.0' -gem 'parallel_tests', '~> 3.13' -gem 'rotp', '~> 6.2.0' -gem 'timecop', '~> 0.9.5' -gem 'parallel', '~> 1.19' -gem 'rainbow', '~> 3.0.0' +gem 'parallel_tests', '~> 4.0' +gem 'rotp', '~> 6.2.1' +gem 'parallel', '~> 1.22', '>= 1.22.1' +gem 'rainbow', '~> 3.1.1' gem 'rspec-parameterized', '~> 0.5.2' -gem 'octokit', '~> 5.6.1' +gem 'octokit', '~> 6.0.0' gem "faraday-retry", "~> 2.0" gem 'webdrivers', '~> 5.2' gem 'zeitwerk', '~> 2.4' -gem 'influxdb-client', '~> 1.17' +gem 'influxdb-client', '~> 2.8' gem 'terminal-table', '~> 3.0.2', require: false gem 'slack-notifier', '~> 2.4', require: false gem 'fog-google', '~> 1.19', require: false @@ -36,7 +35,7 @@ gem "warning", "~> 1.3" gem 'confiner', '~> 0.3' gem 'chemlab', '~> 0.10' -gem 'chemlab-library-www-gitlab-com', '~> 0.1' +gem 'chemlab-library-www-gitlab-com', '~> 0.1', '>= 0.1.1' # dependencies for jenkins client gem 'nokogiri', '~> 1.13', '>= 1.13.9' diff --git a/qa/Gemfile.lock b/qa/Gemfile.lock index 23f82f553f1..3ccc5fe9be3 100644 --- a/qa/Gemfile.lock +++ b/qa/Gemfile.lock @@ -15,10 +15,10 @@ GEM rack-test (>= 1.1.0, < 2.0) rest-client (>= 2.0.2, < 3.0) rspec (~> 3.8) - allure-rspec (2.18.0) - allure-ruby-commons (= 2.18.0) + allure-rspec (2.19.0) + allure-ruby-commons (= 2.19.0) rspec-core (>= 3.8, < 4) - allure-ruby-commons (2.18.0) + allure-ruby-commons (2.19.0) mime-types (>= 3.3, < 4) oj (>= 3.10, < 4) require_all (>= 2, < 4) @@ -27,7 +27,7 @@ GEM binding_ninja (0.2.3) builder (3.2.4) byebug (11.1.3) - capybara (3.37.1) + capybara (3.38.0) addressable matrix mini_mime (>= 0.1.3) @@ -61,7 +61,7 @@ GEM domain_name (0.5.20190701) unf (>= 0.0.5, < 1.0.0) excon (0.92.4) - faker (2.23.0) + faker (3.0.0) i18n (>= 1.8.11, < 2) faraday (2.5.2) faraday-net_http (>= 2.0, < 3.1) @@ -100,14 +100,13 @@ GEM gitlab (4.18.0) httparty (~> 0.18) terminal-table (>= 1.5.1) - gitlab-qa (8.8.0) + gitlab-qa (8.11.0) activesupport (~> 6.1) gitlab (~> 4.18.0) http (~> 5.0) nokogiri (~> 1.10) rainbow (>= 3, < 4) table_print (= 1.5.7) - toxiproxy (~> 2.0.2) zeitwerk (>= 2, < 3) google-apis-compute_v1 (0.51.0) google-apis-core (>= 0.7.2, < 2.a) @@ -156,7 +155,7 @@ GEM httpclient (2.8.3) i18n (1.12.0) concurrent-ruby (~> 1.0) - influxdb-client (1.17.0) + influxdb-client (2.8.0) jwt (2.5.0) knapsack (4.0.0) rake @@ -182,13 +181,13 @@ GEM nokogiri (1.13.9) mini_portile2 (~> 2.8.0) racc (~> 1.4) - octokit (5.6.1) + octokit (6.0.0) faraday (>= 1, < 3) sawyer (~> 0.9) - oj (3.13.21) + oj (3.13.23) os (1.1.4) - parallel (1.19.2) - parallel_tests (3.13.0) + parallel (1.22.1) + parallel_tests (4.0.0) parallel parser (3.1.2.1) ast (~> 2.4.1) @@ -207,7 +206,7 @@ GEM rack (2.2.3.1) rack-test (1.1.0) rack (>= 1.0, < 3) - rainbow (3.0.0) + rainbow (3.1.1) rake (13.0.6) regexp_parser (2.1.1) representable (3.2.0) @@ -222,19 +221,19 @@ GEM netrc (~> 0.8) retriable (3.1.2) rexml (3.2.5) - rotp (6.2.0) - rspec (3.11.0) - rspec-core (~> 3.11.0) - rspec-expectations (~> 3.11.0) - rspec-mocks (~> 3.11.0) - rspec-core (3.11.0) - rspec-support (~> 3.11.0) - rspec-expectations (3.11.1) + rotp (6.2.1) + rspec (3.12.0) + rspec-core (~> 3.12.0) + rspec-expectations (~> 3.12.0) + rspec-mocks (~> 3.12.0) + rspec-core (3.12.0) + rspec-support (~> 3.12.0) + rspec-expectations (3.12.0) diff-lcs (>= 1.2.0, < 2.0) - rspec-support (~> 3.11.0) - rspec-mocks (3.11.1) + rspec-support (~> 3.12.0) + rspec-mocks (3.12.0) diff-lcs (>= 1.2.0, < 2.0) - rspec-support (~> 3.11.0) + rspec-support (~> 3.12.0) rspec-parameterized (0.5.2) binding_ninja (>= 0.2.3) parser @@ -243,7 +242,7 @@ GEM unparser rspec-retry (0.6.2) rspec-core (> 3.3) - rspec-support (3.11.1) + rspec-support (3.12.0) rspec_junit_formatter (0.6.0) rspec-core (>= 2, < 4, != 2.12.0) ruby-debug-ide (0.7.3) @@ -253,7 +252,7 @@ GEM sawyer (0.9.2) addressable (>= 2.3.5) faraday (>= 0.17.3, < 3) - selenium-webdriver (4.5.0) + selenium-webdriver (4.6.1) childprocess (>= 0.5, < 5.0) rexml (~> 3.2, >= 3.2.5) rubyzip (>= 1.2.2, < 3.0) @@ -268,8 +267,6 @@ GEM table_print (1.5.7) terminal-table (3.0.2) unicode-display_width (>= 1.1.1, < 3) - timecop (0.9.5) - toxiproxy (2.0.2) trailblazer-option (0.1.2) tzinfo (2.0.5) concurrent-ruby (~> 1.0) @@ -303,41 +300,40 @@ PLATFORMS DEPENDENCIES activesupport (~> 6.1.4.7) airborne (~> 0.3.7) - allure-rspec (~> 2.18.0) - capybara (~> 3.37.1) + allure-rspec (~> 2.19.0) + capybara (~> 3.38.0) capybara-screenshot (~> 1.0.26) chemlab (~> 0.10) - chemlab-library-www-gitlab-com (~> 0.1) + chemlab-library-www-gitlab-com (~> 0.1, >= 0.1.1) confiner (~> 0.3) deprecation_toolkit (~> 2.0.0) - faker (~> 2.23) + faker (~> 3.0) faraday-retry (~> 2.0) fog-core (= 2.1.0) fog-google (~> 1.19) - gitlab-qa (~> 8, >= 8.8.0) - influxdb-client (~> 1.17) + gitlab-qa (~> 8, >= 8.11.0) + influxdb-client (~> 2.8) knapsack (~> 4.0) nokogiri (~> 1.13, >= 1.13.9) - octokit (~> 5.6.1) - parallel (~> 1.19) - parallel_tests (~> 3.13) + octokit (~> 6.0.0) + parallel (~> 1.22, >= 1.22.1) + parallel_tests (~> 4.0) pry-byebug (~> 3.10.1) - rainbow (~> 3.0.0) - rake (~> 13) + rainbow (~> 3.1.1) + rake (~> 13, >= 13.0.6) rest-client (~> 2.1.0) - rotp (~> 6.2.0) - rspec (~> 3.11) + rotp (~> 6.2.1) + rspec (~> 3.12) rspec-parameterized (~> 0.5.2) - rspec-retry (~> 0.6.1) + rspec-retry (~> 0.6.2) rspec_junit_formatter (~> 0.6.0) ruby-debug-ide (~> 0.7.3) - selenium-webdriver (~> 4.5) + selenium-webdriver (~> 4.6, >= 4.6.1) slack-notifier (~> 2.4) terminal-table (~> 3.0.2) - timecop (~> 0.9.5) warning (~> 1.3) webdrivers (~> 5.2) zeitwerk (~> 2.4) BUNDLED WITH - 2.3.24 + 2.3.25 diff --git a/qa/lib/gitlab/page/group/settings/usage_quotas.rb b/qa/lib/gitlab/page/group/settings/usage_quotas.rb index a1ab345bf1e..8540bce3da8 100644 --- a/qa/lib/gitlab/page/group/settings/usage_quotas.rb +++ b/qa/lib/gitlab/page/group/settings/usage_quotas.rb @@ -7,6 +7,11 @@ module Gitlab class UsageQuotas < Chemlab::Page # Seats section link :seats_tab + div :seats_in_use + p :seats_used + p :seats_owed + table :subscription_users + button :remove_user # Pipelines section link :pipelines_tab diff --git a/qa/lib/gitlab/page/group/settings/usage_quota.stub.rb b/qa/lib/gitlab/page/group/settings/usage_quotas.stub.rb index 2a5d9a6bb5e..6c38625bb3b 100644 --- a/qa/lib/gitlab/page/group/settings/usage_quota.stub.rb +++ b/qa/lib/gitlab/page/group/settings/usage_quotas.stub.rb @@ -4,7 +4,7 @@ module Gitlab module Page module Group module Settings - module UsageQuota + module UsageQuotas # @note Defined as +link :seats_tab+ # Clicks +seats_tab+ def seats_tab @@ -12,8 +12,8 @@ module Gitlab end # @example - # Gitlab::Page::Group::Settings::UsageQuota.perform do |usage_quota| - # expect(usage_quota.seats_tab_element).to exist + # Gitlab::Page::Group::Settings::UsageQuotas.perform do |usage_quotas| + # expect(usage_quotas.seats_tab_element).to exist # end # @return [Watir::Link] The raw +Link+ element def seats_tab_element @@ -21,14 +21,134 @@ module Gitlab end # @example - # Gitlab::Page::Group::Settings::UsageQuota.perform do |usage_quota| - # expect(usage_quota).to be_seats_tab + # Gitlab::Page::Group::Settings::UsageQuotas.perform do |usage_quotas| + # expect(usage_quotas).to be_seats_tab # end # @return [Boolean] true if the +seats_tab+ element is present on the page def seats_tab? # This is a stub, used for indexing. The method is dynamically generated. end + # @note Defined as +div :seats_in_use+ + # @return [String] The text content or value of +seats_in_use+ + def seats_in_use + # This is a stub, used for indexing. The method is dynamically generated. + end + + # @example + # Gitlab::Page::Group::Settings::UsageQuotas.perform do |usage_quotas| + # expect(usage_quotas.seats_in_use_element).to exist + # end + # @return [Watir::Div] The raw +Div+ element + def seats_in_use_element + # This is a stub, used for indexing. The method is dynamically generated. + end + + # @example + # Gitlab::Page::Group::Settings::UsageQuotas.perform do |usage_quotas| + # expect(usage_quotas).to be_seats_in_use + # end + # @return [Boolean] true if the +seats_in_use+ element is present on the page + def seats_in_use? + # This is a stub, used for indexing. The method is dynamically generated. + end + + # @note Defined as +p :seats_used+ + # @return [String] The text content or value of +seats_used+ + def seats_used + # This is a stub, used for indexing. The method is dynamically generated. + end + + # @example + # Gitlab::Page::Group::Settings::UsageQuotas.perform do |usage_quotas| + # expect(usage_quotas.seats_used_element).to exist + # end + # @return [Watir::P] The raw +P+ element + def seats_used_element + # This is a stub, used for indexing. The method is dynamically generated. + end + + # @example + # Gitlab::Page::Group::Settings::UsageQuotas.perform do |usage_quotas| + # expect(usage_quotas).to be_seats_used + # end + # @return [Boolean] true if the +seats_used+ element is present on the page + def seats_used? + # This is a stub, used for indexing. The method is dynamically generated. + end + + # @note Defined as +p :seats_owed+ + # @return [String] The text content or value of +seats_owed+ + def seats_owed + # This is a stub, used for indexing. The method is dynamically generated. + end + + # @example + # Gitlab::Page::Group::Settings::UsageQuotas.perform do |usage_quotas| + # expect(usage_quotas.seats_owed_element).to exist + # end + # @return [Watir::P] The raw +P+ element + def seats_owed_element + # This is a stub, used for indexing. The method is dynamically generated. + end + + # @example + # Gitlab::Page::Group::Settings::UsageQuotas.perform do |usage_quotas| + # expect(usage_quotas).to be_seats_owed + # end + # @return [Boolean] true if the +seats_owed+ element is present on the page + def seats_owed? + # This is a stub, used for indexing. The method is dynamically generated. + end + + # @note Defined as +table :subscription_users+ + # @return [String] The text content or value of +subscription_users+ + def subscription_users + # This is a stub, used for indexing. The method is dynamically generated. + end + + # @example + # Gitlab::Page::Group::Settings::UsageQuotas.perform do |usage_quotas| + # expect(usage_quotas.subscription_users_element).to exist + # end + # @return [Watir::Table] The raw +Table+ element + def subscription_users_element + # This is a stub, used for indexing. The method is dynamically generated. + end + + # @example + # Gitlab::Page::Group::Settings::UsageQuotas.perform do |usage_quotas| + # expect(usage_quotas).to be_subscription_users + # end + # @return [Boolean] true if the +subscription_users+ element is present on the page + def subscription_users? + # This is a stub, used for indexing. The method is dynamically generated. + end + + # @note Defined as +button :remove_user+ + # Clicks +remove_user+ + def remove_user + # This is a stub, used for indexing. The method is dynamically generated. + end + + # @example + # Gitlab::Page::Group::Settings::UsageQuotas.perform do |usage_quotas| + # expect(usage_quotas.remove_user_element).to exist + # end + # @return [Watir::Button] The raw +Button+ element + def remove_user_element + # This is a stub, used for indexing. The method is dynamically generated. + end + + # @example + # Gitlab::Page::Group::Settings::UsageQuotas.perform do |usage_quotas| + # expect(usage_quotas).to be_remove_user + # end + # @return [Boolean] true if the +remove_user+ element is present on the page + def remove_user? + # This is a stub, used for indexing. The method is dynamically generated. + end + # @note Defined as +link :pipelines_tab+ # Clicks +pipelines_tab+ def pipelines_tab @@ -36,8 +156,8 @@ module Gitlab end # @example - # Gitlab::Page::Group::Settings::UsageQuota.perform do |usage_quota| - # expect(usage_quota.pipelines_tab_element).to exist + # Gitlab::Page::Group::Settings::UsageQuotas.perform do |usage_quotas| + # expect(usage_quotas.pipelines_tab_element).to exist # end # @return [Watir::Link] The raw +Link+ element def pipelines_tab_element @@ -45,8 +165,8 @@ module Gitlab end # @example - # Gitlab::Page::Group::Settings::UsageQuota.perform do |usage_quota| - # expect(usage_quota).to be_pipelines_tab + # Gitlab::Page::Group::Settings::UsageQuotas.perform do |usage_quotas| + # expect(usage_quotas).to be_pipelines_tab # end # @return [Boolean] true if the +pipelines_tab+ element is present on the page def pipelines_tab? @@ -60,8 +180,8 @@ module Gitlab end # @example - # Gitlab::Page::Group::Settings::UsageQuota.perform do |usage_quota| - # expect(usage_quota.buy_ci_minutes_element).to exist + # Gitlab::Page::Group::Settings::UsageQuotas.perform do |usage_quotas| + # expect(usage_quotas.buy_ci_minutes_element).to exist # end # @return [Watir::Link] The raw +Link+ element def buy_ci_minutes_element @@ -69,8 +189,8 @@ module Gitlab end # @example - # Gitlab::Page::Group::Settings::UsageQuota.perform do |usage_quota| - # expect(usage_quota).to be_buy_ci_minutes + # Gitlab::Page::Group::Settings::UsageQuotas.perform do |usage_quotas| + # expect(usage_quotas).to be_buy_ci_minutes # end # @return [Boolean] true if the +buy_ci_minutes+ element is present on the page def buy_ci_minutes? @@ -84,8 +204,8 @@ module Gitlab end # @example - # Gitlab::Page::Group::Settings::UsageQuota.perform do |usage_quota| - # expect(usage_quota.plan_ci_minutes_element).to exist + # Gitlab::Page::Group::Settings::UsageQuotas.perform do |usage_quotas| + # expect(usage_quotas.plan_ci_minutes_element).to exist # end # @return [Watir::Div] The raw +Div+ element def plan_ci_minutes_element @@ -93,8 +213,8 @@ module Gitlab end # @example - # Gitlab::Page::Group::Settings::UsageQuota.perform do |usage_quota| - # expect(usage_quota).to be_plan_ci_minutes + # Gitlab::Page::Group::Settings::UsageQuotas.perform do |usage_quotas| + # expect(usage_quotas).to be_plan_ci_minutes # end # @return [Boolean] true if the +plan_ci_minutes+ element is present on the page def plan_ci_minutes? @@ -108,8 +228,8 @@ module Gitlab end # @example - # Gitlab::Page::Group::Settings::UsageQuota.perform do |usage_quota| - # expect(usage_quota.additional_ci_minutes_element).to exist + # Gitlab::Page::Group::Settings::UsageQuotas.perform do |usage_quotas| + # expect(usage_quotas.additional_ci_minutes_element).to exist # end # @return [Watir::Div] The raw +Div+ element def additional_ci_minutes_element @@ -117,8 +237,8 @@ module Gitlab end # @example - # Gitlab::Page::Group::Settings::UsageQuota.perform do |usage_quota| - # expect(usage_quota).to be_additional_ci_minutes + # Gitlab::Page::Group::Settings::UsageQuotas.perform do |usage_quotas| + # expect(usage_quotas).to be_additional_ci_minutes # end # @return [Boolean] true if the +additional_ci_minutes+ element is present on the page def additional_ci_minutes? @@ -132,8 +252,8 @@ module Gitlab end # @example - # Gitlab::Page::Group::Settings::UsageQuota.perform do |usage_quota| - # expect(usage_quota.ci_purchase_successful_alert_element).to exist + # Gitlab::Page::Group::Settings::UsageQuotas.perform do |usage_quotas| + # expect(usage_quotas.ci_purchase_successful_alert_element).to exist # end # @return [Watir::Div] The raw +Div+ element def ci_purchase_successful_alert_element @@ -141,8 +261,8 @@ module Gitlab end # @example - # Gitlab::Page::Group::Settings::UsageQuota.perform do |usage_quota| - # expect(usage_quota).to be_ci_purchase_successful_alert + # Gitlab::Page::Group::Settings::UsageQuotas.perform do |usage_quotas| + # expect(usage_quotas).to be_ci_purchase_successful_alert # end # @return [Boolean] true if the +ci_purchase_successful_alert+ element is present on the page def ci_purchase_successful_alert? @@ -156,8 +276,8 @@ module Gitlab end # @example - # Gitlab::Page::Group::Settings::UsageQuota.perform do |usage_quota| - # expect(usage_quota.storage_tab_element).to exist + # Gitlab::Page::Group::Settings::UsageQuotas.perform do |usage_quotas| + # expect(usage_quotas.storage_tab_element).to exist # end # @return [Watir::Link] The raw +Link+ element def storage_tab_element @@ -165,35 +285,35 @@ module Gitlab end # @example - # Gitlab::Page::Group::Settings::UsageQuota.perform do |usage_quota| - # expect(usage_quota).to be_storage_tab + # Gitlab::Page::Group::Settings::UsageQuotas.perform do |usage_quotas| + # expect(usage_quotas).to be_storage_tab # end # @return [Boolean] true if the +storage_tab+ element is present on the page def storage_tab? # This is a stub, used for indexing. The method is dynamically generated. end - # @note Defined as +link :buy_storage+ - # Clicks +buy_storage+ - def buy_storage + # @note Defined as +link :purchase_more_storage+ + # Clicks +purchase_more_storage+ + def purchase_more_storage # This is a stub, used for indexing. The method is dynamically generated. end # @example - # Gitlab::Page::Group::Settings::UsageQuota.perform do |usage_quota| - # expect(usage_quota.buy_storage_element).to exist + # Gitlab::Page::Group::Settings::UsageQuotas.perform do |usage_quotas| + # expect(usage_quotas.purchase_more_storage_element).to exist # end # @return [Watir::Link] The raw +Link+ element - def buy_storage_element + def purchase_more_storage_element # This is a stub, used for indexing. The method is dynamically generated. end # @example - # Gitlab::Page::Group::Settings::UsageQuota.perform do |usage_quota| - # expect(usage_quota).to be_buy_storage + # Gitlab::Page::Group::Settings::UsageQuotas.perform do |usage_quotas| + # expect(usage_quotas).to be_purchase_more_storage # end - # @return [Boolean] true if the +buy_storage+ element is present on the page - def buy_storage? + # @return [Boolean] true if the +purchase_more_storage+ element is present on the page + def purchase_more_storage? # This is a stub, used for indexing. The method is dynamically generated. end @@ -204,8 +324,8 @@ module Gitlab end # @example - # Gitlab::Page::Group::Settings::UsageQuota.perform do |usage_quota| - # expect(usage_quota.used_storage_message_element).to exist + # Gitlab::Page::Group::Settings::UsageQuotas.perform do |usage_quotas| + # expect(usage_quotas.used_storage_message_element).to exist # end # @return [Watir::Div] The raw +Div+ element def used_storage_message_element @@ -213,8 +333,8 @@ module Gitlab end # @example - # Gitlab::Page::Group::Settings::UsageQuota.perform do |usage_quota| - # expect(usage_quota).to be_used_storage_message + # Gitlab::Page::Group::Settings::UsageQuotas.perform do |usage_quotas| + # expect(usage_quotas).to be_used_storage_message # end # @return [Boolean] true if the +used_storage_message+ element is present on the page def used_storage_message? @@ -228,8 +348,8 @@ module Gitlab end # @example - # Gitlab::Page::Group::Settings::UsageQuota.perform do |usage_quota| - # expect(usage_quota.group_usage_message_element).to exist + # Gitlab::Page::Group::Settings::UsageQuotas.perform do |usage_quotas| + # expect(usage_quotas.group_usage_message_element).to exist # end # @return [Watir::Div] The raw +Div+ element def group_usage_message_element @@ -237,8 +357,8 @@ module Gitlab end # @example - # Gitlab::Page::Group::Settings::UsageQuota.perform do |usage_quota| - # expect(usage_quota).to be_group_usage_message + # Gitlab::Page::Group::Settings::UsageQuotas.perform do |usage_quotas| + # expect(usage_quotas).to be_group_usage_message # end # @return [Boolean] true if the +group_usage_message+ element is present on the page def group_usage_message? @@ -252,8 +372,8 @@ module Gitlab end # @example - # Gitlab::Page::Group::Settings::UsageQuota.perform do |usage_quota| - # expect(usage_quota.dependency_proxy_usage_element).to exist + # Gitlab::Page::Group::Settings::UsageQuotas.perform do |usage_quotas| + # expect(usage_quotas.dependency_proxy_usage_element).to exist # end # @return [Watir::Div] The raw +Div+ element def dependency_proxy_usage_element @@ -261,8 +381,8 @@ module Gitlab end # @example - # Gitlab::Page::Group::Settings::UsageQuota.perform do |usage_quota| - # expect(usage_quota).to be_dependency_proxy_usage + # Gitlab::Page::Group::Settings::UsageQuotas.perform do |usage_quotas| + # expect(usage_quotas).to be_dependency_proxy_usage # end # @return [Boolean] true if the +dependency_proxy_usage+ element is present on the page def dependency_proxy_usage? @@ -276,8 +396,8 @@ module Gitlab end # @example - # Gitlab::Page::Group::Settings::UsageQuota.perform do |usage_quota| - # expect(usage_quota.dependency_proxy_size_element).to exist + # Gitlab::Page::Group::Settings::UsageQuotas.perform do |usage_quotas| + # expect(usage_quotas.dependency_proxy_size_element).to exist # end # @return [Watir::Span] The raw +Span+ element def dependency_proxy_size_element @@ -285,8 +405,8 @@ module Gitlab end # @example - # Gitlab::Page::Group::Settings::UsageQuota.perform do |usage_quota| - # expect(usage_quota).to be_dependency_proxy_size + # Gitlab::Page::Group::Settings::UsageQuotas.perform do |usage_quotas| + # expect(usage_quotas).to be_dependency_proxy_size # end # @return [Boolean] true if the +dependency_proxy_size+ element is present on the page def dependency_proxy_size? @@ -300,8 +420,8 @@ module Gitlab end # @example - # Gitlab::Page::Group::Settings::UsageQuota.perform do |usage_quota| - # expect(usage_quota.container_registry_usage_element).to exist + # Gitlab::Page::Group::Settings::UsageQuotas.perform do |usage_quotas| + # expect(usage_quotas.container_registry_usage_element).to exist # end # @return [Watir::Div] The raw +Div+ element def container_registry_usage_element @@ -309,8 +429,8 @@ module Gitlab end # @example - # Gitlab::Page::Group::Settings::UsageQuota.perform do |usage_quota| - # expect(usage_quota).to be_container_registry_usage + # Gitlab::Page::Group::Settings::UsageQuotas.perform do |usage_quotas| + # expect(usage_quotas).to be_container_registry_usage # end # @return [Boolean] true if the +container_registry_usage+ element is present on the page def container_registry_usage? @@ -324,8 +444,8 @@ module Gitlab end # @example - # Gitlab::Page::Group::Settings::UsageQuota.perform do |usage_quota| - # expect(usage_quota.project_storage_used_element).to exist + # Gitlab::Page::Group::Settings::UsageQuotas.perform do |usage_quotas| + # expect(usage_quotas.project_storage_used_element).to exist # end # @return [Watir::Div] The raw +Div+ element def project_storage_used_element @@ -333,8 +453,8 @@ module Gitlab end # @example - # Gitlab::Page::Group::Settings::UsageQuota.perform do |usage_quota| - # expect(usage_quota).to be_project_storage_used + # Gitlab::Page::Group::Settings::UsageQuotas.perform do |usage_quotas| + # expect(usage_quotas).to be_project_storage_used # end # @return [Boolean] true if the +project_storage_used+ element is present on the page def project_storage_used? @@ -348,8 +468,8 @@ module Gitlab end # @example - # Gitlab::Page::Group::Settings::UsageQuota.perform do |usage_quota| - # expect(usage_quota.project_element).to exist + # Gitlab::Page::Group::Settings::UsageQuotas.perform do |usage_quotas| + # expect(usage_quotas.project_element).to exist # end # @return [Watir::Div] The raw +Div+ element def project_element @@ -357,8 +477,8 @@ module Gitlab end # @example - # Gitlab::Page::Group::Settings::UsageQuota.perform do |usage_quota| - # expect(usage_quota).to be_project + # Gitlab::Page::Group::Settings::UsageQuotas.perform do |usage_quotas| + # expect(usage_quotas).to be_project # end # @return [Boolean] true if the +project+ element is present on the page def project? @@ -372,8 +492,8 @@ module Gitlab end # @example - # Gitlab::Page::Group::Settings::UsageQuota.perform do |usage_quota| - # expect(usage_quota.storage_type_legend_element).to exist + # Gitlab::Page::Group::Settings::UsageQuotas.perform do |usage_quotas| + # expect(usage_quotas.storage_type_legend_element).to exist # end # @return [Watir::Div] The raw +Div+ element def storage_type_legend_element @@ -381,8 +501,8 @@ module Gitlab end # @example - # Gitlab::Page::Group::Settings::UsageQuota.perform do |usage_quota| - # expect(usage_quota).to be_storage_type_legend + # Gitlab::Page::Group::Settings::UsageQuotas.perform do |usage_quotas| + # expect(usage_quotas).to be_storage_type_legend # end # @return [Boolean] true if the +storage_type_legend+ element is present on the page def storage_type_legend? @@ -396,8 +516,8 @@ module Gitlab end # @example - # Gitlab::Page::Group::Settings::UsageQuota.perform do |usage_quota| - # expect(usage_quota.container_registry_size_element).to exist + # Gitlab::Page::Group::Settings::UsageQuotas.perform do |usage_quotas| + # expect(usage_quotas.container_registry_size_element).to exist # end # @return [Watir::Span] The raw +Span+ element def container_registry_size_element @@ -405,8 +525,8 @@ module Gitlab end # @example - # Gitlab::Page::Group::Settings::UsageQuota.perform do |usage_quota| - # expect(usage_quota).to be_container_registry_size + # Gitlab::Page::Group::Settings::UsageQuotas.perform do |usage_quotas| + # expect(usage_quotas).to be_container_registry_size # end # @return [Boolean] true if the +container_registry_size+ element is present on the page def container_registry_size? @@ -420,8 +540,8 @@ module Gitlab end # @example - # Gitlab::Page::Group::Settings::UsageQuota.perform do |usage_quota| - # expect(usage_quota.purchased_usage_total_free_element).to exist + # Gitlab::Page::Group::Settings::UsageQuotas.perform do |usage_quotas| + # expect(usage_quotas.purchased_usage_total_free_element).to exist # end # @return [Watir::Div] The raw +Div+ element def purchased_usage_total_free_element @@ -429,8 +549,8 @@ module Gitlab end # @example - # Gitlab::Page::Group::Settings::UsageQuota.perform do |usage_quota| - # expect(usage_quota).to be_purchased_usage_total_free + # Gitlab::Page::Group::Settings::UsageQuotas.perform do |usage_quotas| + # expect(usage_quotas).to be_purchased_usage_total_free # end # @return [Boolean] true if the +purchased_usage_total_free+ element is present on the page def purchased_usage_total_free? @@ -444,8 +564,8 @@ module Gitlab end # @example - # Gitlab::Page::Group::Settings::UsageQuota.perform do |usage_quota| - # expect(usage_quota.purchased_usage_total_element).to exist + # Gitlab::Page::Group::Settings::UsageQuotas.perform do |usage_quotas| + # expect(usage_quotas.purchased_usage_total_element).to exist # end # @return [Watir::Span] The raw +Span+ element def purchased_usage_total_element @@ -453,8 +573,8 @@ module Gitlab end # @example - # Gitlab::Page::Group::Settings::UsageQuota.perform do |usage_quota| - # expect(usage_quota).to be_purchased_usage_total + # Gitlab::Page::Group::Settings::UsageQuotas.perform do |usage_quotas| + # expect(usage_quotas).to be_purchased_usage_total # end # @return [Boolean] true if the +purchased_usage_total+ element is present on the page def purchased_usage_total? @@ -468,8 +588,8 @@ module Gitlab end # @example - # Gitlab::Page::Group::Settings::UsageQuota.perform do |usage_quota| - # expect(usage_quota.storage_purchase_successful_alert_element).to exist + # Gitlab::Page::Group::Settings::UsageQuotas.perform do |usage_quotas| + # expect(usage_quotas.storage_purchase_successful_alert_element).to exist # end # @return [Watir::Div] The raw +Div+ element def storage_purchase_successful_alert_element @@ -477,8 +597,8 @@ module Gitlab end # @example - # Gitlab::Page::Group::Settings::UsageQuota.perform do |usage_quota| - # expect(usage_quota).to be_storage_purchase_successful_alert + # Gitlab::Page::Group::Settings::UsageQuotas.perform do |usage_quotas| + # expect(usage_quotas).to be_storage_purchase_successful_alert # end # @return [Boolean] true if the +storage_purchase_successful_alert+ element is present on the page def storage_purchase_successful_alert? @@ -492,8 +612,8 @@ module Gitlab end # @example - # Gitlab::Page::Group::Settings::UsageQuota.perform do |usage_quota| - # expect(usage_quota.storage_available_alert_element).to exist + # Gitlab::Page::Group::Settings::UsageQuotas.perform do |usage_quotas| + # expect(usage_quotas.storage_available_alert_element).to exist # end # @return [Watir::H2] The raw +H2+ element def storage_available_alert_element @@ -501,8 +621,8 @@ module Gitlab end # @example - # Gitlab::Page::Group::Settings::UsageQuota.perform do |usage_quota| - # expect(usage_quota).to be_storage_available_alert + # Gitlab::Page::Group::Settings::UsageQuotas.perform do |usage_quotas| + # expect(usage_quotas).to be_storage_available_alert # end # @return [Boolean] true if the +storage_available_alert+ element is present on the page def storage_available_alert? diff --git a/qa/qa/fixtures/package_managers/helm/helm_install_package.yaml.erb b/qa/qa/fixtures/package_managers/helm/helm_install_package.yaml.erb index 786b0592153..590120ce7b2 100644 --- a/qa/qa/fixtures/package_managers/helm/helm_install_package.yaml.erb +++ b/qa/qa/fixtures/package_managers/helm/helm_install_package.yaml.erb @@ -1,7 +1,6 @@ pull: - image: alpine:3 + image: dtzar/helm-kubectl:latest script: - - apk add helm --repository=http://dl-cdn.alpinelinux.org/alpine/edge/testing - helm repo add --username <%= username %> --password <%= access_token %> gitlab_qa ${CI_API_V4_URL}/projects/<%= package_project.id %>/packages/helm/stable - helm repo update - helm pull gitlab_qa/<%= package_name %> diff --git a/qa/qa/fixtures/package_managers/helm/helm_upload_package.yaml.erb b/qa/qa/fixtures/package_managers/helm/helm_upload_package.yaml.erb index b3e907b50f4..b1c275cd96a 100644 --- a/qa/qa/fixtures/package_managers/helm/helm_upload_package.yaml.erb +++ b/qa/qa/fixtures/package_managers/helm/helm_upload_package.yaml.erb @@ -1,7 +1,6 @@ deploy: - image: alpine:3 + image: dtzar/helm-kubectl:latest script: - - apk add helm --repository=http://dl-cdn.alpinelinux.org/alpine/edge/testing - apk add curl - helm create <%= package_name %> - cp ./Chart.yaml <%= package_name %> diff --git a/qa/qa/flow/sign_up.rb b/qa/qa/flow/sign_up.rb index 52c92293bad..abaab064a73 100644 --- a/qa/qa/flow/sign_up.rb +++ b/qa/qa/flow/sign_up.rb @@ -37,7 +37,9 @@ module QA Page::Main::Menu.perform(&:not_signed_in?) end - raise "Failed user registration attempt. Registration was expected to #{user.expect_fabrication_success ? 'succeed' : 'fail'} but #{success ? 'succeeded' : 'failed'}." unless success + return if success + + raise "Failed user registration attempt. Registration was expected to #{user.expect_fabrication_success ? 'succeed' : 'fail'} but #{success ? 'succeeded' : 'failed'}." end def disable_sign_ups diff --git a/qa/qa/git/repository.rb b/qa/qa/git/repository.rb index f132d7b7885..35c5262e767 100644 --- a/qa/qa/git/repository.rb +++ b/qa/qa/git/repository.rb @@ -305,11 +305,12 @@ module QA prefix = "-o merge_request" opts.each_with_object([]) do |(key, value), options| - if value.is_a?(Array) + case value + when Array value.each do |item| options << "#{prefix}.#{key}=\"#{item}\"" end - elsif value == true + when true options << "#{prefix}.#{key}" else options << "#{prefix}.#{key}=\"#{value}\"" diff --git a/qa/qa/mobile/page/base.rb b/qa/qa/mobile/page/base.rb new file mode 100644 index 00000000000..8bc7e5f25ab --- /dev/null +++ b/qa/qa/mobile/page/base.rb @@ -0,0 +1,16 @@ +# frozen_string_literal: true + +module QA + module Mobile + module Page + module Base + prepend Support::Page::Logging + + def fill_element(name, content) + # We need to bypass click_element_cooridinates as it does not work on mobile devices + find_element(name).set(content) + end + end + end + end +end diff --git a/qa/qa/page/admin/overview/users/index.rb b/qa/qa/page/admin/overview/users/index.rb index 2ad45e4a0fa..f46ae30498c 100644 --- a/qa/qa/page/admin/overview/users/index.rb +++ b/qa/qa/page/admin/overview/users/index.rb @@ -28,6 +28,10 @@ module QA click_link(username) end end + + def has_username?(username) + has_element?(:user_row_content, text: username, wait: 1) + end end end end diff --git a/qa/qa/page/base.rb b/qa/qa/page/base.rb index 81c518bb4c6..f59b06b4e75 100644 --- a/qa/qa/page/base.rb +++ b/qa/qa/page/base.rb @@ -6,6 +6,7 @@ module QA module Page class Base prepend Support::Page::Logging + prepend Mobile::Page::Base if QA::Runtime::Env.remote_mobile_device_name include Capybara::DSL include Scenario::Actable @@ -39,7 +40,8 @@ module QA def inspect # For prettier failure messages # Eg.: "expected QA::Page::File::Show not to have file "QA Test - File name" - # Instead of "expected #<QA::Page::File::Show:0x000055c6511e07b8 @retry_later_backoff=60> not to have file "QA Test - File name" + # Instead of "expected #<QA::Page::File::Show:0x000055c6511e07b8 @retry_later_backoff=60> + # not to have file "QA Test - File name" self.class.to_s end @@ -158,16 +160,17 @@ module QA all(element_selector_css(name), **kwargs) end - def check_element(name, click_by_js = false, visibility = false) - if find_element(name, visible: visibility).checked? + def check_element(name, click_by_js = false, **kwargs) + kwargs[:visible] = false unless kwargs.key?(:visible) + if find_element(name, **kwargs).checked? QA::Runtime::Logger.debug("#{name} is already checked") return end retry_until(sleep_interval: 1) do - click_checkbox_or_radio(name, click_by_js, visibility) - checked = find_element(name, visible: visibility).checked? + click_checkbox_or_radio(name, click_by_js, **kwargs) + checked = find_element(name, **kwargs).checked? QA::Runtime::Logger.debug(checked ? "#{name} was checked" : "#{name} was not checked") @@ -175,16 +178,17 @@ module QA end end - def uncheck_element(name, click_by_js = false, visibility = false) - unless find_element(name, visible: visibility).checked? + def uncheck_element(name, click_by_js = false, **kwargs) + kwargs[:visible] = false unless kwargs.key?(:visible) + unless find_element(name, **kwargs).checked? QA::Runtime::Logger.debug("#{name} is already unchecked") return end retry_until(sleep_interval: 1) do - click_checkbox_or_radio(name, click_by_js, visibility) - unchecked = !find_element(name, visible: visibility).checked? + click_checkbox_or_radio(name, click_by_js, **kwargs) + unchecked = !find_element(name, **kwargs).checked? QA::Runtime::Logger.debug(unchecked ? "#{name} was unchecked" : "#{name} was not unchecked") @@ -193,16 +197,17 @@ module QA end # Method for selecting radios - def choose_element(name, click_by_js = false, visibility = false) - if find_element(name, visible: visibility).checked? + def choose_element(name, click_by_js = false, **kwargs) + kwargs[:visible] = false unless kwargs.key?(:visible) + if find_element(name, **kwargs).checked? QA::Runtime::Logger.debug("#{name} is already selected") return end retry_until(sleep_interval: 1) do - click_checkbox_or_radio(name, click_by_js, visibility) - selected = find_element(name, visible: visibility).checked? + click_checkbox_or_radio(name, click_by_js, **kwargs) + selected = find_element(name, **kwargs).checked? QA::Runtime::Logger.debug(selected ? "#{name} was selected" : "#{name} was not selected") @@ -368,19 +373,15 @@ module QA sleep 1 end - def within_element(name, **kwargs) + def within_element(name, **kwargs, &block) wait_for_requests(skip_finished_loading_check: kwargs.delete(:skip_finished_loading_check)) text = kwargs.delete(:text) - page.within(element_selector_css(name, kwargs), text: text) do - yield - end + page.within(element_selector_css(name, kwargs), text: text, &block) end - def within_element_by_index(name, index) - page.within all_elements(name, minimum: index + 1)[index] do - yield - end + def within_element_by_index(name, index, &block) + page.within(all_elements(name, minimum: index + 1)[index], &block) end def scroll_to_element(name, *kwargs) @@ -407,15 +408,14 @@ module QA def wait_if_retry_later return if @retry_later_backoff > QA::Support::Repeater::DEFAULT_MAX_WAIT_TIME * 5 + return unless has_css?('body', text: 'Retry later', wait: 0) - if has_css?('body', text: 'Retry later', wait: 0) - QA::Runtime::Logger.warn("`Retry later` error occurred. Sleeping for #{@retry_later_backoff} seconds...") - sleep @retry_later_backoff - refresh - @retry_later_backoff += QA::Support::Repeater::DEFAULT_MAX_WAIT_TIME + QA::Runtime::Logger.warn("`Retry later` error occurred. Sleeping for #{@retry_later_backoff} seconds...") + sleep @retry_later_backoff + refresh + @retry_later_backoff += QA::Support::Repeater::DEFAULT_MAX_WAIT_TIME - wait_if_retry_later - end + wait_if_retry_later end def current_host @@ -458,6 +458,10 @@ module QA true end + def click_by_javascript(element) + page.execute_script("arguments[0].click();", element) + end + class DSL attr_reader :views @@ -474,13 +478,18 @@ module QA private - def click_checkbox_or_radio(name, click_by_js, visibility) - box = find_element(name, visible: visibility) + def click_checkbox_or_radio(name, click_by_js, **kwargs) + box = find_element(name, **kwargs) # Some checkboxes and radio buttons are hidden by their labels and cannot be clicked directly click_by_js ? page.execute_script("arguments[0].click();", box) : box.click end - def feature_flag_controlled_element(feature_flag, element_when_flag_enabled, element_when_flag_disabled, visibility = true) + def feature_flag_controlled_element( + feature_flag, + element_when_flag_enabled, + element_when_flag_disabled, + visibility = true + ) # Feature flags can change the UI elements shown, but we need admin access to get feature flag values, which # prevents us running the tests on production. Instead we detect the UI element that should be shown when the # feature flag is enabled and otherwise use the element that should be displayed when the feature flag is diff --git a/qa/qa/page/component/access_tokens.rb b/qa/qa/page/component/access_tokens.rb index 3c8a608cdc2..586f69b8a64 100644 --- a/qa/qa/page/component/access_tokens.rb +++ b/qa/qa/page/component/access_tokens.rb @@ -18,27 +18,24 @@ module QA element :expiry_date_field end - base.view 'app/views/shared/access_tokens/_created_container.html.haml' do - element :created_access_token_field - end - base.view 'app/views/shared/access_tokens/_form.html.haml' do element :access_token_name_field element :create_token_button end - base.view 'app/views/shared/access_tokens/_table.html.haml' do - element :revoke_button - end - base.view 'app/views/shared/tokens/_scopes_form.html.haml' do element :api_label, '#{scope}_label' # rubocop:disable QA/ElementWithPattern, Lint/InterpolationCheck end base.view 'app/assets/javascripts/access_tokens/components/new_access_token_app.vue' do + element :access_token_section element :created_access_token_field end + base.view 'app/assets/javascripts/vue_shared/components/form/input_copy_toggle_visibility.vue' do + element :toggle_visibility_button + end + base.view 'app/assets/javascripts/access_tokens/components/access_token_table_app.vue' do element :revoke_button end @@ -57,7 +54,10 @@ module QA end def created_access_token - find_element(:created_access_token_field, wait: 30).value + within_element(:access_token_section) do + click_element(:toggle_visibility_button, wait: 30) + find_element(:created_access_token_field).value + end end def fill_expiry_date(date) diff --git a/qa/qa/page/component/delete_modal.rb b/qa/qa/page/component/delete_modal.rb new file mode 100644 index 00000000000..18bb2b1bb1b --- /dev/null +++ b/qa/qa/page/component/delete_modal.rb @@ -0,0 +1,35 @@ +# frozen_string_literal: true + +module QA + module Page + module Component + module DeleteModal + extend QA::Page::PageConcern + + def self.included(base) + super + + base.view 'app/assets/javascripts/projects/components/shared/delete_button.vue' do + element :confirm_name_field + element :confirm_delete_button + end + end + + def fill_confirmation_path(text) + fill_element(:confirm_name_field, text) + end + + def wait_for_delete_button_enabled + wait_until(reload: false) do + !find_element(:confirm_delete_button).disabled? + end + end + + def confirm_delete + wait_for_delete_button_enabled + click_element(:confirm_delete_button) + end + end + end + end +end diff --git a/qa/qa/page/component/groups_filter.rb b/qa/qa/page/component/groups_filter.rb index 28b8ece918d..ec59d010718 100644 --- a/qa/qa/page/component/groups_filter.rb +++ b/qa/qa/page/component/groups_filter.rb @@ -16,6 +16,10 @@ 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 @@ -28,9 +32,24 @@ module QA # groups_list_tree_container means we have the complete filtered list # of groups has_element?(:groups_list_tree_container, wait: QA::Support::Repeater::DEFAULT_MAX_WAIT_TIME) - # If there are no groups we'll know immediately because we filtered the list - return false if page.has_text?('No groups or projects matched your search', wait: 0) + if page.has_text?('No groups or projects matched your search', +wait: 0) || page.has_text?('No groups matched your search', wait: 0) + return false unless has_element?(:public_groups_tab) + + # Try for public groups + click_element(:public_groups_tab) + # Filter and submit to reload the page and only retrieve the filtered results + find_element(:groups_filter_field).set(name).send_keys(:return) + + # Since we submitted after filtering, the presence of + # groups_list_tree_container means we have the complete filtered list + # of groups + has_element?(:groups_list_tree_container, wait: QA::Support::Repeater::DEFAULT_MAX_WAIT_TIME) + + return false if page.has_text?('No groups or projects matched your search', +wait: 0) || page.has_text?('No groups matched your search', wait: 0) + end # The name will be present as filter input so we check for a link, not text page.has_link?(name, wait: 0) diff --git a/qa/qa/page/component/issuable/sidebar.rb b/qa/qa/page/component/issuable/sidebar.rb index 71a69576c06..fb2e7478684 100644 --- a/qa/qa/page/component/issuable/sidebar.rb +++ b/qa/qa/page/component/issuable/sidebar.rb @@ -86,6 +86,24 @@ module QA end end + def has_reviewer?(username) + wait_reviewers_block_finish_loading do + has_text?(username) + end + end + + def has_no_reviewer?(username) + wait_reviewers_block_finish_loading do + has_no_text?(username) + end + end + + def has_no_reviewers? + wait_reviewers_block_finish_loading do + has_text?('None') + end + end + def has_avatar_image_count?(count) wait_assignees_block_finish_loading do all_elements(:avatar_image, count: count) @@ -133,6 +151,53 @@ module QA click_element(:more_assignees_link) end + def toggle_reviewers_edit + click_element(:reviewers_edit_button) + end + + def suggested_reviewer_usernames + within_element(:reviewers_block_container) do + wait_for_requests + + click_element(:reviewers_edit_button) + wait_for_requests + + list = find_element(:dropdown_list_content) + suggested_reviewers = list.find_all('li[data-user-suggested="true"') + raise ElementNotFound, 'No suggested reviewers found' if suggested_reviewers.nil? + + suggested_reviewers.map do |reviewer| + info = reviewer.text.split('@') + { + name: info[0].chomp, + username: info[1].chomp + } + end.compact + end + end + + def unassign_reviewers + within_element(:reviewers_block_container) do + wait_for_requests + + click_element(:reviewers_edit_button) + wait_for_requests + end + + select_reviewer('Unassigned') + end + + def select_reviewer(username) + within_element(:reviewers_block_container) do + within_element(:dropdown_list_content) do + click_on username + end + + click_element(:reviewers_edit_button) + wait_for_requests + end + end + private def wait_assignees_block_finish_loading @@ -144,6 +209,15 @@ module QA end end + def wait_reviewers_block_finish_loading + within_element(:reviewers_block_container) do + wait_until(reload: false, max_duration: 10, sleep_interval: 1) do + finished_loading_block? + yield + end + end + end + def wait_labels_block_finish_loading within_element(:labels_block) do wait_until(reload: false, max_duration: 10, sleep_interval: 1) do diff --git a/qa/qa/page/component/lazy_loader.rb b/qa/qa/page/component/lazy_loader.rb index 2123431fc55..1b166efbbff 100644 --- a/qa/qa/page/component/lazy_loader.rb +++ b/qa/qa/page/component/lazy_loader.rb @@ -9,8 +9,8 @@ module QA def self.included(base) super - base.view 'app/assets/javascripts/lazy_loader.js' do - element :js_lazy_loaded + base.view 'app/views/layouts/_img_loader.html.haml' do + element :js_lazy_loaded_content end end end diff --git a/qa/qa/page/component/legacy_clone_panel.rb b/qa/qa/page/component/legacy_clone_panel.rb index ee372a3f9aa..8c3c25f6e41 100644 --- a/qa/qa/page/component/legacy_clone_panel.rb +++ b/qa/qa/page/component/legacy_clone_panel.rb @@ -28,7 +28,7 @@ module QA end def repository_location - Git::Location.new(find_element(:clone_url_content).text) + Git::Location.new(find_element(:clone_url_content).value) end private diff --git a/qa/qa/page/component/namespace_select.rb b/qa/qa/page/component/namespace_select.rb index 9b483162f1b..8fb0bb79ab3 100644 --- a/qa/qa/page/component/namespace_select.rb +++ b/qa/qa/page/component/namespace_select.rb @@ -9,7 +9,7 @@ module QA def self.included(base) super - base.view "app/assets/javascripts/vue_shared/components/namespace_select/namespace_select_deprecated.vue" do + base.view "app/assets/javascripts/groups_projects/components/transfer_locations.vue" do element :namespaces_list element :namespaces_list_groups element :namespaces_list_item @@ -20,14 +20,15 @@ module QA def select_namespace(item) click_element :namespaces_list - wait_for_requests - within_element(:namespaces_list) do fill_element(:namespaces_list_search, item) wait_for_requests - find_element(:namespaces_list_item, text: item).click + # Click element by JS in case dropdown changes position mid-click + # Workaround for issue https://gitlab.com/gitlab-org/gitlab/-/issues/381376 + namespace = find_element(:namespaces_list_item, text: item, visible: false) + click_by_javascript(namespace) end end end diff --git a/qa/qa/page/component/users_select.rb b/qa/qa/page/component/users_select.rb deleted file mode 100644 index f88d6450a33..00000000000 --- a/qa/qa/page/component/users_select.rb +++ /dev/null @@ -1,14 +0,0 @@ -# frozen_string_literal: true - -module QA - module Page - module Component - module UsersSelect - def select_user(element, username) - find("#{element_selector_css(element)} input").set(username) - find('.ajax-users-dropdown .user-username', text: "@#{username}").click - end - end - end - end -end diff --git a/qa/qa/page/component/wiki.rb b/qa/qa/page/component/wiki.rb index ffd31f8d7b7..ed68052f997 100644 --- a/qa/qa/page/component/wiki.rb +++ b/qa/qa/page/component/wiki.rb @@ -38,7 +38,7 @@ module QA # webdriver to miss the hit so we wait for the svg to load before # clicking the button. within_element(:svg_content) do - has_element?(:js_lazy_loaded) + has_element?(:js_lazy_loaded_content) end click_element(:create_first_page_link) diff --git a/qa/qa/page/file/edit.rb b/qa/qa/page/file/edit.rb index d2b8c8260fd..b9b676ee3c4 100644 --- a/qa/qa/page/file/edit.rb +++ b/qa/qa/page/file/edit.rb @@ -12,10 +12,6 @@ module QA element :editor_toolbar_button end - view 'app/views/projects/blob/_editor.html.haml' do - element :source_editor_preview_container - end - def has_markdown_preview?(component, content) within_element(:source_editor_preview_container) do has_css?(component, exact_text: content) diff --git a/qa/qa/page/file/form.rb b/qa/qa/page/file/form.rb index bb8934db498..2e0f8c59213 100644 --- a/qa/qa/page/file/form.rb +++ b/qa/qa/page/file/form.rb @@ -11,7 +11,7 @@ module QA include Shared::Editor view 'app/views/projects/blob/_editor.html.haml' do - element :file_name, "text_field_tag 'file_name'" # rubocop:disable QA/ElementWithPattern + element :file_name_field end view 'app/views/projects/blob/_template_selectors.html.haml' do @@ -23,7 +23,7 @@ module QA end def add_name(name) - fill_in 'file_name', with: name + fill_element(:file_name_field, with: name) end def select_template(template_type, template) diff --git a/qa/qa/page/file/shared/editor.rb b/qa/qa/page/file/shared/editor.rb index dab02c1e34f..f392d52747e 100644 --- a/qa/qa/page/file/shared/editor.rb +++ b/qa/qa/page/file/shared/editor.rb @@ -11,7 +11,7 @@ module QA super base.view 'app/views/projects/blob/_editor.html.haml' do - element :editor + element :source_editor_preview_container end end @@ -30,7 +30,7 @@ module QA private def text_area - within_element :editor do + within_element :source_editor_preview_container do find('textarea', visible: false) end end diff --git a/qa/qa/page/group/members.rb b/qa/qa/page/group/members.rb index 58febaddfa0..39003eb03c1 100644 --- a/qa/qa/page/group/members.rb +++ b/qa/qa/page/group/members.rb @@ -5,7 +5,6 @@ module QA module Group class Members < Page::Base include Page::Component::InviteMembersModal - include Page::Component::UsersSelect include Page::Component::MembersFilter view 'app/assets/javascripts/members/components/modals/remove_member_modal.vue' do diff --git a/qa/qa/page/group/new.rb b/qa/qa/page/group/new.rb index 1f17b470ada..47fda787085 100644 --- a/qa/qa/page/group/new.rb +++ b/qa/qa/page/group/new.rb @@ -31,7 +31,7 @@ module QA end def create - click_button 'Create group' + click_element(:create_group_button) end def create_subgroup diff --git a/qa/qa/page/issuable/new.rb b/qa/qa/page/issuable/new.rb index f3e6a84ef54..b74dc705888 100644 --- a/qa/qa/page/issuable/new.rb +++ b/qa/qa/page/issuable/new.rb @@ -12,9 +12,8 @@ module QA element :issuable_form_description_field end - view 'app/views/shared/issuable/_milestone_dropdown.html.haml' do + view 'app/assets/javascripts/sidebar/components/milestone/milestone_dropdown.vue' do element :issuable_milestone_dropdown - element :issuable_milestone_dropdown_content end view 'app/views/shared/issuable/_label_dropdown.html.haml' do @@ -38,9 +37,9 @@ module QA end def choose_milestone(milestone) - click_element :issuable_milestone_dropdown - within_element(:issuable_milestone_dropdown_content) do - click_on milestone.title + within_element(:issuable_milestone_dropdown) do + click_button 'Select milestone' + click_button milestone.title end end diff --git a/qa/qa/page/label/index.rb b/qa/qa/page/label/index.rb index e19bc0838c9..70df2e4dc9e 100644 --- a/qa/qa/page/label/index.rb +++ b/qa/qa/page/label/index.rb @@ -23,7 +23,7 @@ module QA # This can cause webdriver to miss the hit so we wait for the svg to load (implicitly with has_element?) # before clicking the button. within_element(:label_svg_content) do - has_element?(:js_lazy_loaded) + has_element?(:js_lazy_loaded_content) end click_element :create_new_label_button diff --git a/qa/qa/page/main/menu.rb b/qa/qa/page/main/menu.rb index 2f618224a73..ecd71e7c2f4 100644 --- a/qa/qa/page/main/menu.rb +++ b/qa/qa/page/main/menu.rb @@ -64,12 +64,7 @@ module QA def go_to_groups within_groups_menu do - # Remove if statement once :remove_extra_primary_submenu_options ff is enabled by default - if has_element?(:menu_item_link, title: 'Your groups') - click_element(:menu_item_link, title: 'Your groups') - else - click_element(:menu_item_link, title: 'View all groups') - end + click_element(:menu_item_link, title: 'View all groups') end end @@ -80,12 +75,7 @@ module QA def go_to_projects within_projects_menu do - # Remove if statement once :remove_extra_primary_submenu_options ff is enabled by default - if has_element?(:menu_item_link, title: 'Your projects') - click_element(:menu_item_link, title: 'Your projects') - else - click_element(:menu_item_link, title: 'View all projects') - end + click_element(:menu_item_link, title: 'View all projects') end end diff --git a/qa/qa/page/profile/two_factor_auth.rb b/qa/qa/page/profile/two_factor_auth.rb index 63593bf0482..16aa60262d8 100644 --- a/qa/qa/page/profile/two_factor_auth.rb +++ b/qa/qa/page/profile/two_factor_auth.rb @@ -23,7 +23,14 @@ module QA end def click_configure_it_later_button + # TO DO: Investigate why button does not appear sometimes: + # https://gitlab.com/gitlab-org/gitlab/-/issues/382698 + return unless has_element?(:configure_it_later_button) + click_element :configure_it_later_button + wait_until(max_duration: 10, message: "Waiting for create a group page") do + has_text?("Welcome to GitLab") && has_text?("Create a group") + end end def otp_secret_content diff --git a/qa/qa/page/project/branches/show.rb b/qa/qa/page/project/branches/show.rb index 4bf8abb555b..7163bc7464d 100644 --- a/qa/qa/page/project/branches/show.rb +++ b/qa/qa/page/project/branches/show.rb @@ -5,8 +5,6 @@ module QA module Project module Branches class Show < Page::Base - include Page::Component::ConfirmModal - view 'app/assets/javascripts/branches/components/delete_branch_button.vue' do element :delete_branch_button end @@ -16,22 +14,24 @@ module QA end view 'app/views/projects/branches/_branch.html.haml' do - element :branch_name + element :badge_content + element :branch_container + element :branch_link end view 'app/views/projects/branches/_panel.html.haml' do - element :all_branches + element :all_branches_container end - view 'app/views/projects/branches/index.html.haml' do - element :delete_merged_branches + view 'app/assets/javascripts/branches/components/delete_merged_branches.vue' do + element :delete_merged_branches_button + element :delete_merged_branches_input + element :delete_merged_branches_confirmation_button end def delete_branch(branch_name) - within_element(:all_branches) do - within(".js-branch-#{branch_name}") do - click_element(:delete_branch_button) - end + within_element(:branch_container, name: branch_name) do + click_element(:delete_branch_button) end click_element(:delete_branch_confirmation_button) @@ -41,23 +41,23 @@ module QA def has_no_branch?(branch_name, reload: false) wait_until(reload: reload) do - within_element(:all_branches) do - has_no_element?(:branch_name, text: branch_name) + within_element(:all_branches_container) do + has_no_element?(:branch_link, text: branch_name) end end end def has_branch_with_badge?(branch_name, badge) - within_element(:all_branches) do - within(".js-branch-#{branch_name} .badge") do - has_text?(badge) - end + within_element(:branch_container, name: branch_name) do + has_element?(:badge_content, text: badge) end end - def delete_merged_branches - click_element(:delete_merged_branches) - click_confirmation_ok_button + def delete_merged_branches(branches_length) + click_element(:delete_merged_branches_button) + fill_element(:delete_merged_branches_input, branches_length) + click_element(:delete_merged_branches_confirmation_button) + finished_loading? end end end diff --git a/qa/qa/page/project/import/github.rb b/qa/qa/page/project/import/github.rb index 89d044bac8d..75468c74814 100644 --- a/qa/qa/page/project/import/github.rb +++ b/qa/qa/page/project/import/github.rb @@ -85,8 +85,15 @@ module QA end end end - alias_method :wait_for_success, :has_imported_project? + + # Select advanced github import option + # + # @param [Symbol] option_name + # @return [void] + def select_advanced_option(option_name) + check_element(:advanced_settings_checkbox, true, option_name: option_name) + end end end end diff --git a/qa/qa/page/project/new.rb b/qa/qa/page/project/new.rb index fd650d8ca20..f7434656be3 100644 --- a/qa/qa/page/project/new.rb +++ b/qa/qa/page/project/new.rb @@ -64,6 +64,8 @@ module QA end def add_description(description) + return unless has_element?(:project_description, wait: 1) + fill_in 'project_description', with: description end diff --git a/qa/qa/page/project/pipeline/show.rb b/qa/qa/page/project/pipeline/show.rb index 06d154f5178..33ba27a788a 100644 --- a/qa/qa/page/project/pipeline/show.rb +++ b/qa/qa/page/project/pipeline/show.rb @@ -35,10 +35,6 @@ module QA element :status_icon, 'ci-status-icon-${status}' # rubocop:disable QA/ElementWithPattern end - view 'app/views/projects/pipelines/_info.html.haml' do - element :pipeline_badges - end - view 'app/assets/javascripts/pipelines/components/graph/job_group_dropdown.vue' do element :job_dropdown_container element :jobs_dropdown_menu @@ -68,12 +64,6 @@ module QA has_no_element?(:job_link, text: job_name) end - def has_tag?(tag_name) - within_element(:pipeline_badges) do - has_selector?('.badge', text: tag_name) - end - end - def linked_pipelines all_elements(:linked_pipeline_container, minimum: 1) end diff --git a/qa/qa/page/project/pipeline_editor/show.rb b/qa/qa/page/project/pipeline_editor/show.rb index 70c0c5abb52..8fa20aa57cf 100644 --- a/qa/qa/page/project/pipeline_editor/show.rb +++ b/qa/qa/page/project/pipeline_editor/show.rb @@ -91,6 +91,8 @@ module QA def write_to_editor(text) find_element(:source_editor_container).fill_in(with: text) + + wait_for_requests end def submit_changes @@ -140,6 +142,10 @@ module QA all_elements(:job_container, minimum: 1).any? { |item| item.text.match(/#{name}/i) } end + def has_no_alert? + has_no_css?('.gl-alert-body') + end + def tab_alert_message within_element(:file_editor_container) do find('.gl-alert-body').text @@ -174,9 +180,13 @@ module QA within_element(:file_editor_container) do find('.nav-item', text: name).click end + + wait_for_requests end end end end end end + +QA::Page::Project::PipelineEditor::Show.prepend_mod_with('Page::Project::PipelineEditor::Show', namespace: QA) diff --git a/qa/qa/page/project/settings/advanced.rb b/qa/qa/page/project/settings/advanced.rb index 9d8ed132ffd..fcfcecdc183 100644 --- a/qa/qa/page/project/settings/advanced.rb +++ b/qa/qa/page/project/settings/advanced.rb @@ -6,10 +6,11 @@ module QA module Settings class Advanced < Page::Base include QA::Page::Component::ConfirmModal + include QA::Page::Component::DeleteModal include Component::NamespaceSelect - view 'app/assets/javascripts/vue_shared/components/confirm_danger/confirm_danger.vue' do - element :confirm_danger_button + view 'app/assets/javascripts/projects/components/shared/delete_button.vue' do + element :delete_button end view 'app/views/projects/edit.html.haml' do @@ -20,7 +21,6 @@ module QA view 'app/views/projects/settings/_archive.html.haml' do element :archive_project_link element :unarchive_project_link - element :archive_project_content end view 'app/views/projects/_export.html.haml' do @@ -29,6 +29,14 @@ module QA element :export_project_content end + view 'app/views/projects/_transfer.html.haml' do + element :transfer_project_content + end + + view 'app/assets/javascripts/projects/settings/components/transfer_project_form.vue' do + element :transfer_project_button + end + def update_project_path_to(path) fill_project_path(path) click_change_path_button @@ -45,13 +53,16 @@ module QA def transfer_project!(project_name, namespace) QA::Runtime::Logger.info "Transferring project: #{project_name} to namespace: #{namespace}" - click_element_coordinates(:archive_project_content) + scroll_to_transfer_project_content # Workaround for a failure to search when there are no spaces around the / # https://gitlab.com/gitlab-org/gitlab/-/issues/218965 select_namespace(namespace.gsub(%r{([^\s])/([^\s])}, '\1 / \2')) - click_element(:confirm_danger_button) + wait_for_enabled_transfer_project_button + + click_element :transfer_project_button + fill_confirmation_text(project_name) confirm_transfer end @@ -77,6 +88,29 @@ module QA click_element :unarchive_project_link click_confirmation_ok_button end + + def delete_project!(project_name) + click_element :delete_button + fill_confirmation_path(project_name) + wait_for_delete_button_enabled + confirm_delete + end + + private + + def scroll_to_transfer_project_content + retry_until(sleep_interval: 1, message: 'Waiting for transfer project content to display') do + has_element?(:transfer_project_content, wait: 3) + end + + scroll_to_element :transfer_project_content + end + + def wait_for_enabled_transfer_project_button + retry_until(sleep_interval: 1, message: 'Waiting for transfer project button to be enabled') do + has_element?(:transfer_project_button, disabled: false, wait: 3) + end + end end end end diff --git a/qa/qa/page/project/settings/ci_variables.rb b/qa/qa/page/project/settings/ci_variables.rb index 7ee015ceb98..316920ffa90 100644 --- a/qa/qa/page/project/settings/ci_variables.rb +++ b/qa/qa/page/project/settings/ci_variables.rb @@ -14,13 +14,6 @@ module QA element :ci_variable_delete_button end - view 'app/assets/javascripts/ci_variable_list/components/legacy_ci_variable_table.vue' do - element :ci_variable_table_content - element :add_ci_variable_button - element :edit_ci_variable_button - element :reveal_ci_variable_value_button - end - def fill_variable(key, value, masked = false) within_element(:ci_variable_key_field) { find('input').set key } fill_element :ci_variable_value_field, value diff --git a/qa/qa/page/project/settings/default_branch.rb b/qa/qa/page/project/settings/default_branch.rb index 575f9006c84..69ac45ce72d 100644 --- a/qa/qa/page/project/settings/default_branch.rb +++ b/qa/qa/page/project/settings/default_branch.rb @@ -5,7 +5,7 @@ module QA module Project module Settings class DefaultBranch < Page::Base - view 'app/views/projects/default_branch/_show.html.haml' do + view 'app/views/projects/branch_defaults/_show.html.haml' do element :save_changes_button end @@ -18,8 +18,8 @@ module QA end def set_default_branch(branch) - click_button :default_branch_dropdown - fill_in :ref_selector_searchbox, with: branch + find_element(:default_branch_dropdown, visible: false).click + find_element(:ref_selector_searchbox, visible: false).fill_in(with: branch) click_button branch end diff --git a/qa/qa/page/project/settings/mirroring_repositories.rb b/qa/qa/page/project/settings/mirroring_repositories.rb index f55faff19e7..61ee3e4f03c 100644 --- a/qa/qa/page/project/settings/mirroring_repositories.rb +++ b/qa/qa/page/project/settings/mirroring_repositories.rb @@ -6,25 +6,25 @@ module QA module Settings class MirroringRepositories < Page::Base view 'app/views/projects/mirrors/_authentication_method.html.haml' do - element :authentication_method - element :password + element :authentication_method_field + element :password_field end view 'app/views/projects/mirrors/_mirror_repos.html.haml' do - element :mirror_repository_url_input + element :mirror_repository_url_field element :mirror_repository_button end view 'app/views/projects/mirrors/_mirror_repos_list.html.haml' do - element :mirror_repository_url_cell - element :mirror_last_update_at_cell - element :mirror_error_badge - element :mirrored_repository_row + element :mirror_repository_url_content + element :mirror_last_update_at_content + element :mirror_error_badge_content + element :mirrored_repository_row_container element :copy_public_key_button end view 'app/views/projects/mirrors/_mirror_repos_form.html.haml' do - element :mirror_direction + element :mirror_direction_field end view 'app/views/shared/_remote_mirror_update_button.html.haml' do @@ -37,28 +37,23 @@ module QA element :fingerprints_list end - view 'app/views/projects/mirrors/_authentication_method.html.haml' do - element :authentication_method - element :password - end - def repository_url=(value) - fill_element :mirror_repository_url_input, value + fill_element :mirror_repository_url_field, value end def password=(value) - fill_element :password, value + fill_element :password_field, value end def mirror_direction=(value) raise ArgumentError, "Mirror direction must be 'Push' or 'Pull'" unless %w[Push Pull].include?(value) - select_element(:mirror_direction, value) + select_element(:mirror_direction_field, value) # Changing the mirror direction causes the fields below to change, # and that change is animated, so we need to wait for the animation # to complete otherwise changes to those fields could fail - wait_for_animated_element :authentication_method + wait_for_animated_element :authentication_method_field end def authentication_method=(value) @@ -66,13 +61,13 @@ module QA raise ArgumentError, "Authentication method must be 'SSH public key', 'Password', or 'None'" end - select_element(:authentication_method, value) + select_element(:authentication_method_field, value) end def public_key(url) row_index = find_repository_row_index url - within_element_by_index(:mirrored_repository_row, row_index) do + within_element_by_index(:mirrored_repository_row_container, row_index) do find_element(:copy_public_key_button)['data-clipboard-text'] end end @@ -92,7 +87,7 @@ module QA def update(url) row_index = find_repository_row_index(url) - within_element_by_index(:mirrored_repository_row, row_index) do + within_element_by_index(:mirrored_repository_row_container, row_index) do # When a repository is first mirrored, the update process might # already be started, so the button is already "clicked" click_element :update_now_button unless has_element? :updating_button @@ -105,16 +100,16 @@ module QA row_index = find_repository_row_index(url) wait_until(sleep_interval: 1) do - within_element_by_index(:mirrored_repository_row, row_index) do - last_update = find_element(:mirror_last_update_at_cell, wait: 0) + within_element_by_index(:mirrored_repository_row_container, row_index) do + last_update = find_element(:mirror_last_update_at_content, wait: 0) last_update.has_text?('just now') || last_update.has_text?('seconds') end end # Fail early if the page still shows that there has been no update - within_element_by_index(:mirrored_repository_row, row_index) do - find_element(:mirror_last_update_at_cell, wait: 0).assert_no_text('Never') - assert_no_element(:mirror_error_badge) + within_element_by_index(:mirrored_repository_row_container, row_index) do + find_element(:mirror_last_update_at_content, wait: 0).assert_no_text('Never') + assert_no_element(:mirror_error_badge_content) end end @@ -122,7 +117,7 @@ module QA def find_repository_row_index(target_url) wait_until(max_duration: 5, reload: false) do - all_elements(:mirror_repository_url_cell, minimum: 1).index do |url| + all_elements(:mirror_repository_url_content, minimum: 1).index do |url| # The url might be a sanitized url but the target_url won't be so # we compare just the paths instead of the full url URI.parse(url.text).path == target_url.path diff --git a/qa/qa/page/project/settings/protected_branches.rb b/qa/qa/page/project/settings/protected_branches.rb index a78d8a6ccf4..4fbf656210f 100644 --- a/qa/qa/page/project/settings/protected_branches.rb +++ b/qa/qa/page/project/settings/protected_branches.rb @@ -6,8 +6,8 @@ module QA module Settings class ProtectedBranches < Page::Base view 'app/views/projects/protected_branches/shared/_dropdown.html.haml' do - element :protected_branch_select element :protected_branch_dropdown + element :protected_branch_dropdown_content end view 'app/views/projects/protected_branches/_create_protected_branch.html.haml' do @@ -22,9 +22,9 @@ module QA end def select_branch(branch_name) - click_element :protected_branch_select + click_element :protected_branch_dropdown - within_element(:protected_branch_dropdown) do + within_element(:protected_branch_dropdown_content) do click_on branch_name end end diff --git a/qa/qa/page/project/settings/repository.rb b/qa/qa/page/project/settings/repository.rb index de5b4f37076..bf1c3130485 100644 --- a/qa/qa/page/project/settings/repository.rb +++ b/qa/qa/page/project/settings/repository.rb @@ -58,7 +58,7 @@ module QA end def expand_default_branch(&block) - within('#default-branch-settings') do + within('#branch-defaults-settings') do find('.btn-default').click do DefaultBranch.perform(&block) end diff --git a/qa/qa/page/project/show.rb b/qa/qa/page/project/show.rb index 26c2da07b34..a82fa7f5cf3 100644 --- a/qa/qa/page/project/show.rb +++ b/qa/qa/page/project/show.rb @@ -32,7 +32,7 @@ module QA end view 'app/views/projects/_last_push.html.haml' do - element :create_merge_request + element :create_merge_request_button end view 'app/views/projects/_home_panel.html.haml' do @@ -54,7 +54,7 @@ module QA end view 'app/views/projects/empty.html.haml' do - element :quick_actions + element :quick_actions_container end view 'app/assets/javascripts/repository/components/breadcrumbs.vue' do @@ -72,7 +72,7 @@ module QA end view 'app/views/projects/blob/viewers/_loading.html.haml' do - element :spinner + element :spinner_placeholder end view 'app/views/projects/buttons/_download.html.haml' do @@ -80,11 +80,11 @@ module QA end def wait_for_viewers_to_load - has_no_element?(:spinner, wait: QA::Support::Repeater::DEFAULT_MAX_WAIT_TIME) + has_no_element?(:spinner_placeholder, wait: QA::Support::Repeater::DEFAULT_MAX_WAIT_TIME) end def create_first_new_file! - within_element(:quick_actions) do + within_element(:quick_actions_container) do click_link_with_text 'New file' end end @@ -122,7 +122,7 @@ module QA end def has_create_merge_request_button? - has_css?(element_selector_css(:create_merge_request)) + has_css?(element_selector_css(:create_merge_request_button)) end def has_file?(name) @@ -152,7 +152,7 @@ module QA has_create_merge_request_button? end - click_element :create_merge_request + click_element :create_merge_request_button end def open_web_ide! diff --git a/qa/qa/page/project/sub_menus/ci_cd.rb b/qa/qa/page/project/sub_menus/ci_cd.rb index c8c90df2c1f..4ae51798e54 100644 --- a/qa/qa/page/project/sub_menus/ci_cd.rb +++ b/qa/qa/page/project/sub_menus/ci_cd.rb @@ -43,3 +43,5 @@ module QA end end end + +QA::Page::Project::SubMenus::CiCd.prepend_mod_with('Page::Project::SubMenus::CiCd', namespace: QA) diff --git a/qa/qa/page/project/sub_menus/issues.rb b/qa/qa/page/project/sub_menus/issues.rb index 48cdf9791f8..7fa19063653 100644 --- a/qa/qa/page/project/sub_menus/issues.rb +++ b/qa/qa/page/project/sub_menus/issues.rb @@ -74,3 +74,5 @@ module QA end end end + +QA::Page::Project::SubMenus::Issues.prepend_mod_with('Page::Project::SubMenus::Issues', namespace: QA) diff --git a/qa/qa/resource/approval_configuration.rb b/qa/qa/resource/approval_configuration.rb new file mode 100644 index 00000000000..89b8201d7d2 --- /dev/null +++ b/qa/qa/resource/approval_configuration.rb @@ -0,0 +1,55 @@ +# frozen_string_literal: true + +module QA + module Resource + # Helper for approval configuration which exists on project and mr level + module ApprovalConfiguration + include ApiFabricator + + def api_approval_configuration_path + "#{api_get_path}/approvals" + end + + def api_approval_rules_path + "#{api_get_path}/approval_rules" + end + + # Approval configuration + # + # @return [Hash] + def approval_configuration + parse_body(api_get_from(api_approval_configuration_path)) + end + + # Update approvals configuration + # MR: https://docs.gitlab.com/ee/api/merge_request_approvals.html#change-approval-configuration + # Project: https://docs.gitlab.com/ee/api/merge_request_approvals.html#change-configuration + # + # @param [Hash] configuration + # @return [Hash] + def update_approval_configuration(configuration) + api_post_to(api_approval_configuration_path, configuration) + end + + # Approval rules + # + # @return [Array<Hash>] + def fetch_approval_rules + parse_body(api_get_from(api_approval_rules_path)) + end + + # Create approval rules + # + # @return [Hash] + def create_approval_rules + raise("Trying to create approval rules but no rules set!") unless approval_rules + + rule = { approvals_required: 1, name: "Approval rule for mr #{title}" } + rule[:user_ids] = approval_rules[:users].map(&:id) if approval_rules[:users] + rule[:group_ids] = approval_rules[:group].map(&:full_path) if approval_rules[:groups] + + api_post_to(api_approvals_path, rule) + end + end + end +end diff --git a/qa/qa/resource/base.rb b/qa/qa/resource/base.rb index 6025dd6ec40..4a1a60f4da1 100644 --- a/qa/qa/resource/base.rb +++ b/qa/qa/resource/base.rb @@ -22,8 +22,20 @@ module QA new.tap(&prepare_block) end + def fabricate_via_api_unless_fips! + if QA::Support::FIPS.enabled? + fabricate! + else + fabricate_via_api! + end + end + def fabricate!(*args, &prepare_block) - fabricate_via_api!(*args, &prepare_block) + if QA::Support::FIPS.enabled? + fabricate_via_browser_ui!(*args, &prepare_block) + else + fabricate_via_api!(*args, &prepare_block) + end rescue NotImplementedError fabricate_via_browser_ui!(*args, &prepare_block) end @@ -95,7 +107,7 @@ module QA Support::FabricationTracker.save_fabrication(:"#{fabrication_method}_fabrication", fabrication_time) - unless resource.retrieved_from_cache + unless resource.retrieved_from_cache || QA::Support::FIPS.enabled? Tools::TestResourceDataProcessor.collect( resource: resource, info: resource.identifier, diff --git a/qa/qa/resource/group.rb b/qa/qa/resource/group.rb index 84416c0600d..9d1a6868562 100644 --- a/qa/qa/resource/group.rb +++ b/qa/qa/resource/group.rb @@ -18,8 +18,14 @@ module QA end attribute :sandbox do - Sandbox.fabricate_via_api! do |sandbox| - sandbox.api_client = api_client + if QA::Support::FIPS.enabled? + Resource::Sandbox.fabricate! do |sandbox| + sandbox.path = Runtime::Namespace.sandbox_name + end + else + Sandbox.fabricate_via_api! do |sandbox| + sandbox.api_client = api_client + end end end diff --git a/qa/qa/resource/members.rb b/qa/qa/resource/members.rb index d9300f80f5d..4bf9c2bed6b 100644 --- a/qa/qa/resource/members.rb +++ b/qa/qa/resource/members.rb @@ -10,8 +10,8 @@ module QA def add_member(user, access_level = AccessLevel::DEVELOPER) Support::Retrier.retry_until do QA::Runtime::Logger.info(%(Adding user #{user.username} to #{full_path} #{self.class.name})) - - response = post Runtime::API::Request.new(api_client, api_members_path).url, { user_id: user.id, access_level: access_level } + response = post Runtime::API::Request.new(api_client, api_members_path).url, +{ user_id: user.id, access_level: access_level } break true if response.code == QA::Support::API::HTTP_STATUS_CREATED break true if response.body.include?('Member already exists') end @@ -31,7 +31,8 @@ module QA Support::Retrier.retry_until do QA::Runtime::Logger.info(%(Sharing #{self.class.name} with #{group.name})) - response = post Runtime::API::Request.new(api_client, api_share_path).url, { group_id: group.id, group_access: access_level } + response = post Runtime::API::Request.new(api_client, api_share_path).url, +{ group_id: group.id, group_access: access_level } response.code == QA::Support::API::HTTP_STATUS_CREATED end end diff --git a/qa/qa/resource/merge_request.rb b/qa/qa/resource/merge_request.rb index 5d6dc12ac9c..fcfda106523 100644 --- a/qa/qa/resource/merge_request.rb +++ b/qa/qa/resource/merge_request.rb @@ -3,6 +3,8 @@ module QA module Resource class MergeRequest < Issuable + include ApprovalConfiguration + attr_accessor :approval_rules, :source_branch, :target_new_branch, @@ -11,7 +13,8 @@ module QA :milestone, :labels, :file_name, - :file_content + :file_content, + :reviewer_ids attr_writer :no_preparation, :wait_for_merge, @@ -22,7 +25,8 @@ module QA :description, :merge_when_pipeline_succeeds, :merge_status, - :state + :state, + :reviewers attribute :project do Project.fabricate_via_api! do |resource| @@ -121,12 +125,21 @@ module QA "/projects/#{project.id}/merge_requests" end + def api_reviewers_path + "#{api_get_path}/reviewers" + end + + def api_approve_path + "#{api_get_path}/approve" + end + def api_post_body { description: description, source_branch: source_branch, target_branch: target_branch, - title: title + title: title, + reviewer_ids: reviewer_ids } end @@ -152,6 +165,17 @@ module QA end end + # Approve merge request + # + # Due to internal implementation of api client, project needs to have + # setting 'Prevent approval by author' set to false since we use same user that created merge request which + # is set through approval configuration + # + # @return [void] + def approve + api_post_to(api_approve_path, {}) + end + def fabricate_large_merge_request @project = Resource::ImportProject.fabricate_via_browser_ui! # Setting the name here, since otherwise some tests will look for an existing file in diff --git a/qa/qa/resource/project.rb b/qa/qa/resource/project.rb index e5df95f1fa5..3cbc002fa86 100644 --- a/qa/qa/resource/project.rb +++ b/qa/qa/resource/project.rb @@ -7,6 +7,7 @@ module QA include Integrations::Project include Members include Visibility + include ApprovalConfiguration attr_accessor :initialize_with_readme, :auto_devops_enabled, @@ -479,6 +480,16 @@ module QA end end + def remove_via_browser_ui! + Page::Project::Menu.perform(&:go_to_general_settings) + + Page::Project::Settings::Main.perform(&:expand_advanced_settings) + + Page::Project::Settings::Advanced.perform do |advanced| + advanced.delete_project!(full_path) + end + end + # Calls the API endpoint that triggers the backend service that performs repository housekeeping (garbage # collection and similar tasks). def perform_housekeeping diff --git a/qa/qa/resource/project_imported_from_github.rb b/qa/qa/resource/project_imported_from_github.rb index 9ba9723f0cc..1e6b2ff620e 100644 --- a/qa/qa/resource/project_imported_from_github.rb +++ b/qa/qa/resource/project_imported_from_github.rb @@ -18,6 +18,11 @@ module QA Page::Project::Import::Github.perform do |import_page| import_page.add_personal_access_token(github_personal_access_token) + + import_page.select_advanced_option(:single_endpoint_issue_events_import) if issue_events_import + import_page.select_advanced_option(:single_endpoint_notes_import) if full_notes_import + import_page.select_advanced_option(:attachments_import) if attachments_import + import_page.import!(github_repository_path, group.full_path, name) import_page.wait_for_success(github_repository_path, wait: 240) end diff --git a/qa/qa/resource/sandbox.rb b/qa/qa/resource/sandbox.rb index 2080e279e99..18526448b00 100644 --- a/qa/qa/resource/sandbox.rb +++ b/qa/qa/resource/sandbox.rb @@ -10,7 +10,9 @@ module QA class << self # Force top level group creation via UI if test is executed on dot_com environment def fabricate!(*args, &prepare_block) - return fabricate_via_browser_ui!(*args, &prepare_block) if Specs::Helpers::ContextSelector.dot_com? + if Specs::Helpers::ContextSelector.dot_com? || QA::Support::FIPS.enabled? + return fabricate_via_browser_ui!(*args, &prepare_block) + end fabricate_via_api!(*args, &prepare_block) rescue NotImplementedError diff --git a/qa/qa/resource/user.rb b/qa/qa/resource/user.rb index 71a5e1c8930..c8babbc0b16 100644 --- a/qa/qa/resource/user.rb +++ b/qa/qa/resource/user.rb @@ -79,11 +79,22 @@ module QA defined?(@username) && defined?(@password) end + def has_user?(user) + Flow::Login.while_signed_in_as_admin do + Page::Main::Menu.perform(&:go_to_admin_area) + Page::Admin::Menu.perform(&:go_to_users_overview) + Page::Admin::Overview::Users::Index.perform do |index| + index.search_user(user.username) + index.has_username?(user.username) + end + end + end + def fabricate! # Don't try to log-out if we're not logged-in Page::Main::Menu.perform(&:sign_out) if Page::Main::Menu.perform { |p| p.has_personal_area?(wait: 0) } - if credentials_given? + if credentials_given? || has_user?(self) Page::Main::Login.perform do |login| login.sign_in_using_credentials(user: self) end @@ -144,7 +155,7 @@ module QA end def self.fabricate_or_use(username = nil, password = nil) - if Runtime::Env.signup_disabled? + if Runtime::Env.signup_disabled? || !QA::Support::FIPS.enabled? fabricate_via_api! do |user| user.username = username user.password = password diff --git a/qa/qa/runtime/allure_report.rb b/qa/qa/runtime/allure_report.rb index 10f47ca56ba..a9152a5555c 100644 --- a/qa/qa/runtime/allure_report.rb +++ b/qa/qa/runtime/allure_report.rb @@ -96,9 +96,14 @@ module QA return {} unless Env.admin_personal_access_token || Env.personal_access_token client = Env.admin_personal_access_token ? API::Client.as_admin : API::Client.new - response = get(API::Request.new(client, '/version').url) + response = get(API::Request.new(client, '/metadata').url) - JSON.parse(response.body, symbolize_names: true) + JSON.parse(response.body, symbolize_names: true).then do |metadata| + { + **metadata.slice(:version, :revision), + kas_version: metadata.dig(:kas, :version) + }.compact + end rescue StandardError, ArgumentError => e Logger.error("Failed to attach version info to allure report: #{e}") {} diff --git a/qa/qa/runtime/browser.rb b/qa/qa/runtime/browser.rb index 0dbc3cdf09d..d2ddaf86353 100644 --- a/qa/qa/runtime/browser.rb +++ b/qa/qa/runtime/browser.rb @@ -111,6 +111,7 @@ module QA if QA::Runtime::Env.remote_mobile_device_name capabilities['platformName'] = 'Android' + capabilities['appium:automationName'] = 'UiAutomator2' capabilities['appium:deviceName'] = QA::Runtime::Env.remote_mobile_device_name capabilities['appium:platformVersion'] = 'latest' else @@ -120,6 +121,7 @@ module QA when :safari if QA::Runtime::Env.remote_mobile_device_name capabilities['platformName'] = 'iOS' + capabilities['appium:automationName'] = 'XCUITest' capabilities['appium:deviceName'] = QA::Runtime::Env.remote_mobile_device_name capabilities['appium:platformVersion'] = 'latest' end diff --git a/qa/qa/runtime/env.rb b/qa/qa/runtime/env.rb index 782ba1cf2fa..7cb7625118e 100644 --- a/qa/qa/runtime/env.rb +++ b/qa/qa/runtime/env.rb @@ -443,7 +443,11 @@ module QA end def export_metrics? - running_in_ci? && enabled?(ENV['QA_EXPORT_TEST_METRICS'], default: true) + enabled?(ENV['QA_EXPORT_TEST_METRICS'], default: false) + end + + def save_metrics_json? + enabled?(ENV['QA_SAVE_TEST_METRICS'], default: false) end def ee_activation_code diff --git a/qa/qa/runtime/key/ed25519.rb b/qa/qa/runtime/key/ed25519.rb index 3a3567d55da..f59d7b3688d 100644 --- a/qa/qa/runtime/key/ed25519.rb +++ b/qa/qa/runtime/key/ed25519.rb @@ -4,8 +4,8 @@ module QA module Runtime module Key class ED25519 < Base - def initialize - super('ed25519', 256) + def initialize(bits = 256) + super('ed25519', bits) end end end diff --git a/qa/qa/scenario/bootable.rb b/qa/qa/scenario/bootable.rb index 8eedfab3cff..c6050798e22 100644 --- a/qa/qa/scenario/bootable.rb +++ b/qa/qa/scenario/bootable.rb @@ -19,7 +19,8 @@ module QA options.to_a.each do |opt| # The argument for the --set-feature-flags option should look something like "flag1=enabled,flag2=disabled" # Here we translate that string into a hash, e.g.: { 'flag1' => 'enabled', 'flag2' => "disabled" } - if opt.name == :set_feature_flags + case opt.name + when :set_feature_flags parser.on(opt.arg, opt.desc) do |flags| value = flags.split(',').each_with_object({}) do |pair, hash| flag_name, flag_value = pair.split('=') @@ -31,7 +32,7 @@ module QA end next - elsif opt.name == :count_examples_only || opt.name == :test_metadata_only + when :count_examples_only, :test_metadata_only parser.on(opt.arg, opt.desc) do |value| QA::Runtime::Env.dry_run = true Runtime::Scenario.define(opt.name, value) diff --git a/qa/qa/scenario/test/instance/gitlab_pages.rb b/qa/qa/scenario/test/instance/gitlab_pages.rb new file mode 100644 index 00000000000..487fd739626 --- /dev/null +++ b/qa/qa/scenario/test/instance/gitlab_pages.rb @@ -0,0 +1,13 @@ +# frozen_string_literal: true + +module QA + module Scenario + module Test + module Instance + class GitlabPages < All + tags :gitlab_pages + end + end + end + end +end diff --git a/qa/qa/specs/features/api/12_systems/gitaly/automatic_failover_and_recovery_spec.rb b/qa/qa/specs/features/api/12_systems/gitaly/automatic_failover_and_recovery_spec.rb index 2058d58d5d6..8bbef4ae429 100644 --- a/qa/qa/specs/features/api/12_systems/gitaly/automatic_failover_and_recovery_spec.rb +++ b/qa/qa/specs/features/api/12_systems/gitaly/automatic_failover_and_recovery_spec.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true module QA - RSpec.describe 'Systems' do + RSpec.describe 'Systems', product_group: :gitaly do context 'with Gitaly automatic failover and recovery', :orchestrated, :gitaly_cluster do # Variables shared between contexts. They're used and shared between # contexts so they can't be `let` variables. diff --git a/qa/qa/specs/features/api/12_systems/gitaly/backend_node_recovery_spec.rb b/qa/qa/specs/features/api/12_systems/gitaly/backend_node_recovery_spec.rb index 0b4bdf550f8..1abc7b8a912 100644 --- a/qa/qa/specs/features/api/12_systems/gitaly/backend_node_recovery_spec.rb +++ b/qa/qa/specs/features/api/12_systems/gitaly/backend_node_recovery_spec.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true module QA - RSpec.describe 'Systems' do + RSpec.describe 'Systems', product_group: :gitaly do describe 'Gitaly backend node recovery', :orchestrated, :gitaly_cluster, :skip_live_env do let(:praefect_manager) { Service::PraefectManager.new } let(:project) do diff --git a/qa/qa/specs/features/api/12_systems/gitaly/changing_repository_storage_spec.rb b/qa/qa/specs/features/api/12_systems/gitaly/changing_repository_storage_spec.rb index 18ec8e0a8b4..01c50c0cd6a 100644 --- a/qa/qa/specs/features/api/12_systems/gitaly/changing_repository_storage_spec.rb +++ b/qa/qa/specs/features/api/12_systems/gitaly/changing_repository_storage_spec.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true module QA - RSpec.describe 'Systems' do + RSpec.describe 'Systems', product_group: :gitaly do describe 'Changing Gitaly repository storage', :requires_admin, except: { job: 'review-qa-*' } do praefect_manager = Service::PraefectManager.new diff --git a/qa/qa/specs/features/api/12_systems/gitaly/distributed_reads_spec.rb b/qa/qa/specs/features/api/12_systems/gitaly/distributed_reads_spec.rb index 692297e40ce..397fdb909ac 100644 --- a/qa/qa/specs/features/api/12_systems/gitaly/distributed_reads_spec.rb +++ b/qa/qa/specs/features/api/12_systems/gitaly/distributed_reads_spec.rb @@ -3,7 +3,7 @@ require 'parallel' module QA - RSpec.describe 'Systems' do + RSpec.describe 'Systems', product_group: :gitaly do describe 'Gitaly distributed reads', :orchestrated, :gitaly_cluster, :skip_live_env, :requires_admin do let(:number_of_reads_per_loop) { 9 } let(:praefect_manager) { Service::PraefectManager.new } @@ -45,7 +45,11 @@ module QA end it 'does not read from the unhealthy node', - testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347834' do + testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347834', + quarantine: { + issue: 'https://gitlab.com/gitlab-org/gitlab/-/issues/378174', + type: :flaky + } do pre_read_data = praefect_manager.query_read_distribution read_from_project(project, number_of_reads_per_loop * 10) diff --git a/qa/qa/specs/features/api/12_systems/gitaly/gitaly_mtls_spec.rb b/qa/qa/specs/features/api/12_systems/gitaly/gitaly_mtls_spec.rb index a4b39554453..48d08136d28 100644 --- a/qa/qa/specs/features/api/12_systems/gitaly/gitaly_mtls_spec.rb +++ b/qa/qa/specs/features/api/12_systems/gitaly/gitaly_mtls_spec.rb @@ -2,7 +2,7 @@ module QA RSpec.describe 'Systems' do - describe 'Gitaly using mTLS', :orchestrated, :mtls do + describe 'Gitaly using mTLS', :orchestrated, :mtls, product_group: :gitaly do let(:intial_commit_message) { 'Initial commit' } let(:first_added_commit_message) { 'commit over git' } let(:second_added_commit_message) { 'commit over api' } diff --git a/qa/qa/specs/features/api/12_systems/gitaly/praefect_connectivity_spec.rb b/qa/qa/specs/features/api/12_systems/gitaly/praefect_connectivity_spec.rb index f25b50f584d..bd00b3781f7 100644 --- a/qa/qa/specs/features/api/12_systems/gitaly/praefect_connectivity_spec.rb +++ b/qa/qa/specs/features/api/12_systems/gitaly/praefect_connectivity_spec.rb @@ -2,7 +2,7 @@ module QA RSpec.describe 'Systems' do - describe 'Praefect connectivity commands', :orchestrated, :gitaly_cluster do + describe 'Praefect connectivity commands', :orchestrated, :gitaly_cluster, product_group: :gitaly do praefect_manager = Service::PraefectManager.new before do diff --git a/qa/qa/specs/features/api/12_systems/gitaly/praefect_dataloss_spec.rb b/qa/qa/specs/features/api/12_systems/gitaly/praefect_dataloss_spec.rb index 944c58ebc83..6ba192a9dd6 100644 --- a/qa/qa/specs/features/api/12_systems/gitaly/praefect_dataloss_spec.rb +++ b/qa/qa/specs/features/api/12_systems/gitaly/praefect_dataloss_spec.rb @@ -2,7 +2,7 @@ module QA RSpec.describe 'Systems' do - describe 'Praefect dataloss commands', :orchestrated, :gitaly_cluster do + describe 'Praefect dataloss commands', :orchestrated, :gitaly_cluster, product_group: :gitaly do let(:praefect_manager) { Service::PraefectManager.new } let(:project) do diff --git a/qa/qa/specs/features/api/12_systems/gitaly/praefect_replication_queue_spec.rb b/qa/qa/specs/features/api/12_systems/gitaly/praefect_replication_queue_spec.rb index f4efcf74956..94bae38c5c8 100644 --- a/qa/qa/specs/features/api/12_systems/gitaly/praefect_replication_queue_spec.rb +++ b/qa/qa/specs/features/api/12_systems/gitaly/praefect_replication_queue_spec.rb @@ -3,7 +3,7 @@ require 'parallel' module QA - RSpec.describe 'Systems' do + RSpec.describe 'Systems', product_group: :gitaly do describe 'Gitaly Cluster replication queue', :orchestrated, :gitaly_cluster, :skip_live_env do let(:praefect_manager) { Service::PraefectManager.new } let(:project) do diff --git a/qa/qa/specs/features/api/12_systems/gitaly/praefect_repo_sync_spec.rb b/qa/qa/specs/features/api/12_systems/gitaly/praefect_repo_sync_spec.rb index 064743ae469..40fc6bf2637 100644 --- a/qa/qa/specs/features/api/12_systems/gitaly/praefect_repo_sync_spec.rb +++ b/qa/qa/specs/features/api/12_systems/gitaly/praefect_repo_sync_spec.rb @@ -2,7 +2,7 @@ module QA RSpec.describe 'Systems' do - describe 'Praefect repository commands', :orchestrated, :gitaly_cluster do + describe 'Praefect repository commands', :orchestrated, :gitaly_cluster, product_group: :gitaly do let(:praefect_manager) { Service::PraefectManager.new } let(:repo1) do diff --git a/qa/qa/specs/features/api/1_manage/group_access_token_spec.rb b/qa/qa/specs/features/api/1_manage/group_access_token_spec.rb index bf95a215c8e..e0db758dde3 100644 --- a/qa/qa/specs/features/api/1_manage/group_access_token_spec.rb +++ b/qa/qa/specs/features/api/1_manage/group_access_token_spec.rb @@ -2,7 +2,7 @@ module QA RSpec.describe 'Manage' do - describe 'Group access token' do + describe 'Group access token', product_group: :authentication_and_authorization do let(:group_access_token) { QA::Resource::GroupAccessToken.fabricate_via_api! } let(:api_client) { Runtime::API::Client.new(:gitlab, personal_access_token: group_access_token.token) } let(:project) do 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 c3e41e9298b..ab50e02c790 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,165 +1,197 @@ # frozen_string_literal: true module QA - # Spec uses real github.com, which means outage of github.com can actually block deployment - # Keep spec in reliable bucket but don't run in blocking pipelines - RSpec.describe 'Manage', :github, :reliable, :skip_live_env, :requires_admin, product_group: :import do - describe 'Project import', issue: 'https://gitlab.com/gitlab-org/gitlab/-/issues/353583' do - let!(:api_client) { Runtime::API::Client.as_admin } - let!(:group) { Resource::Group.fabricate_via_api! { |resource| resource.api_client = api_client } } - let!(:user) do - Resource::User.fabricate_via_api! do |resource| - resource.api_client = api_client - resource.hard_delete_on_api_removal = true + # https://github.com/gitlab-qa-github/import-test <- project under test + # + RSpec.describe 'Manage', product_group: :import do + describe 'GitHub import', :reliable do + include_context 'with github import' + + context 'when imported via api' do + it 'imports project', testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347670' do + imported_project.reload! # import the project + + expect { imported_project.project_import_status[:import_status] }.to eventually_eq('finished') + .within(max_duration: 240, sleep_interval: 1) + + aggregate_failures do + verify_status_data + verify_repository_import + verify_protected_branches_import + verify_commits_import + verify_labels_import + verify_issues_import + verify_milestones_import + verify_wikis_import + verify_merge_requests_import + verify_release_import + end end - end - let(:imported_project) do - Resource::ProjectImportedFromGithub.fabricate_via_api! do |project| - project.name = 'imported-project' - project.group = group - project.github_personal_access_token = Runtime::Env.github_access_token - project.github_repository_path = 'gitlab-qa-github/import-test' - project.api_client = Runtime::API::Client.new(user: user) - project.issue_events_import = true - project.full_notes_import = true + def verify_status_data + stats = imported_project.project_import_status.dig(:stats, :imported) + expect(stats).to include( + issue: 1, + label: 9, + milestone: 1, + note: 3, + pull_request: 1, + pull_request_review: 1, + diff_note: 1, + release: 1 + ) end - end - - before do - group.add_member(user, Resource::Members::AccessLevel::MAINTAINER) - end - after do - user.remove_via_api! - end - - it 'imports Github repo via api', testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347670' do - imported_project.reload! # import the project - - expect { imported_project.project_import_status[:import_status] }.to eventually_eq('finished') - .within(max_duration: 240, sleep_interval: 1) - - aggregate_failures do - verify_status_data - verify_repository_import - verify_protected_branches_import - verify_commits_import - verify_labels_import - verify_issues_import - verify_milestones_import - verify_wikis_import - verify_merge_requests_import + def verify_repository_import + expect(imported_project.reload!.description).to eq('Project for github import test') + expect(imported_project.api_response[:import_error]).to be_nil end - end - def verify_status_data - stats = imported_project.project_import_status.dig(:stats, :imported) - expect(stats).to include( - issue: 1, - label: 9, - milestone: 1, - note: 3, - pull_request: 1, - pull_request_review: 1, - diff_note: 1, - release: 1 - ) - end + def verify_protected_branches_import + imported_branches = imported_project.protected_branches.map do |branch| + branch.slice(:name, :allow_force_push) + end + actual_branches = [ + { + name: 'main', + allow_force_push: false + }, + { + name: 'release', + allow_force_push: true + } + ] - def verify_repository_import - expect(imported_project.reload!.description).to eq('Project for github import test') - expect(imported_project.api_response[:import_error]).to be_nil - end + expect(imported_branches).to match_array(actual_branches) + end - def verify_protected_branches_import - branches = imported_project.protected_branches.map do |branch| - branch.slice(:name, :allow_force_push, :code_owner_approval_required) + def verify_commits_import + expect(imported_project.commits.length).to eq(2) end - expect(branches.first).to include( - { - name: 'main' - # TODO: Add validation once https://gitlab.com/groups/gitlab-org/-/epics/8585 is closed - # At the moment both options are always set to false regardless of state in github - # allow_force_push: true, - # code_owner_approval_required: true - } - ) - end - def verify_commits_import - expect(imported_project.commits.length).to eq(2) - end + def verify_labels_import + labels = imported_project.labels.map { |label| label.slice(:name, :color) } + + expect(labels).to include( + { name: 'bug', color: '#d73a4a' }, + { name: 'documentation', color: '#0075ca' }, + { name: 'duplicate', color: '#cfd3d7' }, + { name: 'enhancement', color: '#a2eeef' }, + { name: 'good first issue', color: '#7057ff' }, + { name: 'help wanted', color: '#008672' }, + { name: 'invalid', color: '#e4e669' }, + { name: 'question', color: '#d876e3' }, + { name: 'wontfix', color: '#ffffff' } + ) + end - def verify_labels_import - labels = imported_project.labels.map { |label| label.slice(:name, :color) } - - expect(labels).to include( - { name: 'bug', color: '#d73a4a' }, - { name: 'documentation', color: '#0075ca' }, - { name: 'duplicate', color: '#cfd3d7' }, - { name: 'enhancement', color: '#a2eeef' }, - { name: 'good first issue', color: '#7057ff' }, - { name: 'help wanted', color: '#008672' }, - { name: 'invalid', color: '#e4e669' }, - { name: 'question', color: '#d876e3' }, - { name: 'wontfix', color: '#ffffff' } - ) - end + def verify_milestones_import + milestones = imported_project.milestones - def verify_issues_import - issues = imported_project.issues + expect(milestones.length).to eq(1) + expect(milestones.first).to include(title: '0.0.1', description: nil, state: 'active') + end - expect(issues.length).to eq(1) - expect(issues.first).to include( - title: 'Test issue', - description: "*Created by: gitlab-qa-github*\n\nTest issue description", - labels: ['good first issue', 'help wanted', 'question'], - user_notes_count: 2 - ) - end + def verify_wikis_import + wikis = imported_project.wikis - def verify_milestones_import - milestones = imported_project.milestones + expect(wikis.length).to eq(1) + expect(wikis.first).to include(title: 'Home', format: 'markdown') + end - expect(milestones.length).to eq(1) - expect(milestones.first).to include(title: '0.0.1', description: nil, state: 'active') - end + def verify_issues_import + issues = imported_project.issues + issue = Resource::Issue.init do |resource| + resource.project = imported_project + resource.iid = issues.first[:iid] + resource.api_client = user_api_client + end.reload! + comments, events = fetch_events_and_comments(issue) + + expect(issues.length).to eq(1) + expect(issue.api_resource).to include( + title: 'Test issue', + description: "*Created by: gitlab-qa-github*\n\nTest issue description", + labels: ['good first issue', 'help wanted', 'question'] + ) + expect(comments).to match_array( + [ + "*Created by: gitlab-qa-github*\n\nSome test comment", + "*Created by: gitlab-qa-github*\n\nAnother test comment" + ] + ) + expect(events).to match_array( + [ + { name: "add_label", label: "question" }, + { name: "add_label", label: "good first issue" }, + { name: "add_label", label: "help wanted" }, + { name: "add_milestone", label: "0.0.1" }, + { name: "closed" }, + { name: "reopened" } + ] + ) + end - def verify_wikis_import - wikis = imported_project.wikis + def verify_merge_requests_import + merge_requests = imported_project.merge_requests + merge_request = Resource::MergeRequest.init do |mr| + mr.project = imported_project + mr.iid = merge_requests.first[:iid] + mr.api_client = user_api_client + end.reload! + comments, events = fetch_events_and_comments(merge_request) + + expect(merge_requests.length).to eq(1) + expect(merge_request.api_resource).to include( + title: 'Test pull request', + state: 'opened', + target_branch: 'main', + source_branch: 'gitlab-qa-github-patch-1', + labels: %w[documentation], + description: "*Created by: gitlab-qa-github*\n\nTest pull request body" + ) + expect(comments).to match_array( + [ + "*Created by: gitlab-qa-github*\n\n**Review:** Commented\n\nGood but needs some improvement", + "*Created by: gitlab-qa-github*\n\n```suggestion:-0+0\nProject for GitHub import test to GitLab\r\n```", + "*Created by: gitlab-qa-github*\n\nSome test PR comment" + ] + ) + expect(events).to match_array( + [ + { name: "add_label", label: "documentation" }, + { name: "add_milestone", label: "0.0.1" } + ] + ) + end - expect(wikis.length).to eq(1) - expect(wikis.first).to include(title: 'Home', format: 'markdown') - end + def verify_release_import + releases = imported_project.releases + + expect(releases.length).to eq(1) + expect(releases.first).to include( + tag_name: "0.0.1", + name: "0.0.1", + description: "Initial release", + created_at: "2022-03-07T07:59:22.000Z", + released_at: "2022-03-07T08:02:09.000Z" + ) + end - def verify_merge_requests_import - merge_requests = imported_project.merge_requests - merge_request = Resource::MergeRequest.init do |mr| - mr.project = imported_project - mr.iid = merge_requests.first[:iid] - mr.api_client = api_client - end.reload! - mr_comments = merge_request.comments.map { |comment| comment[:body] } - - expect(merge_requests.length).to eq(1) - expect(merge_request.api_resource).to include( - title: 'Test pull request', - state: 'opened', - target_branch: 'main', - source_branch: 'gitlab-qa-github-patch-1', - labels: %w[documentation], - description: <<~DSC.strip - *Created by: gitlab-qa-github*\n\nTest pull request body - DSC - ) - expect(mr_comments).to match_array( - [ - "*Created by: gitlab-qa-github*\n\n**Review:** Commented\n\nGood but needs some improvement", - "*Created by: gitlab-qa-github*\n\n```suggestion:-0+0\nProject for GitHub import test to GitLab\r\n```", - "*Created by: gitlab-qa-github*\n\nSome test PR comment" + # Fetch events and comments from issue or mr + # + # @param [QA::Resource::Issuable] issuable + # @return [Array] + def fetch_events_and_comments(issuable) + comments = issuable.comments.map { |comment| comment[:body] } + events = [ + *issuable.label_events.map { |e| { name: "#{e[:action]}_label", label: e.dig(:label, :name) } }, + *issuable.state_events.map { |e| { name: e[:state] } }, + *issuable.milestone_events.map { |e| { name: "#{e[:action]}_milestone", label: e.dig(:milestone, :title) } } ] - ) + + [comments, events] + end 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 c1f11b15068..887eeda51e3 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 @@ -1,7 +1,5 @@ # frozen_string_literal: true -require_relative 'gitlab_project_migration_common' - module QA RSpec.describe 'Manage' do describe 'Gitlab migration', product_group: :import do 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 5689fa169ce..116a00f8385 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 @@ -98,12 +98,17 @@ module QA let(:mrs) { fetch_mrs(imported_project, target_api_client) } let(:issues) { fetch_issues(imported_project, target_api_client) } + let(:import_failures) { imported_group.import_details.sum([]) { |details| details[:failures] } } + before do destination_group.add_member(user, Resource::Members::AccessLevel::MAINTAINER) end # rubocop:disable RSpec/InstanceVariable after do |example| + # Log failures for easier debugging + Runtime::Logger.error("Import failures: #{import_failures}") if example.exception && !import_failures.empty? + next unless defined?(@import_time) # save data for comparison notification creation @@ -112,7 +117,7 @@ module QA { importer: :gitlab, import_time: @import_time, - errors: imported_group.import_details.sum([]) { |details| details[:failures] }, + errors: import_failures, source: { name: "GitLab Source", project_name: source_project.path_with_namespace, @@ -154,7 +159,7 @@ module QA end # rubocop:enable RSpec/InstanceVariable - it "migrates large gitlab group via api", testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/358842' do + it "migrates large gitlab group via api", testcase: "https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/358842" do start = Time.now # trigger import and log imported group path @@ -165,7 +170,11 @@ module QA # wait for import to finish and save import time logger.info("== Waiting for import to be finished ==") - expect { imported_group.import_status }.to eventually_eq('finished').within(import_wait_duration) + expect { imported_group.import_status }.not_to eventually_eq("started").within(import_wait_duration) + # finished status actually means success, don't wait for finished status explicitly + # because test would wait full duration if returned status is "failed" + expect(imported_group.import_status).to eq("finished") + @import_time = Time.now - start aggregate_failures do diff --git a/qa/qa/specs/features/api/1_manage/migration/gitlab_migration_members_spec.rb b/qa/qa/specs/features/api/1_manage/migration/gitlab_migration_members_spec.rb index aa4d3becbe7..07e54ead9c8 100644 --- a/qa/qa/specs/features/api/1_manage/migration/gitlab_migration_members_spec.rb +++ b/qa/qa/specs/features/api/1_manage/migration/gitlab_migration_members_spec.rb @@ -1,7 +1,5 @@ # frozen_string_literal: true -require_relative 'gitlab_project_migration_common' - module QA RSpec.describe 'Manage' do describe 'Gitlab migration', product_group: :import do 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 92cba005832..f44786939dc 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 @@ -1,49 +1,66 @@ # frozen_string_literal: true -require_relative 'gitlab_project_migration_common' - module QA RSpec.describe 'Manage' do describe 'Gitlab migration', product_group: :import do include_context 'with gitlab project migration' - context 'with merge request' do - let!(:source_project_with_readme) { true } - - let!(:other_user) do - Resource::User - .fabricate_via_api! { |usr| usr.api_client = admin_api_client } - .tap do |usr| - usr.set_public_email - source_project.add_member(usr, Resource::Members::AccessLevel::MAINTAINER) - end - end + let!(:source_project_with_readme) { true } - let!(:source_mr) do - Resource::MergeRequest.fabricate_via_api! do |mr| - mr.project = source_project - mr.api_client = Runtime::API::Client.new(user: other_user) + # We create additional user so that object being migrated is not owned by the user doing migration + let!(:other_user) do + Resource::User + .fabricate_via_api! { |usr| usr.api_client = admin_api_client } + .tap do |usr| + usr.set_public_email + source_project.add_member(usr, Resource::Members::AccessLevel::MAINTAINER) end + end + + let!(:source_mr) do + Resource::MergeRequest.fabricate_via_api! do |mr| + mr.project = source_project + mr.api_client = Runtime::API::Client.new(user: other_user) + mr.reviewer_ids = [other_user.id] end + end - let!(:source_comment) { source_mr.add_comment('This is a test comment!') } + let!(:source_comment) { source_mr.add_comment(body: 'This is a test comment!') } - let(:imported_mrs) { imported_project.merge_requests } - let(:imported_mr_comments) { imported_mr.comments.map { |note| note.except(:id, :noteable_id) } } - let(:source_mr_comments) { source_mr.comments.map { |note| note.except(:id, :noteable_id) } } + let(:imported_mrs) { imported_project.merge_requests } + let(:imported_mr_comments) { imported_mr.comments.map { |note| note.except(:id, :noteable_id) } } + let(:source_mr_comments) { source_mr.comments.map { |note| note.except(:id, :noteable_id) } } - let(:imported_mr) do - Resource::MergeRequest.init do |mr| - mr.project = imported_project - mr.iid = imported_mrs.first[:iid] - mr.api_client = api_client - end + let(:imported_mr) do + Resource::MergeRequest.init do |mr| + mr.project = imported_project + mr.iid = imported_mrs.first[:iid] + mr.api_client = api_client end + end - after do - other_user.remove_via_api! + let(:imported_mr_reviewers) { imported_mr.reviewers.map { |r| r.slice(:name, :username) } } + let(:source_mr_reviewers) { [{ name: other_user.name, username: other_user.username }] } + + let(:imported_mr_approvers) do + imported_mr.approval_configuration[:approved_by].map do |usr| + { username: usr.dig(:user, :username), name: usr.dig(:user, :name) } end + end + + before do + source_project.update_approval_configuration( + merge_requests_author_approval: true, + approvals_before_merge: 1 + ) + source_mr.approve + end + after do + other_user.remove_via_api! + end + + context 'with merge request' do it( 'successfully imports merge request', testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/348478' @@ -54,7 +71,9 @@ module QA aggregate_failures do expect(imported_mr).to eq(source_mr.reload!) - expect(imported_mr_comments).to eq(source_mr_comments) + expect(imported_mr_comments).to match_array(source_mr_comments) + expect(imported_mr_reviewers).to eq(source_mr_reviewers) + expect(imported_mr_approvers).to eq([{ username: other_user.username, name: other_user.name }]) end end end diff --git a/qa/qa/specs/features/api/1_manage/migration/gitlab_migration_pipeline_spec.rb b/qa/qa/specs/features/api/1_manage/migration/gitlab_migration_pipeline_spec.rb index 3db4ff4351e..7b79e6967c7 100644 --- a/qa/qa/specs/features/api/1_manage/migration/gitlab_migration_pipeline_spec.rb +++ b/qa/qa/specs/features/api/1_manage/migration/gitlab_migration_pipeline_spec.rb @@ -1,7 +1,5 @@ # frozen_string_literal: true -require_relative 'gitlab_project_migration_common' - module QA RSpec.describe 'Manage' do describe 'Gitlab migration', product_group: :import do 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 3e0df3d1e13..2b7818d1ed2 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 @@ -1,7 +1,5 @@ # frozen_string_literal: true -require_relative 'gitlab_project_migration_common' - module QA RSpec.describe 'Manage' do describe 'Gitlab migration', product_group: :import do diff --git a/qa/qa/specs/features/api/1_manage/migration/gitlab_migration_release_spec.rb b/qa/qa/specs/features/api/1_manage/migration/gitlab_migration_release_spec.rb index 91dcfe6a1a3..36036a2321e 100644 --- a/qa/qa/specs/features/api/1_manage/migration/gitlab_migration_release_spec.rb +++ b/qa/qa/specs/features/api/1_manage/migration/gitlab_migration_release_spec.rb @@ -1,7 +1,5 @@ # frozen_string_literal: true -require_relative 'gitlab_project_migration_common' - module QA RSpec.describe 'Manage' do describe 'Gitlab migration', product_group: :import do diff --git a/qa/qa/specs/features/api/1_manage/project_access_token_spec.rb b/qa/qa/specs/features/api/1_manage/project_access_token_spec.rb index 756bbe2164a..e210ba882bb 100644 --- a/qa/qa/specs/features/api/1_manage/project_access_token_spec.rb +++ b/qa/qa/specs/features/api/1_manage/project_access_token_spec.rb @@ -2,7 +2,7 @@ module QA RSpec.describe 'Manage' do - describe 'Project access token' do + describe 'Project access token', product_group: :authentication_and_authorization do before(:all) do @project_access_token = QA::Resource::ProjectAccessToken.fabricate_via_api! do |pat| pat.project = Resource::ReusableProject.fabricate_via_api! diff --git a/qa/qa/specs/features/api/1_manage/user_access_termination_spec.rb b/qa/qa/specs/features/api/1_manage/user_access_termination_spec.rb index 28c20344b29..b7d0d72297a 100644 --- a/qa/qa/specs/features/api/1_manage/user_access_termination_spec.rb +++ b/qa/qa/specs/features/api/1_manage/user_access_termination_spec.rb @@ -2,7 +2,7 @@ module QA RSpec.describe 'Manage' do - describe 'User', :requires_admin, :reliable do + describe 'User', :requires_admin, :reliable, product_group: :authentication_and_authorization do before(:all) do admin_api_client = Runtime::API::Client.as_admin diff --git a/qa/qa/specs/features/api/2_plan/closes_issue_via_pushing_a_commit_spec.rb b/qa/qa/specs/features/api/2_plan/closes_issue_via_pushing_a_commit_spec.rb index 073669f033c..6935f9de486 100644 --- a/qa/qa/specs/features/api/2_plan/closes_issue_via_pushing_a_commit_spec.rb +++ b/qa/qa/specs/features/api/2_plan/closes_issue_via_pushing_a_commit_spec.rb @@ -6,7 +6,7 @@ module QA RSpec.describe 'Plan' do include Support::API - describe 'Issue' do + describe 'Issue', product_group: :project_management do let(:issue) do Resource::Issue.fabricate_via_api! end diff --git a/qa/qa/specs/features/api/3_create/merge_request/push_options_labels_spec.rb b/qa/qa/specs/features/api/3_create/merge_request/push_options_labels_spec.rb index ab9af872753..a1060c1d890 100644 --- a/qa/qa/specs/features/api/3_create/merge_request/push_options_labels_spec.rb +++ b/qa/qa/specs/features/api/3_create/merge_request/push_options_labels_spec.rb @@ -2,7 +2,7 @@ module QA RSpec.describe 'Create' do - describe 'Merge request push options' do + describe 'Merge request push options', product_group: :code_review do # If run locally on GDK, push options need to be enabled on the host with the following command: # # git config --global receive.advertisepushoptions true diff --git a/qa/qa/specs/features/api/3_create/merge_request/push_options_mwps_spec.rb b/qa/qa/specs/features/api/3_create/merge_request/push_options_mwps_spec.rb index 6eb3060fb59..0a82c5d6736 100644 --- a/qa/qa/specs/features/api/3_create/merge_request/push_options_mwps_spec.rb +++ b/qa/qa/specs/features/api/3_create/merge_request/push_options_mwps_spec.rb @@ -2,7 +2,7 @@ module QA RSpec.describe 'Create' do - describe 'Merge request push options' do + describe 'Merge request push options', product_group: :code_review do # If run locally on GDK, push options need to be enabled on the host with the following command: # # git config --global receive.advertisepushoptions true diff --git a/qa/qa/specs/features/api/3_create/merge_request/push_options_remove_source_branch_spec.rb b/qa/qa/specs/features/api/3_create/merge_request/push_options_remove_source_branch_spec.rb index 708dd7aa8af..11328c2f517 100644 --- a/qa/qa/specs/features/api/3_create/merge_request/push_options_remove_source_branch_spec.rb +++ b/qa/qa/specs/features/api/3_create/merge_request/push_options_remove_source_branch_spec.rb @@ -2,7 +2,7 @@ module QA RSpec.describe 'Create' do - describe 'Merge request push options' do + describe 'Merge request push options', product_group: :code_review do # If run locally on GDK, push options need to be enabled on the host with the following command: # # git config --global receive.advertisepushoptions true diff --git a/qa/qa/specs/features/api/3_create/merge_request/push_options_target_branch_spec.rb b/qa/qa/specs/features/api/3_create/merge_request/push_options_target_branch_spec.rb index 97d461c5113..eb7d3da0f97 100644 --- a/qa/qa/specs/features/api/3_create/merge_request/push_options_target_branch_spec.rb +++ b/qa/qa/specs/features/api/3_create/merge_request/push_options_target_branch_spec.rb @@ -2,7 +2,7 @@ module QA RSpec.describe 'Create' do - describe 'Merge request push options' do + describe 'Merge request push options', product_group: :code_review do # If run locally on GDK, push options need to be enabled on the host with the following command: # # git config --global receive.advertisepushoptions true diff --git a/qa/qa/specs/features/api/3_create/merge_request/push_options_title_description_spec.rb b/qa/qa/specs/features/api/3_create/merge_request/push_options_title_description_spec.rb index 9d534e9ea6b..dd297f47975 100644 --- a/qa/qa/specs/features/api/3_create/merge_request/push_options_title_description_spec.rb +++ b/qa/qa/specs/features/api/3_create/merge_request/push_options_title_description_spec.rb @@ -2,7 +2,7 @@ module QA RSpec.describe 'Create' do - describe 'Merge request push options' do + describe 'Merge request push options', product_group: :code_review do # If run locally on GDK, push options need to be enabled on the host with the following command: # # git config --global receive.advertisepushoptions true diff --git a/qa/qa/specs/features/api/3_create/repository/storage_size_spec.rb b/qa/qa/specs/features/api/3_create/repository/storage_size_spec.rb index df3b5a4e7fb..8c7a58be43a 100644 --- a/qa/qa/specs/features/api/3_create/repository/storage_size_spec.rb +++ b/qa/qa/specs/features/api/3_create/repository/storage_size_spec.rb @@ -46,6 +46,7 @@ module QA local_size = Git::Repository.perform do |repository| repository.uri = project.repository_http_location.uri repository.use_default_credentials + repository.default_branch = project.default_branch repository.clone repository.configure_identity('GitLab QA', 'root@gitlab.com') # These two commits add a total of 1mb, but half of that is the same as content that has already been added to diff --git a/qa/qa/specs/features/api/3_create/snippet/snippet_repository_storage_move_spec.rb b/qa/qa/specs/features/api/3_create/snippet/snippet_repository_storage_move_spec.rb index bfa408e1c92..60dace0938e 100644 --- a/qa/qa/specs/features/api/3_create/snippet/snippet_repository_storage_move_spec.rb +++ b/qa/qa/specs/features/api/3_create/snippet/snippet_repository_storage_move_spec.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true module QA - RSpec.describe 'Create' do + RSpec.describe 'Create', product_group: :editor do describe 'Snippet repository storage', :requires_admin, :orchestrated, :repository_storage do let(:source_storage) { { type: :gitaly, name: 'default' } } let(:destination_storage) { { type: :gitaly, name: QA::Runtime::Env.additional_repository_storage } } 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 8ca0ae1f052..8890b3ff317 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 do + RSpec.describe 'Verify', :runner, product_group: :pipeline_authoring do describe 'Pipeline API defined variable inheritance' do include_context 'variable inheritance test prep' diff --git a/qa/qa/specs/features/api/4_verify/cancel_pipeline_when_block_user_spec.rb b/qa/qa/specs/features/api/4_verify/cancel_pipeline_when_block_user_spec.rb index 7c3fb9ebeba..a360c662cf8 100644 --- a/qa/qa/specs/features/api/4_verify/cancel_pipeline_when_block_user_spec.rb +++ b/qa/qa/specs/features/api/4_verify/cancel_pipeline_when_block_user_spec.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true module QA - RSpec.describe 'Verify', :requires_admin do + RSpec.describe 'Verify', :requires_admin, product_group: :pipeline_execution do describe 'When user is blocked' do let!(:admin_api_client) { Runtime::API::Client.as_admin } let!(:user_api_client) { Runtime::API::Client.new(:gitlab, user: user) } 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 9722f62d5a7..4ae97f589cf 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,10 +1,7 @@ # frozen_string_literal: true module QA - RSpec.describe 'Verify', :runner, feature_flag: { - name: 'ci_stop_expanding_file_vars_for_runners', - scope: :project - } do + RSpec.describe 'Verify', :runner, product_group: :pipeline_authoring do describe 'Pipeline with project file variables' do let(:executor) { "qa-runner-#{Faker::Alphanumeric.alphanumeric(number: 8)}" } @@ -14,7 +11,7 @@ module QA end end - let(:runner) do + let!(:runner) do Resource::Runner.fabricate! do |runner| runner.project = project runner.name = executor @@ -60,59 +57,30 @@ module QA end end - after do - runner.remove_via_api! + before do + add_file_variables + add_ci_file + trigger_pipeline + wait_for_pipeline end - shared_examples 'variables are read correctly' do - it 'shows in job log accordingly' do - job = Resource::Job.fabricate_via_api! do |job| - job.project = project - job.id = project.job_by_name('test')[:id] - end - - aggregate_failures do - trace = job.trace - expect(trace).to have_content('run something -f hello, this is test') - expect(trace).to have_content('docker run --tlscacert="This is secret"') - expect(trace).to have_content('run --output=This is secret.crt') - expect(trace).to have_content('Will read private key from hello, this is test') - end - end + after do + runner.remove_via_api! end - # FF does not change current behavior - # https://gitlab.com/gitlab-org/gitlab/-/merge_requests/94198#note_1057609893 - # - # TODO: Remove when FF is removed - # TODO: Archive testcase issue when FF is removed - # Rollout issue: https://gitlab.com/gitlab-org/gitlab/-/issues/369907 - context 'when FF is on', testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/370787' do - before do - Runtime::Feature.enable(:ci_stop_expanding_file_vars_for_runners, project: project) - - runner - add_file_variables - add_ci_file - trigger_pipeline - wait_for_pipeline + it 'shows in job log accordingly', testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/370791' do + job = Resource::Job.fabricate_via_api! do |job| + job.project = project + job.id = project.job_by_name('test')[:id] end - it_behaves_like 'variables are read correctly' - end - - # TODO: Refactor when FF is removed - # TODO: Update testcase issue title and description to not refer to FF status - context 'when FF is off', testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/370791' do - before do - runner - add_file_variables - add_ci_file - trigger_pipeline - wait_for_pipeline + aggregate_failures do + trace = job.trace + expect(trace).to have_content('run something -f hello, this is test') + expect(trace).to have_content('docker run --tlscacert="This is secret"') + expect(trace).to have_content('run --output=This is secret.crt') + expect(trace).to have_content('Will read private key from hello, this is test') end - - it_behaves_like 'variables are read correctly' end private diff --git a/qa/qa/specs/features/api/4_verify/remove_runner_spec.rb b/qa/qa/specs/features/api/4_verify/remove_runner_spec.rb index 6e6198328e5..eb1b085c35c 100644 --- a/qa/qa/specs/features/api/4_verify/remove_runner_spec.rb +++ b/qa/qa/specs/features/api/4_verify/remove_runner_spec.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true module QA - RSpec.describe 'Verify', :runner do + RSpec.describe 'Verify', :runner, product_group: :runner do describe 'Runner removal' do include Support::API diff --git a/qa/qa/specs/features/api/5_package/container_registry_spec.rb b/qa/qa/specs/features/api/5_package/container_registry_spec.rb index 8412c0b2872..0264b8b1ff2 100644 --- a/qa/qa/specs/features/api/5_package/container_registry_spec.rb +++ b/qa/qa/specs/features/api/5_package/container_registry_spec.rb @@ -3,7 +3,7 @@ require 'airborne' module QA - RSpec.describe 'Package', :reliable, only: { subdomain: %i[staging staging-canary pre] } do + RSpec.describe 'Package', :reliable, only: { subdomain: %i[staging staging-canary pre] }, product_group: :container_registry do include Support::API include Support::Helpers::MaskToken diff --git a/qa/qa/specs/features/api/8_monitor/metrics_spec.rb b/qa/qa/specs/features/api/8_monitor/metrics_spec.rb index 1235b996958..932d2a8e4f4 100644 --- a/qa/qa/specs/features/api/8_monitor/metrics_spec.rb +++ b/qa/qa/specs/features/api/8_monitor/metrics_spec.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true module QA - RSpec.describe 'GitLab Metrics', :aggregate_failures, :orchestrated, :metrics do + RSpec.describe 'GitLab Metrics', :aggregate_failures, :orchestrated, :metrics, product_group: :observability do let(:web_uri) { URI.parse(Runtime::Scenario.gitlab_address) } let(:endpoint) do "#{web_uri.scheme}://#{web_uri.host}:#{port}#{path}" diff --git a/qa/qa/specs/features/browser_ui/14_analytics/performance_bar_spec.rb b/qa/qa/specs/features/browser_ui/14_analytics/performance_bar_spec.rb index 867c54102ae..6dfc58fbfea 100644 --- a/qa/qa/specs/features/browser_ui/14_analytics/performance_bar_spec.rb +++ b/qa/qa/specs/features/browser_ui/14_analytics/performance_bar_spec.rb @@ -2,7 +2,7 @@ module QA RSpec.describe 'Analytics' do - describe 'Performance bar display', :requires_admin, :skip_live_env do + describe 'Performance bar display', :requires_admin, :skip_live_env, product_group: :product_analytics do context 'when logged in as an admin user' do # performance metrics: pg, gitaly, redis, rugged (feature flagged), total (not always provided) let(:minimum_metrics_count) { 3 } diff --git a/qa/qa/specs/features/browser_ui/14_analytics/service_ping_default_enabled_spec.rb b/qa/qa/specs/features/browser_ui/14_analytics/service_ping_default_enabled_spec.rb index 7826aca3601..8e4b76cdb7c 100644 --- a/qa/qa/specs/features/browser_ui/14_analytics/service_ping_default_enabled_spec.rb +++ b/qa/qa/specs/features/browser_ui/14_analytics/service_ping_default_enabled_spec.rb @@ -2,7 +2,7 @@ module QA RSpec.describe 'Analytics' do - describe 'Service ping default enabled' do + describe 'Service ping default enabled', product_group: :product_intelligence do context 'when using default enabled from gitlab.yml config', :requires_admin, except: { job: 'review-qa-*' } do before do Flow::Login.sign_in_as_admin diff --git a/qa/qa/specs/features/browser_ui/14_analytics/service_ping_disabled_spec.rb b/qa/qa/specs/features/browser_ui/14_analytics/service_ping_disabled_spec.rb index 8b30d6a7ad7..e25bba97288 100644 --- a/qa/qa/specs/features/browser_ui/14_analytics/service_ping_disabled_spec.rb +++ b/qa/qa/specs/features/browser_ui/14_analytics/service_ping_disabled_spec.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true module QA - RSpec.describe 'Analytics' do + RSpec.describe 'Analytics', product_group: :product_intelligence do describe 'Service ping disabled', :orchestrated, :service_ping_disabled, :requires_admin do context 'when disabled from gitlab.yml config' do before do diff --git a/qa/qa/specs/features/browser_ui/1_manage/group/group_access_token_spec.rb b/qa/qa/specs/features/browser_ui/1_manage/group/group_access_token_spec.rb index 9f39d376baf..a35cde854a2 100644 --- a/qa/qa/specs/features/browser_ui/1_manage/group/group_access_token_spec.rb +++ b/qa/qa/specs/features/browser_ui/1_manage/group/group_access_token_spec.rb @@ -2,7 +2,7 @@ module QA RSpec.describe 'Manage' do - describe 'Group access tokens' do + describe 'Group access tokens', product_group: :authentication_and_authorization do let(:group_access_token) { QA::Resource::GroupAccessToken.fabricate_via_browser_ui! } it( diff --git a/qa/qa/specs/features/browser_ui/1_manage/login/2fa_recovery_spec.rb b/qa/qa/specs/features/browser_ui/1_manage/login/2fa_recovery_spec.rb index f459c0c71eb..0f3d6a104a7 100644 --- a/qa/qa/specs/features/browser_ui/1_manage/login/2fa_recovery_spec.rb +++ b/qa/qa/specs/features/browser_ui/1_manage/login/2fa_recovery_spec.rb @@ -2,7 +2,7 @@ module QA RSpec.describe 'Manage', :requires_admin, :skip_live_env, :reliable do - describe '2FA' do + describe '2FA', product_group: :authentication_and_authorization do let(:owner_user) do Resource::User.fabricate_via_api! do |usr| usr.api_client = admin_api_client diff --git a/qa/qa/specs/features/browser_ui/1_manage/login/2fa_ssh_recovery_spec.rb b/qa/qa/specs/features/browser_ui/1_manage/login/2fa_ssh_recovery_spec.rb index 6c69e4c59d9..9484f15f35d 100644 --- a/qa/qa/specs/features/browser_ui/1_manage/login/2fa_ssh_recovery_spec.rb +++ b/qa/qa/specs/features/browser_ui/1_manage/login/2fa_ssh_recovery_spec.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true module QA - context 'Manage', :reliable, :requires_admin, :skip_live_env do + context 'Manage', :reliable, :requires_admin, :skip_live_env, product_group: :authentication_and_authorization do describe '2FA' do let!(:user) { Resource::User.fabricate_via_api! } let!(:user_api_client) { Runtime::API::Client.new(:gitlab, user: user) } diff --git a/qa/qa/specs/features/browser_ui/1_manage/login/log_in_spec.rb b/qa/qa/specs/features/browser_ui/1_manage/login/log_in_spec.rb index 98b5ecc8f0d..7b91156d926 100644 --- a/qa/qa/specs/features/browser_ui/1_manage/login/log_in_spec.rb +++ b/qa/qa/specs/features/browser_ui/1_manage/login/log_in_spec.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true module QA - RSpec.describe 'Manage', :smoke, :mobile do + RSpec.describe 'Manage', :smoke, :mobile, product_group: :authentication_and_authorization do describe 'basic user login' do it 'user logs in using basic credentials and logs out', testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347880' do Flow::Login.sign_in diff --git a/qa/qa/specs/features/browser_ui/1_manage/login/log_in_with_2fa_spec.rb b/qa/qa/specs/features/browser_ui/1_manage/login/log_in_with_2fa_spec.rb index 56883917153..cf9282c1149 100644 --- a/qa/qa/specs/features/browser_ui/1_manage/login/log_in_with_2fa_spec.rb +++ b/qa/qa/specs/features/browser_ui/1_manage/login/log_in_with_2fa_spec.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true module QA - RSpec.describe 'Manage', :requires_admin, :skip_live_env do + RSpec.describe 'Manage', :requires_admin, :skip_live_env, product_group: :authentication_and_authorization do describe '2FA' do let(:admin_api_client) { Runtime::API::Client.as_admin } let(:owner_api_client) { Runtime::API::Client.new(:gitlab, user: owner_user) } diff --git a/qa/qa/specs/features/browser_ui/1_manage/login/log_into_gitlab_via_ldap_spec.rb b/qa/qa/specs/features/browser_ui/1_manage/login/log_into_gitlab_via_ldap_spec.rb index 7ecad1101c9..3d2e8c13900 100644 --- a/qa/qa/specs/features/browser_ui/1_manage/login/log_into_gitlab_via_ldap_spec.rb +++ b/qa/qa/specs/features/browser_ui/1_manage/login/log_into_gitlab_via_ldap_spec.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true module QA - RSpec.describe 'Manage', :orchestrated, :ldap_no_tls, :ldap_tls do + RSpec.describe 'Manage', :orchestrated, :ldap_no_tls, :ldap_tls, product_group: :authentication_and_authorization do describe 'LDAP login' do it 'user logs into GitLab using LDAP credentials', testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347892' do Flow::Login.sign_in diff --git a/qa/qa/specs/features/browser_ui/1_manage/login/log_into_mattermost_via_gitlab_spec.rb b/qa/qa/specs/features/browser_ui/1_manage/login/log_into_mattermost_via_gitlab_spec.rb index 80e660c1c1d..388c9f6b486 100644 --- a/qa/qa/specs/features/browser_ui/1_manage/login/log_into_mattermost_via_gitlab_spec.rb +++ b/qa/qa/specs/features/browser_ui/1_manage/login/log_into_mattermost_via_gitlab_spec.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true module QA - RSpec.describe 'Manage', :orchestrated, :mattermost do + RSpec.describe 'Manage', :orchestrated, :mattermost, product_group: :authentication_and_authorization do describe 'Mattermost login' do it 'user logs into Mattermost using GitLab OAuth', testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347891' do Flow::Login.sign_in diff --git a/qa/qa/specs/features/browser_ui/1_manage/login/login_via_instance_wide_saml_sso_spec.rb b/qa/qa/specs/features/browser_ui/1_manage/login/login_via_instance_wide_saml_sso_spec.rb index d6cb65c2788..ca10a3f3d65 100644 --- a/qa/qa/specs/features/browser_ui/1_manage/login/login_via_instance_wide_saml_sso_spec.rb +++ b/qa/qa/specs/features/browser_ui/1_manage/login/login_via_instance_wide_saml_sso_spec.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true module QA - RSpec.describe 'Manage', :orchestrated, :instance_saml do + RSpec.describe 'Manage', :orchestrated, :instance_saml, product_group: :authentication_and_authorization do describe 'Instance wide SAML SSO' do it( 'user logs in to gitlab with SAML SSO', diff --git a/qa/qa/specs/features/browser_ui/1_manage/login/maintain_log_in_mixed_env_spec.rb b/qa/qa/specs/features/browser_ui/1_manage/login/maintain_log_in_mixed_env_spec.rb index 1d30b915594..dd39b0c8835 100644 --- a/qa/qa/specs/features/browser_ui/1_manage/login/maintain_log_in_mixed_env_spec.rb +++ b/qa/qa/specs/features/browser_ui/1_manage/login/maintain_log_in_mixed_env_spec.rb @@ -2,7 +2,7 @@ module QA RSpec.describe 'Manage', only: { subdomain: %i[staging staging-canary] }, quarantine: { issue: 'https://gitlab.com/gitlab-org/gitlab/-/issues/344213', type: :stale } do - describe 'basic user' do + describe 'basic user', product_group: :authentication_and_authorization do it 'remains logged in when redirected from canary to non-canary node', testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347626' do Runtime::Browser.visit(:gitlab, Page::Main::Login) diff --git a/qa/qa/specs/features/browser_ui/1_manage/login/register_spec.rb b/qa/qa/specs/features/browser_ui/1_manage/login/register_spec.rb index 295702aa328..e0242008785 100644 --- a/qa/qa/specs/features/browser_ui/1_manage/login/register_spec.rb +++ b/qa/qa/specs/features/browser_ui/1_manage/login/register_spec.rb @@ -13,7 +13,7 @@ module QA end end - RSpec.describe 'Manage', :skip_signup_disabled, :requires_admin do + RSpec.describe 'Manage', :skip_signup_disabled, :requires_admin, product_group: :authentication_and_authorization do describe 'while LDAP is enabled', :orchestrated, :ldap_no_tls, testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347934' do before do # When LDAP is enabled, a previous test might have created a token for the LDAP 'tanuki' user who is not an admin diff --git a/qa/qa/specs/features/browser_ui/1_manage/project/create_project_spec.rb b/qa/qa/specs/features/browser_ui/1_manage/project/create_project_spec.rb index 7c6b0d77219..686cc8fe11e 100644 --- a/qa/qa/specs/features/browser_ui/1_manage/project/create_project_spec.rb +++ b/qa/qa/specs/features/browser_ui/1_manage/project/create_project_spec.rb @@ -7,9 +7,6 @@ module QA it 'creates a new project' do Page::Project::Show.perform do |project_page| expect(project_page).to have_content(project_name) - expect(project_page).to have_content( - /Project \S?#{project_name}\S+ was successfully created/ - ) expect(project_page).to have_content('The repository for this project is empty') end end diff --git a/qa/qa/specs/features/browser_ui/1_manage/project/import_github_repo_spec.rb b/qa/qa/specs/features/browser_ui/1_manage/project/import_github_repo_spec.rb index 6ac11fea7e1..15563e3aa2a 100644 --- a/qa/qa/specs/features/browser_ui/1_manage/project/import_github_repo_spec.rb +++ b/qa/qa/specs/features/browser_ui/1_manage/project/import_github_repo_spec.rb @@ -4,61 +4,89 @@ module QA # Spec uses real github.com, which means outage of github can actually block deployment # Keep spec in reliable bucket but don't run in blocking pipelines RSpec.describe 'Manage', :github, :reliable, :skip_live_env, :requires_admin, product_group: :import do - describe 'Project import' do - let(:github_repo) { 'gitlab-qa-github/import-test' } - let(:api_client) { Runtime::API::Client.as_admin } - let(:group) { Resource::Group.fabricate_via_api! { |resource| resource.api_client = api_client } } - let(:user) do - Resource::User.fabricate_via_api! do |resource| - resource.api_client = api_client - resource.hard_delete_on_api_removal = true + describe 'GitHub import' do + context 'when imported via UI' do + let(:github_repo) { 'gitlab-qa-github/import-test' } + let(:api_client) { Runtime::API::Client.as_admin } + let(:group) { Resource::Group.fabricate_via_api! { |resource| resource.api_client = api_client } } + let(:user) do + Resource::User.fabricate_via_api! do |resource| + resource.api_client = api_client + resource.hard_delete_on_api_removal = true + end end - end - let(:imported_project) do - Resource::ProjectImportedFromGithub.init do |project| - project.import = true - project.group = group - project.github_personal_access_token = Runtime::Env.github_access_token - project.github_repository_path = github_repo - project.api_client = api_client + let(:imported_project) do + Resource::ProjectImportedFromGithub.init do |project| + project.import = true + project.group = group + project.github_personal_access_token = Runtime::Env.github_access_token + project.github_repository_path = github_repo + project.api_client = api_client + end end - end - before do - group.add_member(user, Resource::Members::AccessLevel::MAINTAINER) - - Flow::Login.sign_in(as: user) - Page::Main::Menu.perform(&:go_to_create_project) - Page::Project::New.perform do |project_page| - project_page.click_import_project - project_page.click_github_link + let(:imported_issue) do + Resource::Issue.init do |resource| + resource.project = imported_project + resource.iid = imported_project.issues.first[:iid] + resource.api_client = api_client + end.reload! end - end - after do - user.remove_via_api! - end + let(:imported_issue_events) do + imported_issue.label_events.map { |e| { name: "#{e[:action]}_label", label: e.dig(:label, :name) } } + end - it 'imports a GitHub repo', testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347877' do - Page::Project::Import::Github.perform do |import_page| - import_page.add_personal_access_token(Runtime::Env.github_access_token) - import_page.import!(github_repo, group.full_path, imported_project.name) + before do + group.add_member(user, Resource::Members::AccessLevel::MAINTAINER) - aggregate_failures do - expect(import_page).to have_imported_project(github_repo, wait: 240) - # validate button is present instead of navigating to avoid dealing with multiple tabs - # which makes the test more complicated - expect(import_page).to have_go_to_project_button(github_repo) + Flow::Login.sign_in(as: user) + Page::Main::Menu.perform(&:go_to_create_project) + Page::Project::New.perform do |project_page| + project_page.click_import_project + project_page.click_github_link end end - imported_project.reload!.visit! - Page::Project::Show.perform do |project| - aggregate_failures do - expect(project).to have_content(imported_project.name) - expect(project).to have_content('Project for github import test') + after do + user.remove_via_api! + end + + it 'imports a project', testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347877' do + Page::Project::Import::Github.perform do |import_page| + import_page.add_personal_access_token(Runtime::Env.github_access_token) + + import_page.select_advanced_option(:single_endpoint_issue_events_import) + import_page.select_advanced_option(:single_endpoint_notes_import) + import_page.select_advanced_option(:attachments_import) + + import_page.import!(github_repo, group.full_path, imported_project.name) + + aggregate_failures do + expect(import_page).to have_imported_project(github_repo, wait: 240) + # validate button is present instead of navigating to avoid dealing with multiple tabs + # which makes the test more complicated + expect(import_page).to have_go_to_project_button(github_repo) + end + end + + imported_project.reload!.visit! + Page::Project::Show.perform do |project| + aggregate_failures do + expect(project).to have_content(imported_project.name) + expect(project).to have_content('Project for github import test') + end end + + # Validate :single_endpoint_issue_events_import option was triggered correctly and imported the events + expect(imported_issue_events).to match_array( + [ + { name: "add_label", label: "question" }, + { name: "add_label", label: "good first issue" }, + { name: "add_label", label: "help wanted" } + ] + ) end end end diff --git a/qa/qa/specs/features/browser_ui/1_manage/project/project_access_token_spec.rb b/qa/qa/specs/features/browser_ui/1_manage/project/project_access_token_spec.rb index 63ae90aed9c..55f63845acd 100644 --- a/qa/qa/specs/features/browser_ui/1_manage/project/project_access_token_spec.rb +++ b/qa/qa/specs/features/browser_ui/1_manage/project/project_access_token_spec.rb @@ -2,7 +2,7 @@ module QA RSpec.describe 'Manage' do - describe 'Project access tokens', :reliable do + describe 'Project access tokens', :reliable, product_group: :authentication_and_authorization do let(:project_access_token) { QA::Resource::ProjectAccessToken.fabricate_via_browser_ui! } it( diff --git a/qa/qa/specs/features/browser_ui/1_manage/user/impersonation_token_spec.rb b/qa/qa/specs/features/browser_ui/1_manage/user/impersonation_token_spec.rb index 5bcea1ff094..ce5d9307769 100644 --- a/qa/qa/specs/features/browser_ui/1_manage/user/impersonation_token_spec.rb +++ b/qa/qa/specs/features/browser_ui/1_manage/user/impersonation_token_spec.rb @@ -2,7 +2,7 @@ module QA RSpec.describe 'Manage' do - describe 'Impersonation tokens', :requires_admin do + describe 'Impersonation tokens', :requires_admin, product_group: :authentication_and_authorization do let(:admin_api_client) { Runtime::API::Client.as_admin } let!(:user) do diff --git a/qa/qa/specs/features/browser_ui/1_manage/user/parent_group_access_termination_spec.rb b/qa/qa/specs/features/browser_ui/1_manage/user/parent_group_access_termination_spec.rb index 54f05f84dca..6bc695487ee 100644 --- a/qa/qa/specs/features/browser_ui/1_manage/user/parent_group_access_termination_spec.rb +++ b/qa/qa/specs/features/browser_ui/1_manage/user/parent_group_access_termination_spec.rb @@ -12,11 +12,9 @@ module QA end let!(:group) do - group = QA::Resource::Group.fabricate_via_api! do |group| + QA::Resource::Group.fabricate_via_api! do |group| group.path = "group-to-test-access-termination-#{SecureRandom.hex(8)}" end - group.sandbox.add_member(user) - group end let!(:project) do @@ -27,24 +25,20 @@ module QA end end - context 'for after parent group membership termination' do + context 'when parent group membership is terminated' do before do + group.add_member(user) + Flow::Login.while_signed_in_as_admin do - group.sandbox.visit! + group.visit! - Page::Group::Menu.perform(&:click_group_members_item) + Page::Group::Menu.perform(&:click_subgroup_members_item) Page::Group::Members.perform do |members_page| members_page.remove_member(user.username) end end end - after do - user.remove_via_api! - project.remove_via_api! - group.remove_via_api! - end - it 'is not allowed to edit the project files', testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347866' do Flow::Login.sign_in(as: user) diff --git a/qa/qa/specs/features/browser_ui/2_plan/email/trigger_email_notification_spec.rb b/qa/qa/specs/features/browser_ui/2_plan/email/trigger_email_notification_spec.rb index b815186cd49..b70590e65c8 100644 --- a/qa/qa/specs/features/browser_ui/2_plan/email/trigger_email_notification_spec.rb +++ b/qa/qa/specs/features/browser_ui/2_plan/email/trigger_email_notification_spec.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true module QA - RSpec.describe 'Plan', :orchestrated, :smtp, :reliable do + RSpec.describe 'Plan', :orchestrated, :smtp, :reliable, product_group: :project_management do describe 'Email Notification' do include Support::API diff --git a/qa/qa/specs/features/browser_ui/2_plan/issue/check_mentions_for_xss_spec.rb b/qa/qa/specs/features/browser_ui/2_plan/issue/check_mentions_for_xss_spec.rb index 1ba110a9602..2f177d12389 100644 --- a/qa/qa/specs/features/browser_ui/2_plan/issue/check_mentions_for_xss_spec.rb +++ b/qa/qa/specs/features/browser_ui/2_plan/issue/check_mentions_for_xss_spec.rb @@ -1,11 +1,11 @@ # frozen_string_literal: true module QA - RSpec.describe 'Plan', :reliable do + RSpec.describe 'Plan', :reliable, product_group: :project_management do let!(:user) do Resource::User.fabricate_via_api! do |user| user.name = "QA User <img src=x onerror=alert(2)<img src=x onerror=alert(1)>" - user.password = "test1234" + user.password = "pw_#{SecureRandom.hex(12)}" user.api_client = Runtime::API::Client.as_admin end end diff --git a/qa/qa/specs/features/browser_ui/2_plan/issue/collapse_comments_in_discussions_spec.rb b/qa/qa/specs/features/browser_ui/2_plan/issue/collapse_comments_in_discussions_spec.rb index 8e8112faa48..d446a773809 100644 --- a/qa/qa/specs/features/browser_ui/2_plan/issue/collapse_comments_in_discussions_spec.rb +++ b/qa/qa/specs/features/browser_ui/2_plan/issue/collapse_comments_in_discussions_spec.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true module QA - RSpec.describe 'Plan', :reliable do + RSpec.describe 'Plan', :reliable, product_group: :project_management do describe 'collapse comments in issue discussions' do let(:my_first_reply) { 'My first reply' } let(:one_reply) { '1 reply' } diff --git a/qa/qa/specs/features/browser_ui/2_plan/issue/comment_issue_spec.rb b/qa/qa/specs/features/browser_ui/2_plan/issue/comment_issue_spec.rb index 3b02093054d..f7dc9157275 100644 --- a/qa/qa/specs/features/browser_ui/2_plan/issue/comment_issue_spec.rb +++ b/qa/qa/specs/features/browser_ui/2_plan/issue/comment_issue_spec.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true module QA - RSpec.describe 'Plan', :reliable do + RSpec.describe 'Plan', :reliable, product_group: :project_management do describe 'Issue comments' do before do Flow::Login.sign_in diff --git a/qa/qa/specs/features/browser_ui/2_plan/issue/create_issue_spec.rb b/qa/qa/specs/features/browser_ui/2_plan/issue/create_issue_spec.rb index 7e4a391c390..45c3c264837 100644 --- a/qa/qa/specs/features/browser_ui/2_plan/issue/create_issue_spec.rb +++ b/qa/qa/specs/features/browser_ui/2_plan/issue/create_issue_spec.rb @@ -1,10 +1,19 @@ # frozen_string_literal: true module QA - RSpec.describe 'Plan', :smoke do + RSpec.describe 'Plan', :smoke, product_group: :project_management do describe 'Issue creation' do - let(:project) { Resource::Project.fabricate_via_api! } - let(:closed_issue) { Resource::Issue.fabricate_via_api! { |issue| issue.project = project } } + let(:project) do + Resource::Project.fabricate_via_api_unless_fips! do |project| + project.name = "project-create-issue-#{SecureRandom.hex(8)}" + project.personal_namespace = Runtime::User.username + project.description = nil + end + end + + let(:closed_issue) do + Resource::Issue.fabricate_via_api_unless_fips! { |issue| issue.project = project } + end before do Flow::Login.sign_in @@ -55,7 +64,7 @@ module QA end before do - Resource::Issue.fabricate_via_api! { |issue| issue.project = project }.visit! + Resource::Issue.fabricate_via_api_unless_fips! { |issue| issue.project = project }.visit! end # The following example is excluded from running in `review-qa-smoke` job diff --git a/qa/qa/specs/features/browser_ui/2_plan/issue/custom_issue_template_spec.rb b/qa/qa/specs/features/browser_ui/2_plan/issue/custom_issue_template_spec.rb index b2c612d38fe..bad312bb392 100644 --- a/qa/qa/specs/features/browser_ui/2_plan/issue/custom_issue_template_spec.rb +++ b/qa/qa/specs/features/browser_ui/2_plan/issue/custom_issue_template_spec.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true module QA - RSpec.describe 'Plan', :reliable do + RSpec.describe 'Plan', :reliable, product_group: :project_management do describe 'Custom issue templates' do let(:template_name) { 'custom_issue_template' } let(:template_content) { 'This is a custom issue template test' } diff --git a/qa/qa/specs/features/browser_ui/2_plan/issue/export_as_csv_spec.rb b/qa/qa/specs/features/browser_ui/2_plan/issue/export_as_csv_spec.rb index e8c624e9554..61fd743f920 100644 --- a/qa/qa/specs/features/browser_ui/2_plan/issue/export_as_csv_spec.rb +++ b/qa/qa/specs/features/browser_ui/2_plan/issue/export_as_csv_spec.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true module QA - RSpec.describe 'Plan', :reliable do + RSpec.describe 'Plan', :reliable, product_group: :project_management do describe 'Issues list' do let(:project) do Resource::Project.fabricate_via_api! do |project| diff --git a/qa/qa/specs/features/browser_ui/2_plan/issue/filter_issue_comments_spec.rb b/qa/qa/specs/features/browser_ui/2_plan/issue/filter_issue_comments_spec.rb index d8fa7480f01..8af39cb6a82 100644 --- a/qa/qa/specs/features/browser_ui/2_plan/issue/filter_issue_comments_spec.rb +++ b/qa/qa/specs/features/browser_ui/2_plan/issue/filter_issue_comments_spec.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true module QA - RSpec.describe 'Plan', :reliable do + RSpec.describe 'Plan', :reliable, product_group: :project_management do describe 'filter issue comments activities' do before do Flow::Login.sign_in diff --git a/qa/qa/specs/features/browser_ui/2_plan/issue/issue_suggestions_spec.rb b/qa/qa/specs/features/browser_ui/2_plan/issue/issue_suggestions_spec.rb index 6bb338ae31f..45541939606 100644 --- a/qa/qa/specs/features/browser_ui/2_plan/issue/issue_suggestions_spec.rb +++ b/qa/qa/specs/features/browser_ui/2_plan/issue/issue_suggestions_spec.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true module QA - RSpec.describe 'Plan', :reliable do + RSpec.describe 'Plan', :reliable, product_group: :project_management do describe 'issue suggestions' do let(:issue_title) { 'Issue Lists are awesome' } diff --git a/qa/qa/specs/features/browser_ui/2_plan/issue/mentions_spec.rb b/qa/qa/specs/features/browser_ui/2_plan/issue/mentions_spec.rb index 96f5731ea65..36cfb9dfb6e 100644 --- a/qa/qa/specs/features/browser_ui/2_plan/issue/mentions_spec.rb +++ b/qa/qa/specs/features/browser_ui/2_plan/issue/mentions_spec.rb @@ -1,11 +1,14 @@ # frozen_string_literal: true module QA - RSpec.describe 'Plan', :smoke do + RSpec.describe 'Plan', :smoke, product_group: :project_management do describe 'mention' do - let(:user) { Resource::User.fabricate_or_use(Runtime::Env.gitlab_qa_username_1, Runtime::Env.gitlab_qa_password_1) } + let(:user) do + Resource::User.fabricate_or_use(Runtime::Env.gitlab_qa_username_1, Runtime::Env.gitlab_qa_password_1) + end + let(:project) do - Resource::Project.fabricate_via_api! do |project| + Resource::Project.fabricate_via_api_unless_fips! do |project| project.name = 'project-to-test-mention' project.visibility = 'private' end @@ -14,14 +17,33 @@ module QA before do Flow::Login.sign_in - project.add_member(user) + if QA::Support::FIPS.enabled? + # Ensure user exists + user + Flow::Login.sign_in_as_admin + project.visit! + Page::Project::Menu.perform(&:click_members) + Page::Project::Members.perform do |members| + members.add_member(user.username) + end + else + project.visit! + project.add_member(user) + end - Resource::Issue.fabricate_via_api! do |issue| - issue.project = project - end.visit! + if QA::Support::FIPS.enabled? + Resource::Issue.fabricate_via_browser_ui! do |issue| + issue.project = project + end.visit! + else + Resource::Issue.fabricate_via_api! do |issue| + issue.project = project + end.visit! + end end - it 'mentions another user in an issue', testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347988' do + it 'mentions another user in an issue', +testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347988' do Page::Project::Issue::Show.perform do |show| at_username = "@#{user.username}" diff --git a/qa/qa/specs/features/browser_ui/2_plan/issue/real_time_assignee_spec.rb b/qa/qa/specs/features/browser_ui/2_plan/issue/real_time_assignee_spec.rb index 66e2309e173..060e52276a9 100644 --- a/qa/qa/specs/features/browser_ui/2_plan/issue/real_time_assignee_spec.rb +++ b/qa/qa/specs/features/browser_ui/2_plan/issue/real_time_assignee_spec.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true module QA - RSpec.describe 'Plan' do + RSpec.describe 'Plan', product_group: :project_management do describe 'Assignees' do let(:user1) { Resource::User.fabricate_or_use(Runtime::Env.gitlab_qa_username_1, Runtime::Env.gitlab_qa_password_1) } let(:user2) { Resource::User.fabricate_or_use(Runtime::Env.gitlab_qa_username_2, Runtime::Env.gitlab_qa_password_2) } diff --git a/qa/qa/specs/features/browser_ui/2_plan/issue_boards/focus_mode_spec.rb b/qa/qa/specs/features/browser_ui/2_plan/issue_boards/focus_mode_spec.rb index f116c690eec..83e178ae4c3 100644 --- a/qa/qa/specs/features/browser_ui/2_plan/issue_boards/focus_mode_spec.rb +++ b/qa/qa/specs/features/browser_ui/2_plan/issue_boards/focus_mode_spec.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true module QA - RSpec.describe 'Plan', :reliable do + RSpec.describe 'Plan', :reliable, product_group: :project_management do describe 'Issue board focus mode' do let(:project) do QA::Resource::Project.fabricate_via_api! do |project| diff --git a/qa/qa/specs/features/browser_ui/2_plan/milestone/assign_milestone_spec.rb b/qa/qa/specs/features/browser_ui/2_plan/milestone/assign_milestone_spec.rb index d6eab3c8dd0..56e110e6f61 100644 --- a/qa/qa/specs/features/browser_ui/2_plan/milestone/assign_milestone_spec.rb +++ b/qa/qa/specs/features/browser_ui/2_plan/milestone/assign_milestone_spec.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true module QA - RSpec.describe 'Plan', :reliable do + RSpec.describe 'Plan', :reliable, product_group: :project_management do describe 'Milestones' do include Support::Dates diff --git a/qa/qa/specs/features/browser_ui/2_plan/milestone/create_group_milestone_spec.rb b/qa/qa/specs/features/browser_ui/2_plan/milestone/create_group_milestone_spec.rb index 22709e8fbc4..5febb6579df 100644 --- a/qa/qa/specs/features/browser_ui/2_plan/milestone/create_group_milestone_spec.rb +++ b/qa/qa/specs/features/browser_ui/2_plan/milestone/create_group_milestone_spec.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true module QA - RSpec.describe 'Plan', :reliable do + RSpec.describe 'Plan', :reliable, product_group: :project_management do describe 'Group milestone' do include Support::Dates diff --git a/qa/qa/specs/features/browser_ui/2_plan/milestone/create_project_milestone_spec.rb b/qa/qa/specs/features/browser_ui/2_plan/milestone/create_project_milestone_spec.rb index 8047f8aea4c..5b580a67f5b 100644 --- a/qa/qa/specs/features/browser_ui/2_plan/milestone/create_project_milestone_spec.rb +++ b/qa/qa/specs/features/browser_ui/2_plan/milestone/create_project_milestone_spec.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true module QA - RSpec.describe 'Plan', :reliable do + RSpec.describe 'Plan', :reliable, product_group: :project_management do describe 'Project milestone' do include Support::Dates diff --git a/qa/qa/specs/features/browser_ui/2_plan/related_issues/related_issues_spec.rb b/qa/qa/specs/features/browser_ui/2_plan/related_issues/related_issues_spec.rb index 85011415177..197e283c93b 100644 --- a/qa/qa/specs/features/browser_ui/2_plan/related_issues/related_issues_spec.rb +++ b/qa/qa/specs/features/browser_ui/2_plan/related_issues/related_issues_spec.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true module QA - RSpec.describe 'Plan', :reliable do + RSpec.describe 'Plan', :reliable, product_group: :project_management do describe 'Related issues' do let(:project) do Resource::Project.fabricate_via_api! do |project| diff --git a/qa/qa/specs/features/browser_ui/2_plan/transient/comment_on_discussion_spec.rb b/qa/qa/specs/features/browser_ui/2_plan/transient/comment_on_discussion_spec.rb index a3fe1d655aa..878c4dea26e 100644 --- a/qa/qa/specs/features/browser_ui/2_plan/transient/comment_on_discussion_spec.rb +++ b/qa/qa/specs/features/browser_ui/2_plan/transient/comment_on_discussion_spec.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true module QA - RSpec.describe 'Plan', :transient do + RSpec.describe 'Plan', :transient, product_group: :project_management do describe 'Discussion comments transient bugs' do let(:user1) do Resource::User.fabricate_or_use(Runtime::Env.gitlab_qa_username_1, Runtime::Env.gitlab_qa_password_1) diff --git a/qa/qa/specs/features/browser_ui/3_create/merge_request/cherry_pick/cherry_pick_a_merge_spec.rb b/qa/qa/specs/features/browser_ui/3_create/merge_request/cherry_pick/cherry_pick_a_merge_spec.rb index 413c530116c..8f99644bd24 100644 --- a/qa/qa/specs/features/browser_ui/3_create/merge_request/cherry_pick/cherry_pick_a_merge_spec.rb +++ b/qa/qa/specs/features/browser_ui/3_create/merge_request/cherry_pick/cherry_pick_a_merge_spec.rb @@ -2,7 +2,7 @@ module QA RSpec.describe 'Create' do - describe 'Cherry picking from a merge request' do + describe 'Cherry picking from a merge request', product_group: :code_review do let(:project) do Resource::Project.fabricate_via_api! do |project| project.name = 'project' diff --git a/qa/qa/specs/features/browser_ui/3_create/merge_request/cherry_pick/cherry_pick_commit_spec.rb b/qa/qa/specs/features/browser_ui/3_create/merge_request/cherry_pick/cherry_pick_commit_spec.rb index d6e9c1a13df..111adf32a69 100644 --- a/qa/qa/specs/features/browser_ui/3_create/merge_request/cherry_pick/cherry_pick_commit_spec.rb +++ b/qa/qa/specs/features/browser_ui/3_create/merge_request/cherry_pick/cherry_pick_commit_spec.rb @@ -2,7 +2,7 @@ module QA RSpec.describe 'Create' do - describe 'Cherry picking a commit' do + describe 'Cherry picking a commit', product_group: :code_review do let(:file_name) { "secret_file.md" } let(:project) do diff --git a/qa/qa/specs/features/browser_ui/3_create/merge_request/create_merge_request_from_push_notification_spec.rb b/qa/qa/specs/features/browser_ui/3_create/merge_request/create_merge_request_from_push_notification_spec.rb index 10d7e0b071f..509714fb5a4 100644 --- a/qa/qa/specs/features/browser_ui/3_create/merge_request/create_merge_request_from_push_notification_spec.rb +++ b/qa/qa/specs/features/browser_ui/3_create/merge_request/create_merge_request_from_push_notification_spec.rb @@ -2,7 +2,7 @@ module QA RSpec.describe 'Create' do - describe 'Create a new merge request from the event notification after a push' do + describe 'Create a new merge request from the event notification after a push', product_group: :code_review do let(:branch_name) { "merge-request-test-#{SecureRandom.hex(8)}" } let(:title) { "Merge from push event notification test #{SecureRandom.hex(8)}" } let(:project) do diff --git a/qa/qa/specs/features/browser_ui/3_create/merge_request/create_merge_request_spec.rb b/qa/qa/specs/features/browser_ui/3_create/merge_request/create_merge_request_spec.rb index 25dec82b74c..1e08fc49066 100644 --- a/qa/qa/specs/features/browser_ui/3_create/merge_request/create_merge_request_spec.rb +++ b/qa/qa/specs/features/browser_ui/3_create/merge_request/create_merge_request_spec.rb @@ -2,7 +2,7 @@ module QA RSpec.describe 'Create' do - describe 'Create a new merge request' do + describe 'Create a new merge request', product_group: :code_review do let(:project) do Resource::Project.fabricate_via_api! do |project| project.name = 'project' @@ -18,7 +18,7 @@ module QA it( 'creates a basic merge request', - :smoke, + :smoke, :skip_fips_env, testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347738' ) do Resource::MergeRequest.fabricate_via_browser_ui! do |merge_request| diff --git a/qa/qa/specs/features/browser_ui/3_create/merge_request/create_merge_request_via_template_spec.rb b/qa/qa/specs/features/browser_ui/3_create/merge_request/create_merge_request_via_template_spec.rb index d975e18e962..1ce9430290f 100644 --- a/qa/qa/specs/features/browser_ui/3_create/merge_request/create_merge_request_via_template_spec.rb +++ b/qa/qa/specs/features/browser_ui/3_create/merge_request/create_merge_request_via_template_spec.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true module QA - RSpec.describe 'Create', :reliable do + RSpec.describe 'Create', :reliable, product_group: :code_review do describe 'Merge request custom templates' do let(:template_name) { 'custom_merge_request_template' } let(:template_content) { 'This is a custom merge request template test' } diff --git a/qa/qa/specs/features/browser_ui/3_create/merge_request/merge_merge_request_from_fork_spec.rb b/qa/qa/specs/features/browser_ui/3_create/merge_request/merge_merge_request_from_fork_spec.rb index 109cf7b73c3..d27ec32fdda 100644 --- a/qa/qa/specs/features/browser_ui/3_create/merge_request/merge_merge_request_from_fork_spec.rb +++ b/qa/qa/specs/features/browser_ui/3_create/merge_request/merge_merge_request_from_fork_spec.rb @@ -2,7 +2,7 @@ module QA RSpec.describe 'Create' do - describe 'Merge request creation from fork' do + describe 'Merge request creation from fork', product_group: :code_review do let(:merge_request) do Resource::MergeRequestFromFork.fabricate_via_browser_ui! do |merge_request| merge_request.fork_branch = 'feature-branch' diff --git a/qa/qa/specs/features/browser_ui/3_create/merge_request/merge_when_pipeline_succeeds_spec.rb b/qa/qa/specs/features/browser_ui/3_create/merge_request/merge_when_pipeline_succeeds_spec.rb index ac53357a86f..257021b158a 100644 --- a/qa/qa/specs/features/browser_ui/3_create/merge_request/merge_when_pipeline_succeeds_spec.rb +++ b/qa/qa/specs/features/browser_ui/3_create/merge_request/merge_when_pipeline_succeeds_spec.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true module QA - RSpec.describe 'Create', :runner do + RSpec.describe 'Create', :runner, product_group: :code_review do describe 'Merge requests' do shared_examples 'merge when pipeline succeeds' do |repeat: 1| let(:runner_name) { "qa-runner-#{Faker::Alphanumeric.alphanumeric(number: 8)}" } 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 c7296b6eea2..330cae575e4 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 @@ -2,7 +2,7 @@ module QA RSpec.describe 'Create' do - describe 'Merge request rebasing' do + describe 'Merge request rebasing', product_group: :code_review do let(:merge_request) { Resource::MergeRequest.fabricate_via_api! } before do diff --git a/qa/qa/specs/features/browser_ui/3_create/merge_request/revert/revert_commit_spec.rb b/qa/qa/specs/features/browser_ui/3_create/merge_request/revert/revert_commit_spec.rb index 205ff12ff03..a79c56bd051 100644 --- a/qa/qa/specs/features/browser_ui/3_create/merge_request/revert/revert_commit_spec.rb +++ b/qa/qa/specs/features/browser_ui/3_create/merge_request/revert/revert_commit_spec.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true module QA - RSpec.describe 'Create', :reliable do + RSpec.describe 'Create', :reliable, product_group: :code_review do describe 'Reverting a commit' do let(:file_name) { "secret_file.md" } diff --git a/qa/qa/specs/features/browser_ui/3_create/merge_request/revert/reverting_merge_request_spec.rb b/qa/qa/specs/features/browser_ui/3_create/merge_request/revert/reverting_merge_request_spec.rb index 948aedf5aae..82e2136cd22 100644 --- a/qa/qa/specs/features/browser_ui/3_create/merge_request/revert/reverting_merge_request_spec.rb +++ b/qa/qa/specs/features/browser_ui/3_create/merge_request/revert/reverting_merge_request_spec.rb @@ -2,7 +2,7 @@ module QA RSpec.describe 'Create' do - describe 'Merged merge request' do + describe 'Merged merge request', product_group: :code_review do let(:project) do Resource::Project.fabricate_via_api! do |project| project.name = 'revert' diff --git a/qa/qa/specs/features/browser_ui/3_create/merge_request/squash_merge_request_spec.rb b/qa/qa/specs/features/browser_ui/3_create/merge_request/squash_merge_request_spec.rb index fa129f39a4c..a127b846eb9 100644 --- a/qa/qa/specs/features/browser_ui/3_create/merge_request/squash_merge_request_spec.rb +++ b/qa/qa/specs/features/browser_ui/3_create/merge_request/squash_merge_request_spec.rb @@ -2,7 +2,7 @@ module QA RSpec.describe 'Create' do - describe 'Merge request squashing' do + describe 'Merge request squashing', product_group: :code_review do let(:project) do Resource::Project.fabricate_via_api! do |project| project.name = "squash-before-merge" diff --git a/qa/qa/specs/features/browser_ui/3_create/merge_request/suggestions/batch_suggestion_spec.rb b/qa/qa/specs/features/browser_ui/3_create/merge_request/suggestions/batch_suggestion_spec.rb index b20d0929e9c..829b7bab829 100644 --- a/qa/qa/specs/features/browser_ui/3_create/merge_request/suggestions/batch_suggestion_spec.rb +++ b/qa/qa/specs/features/browser_ui/3_create/merge_request/suggestions/batch_suggestion_spec.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true module QA - RSpec.describe 'Create', :reliable do + RSpec.describe 'Create', :reliable, product_group: :code_review do context 'Add batch suggestions to a Merge Request' do let(:project) do Resource::Project.fabricate_via_api! do |project| diff --git a/qa/qa/specs/features/browser_ui/3_create/merge_request/suggestions/custom_commit_suggestion_spec.rb b/qa/qa/specs/features/browser_ui/3_create/merge_request/suggestions/custom_commit_suggestion_spec.rb index aa637ac4d55..433ef90d9aa 100644 --- a/qa/qa/specs/features/browser_ui/3_create/merge_request/suggestions/custom_commit_suggestion_spec.rb +++ b/qa/qa/specs/features/browser_ui/3_create/merge_request/suggestions/custom_commit_suggestion_spec.rb @@ -2,7 +2,7 @@ module QA RSpec.describe 'Create' do - context 'Add suggestions to a Merge Request' do + context 'Add suggestions to a Merge Request', product_group: :code_review do let(:commit_message) { 'Applying suggested change for testing purposes.' } let(:project) do diff --git a/qa/qa/specs/features/browser_ui/3_create/merge_request/view_merge_request_diff_patch_spec.rb b/qa/qa/specs/features/browser_ui/3_create/merge_request/view_merge_request_diff_patch_spec.rb index 18aa6bfe78a..a969b48f0fc 100644 --- a/qa/qa/specs/features/browser_ui/3_create/merge_request/view_merge_request_diff_patch_spec.rb +++ b/qa/qa/specs/features/browser_ui/3_create/merge_request/view_merge_request_diff_patch_spec.rb @@ -2,7 +2,7 @@ module QA RSpec.describe 'Create' do - describe 'Download merge request patch and diff' do + describe 'Download merge request patch and diff', product_group: :code_review do let(:merge_request) do Resource::MergeRequest.fabricate_via_api! do |merge_request| merge_request.title = 'This is a merge request' diff --git a/qa/qa/specs/features/browser_ui/3_create/pages/new_static_page_spec.rb b/qa/qa/specs/features/browser_ui/3_create/pages/new_static_page_spec.rb index 9c912080c5f..c35aa403bfa 100644 --- a/qa/qa/specs/features/browser_ui/3_create/pages/new_static_page_spec.rb +++ b/qa/qa/specs/features/browser_ui/3_create/pages/new_static_page_spec.rb @@ -1,8 +1,9 @@ # frozen_string_literal: true + module QA - RSpec.describe 'Create', :runner, only: { subdomain: :staging } do + RSpec.describe 'Create', :gitlab_pages, :orchestrated, except: { job: 'review-qa-*', subdomain: :production } do # TODO: Convert back to :smoke once proved to be stable. Related issue: https://gitlab.com/gitlab-org/gitlab/-/issues/300906 - describe 'Pages' do + describe 'Pages', product_group: :editor do let!(:project) do Resource::Project.fabricate_via_api! do |project| project.name = 'jekyll-pages-project' @@ -21,7 +22,6 @@ module QA before do Flow::Login.sign_in - Resource::Runner.fabricate_via_api! do |runner| runner.project = project runner.executor = :docker 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 37e737a4f84..feb0f28763c 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 @@ -1,7 +1,7 @@ # frozen_string_literal: true module QA - RSpec.describe 'Create' do + RSpec.describe 'Create', product_group: :editor do describe 'Testing wiki content creation inside a project' do let(:new_wiki_title) { "just_another_wiki_page" } let(:new_wiki_content) { "this content is changed or added" } diff --git a/qa/qa/specs/features/browser_ui/3_create/project_wiki/project_based_content_manipulation_spec.rb b/qa/qa/specs/features/browser_ui/3_create/project_wiki/project_based_content_manipulation_spec.rb index a4bdb0193dd..dcac2ad3a9d 100644 --- a/qa/qa/specs/features/browser_ui/3_create/project_wiki/project_based_content_manipulation_spec.rb +++ b/qa/qa/specs/features/browser_ui/3_create/project_wiki/project_based_content_manipulation_spec.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true module QA - RSpec.describe 'Create' do + RSpec.describe 'Create', product_group: :editor do describe 'Testing wiki content manipulation inside a project' do let(:new_wiki_title) { "just_another_wiki_page" } let(:new_wiki_content) { "this content is changed or added" } diff --git a/qa/qa/specs/features/browser_ui/3_create/project_wiki/project_based_directory_management_spec.rb b/qa/qa/specs/features/browser_ui/3_create/project_wiki/project_based_directory_management_spec.rb index 0af964fc4bf..7edbb01a522 100644 --- a/qa/qa/specs/features/browser_ui/3_create/project_wiki/project_based_directory_management_spec.rb +++ b/qa/qa/specs/features/browser_ui/3_create/project_wiki/project_based_directory_management_spec.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true module QA - RSpec.describe 'Create' do + RSpec.describe 'Create', product_group: :editor do describe 'A project wiki' do let(:initial_wiki) { Resource::Wiki::ProjectPage.fabricate_via_api! } let(:new_path) { "a/new/path-with-spaces" } diff --git a/qa/qa/specs/features/browser_ui/3_create/project_wiki/project_based_file_upload_spec.rb b/qa/qa/specs/features/browser_ui/3_create/project_wiki/project_based_file_upload_spec.rb index 361fc459d54..fbe662341c0 100644 --- a/qa/qa/specs/features/browser_ui/3_create/project_wiki/project_based_file_upload_spec.rb +++ b/qa/qa/specs/features/browser_ui/3_create/project_wiki/project_based_file_upload_spec.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true module QA - RSpec.describe 'Create', :reliable do + RSpec.describe 'Create', :reliable, product_group: :editor do describe 'Testing project wiki file upload' do let(:initial_wiki) { Resource::Wiki::ProjectPage.fabricate_via_api! } let(:page_title) { 'Content Editor Page' } diff --git a/qa/qa/specs/features/browser_ui/3_create/project_wiki/project_based_list_spec.rb b/qa/qa/specs/features/browser_ui/3_create/project_wiki/project_based_list_spec.rb index 5c9b97659a7..e0699bccff6 100644 --- a/qa/qa/specs/features/browser_ui/3_create/project_wiki/project_based_list_spec.rb +++ b/qa/qa/specs/features/browser_ui/3_create/project_wiki/project_based_list_spec.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true module QA - RSpec.describe 'Create' do + RSpec.describe 'Create', product_group: :editor do describe 'Project Wiki' do let(:small_number_of_pages) { 5 } let(:large_number_of_pages) { 15 } diff --git a/qa/qa/specs/features/browser_ui/3_create/project_wiki/project_based_page_deletion_spec.rb b/qa/qa/specs/features/browser_ui/3_create/project_wiki/project_based_page_deletion_spec.rb index 13e04180ab5..626f9a7d593 100644 --- a/qa/qa/specs/features/browser_ui/3_create/project_wiki/project_based_page_deletion_spec.rb +++ b/qa/qa/specs/features/browser_ui/3_create/project_wiki/project_based_page_deletion_spec.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true module QA - RSpec.describe 'Create' do + RSpec.describe 'Create', product_group: :editor do describe 'Testing project wiki' let(:initial_wiki) { Resource::Wiki::ProjectPage.fabricate_via_api! } diff --git a/qa/qa/specs/features/browser_ui/3_create/repository/add_list_delete_branches_spec.rb b/qa/qa/specs/features/browser_ui/3_create/repository/add_list_delete_branches_spec.rb index 849022f5a93..866c6a146de 100644 --- a/qa/qa/specs/features/browser_ui/3_create/repository/add_list_delete_branches_spec.rb +++ b/qa/qa/specs/features/browser_ui/3_create/repository/add_list_delete_branches_spec.rb @@ -76,7 +76,7 @@ module QA expect(branches_page).to have_no_branch(third_branch) - branches_page.delete_merged_branches + branches_page.delete_merged_branches('delete') expect(branches_page).to have_content( 'Merged branches are being deleted. This can take some time depending on the number of branches. Please refresh the page to see changes.' diff --git a/qa/qa/specs/features/browser_ui/3_create/repository/push_http_private_token_spec.rb b/qa/qa/specs/features/browser_ui/3_create/repository/push_http_private_token_spec.rb index a785e4ae764..0ec231ed66e 100644 --- a/qa/qa/specs/features/browser_ui/3_create/repository/push_http_private_token_spec.rb +++ b/qa/qa/specs/features/browser_ui/3_create/repository/push_http_private_token_spec.rb @@ -2,8 +2,9 @@ module QA RSpec.describe 'Create' do - describe 'Git push over HTTP', :smoke, product_group: :source_code do - it 'user using a personal access token pushes code to the repository', testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347749' do + describe 'Git push over HTTP', :smoke, :skip_fips_env, product_group: :source_code do + it 'user using a personal access token pushes code to the repository', +testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347749' do Flow::Login.sign_in access_token = Resource::PersonalAccessToken.fabricate!.token diff --git a/qa/qa/specs/features/browser_ui/3_create/repository/push_over_http_spec.rb b/qa/qa/specs/features/browser_ui/3_create/repository/push_over_http_spec.rb index e8f7cb252a0..efa1f9fe2c9 100644 --- a/qa/qa/specs/features/browser_ui/3_create/repository/push_over_http_spec.rb +++ b/qa/qa/specs/features/browser_ui/3_create/repository/push_over_http_spec.rb @@ -3,7 +3,8 @@ module QA RSpec.describe 'Create' do describe 'Git push over HTTP', product_group: :source_code do - it 'user pushes code to the repository', :smoke, testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347747' do + it 'user pushes code to the repository', :smoke, :skip_fips_env, + testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347747' do Flow::Login.sign_in Resource::Repository::ProjectPush.fabricate! do |push| @@ -18,7 +19,8 @@ module QA end end - it 'pushes to a project using a specific Praefect repository storage', :smoke, :requires_admin, :requires_praefect, testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347789' do + it 'pushes to a project using a specific Praefect repository storage', :smoke, :skip_fips_env, :requires_admin, + :requires_praefect, testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347789' do Flow::Login.sign_in_as_admin project = Resource::Project.fabricate_via_api! do |storage_project| diff --git a/qa/qa/specs/features/browser_ui/3_create/repository/push_over_ssh_spec.rb b/qa/qa/specs/features/browser_ui/3_create/repository/push_over_ssh_spec.rb index 4fb52f1e54d..f281f441e8a 100644 --- a/qa/qa/specs/features/browser_ui/3_create/repository/push_over_ssh_spec.rb +++ b/qa/qa/specs/features/browser_ui/3_create/repository/push_over_ssh_spec.rb @@ -26,7 +26,8 @@ module QA Flow::Login.sign_in end - it 'pushes code to the repository via SSH', :smoke, testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347825' do + it 'pushes code to the repository via SSH', :smoke, :skip_fips_env, + testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347825' do Resource::Repository::ProjectPush.fabricate! do |push| push.project = project push.ssh_key = @key @@ -41,7 +42,8 @@ module QA end end - it 'pushes multiple branches and tags together', :smoke, testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347826' do + it 'pushes multiple branches and tags together', :smoke, :skip_fips_env, + testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347826' do branches = [] tags = [] Git::Repository.perform do |repository| diff --git a/qa/qa/specs/features/browser_ui/3_create/snippet/add_comment_to_snippet_spec.rb b/qa/qa/specs/features/browser_ui/3_create/snippet/add_comment_to_snippet_spec.rb index 1a7c64a363f..db180b729c8 100644 --- a/qa/qa/specs/features/browser_ui/3_create/snippet/add_comment_to_snippet_spec.rb +++ b/qa/qa/specs/features/browser_ui/3_create/snippet/add_comment_to_snippet_spec.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true module QA - RSpec.describe 'Create' do + RSpec.describe 'Create', product_group: :editor do describe 'Adding comments on snippets' do let(:comment_author) { Resource::User.fabricate_or_use(Runtime::Env.gitlab_qa_username_1, Runtime::Env.gitlab_qa_password_1) } let(:comment_content) { 'Comment 123' } @@ -23,11 +23,6 @@ module QA Flow::Login.sign_in end - after do - personal_snippet&.remove_via_api! - project_snippet&.remove_via_api! - end - shared_examples 'comments on snippets' do |snippet_type, testcase| it "adds, edits, and deletes a comment on a #{snippet_type}", testcase: testcase do send(snippet_type) diff --git a/qa/qa/specs/features/browser_ui/3_create/snippet/add_file_to_snippet_spec.rb b/qa/qa/specs/features/browser_ui/3_create/snippet/add_file_to_snippet_spec.rb index 8f05446ff70..20a4866baee 100644 --- a/qa/qa/specs/features/browser_ui/3_create/snippet/add_file_to_snippet_spec.rb +++ b/qa/qa/specs/features/browser_ui/3_create/snippet/add_file_to_snippet_spec.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true module QA - RSpec.describe 'Create' do + RSpec.describe 'Create', product_group: :editor do describe 'Multiple file snippet' do let(:personal_snippet) do Resource::Snippet.fabricate_via_api! do |snippet| @@ -23,11 +23,6 @@ module QA Flow::Login.sign_in end - after do - personal_snippet&.remove_via_api! - project_snippet&.remove_via_api! - end - shared_examples 'adding file to snippet' do |snippet_type, testcase| it "adds second file to an existing #{snippet_type} to make it multi-file", testcase: testcase do send(snippet_type).visit! diff --git a/qa/qa/specs/features/browser_ui/3_create/snippet/clone_push_pull_personal_snippet_spec.rb b/qa/qa/specs/features/browser_ui/3_create/snippet/clone_push_pull_personal_snippet_spec.rb index 8f22a28628f..833d3bd6126 100644 --- a/qa/qa/specs/features/browser_ui/3_create/snippet/clone_push_pull_personal_snippet_spec.rb +++ b/qa/qa/specs/features/browser_ui/3_create/snippet/clone_push_pull_personal_snippet_spec.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true module QA - RSpec.describe 'Create' do + RSpec.describe 'Create', product_group: :editor do describe 'Version control for personal snippets' do let(:new_file) { 'new_snippet_file' } let(:changed_content) { 'changes' } diff --git a/qa/qa/specs/features/browser_ui/3_create/snippet/clone_push_pull_project_snippet_spec.rb b/qa/qa/specs/features/browser_ui/3_create/snippet/clone_push_pull_project_snippet_spec.rb index 9a5fe44c927..a6bdac8c205 100644 --- a/qa/qa/specs/features/browser_ui/3_create/snippet/clone_push_pull_project_snippet_spec.rb +++ b/qa/qa/specs/features/browser_ui/3_create/snippet/clone_push_pull_project_snippet_spec.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true module QA - RSpec.describe 'Create' do + RSpec.describe 'Create', product_group: :editor do describe 'Version control for project snippets' do let(:new_file) { 'new_snippet_file' } let(:changed_content) { 'changes' } diff --git a/qa/qa/specs/features/browser_ui/3_create/snippet/copy_snippet_file_contents_spec.rb b/qa/qa/specs/features/browser_ui/3_create/snippet/copy_snippet_file_contents_spec.rb index e4204776c46..1a614e538ea 100644 --- a/qa/qa/specs/features/browser_ui/3_create/snippet/copy_snippet_file_contents_spec.rb +++ b/qa/qa/specs/features/browser_ui/3_create/snippet/copy_snippet_file_contents_spec.rb @@ -1,7 +1,11 @@ # frozen_string_literal: true module QA - RSpec.describe 'Create', :reliable do + RSpec.describe 'Create', :reliable, product_group: :editor, quarantine: { + only: { subdomain: 'pre' }, + type: :investigating, + issue: 'https://gitlab.com/gitlab-org/gitlab/-/issues/378697' + } do describe 'Multiple file snippet' do let(:first_file_content) { 'First file content' } let(:second_file_content) { 'Second file content' } @@ -54,11 +58,6 @@ module QA Flow::Login.sign_in end - after do - personal_snippet&.remove_via_api! - project_snippet&.remove_via_api! - end - shared_examples 'copying snippet file contents' do |snippet_type, testcase| it "copies file contents of a multi-file #{snippet_type} to a comment and verifies them", testcase: testcase do send(snippet_type).visit! diff --git a/qa/qa/specs/features/browser_ui/3_create/snippet/create_personal_snippet_spec.rb b/qa/qa/specs/features/browser_ui/3_create/snippet/create_personal_snippet_spec.rb index 620e6870b26..0e5fcea438d 100644 --- a/qa/qa/specs/features/browser_ui/3_create/snippet/create_personal_snippet_spec.rb +++ b/qa/qa/specs/features/browser_ui/3_create/snippet/create_personal_snippet_spec.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true module QA - RSpec.describe 'Create', :smoke do + RSpec.describe 'Create', :smoke, product_group: :editor do describe 'Personal snippet creation' do let(:snippet) do Resource::Snippet.fabricate_via_browser_ui! do |snippet| @@ -18,7 +18,12 @@ module QA end after do - snippet.remove_via_api! + if QA::Support::FIPS.enabled? + snippet.visit! + Page::Dashboard::Snippet::Show.perform(&:click_delete_button) + else + snippet.remove_via_api! + end end it 'user creates a personal snippet', testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347799' do diff --git a/qa/qa/specs/features/browser_ui/3_create/snippet/create_personal_snippet_with_multiple_files_spec.rb b/qa/qa/specs/features/browser_ui/3_create/snippet/create_personal_snippet_with_multiple_files_spec.rb index 0560a5b125c..66376769419 100644 --- a/qa/qa/specs/features/browser_ui/3_create/snippet/create_personal_snippet_with_multiple_files_spec.rb +++ b/qa/qa/specs/features/browser_ui/3_create/snippet/create_personal_snippet_with_multiple_files_spec.rb @@ -2,7 +2,7 @@ module QA RSpec.describe 'Create' do - describe 'Multiple file snippet', :reliable do + describe 'Multiple file snippet', :reliable, product_group: :editor do let(:snippet) do Resource::Snippet.fabricate_via_browser_ui! do |snippet| snippet.title = 'Personal snippet with multiple files' @@ -22,10 +22,6 @@ module QA Flow::Login.sign_in end - after do - snippet.remove_via_api! - end - it 'creates a personal snippet with multiple files', testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347723' do snippet diff --git a/qa/qa/specs/features/browser_ui/3_create/snippet/create_project_snippet_spec.rb b/qa/qa/specs/features/browser_ui/3_create/snippet/create_project_snippet_spec.rb index 0f01a965e7b..0e10a9908f4 100644 --- a/qa/qa/specs/features/browser_ui/3_create/snippet/create_project_snippet_spec.rb +++ b/qa/qa/specs/features/browser_ui/3_create/snippet/create_project_snippet_spec.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true module QA - RSpec.describe 'Create' do # to be converted to a smoke test once proved to be stable + RSpec.describe 'Create', product_group: :editor do # to be converted to a smoke test once proved to be stable describe 'Project snippet creation' do let(:snippet) do Resource::ProjectSnippet.fabricate_via_browser_ui! do |snippet| @@ -17,10 +17,6 @@ module QA Flow::Login.sign_in end - after do - snippet.remove_via_api! - end - it 'user creates a project snippet', testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347798' do snippet diff --git a/qa/qa/specs/features/browser_ui/3_create/snippet/create_project_snippet_with_multiple_files_spec.rb b/qa/qa/specs/features/browser_ui/3_create/snippet/create_project_snippet_with_multiple_files_spec.rb index 77b3c4df7e1..3c94107950c 100644 --- a/qa/qa/specs/features/browser_ui/3_create/snippet/create_project_snippet_with_multiple_files_spec.rb +++ b/qa/qa/specs/features/browser_ui/3_create/snippet/create_project_snippet_with_multiple_files_spec.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true module QA - RSpec.describe 'Create', :reliable do + RSpec.describe 'Create', :reliable, product_group: :editor do describe 'Multiple file snippet' do let(:snippet) do Resource::ProjectSnippet.fabricate_via_browser_ui! do |snippet| @@ -24,10 +24,6 @@ module QA Flow::Login.sign_in end - after do - snippet.remove_via_api! - end - it 'creates a project snippet with multiple files', testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347725' do snippet diff --git a/qa/qa/specs/features/browser_ui/3_create/snippet/delete_file_from_snippet_spec.rb b/qa/qa/specs/features/browser_ui/3_create/snippet/delete_file_from_snippet_spec.rb index e9339342386..906ac6e09b7 100644 --- a/qa/qa/specs/features/browser_ui/3_create/snippet/delete_file_from_snippet_spec.rb +++ b/qa/qa/specs/features/browser_ui/3_create/snippet/delete_file_from_snippet_spec.rb @@ -2,7 +2,7 @@ module QA RSpec.describe 'Create' do - describe 'Multiple file snippet', :reliable do + describe 'Multiple file snippet', :reliable, product_group: :editor do let(:personal_snippet) do Resource::Snippet.fabricate_via_api! do |snippet| snippet.title = 'Personal snippet to delete file from' @@ -31,11 +31,6 @@ module QA Flow::Login.sign_in end - after do - personal_snippet&.remove_via_api! - project_snippet&.remove_via_api! - end - shared_examples 'deleting file from snippet' do |snippet_type, testcase| it "deletes second file from an existing #{snippet_type} to make it single-file", testcase: testcase do send(snippet_type).visit! diff --git a/qa/qa/specs/features/browser_ui/3_create/snippet/share_snippet_spec.rb b/qa/qa/specs/features/browser_ui/3_create/snippet/share_snippet_spec.rb index 182a21a9377..b58b487531e 100644 --- a/qa/qa/specs/features/browser_ui/3_create/snippet/share_snippet_spec.rb +++ b/qa/qa/specs/features/browser_ui/3_create/snippet/share_snippet_spec.rb @@ -2,7 +2,7 @@ module QA RSpec.describe 'Create' do - describe 'Sharing snippets', :reliable do + describe 'Sharing snippets', :reliable, product_group: :editor do let(:snippet) do Resource::Snippet.fabricate! do |snippet| snippet.title = 'Shared snippet' @@ -16,10 +16,6 @@ module QA Flow::Login.sign_in end - after do - snippet&.remove_via_api! - end - context 'when the snippet is public' do it 'can be shared with not signed-in users', testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347836' do snippet.visit! 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 97e42edfd01..63e9fdbb881 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 @@ -1,7 +1,7 @@ # frozen_string_literal: true module QA - RSpec.describe 'Create' do + RSpec.describe 'Create', product_group: :editor do describe 'Snippet index page' do let(:personal_snippet_with_single_file) do Resource::Snippet.fabricate_via_api! do |snippet| @@ -49,13 +49,6 @@ module QA Flow::Login.sign_in end - after do - personal_snippet_with_single_file.remove_via_api! - personal_snippet_with_multiple_files.remove_via_api! - project_snippet_with_single_file.remove_via_api! - project_snippet_with_multiple_files.remove_via_api! - end - 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) diff --git a/qa/qa/specs/features/browser_ui/3_create/source_editor/source_editor_toolbar_spec.rb b/qa/qa/specs/features/browser_ui/3_create/source_editor/source_editor_toolbar_spec.rb index f95f624d59a..b8617de2e47 100644 --- a/qa/qa/specs/features/browser_ui/3_create/source_editor/source_editor_toolbar_spec.rb +++ b/qa/qa/specs/features/browser_ui/3_create/source_editor/source_editor_toolbar_spec.rb @@ -2,7 +2,7 @@ # tagged transient due to feature-flag caching flakiness. Remove tag along with feature flag removal. module QA RSpec.describe 'Create', feature_flag: { name: 'source_editor_toolbar', scope: :global } do - describe 'Source editor toolbar preview' do + describe 'Source editor toolbar preview', product_group: :editor do let(:project) do Resource::Project.fabricate_via_api! do |project| project.name = 'empty-project-with-md' 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 19dd868744f..8ea65e17e13 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,7 +1,7 @@ # frozen_string_literal: true module QA - RSpec.describe 'Create' do + RSpec.describe 'Create', product_group: :editor do describe 'Web IDE file templates' do include Runtime::Fixtures 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 561a5a2cc1c..1da9ed652fe 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,7 +1,7 @@ # frozen_string_literal: true module QA - RSpec.describe 'Create' do + RSpec.describe 'Create', product_group: :editor do describe 'Add a directory in Web IDE' do let(:project) do Resource::Project.fabricate_via_api! do |project| 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 948417458fc..1dfda1608f4 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,7 +1,7 @@ # frozen_string_literal: true module QA - RSpec.describe 'Create' do + RSpec.describe 'Create', product_group: :editor do describe 'First file using Web IDE' do let(:project) do Resource::Project.fabricate_via_api! do |project| 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 9c1d327f02c..56cf2a08bd9 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,7 +1,7 @@ # frozen_string_literal: true module QA - RSpec.describe 'Create' do + RSpec.describe 'Create', 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 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 index 046327f780b..820b47a3175 100644 --- 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 @@ -1,7 +1,7 @@ # frozen_string_literal: true module QA - RSpec.describe 'Create' do + RSpec.describe 'Create', product_group: :editor do describe 'Open a fork in Web IDE', skip: { issue: "https://gitlab.com/gitlab-org/gitlab/-/issues/351696", 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 f03c651992c..685cd2d4ad6 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,7 +1,7 @@ # frozen_string_literal: true module QA - RSpec.describe 'Create' do + RSpec.describe 'Create', product_group: :editor do describe 'Open Web IDE from Diff Tab' do files = [ { 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 bd19d70ae5c..e4f29952f99 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,7 +1,7 @@ # frozen_string_literal: true module QA - RSpec.describe 'Create' do + RSpec.describe 'Create', product_group: :editor, quarantine: { issue: 'https://gitlab.com/gitlab-org/gitlab/-/issues/381530', type: :stale } do describe 'Review a merge request in Web IDE' do let(:new_file) { 'awesome_new_file.txt' } let(:original_text) { 'Text' } 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 ac2d374b0ed..0972e4f3e3d 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,7 +1,7 @@ # frozen_string_literal: true module QA - RSpec.describe 'Create', :skip_live_env, except: { job: 'review-qa-*' } do + RSpec.describe 'Create', :skip_live_env, except: { job: 'review-qa-*' }, product_group: :editor do describe 'Git Server Hooks' do let(:file_path) { File.absolute_path(File.join('qa', 'fixtures', 'web_ide', 'README.md')) } 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 3d9d5695d06..c0f65416a1c 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,7 +1,7 @@ # frozen_string_literal: true module QA - RSpec.describe 'Create' do + RSpec.describe 'Create', product_group: :editor do describe 'Upload a file in Web IDE' do let(:file_path) { File.absolute_path(File.join('qa', 'fixtures', 'web_ide', file_name)) } diff --git a/qa/qa/specs/features/browser_ui/3_create/web_ide/web_terminal_spec.rb b/qa/qa/specs/features/browser_ui/3_create/web_ide/web_terminal_spec.rb index 09459057992..f90676ee15a 100644 --- a/qa/qa/specs/features/browser_ui/3_create/web_ide/web_terminal_spec.rb +++ b/qa/qa/specs/features/browser_ui/3_create/web_ide/web_terminal_spec.rb @@ -9,7 +9,8 @@ module QA quarantine: { issue: 'https://gitlab.com/gitlab-org/gitlab/-/issues/338179', type: :bug - } + }, + product_group: :editor ) do describe 'Web IDE web terminal' do before do 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 fa8d0d1501c..aec0da99a5c 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,9 +2,9 @@ module QA RSpec.describe 'Verify' do - describe 'Add or Remove CI variable via UI', :smoke do + describe 'Add or Remove CI variable via UI', :smoke, product_group: :pipeline_authoring do let(:project) do - Resource::Project.fabricate_via_api! do |project| + Resource::Project.fabricate_via_api_unless_fips! do |project| project.name = 'project-with-ci-variables' project.description = 'project with CI variables' end 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 63801536c34..4a0a8be3659 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 @@ -2,7 +2,10 @@ module QA RSpec.describe 'Verify', :runner do - describe 'Pipeline with customizable variable' do + describe 'Pipeline with customizable variable', feature_flag: { + name: :run_pipeline_graphql, + scope: :project + } do let(:executor) { "qa-runner-#{Time.now.to_i}" } let(:pipeline_job_name) { 'customizable-variable' } let(:variable_custom_value) { 'Custom Foo' } @@ -45,43 +48,74 @@ module QA end end - before do - Flow::Login.sign_in - project.visit! - Page::Project::Menu.perform(&:click_ci_cd_pipelines) - Page::Project::Pipeline::Index.perform do |index| - index.click_run_pipeline_button + shared_examples 'pipeline with custom variable' do + before do + Flow::Login.sign_in + + 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 - end - after do - [runner, project].each(&:remove_via_api!) + after do + runner&.remove_via_api! + end + + it 'manually creates a pipeline and uses the defined custom variable value' do + Page::Project::Pipeline::New.perform do |new| + new.configure_variable(value: variable_custom_value) + new.click_run_pipeline_button + end + + Page::Project::Pipeline::Show.perform do |show| + Support::Waiter.wait_until { show.passed? } + end + + job = Resource::Job.fabricate_via_api! do |job| + job.id = project.job_by_name(pipeline_job_name)[:id] + job.name = pipeline_job_name + job.project = project + end + + job.visit! + + Page::Project::Job::Show.perform do |show| + expect(show.output).to have_content(variable_custom_value) + end + end end - it( - 'manually creates a pipeline and uses the defined custom variable value', + # TODO: Clean up tests when run_pipeline_graphql is enabled + # Issue https://gitlab.com/gitlab-org/gitlab/-/issues/372310 + context( + 'with feature flag disabled', testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/361814' ) do - Page::Project::Pipeline::New.perform do |new| - new.configure_variable(value: variable_custom_value) - new.click_run_pipeline_button + before do + Runtime::Feature.disable(:run_pipeline_graphql, project: project) end - Page::Project::Pipeline::Show.perform do |show| - Support::Waiter.wait_until { show.passed? } - end + it_behaves_like 'pipeline with custom variable' + end - job = Resource::Job.fabricate_via_api! do |job| - job.id = project.job_by_name(pipeline_job_name)[:id] - job.name = pipeline_job_name - job.project = project + context( + 'with feature flag enabled', + testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/378975' + ) do + before do + Runtime::Feature.enable(:run_pipeline_graphql, project: project) end - job.visit! - - Page::Project::Job::Show.perform do |show| - expect(show.output).to have_content(variable_custom_value) + after do + Runtime::Feature.disable(:run_pipeline_graphql, project: project) end + + it_behaves_like 'pipeline with custom variable' end end end 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 5bb60e64da5..48d6ed8dc49 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,10 +1,10 @@ # frozen_string_literal: true module QA - RSpec.describe 'Verify', :runner do + RSpec.describe 'Verify', :runner, product_group: :pipeline_authoring do describe 'Pipeline with protected variable' do - let(:executor) { "qa-runner-#{Faker::Alphanumeric.alphanumeric(8)}" } - let(:protected_value) { Faker::Alphanumeric.alphanumeric(8) } + let(:executor) { "qa-runner-#{Faker::Alphanumeric.alphanumeric(number: 8)}" } + let(:protected_value) { Faker::Alphanumeric.alphanumeric(number: 8) } let(:project) do Resource::Project.fabricate_via_api! do |project| 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 8352ad6aa33..c4ce916d47d 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,10 @@ module QA RSpec.describe 'Verify' do - describe 'Pipeline with prefill variables' do + describe 'Pipeline with prefill variables', feature_flag: { + name: :run_pipeline_graphql, + scope: :project + } do let(:prefill_variable_description1) { Faker::Lorem.sentence } let(:prefill_variable_value1) { Faker::Lorem.word } let(:prefill_variable_description2) { Faker::Lorem.sentence } @@ -40,32 +43,62 @@ module QA end end - before do - Flow::Login.sign_in - project.visit! + shared_examples 'pre-filled variables form' do + before do + Flow::Login.sign_in - # Navigate to Run Pipeline page - Page::Project::Menu.perform(&:click_ci_cd_pipelines) - Page::Project::Pipeline::Index.perform(&:click_run_pipeline_button) + project.visit! + # 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' do + Page::Project::Pipeline::New.perform do |new| + aggregate_failures do + expect(new).to have_field('Input variable key', with: 'TEST1') + expect(new).to have_field('Input variable value', with: prefill_variable_value1) + expect(new).to have_content(prefill_variable_description1) + + expect(new).to have_field('Input variable key', with: 'TEST2') + expect(new).to have_content(prefill_variable_description2) + + expect(new).not_to have_field('Input variable key', with: 'TEST3') + expect(new).not_to have_field('Input variable key', with: 'TEST4') + end + end + end end - it( - 'shows only variables with description as prefill variables on the run pipeline page', + # TODO: Clean up tests when run_pipeline_graphql is enabled + # Issue https://gitlab.com/gitlab-org/gitlab/-/issues/372310 + context( + 'with feature flag disabled', testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/371204' ) do - Page::Project::Pipeline::New.perform do |new| - aggregate_failures do - expect(new).to have_field('Input variable key', with: 'TEST1') - expect(new).to have_field('Input variable value', with: prefill_variable_value1) - expect(new).to have_content(prefill_variable_description1) + before do + Runtime::Feature.disable(:run_pipeline_graphql, project: project) + end - expect(new).to have_field('Input variable key', with: 'TEST2') - expect(new).to have_content(prefill_variable_description2) + it_behaves_like 'pre-filled variables form' + end - expect(new).not_to have_field('Input variable key', with: 'TEST3') - expect(new).not_to have_field('Input variable key', with: 'TEST4') - end + context 'with feature flag enabled', + testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/378977' do + before do + Runtime::Feature.enable(:run_pipeline_graphql, project: project) end + + after do + Runtime::Feature.disable(:run_pipeline_graphql, project: project) + end + + it_behaves_like 'pre-filled variables form' end end end 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 new file mode 100644 index 00000000000..fe934e8c60f --- /dev/null +++ b/qa/qa/specs/features/browser_ui/4_verify/ci_variable/raw_variables_defined_in_yaml_spec.rb @@ -0,0 +1,148 @@ +# frozen_string_literal: true + +module QA + RSpec.describe 'Verify', :runner do + describe 'Pipeline with raw variables in YAML', product_group: :pipeline_authoring, feature_flag: { + name: 'ci_raw_variables_in_yaml_config', + scope: :project + } do + let(:executor) { "qa-runner-#{Time.now.to_i}" } + let(:pipeline_job_name) { 'rspec' } + + let(:project) do + Resource::Project.fabricate_via_api! do |project| + project.name = 'project-with-raw-variable-pipeline' + end + end + + let!(:runner) do + Resource::Runner.fabricate! do |runner| + runner.project = project + runner.name = executor + runner.tags = [executor] + end + end + + let(:commit_ci_file) do + Resource::Repository::Commit.fabricate_via_api! do |commit| + commit.project = project + commit.commit_message = 'Add .gitlab-ci.yml' + commit.add_files( + [ + { + file_path: '.gitlab-ci.yml', + content: <<~YAML + variables: + VAR7: + value: "value 7 $CI_PIPELINE_ID" + expand: false + VAR8: + value: "value 8 $CI_PIPELINE_ID" + expand: false + + #{pipeline_job_name}: + tags: + - #{executor} + script: + - echo "VAR1 is $VAR1" + - echo "VAR2 is $VAR2" + - echo "VAR3 is $VAR3" + - echo "VAR4 is $VAR4" + - echo "VAR5 is $VAR5" + - echo "VAR6 is $VAR6" + - echo "VAR7 is $VAR7" + - echo "VAR8 is $VAR8" + variables: + VAR1: "JOBID-$CI_JOB_ID" + VAR2: "PIPELINEID-$CI_PIPELINE_ID and $VAR1" + VAR3: + value: "PIPELINEID-$CI_PIPELINE_ID and $VAR1" + expand: false + VAR4: + value: "JOBID-$CI_JOB_ID" + expand: false + VAR5: "PIPELINEID-$CI_PIPELINE_ID and $VAR4" + VAR6: + value: "PIPELINEID-$CI_PIPELINE_ID and $VAR4" + expand: false + VAR7: "overridden value 7 $CI_PIPELINE_ID" + YAML + } + ] + ) + end + end + + let(:pipeline_id) { project.pipelines.first[:id] } + let(:job_id) { project.job_by_name(pipeline_job_name)[:id] } + + def before_do + # TODO: Switch to use `let!` and remove this line when removing FF + commit_ci_file + + Flow::Login.sign_in + project.visit! + Flow::Pipeline.visit_latest_pipeline(status: 'passed') + Page::Project::Pipeline::Show.perform do |show| + show.click_job(pipeline_job_name) + end + end + + after do + runner&.remove_via_api! + end + + context 'when FF is on', testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/381487' do + before do + Runtime::Feature.enable(:ci_raw_variables_in_yaml_config, project: project) + sleep 60 + + before_do + end + + it 'expands variables according to expand: true/false', :aggregate_failures do + Page::Project::Job::Show.perform do |show| + expect(show.output).to have_content("VAR1 is JOBID-#{job_id}") + expect(show.output).to have_content("VAR2 is PIPELINEID-#{pipeline_id} and JOBID-#{job_id}") + expect(show.output).to have_content("VAR3 is PIPELINEID-$CI_PIPELINE_ID and $VAR1") + expect(show.output).to have_content("VAR4 is JOBID-$CI_JOB_ID") + expect(show.output).to have_content("VAR5 is PIPELINEID-#{pipeline_id} and JOBID-$CI_JOB_ID") + expect(show.output).to have_content("VAR6 is PIPELINEID-$CI_PIPELINE_ID and $VAR4") + expect(show.output).to have_content("VAR7 is overridden value 7 #{pipeline_id}") + expect(show.output).to have_content("VAR8 is value 8 $CI_PIPELINE_ID") + end + end + end + + # TODO: Remove this context when FF :ci_raw_variables_in_yaml_config is removed + # Also archive testcase and close related issue + context 'when FF is off', + testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/381486', + quarantine: { + issue: 'https://gitlab.com/gitlab-org/gitlab/-/issues/381806', + only: { pipeline: %w[staging staging-canary] }, + type: :waiting_on + } do + before do + Runtime::Feature.disable(:ci_raw_variables_in_yaml_config, project: project) + sleep 60 + + before_do + end + + it 'expands all variables', :aggregate_failures do + Page::Project::Job::Show.perform do |show| + expect(show.output).to have_content("VAR1 is JOBID-#{job_id}") + expect(show.output).to have_content("VAR2 is PIPELINEID-#{pipeline_id} and JOBID-#{job_id}") + expect(show.output).to have_content("VAR3 is PIPELINEID-#{pipeline_id} and JOBID-#{job_id}") + expect(show.output).to have_content("VAR4 is JOBID-#{job_id}") + expect(show.output).to have_content("VAR5 is PIPELINEID-#{pipeline_id} and JOBID-#{job_id}") + expect(show.output).to have_content("VAR6 is PIPELINEID-#{pipeline_id} and JOBID-#{job_id}") + expect(show.output).to have_content("VAR7 is overridden value 7 #{pipeline_id}") + expect(show.output).to have_content("VAR8 is value 8 #{pipeline_id}") + end + end + end + end + end +end 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 7782c0240e9..a5ebd4004d2 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 do + RSpec.describe 'Verify', :runner, product_group: :pipeline_authoring 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 69a99483b38..f53454b801c 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 do + RSpec.describe 'Verify', :runner, product_group: :pipeline_authoring do describe 'UI defined variable' do include_context 'variable inheritance test prep' diff --git a/qa/qa/specs/features/browser_ui/4_verify/pipeline/create_and_process_pipeline_spec.rb b/qa/qa/specs/features/browser_ui/4_verify/pipeline/create_and_process_pipeline_spec.rb index 1bba5355790..b6270c11ef6 100644 --- a/qa/qa/specs/features/browser_ui/4_verify/pipeline/create_and_process_pipeline_spec.rb +++ b/qa/qa/specs/features/browser_ui/4_verify/pipeline/create_and_process_pipeline_spec.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true module QA - RSpec.describe 'Verify', :smoke, :runner, quarantine: { + RSpec.describe 'Verify', :smoke, :runner, product_group: :pipeline_execution, quarantine: { issue: 'https://gitlab.com/gitlab-org/gitlab/-/issues/356295', type: :investigating } do diff --git a/qa/qa/specs/features/browser_ui/4_verify/pipeline/include_local_config_file_paths_with_wildcard_spec.rb b/qa/qa/specs/features/browser_ui/4_verify/pipeline/include_local_config_file_paths_with_wildcard_spec.rb index b9b87ed29bb..027383550a7 100644 --- a/qa/qa/specs/features/browser_ui/4_verify/pipeline/include_local_config_file_paths_with_wildcard_spec.rb +++ b/qa/qa/specs/features/browser_ui/4_verify/pipeline/include_local_config_file_paths_with_wildcard_spec.rb @@ -2,7 +2,7 @@ module QA RSpec.describe 'Verify' do - describe 'Include local config file paths with wildcard', :reliable do + describe 'Include local config file paths with wildcard', :reliable, product_group: :pipeline_authoring do let(:project) do Resource::Project.fabricate_via_api! do |project| project.name = 'project-with-pipeline' diff --git a/qa/qa/specs/features/browser_ui/4_verify/pipeline/include_multiple_files_from_a_project_spec.rb b/qa/qa/specs/features/browser_ui/4_verify/pipeline/include_multiple_files_from_a_project_spec.rb index 2fa6b9179ef..d773d0f36d0 100644 --- a/qa/qa/specs/features/browser_ui/4_verify/pipeline/include_multiple_files_from_a_project_spec.rb +++ b/qa/qa/specs/features/browser_ui/4_verify/pipeline/include_multiple_files_from_a_project_spec.rb @@ -1,9 +1,9 @@ # frozen_string_literal: true module QA - RSpec.describe 'Verify', :runner do + RSpec.describe 'Verify', :runner, product_group: :pipeline_authoring do describe 'Include multiple files from a project' do - let(:executor) { "qa-runner-#{Faker::Alphanumeric.alphanumeric(8)}" } + let(:executor) { "qa-runner-#{Faker::Alphanumeric.alphanumeric(number: 8)}" } let(:expected_text) { Faker::Lorem.sentence } let(:unexpected_text) { Faker::Lorem.sentence } 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 3356d1274c8..ba1363d79c5 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 do + RSpec.describe 'Verify', :runner, :requires_admin, product_group: :pipeline_insights 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/merge_mr_when_pipline_is_blocked_spec.rb b/qa/qa/specs/features/browser_ui/4_verify/pipeline/merge_mr_when_pipline_is_blocked_spec.rb index d201627218e..34f548a0e69 100644 --- a/qa/qa/specs/features/browser_ui/4_verify/pipeline/merge_mr_when_pipline_is_blocked_spec.rb +++ b/qa/qa/specs/features/browser_ui/4_verify/pipeline/merge_mr_when_pipline_is_blocked_spec.rb @@ -1,9 +1,9 @@ # frozen_string_literal: true module QA - RSpec.describe 'Verify', :runner do + RSpec.describe 'Verify', :runner, product_group: :pipeline_execution do context 'When pipeline is blocked' do - let(:executor) { "qa-runner-#{Faker::Alphanumeric.alphanumeric(8)}" } + let(:executor) { "qa-runner-#{Faker::Alphanumeric.alphanumeric(number: 8)}" } let(:project) do Resource::Project.fabricate_via_api! do |project| diff --git a/qa/qa/specs/features/browser_ui/4_verify/pipeline/mr_event_rule_pipeline_spec.rb b/qa/qa/specs/features/browser_ui/4_verify/pipeline/mr_event_rule_pipeline_spec.rb index 65561bbba29..e876bf3ab8b 100644 --- a/qa/qa/specs/features/browser_ui/4_verify/pipeline/mr_event_rule_pipeline_spec.rb +++ b/qa/qa/specs/features/browser_ui/4_verify/pipeline/mr_event_rule_pipeline_spec.rb @@ -1,11 +1,11 @@ # frozen_string_literal: true module QA - RSpec.describe 'Verify', :runner do + RSpec.describe 'Verify', :runner, product_group: :pipeline_authoring do context 'When job is configured to only run on merge_request_events' do let(:mr_only_job_name) { 'mr_only_job' } let(:non_mr_only_job_name) { 'non_mr_only_job' } - let(:executor) { "qa-runner-#{Faker::Alphanumeric.alphanumeric(8)}" } + let(:executor) { "qa-runner-#{Faker::Alphanumeric.alphanumeric(number: 8)}" } let(:project) do Resource::Project.fabricate_via_api! do |project| diff --git a/qa/qa/specs/features/browser_ui/4_verify/pipeline/parent_child_pipelines_independent_relationship_spec.rb b/qa/qa/specs/features/browser_ui/4_verify/pipeline/parent_child_pipelines_independent_relationship_spec.rb index 9e3c29db9e7..a7ca7b82d1e 100644 --- a/qa/qa/specs/features/browser_ui/4_verify/pipeline/parent_child_pipelines_independent_relationship_spec.rb +++ b/qa/qa/specs/features/browser_ui/4_verify/pipeline/parent_child_pipelines_independent_relationship_spec.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true module QA - RSpec.describe 'Verify', :runner, :reliable do + RSpec.describe 'Verify', :runner, :reliable, product_group: :pipeline_execution do describe 'Parent-child pipelines independent relationship' do let!(:project) do Resource::Project.fabricate_via_api! do |project| 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 bbcc71bade7..fca34fc1f8e 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 do + RSpec.describe 'Verify', :runner, product_group: :pipeline_authoring 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/pipeline/pipeline_editor_branch_switcher_spec.rb b/qa/qa/specs/features/browser_ui/4_verify/pipeline/pipeline_editor_branch_switcher_spec.rb index ac91a9dd2d3..30c71bc590c 100644 --- a/qa/qa/specs/features/browser_ui/4_verify/pipeline/pipeline_editor_branch_switcher_spec.rb +++ b/qa/qa/specs/features/browser_ui/4_verify/pipeline/pipeline_editor_branch_switcher_spec.rb @@ -2,7 +2,7 @@ module QA RSpec.describe 'Verify' do - describe 'Pipeline editor' do + describe 'Pipeline editor', product_group: :pipeline_authoring do let(:random_test_string) { SecureRandom.hex(10) } let(:project) do diff --git a/qa/qa/specs/features/browser_ui/4_verify/pipeline/pipeline_editor_can_create_merge_request_spec.rb b/qa/qa/specs/features/browser_ui/4_verify/pipeline/pipeline_editor_can_create_merge_request_spec.rb index 931bb97ba32..1f7871b0900 100644 --- a/qa/qa/specs/features/browser_ui/4_verify/pipeline/pipeline_editor_can_create_merge_request_spec.rb +++ b/qa/qa/specs/features/browser_ui/4_verify/pipeline/pipeline_editor_can_create_merge_request_spec.rb @@ -2,7 +2,7 @@ module QA RSpec.describe 'Verify' do - describe 'Pipeline editor' do + describe 'Pipeline editor', product_group: :pipeline_authoring do let(:project) do Resource::Project.fabricate_via_api! do |project| project.name = 'pipeline-editor-project' diff --git a/qa/qa/specs/features/browser_ui/4_verify/pipeline/pipeline_editor_tabs_spec.rb b/qa/qa/specs/features/browser_ui/4_verify/pipeline/pipeline_editor_tabs_spec.rb index bef15b46fcd..dbe24e2a2b2 100644 --- a/qa/qa/specs/features/browser_ui/4_verify/pipeline/pipeline_editor_tabs_spec.rb +++ b/qa/qa/specs/features/browser_ui/4_verify/pipeline/pipeline_editor_tabs_spec.rb @@ -2,7 +2,7 @@ module QA RSpec.describe 'Verify' do - describe 'Pipeline editor', :reliable do + describe 'Pipeline editor', :reliable, product_group: :pipeline_authoring do let(:project) do Resource::Project.fabricate_via_api! do |project| project.name = 'pipeline-editor-project' @@ -36,6 +36,15 @@ module QA end end + let(:invalid_content) do + <<~YAML + + job3: + stage: stage_foo + script: echo 'Done.' + YAML + end + before do # Make sure a pipeline is created before visiting pipeline editor page. # Otherwise, test might timeout before the page finishing fetching pipeline status. @@ -80,7 +89,7 @@ module QA invalid_msg = 'syntax is invalid' Page::Project::PipelineEditor::Show.perform do |show| - show.write_to_editor(SecureRandom.hex(10)) + show.write_to_editor(invalid_content) aggregate_failures do show.go_to_visualize_tab @@ -90,8 +99,14 @@ module QA show.simulate_pipeline expect(show.tab_alert_title).to have_content('Pipeline simulation completed with errors') + expect(show.ci_syntax_validate_message).to have_content('CI configuration is invalid') + show.go_to_view_merged_yaml_tab - expect(show.tab_alert_message).to have_content(invalid_msg) + + # TODO: remove this retry when + # https://gitlab.com/gitlab-org/gitlab/-/issues/378536 is resolved + show.retry_until(max_attempts: 2, reload: true, sleep_interval: 1) { show.has_no_alert? } + expect(show).to have_source_editor expect(show.ci_syntax_validate_message).to have_content('CI configuration is invalid') end diff --git a/qa/qa/specs/features/browser_ui/4_verify/pipeline/pipeline_with_image_pull_policy_spec.rb b/qa/qa/specs/features/browser_ui/4_verify/pipeline/pipeline_with_image_pull_policy_spec.rb index f9113573295..b1ecce297c9 100644 --- a/qa/qa/specs/features/browser_ui/4_verify/pipeline/pipeline_with_image_pull_policy_spec.rb +++ b/qa/qa/specs/features/browser_ui/4_verify/pipeline/pipeline_with_image_pull_policy_spec.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true module QA - RSpec.describe 'Verify', :runner do + RSpec.describe 'Verify', :runner, product_group: :pipeline_authoring do describe 'Pipeline with image:pull_policy' do let(:runner_name) { "qa-runner-#{Faker::Alphanumeric.alphanumeric(number: 8)}" } let(:job_name) { "test-job-#{pull_policies.join('-')}" } diff --git a/qa/qa/specs/features/browser_ui/4_verify/pipeline/run_pipeline_via_web_only_spec.rb b/qa/qa/specs/features/browser_ui/4_verify/pipeline/run_pipeline_via_web_only_spec.rb index f36593218a9..e8ec01577b1 100644 --- a/qa/qa/specs/features/browser_ui/4_verify/pipeline/run_pipeline_via_web_only_spec.rb +++ b/qa/qa/specs/features/browser_ui/4_verify/pipeline/run_pipeline_via_web_only_spec.rb @@ -2,7 +2,7 @@ module QA RSpec.describe 'Verify' do - describe 'Run pipeline', :reliable do + describe 'Run pipeline', :reliable, product_group: :pipeline_execution do context 'with web only rule' do let(:job_name) { 'test_job' } let(:project) do diff --git a/qa/qa/specs/features/browser_ui/4_verify/pipeline/run_pipeline_with_manual_jobs_spec.rb b/qa/qa/specs/features/browser_ui/4_verify/pipeline/run_pipeline_with_manual_jobs_spec.rb index fb7e3a8437f..4223caaafef 100644 --- a/qa/qa/specs/features/browser_ui/4_verify/pipeline/run_pipeline_with_manual_jobs_spec.rb +++ b/qa/qa/specs/features/browser_ui/4_verify/pipeline/run_pipeline_with_manual_jobs_spec.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true module QA - RSpec.describe 'Verify', :runner do + RSpec.describe 'Verify', :runner, product_group: :pipeline_execution do describe 'Run pipeline with manual jobs' do let(:executor) { "qa-runner-#{SecureRandom.hex(4)}" } diff --git a/qa/qa/specs/features/browser_ui/4_verify/pipeline/trigger_child_pipeline_with_manual_spec.rb b/qa/qa/specs/features/browser_ui/4_verify/pipeline/trigger_child_pipeline_with_manual_spec.rb index 1c75beebb48..c1d996df925 100644 --- a/qa/qa/specs/features/browser_ui/4_verify/pipeline/trigger_child_pipeline_with_manual_spec.rb +++ b/qa/qa/specs/features/browser_ui/4_verify/pipeline/trigger_child_pipeline_with_manual_spec.rb @@ -1,9 +1,9 @@ # frozen_string_literal: true module QA - RSpec.describe 'Verify', :runner do + RSpec.describe 'Verify', :runner, product_group: :pipeline_execution do describe "Trigger child pipeline with 'when:manual'" do - let(:executor) { "qa-runner-#{Faker::Alphanumeric.alphanumeric(8)}" } + let(:executor) { "qa-runner-#{Faker::Alphanumeric.alphanumeric(number: 8)}" } let(:project) do Resource::Project.fabricate_via_api! do |project| diff --git a/qa/qa/specs/features/browser_ui/4_verify/pipeline/trigger_matrix_spec.rb b/qa/qa/specs/features/browser_ui/4_verify/pipeline/trigger_matrix_spec.rb index 205b4d1168a..83283c5d8e3 100644 --- a/qa/qa/specs/features/browser_ui/4_verify/pipeline/trigger_matrix_spec.rb +++ b/qa/qa/specs/features/browser_ui/4_verify/pipeline/trigger_matrix_spec.rb @@ -1,9 +1,9 @@ # frozen_string_literal: true module QA - RSpec.describe 'Verify', :runner do + RSpec.describe 'Verify', :runner, product_group: :pipeline_authoring do describe 'Trigger matrix' do - let(:executor) { "qa-runner-#{Faker::Alphanumeric.alphanumeric(8)}" } + let(:executor) { "qa-runner-#{Faker::Alphanumeric.alphanumeric(number: 8)}" } let(:project) do Resource::Project.fabricate_via_api! do |project| diff --git a/qa/qa/specs/features/browser_ui/4_verify/pipeline/update_ci_file_with_pipeline_editor_spec.rb b/qa/qa/specs/features/browser_ui/4_verify/pipeline/update_ci_file_with_pipeline_editor_spec.rb index d34df17c477..1f49c7a3663 100644 --- a/qa/qa/specs/features/browser_ui/4_verify/pipeline/update_ci_file_with_pipeline_editor_spec.rb +++ b/qa/qa/specs/features/browser_ui/4_verify/pipeline/update_ci_file_with_pipeline_editor_spec.rb @@ -2,7 +2,7 @@ module QA RSpec.describe 'Verify' do - describe 'Update CI file with pipeline editor' do + describe 'Update CI file with pipeline editor', product_group: :pipeline_authoring do let(:random_test_string) { SecureRandom.hex(10) } let(:project) do diff --git a/qa/qa/specs/features/browser_ui/4_verify/runner/register_runner_spec.rb b/qa/qa/specs/features/browser_ui/4_verify/runner/register_runner_spec.rb index f8261bba342..24c49be13bb 100644 --- a/qa/qa/specs/features/browser_ui/4_verify/runner/register_runner_spec.rb +++ b/qa/qa/specs/features/browser_ui/4_verify/runner/register_runner_spec.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true module QA - RSpec.describe 'Verify', :runner do + RSpec.describe 'Verify', :runner, product_group: :runner do describe 'Runner registration' do let(:executor) { "qa-runner-#{Time.now.to_i}" } let!(:runner) do 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 adcf91a550c..0166c53ffd5 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 do + RSpec.describe 'Verify', :runner, product_group: :pipeline_insights 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 122fb0fc1a0..2a4852a2b8b 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 do + RSpec.describe 'Verify', :runner, product_group: :pipeline_insights 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/container_registry/container_registry_omnibus_spec.rb b/qa/qa/specs/features/browser_ui/5_package/container_registry/container_registry_omnibus_spec.rb index fca14a55468..c57a5c27dd2 100644 --- a/qa/qa/specs/features/browser_ui/5_package/container_registry/container_registry_omnibus_spec.rb +++ b/qa/qa/specs/features/browser_ui/5_package/container_registry/container_registry_omnibus_spec.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true module QA - RSpec.describe 'Package', :orchestrated, :skip_live_env do + RSpec.describe 'Package', :orchestrated, :skip_live_env, product_group: :container_registry do describe 'Self-managed Container Registry' do include Support::Helpers::MaskToken @@ -174,7 +174,7 @@ module QA Page::Project::Registry::Show.perform do |registry| expect(registry).to have_registry_repository(project.name) - registry.click_on_image(project.path_with_namespace) + registry.click_on_image(project.name) expect(registry).to have_tag('master') end end @@ -232,7 +232,7 @@ module QA Page::Project::Registry::Show.perform do |registry| expect(registry).to have_registry_repository(project.name) - registry.click_on_image(project.path_with_namespace) + registry.click_on_image(project.name) expect(registry).to have_tag('master') diff --git a/qa/qa/specs/features/browser_ui/5_package/container_registry/container_registry_spec.rb b/qa/qa/specs/features/browser_ui/5_package/container_registry/container_registry_spec.rb index 5a29b44e8b3..680b722edb7 100644 --- a/qa/qa/specs/features/browser_ui/5_package/container_registry/container_registry_spec.rb +++ b/qa/qa/specs/features/browser_ui/5_package/container_registry/container_registry_spec.rb @@ -2,7 +2,7 @@ module QA RSpec.describe 'Package' do - describe 'Container Registry', only: { subdomain: %i[staging staging-canary pre] } do + describe 'Container Registry', only: { subdomain: %i[staging staging-canary pre] }, product_group: :container_registry do let(:project) do Resource::Project.fabricate_via_api! do |project| project.name = 'project-with-registry' diff --git a/qa/qa/specs/features/browser_ui/5_package/container_registry/online_garbage_collection_spec.rb b/qa/qa/specs/features/browser_ui/5_package/container_registry/online_garbage_collection_spec.rb index 56e3ec82388..bf328a2bced 100644 --- a/qa/qa/specs/features/browser_ui/5_package/container_registry/online_garbage_collection_spec.rb +++ b/qa/qa/specs/features/browser_ui/5_package/container_registry/online_garbage_collection_spec.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true module QA - RSpec.describe 'Package' do + RSpec.describe 'Package', product_group: :container_registry do describe 'Container Registry Online Garbage Collection', :registry_gc, only: { subdomain: %i[pre] } do let(:group) { Resource::Group.fabricate_via_api! } diff --git a/qa/qa/specs/features/browser_ui/5_package/dependency_proxy/dependency_proxy_spec.rb b/qa/qa/specs/features/browser_ui/5_package/dependency_proxy/dependency_proxy_spec.rb index ad820977747..978867d5cf1 100644 --- a/qa/qa/specs/features/browser_ui/5_package/dependency_proxy/dependency_proxy_spec.rb +++ b/qa/qa/specs/features/browser_ui/5_package/dependency_proxy/dependency_proxy_spec.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true module QA - RSpec.describe 'Package', :orchestrated, :registry, only: { pipeline: :main } do + RSpec.describe 'Package', :orchestrated, :registry, only: { pipeline: :main }, product_group: :container_registry do describe 'Dependency Proxy' do using RSpec::Parameterized::TableSyntax include Support::Helpers::MaskToken diff --git a/qa/qa/specs/features/browser_ui/5_package/infrastructure_registry/terraform_module_registry_spec.rb b/qa/qa/specs/features/browser_ui/5_package/infrastructure_registry/terraform_module_registry_spec.rb index 6ce395affc7..a80e154a969 100644 --- a/qa/qa/specs/features/browser_ui/5_package/infrastructure_registry/terraform_module_registry_spec.rb +++ b/qa/qa/specs/features/browser_ui/5_package/infrastructure_registry/terraform_module_registry_spec.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true module QA - RSpec.describe 'Package', :orchestrated, :packages do + RSpec.describe 'Package', :orchestrated, :packages, product_group: :package_registry do describe 'Terraform Module Registry' do include Runtime::Fixtures diff --git a/qa/qa/specs/features/browser_ui/5_package/package_registry/composer_registry_spec.rb b/qa/qa/specs/features/browser_ui/5_package/package_registry/composer_registry_spec.rb index d5ef9dce10d..ab4fb21f19a 100644 --- a/qa/qa/specs/features/browser_ui/5_package/package_registry/composer_registry_spec.rb +++ b/qa/qa/specs/features/browser_ui/5_package/package_registry/composer_registry_spec.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true module QA - RSpec.describe 'Package', :orchestrated, :packages, :object_storage do + RSpec.describe 'Package', :orchestrated, :packages, :object_storage, product_group: :package_registry do describe 'Composer Repository' do include Runtime::Fixtures diff --git a/qa/qa/specs/features/browser_ui/5_package/package_registry/conan_repository_spec.rb b/qa/qa/specs/features/browser_ui/5_package/package_registry/conan_repository_spec.rb index 1840ae4e7f8..687d9f710fb 100644 --- a/qa/qa/specs/features/browser_ui/5_package/package_registry/conan_repository_spec.rb +++ b/qa/qa/specs/features/browser_ui/5_package/package_registry/conan_repository_spec.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true module QA - RSpec.describe 'Package', :orchestrated, :packages, :object_storage, quarantine: { + RSpec.describe 'Package', :orchestrated, :packages, :object_storage, product_group: :package_registry, quarantine: { only: { job: 'object_storage' }, issue: 'https://gitlab.com/gitlab-org/gitlab/-/issues/335981', type: :bug diff --git a/qa/qa/specs/features/browser_ui/5_package/package_registry/generic_repository_spec.rb b/qa/qa/specs/features/browser_ui/5_package/package_registry/generic_repository_spec.rb index 677b8970a75..820571593a6 100644 --- a/qa/qa/specs/features/browser_ui/5_package/package_registry/generic_repository_spec.rb +++ b/qa/qa/specs/features/browser_ui/5_package/package_registry/generic_repository_spec.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true module QA - RSpec.describe 'Package', :orchestrated, :packages, :object_storage, :reliable do + RSpec.describe 'Package', :orchestrated, :packages, :object_storage, :reliable, product_group: :package_registry do describe 'Generic Repository' do include Runtime::Fixtures diff --git a/qa/qa/specs/features/browser_ui/5_package/package_registry/helm_registry_spec.rb b/qa/qa/specs/features/browser_ui/5_package/package_registry/helm_registry_spec.rb index 222d1993bf4..4c15b7c7f99 100644 --- a/qa/qa/specs/features/browser_ui/5_package/package_registry/helm_registry_spec.rb +++ b/qa/qa/specs/features/browser_ui/5_package/package_registry/helm_registry_spec.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true module QA - RSpec.describe 'Package', :orchestrated, :packages, :object_storage do + RSpec.describe 'Package', :skip_live_env, :orchestrated, :packages, :object_storage, product_group: :package_registry do describe 'Helm Registry' do using RSpec::Parameterized::TableSyntax include Runtime::Fixtures diff --git a/qa/qa/specs/features/browser_ui/5_package/package_registry/maven/maven_group_level_spec.rb b/qa/qa/specs/features/browser_ui/5_package/package_registry/maven/maven_group_level_spec.rb index 690451f6147..aac8893ff2c 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 do + RSpec.describe 'Package', :skip_live_env, :orchestrated, :packages, :object_storage, :reliable, product_group: :package_registry do describe 'Maven group level endpoint' do include Runtime::Fixtures include_context 'packages registry qa scenario' @@ -131,7 +131,7 @@ module QA Page::Group::Settings::PackageRegistries.perform(&:set_allow_duplicates_disabled) end - it 'prevents users from publishing duplicates' do + it 'prevents users from publishing duplicates', testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/377491' do create_duplicated_package push_duplicated_package @@ -151,7 +151,7 @@ module QA Page::Group::Settings::PackageRegistries.perform(&:set_allow_duplicates_enabled) end - it 'allows users to publish duplicates' do + it 'allows users to publish duplicates', testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/377492' do create_duplicated_package push_duplicated_package diff --git a/qa/qa/specs/features/browser_ui/5_package/package_registry/maven/maven_project_level_spec.rb b/qa/qa/specs/features/browser_ui/5_package/package_registry/maven/maven_project_level_spec.rb index 324e881f160..8e1b0176f35 100644 --- a/qa/qa/specs/features/browser_ui/5_package/package_registry/maven/maven_project_level_spec.rb +++ b/qa/qa/specs/features/browser_ui/5_package/package_registry/maven/maven_project_level_spec.rb @@ -1,12 +1,12 @@ # frozen_string_literal: true module QA - RSpec.describe 'Package', :orchestrated, :packages, :object_storage, :reliable, + RSpec.describe 'Package', :skip_live_env, :orchestrated, :packages, :object_storage, :reliable, feature_flag: { name: 'maven_central_request_forwarding', scope: :global } do - describe 'Maven project level endpoint' do + describe 'Maven project level endpoint', product_group: :package_registry do include Runtime::Fixtures let(:group_id) { 'com.gitlab.qa' } 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 22052aa4110..a9d66c93fac 100644 --- a/qa/qa/specs/features/browser_ui/5_package/package_registry/maven_gradle_repository_spec.rb +++ b/qa/qa/specs/features/browser_ui/5_package/package_registry/maven_gradle_repository_spec.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true module QA - RSpec.describe 'Package', :orchestrated, :packages, :object_storage do + RSpec.describe 'Package', :skip_live_env, :orchestrated, :packages, :object_storage, product_group: :package_registry do describe 'Maven Repository with Gradle' do using RSpec::Parameterized::TableSyntax include Runtime::Fixtures diff --git a/qa/qa/specs/features/browser_ui/5_package/package_registry/npm/npm_instance_level_spec.rb b/qa/qa/specs/features/browser_ui/5_package/package_registry/npm/npm_instance_level_spec.rb index 124e7743728..e209fc55e35 100644 --- a/qa/qa/specs/features/browser_ui/5_package/package_registry/npm/npm_instance_level_spec.rb +++ b/qa/qa/specs/features/browser_ui/5_package/package_registry/npm/npm_instance_level_spec.rb @@ -2,7 +2,7 @@ module QA RSpec.describe 'Package' do - describe 'Package Registry', :orchestrated, :reliable, :packages, :object_storage do + describe 'Package Registry', :skip_live_env, :orchestrated, :reliable, :packages, :object_storage, product_group: :package_registry do describe 'npm instance level endpoint' do using RSpec::Parameterized::TableSyntax include Runtime::Fixtures diff --git a/qa/qa/specs/features/browser_ui/5_package/package_registry/npm/npm_project_level_spec.rb b/qa/qa/specs/features/browser_ui/5_package/package_registry/npm/npm_project_level_spec.rb index 59324c7338a..d1aaa05c85a 100644 --- a/qa/qa/specs/features/browser_ui/5_package/package_registry/npm/npm_project_level_spec.rb +++ b/qa/qa/specs/features/browser_ui/5_package/package_registry/npm/npm_project_level_spec.rb @@ -2,7 +2,7 @@ module QA RSpec.describe 'Package' do - describe 'Package Registry', :orchestrated, :reliable, :packages, :object_storage do + describe 'Package Registry', :skip_live_env, :orchestrated, :reliable, :packages, :object_storage, product_group: :package_registry do describe 'npm project level endpoint' do using RSpec::Parameterized::TableSyntax include Runtime::Fixtures diff --git a/qa/qa/specs/features/browser_ui/5_package/package_registry/nuget/nuget_group_level_spec.rb b/qa/qa/specs/features/browser_ui/5_package/package_registry/nuget/nuget_group_level_spec.rb index e2a7006249d..d44bc8fa2ad 100644 --- a/qa/qa/specs/features/browser_ui/5_package/package_registry/nuget/nuget_group_level_spec.rb +++ b/qa/qa/specs/features/browser_ui/5_package/package_registry/nuget/nuget_group_level_spec.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true module QA - RSpec.describe 'Package', :orchestrated, :packages, :object_storage, :reliable do + RSpec.describe 'Package', :skip_live_env, :orchestrated, :packages, :object_storage, :reliable, product_group: :package_registry do describe 'NuGet group level endpoint' do using RSpec::Parameterized::TableSyntax include Runtime::Fixtures @@ -133,14 +133,14 @@ module QA { file_path: 'otherdotnet.csproj', content: <<~EOF - <Project Sdk="Microsoft.NET.Sdk"> + <Project Sdk="Microsoft.NET.Sdk"> - <PropertyGroup> - <OutputType>Exe</OutputType> - <TargetFramework>net5.0</TargetFramework> - </PropertyGroup> + <PropertyGroup> + <OutputType>Exe</OutputType> + <TargetFramework>net5.0</TargetFramework> + </PropertyGroup> - </Project> + </Project> EOF } ] diff --git a/qa/qa/specs/features/browser_ui/5_package/package_registry/nuget/nuget_project_level_spec.rb b/qa/qa/specs/features/browser_ui/5_package/package_registry/nuget/nuget_project_level_spec.rb index 620bb7e4988..442deb1eb4e 100644 --- a/qa/qa/specs/features/browser_ui/5_package/package_registry/nuget/nuget_project_level_spec.rb +++ b/qa/qa/specs/features/browser_ui/5_package/package_registry/nuget/nuget_project_level_spec.rb @@ -1,7 +1,8 @@ # frozen_string_literal: true module QA - RSpec.describe 'Package', :orchestrated, :packages, :object_storage do + RSpec.describe 'Package', :skip_live_env, :orchestrated, :packages, :object_storage, +product_group: :package_registry do describe 'NuGet project level endpoint' do include Support::Helpers::MaskToken diff --git a/qa/qa/specs/features/browser_ui/5_package/package_registry/pypi_repository_spec.rb b/qa/qa/specs/features/browser_ui/5_package/package_registry/pypi_repository_spec.rb index 012a03ca115..fddb7fb6ebc 100644 --- a/qa/qa/specs/features/browser_ui/5_package/package_registry/pypi_repository_spec.rb +++ b/qa/qa/specs/features/browser_ui/5_package/package_registry/pypi_repository_spec.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true module QA - RSpec.describe 'Package', :orchestrated, :packages, :object_storage do + RSpec.describe 'Package', :skip_live_env, :orchestrated, :packages, :object_storage, product_group: :package_registry do describe 'PyPI Repository' do include Runtime::Fixtures include Support::Helpers::MaskToken diff --git a/qa/qa/specs/features/browser_ui/5_package/package_registry/rubygems_registry_spec.rb b/qa/qa/specs/features/browser_ui/5_package/package_registry/rubygems_registry_spec.rb index 409a1c10943..63ab826e57b 100644 --- a/qa/qa/specs/features/browser_ui/5_package/package_registry/rubygems_registry_spec.rb +++ b/qa/qa/specs/features/browser_ui/5_package/package_registry/rubygems_registry_spec.rb @@ -3,7 +3,7 @@ module QA RSpec.describe 'Package', :orchestrated, :packages, :object_storage, feature_flag: { name: 'rubygem_packages', scope: :project } do - describe 'RubyGems Repository' do + describe 'RubyGems Repository', product_group: :package_registry do include Runtime::Fixtures let(:project) do diff --git a/qa/qa/specs/features/browser_ui/6_release/deploy_key/add_deploy_key_spec.rb b/qa/qa/specs/features/browser_ui/6_release/deploy_key/add_deploy_key_spec.rb index 8b7b827de91..05dfc0c572e 100644 --- a/qa/qa/specs/features/browser_ui/6_release/deploy_key/add_deploy_key_spec.rb +++ b/qa/qa/specs/features/browser_ui/6_release/deploy_key/add_deploy_key_spec.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true module QA - RSpec.describe 'Release' do + RSpec.describe 'Release', product_group: :release do describe 'Deploy key creation' do it 'user adds a deploy key', testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/348023' do Flow::Login.sign_in 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 1f5a431938c..3f91d120fdd 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 @@ -3,7 +3,7 @@ require 'digest/sha1' module QA - RSpec.describe 'Release', :runner do + RSpec.describe 'Release', :runner, product_group: :release do describe 'Git clone using a deploy key' do let(:runner_name) { "qa-runner-#{SecureRandom.hex(4)}" } let(:repository_location) { project.repository_ssh_location } @@ -35,7 +35,7 @@ module QA keys = [ ['https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/348022', Runtime::Key::RSA, 8192, true], ['https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/348021', Runtime::Key::ECDSA, 521, true], - ['https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/348020', Runtime::Key::ED25519, false] + ['https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/348020', Runtime::Key::ED25519, 256, false] ] supported_keys = diff --git a/qa/qa/specs/features/browser_ui/6_release/deploy_token/add_deploy_token_spec.rb b/qa/qa/specs/features/browser_ui/6_release/deploy_token/add_deploy_token_spec.rb index 9811453605e..b0b1fa2b68d 100644 --- a/qa/qa/specs/features/browser_ui/6_release/deploy_token/add_deploy_token_spec.rb +++ b/qa/qa/specs/features/browser_ui/6_release/deploy_token/add_deploy_token_spec.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true module QA - RSpec.describe 'Release' do + RSpec.describe 'Release', product_group: :release do describe 'Deploy token creation' do it 'user adds a deploy token', testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/348028' do Flow::Login.sign_in diff --git a/qa/qa/specs/features/browser_ui/7_configure/auto_devops/auto_devops_templates_spec.rb b/qa/qa/specs/features/browser_ui/7_configure/auto_devops/auto_devops_templates_spec.rb index 608dd7e089f..42a64099a3d 100644 --- a/qa/qa/specs/features/browser_ui/7_configure/auto_devops/auto_devops_templates_spec.rb +++ b/qa/qa/specs/features/browser_ui/7_configure/auto_devops/auto_devops_templates_spec.rb @@ -2,7 +2,7 @@ module QA RSpec.describe 'Configure' do - describe 'AutoDevOps Templates', only: { subdomain: %i[staging staging-canary] } do + describe 'AutoDevOps Templates', only: { subdomain: %i[staging staging-canary] }, product_group: :configure do using RSpec::Parameterized::TableSyntax # specify jobs to be disabled in the pipeline. diff --git a/qa/qa/specs/features/browser_ui/7_configure/auto_devops/create_project_with_auto_devops_spec.rb b/qa/qa/specs/features/browser_ui/7_configure/auto_devops/create_project_with_auto_devops_spec.rb index b839855c500..057b4c15db1 100644 --- a/qa/qa/specs/features/browser_ui/7_configure/auto_devops/create_project_with_auto_devops_spec.rb +++ b/qa/qa/specs/features/browser_ui/7_configure/auto_devops/create_project_with_auto_devops_spec.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true module QA - RSpec.describe 'Configure', only: { subdomain: %i[staging staging-canary] } do + RSpec.describe 'Configure', only: { subdomain: %i[staging staging-canary] }, product_group: :configure do describe 'Auto DevOps with a Kubernetes Agent' do let!(:app_project) do Resource::Project.fabricate_via_api! do |project| @@ -98,7 +98,7 @@ module QA content: <<~YAML ci_access: projects: - - id: #{project.path_with_namespace} + - id: #{project.path_with_namespace} YAML } ] 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 new file mode 100644 index 00000000000..0a0c2a4a6df --- /dev/null +++ b/qa/qa/specs/features/shared_contexts/import/github_import_shared_context.rb @@ -0,0 +1,46 @@ +# frozen_string_literal: true + +module QA + RSpec.shared_context "with github import", :github, :skip_live_env, :requires_admin, quarantine: { + type: :broken, + issue: "https://gitlab.com/gitlab-org/gitlab/-/issues/382166" + } do + let!(:api_client) { Runtime::API::Client.as_admin } + + let!(:group) do + Resource::Group.fabricate_via_api! do |resource| + resource.api_client = api_client + resource.path = "destination-group-for-import-#{SecureRandom.hex(4)}" + end + end + + let!(:user) do + Resource::User.fabricate_via_api! do |resource| + resource.api_client = api_client + resource.hard_delete_on_api_removal = true + end + end + + let!(:user_api_client) { Runtime::API::Client.new(user: user) } + + let(:imported_project) do + Resource::ProjectImportedFromGithub.fabricate_via_api! do |project| + project.name = 'imported-project' + project.group = group + project.github_personal_access_token = Runtime::Env.github_access_token + project.github_repository_path = 'gitlab-qa-github/import-test' + project.api_client = user_api_client + project.issue_events_import = true + project.full_notes_import = true + end + end + + before do + group.add_member(user, Resource::Members::AccessLevel::MAINTAINER) + end + + after do + user.remove_via_api! + end + end +end diff --git a/qa/qa/specs/features/api/1_manage/migration/gitlab_project_migration_common.rb b/qa/qa/specs/features/shared_contexts/import/gitlab_project_migration_common.rb index 9c80c088917..9c80c088917 100644 --- a/qa/qa/specs/features/api/1_manage/migration/gitlab_project_migration_common.rb +++ b/qa/qa/specs/features/shared_contexts/import/gitlab_project_migration_common.rb diff --git a/qa/qa/specs/helpers/context_selector.rb b/qa/qa/specs/helpers/context_selector.rb index 3608fa7c581..caa5ace430f 100644 --- a/qa/qa/specs/helpers/context_selector.rb +++ b/qa/qa/specs/helpers/context_selector.rb @@ -18,6 +18,7 @@ module QA def context_matches?(*options) return false unless Runtime::Scenario.attributes[:gitlab_address] + return false if Runtime::Scenario.attributes[:test_metadata_only] opts = {} opts[:domain] = '.+' diff --git a/qa/qa/specs/runner.rb b/qa/qa/specs/runner.rb index c46b6300200..4eb799f34c1 100644 --- a/qa/qa/specs/runner.rb +++ b/qa/qa/specs/runner.rb @@ -23,6 +23,8 @@ module QA def rspec_tags tags_for_rspec = [] + return tags_for_rspec if Runtime::Scenario.attributes[:test_metadata_only] + if tags.any? tags.each { |tag| tags_for_rspec.push(['--tag', tag.to_s]) } else diff --git a/qa/qa/specs/spec_helper.rb b/qa/qa/specs/spec_helper.rb index 97901042883..a4721040683 100644 --- a/qa/qa/specs/spec_helper.rb +++ b/qa/qa/specs/spec_helper.rb @@ -1,6 +1,7 @@ # frozen_string_literal: true require_relative '../../qa' +require 'active_support/testing/time_helpers' QA::Specs::QaDeprecationToolkitEnv.configure! @@ -14,20 +15,18 @@ QA::Runtime::Scenario.from_env(QA::Runtime::Env.runtime_scenario_attributes) # Enable zero monkey patching mode before loading any other RSpec code. RSpec.configure(&:disable_monkey_patching!) -Dir[::File.join(__dir__, "features/shared_examples/*.rb")].sort.each { |f| require f } -Dir[::File.join(__dir__, "features/shared_contexts/*.rb")].sort.each { |f| require f } - # For JH additionally process when `jh/` exists require_relative('../../../jh/qa/qa/specs/spec_helper') if GitlabEdition.jh? RSpec.configure do |config| + config.include ActiveSupport::Testing::TimeHelpers config.include QA::Support::Matchers::EventuallyMatcher config.include QA::Support::Matchers::HaveMatcher config.add_formatter QA::Support::Formatters::ContextFormatter config.add_formatter QA::Support::Formatters::QuarantineFormatter config.add_formatter QA::Support::Formatters::FeatureFlagFormatter - config.add_formatter QA::Support::Formatters::TestStatsFormatter if QA::Runtime::Env.export_metrics? + config.add_formatter QA::Support::Formatters::TestMetricsFormatter if QA::Runtime::Env.running_in_ci? config.before(:suite) do |suite| QA::Resource::ReusableCollection.register_resource_classes do |collection| @@ -149,3 +148,6 @@ RSpec.configure do |config| end end end + +Dir[::File.join(__dir__, "features/shared_examples/**/*.rb")].sort.each { |f| require f } +Dir[::File.join(__dir__, "features/shared_contexts/**/*.rb")].sort.each { |f| require f } diff --git a/qa/qa/support/fips.rb b/qa/qa/support/fips.rb index f5ebce4fa9c..0fed39e8109 100644 --- a/qa/qa/support/fips.rb +++ b/qa/qa/support/fips.rb @@ -5,7 +5,7 @@ module QA module Support class FIPS def self.enabled? - %(1 true yes).include?(ENV['FIPS'].to_s) + %w[1 true yes].include?(ENV['FIPS'].to_s) end end end diff --git a/qa/qa/support/formatters/allure_metadata_formatter.rb b/qa/qa/support/formatters/allure_metadata_formatter.rb index d1baf87799a..02719536b17 100644 --- a/qa/qa/support/formatters/allure_metadata_formatter.rb +++ b/qa/qa/support/formatters/allure_metadata_formatter.rb @@ -39,6 +39,7 @@ module QA add_failure_issues_link(example) add_ci_job_link(example) set_flaky_status(example) + set_behaviour_categories(example) end private @@ -97,6 +98,19 @@ module QA log(:error, "Failed to add spec pass rate data for example '#{example.description}', error: #{e}") end + # Add behaviour categories to report + # + # @param [RSpec::Core::Example] example + # @return [void] + def set_behaviour_categories(example) + file_path = example.file_path.gsub('./qa/specs/features', '') + devops_stage = file_path.match(%r{\d{1,2}_(\w+)/})&.captures&.first + product_group = example.metadata[:product_group] + + example.epic(devops_stage) if devops_stage + example.feature(product_group) if product_group + end + # Flaky specs with pass rate below 98% # # @return [Array] @@ -107,7 +121,7 @@ module QA runs = records.count failed = records.count { |r| r.values["status"] == "failed" } - pass_rate = 100 - ((failed.to_f / runs.to_f) * 100) + pass_rate = 100 - ((failed.to_f / runs) * 100) # Consider spec with a pass rate less than 98% as flaky result[records.last.values["testcase"]] = pass_rate if pass_rate < 98 diff --git a/qa/qa/support/formatters/context_formatter.rb b/qa/qa/support/formatters/context_formatter.rb index c8991561f45..11f6a182ebb 100644 --- a/qa/qa/support/formatters/context_formatter.rb +++ b/qa/qa/support/formatters/context_formatter.rb @@ -36,6 +36,7 @@ module QA # @param [<RSpec::Core::ExampleGroup, RSpec::Core::Example>] example # @return [void] def set_skip_metadata(example) + return if Runtime::Scenario.attributes[:test_metadata_only] return skip_only(example.metadata) if example.metadata.key?(:only) return skip_except(example.metadata) if example.metadata.key?(:except) end diff --git a/qa/qa/support/formatters/test_stats_formatter.rb b/qa/qa/support/formatters/test_metrics_formatter.rb index 2cde2d0928e..e84373a487d 100644 --- a/qa/qa/support/formatters/test_stats_formatter.rb +++ b/qa/qa/support/formatters/test_metrics_formatter.rb @@ -1,9 +1,11 @@ # frozen_string_literal: true +require "active_support/core_ext/string/conversions" + module QA module Support module Formatters - class TestStatsFormatter < RSpec::Core::Formatters::BaseFormatter + class TestMetricsFormatter < RSpec::Core::Formatters::BaseFormatter include Support::InfluxdbTools RSpec::Core::Formatters.register(self, :stop) @@ -13,29 +15,43 @@ module QA # @param [RSpec::Core::Notifications::ExamplesNotification] notification # @return [void] def stop(notification) - push_test_stats(notification.examples) - push_fabrication_stats + return log(:warn, "Missing run_type, skipping metrics export!") unless run_type + + parse_execution_data(notification.examples) + + if Runtime::Env.export_metrics? + push_test_metrics + push_fabrication_metrics + end + + save_test_metrics if Runtime::Env.save_metrics_json? end private - # Push test execution stats to influxdb + # Save execution data for the run # # @param [Array<RSpec::Core::Example>] examples - # @return [void] - def push_test_stats(examples) - data = examples.map { |example| test_stats(example) }.compact + # @return [Array<Hash>] + def execution_data(examples = nil) + @execution_metrics ||= examples.map { |example| test_stats(example) }.compact + end + alias_method :parse_execution_data, :execution_data - write_api.write(data: data) - log(:debug, "Pushed #{data.length} test execution entries to influxdb") + # Push test execution metrics to influxdb + # + # @return [void] + def push_test_metrics + write_api.write(data: execution_data) + log(:debug, "Pushed #{execution_data.length} test execution entries to influxdb") rescue StandardError => e - log(:error, "Failed to push test execution stats to influxdb, error: #{e}") + log(:error, "Failed to push test execution metrics to influxdb, error: #{e}") end - # Push resource fabrication stats to influxdb + # Push resource fabrication metrics to influxdb # # @return [void] - def push_fabrication_stats + def push_fabrication_metrics data = Tools::TestResourceDataProcessor.resources.flat_map do |resource, values| values.map { |v| fabrication_stats(resource: resource, **v) } end @@ -44,7 +60,16 @@ module QA write_api.write(data: data) log(:debug, "Pushed #{data.length} resource fabrication entries to influxdb") rescue StandardError => e - log(:error, "Failed to push fabrication stats to influxdb, error: #{e}") + log(:error, "Failed to push fabrication metrics to influxdb, error: #{e}") + end + + # Save metrics in json file + # + # @return [void] + def save_test_metrics + File.write("tmp/test-metrics-#{env('CI_JOB_NAME_SLUG') || 'local'}.json", execution_data.to_json) + rescue StandardError => e + log(:error, "Failed to save test execution metrics, error: #{e}") end # Transform example to influxdb compatible metrics data @@ -57,21 +82,25 @@ module QA api_fabrication = ((example.metadata[:api_fabrication] || 0) * 1000).round ui_fabrication = ((example.metadata[:browser_ui_fabrication] || 0) * 1000).round + # do not export results for tests that are not compatible with environment + return if incompatible_env?(example) + { name: 'test-stats', time: time, tags: { name: example.full_description, file_path: file_path, - status: example.execution_result.status, + status: status(example), smoke: example.metadata.key?(:smoke).to_s, reliable: example.metadata.key?(:reliable).to_s, quarantined: quarantined(example.metadata), - retried: ((example.metadata[:retry_attempts] || 0) > 0).to_s, + retried: (retry_attempts(example.metadata) > 0).to_s, job_name: job_name, merge_request: merge_request, run_type: run_type, stage: devops_stage(file_path), + product_group: example.metadata[:product_group], testcase: example.metadata[:testcase] }, fields: { @@ -80,7 +109,7 @@ module QA api_fabrication: api_fabrication, ui_fabrication: ui_fabrication, total_fabrication: api_fabrication + ui_fabrication, - retry_attempts: example.metadata[:retry_attempts] || 0, + retry_attempts: retry_attempts(example.metadata), job_url: QA::Runtime::Env.ci_job_url, pipeline_url: env('CI_PIPELINE_URL'), pipeline_id: env('CI_PIPELINE_ID'), @@ -100,6 +129,7 @@ module QA # @param [Symbol] fabrication_method # @param [Symbol] http_method # @param [Integer] fabrication_time + # @param [String] timestamp # @return [Hash] def fabrication_stats(resource:, info:, fabrication_method:, http_method:, fabrication_time:, timestamp:, **) { @@ -135,7 +165,7 @@ module QA @time ||= begin return Time.now unless env('CI_PIPELINE_CREATED_AT') - DateTime.strptime(env('CI_PIPELINE_CREATED_AT')).to_time + env('CI_PIPELINE_CREATED_AT').to_time end end @@ -157,6 +187,39 @@ module QA (!Specs::Helpers::Quarantine.quarantined_different_context?(metadata[:quarantine])).to_s end + # Return a more detailed status + # + # - if test is failed or pending, return rspec status + # - if test passed but had more than 1 attempt, consider test flaky + # + # @param [RSpec::Core::Example] example + # @return [String] + def status(example) + rspec_status = example.execution_result.status + return rspec_status if [:pending, :failed].include?(rspec_status) + + retry_attempts(example.metadata) > 0 ? :flaky : :passed + end + + # Check if test was skipped due to context condition + # + # @param [RSpec::Core::Example] example + # @return [Boolean] + def incompatible_env?(example) + return false unless example.execution_result.status == :pending + return false unless example.metadata[:skip] + + !example.metadata[:skip].to_s.include?("quarantine") # rubocop:disable Rails/NegateInclude + end + + # Retry attempts + # + # @param [Hash] metadata + # @return [Integer] + def retry_attempts(metadata) + metadata[:retry_attempts] || 0 + end + # Print log message # # @param [Symbol] level diff --git a/qa/qa/support/influxdb_tools.rb b/qa/qa/support/influxdb_tools.rb index e53b843ca87..e817b096864 100644 --- a/qa/qa/support/influxdb_tools.rb +++ b/qa/qa/support/influxdb_tools.rb @@ -7,7 +7,11 @@ module QA # Common tools for use with influxdb metrics setup # module InfluxdbTools + # @return [String] bucket for storing all test run metrics INFLUX_TEST_METRICS_BUCKET = "e2e-test-stats" + # @return [String] bucket for storing metrics from main runs + INFLUX_MAIN_TEST_METRICS_BUCKET = "e2e-test-stats-main" + # @return [Array] live environment names LIVE_ENVS = %w[staging staging-canary staging-ref canary preprod production].freeze private diff --git a/qa/qa/support/loglinking.rb b/qa/qa/support/loglinking.rb index ceddd35da17..f24577ff313 100644 --- a/qa/qa/support/loglinking.rb +++ b/qa/qa/support/loglinking.rb @@ -9,15 +9,12 @@ module QA PRE_PROD_ADDRESS = 'https://pre.gitlab.com' SENTRY_ENVIRONMENTS = { staging: 'https://sentry.gitlab.net/gitlab/staginggitlabcom/?environment=gstg', - staging_canary: 'https://sentry.gitlab.net/gitlab/staginggitlabcom/?environment=gstg-cny', - staging_ref: 'https://sentry.gitlab.net/gitlab/staging-ref/?environment=gstg-ref', - pre: 'https://sentry.gitlab.net/gitlab/pregitlabcom/?environment=pre', - canary: 'https://sentry.gitlab.net/gitlab/gitlabcom/?environment=gprd', - production: 'https://sentry.gitlab.net/gitlab/gitlabcom/?environment=gprd-cny' + staging_ref: 'https://sentry.gitlab.net/gitlab/staging-ref/?environment=all', + pre: 'https://sentry.gitlab.net/gitlab/pregitlabcom/?environment=all', + production: 'https://sentry.gitlab.net/gitlab/gitlabcom/?environment=gprd' }.freeze KIBANA_ENVIRONMENTS = { staging: 'https://nonprod-log.gitlab.net/', - staging_canary: 'https://nonprod-log.gitlab.net/', canary: 'https://log.gprd.gitlab.net/', production: 'https://log.gprd.gitlab.net/' }.freeze @@ -30,7 +27,7 @@ module QA errors = ["Correlation Id: #{correlation_id}"] errors << "Sentry Url: #{sentry_uri}&query=correlation_id%3A%22#{correlation_id}%22" if sentry_uri - errors << "Kibana Url: #{kibana_uri}app/discover#/?_a=(query:(language:kuery,query:'json.correlation_id%20:%20#{correlation_id}'))&_g=(time:(from:now-24h%2Fh,to:now))" if kibana_uri + errors << "Kibana Url: #{kibana_uri}app/discover#/?_a=%28query%3A%28language%3Akuery%2Cquery%3A%27json.correlation_id%20%3A%20#{correlation_id}%27%29%29&_g=%28time%3A%28from%3Anow-24h%2Cto%3Anow%29%29" if kibana_uri errors.join("\n") end @@ -53,11 +50,11 @@ module QA case address when STAGING_ADDRESS - canary? ? :staging_canary : :staging + :staging when STAGING_REF_ADDRESS :staging_ref when PRODUCTION_ADDRESS - canary? ? :canary : :production + :production when PRE_PROD_ADDRESS :pre else @@ -68,19 +65,6 @@ module QA def self.logging_environment? !logging_environment.nil? end - - def self.cookies - browser_cookies = Capybara.current_session.driver.browser.manage.all_cookies - # rubocop:disable Rails/IndexBy - browser_cookies.each_with_object({}) do |cookie, memo| - memo[cookie[:name]] = cookie - end - # rubocop:enable Rails/IndexBy - end - - def self.canary? - cookies.dig('gitlab_canary', :value) == 'true' - end end end end diff --git a/qa/qa/support/page/logging.rb b/qa/qa/support/page/logging.rb index 6dfb348a347..79ea4a8d001 100644 --- a/qa/qa/support/page/logging.rb +++ b/qa/qa/support/page/logging.rb @@ -54,18 +54,25 @@ module QA elements end - def check_element(name, click_by_js = nil) - log("checking :#{highlight_element(name)}", :info) + def check_element(name, click_by_js = false, **kwargs) + log_by_js("checking", name, click_by_js, **kwargs) super end - def uncheck_element(name, click_by_js = nil) - log("unchecking :#{highlight_element(name)}", :info) + def uncheck_element(name, click_by_js = false, **kwargs) + log_by_js("unchecking", name, click_by_js, **kwargs) super end + def log_by_js(action, name, click_by_js, **kwargs) + msg = action + msg += " via JS" if click_by_js + msg += " :#{highlight_element(name)} with args #{kwargs}" + log(msg, :info) + end + def click_element_coordinates(name, **kwargs) log(%(clicking the coordinates of :#{highlight_element(name)}), :info) diff --git a/qa/qa/tools/ci/qa_changes.rb b/qa/qa/tools/ci/qa_changes.rb index 784923714d6..1ab93b6dfbf 100644 --- a/qa/qa/tools/ci/qa_changes.rb +++ b/qa/qa/tools/ci/qa_changes.rb @@ -10,7 +10,7 @@ module QA include Helpers QA_PATTERN = %r{^qa/}.freeze - SPEC_PATTERN = %r{^qa/qa/specs/features/}.freeze + SPEC_PATTERN = %r{^qa/qa/specs/features/\S+_spec\.rb}.freeze DEPENDENCY_PATTERN = Regexp.union( /_VERSION/, /Gemfile\.lock/, diff --git a/qa/qa/tools/ci/test_metrics.rb b/qa/qa/tools/ci/test_metrics.rb new file mode 100644 index 00000000000..96df432374a --- /dev/null +++ b/qa/qa/tools/ci/test_metrics.rb @@ -0,0 +1,52 @@ +# frozen_string_literal: true + +require "active_support/core_ext/string/conversions" + +module QA + module Tools + module Ci + class TestMetrics + include Helpers + include Support::InfluxdbTools + + def initialize(metrics_file_glob) + @metrics_file_glob = metrics_file_glob + end + + def self.export(metrics_file_glob) + new(metrics_file_glob).export + end + + # Export metrics to main bucket + # + # @return [void] + def export + return logger.warn("No files matched pattern '#{metrics_file_glob}'") if metrics_files.empty? + + logger.info("Exporting #{metrics_data.size} entries to influxdb") + influx_client.create_write_api.write(data: metrics_data, bucket: INFLUX_MAIN_TEST_METRICS_BUCKET) + end + + private + + attr_reader :metrics_file_glob + + # Metrics data files + # + # @return [Array] + def metrics_files + @metrics_files ||= Dir.glob(metrics_file_glob) + end + + # Test metrics data + # + # @return [Array<Hash>] + def metrics_data + @metrics_data ||= metrics_files + .flat_map { |file| JSON.parse(File.read(file), symbolize_names: true) } + .map { |entry| entry.merge(time: entry[:time].to_time) } + end + end + end + end +end diff --git a/qa/qa/tools/delete_subgroups.rb b/qa/qa/tools/delete_subgroups.rb index 355bd6bf10d..edf2f0ff5f0 100644 --- a/qa/qa/tools/delete_subgroups.rb +++ b/qa/qa/tools/delete_subgroups.rb @@ -1,70 +1,149 @@ # frozen_string_literal: true # This script deletes all subgroups of a group specified by ENV['TOP_LEVEL_GROUP_NAME'] +# # Required environment variables: GITLAB_QA_ACCESS_TOKEN and GITLAB_ADDRESS -# Optional environment variable: TOP_LEVEL_GROUP_NAME (defaults to 'gitlab-qa-sandbox-group') +# Optional environment variable: TOP_LEVEL_GROUP_NAME (defaults to 'gitlab-qa-sandbox-group-<current weekday #>') + +# Optional environment variable: PERMANENTLY_DELETE (defaults to false) +# Set PERMANENTLY_DELETE to true if you would like to permanently delete subgroups on an environment with +# deletion protection enabled. Otherwise, subgroups will remain available during the retention period specified +# in admin settings. On environments with deletion protection disabled, subgroups will always be permanently deleted. +# # Run `rake delete_subgroups` module QA module Tools class DeleteSubgroups include Support::API + include Ci::Helpers def initialize raise ArgumentError, "Please provide GITLAB_ADDRESS" unless ENV['GITLAB_ADDRESS'] raise ArgumentError, "Please provide GITLAB_QA_ACCESS_TOKEN" unless ENV['GITLAB_QA_ACCESS_TOKEN'] @api_client = Runtime::API::Client.new(ENV['GITLAB_ADDRESS'], personal_access_token: ENV['GITLAB_QA_ACCESS_TOKEN']) + @failed_deletion_attempts = [] end def run - $stdout.puts 'Fetching subgroups for deletion...' + group_id = fetch_group_id + return logger.info('Top level group not found') if group_id.nil? - sub_group_ids = fetch_subgroup_ids - $stdout.puts "\nNumber of Sub Groups not already marked for deletion: #{sub_group_ids.length}" + subgroups = fetch_subgroups(group_id) + return logger.info('No subgroups available') if subgroups.empty? - delete_subgroups(sub_group_ids) unless sub_group_ids.empty? - $stdout.puts "\nDone" - end + subgroups_marked_for_deletion = mark_for_deletion(subgroups) - private + if ENV['PERMANENTLY_DELETE'] && !subgroups_marked_for_deletion.empty? + delete_permanently(subgroups_marked_for_deletion) + end - def delete_subgroups(sub_group_ids) - $stdout.puts "Deleting #{sub_group_ids.length} subgroups..." - sub_group_ids.each do |subgroup_id| - request_url = Runtime::API::Request.new(@api_client, "/groups/#{subgroup_id}").url - path = parse_body(get(request_url))[:full_path] - $stdout.puts "\nDeleting subgroup #{path}..." + print_failed_deletion_attempts - delete_response = delete(request_url) - dot_or_f = delete_response.code == 202 ? "\e[32m.\e[0m" : "\e[31mF - #{delete_response}\e[0m" - print dot_or_f - end + logger.info('Done') end + private + def fetch_group_id + logger.info("Fetching top level group id...\n") + group_name = ENV['TOP_LEVEL_GROUP_NAME'] || "gitlab-qa-sandbox-group-#{Time.now.wday + 1}" group_search_response = get Runtime::API::Request.new(@api_client, "/groups/#{group_name}" ).url - JSON.parse(group_search_response.body)["id"] + JSON.parse(group_search_response.body)['id'] end - def fetch_subgroup_ids - group_id = fetch_group_id - sub_groups_ids = [] + def fetch_subgroups(group_id) + logger.info("Fetching subgroups...") + + api_path = "/groups/#{group_id}/subgroups" page_no = '1' + subgroups = [] - # When we reach the last page, the x-next-page header is a blank string while page_no.present? - $stdout.print '.' + subgroups_response = get Runtime::API::Request.new(@api_client, api_path, page: page_no, per_page: '100').url + subgroups.concat(JSON.parse(subgroups_response.body)) + + page_no = subgroups_response.headers[:x_next_page].to_s + end + + subgroups + end + + def subgroup_request(subgroup, **options) + Runtime::API::Request.new(@api_client, "/groups/#{subgroup['id']}", **options).url + end + + def process_response_and_subgroup(response, subgroup, opts = {}) + if response.code == 202 + logger.info("Success\n") + opts[:save_successes_to] << subgroup if opts[:save_successes_to] + else + logger.error("Failed - #{response}\n") + @failed_deletion_attempts << { path: subgroup['full_path'], response: response } + end + end + + def mark_for_deletion(subgroups) + subgroups_marked_for_deletion = [] + + logger.info("Marking #{subgroups.length} subgroups for deletion...\n") + + subgroups.each do |subgroup| + path = subgroup['full_path'] + + if subgroup['marked_for_deletion_on'].nil? + logger.info("Marking subgroup #{path} for deletion...") + response = delete(subgroup_request(subgroup)) - sub_groups_response = get Runtime::API::Request.new(@api_client, "/groups/#{group_id}/subgroups", page: page_no, per_page: '100').url - sub_groups_ids.concat(JSON.parse(sub_groups_response.body) - .reject { |subgroup| !subgroup["marked_for_deletion_on"].nil? }.map { |subgroup| subgroup['id'] }) + process_response_and_subgroup(response, subgroup, save_successes_to: subgroups_marked_for_deletion) + else + logger.info("Subgroup #{path} already marked for deletion\n") + subgroups_marked_for_deletion << subgroup + end + end + + subgroups_marked_for_deletion + end - page_no = sub_groups_response.headers[:x_next_page].to_s + def subgroup_exists?(subgroup) + response = get(subgroup_request(subgroup)) + + if response.code == 404 + logger.info("Subgroup #{subgroup['full_path']} is no longer available\n") + false + else + true end + end - sub_groups_ids.uniq + def delete_permanently(subgroups) + logger.info("Permanently deleting #{subgroups.length} subgroups...\n") + + subgroups.each do |subgroup| + path = subgroup['full_path'] + + next unless subgroup_exists?(subgroup) + + logger.info("Permanently deleting subgroup #{path}...") + delete_subgroup_response = delete(subgroup_request(subgroup, { permanently_remove: true, full_path: path })) + + process_response_and_subgroup(delete_subgroup_response, subgroup) + end + end + + def print_failed_deletion_attempts + if @failed_deletion_attempts.empty? + logger.info('No failed deletion attempts to report!') + else + logger.info("There were #{@failed_deletion_attempts.length} failed deletion attempts:\n") + + @failed_deletion_attempts.each do |attempt| + logger.info("Subgroup: #{attempt[:path]}") + logger.error("Response: #{attempt[:response]}\n") + end + end end end end diff --git a/qa/spec/resource/api_fabricator_spec.rb b/qa/spec/resource/api_fabricator_spec.rb index 581236e5ac5..4cb6ef3c9b5 100644 --- a/qa/spec/resource/api_fabricator_spec.rb +++ b/qa/spec/resource/api_fabricator_spec.rb @@ -155,8 +155,8 @@ RSpec.describe QA::Resource::ApiFabricator do expect(error.to_s).to eql(<<~ERROR.chomp) Fabrication of FooBarResource using the API failed (400) with `#{raw_post}`. Correlation Id: foobar - Sentry Url: https://sentry.gitlab.net/gitlab/staginggitlabcom/?environment=gstg-cny&query=correlation_id%3A%22foobar%22 - Kibana Url: https://nonprod-log.gitlab.net/app/discover#/?_a=(query:(language:kuery,query:'json.correlation_id%20:%20foobar'))&_g=(time:(from:now-24h%2Fh,to:now)) + Sentry Url: https://sentry.gitlab.net/gitlab/staginggitlabcom/?environment=gstg&query=correlation_id%3A%22foobar%22 + Kibana Url: https://nonprod-log.gitlab.net/app/discover#/?_a=%28query%3A%28language%3Akuery%2Cquery%3A%27json.correlation_id%20%3A%20foobar%27%29%29&_g=%28time%3A%28from%3Anow-24h%2Cto%3Anow%29%29 ERROR end end diff --git a/qa/spec/resource/base_spec.rb b/qa/spec/resource/base_spec.rb index 195e497f290..0ec27da7277 100644 --- a/qa/spec/resource/base_spec.rb +++ b/qa/spec/resource/base_spec.rb @@ -87,12 +87,46 @@ RSpec.describe QA::Resource::Base do end context 'when resource supports fabrication via the API' do - it 'calls .fabricate_via_browser_ui!' do + it 'calls .fabricate_via_api!!' do expect(described_class).to receive(:fabricate_via_api!) described_class.fabricate! end end + + context 'when FIPS mode is enabled' do + before do + stub_env('FIPS', '1') + end + + it 'calls .fabricate_via_browser_ui!' do + expect(described_class).to receive(:fabricate_via_browser_ui!) + + described_class.fabricate! + end + end + end + + describe '.fabricate_via_api_unless_fips!' do + context 'when FIPS mode is not enabled' do + it 'calls .fabricate_via_api!!' do + expect(described_class).to receive(:fabricate_via_api!) + + described_class.fabricate_via_api_unless_fips! + end + end + + context 'when FIPS mode is enabled' do + before do + stub_env('FIPS', '1') + end + + it 'calls .fabricate_via_browser_ui!' do + expect(described_class).to receive(:fabricate_via_browser_ui!) + + described_class.fabricate_via_api_unless_fips! + end + end end describe '.fabricate_via_api!' do diff --git a/qa/spec/resource/user_spec.rb b/qa/spec/resource/user_spec.rb index d82dcc3b21e..d1fc02ff033 100644 --- a/qa/spec/resource/user_spec.rb +++ b/qa/spec/resource/user_spec.rb @@ -116,4 +116,31 @@ RSpec.describe QA::Resource::User do expect(subject).to be_credentials_given end end + + describe '#has_user?' do + let(:index_mock) do + instance_double(QA::Page::Admin::Overview::Users::Index) + end + + users = [ + ['foo', true], + ['bar', false] + ] + + users.each do |(username, found)| + it "returns #{found} when has_username returns #{found}" do + subject.username = username + + allow(QA::Flow::Login).to receive(:while_signed_in_as_admin).and_yield + allow(QA::Page::Main::Menu).to receive(:perform) + allow(QA::Page::Admin::Menu).to receive(:perform) + allow(QA::Page::Admin::Overview::Users::Index).to receive(:perform).and_yield(index_mock) + + expect(index_mock).to receive(:search_user).with(username) + expect(index_mock).to receive(:has_username?).with(username).and_return(found) + + expect(subject.has_user?(subject)).to eq(found) + end + end + end end diff --git a/qa/spec/specs/runner_spec.rb b/qa/spec/specs/runner_spec.rb index dd013497367..cbe5699a306 100644 --- a/qa/spec/specs/runner_spec.rb +++ b/qa/spec/specs/runner_spec.rb @@ -111,7 +111,7 @@ RSpec.describe QA::Specs::Runner do it 'sets the `--dry-run` flag' do expect_rspec_runner_arguments( - ['--dry-run'] + DEFAULT_SKIPPED_TAGS + ['--tag', '~geo', *described_class::DEFAULT_TEST_PATH_ARGS], + ['--dry-run', *described_class::DEFAULT_TEST_PATH_ARGS], [$stderr, anything] ) diff --git a/qa/spec/support/formatters/test_stats_formatter_spec.rb b/qa/spec/support/formatters/test_metrics_formatter_spec.rb index d0d89b5ee73..76bde98cc33 100644 --- a/qa/spec/support/formatters/test_stats_formatter_spec.rb +++ b/qa/spec/support/formatters/test_metrics_formatter_spec.rb @@ -3,7 +3,7 @@ require 'rspec/core/sandbox' require 'active_support/testing/time_helpers' -describe QA::Support::Formatters::TestStatsFormatter do +describe QA::Support::Formatters::TestMetricsFormatter do include QA::Support::Helpers::StubEnv include QA::Specs::Helpers::RSpec include ActiveSupport::Testing::TimeHelpers @@ -28,6 +28,7 @@ describe QA::Support::Formatters::TestStatsFormatter do let(:api_fabrication) { 0 } let(:fabrication_resources) { {} } let(:testcase) { 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/1234' } + let(:product_group) { nil } let(:influx_client_args) do { @@ -53,10 +54,11 @@ describe QA::Support::Formatters::TestStatsFormatter do merge_request: 'false', run_type: run_type, stage: stage.match(%r{\d{1,2}_(\w+)}).captures.first, + product_group: product_group, testcase: testcase }, fields: { - id: './spec/support/formatters/test_stats_formatter_spec.rb[1:1]', + id: './spec/support/formatters/test_metrics_formatter_spec.rb[1:1]', run_time: 0, api_fabrication: api_fabrication * 1000, ui_fabrication: ui_fabrication * 1000, @@ -131,6 +133,7 @@ describe QA::Support::Formatters::TestStatsFormatter do stub_env('CI_MERGE_REQUEST_IID', nil) stub_env('TOP_UPSTREAM_MERGE_REQUEST_IID', nil) stub_env('QA_RUN_TYPE', run_type) + stub_env('QA_EXPORT_TEST_METRICS', "true") end context 'with reliable spec' do @@ -146,6 +149,19 @@ describe QA::Support::Formatters::TestStatsFormatter do end end + context 'with product group tag' do + let(:product_group) { :import } + + it 'exports data to influxdb with correct reliable tag' do + run_spec do + it('spec', product_group: :import, testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/1234') {} + end + + expect(influx_write_api).to have_received(:write).once + expect(influx_write_api).to have_received(:write).with(data: [data]) + end + end + context 'with smoke spec' do let(:smoke) { 'true' } @@ -189,6 +205,20 @@ describe QA::Support::Formatters::TestStatsFormatter do end end + context 'with skipped spec' do + it 'skips export' do + run_spec do + it( + 'spec', + skip: 'not compatible', + testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/1234' + ) {} + end + + expect(influx_write_api).to have_received(:write).with(data: []) + end + end + context 'with staging full run' do let(:run_type) { 'staging-full' } @@ -286,5 +316,21 @@ describe QA::Support::Formatters::TestStatsFormatter do expect(influx_write_api).to have_received(:write).with(data: [fabrication_data]) end end + + context 'with persisting metrics' do + before do + stub_env('QA_EXPORT_TEST_METRICS', "false") + stub_env('QA_SAVE_TEST_METRICS', "true") + stub_env('CI_JOB_NAME_SLUG', "test-job") + + allow(File).to receive(:write) + end + + it 'saves test metrics as json files' do + run_spec + + expect(File).to have_received(:write).with("tmp/test-metrics-test-job.json", [data].to_json) + end + end end end diff --git a/qa/spec/support/loglinking_spec.rb b/qa/spec/support/loglinking_spec.rb index d1cc76bccc4..10865068e3d 100644 --- a/qa/spec/support/loglinking_spec.rb +++ b/qa/spec/support/loglinking_spec.rb @@ -29,7 +29,7 @@ RSpec.describe QA::Support::Loglinking do expect(QA::Support::Loglinking.failure_metadata('foo123')).to eql(<<~ERROR.chomp) Correlation Id: foo123 - Kibana Url: https://kibana.address/app/discover#/?_a=(query:(language:kuery,query:'json.correlation_id%20:%20foo123'))&_g=(time:(from:now-24h%2Fh,to:now)) + Kibana Url: https://kibana.address/app/discover#/?_a=%28query%3A%28language%3Akuery%2Cquery%3A%27json.correlation_id%20%3A%20foo123%27%29%29&_g=%28time%3A%28from%3Anow-24h%2Cto%3Anow%29%29 ERROR end end @@ -39,11 +39,9 @@ RSpec.describe QA::Support::Loglinking do let(:url_hash) do { :staging => 'https://sentry.gitlab.net/gitlab/staginggitlabcom/?environment=gstg', - :staging_canary => 'https://sentry.gitlab.net/gitlab/staginggitlabcom/?environment=gstg-cny', - :staging_ref => 'https://sentry.gitlab.net/gitlab/staging-ref/?environment=gstg-ref', - :pre => 'https://sentry.gitlab.net/gitlab/pregitlabcom/?environment=pre', - :canary => 'https://sentry.gitlab.net/gitlab/gitlabcom/?environment=gprd', - :production => 'https://sentry.gitlab.net/gitlab/gitlabcom/?environment=gprd-cny', + :staging_ref => 'https://sentry.gitlab.net/gitlab/staging-ref/?environment=all', + :pre => 'https://sentry.gitlab.net/gitlab/pregitlabcom/?environment=all', + :production => 'https://sentry.gitlab.net/gitlab/gitlabcom/?environment=gprd', :foo => nil, nil => nil } @@ -62,10 +60,7 @@ RSpec.describe QA::Support::Loglinking do let(:url_hash) do { :staging => 'https://nonprod-log.gitlab.net/', - :staging_canary => 'https://nonprod-log.gitlab.net/', :staging_ref => nil, - :pre => nil, - :canary => 'https://log.gprd.gitlab.net/', :production => 'https://log.gprd.gitlab.net/', :foo => nil, nil => nil @@ -90,37 +85,22 @@ RSpec.describe QA::Support::Loglinking do [ { address: staging_address, - canary: false, expected_env: :staging }, { - address: staging_address, - canary: true, - expected_env: :staging_canary - }, - { address: staging_ref_address, - canary: true, expected_env: :staging_ref }, { address: production_address, - canary: false, expected_env: :production }, { - address: production_address, - canary: true, - expected_env: :canary - }, - { address: pre_prod_address, - canary: true, expected_env: :pre }, { address: 'https://foo.com', - canary: true, expected_env: nil } ] @@ -129,7 +109,6 @@ RSpec.describe QA::Support::Loglinking do it 'returns logging environment if environment found' do logging_env_array.each do |logging_env_hash| allow(QA::Runtime::Scenario).to receive(:attributes).and_return({ gitlab_address: logging_env_hash[:address] }) - allow(QA::Support::Loglinking).to receive(:canary?).and_return(logging_env_hash[:canary]) expect(QA::Support::Loglinking.logging_environment).to eq(logging_env_hash[:expected_env]) end @@ -151,37 +130,4 @@ RSpec.describe QA::Support::Loglinking do end end end - - describe '.cookies' do - let(:cookies) { [{ name: 'Foo', value: 'Bar' }, { name: 'gitlab_canary', value: 'true' }] } - - it 'returns browser cookies' do - allow(Capybara.current_session).to receive_message_chain(:driver, :browser, :manage, :all_cookies).and_return(cookies) - - expect(QA::Support::Loglinking.cookies).to eq({ "Foo" => { name: "Foo", value: "Bar" }, "gitlab_canary" => { name: "gitlab_canary", value: "true" } }) - end - end - - describe '.canary?' do - context 'gitlab_canary cookie is present' do - it 'and true returns true' do - allow(QA::Support::Loglinking).to receive(:cookies).and_return({ 'gitlab_canary' => { name: 'gitlab_canary', value: 'true' } }) - - expect(QA::Support::Loglinking.canary?).to eq(true) - end - - it 'and not true returns false' do - allow(QA::Support::Loglinking).to receive(:cookies).and_return({ 'gitlab_canary' => { name: 'gitlab_canary', value: 'false' } }) - - expect(QA::Support::Loglinking.canary?).to eq(false) - end - end - context 'gitlab_canary cookie is not present' do - it 'returns false' do - allow(QA::Support::Loglinking).to receive(:cookies).and_return({ 'foo' => { name: 'foo', path: '/pathname' } }) - - expect(QA::Support::Loglinking.canary?).to eq(false) - end - end - end end diff --git a/qa/spec/support/repeater_spec.rb b/qa/spec/support/repeater_spec.rb index 96e780fc9bd..9810456321e 100644 --- a/qa/spec/support/repeater_spec.rb +++ b/qa/spec/support/repeater_spec.rb @@ -1,17 +1,23 @@ # frozen_string_literal: true require 'active_support/core_ext/integer/time' +require 'active_support/testing/time_helpers' RSpec.describe QA::Support::Repeater do + include ActiveSupport::Testing::TimeHelpers + subject do Module.new do extend QA::Support::Repeater end end - let(:time_start) { Time.now } let(:return_value) { "test passed" } + after do + travel_back + end + describe '.repeat_until' do context 'when raise_on_failure is not provided (default: true)' do context 'when retry_on_exception is not provided (default: false)' do @@ -19,12 +25,7 @@ RSpec.describe QA::Support::Repeater do context 'when max duration is reached' do it 'raises an exception with default message' do expect do - Timecop.freeze do - subject.repeat_until(max_duration: 1) do - Timecop.travel(2) - false - end - end + subject.repeat_until(max_duration: 1) { travel(2.seconds) && false } end.to raise_error(QA::Support::Repeater::WaitExceededError, "Wait failed after 1 second") end @@ -32,12 +33,7 @@ RSpec.describe QA::Support::Repeater do message = 'Some custom action' expect do - Timecop.freeze do - subject.repeat_until(max_duration: 1, message: message) do - Timecop.travel(2) - false - end - end + subject.repeat_until(max_duration: 1, message: message) { travel(2.seconds) && false } end.to raise_error(QA::Support::Repeater::WaitExceededError, "#{message} failed after 1 second") end @@ -45,16 +41,14 @@ RSpec.describe QA::Support::Repeater do loop_counter = 0 expect( - Timecop.freeze do - subject.repeat_until(max_duration: 1) do - loop_counter += 1 - - if loop_counter > 3 - Timecop.travel(1) - return_value - else - false - end + subject.repeat_until(max_duration: 1) do + loop_counter += 1 + + if loop_counter > 3 + travel(1.second) + return_value + else + false end end ).to eq(return_value) @@ -64,13 +58,7 @@ RSpec.describe QA::Support::Repeater do context 'when max duration is not reached' do it 'returns value from block' do - Timecop.freeze(time_start) do - expect( - subject.repeat_until(max_duration: 1) do - return_value - end - ).to eq(return_value) - end + expect(subject.repeat_until(max_duration: 10) { return_value }).to eq(return_value) end end end @@ -78,41 +66,31 @@ RSpec.describe QA::Support::Repeater do context 'when max_attempts is provided' do context 'when max_attempts is reached' do it 'raises an exception with default message' do - expect do - Timecop.freeze do - subject.repeat_until(max_attempts: 1) do - false - end - end - end.to raise_error(QA::Support::Repeater::RetriesExceededError, "Retry failed after 1 attempt") + expect { subject.repeat_until(max_attempts: 1) { false } }.to raise_error( + QA::Support::Repeater::RetriesExceededError, "Retry failed after 1 attempt" + ) end it 'raises an exception with custom message' do message = 'Some custom action' - expect do - Timecop.freeze do - subject.repeat_until(max_attempts: 1, message: message) do - false - end - end - end.to raise_error(QA::Support::Repeater::RetriesExceededError, "#{message} failed after 1 attempt") + expect { subject.repeat_until(max_attempts: 1, message: message) { false } }.to raise_error( + QA::Support::Repeater::RetriesExceededError, "#{message} failed after 1 attempt" + ) end it 'ignores duration' do loop_counter = 0 expect( - Timecop.freeze do - subject.repeat_until(max_attempts: 2) do - loop_counter += 1 - Timecop.travel(1.year) - - if loop_counter > 1 - return_value - else - false - end + subject.repeat_until(max_attempts: 2) do + loop_counter += 1 + travel(1.year) + + if loop_counter > 1 + return_value + else + false end end ).to eq(return_value) @@ -122,13 +100,7 @@ RSpec.describe QA::Support::Repeater do context 'when max_attempts is not reached' do it 'returns value from block' do - expect( - Timecop.freeze do - subject.repeat_until(max_attempts: 1) do - return_value - end - end - ).to eq(return_value) + expect(subject.repeat_until(max_attempts: 1) { return_value }).to eq(return_value) end end end @@ -136,31 +108,17 @@ RSpec.describe QA::Support::Repeater do context 'when both max_attempts and max_duration are provided' do context 'when max_attempts is reached first' do it 'raises an exception' do - loop_counter = 0 - expect do - Timecop.freeze do - subject.repeat_until(max_attempts: 1, max_duration: 2) do - loop_counter += 1 - Timecop.travel(time_start + loop_counter) - false - end - end - end.to raise_error(QA::Support::Repeater::RetriesExceededError, "Retry failed after 1 attempt") + expect { subject.repeat_until(max_attempts: 1, max_duration: 2) { false } }.to( + raise_error(QA::Support::Repeater::RetriesExceededError, "Retry failed after 1 attempt") + ) end end context 'when max_duration is reached first' do it 'raises an exception' do - loop_counter = 0 - expect do - Timecop.freeze do - subject.repeat_until(max_attempts: 2, max_duration: 1) do - loop_counter += 1 - Timecop.travel(time_start + loop_counter) - false - end - end - end.to raise_error(QA::Support::Repeater::WaitExceededError, "Wait failed after 1 second") + expect { subject.repeat_until(max_attempts: 2, max_duration: 1) { travel(10.seconds) && false } }.to( + raise_error(QA::Support::Repeater::WaitExceededError, "Wait failed after 1 second") + ) end end end @@ -169,30 +127,26 @@ RSpec.describe QA::Support::Repeater do context 'when retry_on_exception is true' do context 'when max duration is reached' do it 'raises an exception' do - Timecop.freeze do - expect do - subject.repeat_until(max_duration: 1, retry_on_exception: true) do - Timecop.travel(2) + expect do + subject.repeat_until(max_duration: 1, retry_on_exception: true) do + travel(10.seconds) - raise "this should be raised" - end - end.to raise_error(RuntimeError, "this should be raised") - end + raise "this should be raised" + end + end.to raise_error(RuntimeError, "this should be raised") end it 'does not raise an exception until max_duration is reached' do loop_counter = 0 - Timecop.freeze(time_start) do - expect do - subject.repeat_until(max_duration: 2, retry_on_exception: true) do - loop_counter += 1 - Timecop.travel(time_start + loop_counter) + expect do + subject.repeat_until(max_duration: 5, retry_on_exception: true) do + loop_counter += 1 + travel(10.seconds) if loop_counter == 2 - raise "this should be raised" - end - end.to raise_error(RuntimeError, "this should be raised") - end + raise "this should be raised" + end + end.to raise_error(RuntimeError, "this should be raised") expect(loop_counter).to eq(2) end end @@ -201,53 +155,18 @@ RSpec.describe QA::Support::Repeater do it 'returns value from block' do loop_counter = 0 - Timecop.freeze(time_start) do - expect( - subject.repeat_until(max_duration: 3, retry_on_exception: true) do - loop_counter += 1 - Timecop.travel(time_start + loop_counter) + expect( + subject.repeat_until(max_duration: 3, retry_on_exception: true) do + loop_counter += 1 - raise "this should not be raised" if loop_counter == 1 + raise "this should not be raised" if loop_counter == 1 - return_value - end - ).to eq(return_value) - end + return_value + end + ).to eq(return_value) expect(loop_counter).to eq(2) end end - - context 'when both max_attempts and max_duration are provided' do - context 'when max_attempts is reached first' do - it 'raises an exception' do - loop_counter = 0 - expect do - Timecop.freeze do - subject.repeat_until(max_attempts: 1, max_duration: 2, retry_on_exception: true) do - loop_counter += 1 - Timecop.travel(time_start + loop_counter) - false - end - end - end.to raise_error(QA::Support::Repeater::RetriesExceededError, "Retry failed after 1 attempt") - end - end - - context 'when max_duration is reached first' do - it 'raises an exception' do - loop_counter = 0 - expect do - Timecop.freeze do - subject.repeat_until(max_attempts: 2, max_duration: 1, retry_on_exception: true) do - loop_counter += 1 - Timecop.travel(time_start + loop_counter) - false - end - end - end.to raise_error(QA::Support::Repeater::WaitExceededError, "Wait failed after 1 second") - end - end - end end end @@ -255,11 +174,9 @@ RSpec.describe QA::Support::Repeater do context 'when retry_on_exception is not provided (default: false)' do context 'when max duration is reached' do def test_wait - Timecop.freeze do - subject.repeat_until(max_duration: 1, raise_on_failure: false) do - Timecop.travel(2) - return_value - end + subject.repeat_until(max_duration: 1, raise_on_failure: false) do + travel(10.seconds) + return_value end end @@ -274,23 +191,15 @@ RSpec.describe QA::Support::Repeater do context 'when max duration is not reached' do it 'returns the value from the block' do - Timecop.freeze do - expect( - subject.repeat_until(max_duration: 1, raise_on_failure: false) do - return_value - end - ).to eq(return_value) - end + expect(subject.repeat_until(max_duration: 10, raise_on_failure: false) { return_value }).to eq(return_value) end it 'raises an exception' do - Timecop.freeze do - expect do - subject.repeat_until(max_duration: 1, raise_on_failure: false) do - raise "this should be raised" - end - end.to raise_error(RuntimeError, "this should be raised") - end + expect do + subject.repeat_until(max_duration: 10, raise_on_failure: false) do + raise "this should be raised" + end + end.to raise_error(RuntimeError, "this should be raised") end end @@ -300,12 +209,10 @@ RSpec.describe QA::Support::Repeater do loop_counter = 0 expect( - Timecop.freeze do - subject.repeat_until(max_attempts: max_attempts, max_duration: max_duration, raise_on_failure: false) do - loop_counter += 1 - Timecop.travel(time_start + loop_counter) - false - end + subject.repeat_until(max_attempts: max_attempts, max_duration: max_duration, raise_on_failure: false) do + loop_counter += 1 + travel(max_attempts.seconds) + false end ).to eq(false) expect(loop_counter).to eq(1) @@ -313,7 +220,7 @@ RSpec.describe QA::Support::Repeater do end context 'when max_attempts is reached first' do - it_behaves_like 'repeat until', max_attempts: 1, max_duration: 2 + it_behaves_like 'repeat until', max_attempts: 1, max_duration: 10 end context 'when max_duration is reached first' do @@ -325,11 +232,9 @@ RSpec.describe QA::Support::Repeater do context 'when retry_on_exception is true' do context 'when max duration is reached' do def test_wait - Timecop.freeze do - subject.repeat_until(max_duration: 1, raise_on_failure: false, retry_on_exception: true) do - Timecop.travel(2) - return_value - end + subject.repeat_until(max_duration: 1, raise_on_failure: false, retry_on_exception: true) do + travel(10.seconds) + return_value end end @@ -341,61 +246,6 @@ RSpec.describe QA::Support::Repeater do expect(test_wait).to eq(return_value) end end - - context 'when max duration is not reached' do - before do - @loop_counter = 0 - end - - def test_wait_with_counter - Timecop.freeze(time_start) do - subject.repeat_until(max_duration: 3, raise_on_failure: false, retry_on_exception: true) do - @loop_counter += 1 - Timecop.travel(time_start + @loop_counter) - - raise "this should not be raised" if @loop_counter == 1 - - return_value - end - end - end - - it 'does not raise an exception' do - expect { test_wait_with_counter }.not_to raise_error - end - - it 'returns the value from the block' do - expect(test_wait_with_counter).to eq(return_value) - expect(@loop_counter).to eq(2) - end - end - - context 'when both max_attempts and max_duration are provided' do - shared_examples 'repeat until' do |max_attempts:, max_duration:| - it "returns when #{max_attempts < max_duration ? 'max_attempts' : 'max_duration'} is reached" do - loop_counter = 0 - - expect( - Timecop.freeze do - subject.repeat_until(max_attempts: max_attempts, max_duration: max_duration, raise_on_failure: false, retry_on_exception: true) do - loop_counter += 1 - Timecop.travel(time_start + loop_counter) - false - end - end - ).to eq(false) - expect(loop_counter).to eq(1) - end - end - - context 'when max_attempts is reached first' do - it_behaves_like 'repeat until', max_attempts: 1, max_duration: 2 - end - - context 'when max_duration is reached first' do - it_behaves_like 'repeat until', max_attempts: 2, max_duration: 1 - end - end end end diff --git a/qa/spec/tools/ci/qa_changes_spec.rb b/qa/spec/tools/ci/qa_changes_spec.rb index d93d3cd9258..778a0ad33bb 100644 --- a/qa/spec/tools/ci/qa_changes_spec.rb +++ b/qa/spec/tools/ci/qa_changes_spec.rb @@ -49,6 +49,14 @@ RSpec.describe QA::Tools::Ci::QaChanges do end end + context "with shared example changes" do + let(:mr_diff) { [{ path: "qa/qa/specs/features/shared_context/some_context.rb", diff: "" }] } + + it ".qa_tests do not return specific specs" do + expect(qa_changes.qa_tests).to be_nil + end + end + context "with non qa changes" do let(:mr_diff) { [{ path: "Gemfile" }] } diff --git a/qa/spec/tools/ci/test_metrics_spec.rb b/qa/spec/tools/ci/test_metrics_spec.rb new file mode 100644 index 00000000000..4c1c4092d15 --- /dev/null +++ b/qa/spec/tools/ci/test_metrics_spec.rb @@ -0,0 +1,54 @@ +# frozen_string_literal: true + +RSpec.describe QA::Tools::Ci::TestMetrics do + include QA::Support::Helpers::StubEnv + + let(:influx_client) { instance_double("InfluxDB2::Client", create_write_api: influx_write_api) } + let(:influx_write_api) { instance_double("InfluxDB2::WriteApi", write: nil) } + let(:logger) { instance_double("Logger", info: true, warn: true) } + + let(:glob) { "metrics_glob/*.json" } + let(:paths) { ["/metrics_glob/metrics.json"] } + let(:timestamp) { "2022-11-11 07:54:11 +0000" } + let(:metrics_json) { metrics_data.to_json } + + let(:metrics_data) do + [ + { + time: timestamp.to_time, + name: "name", + tags: {}, + fields: {} + } + ] + end + + before do + allow(InfluxDB2::Client).to receive(:new) { influx_client } + allow(Gitlab::QA::TestLogger).to receive(:logger) { logger } + allow(Dir).to receive(:glob).with(glob) { paths } + allow(File).to receive(:read).with(paths.first) { metrics_json } + + stub_env('QA_INFLUXDB_URL', "test") + stub_env('QA_INFLUXDB_TOKEN', "test") + end + + context "with metrics files present" do + it "exports saved metrics to influxdb" do + described_class.export(glob) + + expect(influx_write_api).to have_received(:write).with(data: metrics_data, bucket: "e2e-test-stats-main") + end + end + + context "without metrics files present" do + let(:paths) { [] } + + it "exits without error" do + described_class.export(glob) + + expect(influx_write_api).not_to have_received(:write) + expect(logger).to have_received(:warn).with("No files matched pattern '#{glob}'") + end + end +end diff --git a/qa/spec/tools/test_resources_data_processor_spec.rb b/qa/spec/tools/test_resources_data_processor_spec.rb index 2ae43974a0c..73fc2f6e853 100644 --- a/qa/spec/tools/test_resources_data_processor_spec.rb +++ b/qa/spec/tools/test_resources_data_processor_spec.rb @@ -1,7 +1,5 @@ # frozen_string_literal: true - require 'active_support/testing/time_helpers' - RSpec.describe QA::Tools::TestResourceDataProcessor do include QA::Support::Helpers::StubEnv include ActiveSupport::Testing::TimeHelpers diff --git a/qa/tasks/ci.rake b/qa/tasks/ci.rake index 435fe8ebb77..84a26e3e555 100644 --- a/qa/tasks/ci.rake +++ b/qa/tasks/ci.rake @@ -1,9 +1,8 @@ # frozen_string_literal: true -require_relative "helpers/util" - -# rubocop:disable Rails/RakeEnvironment namespace :ci do + require_relative "helpers/util" + include Task::Helpers::Util desc "Detect changes and populate test variables for selective test execution and feature flag testing" @@ -23,18 +22,20 @@ namespace :ci do # skip running tests when only quarantine changes detected if qa_changes.quarantine_changes? logger.info(" merge request contains only quarantine changes, e2e test execution will be skipped!") - append_to_file(env_file, <<~TXT) - QA_SKIP_ALL_TESTS=true - TXT + append_to_file(env_file, "QA_SKIP_ALL_TESTS=true") next end - tests = qa_changes.qa_tests - if qa_changes.framework_changes? # run all tests when framework changes detected + run_all_label_present = mr_labels.include?("pipeline:run-all-e2e") + # on run-all label of framework changes do not infer specific tests + tests = run_all_label_present || qa_changes.framework_changes? ? nil : qa_changes.qa_tests + + if run_all_label_present + logger.info(" merge request has pipeline:run-all-e2e label, full test suite will be executed") + append_to_file(env_file, "QA_RUN_ALL_TESTS=true\n") + elsif qa_changes.framework_changes? # run all tests when framework changes detected logger.info(" merge request contains qa framework changes, full test suite will be executed") - append_to_file(env_file, <<~TXT) - QA_FRAMEWORK_CHANGES=true - TXT + append_to_file(env_file, "QA_FRAMEWORK_CHANGES=true\n") elsif tests logger.info(" detected following specs to execute: '#{tests}'") else @@ -44,20 +45,24 @@ namespace :ci do # always check all test suites in case a suite is defined but doesn't have any runnable specs suites = QA::Tools::Ci::NonEmptySuites.new(tests).fetch append_to_file(env_file, <<~TXT) - QA_TESTS='#{tests}' QA_SUITES='#{suites}' + QA_TESTS='#{tests}' TXT # check if mr contains feature flag changes feature_flags = QA::Tools::Ci::FfChanges.new(diff).fetch - append_to_file(env_file, <<~TXT) - QA_FEATURE_FLAGS='#{feature_flags}' - TXT + append_to_file(env_file, "QA_FEATURE_FLAGS='#{feature_flags}'") end desc "Download test results from downstream pipeline" task :download_test_results, [:trigger_name, :test_report_job_name, :report_path] do |_, args| QA::Tools::Ci::TestResults.get(args[:trigger_name], args[:test_report_job_name], args[:report_path]) end + + desc "Export test run metrics to influxdb" + task :export_test_metrics, [:glob] do |_, args| + raise("Metrics file glob pattern is required") unless args[:glob] + + QA::Tools::Ci::TestMetrics.export(args[:glob]) + end end -# rubocop:enable Rails/RakeEnvironment diff --git a/qa/tasks/knapsack.rake b/qa/tasks/knapsack.rake index c1225964aef..c502d1cbb4a 100644 --- a/qa/tasks/knapsack.rake +++ b/qa/tasks/knapsack.rake @@ -18,20 +18,20 @@ namespace :knapsack do desc "Download latest knapsack reports for parallel jobs" task :download, [:stage_name] do |_, args| test_stage_name = args[:stage_name] + knapsack_reports = ENV["QA_KNAPSACK_REPORTS"]&.split(",") + ci_token = ENV["QA_GITLAB_CI_TOKEN"] - # QA_KNAPSACK_REPORTS remains for changes to be backwards compatible - # TODO: remove and only use automated detection once changes are merged - unless ENV["QA_KNAPSACK_REPORTS"] || test_stage_name - QA::Runtime::Logger.warn("Missing QA_KNAPSACK_REPORTS environment variable or test stage name for autodetection") - next - end + reports = if knapsack_reports + knapsack_reports + else + unless ci_token + QA::Runtime::Logger.error("Missing QA_GITLAB_CI_TOKEN for automatically detecting parallel jobs") + next + end - reports = if test_stage_name QA::Support::ParallelPipelineJobs - .fetch(stage_name: test_stage_name, access_token: ENV["QA_GITLAB_CI_TOKEN"]) + .fetch(stage_name: test_stage_name, access_token: ci_token) .map { |job| job.tr(":", "-") } - else - ENV["QA_KNAPSACK_REPORTS"].split(",") end reports.each do |report_name| |