diff options
Diffstat (limited to 'qa')
254 files changed, 2645 insertions, 2087 deletions
diff --git a/qa/Dockerfile b/qa/Dockerfile index 213ec3450cb..92866ec66cc 100644 --- a/qa/Dockerfile +++ b/qa/Dockerfile @@ -49,6 +49,8 @@ COPY ./config/initializers/0_inject_enterprise_edition_module.rb /home/gitlab/co COPY ./config/feature_flags /home/gitlab/config/feature_flags COPY ./config/bundler_setup.rb /home/gitlab/config/ COPY ./lib/gitlab_edition.rb /home/gitlab/lib/ +COPY ./spec/support/fast_quarantine.rb /home/gitlab/spec/support/ +COPY ./tooling/lib/tooling/fast_quarantine.rb /home/gitlab/tooling/lib/tooling/ COPY ./INSTALLATION_TYPE ./VERSION /home/gitlab/ COPY ./qa /home/gitlab/qa diff --git a/qa/Gemfile b/qa/Gemfile index e9616f29731..8ad40ec12c2 100644 --- a/qa/Gemfile +++ b/qa/Gemfile @@ -2,8 +2,8 @@ source 'https://rubygems.org' -gem 'gitlab-qa', '~> 12', '>= 12.1.0', require: 'gitlab/qa' -gem 'gitlab_quality-test_tooling', '~> 0.8.3', require: false +gem 'gitlab-qa', '~> 12', '>= 12.2.1', require: 'gitlab/qa' +gem 'gitlab_quality-test_tooling', '~> 0.9.3', require: false gem 'gitlab-utils', path: '../gems/gitlab-utils' gem 'activesupport', '~> 7.0.5.1' # This should stay in sync with the root's Gemfile gem 'allure-rspec', '~> 2.20.0' @@ -24,7 +24,7 @@ gem 'rotp', '~> 6.2.2' gem 'parallel', '~> 1.23' gem 'rainbow', '~> 3.1.1' gem 'rspec-parameterized', '~> 1.0.0' -gem 'octokit', '~> 6.1.1' +gem 'octokit', '~> 7.0.0' gem "faraday-retry", "~> 2.2" gem 'zeitwerk', '~> 2.6', '>= 2.6.8' gem 'influxdb-client', '~> 2.9' @@ -36,14 +36,16 @@ gem "warning", "~> 1.3" gem 'confiner', '~> 0.4' -gem 'chemlab', '~> 0.10' +gem 'chemlab', '~> 0.11', '>= 0.11.1' gem 'chemlab-library-www-gitlab-com', '~> 0.1', '>= 0.1.1' # dependencies for jenkins client -gem 'nokogiri', '~> 1.15', '>= 1.15.3' +gem 'nokogiri', '~> 1.15', '>= 1.15.4' gem 'deprecation_toolkit', '~> 2.0.3', require: false +gem 'factory_bot', '~> 6.2.1' + group :development do gem 'pry-byebug', '~> 3.10.1', platform: :mri gem "ruby-debug-ide", "~> 0.7.3" diff --git a/qa/Gemfile.lock b/qa/Gemfile.lock index 521f101ee4d..67d64684aa1 100644 --- a/qa/Gemfile.lock +++ b/qa/Gemfile.lock @@ -56,7 +56,7 @@ GEM capybara-screenshot (1.0.26) capybara (>= 1.0, < 4) launchy - chemlab (0.10.0) + chemlab (0.11.1) colorize (~> 0.8) i18n (~> 1.8) rake (>= 12, < 14) @@ -80,6 +80,8 @@ GEM unf (>= 0.0.5, < 1.0.0) erubi (1.12.0) excon (0.92.4) + factory_bot (6.2.1) + activesupport (>= 5.0.0) faker (3.2.0) i18n (>= 1.8.11, < 2) faraday (2.5.2) @@ -119,7 +121,7 @@ GEM gitlab (4.19.0) httparty (~> 0.20) terminal-table (>= 1.5.1) - gitlab-qa (12.1.0) + gitlab-qa (12.2.1) activesupport (>= 6.1, < 7.1) gitlab (~> 4.19) http (~> 5.0) @@ -128,7 +130,7 @@ GEM rainbow (>= 3, < 4) table_print (= 1.5.7) zeitwerk (>= 2, < 3) - gitlab_quality-test_tooling (0.8.3) + gitlab_quality-test_tooling (0.9.3) activesupport (>= 6.1, < 7.1) gitlab (~> 4.19) http (~> 5.0) @@ -210,10 +212,10 @@ GEM multi_json (1.15.0) multi_xml (0.6.0) netrc (0.11.0) - nokogiri (1.15.3) + nokogiri (1.15.4) mini_portile2 (~> 2.8.2) racc (~> 1.4) - octokit (6.1.1) + octokit (7.0.0) faraday (>= 1, < 3) sawyer (~> 0.9) oj (3.13.23) @@ -340,21 +342,22 @@ DEPENDENCIES allure-rspec (~> 2.20.0) capybara (~> 3.39.2) capybara-screenshot (~> 1.0.26) - chemlab (~> 0.10) + chemlab (~> 0.11, >= 0.11.1) chemlab-library-www-gitlab-com (~> 0.1, >= 0.1.1) confiner (~> 0.4) deprecation_toolkit (~> 2.0.3) + factory_bot (~> 6.2.1) faker (~> 3.2) faraday-retry (~> 2.2) fog-core (= 2.1.0) fog-google (~> 1.19) - gitlab-qa (~> 12, >= 12.1.0) + gitlab-qa (~> 12, >= 12.2.1) gitlab-utils! - gitlab_quality-test_tooling (~> 0.8.3) + gitlab_quality-test_tooling (~> 0.9.3) influxdb-client (~> 2.9) knapsack (~> 4.0) - nokogiri (~> 1.15, >= 1.15.3) - octokit (~> 6.1.1) + nokogiri (~> 1.15, >= 1.15.4) + octokit (~> 7.0.0) parallel (~> 1.23) parallel_tests (~> 4.2, >= 4.2.1) pry-byebug (~> 3.10.1) @@ -374,4 +377,4 @@ DEPENDENCIES zeitwerk (~> 2.6, >= 2.6.8) BUNDLED WITH - 2.4.15 + 2.4.18 diff --git a/qa/README.md b/qa/README.md index d8670d4da02..c1b6794ca60 100644 --- a/qa/README.md +++ b/qa/README.md @@ -93,9 +93,9 @@ By default tests on CI use `info` log level. `debug` level is still available in ### Run the end-to-end tests in a local development environment -1. Follow the instructions to [install GDK](https://gitlab.com/gitlab-org/gitlab-development-kit/blob/main/doc/index.md), your local GitLab development environment. +First, follow the instructions to [install GDK](https://gitlab.com/gitlab-org/gitlab-development-kit/blob/main/doc/index.md) as your local GitLab development environment. -1. Navigate to the QA folder and run the following commands. +Then, navigate to the QA folder and run the following commands: ```bash cd gitlab-development-kit/gitlab/qa @@ -104,13 +104,13 @@ export WEBDRIVER_HEADLESS=false export GITLAB_INITIAL_ROOT_PASSWORD={your current root user's password} ``` -1. Most tests that do not require special setup could simply be run with the following command. However, tests that are tagged with `:orchestrated` tag require special setup. These tests can only be run with [bin/qa](https://gitlab.com/gitlab-org/gitlab/-/blob/master/qa/README.md#running-tests-with-a-custom-binqa-test-runner) script. +Finally, most tests that do not require special setup (or have the `:orchestrated` tag) can be run with the following command: ```bash bundle exec rspec <path/to/spec.rb> ``` -1. For test that are tagged with `:orchestrated`, [re-configure IP address in GDK](https://gitlab.com/gitlab-org/gitlab-qa/-/blob/master/docs/run_qa_against_gdk.md#run-qa-tests-against-your-gdk-setup) to run QA tests. Once you have reconfigured GDK, ensure GitLab is running successfully on the IP address configured, then run the following command: +However, tests that are tagged with the `:orchestrated` tag require special setup. To run these tests, first [re-configure the IP address in GDK](https://gitlab.com/gitlab-org/gitlab-qa/-/blob/master/docs/run_qa_against_gdk.md#run-qa-tests-against-your-gdk-setup), and then run the following command: ```bash bundle exec bin/qa Test::Instance::All {GDK IP ADDRESS} @@ -119,6 +119,21 @@ bundle exec bin/qa Test::Instance::All {GDK IP ADDRESS} - Note: If you want to run tests requiring SSH against GDK, you will need to [modify your GDK setup](https://gitlab.com/gitlab-org/gitlab-qa/blob/master/docs/run_qa_against_gdk.md). - Note: If this is your first time running GDK, you can use the password pre-set for `root`. [See supported GitLab environment variables](https://gitlab.com/gitlab-org/gitlab-qa/-/blob/master/docs/what_tests_can_be_run.md#supported-gitlab-environment-variables). If you have changed your `root` password, use that when exporting `GITLAB_INITIAL_ROOT_PASSWORD`. +#### Generic command for a typical GDK installation + +The following is an example command you can use if you have configured GDK to run on a specific IP address and port, with a username, password, and personal access token that aren't the defaults, and you would like the test framework to show debug logs: + +```bash +GITLAB_QA_ACCESS_TOKEN={GDK API PAT} \ +GITLAB_USERNAME={GDK USERNAME} \ +GITLAB_PASSWORD={GDK PASSWORD} \ +QA_LOG_LEVEL=DEBUG \ +QA_GITLAB_URL="http://{GDK IP ADDRESS}:{GDK PORT}" \ +bundle exec rspec <path/to/spec.rb> +``` + +For an explanation of the variables see the [additional examples below](#overriding-gitlab-address) and the [list of supported environment variables](https://gitlab.com/gitlab-org/gitlab-qa/blob/master/docs/what_tests_can_be_run.md#supported-environment-variables). + #### Run the end-to-end tests on GitLab in Docker GitLab can be [installed in Docker](https://docs.gitlab.com/ee/install/docker.html). diff --git a/qa/allure/categories.json b/qa/allure/categories.json new file mode 100644 index 00000000000..828dc02bddc --- /dev/null +++ b/qa/allure/categories.json @@ -0,0 +1,57 @@ +[ + { + "name": "Fabrication 404 failure", + "matchedStatuses": ["broken"], + "messageRegex": "^Fabrication of \\S+ .* failed \\\\(404\\\\).*" + }, + { + "name": "Fabrication 401 failure", + "matchedStatuses": ["broken"], + "messageRegex": "^Fabrication of \\S+ .* failed \\\\(401\\\\)*" + }, + { + "name": "Fabrication failure", + "matchedStatuses": ["broken"], + "messageRegex": "^Fabrication of \\S+ .* failed \\\\(\\d+\\\\).*" + }, + { + "name": "Element not found", + "matchedStatuses": ["broken"], + "messageRegex": "^(Unable to find css|\\S+ did not appear on).*" + }, + { + "name": "Runner did not start failure", + "matchedStatuses": ["broken"], + "messageRegex": "^Wait for runner '\\S+' to register in (group|project) '\\S+' failed.*" + }, + { + "name": "Click intercepted failure", + "matchedStatuses": ["broken"], + "messageRegex": ".*element click intercepted.*" + }, + { + "name": "Page did not fully load failure", + "matchedStatuses": ["broken"], + "messageRegex": "^Page did not fully load.*" + }, + { + "name": "Waiter failure", + "matchedStatuses": ["broken"], + "messageRegex": "^Wait failed after \\d+ seconds.*" + }, + { + "name": "Timeout failure", + "matchedStatuses": ["broken"], + "messageRegex": "^Timed out reading data from server.*" + }, + { + "name": "Ambiguous match failure", + "matchedStatuses": ["broken"], + "messageRegex": "Ambiguous match, found \\d+ elements.*" + }, + { + "name": "Page validation failure", + "matchedStatuses": ["broken"], + "messageRegex": "\\S+ did not appear on \\S+ as expected.*" + } +] diff --git a/qa/gdk/gdk.yml b/qa/gdk/gdk.yml index 649ac9a60c6..36bf901033c 100644 --- a/qa/gdk/gdk.yml +++ b/qa/gdk/gdk.yml @@ -18,6 +18,7 @@ gitlab: rails: bootsnap: false hostname: gdk.test + application_settings_cache_seconds: 0 gitlab_k8s_agent: enabled: false gitlab_pages: diff --git a/qa/lib/gitlab/page/admin/dashboard.rb b/qa/lib/gitlab/page/admin/dashboard.rb index f1a732f8fac..b6ae49a0e3b 100644 --- a/qa/lib/gitlab/page/admin/dashboard.rb +++ b/qa/lib/gitlab/page/admin/dashboard.rb @@ -8,7 +8,6 @@ module Gitlab h2 :users_in_license h2 :billable_users - h3 :number_of_users end end end diff --git a/qa/lib/gitlab/page/admin/dashboard.stub.rb b/qa/lib/gitlab/page/admin/dashboard.stub.rb index 820acf79b9b..da717558133 100644 --- a/qa/lib/gitlab/page/admin/dashboard.stub.rb +++ b/qa/lib/gitlab/page/admin/dashboard.stub.rb @@ -51,30 +51,6 @@ module Gitlab def billable_users? # This is a stub, used for indexing. The method is dynamically generated. end - - # @note Defined as +h3 :number_of_users+ - # @return [String] The text content or value of +number_of_users+ - def number_of_users - # This is a stub, used for indexing. The method is dynamically generated. - end - - # @example - # Gitlab::Page::Admin::Dashboard.perform do |dashboard| - # expect(dashboard.number_of_users_element).to exist - # end - # @return [Watir::H3] The raw +H3+ element - def number_of_users_element - # This is a stub, used for indexing. The method is dynamically generated. - end - - # @example - # Gitlab::Page::Admin::Dashboard.perform do |dashboard| - # expect(dashboard).to be_number_of_users - # end - # @return [Boolean] true if the +number_of_users+ element is present on the page - def number_of_users? - # This is a stub, used for indexing. The method is dynamically generated. - end end end end diff --git a/qa/lib/gitlab/page/admin/subscription.rb b/qa/lib/gitlab/page/admin/subscription.rb index 058cf8d281e..e19f0580007 100644 --- a/qa/lib/gitlab/page/admin/subscription.rb +++ b/qa/lib/gitlab/page/admin/subscription.rb @@ -12,15 +12,11 @@ module Gitlab label :terms_of_services, text: /I agree that/ button :remove_license button :confirm_remove_license - p :plan - p :started - p :name - p :company - p :email - h2 :billable_users - h2 :maximum_users + td :plan + td :name + td :company + td :email h2 :users_in_subscription - h2 :users_over_subscription table :subscription_history div :no_valid_license_alert, text: /no longer has a valid license/ diff --git a/qa/lib/gitlab/page/admin/subscription.stub.rb b/qa/lib/gitlab/page/admin/subscription.stub.rb index 56a063e8978..9ed127f9281 100644 --- a/qa/lib/gitlab/page/admin/subscription.stub.rb +++ b/qa/lib/gitlab/page/admin/subscription.stub.rb @@ -4,7 +4,7 @@ module Gitlab module Page module Admin module Subscription - # @note Defined as +h6 :subscription_details+ + # @note Defined as +div :subscription_details+ # @return [String] The text content or value of +subscription_details+ def subscription_details # This is a stub, used for indexing. The method is dynamically generated. @@ -14,7 +14,7 @@ module Gitlab # Gitlab::Page::Admin::Subscription.perform do |subscription| # expect(subscription.subscription_details_element).to exist # end - # @return [Watir::H6] The raw +H6+ element + # @return [Watir::Div] The raw +Div+ element def subscription_details_element # This is a stub, used for indexing. The method is dynamically generated. end @@ -62,6 +62,30 @@ module Gitlab # This is a stub, used for indexing. The method is dynamically generated. end + # @note Defined as +button :activate+ + # Clicks +activate+ + def activate + # This is a stub, used for indexing. The method is dynamically generated. + end + + # @example + # Gitlab::Page::Admin::Subscription.perform do |subscription| + # expect(subscription.activate_element).to exist + # end + # @return [Watir::Button] The raw +Button+ element + def activate_element + # This is a stub, used for indexing. The method is dynamically generated. + end + + # @example + # Gitlab::Page::Admin::Subscription.perform do |subscription| + # expect(subscription).to be_activate + # end + # @return [Boolean] true if the +activate+ element is present on the page + def activate? + # This is a stub, used for indexing. The method is dynamically generated. + end + # @note Defined as +label :terms_of_services+ # @return [String] The text content or value of +terms_of_services+ def terms_of_services @@ -86,79 +110,79 @@ module Gitlab # This is a stub, used for indexing. The method is dynamically generated. end - # @note Defined as +button :activate+ - # Clicks +activate+ - def activate + # @note Defined as +button :remove_license+ + # Clicks +remove_license+ + def remove_license # This is a stub, used for indexing. The method is dynamically generated. end # @example # Gitlab::Page::Admin::Subscription.perform do |subscription| - # expect(subscription.activate_element).to exist + # expect(subscription.remove_license_element).to exist # end # @return [Watir::Button] The raw +Button+ element - def activate_element + def remove_license_element # This is a stub, used for indexing. The method is dynamically generated. end # @example # Gitlab::Page::Admin::Subscription.perform do |subscription| - # expect(subscription).to be_activate + # expect(subscription).to be_remove_license # end - # @return [Boolean] true if the +activate+ element is present on the page - def activate? + # @return [Boolean] true if the +remove_license+ element is present on the page + def remove_license? # This is a stub, used for indexing. The method is dynamically generated. end - # @note Defined as +p :plan+ - # @return [String] The text content or value of +plan+ - def plan + # @note Defined as +button :confirm_remove_license+ + # Clicks +confirm_remove_license+ + def confirm_remove_license # This is a stub, used for indexing. The method is dynamically generated. end # @example # Gitlab::Page::Admin::Subscription.perform do |subscription| - # expect(subscription.plan_element).to exist + # expect(subscription.confirm_remove_license_element).to exist # end - # @return [Watir::P] The raw +P+ element - def plan_element + # @return [Watir::Button] The raw +Button+ element + def confirm_remove_license_element # This is a stub, used for indexing. The method is dynamically generated. end # @example # Gitlab::Page::Admin::Subscription.perform do |subscription| - # expect(subscription).to be_plan + # expect(subscription).to be_confirm_remove_license # end - # @return [Boolean] true if the +plan+ element is present on the page - def plan? + # @return [Boolean] true if the +confirm_remove_license+ element is present on the page + def confirm_remove_license? # This is a stub, used for indexing. The method is dynamically generated. end - # @note Defined as +p :started+ - # @return [String] The text content or value of +started+ - def started + # @note Defined as +td :plan+ + # @return [String] The text content or value of +plan+ + def plan # This is a stub, used for indexing. The method is dynamically generated. end # @example # Gitlab::Page::Admin::Subscription.perform do |subscription| - # expect(subscription.started_element).to exist + # expect(subscription.plan_element).to exist # end - # @return [Watir::P] The raw +P+ element - def started_element + # @return [Watir::Td] The raw +Td+ element + def plan_element # This is a stub, used for indexing. The method is dynamically generated. end # @example # Gitlab::Page::Admin::Subscription.perform do |subscription| - # expect(subscription).to be_started + # expect(subscription).to be_plan # end - # @return [Boolean] true if the +started+ element is present on the page - def started? + # @return [Boolean] true if the +plan+ element is present on the page + def plan? # This is a stub, used for indexing. The method is dynamically generated. end - # @note Defined as +p :name+ + # @note Defined as +td :name+ # @return [String] The text content or value of +name+ def name # This is a stub, used for indexing. The method is dynamically generated. @@ -168,7 +192,7 @@ module Gitlab # Gitlab::Page::Admin::Subscription.perform do |subscription| # expect(subscription.name_element).to exist # end - # @return [Watir::P] The raw +P+ element + # @return [Watir::Td] The raw +Td+ element def name_element # This is a stub, used for indexing. The method is dynamically generated. end @@ -182,7 +206,7 @@ module Gitlab # This is a stub, used for indexing. The method is dynamically generated. end - # @note Defined as +p :company+ + # @note Defined as +td :company+ # @return [String] The text content or value of +company+ def company # This is a stub, used for indexing. The method is dynamically generated. @@ -192,7 +216,7 @@ module Gitlab # Gitlab::Page::Admin::Subscription.perform do |subscription| # expect(subscription.company_element).to exist # end - # @return [Watir::P] The raw +P+ element + # @return [Watir::Td] The raw +Td+ element def company_element # This is a stub, used for indexing. The method is dynamically generated. end @@ -206,7 +230,7 @@ module Gitlab # This is a stub, used for indexing. The method is dynamically generated. end - # @note Defined as +p :email+ + # @note Defined as +td :email+ # @return [String] The text content or value of +email+ def email # This is a stub, used for indexing. The method is dynamically generated. @@ -216,7 +240,7 @@ module Gitlab # Gitlab::Page::Admin::Subscription.perform do |subscription| # expect(subscription.email_element).to exist # end - # @return [Watir::P] The raw +P+ element + # @return [Watir::Td] The raw +Td+ element def email_element # This is a stub, used for indexing. The method is dynamically generated. end @@ -230,123 +254,99 @@ module Gitlab # This is a stub, used for indexing. The method is dynamically generated. end - # @note Defined as +h2 :billable_users+ - # @return [String] The text content or value of +billable_users+ - def billable_users - # This is a stub, used for indexing. The method is dynamically generated. - end - - # @example - # Gitlab::Page::Admin::Subscription.perform do |subscription| - # expect(subscription.billable_users_element).to exist - # end - # @return [Watir::H2] The raw +H2+ element - def billable_users_element - # This is a stub, used for indexing. The method is dynamically generated. - end - - # @example - # Gitlab::Page::Admin::Subscription.perform do |subscription| - # expect(subscription).to be_billable_users - # end - # @return [Boolean] true if the +billable_users+ element is present on the page - def billable_users? - # This is a stub, used for indexing. The method is dynamically generated. - end - - # @note Defined as +h2 :maximum_users+ - # @return [String] The text content or value of +maximum_users+ - def maximum_users + # @note Defined as +h2 :users_in_subscription+ + # @return [String] The text content or value of +users_in_subscription+ + def users_in_subscription # This is a stub, used for indexing. The method is dynamically generated. end # @example # Gitlab::Page::Admin::Subscription.perform do |subscription| - # expect(subscription.maximum_users_element).to exist + # expect(subscription.users_in_subscription_element).to exist # end # @return [Watir::H2] The raw +H2+ element - def maximum_users_element + def users_in_subscription_element # This is a stub, used for indexing. The method is dynamically generated. end # @example # Gitlab::Page::Admin::Subscription.perform do |subscription| - # expect(subscription).to be_maximum_users + # expect(subscription).to be_users_in_subscription # end - # @return [Boolean] true if the +maximum_users+ element is present on the page - def maximum_users? + # @return [Boolean] true if the +users_in_subscription+ element is present on the page + def users_in_subscription? # This is a stub, used for indexing. The method is dynamically generated. end - # @note Defined as +h2 :users_in_subscription+ - # @return [String] The text content or value of +users_in_subscription+ - def users_in_subscription + # @note Defined as +table :subscription_history+ + # @return [String] The text content or value of +subscription_history+ + def subscription_history # This is a stub, used for indexing. The method is dynamically generated. end # @example # Gitlab::Page::Admin::Subscription.perform do |subscription| - # expect(subscription.users_in_subscription_element).to exist + # expect(subscription.subscription_history_element).to exist # end - # @return [Watir::H2] The raw +H2+ element - def users_in_subscription_element + # @return [Watir::Table] The raw +Table+ element + def subscription_history_element # This is a stub, used for indexing. The method is dynamically generated. end # @example # Gitlab::Page::Admin::Subscription.perform do |subscription| - # expect(subscription).to be_users_in_subscription + # expect(subscription).to be_subscription_history # end - # @return [Boolean] true if the +users_in_subscription+ element is present on the page - def users_in_subscription? + # @return [Boolean] true if the +subscription_history+ element is present on the page + def subscription_history? # This is a stub, used for indexing. The method is dynamically generated. end - # @note Defined as +h2 :users_over_subscription+ - # @return [String] The text content or value of +users_over_subscription+ - def users_over_subscription + # @note Defined as +div :no_valid_license_alert+ + # @return [String] The text content or value of +no_valid_license_alert+ + def no_valid_license_alert # This is a stub, used for indexing. The method is dynamically generated. end # @example # Gitlab::Page::Admin::Subscription.perform do |subscription| - # expect(subscription.users_over_subscription_element).to exist + # expect(subscription.no_valid_license_alert_element).to exist # end - # @return [Watir::H2] The raw +H2+ element - def users_over_subscription_element + # @return [Watir::Div] The raw +Div+ element + def no_valid_license_alert_element # This is a stub, used for indexing. The method is dynamically generated. end # @example # Gitlab::Page::Admin::Subscription.perform do |subscription| - # expect(subscription).to be_users_over_subscription + # expect(subscription).to be_no_valid_license_alert # end - # @return [Boolean] true if the +users_over_subscription+ element is present on the page - def users_over_subscription? + # @return [Boolean] true if the +no_valid_license_alert+ element is present on the page + def no_valid_license_alert? # This is a stub, used for indexing. The method is dynamically generated. end - # @note Defined as +table :subscription_history+ - # @return [String] The text content or value of +subscription_history+ - def subscription_history + # @note Defined as +h3 :no_active_subscription_title+ + # @return [String] The text content or value of +no_active_subscription_title+ + def no_active_subscription_title # This is a stub, used for indexing. The method is dynamically generated. end # @example # Gitlab::Page::Admin::Subscription.perform do |subscription| - # expect(subscription.subscription_history_element).to exist + # expect(subscription.no_active_subscription_title_element).to exist # end - # @return [Watir::Table] The raw +Table+ element - def subscription_history_element + # @return [Watir::H3] The raw +H3+ element + def no_active_subscription_title_element # This is a stub, used for indexing. The method is dynamically generated. end # @example # Gitlab::Page::Admin::Subscription.perform do |subscription| - # expect(subscription).to be_subscription_history + # expect(subscription).to be_no_active_subscription_title # end - # @return [Boolean] true if the +subscription_history+ element is present on the page - def subscription_history? + # @return [Boolean] true if the +no_active_subscription_title+ element is present on the page + def no_active_subscription_title? # This is a stub, used for indexing. The method is dynamically generated. end end diff --git a/qa/lib/gitlab/page/group/settings/usage_quotas.rb b/qa/lib/gitlab/page/group/settings/usage_quotas.rb index 11d1dd78dbe..cdb0760ad9c 100644 --- a/qa/lib/gitlab/page/group/settings/usage_quotas.rb +++ b/qa/lib/gitlab/page/group/settings/usage_quotas.rb @@ -35,6 +35,13 @@ module Gitlab span :container_registry_size div :storage_purchased, 'data-testid': 'storage-purchased' div :storage_purchase_successful_alert, text: /You have successfully purchased a storage/ + span :project_repository_size + span :project_lfs_object_size + span :project_build_artifact_size + span :project_packages_size + span :project_wiki_size + span :project_snippets_size + span :project_containers_registry_size # Pending members div :pending_members diff --git a/qa/lib/gitlab/page/trials/new.rb b/qa/lib/gitlab/page/trials/new.rb index b2e6cbdb682..f7aa168e6bf 100644 --- a/qa/lib/gitlab/page/trials/new.rb +++ b/qa/lib/gitlab/page/trials/new.rb @@ -9,8 +9,8 @@ module Gitlab text_field :first_name text_field :last_name text_field :company_name - select :number_of_employees - text_field :telephone_number + select :company_size + text_field :phone_number select :country select :state button :continue diff --git a/qa/lib/gitlab/page/trials/new.stub.rb b/qa/lib/gitlab/page/trials/new.stub.rb new file mode 100644 index 00000000000..0b3dbaafacc --- /dev/null +++ b/qa/lib/gitlab/page/trials/new.stub.rb @@ -0,0 +1,241 @@ +# frozen_string_literal: true + +module Gitlab + module Page + module Trials + module New + # @note Defined as +text_field :first_name+ + # @return [String] The text content or value of +first_name+ + def first_name + # This is a stub, used for indexing. The method is dynamically generated. + end + + # Set the value of first_name + # @example + # Gitlab::Page::Trials::New.perform do |new| + # new.first_name = 'value' + # end + # @param value [String] The value to set. + def first_name=(value) + # This is a stub, used for indexing. The method is dynamically generated. + end + + # @example + # Gitlab::Page::Trials::New.perform do |new| + # expect(new.first_name_element).to exist + # end + # @return [Watir::TextField] The raw +TextField+ element + def first_name_element + # This is a stub, used for indexing. The method is dynamically generated. + end + + # @example + # Gitlab::Page::Trials::New.perform do |new| + # expect(new).to be_first_name + # end + # @return [Boolean] true if the +first_name+ element is present on the page + def first_name? + # This is a stub, used for indexing. The method is dynamically generated. + end + + # @note Defined as +text_field :last_name+ + # @return [String] The text content or value of +last_name+ + def last_name + # This is a stub, used for indexing. The method is dynamically generated. + end + + # Set the value of last_name + # @example + # Gitlab::Page::Trials::New.perform do |new| + # new.last_name = 'value' + # end + # @param value [String] The value to set. + def last_name=(value) + # This is a stub, used for indexing. The method is dynamically generated. + end + + # @example + # Gitlab::Page::Trials::New.perform do |new| + # expect(new.last_name_element).to exist + # end + # @return [Watir::TextField] The raw +TextField+ element + def last_name_element + # This is a stub, used for indexing. The method is dynamically generated. + end + + # @example + # Gitlab::Page::Trials::New.perform do |new| + # expect(new).to be_last_name + # end + # @return [Boolean] true if the +last_name+ element is present on the page + def last_name? + # This is a stub, used for indexing. The method is dynamically generated. + end + + # @note Defined as +text_field :company_name+ + # @return [String] The text content or value of +company_name+ + def company_name + # This is a stub, used for indexing. The method is dynamically generated. + end + + # Set the value of company_name + # @example + # Gitlab::Page::Trials::New.perform do |new| + # new.company_name = 'value' + # end + # @param value [String] The value to set. + def company_name=(value) + # This is a stub, used for indexing. The method is dynamically generated. + end + + # @example + # Gitlab::Page::Trials::New.perform do |new| + # expect(new.company_name_element).to exist + # end + # @return [Watir::TextField] The raw +TextField+ element + def company_name_element + # This is a stub, used for indexing. The method is dynamically generated. + end + + # @example + # Gitlab::Page::Trials::New.perform do |new| + # expect(new).to be_company_name + # end + # @return [Boolean] true if the +company_name+ element is present on the page + def company_name? + # This is a stub, used for indexing. The method is dynamically generated. + end + + # @note Defined as +select :company_size+ + # @return [String] The text content or value of +company_size+ + def company_size + # This is a stub, used for indexing. The method is dynamically generated. + end + + # @example + # Gitlab::Page::Trials::New.perform do |new| + # expect(new.company_size_element).to exist + # end + # @return [Watir::Select] The raw +Select+ element + def company_size_element + # This is a stub, used for indexing. The method is dynamically generated. + end + + # @example + # Gitlab::Page::Trials::New.perform do |new| + # expect(new).to be_company_size + # end + # @return [Boolean] true if the +company_size+ element is present on the page + def company_size? + # This is a stub, used for indexing. The method is dynamically generated. + end + + # @note Defined as +text_field :phone_number+ + # @return [String] The text content or value of +phone_number+ + def phone_number + # This is a stub, used for indexing. The method is dynamically generated. + end + + # Set the value of phone_number + # @example + # Gitlab::Page::Trials::New.perform do |new| + # new.phone_number = 'value' + # end + # @param value [String] The value to set. + def phone_number=(value) + # This is a stub, used for indexing. The method is dynamically generated. + end + + # @example + # Gitlab::Page::Trials::New.perform do |new| + # expect(new.phone_number_element).to exist + # end + # @return [Watir::TextField] The raw +TextField+ element + def phone_number_element + # This is a stub, used for indexing. The method is dynamically generated. + end + + # @example + # Gitlab::Page::Trials::New.perform do |new| + # expect(new).to be_phone_number + # end + # @return [Boolean] true if the +phone_number+ element is present on the page + def phone_number? + # This is a stub, used for indexing. The method is dynamically generated. + end + + # @note Defined as +select :country+ + # @return [String] The text content or value of +country+ + def country + # This is a stub, used for indexing. The method is dynamically generated. + end + + # @example + # Gitlab::Page::Trials::New.perform do |new| + # expect(new.country_element).to exist + # end + # @return [Watir::Select] The raw +Select+ element + def country_element + # This is a stub, used for indexing. The method is dynamically generated. + end + + # @example + # Gitlab::Page::Trials::New.perform do |new| + # expect(new).to be_country + # end + # @return [Boolean] true if the +country+ element is present on the page + def country? + # This is a stub, used for indexing. The method is dynamically generated. + end + + # @note Defined as +select :state+ + # @return [String] The text content or value of +state+ + def state + # This is a stub, used for indexing. The method is dynamically generated. + end + + # @example + # Gitlab::Page::Trials::New.perform do |new| + # expect(new.state_element).to exist + # end + # @return [Watir::Select] The raw +Select+ element + def state_element + # This is a stub, used for indexing. The method is dynamically generated. + end + + # @example + # Gitlab::Page::Trials::New.perform do |new| + # expect(new).to be_state + # end + # @return [Boolean] true if the +state+ element is present on the page + def state? + # This is a stub, used for indexing. The method is dynamically generated. + end + + # @note Defined as +button :continue+ + # Clicks +continue+ + def continue + # This is a stub, used for indexing. The method is dynamically generated. + end + + # @example + # Gitlab::Page::Trials::New.perform do |new| + # expect(new.continue_element).to exist + # end + # @return [Watir::Button] The raw +Button+ element + def continue_element + # This is a stub, used for indexing. The method is dynamically generated. + end + + # @example + # Gitlab::Page::Trials::New.perform do |new| + # expect(new).to be_continue + # end + # @return [Boolean] true if the +continue+ element is present on the page + def continue? + # This is a stub, used for indexing. The method is dynamically generated. + end + end + end + end +end diff --git a/qa/lib/gitlab/page/trials/select.rb b/qa/lib/gitlab/page/trials/select.rb index d4cf54805ea..ae807f99c25 100644 --- a/qa/lib/gitlab/page/trials/select.rb +++ b/qa/lib/gitlab/page/trials/select.rb @@ -8,7 +8,6 @@ module Gitlab button :select_group, 'data-testid': 'base-dropdown-toggle' div :group_dropdown, 'data-testid': 'base-dropdown-menu' - text_field :new_group_name button :start_your_free_trial radio :trial_company radio :trial_individual diff --git a/qa/lib/gitlab/page/trials/select.stub.rb b/qa/lib/gitlab/page/trials/select.stub.rb new file mode 100644 index 00000000000..0c61a58d35c --- /dev/null +++ b/qa/lib/gitlab/page/trials/select.stub.rb @@ -0,0 +1,129 @@ +# frozen_string_literal: true + +module Gitlab + module Page + module Trials + module Select + # @note Defined as +button :select_group+ + # Clicks +select_group+ + def select_group + # This is a stub, used for indexing. The method is dynamically generated. + end + + # @example + # Gitlab::Page::Trials::Select.perform do |select| + # expect(select.select_group_element).to exist + # end + # @return [Watir::Button] The raw +Button+ element + def select_group_element + # This is a stub, used for indexing. The method is dynamically generated. + end + + # @example + # Gitlab::Page::Trials::Select.perform do |select| + # expect(select).to be_select_group + # end + # @return [Boolean] true if the +select_group+ element is present on the page + def select_group? + # This is a stub, used for indexing. The method is dynamically generated. + end + + # @note Defined as +div :group_dropdown+ + # @return [String] The text content or value of +group_dropdown+ + def group_dropdown + # This is a stub, used for indexing. The method is dynamically generated. + end + + # @example + # Gitlab::Page::Trials::Select.perform do |select| + # expect(select.group_dropdown_element).to exist + # end + # @return [Watir::Div] The raw +Div+ element + def group_dropdown_element + # This is a stub, used for indexing. The method is dynamically generated. + end + + # @example + # Gitlab::Page::Trials::Select.perform do |select| + # expect(select).to be_group_dropdown + # end + # @return [Boolean] true if the +group_dropdown+ element is present on the page + def group_dropdown? + # This is a stub, used for indexing. The method is dynamically generated. + end + + # @note Defined as +button :start_your_free_trial+ + # Clicks +start_your_free_trial+ + def start_your_free_trial + # This is a stub, used for indexing. The method is dynamically generated. + end + + # @example + # Gitlab::Page::Trials::Select.perform do |select| + # expect(select.start_your_free_trial_element).to exist + # end + # @return [Watir::Button] The raw +Button+ element + def start_your_free_trial_element + # This is a stub, used for indexing. The method is dynamically generated. + end + + # @example + # Gitlab::Page::Trials::Select.perform do |select| + # expect(select).to be_start_your_free_trial + # end + # @return [Boolean] true if the +start_your_free_trial+ element is present on the page + def start_your_free_trial? + # This is a stub, used for indexing. The method is dynamically generated. + end + + # @note Defined as +radio :trial_company+ + # Clicks +trial_company+ + def trial_company + # This is a stub, used for indexing. The method is dynamically generated. + end + + # @example + # Gitlab::Page::Trials::Select.perform do |select| + # expect(select.trial_company_element).to exist + # end + # @return [Watir::Radio] The raw +Radio+ element + def trial_company_element + # This is a stub, used for indexing. The method is dynamically generated. + end + + # @example + # Gitlab::Page::Trials::Select.perform do |select| + # expect(select).to be_trial_company + # end + # @return [Boolean] true if the +trial_company+ element is present on the page + def trial_company? + # This is a stub, used for indexing. The method is dynamically generated. + end + + # @note Defined as +radio :trial_individual+ + # Clicks +trial_individual+ + def trial_individual + # This is a stub, used for indexing. The method is dynamically generated. + end + + # @example + # Gitlab::Page::Trials::Select.perform do |select| + # expect(select.trial_individual_element).to exist + # end + # @return [Watir::Radio] The raw +Radio+ element + def trial_individual_element + # This is a stub, used for indexing. The method is dynamically generated. + end + + # @example + # Gitlab::Page::Trials::Select.perform do |select| + # expect(select).to be_trial_individual + # end + # @return [Boolean] true if the +trial_individual+ element is present on the page + def trial_individual? + # This is a stub, used for indexing. The method is dynamically generated. + end + end + end + end +end @@ -18,6 +18,7 @@ require 'rainbow/refinement' require 'active_support/core_ext/hash' require 'active_support/core_ext/object/blank' require 'active_support/core_ext/module/delegation' +require 'active_support/parameter_filter' module QA root = "#{__dir__}/qa" @@ -29,6 +30,7 @@ module QA loader.push_dir(root, namespace: QA) + loader.ignore("#{root}/factories") loader.ignore("#{root}/specs/features") loader.ignore("#{root}/specs/spec_helper.rb") diff --git a/qa/qa/factories/_shared.rb b/qa/qa/factories/_shared.rb new file mode 100644 index 00000000000..0fd38faa7dd --- /dev/null +++ b/qa/qa/factories/_shared.rb @@ -0,0 +1,7 @@ +# frozen_string_literal: true + +module QA + FactoryBot.define do + to_create(&:fabricate_via_api!) + end +end diff --git a/qa/qa/factories/groups.rb b/qa/qa/factories/groups.rb new file mode 100644 index 00000000000..7daa365bfca --- /dev/null +++ b/qa/qa/factories/groups.rb @@ -0,0 +1,18 @@ +# frozen_string_literal: true + +module QA + FactoryBot.define do + factory :group_base, class: 'QA::Resource::GroupBase' do + trait :private do + visibility { :private } + end + + trait :require_2fa do + require_two_factor_authentication { true } + end + + factory :sandbox, class: 'QA::Resource::Sandbox' + factory :group, class: 'QA::Resource::Group' + end + end +end diff --git a/qa/qa/factories/issues.rb b/qa/qa/factories/issues.rb new file mode 100644 index 00000000000..2931a41e347 --- /dev/null +++ b/qa/qa/factories/issues.rb @@ -0,0 +1,17 @@ +# frozen_string_literal: true + +module QA + FactoryBot.define do + # https://docs.gitlab.com/ee/api/issues.html + factory :issue, class: 'QA::Resource::Issue' do + title { Faker::Lorem.sentence } + description { Faker::Lorem.paragraph } + + confidential { false } + + trait :confidential do + confidential { true } + end + end + end +end diff --git a/qa/qa/factories/projects.rb b/qa/qa/factories/projects.rb new file mode 100644 index 00000000000..69eefe12129 --- /dev/null +++ b/qa/qa/factories/projects.rb @@ -0,0 +1,20 @@ +# frozen_string_literal: true + +module QA + FactoryBot.define do + # https://docs.gitlab.com/ee/api/projects.html + factory :project, class: 'QA::Resource::Project' do + trait :private do + visibility { 'private' } + end + + trait :with_readme do + initialize_with_readme { true } + end + + trait :auto_devops do + auto_devops_enabled { true } + end + end + end +end diff --git a/qa/qa/fixtures/package_managers/composer/composer_upload_package.yaml.erb b/qa/qa/fixtures/package_managers/composer/composer_upload_package.yaml.erb index b6bcfafffee..5ebb2a0d8f3 100644 --- a/qa/qa/fixtures/package_managers/composer/composer_upload_package.yaml.erb +++ b/qa/qa/fixtures/package_managers/composer/composer_upload_package.yaml.erb @@ -2,7 +2,7 @@ publish: image: curlimages/curl:latest stage: build variables: - URL: "$CI_SERVER_PROTOCOL://$CI_SERVER_HOST:$CI_SERVER_PORT/api/v4/projects/$CI_PROJECT_ID/packages/composer?job_token=$CI_JOB_TOKEN" + URL: "<%= gitlab_host_with_port %>/api/v4/projects/$CI_PROJECT_ID/packages/composer?job_token=$CI_JOB_TOKEN" script: - version=$([[ -z "$CI_COMMIT_TAG" ]] && echo "branch=$CI_COMMIT_REF_NAME" || echo "tag=$CI_COMMIT_TAG") - insecure=$([ "$CI_SERVER_PROTOCOL" = "http" ] && echo "--insecure" || echo "") diff --git a/qa/qa/fixtures/package_managers/npm/npm_install_package_group.yaml.erb b/qa/qa/fixtures/package_managers/npm/npm_install_package_group.yaml.erb index a5ec4f298e2..2b6cb60df21 100644 --- a/qa/qa/fixtures/package_managers/npm/npm_install_package_group.yaml.erb +++ b/qa/qa/fixtures/package_managers/npm/npm_install_package_group.yaml.erb @@ -6,7 +6,7 @@ stages: install: stage: install script: - - "npm config set @<%= registry_scope %>:registry <%= gitlab_address_with_port %>/api/v4/groups/<%= another_project.group.id %>/-/packages/npm/" + - "npm config set @<%= registry_scope %>:registry <%= gitlab_address_without_port %>/api/v4/groups/<%= another_project.group.id %>/-/packages/npm/" - "npm install <%= package.name %>" cache: key: ${CI_COMMIT_REF_NAME} diff --git a/qa/qa/fixtures/package_managers/npm/npm_install_package_instance.yaml.erb b/qa/qa/fixtures/package_managers/npm/npm_install_package_instance.yaml.erb index 07f426c3bfa..92411593620 100644 --- a/qa/qa/fixtures/package_managers/npm/npm_install_package_instance.yaml.erb +++ b/qa/qa/fixtures/package_managers/npm/npm_install_package_instance.yaml.erb @@ -6,7 +6,7 @@ stages: install: stage: install script: - - "npm config set @<%= registry_scope %>:registry <%= gitlab_address_with_port %>/api/v4/packages/npm/" + - "npm config set @<%= registry_scope %>:registry <%= gitlab_address_without_port %>/api/v4/packages/npm/" - "npm install <%= package.name %>" cache: key: ${CI_COMMIT_REF_NAME} diff --git a/qa/qa/fixtures/package_managers/npm/npm_upload_install_package_project.yaml.erb b/qa/qa/fixtures/package_managers/npm/npm_upload_install_package_project.yaml.erb index b5277a2c315..6fb86845bb5 100644 --- a/qa/qa/fixtures/package_managers/npm/npm_upload_install_package_project.yaml.erb +++ b/qa/qa/fixtures/package_managers/npm/npm_upload_install_package_project.yaml.erb @@ -7,7 +7,7 @@ stages: deploy: stage: deploy script: - - echo "//${CI_SERVER_HOST}/api/v4/projects/${CI_PROJECT_ID}/packages/npm/:_authToken=<%= auth_token %>">.npmrc + - echo "//<%= gitlab_host_without_port %>/api/v4/projects/${CI_PROJECT_ID}/packages/npm/:_authToken=<%= auth_token %>">.npmrc - npm publish only: - "<%= project.default_branch %>" @@ -16,8 +16,8 @@ deploy: install: stage: install script: - - echo "//${CI_SERVER_HOST}/api/v4/projects/${CI_PROJECT_ID}/packages/npm/:_authToken=<%= auth_token %>">.npmrc - - "npm config set @<%= registry_scope %>:registry <%= gitlab_address_with_port %>/api/v4/projects/${CI_PROJECT_ID}/packages/npm/" + - echo "//<%= gitlab_host_without_port %>/api/v4/projects/${CI_PROJECT_ID}/packages/npm/:_authToken=<%= auth_token %>">.npmrc + - "npm config set @<%= registry_scope %>:registry <%= gitlab_address_without_port %>/api/v4/projects/${CI_PROJECT_ID}/packages/npm/" - "npm install <%= package.name %>" cache: key: ${CI_COMMIT_REF_NAME} diff --git a/qa/qa/fixtures/package_managers/npm/npm_upload_package_group.yaml.erb b/qa/qa/fixtures/package_managers/npm/npm_upload_package_group.yaml.erb index 13c00cd17c4..8e81953ad19 100644 --- a/qa/qa/fixtures/package_managers/npm/npm_upload_package_group.yaml.erb +++ b/qa/qa/fixtures/package_managers/npm/npm_upload_package_group.yaml.erb @@ -6,7 +6,7 @@ stages: deploy: stage: deploy script: - - echo "//${CI_SERVER_HOST}/api/v4/projects/${CI_PROJECT_ID}/packages/npm/:_authToken=<%= auth_token %>">.npmrc + - echo "//<%= gitlab_host_without_port %>/api/v4/projects/${CI_PROJECT_ID}/packages/npm/:_authToken=<%= auth_token %>">.npmrc - npm publish only: - "<%= project.default_branch %>" diff --git a/qa/qa/fixtures/package_managers/npm/npm_upload_package_instance.yaml.erb b/qa/qa/fixtures/package_managers/npm/npm_upload_package_instance.yaml.erb index 13c00cd17c4..8e81953ad19 100644 --- a/qa/qa/fixtures/package_managers/npm/npm_upload_package_instance.yaml.erb +++ b/qa/qa/fixtures/package_managers/npm/npm_upload_package_instance.yaml.erb @@ -6,7 +6,7 @@ stages: deploy: stage: deploy script: - - echo "//${CI_SERVER_HOST}/api/v4/projects/${CI_PROJECT_ID}/packages/npm/:_authToken=<%= auth_token %>">.npmrc + - echo "//<%= gitlab_host_without_port %>/api/v4/projects/${CI_PROJECT_ID}/packages/npm/:_authToken=<%= auth_token %>">.npmrc - npm publish only: - "<%= project.default_branch %>" diff --git a/qa/qa/fixtures/package_managers/npm/package.json.erb b/qa/qa/fixtures/package_managers/npm/package.json.erb index 46fecf97e2c..68539da02bc 100644 --- a/qa/qa/fixtures/package_managers/npm/package.json.erb +++ b/qa/qa/fixtures/package_managers/npm/package.json.erb @@ -3,6 +3,6 @@ "version": "1.0.0", "description": "Example package for GitLab npm registry", "publishConfig": { - "@<%= registry_scope %>:registry": "<%= gitlab_address_with_port %>/api/v4/projects/<%= project.id %>/packages/npm/" + "@<%= registry_scope %>:registry": "<%= gitlab_address_without_port %>/api/v4/projects/<%= project.id %>/packages/npm/" } }
\ No newline at end of file diff --git a/qa/qa/flow/trial.rb b/qa/qa/flow/trial.rb index 109afeffaa3..9bab98bf027 100644 --- a/qa/qa/flow/trial.rb +++ b/qa/qa/flow/trial.rb @@ -7,8 +7,8 @@ module QA CUSTOMER_TRIAL_INFO = { company_name: 'QA Test Company', - number_of_employees: '500 - 1,999', - telephone_number: '555-555-5555', + company_size: '500 - 1,999', + phone_number: '555-555-5555', country: 'United States of America', state: 'CA' }.freeze @@ -16,9 +16,9 @@ module QA def register_for_trial(group: nil) Gitlab::Page::Trials::New.perform do |new| new.company_name = CUSTOMER_TRIAL_INFO[:company_name] - new.number_of_employees = CUSTOMER_TRIAL_INFO[:number_of_employees] + new.company_size = CUSTOMER_TRIAL_INFO[:company_size] new.country = CUSTOMER_TRIAL_INFO[:country] - new.telephone_number = CUSTOMER_TRIAL_INFO[:telephone_number] + new.phone_number = CUSTOMER_TRIAL_INFO[:phone_number] new.state = CUSTOMER_TRIAL_INFO[:state] new.continue diff --git a/qa/qa/page/admin/menu.rb b/qa/qa/page/admin/menu.rb index f58d672efe8..3b044f8a051 100644 --- a/qa/qa/page/admin/menu.rb +++ b/qa/qa/page/admin/menu.rb @@ -67,6 +67,12 @@ module QA click_element :admin_overview_groups_link end + def go_to_security_and_compliance + hover_element(:admin_settings_menu_link) do + click_element :admin_security_and_compliance_link + end + end + def go_to_applications return click_element(:nav_item_link, submenu_item: 'Applications') if Runtime::Env.super_sidebar_enabled? diff --git a/qa/qa/page/admin/overview/users/index.rb b/qa/qa/page/admin/overview/users/index.rb index f46ae30498c..6f1134b751a 100644 --- a/qa/qa/page/admin/overview/users/index.rb +++ b/qa/qa/page/admin/overview/users/index.rb @@ -12,7 +12,7 @@ module QA end view 'app/assets/javascripts/admin/users/components/users_table.vue' do - element :user_row_content + element 'user-row-content' end def search_user(username) @@ -24,13 +24,13 @@ module QA end def click_user(username) - within_element(:user_row_content, text: username) do + within_element('user-row-content', text: username) do click_link(username) end end def has_username?(username) - has_element?(:user_row_content, text: username, wait: 1) + has_element?('user-row-content', text: username, wait: 1) end end end diff --git a/qa/qa/page/base.rb b/qa/qa/page/base.rb index 92b4fd39759..1961e522b89 100644 --- a/qa/qa/page/base.rb +++ b/qa/qa/page/base.rb @@ -165,7 +165,7 @@ module QA raise ArgumentError, "Please use :minimum, :maximum, :count, or :between so that all is more reliable" end - wait_for_requests + wait_for_requests(skip_finished_loading_check: !!kwargs.delete(:skip_finished_loading_check)) all(element_selector_css(name), **kwargs) end @@ -243,7 +243,20 @@ module QA wait = kwargs.delete(:wait) || Capybara.default_max_wait_time text = kwargs.delete(:text) - find(element_selector_css(name, kwargs), text: text, wait: wait).click + begin + find(element_selector_css(name, kwargs), text: text, wait: wait).click + rescue Net::ReadTimeout => error + # In some situations due to perhaps a slow environment we can encounter errors + # where clicks are registered, but the calls to selenium-webdriver result in + # timeout errors. In these cases rescue from the error and attempt to continue in + # the test to avoid a flaky test failure. This should be safe as assertions in the + # tests will catch any case where the click wasn't actually registered. + QA::Runtime::Logger.warn "click_element -- #{error} -- #{error.backtrace.inspect}" + # There may be a 5xx error -- lets refresh the page like the warning page suggests + # and it if resolves itself we can avoid a flaky failure + refresh + end + page.validate_elements_present! if page end @@ -381,7 +394,7 @@ module QA end def within_element(name, **kwargs, &block) - wait_for_requests(skip_finished_loading_check: kwargs.delete(:skip_finished_loading_check)) + 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, &block) diff --git a/qa/qa/page/component/access_tokens.rb b/qa/qa/page/component/access_tokens.rb index 586f69b8a64..6d7c36065ef 100644 --- a/qa/qa/page/component/access_tokens.rb +++ b/qa/qa/page/component/access_tokens.rb @@ -39,6 +39,26 @@ module QA base.view 'app/assets/javascripts/access_tokens/components/access_token_table_app.vue' do element :revoke_button end + + base.view 'app/views/profiles/personal_access_tokens/index.html.haml' do + element 'add-new-token-button' + end + + base.view 'app/views/projects/settings/access_tokens/index.html.haml' do + element 'add-new-token-button' + end + + base.view 'app/views/groups/settings/access_tokens/index.html.haml' do + element 'add-new-token-button' + end + + base.view 'app/views/admin/impersonation_tokens/index.html.haml' do + element 'add-new-token-button' + end + end + + def click_add_new_token_button + click_element('add-new-token-button') end def fill_token_name(name) diff --git a/qa/qa/page/component/badges.rb b/qa/qa/page/component/badges.rb index f2c5f809d8d..9d2959c010e 100644 --- a/qa/qa/page/component/badges.rb +++ b/qa/qa/page/component/badges.rb @@ -4,6 +4,10 @@ module QA module Page module Component class Badges < Page::Base + view 'app/assets/javascripts/badges/components/badge_settings.vue' do + element 'show-badge-add-form' + end + view 'app/assets/javascripts/badges/components/badge_form.vue' do element :badge_name_field element :badge_link_url_field @@ -13,13 +17,17 @@ module QA view 'app/assets/javascripts/badges/components/badge_list.vue' do element :badge_list_content - element :badge_list_row + element :badge_list end view 'app/assets/javascripts/badges/components/badge.vue' do element :badge_image_link end + def show_badge_add_form + click_element 'show-badge-add-form' + end + def fill_name(name) fill_element :badge_name_field, name end @@ -38,7 +46,7 @@ module QA def has_badge?(badge_name) within_element(:badge_list_content) do - has_element?(:badge_list_row, badge_name: badge_name) + has_element?(:badge_list, text: badge_name) end end diff --git a/qa/qa/page/component/confirm_modal.rb b/qa/qa/page/component/confirm_modal.rb index f72ca4f068e..26d06ecaa22 100644 --- a/qa/qa/page/component/confirm_modal.rb +++ b/qa/qa/page/component/confirm_modal.rb @@ -10,8 +10,8 @@ module QA super base.view 'app/assets/javascripts/lib/utils/confirm_via_gl_modal/confirm_modal.vue' do - element :confirm_ok_button - element :confirmation_modal + element 'confirm-ok-button' + element 'confirmation-modal' end base.view 'app/assets/javascripts/vue_shared/components/confirm_danger/confirm_danger_modal.vue' do @@ -36,7 +36,7 @@ module QA end def click_confirmation_ok_button - click_element(:confirm_ok_button) + click_element('confirm-ok-button') end # Click the confirmation button if the confirmation modal is present @@ -48,9 +48,9 @@ module QA # to skip the loading check otherwise it will time out. # # [1]: https://gitlab.com/gitlab-org/gitlab/-/blob/4a99af809b86047ce3c8985e6582748bbd23fc84/qa/qa/page/component/members/members_table.rb#L54 - return unless has_element?(:confirmation_modal, skip_finished_loading_check: true) + return unless has_element?('confirmation-modal', skip_finished_loading_check: true) - click_element(:confirm_ok_button, skip_finished_loading_check: true) + click_element('confirm-ok-button', skip_finished_loading_check: true) end end end diff --git a/qa/qa/page/component/delete_modal.rb b/qa/qa/page/component/delete_modal.rb index 18bb2b1bb1b..9fbbd9930a9 100644 --- a/qa/qa/page/component/delete_modal.rb +++ b/qa/qa/page/component/delete_modal.rb @@ -9,7 +9,7 @@ module QA def self.included(base) super - base.view 'app/assets/javascripts/projects/components/shared/delete_button.vue' do + base.view 'app/assets/javascripts/projects/components/shared/delete_modal.vue' do element :confirm_name_field element :confirm_delete_button end diff --git a/qa/qa/page/component/issuable/common.rb b/qa/qa/page/component/issuable/common.rb index 2f116822a12..526f8763488 100644 --- a/qa/qa/page/component/issuable/common.rb +++ b/qa/qa/page/component/issuable/common.rb @@ -11,7 +11,7 @@ module QA super base.view 'app/assets/javascripts/issues/show/components/title.vue' do - element :issue_title, required: true + element 'issue-title', required: true end end end diff --git a/qa/qa/page/component/issuable/sidebar.rb b/qa/qa/page/component/issuable/sidebar.rb index 15155fd9f44..680f1d41a5e 100644 --- a/qa/qa/page/component/issuable/sidebar.rb +++ b/qa/qa/page/component/issuable/sidebar.rb @@ -31,7 +31,7 @@ module QA end base.view 'app/assets/javascripts/sidebar/components/labels/labels_select_widget/dropdown_contents.vue' do - element :labels_select_dropdown_contents + element 'labels-select-dropdown-contents' end base.view 'app/assets/javascripts/sidebar/components/labels/labels_select_widget/dropdown_value.vue' do @@ -49,7 +49,7 @@ module QA end base.view 'app/assets/javascripts/sidebar/components/sidebar_editable_item.vue' do - element :edit_button + element 'edit-button' end base.view 'app/helpers/dropdowns_helper.rb' do @@ -59,7 +59,7 @@ module QA def assign_milestone(milestone) wait_milestone_block_finish_loading do - click_element(:edit_button) + click_element('edit-button') click_on(milestone.title) end @@ -134,17 +134,17 @@ module QA def select_labels(labels) within_element(:labels_block) do - click_element(:edit_button) + click_element('edit-button') labels.each do |label| - within_element(:labels_select_dropdown_contents) do + within_element('labels-select-dropdown-contents') do fill_element(:dropdown_input_field, label) click_button(text: label) end end end - click_element(:issue_title) # to blur dropdown + click_element('issue-title') # to blur dropdown end def toggle_more_assignees_link diff --git a/qa/qa/page/component/listbox_filter.rb b/qa/qa/page/component/listbox_filter.rb new file mode 100644 index 00000000000..b8ddab23819 --- /dev/null +++ b/qa/qa/page/component/listbox_filter.rb @@ -0,0 +1,16 @@ +# frozen_string_literal: true + +module QA + module Page + module Component + module ListboxFilter + def filter_and_select(item) + page.has_css?('.gl-listbox-search-input', wait: QA::Support::Repeater::DEFAULT_MAX_WAIT_TIME) + + find('.gl-listbox-search-input').set(item) + find('.gl-new-dropdown-item', text: item, exact_text: true).click + end + end + end + end +end diff --git a/qa/qa/page/component/members/invite_members_modal.rb b/qa/qa/page/component/members/invite_members_modal.rb index ae51213b3e2..876c5ba65b6 100644 --- a/qa/qa/page/component/members/invite_members_modal.rb +++ b/qa/qa/page/component/members/invite_members_modal.rb @@ -59,6 +59,10 @@ module QA Support::WaitForRequests.wait_for_requests + # Needed as a workaround to help avoid race condition with initial search request + # https://gitlab.com/gitlab-org/gitlab/-/issues/349379 + sleep 2 + search_and_select(group_name) set_access_level(access_level) diff --git a/qa/qa/page/component/note.rb b/qa/qa/page/component/note.rb index 638c46f228f..6bb83d8b7e8 100644 --- a/qa/qa/page/component/note.rb +++ b/qa/qa/page/component/note.rb @@ -171,7 +171,7 @@ module QA def select_filter_with_text(text) retry_on_exception do - click_element(:issue_title) + click_element('issue-title') click_element :discussion_preferences_dropdown find_element(:filter_menu_item, text: text).click diff --git a/qa/qa/page/component/project/templates.rb b/qa/qa/page/component/project/templates.rb index 6e86455fc52..0812c162914 100644 --- a/qa/qa/page/component/project/templates.rb +++ b/qa/qa/page/component/project/templates.rb @@ -5,8 +5,8 @@ module QA module Project module Templates def use_template_for_project(project_name) - within find_element(:template_option_container, text: project_name) do - click_element :use_template_button + within find_element('template-option-container', text: project_name) do + click_element 'use-template-button' end end end diff --git a/qa/qa/page/component/rich_text_popover.rb b/qa/qa/page/component/rich_text_popover.rb index 6a187dcedc5..f5b0c668fb1 100644 --- a/qa/qa/page/component/rich_text_popover.rb +++ b/qa/qa/page/component/rich_text_popover.rb @@ -10,7 +10,7 @@ module QA super base.view 'app/assets/javascripts/vue_shared/components/markdown/editor_mode_switcher.vue' do - element :rich_text_promo_popover + element 'rich-text-promo-popover' end base.view 'app/views/shared/_broadcast_message.html.haml' do @@ -19,11 +19,12 @@ module QA end def close_rich_text_promo_popover_if_present - return unless has_element?(:rich_text_promo_popover, wait: 0) + return unless has_element?('rich-text-promo-popover', wait: 0) - within_element(:rich_text_promo_popover) do - click_element(:close_button) + within_element('rich-text-promo-popover') do + click_element('close-button') end + has_no_element?('rich-text-promo-popover') end end end diff --git a/qa/qa/page/dashboard/groups.rb b/qa/qa/page/dashboard/groups.rb index 644d19d6bcb..5fa27f453ea 100644 --- a/qa/qa/page/dashboard/groups.rb +++ b/qa/qa/page/dashboard/groups.rb @@ -7,7 +7,7 @@ module QA include Page::Component::GroupsFilter view 'app/views/dashboard/_groups_head.html.haml' do - element :new_group_button + element 'new-group-button' end def has_group?(name) @@ -21,7 +21,7 @@ module QA end def click_new_group - click_element(:new_group_button) + click_element('new-group-button') end end end diff --git a/qa/qa/page/element.rb b/qa/qa/page/element.rb index f0e67627dca..ec8aca76250 100644 --- a/qa/qa/page/element.rb +++ b/qa/qa/page/element.rb @@ -12,49 +12,39 @@ module QA def initialize(name, *options) @name = name @attributes = options.extract_options! - @attributes[:pattern] ||= selector options.each do |option| @attributes[:pattern] = option if option.is_a?(String) || option.is_a?(Regexp) end end - def selector - "qa-#{@name.to_s.tr('_', '-')}" - end - def required? !!@attributes[:required] end def selector_css - %(#{qa_selector}#{additional_selectors},.#{selector}) + [ + %([data-testid="#{name}"]#{additional_selectors}), + %([data-qa-selector="#{name}"]#{additional_selectors}) + ].join(',') end - def expression - if @attributes[:pattern].is_a?(String) - @_regexp ||= Regexp.new(Regexp.escape(@attributes[:pattern])) + def matches?(line) + if expression + !!(line =~ /["']#{name}['"]|#{expression}/) else - @attributes[:pattern] + !!(line =~ /["']#{name}['"]/) end end - def matches?(line) - !!(line =~ /["']#{name}['"]|["']#{convert_to_kebabcase(name)}['"]|#{expression}/) - end - private - def convert_to_kebabcase(text) - text.to_s.tr('_', '-') - end - - def qa_selector - [ - %([data-testid="#{name}"]#{additional_selectors}), - %([data-testid="#{convert_to_kebabcase(name)}"]#{additional_selectors}), - %([data-qa-selector="#{name}"]#{additional_selectors}) - ].join(',') + def expression + if @attributes[:pattern].is_a?(String) + @_regexp ||= Regexp.new(Regexp.escape(@attributes[:pattern])) + else + @attributes[:pattern] + end end def additional_selectors diff --git a/qa/qa/page/file/form.rb b/qa/qa/page/file/form.rb index 06b75f42e4d..cfc689daa32 100644 --- a/qa/qa/page/file/form.rb +++ b/qa/qa/page/file/form.rb @@ -4,7 +4,7 @@ module QA module Page module File class Form < Page::Base - include Page::Component::DropdownFilter + include Page::Component::ListboxFilter include Page::Component::BlobContent include Shared::CommitMessage include Shared::CommitButton @@ -14,11 +14,8 @@ module QA element :file_name_field end - view 'app/views/projects/blob/_template_selectors.html.haml' do - element :gitignore_dropdown - element :gitlab_ci_yml_dropdown - element :dockerfile_dropdown - element :license_dropdown + view 'app/assets/javascripts/blob/filepath_form/components/template_selector.vue' do + element :template_selector end def add_name(name) @@ -37,14 +34,8 @@ module QA def select_template(template_type, template) case template_type - when '.gitignore' - click_element :gitignore_dropdown - when '.gitlab-ci.yml' - click_element :gitlab_ci_yml_dropdown - when 'Dockerfile' - click_element :dockerfile_dropdown - when 'LICENSE' - click_element :license_dropdown + when '.gitignore', '.gitlab-ci.yml', 'Dockerfile', 'LICENSE' + click_element :template_selector else raise %(Unsupported template_type "#{template_type}". Please confirm that it is a valid option.) end diff --git a/qa/qa/page/file/show.rb b/qa/qa/page/file/show.rb index 173baa21160..284fab58d5d 100644 --- a/qa/qa/page/file/show.rb +++ b/qa/qa/page/file/show.rb @@ -12,7 +12,7 @@ module QA element :lock_button end - view 'app/assets/javascripts/vue_shared/components/actions_button.vue' do + view 'app/assets/javascripts/vue_shared/components/web_ide_link.vue' do element :action_dropdown element :edit_menu_item, ':data-qa-selector="`${action.key}_menu_item`"' # rubocop:disable QA/ElementWithPattern element :webide_menu_item, ':data-qa-selector="`${action.key}_menu_item`"' # rubocop:disable QA/ElementWithPattern diff --git a/qa/qa/page/group/bulk_import.rb b/qa/qa/page/group/bulk_import.rb index f57b76b11a9..9fb262c27c3 100644 --- a/qa/qa/page/group/bulk_import.rb +++ b/qa/qa/page/group/bulk_import.rb @@ -8,7 +8,7 @@ module QA element :import_table element :import_item element :import_status_indicator - element :filter_groups + element 'filter-groups' end view "app/assets/javascripts/import_entities/import_groups/components/import_target_cell.vue" do @@ -20,7 +20,7 @@ module QA end view "app/assets/javascripts/import_entities/import_groups/components/import_actions_cell.vue" do - element :import_group_button + element 'import-group-button' end def filter_group(source_group_name) @@ -44,7 +44,7 @@ module QA click_element(:target_group_dropdown_item, group_name: target_group_name) retry_until(message: "Triggering import") do - click_element(:import_group_button) + click_element('import-group-button') # Make sure import started before waiting for completion has_no_element?(:import_status_indicator, text: "Not started", wait: 1) end diff --git a/qa/qa/page/group/dependency_proxy.rb b/qa/qa/page/group/dependency_proxy.rb index fa37e8eac83..70dfa78069c 100644 --- a/qa/qa/page/group/dependency_proxy.rb +++ b/qa/qa/page/group/dependency_proxy.rb @@ -5,11 +5,11 @@ module QA module Group class DependencyProxy < QA::Page::Base view 'app/assets/javascripts/packages_and_registries/dependency_proxy/app.vue' do - element :dependency_proxy_count + element 'proxy-count' end def has_blob_count?(blob_text) - has_element?(:dependency_proxy_count, text: blob_text) + has_element?('proxy-count', text: blob_text) end end end diff --git a/qa/qa/page/group/menu.rb b/qa/qa/page/group/menu.rb index c166023a620..c8f826b20e7 100644 --- a/qa/qa/page/group/menu.rb +++ b/qa/qa/page/group/menu.rb @@ -4,7 +4,7 @@ module QA module Page module Group class Menu < Page::Base - include SubMenus::Common + include QA::Page::SubMenus::Common if Runtime::Env.super_sidebar_enabled? prepend Page::SubMenus::SuperSidebar::Manage diff --git a/qa/qa/page/group/new.rb b/qa/qa/page/group/new.rb index 47fda787085..5b86dea2b8f 100644 --- a/qa/qa/page/group/new.rb +++ b/qa/qa/page/group/new.rb @@ -7,31 +7,31 @@ module QA include Page::Component::VisibilitySetting view 'app/assets/javascripts/groups/components/group_name_and_path.vue' do - element :group_path_field - element :group_name_field + element 'group-path-field' + element 'group-name-field' end view 'app/views/groups/_new_group_fields.html.haml' do - element :create_group_button + element 'create-group-button' end view 'app/views/groups/_import_group_from_another_instance_panel.html.haml' do - element :import_gitlab_url - element :import_gitlab_token - element :connect_instance_button + element 'import-gitlab-url' + element 'import-gitlab-token' + element 'connect-instance-button' end view 'app/assets/javascripts/vue_shared/new_namespace/components/welcome.vue' do - element :panel_link + element 'panel-link' end def set_path(path) - fill_element(:group_path_field, path) - fill_element(:group_name_field, path) + fill_element('group-path-field', path) + fill_element('group-name-field', path) end def create - click_element(:create_group_button) + click_element('create-group-button') end def create_subgroup @@ -39,11 +39,11 @@ module QA end def set_gitlab_url(url) - fill_element(:import_gitlab_url, url) + fill_element('import-gitlab-url', url) end def set_gitlab_token(token) - fill_element(:import_gitlab_token, token) + fill_element('import-gitlab-token', token) end def click_import_group @@ -51,7 +51,7 @@ module QA end def click_create_group - click_on 'Create group' + click_element('panel-link', panel_name: 'create-group-pane') end # Connect gitlab instance @@ -61,16 +61,16 @@ module QA # @return [void] def connect_gitlab_instance(gitlab_url, gitlab_token) # Wait until element is present and refresh if not in case feature flag did not kick in - wait_until(max_duration: 10) { has_element?(:import_gitlab_url, wait: 1) } + wait_until(max_duration: 10) { has_element?('import-gitlab-url', wait: 1) } set_gitlab_url(gitlab_url) set_gitlab_token(gitlab_token) - click_element(:connect_instance_button) + click_element('connect-instance-button') end def switch_to_import_tab - click_element(:panel_link, panel_name: 'import-group-pane') + click_element('panel-link', panel_name: 'import-group-pane') end end end diff --git a/qa/qa/page/group/sub_menus/common.rb b/qa/qa/page/group/sub_menus/common.rb deleted file mode 100644 index 6369306da3f..00000000000 --- a/qa/qa/page/group/sub_menus/common.rb +++ /dev/null @@ -1,30 +0,0 @@ -# frozen_string_literal: true - -module QA - module Page - module Group - module SubMenus - module Common - extend QA::Page::PageConcern - include QA::Page::SubMenus::Common - - def self.included(base) - super - - base.class_eval do - view 'app/views/shared/nav/_sidebar.html.haml' do - element :group_sidebar, 'testid: sidebar_qa_selector(sidebar.container)' # rubocop:disable QA/ElementWithPattern - end - end - end - - private - - def sidebar_element - QA::Runtime::Env.super_sidebar_enabled? ? :navbar : :group_sidebar - end - end - end - end - end -end diff --git a/qa/qa/page/issuable/new.rb b/qa/qa/page/issuable/new.rb index 0a8be750752..8004875dedb 100644 --- a/qa/qa/page/issuable/new.rb +++ b/qa/qa/page/issuable/new.rb @@ -23,7 +23,7 @@ module QA end view 'app/assets/javascripts/sidebar/components/labels/labels_select_widget/dropdown_contents.vue' do - element :labels_select_dropdown_contents + element 'labels-select-dropdown-contents' end view 'app/views/shared/issuable/form/_metadata_issuable_assignee.html.haml' do diff --git a/qa/qa/page/main/login.rb b/qa/qa/page/main/login.rb index 8812c792554..47e50c4a8a3 100644 --- a/qa/qa/page/main/login.rb +++ b/qa/qa/page/main/login.rb @@ -103,12 +103,6 @@ module QA click_element :sign_in_button end - if Runtime::Env.super_sidebar_enabled? - Page::Main::Menu.perform(&:enable_new_navigation) - else - Page::Main::Menu.perform(&:disable_new_navigation) - end - Page::Main::Menu.perform(&:signed_in?) end @@ -269,14 +263,6 @@ module QA wait_for_gitlab_to_respond - if Runtime::Env.super_sidebar_enabled? - Page::Main::Menu.perform(&:enable_new_navigation) - else - Page::Main::Menu.perform(&:disable_new_navigation) - end - - wait_for_gitlab_to_respond - Page::Main::Menu.validate_elements_present! unless skip_page_validation end diff --git a/qa/qa/page/main/menu.rb b/qa/qa/page/main/menu.rb index 29c4360f814..f5bfeecec10 100644 --- a/qa/qa/page/main/menu.rb +++ b/qa/qa/page/main/menu.rb @@ -20,7 +20,7 @@ module QA end view 'app/assets/javascripts/super_sidebar/components/user_menu.vue' do - element :user_dropdown, required: !Runtime::Env.phone_layout? + element 'user-dropdown', required: !Runtime::Env.phone_layout? element :user_avatar_content, required: !Runtime::Env.phone_layout? element :sign_out_link element :edit_profile_link @@ -31,26 +31,26 @@ module QA end view 'app/assets/javascripts/super_sidebar/components/user_bar.vue' do - element :super_sidebar_search_button - element :stop_impersonation_btn - element :issues_shortcut_button, required: !Runtime::Env.phone_layout? - element :merge_requests_shortcut_button, required: !Runtime::Env.phone_layout? - element :todos_shortcut_button, required: !Runtime::Env.phone_layout? + element 'super-sidebar-search-button' + element 'stop-impersonation-btn' + element 'issues-shortcut-button', required: !Runtime::Env.phone_layout? + element 'merge-requests-shortcut-button', required: !Runtime::Env.phone_layout? + element 'todos-shortcut-button', required: !Runtime::Env.phone_layout? end view 'app/assets/javascripts/super_sidebar/components/global_search/components/global_search.vue' do - element :global_search_input + element 'global-search-input' end else view 'app/views/layouts/header/_default.html.haml' do element :navbar, required: true element :canary_badge_link element :user_avatar_content, required: !Runtime::Env.phone_layout? - element :user_dropdown, required: !Runtime::Env.phone_layout? - element :stop_impersonation_btn - element :issues_shortcut_button, required: !Runtime::Env.phone_layout? - element :merge_requests_shortcut_button, required: !Runtime::Env.phone_layout? - element :todos_shortcut_button, required: !Runtime::Env.phone_layout? + element 'user-dropdown', required: !Runtime::Env.phone_layout? + element 'stop-impersonation-btn' + element 'issues-shortcut-button', required: !Runtime::Env.phone_layout? + element 'merge-requests-shortcut-button', required: !Runtime::Env.phone_layout? + element 'todos-shortcut-button', required: !Runtime::Env.phone_layout? end view 'app/views/layouts/header/_current_user_dropdown.html.haml' do @@ -65,7 +65,7 @@ module QA end view 'app/assets/javascripts/nav/components/top_nav_dropdown_menu.vue' do - element :menu_subview + element 'menu-subview' end view 'lib/gitlab/nav/top_nav_menu_item.rb' do @@ -84,11 +84,11 @@ module QA end view 'app/assets/javascripts/header_search/components/app.vue' do - element :global_search_input + element 'global-search-input' end view 'app/views/layouts/header/_new_dropdown.html.haml' do - element :new_menu_toggle + element 'new-menu-toggle' end view 'app/helpers/nav/new_dropdown_helper.rb' do @@ -140,17 +140,17 @@ module QA end def go_to_create_project - click_element(:new_menu_toggle) + click_element('new-menu-toggle') click_element(:global_new_project_link) end def go_to_create_group - click_element(:new_menu_toggle) + click_element('new-menu-toggle') click_element(:global_new_group_link) end def go_to_create_snippet - click_element(:new_menu_toggle) + click_element('new-menu-toggle') click_element(:global_new_snippet_link) end @@ -167,7 +167,7 @@ module QA # @param [Symbol] the name of the element (e.g: `:issues_shortcut button`) # @example: # Menu.perform do |menu| - # menu.go_to_page_by_shortcut(:issues_shortcut_button) #=> Go to Issues page using shortcut button + # menu.go_to_page_by_shortcut('issues-shortcut-button') #=> Go to Issues page using shortcut button # end def go_to_page_by_shortcut(button) within_top_menu do @@ -243,8 +243,8 @@ module QA end def search_for(term) - click_element(Runtime::Env.super_sidebar_enabled? ? :super_sidebar_search_button : :search_box) - fill_element(:global_search_input, "#{term}\n") + click_element(Runtime::Env.super_sidebar_enabled? ? 'super-sidebar-search-button' : :search_box) + fill_element('global-search-input', "#{term}\n") end def has_personal_area?(wait: Capybara.default_max_wait_time) @@ -265,7 +265,7 @@ module QA end def click_stop_impersonation_link - click_element(:stop_impersonation_btn) + click_element('stop-impersonation-btn') end # To verify whether the user has been directed to a canary web node @@ -308,20 +308,20 @@ module QA within_top_menu do click_element :user_avatar_content unless has_element?(:user_profile_link, wait: 1) - within_element(:user_dropdown, &block) + within_element('user-dropdown', &block) end end def within_groups_menu(&block) go_to_menu_dropdown_option(:groups_dropdown) - within_element(:menu_subview, &block) + within_element('menu-subview', &block) end def within_projects_menu(&block) go_to_menu_dropdown_option(:projects_dropdown) - within_element(:menu_subview, &block) + within_element('menu-subview', &block) end def click_admin_area diff --git a/qa/qa/page/merge_request/show.rb b/qa/qa/page/merge_request/show.rb index 71c2aa2d0b3..2ff6460b1c8 100644 --- a/qa/qa/page/merge_request/show.rb +++ b/qa/qa/page/merge_request/show.rb @@ -241,7 +241,7 @@ module QA end def open_file_tree - click_element(:file_tree_button) unless has_element?(:file_tree_container) + click_element(:file_tree_button) if has_no_element?(:file_tree_container, wait: 1) end def has_merge_button? @@ -286,7 +286,6 @@ module QA end def merge! - close_rich_text_promo_popover_if_present try_to_merge! finished_loading? @@ -311,13 +310,14 @@ module QA end end - # Check if the MR is able to be merged - # Waits up 10 seconds and returns false if the MR can't be merged - def mergeable? - # The merge button is enabled via JS, but `has_element?` calls - # `wait_for_requests`, which should ensure the disabled/enabled - # state of the element is reliable - has_element?(:merge_button, disabled: false) + RSpec::Matchers.define :be_mergeable do + match do |page| + page.has_element?(:merge_button, disabled: false) + end + + match_when_negated do |page| + page.has_no_element?(:merge_button, disabled: false) + end end # Waits up 10 seconds and returns false if the Revert button is not enabled diff --git a/qa/qa/page/profile/emails.rb b/qa/qa/page/profile/emails.rb index f8aeea50513..1e6b7518e55 100644 --- a/qa/qa/page/profile/emails.rb +++ b/qa/qa/page/profile/emails.rb @@ -11,9 +11,16 @@ module QA element :add_email_address_button element :email_row_content element :delete_email_link + element :toggle_email_address_field + end + + def expand_email_input + click_element(:toggle_email_address_field) if has_no_element?(:email_address_field) + has_element?(:email_address_field) end def add_email_address(email_address) + expand_email_input find_element(:email_address_field).set email_address click_element(:add_email_address_button) end diff --git a/qa/qa/page/profile/ssh_keys.rb b/qa/qa/page/profile/ssh_keys.rb index 0653df62560..2990ba6a4ac 100644 --- a/qa/qa/page/profile/ssh_keys.rb +++ b/qa/qa/page/profile/ssh_keys.rb @@ -24,6 +24,8 @@ module QA end def add_key(public_key, title) + click_button('Add new key') + fill_element(:key_public_key_field, public_key) fill_element(:key_title_field, title) # Expire in 2 days just in case the key is created just before midnight diff --git a/qa/qa/page/project/import/github.rb b/qa/qa/page/project/import/github.rb index 898bf78b46a..9e1bf0a393f 100644 --- a/qa/qa/page/project/import/github.rb +++ b/qa/qa/page/project/import/github.rb @@ -19,7 +19,7 @@ module QA element :import_status_indicator end - view "app/assets/javascripts/import_entities/components/group_dropdown.vue" do + view "app/assets/javascripts/import_entities/components/import_target_dropdown.vue" do element :target_namespace_selector_dropdown end @@ -47,7 +47,7 @@ module QA def import!(gh_project_name, target_group_path, project_name) within_element(:project_import_row, source_project: gh_project_name) do click_element(:target_namespace_selector_dropdown) - click_element(:target_group_dropdown_item, group_name: target_group_path) + click_element("listbox-item-#{target_group_path}", wait: 10) fill_element(:project_path_field, project_name) retry_until do diff --git a/qa/qa/page/project/import/repo_by_url.rb b/qa/qa/page/project/import/repo_by_url.rb index 1adfe001573..1e12ec1541d 100644 --- a/qa/qa/page/project/import/repo_by_url.rb +++ b/qa/qa/page/project/import/repo_by_url.rb @@ -6,12 +6,12 @@ module QA module Import class RepoByURL < Page::Base view 'app/assets/javascripts/projects/new/components/new_project_url_select.vue' do - element :select_namespace_dropdown - element :select_namespace_dropdown_search_field + element 'select-namespace-dropdown' + element 'select-namespace-dropdown-search-field' end view 'app/views/projects/_new_project_fields.html.haml' do - element :project_create_button + element 'project-create-button' end def import!(gitlab_repo_path, name) @@ -39,14 +39,14 @@ module QA def choose_namespace(namespace) retry_on_exception do - click_element :select_namespace_dropdown - fill_element :select_namespace_dropdown_search_field, namespace + click_element 'select-namespace-dropdown' + fill_element 'select-namespace-dropdown-search-field', namespace click_button namespace end end def click_create_button - click_element(:project_create_button) + click_element('project-create-button') end def wait_for_success diff --git a/qa/qa/page/project/infrastructure/kubernetes/add_existing.rb b/qa/qa/page/project/infrastructure/kubernetes/add_existing.rb deleted file mode 100644 index 2fc65cf0afe..00000000000 --- a/qa/qa/page/project/infrastructure/kubernetes/add_existing.rb +++ /dev/null @@ -1,46 +0,0 @@ -# frozen_string_literal: true - -module QA - module Page - module Project - module Infrastructure - module Kubernetes - class AddExisting < Page::Base - view 'app/views/clusters/clusters/user/_form.html.haml' do - element :cluster_name, 'text_field :name' # rubocop:disable QA/ElementWithPattern - element :api_url, 'url_field :api_url' # rubocop:disable QA/ElementWithPattern - element :ca_certificate, 'text_area :ca_cert' # rubocop:disable QA/ElementWithPattern - element :token, 'text_field :token' # rubocop:disable QA/ElementWithPattern - element :add_kubernetes_cluster_button - element :rbac_checkbox - end - - def set_cluster_name(name) - fill_in 'cluster_name', with: name - end - - def set_api_url(api_url) - fill_in 'cluster_platform_kubernetes_attributes_api_url', with: api_url - end - - def set_ca_certificate(ca_certificate) - fill_in 'cluster_platform_kubernetes_attributes_ca_cert', with: ca_certificate - end - - def set_token(token) - fill_in 'cluster_platform_kubernetes_attributes_token', with: token - end - - def add_cluster! - click_element :add_kubernetes_cluster_button, Page::Project::Infrastructure::Kubernetes::Show - end - - def uncheck_rbac! - uncheck_element(:rbac_checkbox) - end - end - end - end - end - end -end diff --git a/qa/qa/page/project/infrastructure/kubernetes/index.rb b/qa/qa/page/project/infrastructure/kubernetes/index.rb deleted file mode 100644 index 4c759a049e1..00000000000 --- a/qa/qa/page/project/infrastructure/kubernetes/index.rb +++ /dev/null @@ -1,25 +0,0 @@ -# frozen_string_literal: true - -module QA - module Page - module Project - module Infrastructure - module Kubernetes - class Index < Page::Base - view 'app/assets/javascripts/clusters_list/components/clusters_actions.vue' do - element :clusters_actions_button - end - - def connect_cluster - click_element(:clusters_actions_button) - end - - def has_cluster?(cluster) - has_element?(:cluster, cluster_name: cluster.to_s) - end - end - end - end - end - end -end diff --git a/qa/qa/page/project/infrastructure/kubernetes/show.rb b/qa/qa/page/project/infrastructure/kubernetes/show.rb deleted file mode 100644 index 8725f64fe32..00000000000 --- a/qa/qa/page/project/infrastructure/kubernetes/show.rb +++ /dev/null @@ -1,30 +0,0 @@ -# frozen_string_literal: true - -module QA - module Page - module Project - module Infrastructure - module Kubernetes - class Show < Page::Base - view 'app/assets/javascripts/clusters/forms/components/integration_form.vue' do - element :integration_status_toggle - element :base_domain_field - end - - view 'app/assets/javascripts/integrations/edit/components/integration_form_actions.vue' do - element :save_changes_button - end - - def set_domain(domain) - fill_element :base_domain_field, domain - end - - def save_domain - click_element :save_changes_button, Page::Project::Infrastructure::Kubernetes::Show - end - end - end - end - end - end -end diff --git a/qa/qa/page/project/issue/show.rb b/qa/qa/page/project/issue/show.rb index c95375dbbb9..8092b69d377 100644 --- a/qa/qa/page/project/issue/show.rb +++ b/qa/qa/page/project/issue/show.rb @@ -19,9 +19,9 @@ module QA end view 'app/assets/javascripts/issues/show/components/header_actions.vue' do - element :toggle_issue_state_button - element :desktop_dropdown - element :delete_issue_button + element 'toggle-issue-state-button' + element 'desktop-dropdown' + element 'delete-issue-button' end view 'app/assets/javascripts/related_issues/components/add_issuable_form.vue' do @@ -33,7 +33,7 @@ module QA end view 'app/assets/javascripts/related_issues/components/related_issues_block.vue' do - element :related_issues_plus_button + element 'related-issues-plus-button' end view 'app/assets/javascripts/related_issues/components/related_issues_list.vue' do @@ -42,7 +42,7 @@ module QA end def relate_issue(issue) - click_element(:related_issues_plus_button) + click_element('related-issues-plus-button') fill_element(:add_issue_field, issue.web_url) send_keys_to_element(:add_issue_field, :enter) end @@ -63,29 +63,30 @@ module QA end def click_close_issue_button - # Click by JS is needed to bypass the Moved MR actions popover - # Change back to regular click_element when moved_mr_sidebar FF is removed - # Rollout issue: https://gitlab.com/gitlab-org/gitlab/-/issues/385460 - click_by_javascript(find_element(:toggle_issue_state_button, text: 'Close issue')) + open_actions_dropdown + click_element('toggle-issue-state-button', text: 'Close issue') end def has_reopen_issue_button? - has_element?(:toggle_issue_state_button, text: 'Reopen issue') + open_actions_dropdown + has_element?('toggle-issue-state-button', text: 'Reopen issue') end def has_delete_issue_button? - # Click by JS is needed to bypass the Moved MR actions popover - # Change back to regular click_element when moved_mr_sidebar FF is removed - # Rollout issue: https://gitlab.com/gitlab-org/gitlab/-/issues/385460 - click_by_javascript(find('[data-testid="desktop-dropdown"] > button')) - has_element?(:delete_issue_button) + open_actions_dropdown + has_element?('delete-issue-button') + end + + def has_no_delete_issue_button? + open_actions_dropdown + has_no_element?('delete-issue-button') end def delete_issue has_delete_issue_button? click_element( - :delete_issue_button, + 'delete-issue-button', Page::Modal::DeleteIssue, wait: Support::Repeater::DEFAULT_MAX_WAIT_TIME ) @@ -94,6 +95,11 @@ module QA wait_for_requests end + + def open_actions_dropdown + # We use find here because these are gitlab-ui elements + find('[data-testid="desktop-dropdown"] > button').click + end end end end diff --git a/qa/qa/page/project/new.rb b/qa/qa/page/project/new.rb index 8ea0b57ef3e..d61f9cf0218 100644 --- a/qa/qa/page/project/new.rb +++ b/qa/qa/page/project/new.rb @@ -6,41 +6,42 @@ module QA class New < Page::Base include Page::Component::Project::Templates include Page::Component::VisibilitySetting + include QA::Page::Component::Dropdown include Layout::Flash include Page::Component::Import::Selection include Page::Component::Import::Gitlab view 'app/views/projects/_new_project_fields.html.haml' do - element :initialize_with_readme_checkbox - element :initialize_with_sast_checkbox - element :project_name - element :project_path - element :project_description - element :project_create_button - element :visibility_radios + element 'initialize-with-readme-checkbox' + element 'initialize-with-sast-checkbox' + element 'project-name' + element 'project-path' + element 'project-description' + element 'project-create-button' + element 'visibility-radios' end view 'app/views/projects/project_templates/_template.html.haml' do - element :use_template_button - element :template_option_container + element 'use-template-button' + element 'template-option-container' end view 'app/assets/javascripts/projects/new/components/new_project_url_select.vue' do - element :select_namespace_dropdown - element :select_namespace_dropdown_search_field + element 'select-namespace-dropdown' + element 'select-namespace-dropdown-search-field' end view 'app/assets/javascripts/vue_shared/new_namespace/components/welcome.vue' do - element :panel_link + element 'panel-link' end def click_blank_project_link - click_element(:panel_link, panel_name: 'blank_project') + click_element('panel-link', panel_name: 'blank_project') end def click_create_from_template_link - click_element(:panel_link, panel_name: 'create_from_template') + click_element('panel-link', panel_name: 'create_from_template') end def choose_test_namespace @@ -48,9 +49,12 @@ module QA end def choose_namespace(namespace) - click_element :select_namespace_dropdown - fill_element :select_namespace_dropdown_search_field, namespace - within_element(:select_namespace_dropdown) { click_button namespace } + # The current group is the default, we use end_with? in case we want to select the top level group + return if find_element('select-namespace-dropdown').text.end_with?(namespace) + + click_element 'select-namespace-dropdown' + fill_element 'select-namespace-dropdown-search-field', namespace + select_item(namespace, css: '.gl-dropdown-item') end def click_import_project @@ -62,7 +66,7 @@ module QA end def add_description(description) - return unless has_element?(:project_description, wait: 1) + return unless has_element?('project-description', wait: 1) fill_in 'project_description', with: description end @@ -81,9 +85,9 @@ module QA # Disable experiment for SAST at project creation https://gitlab.com/gitlab-org/gitlab/-/issues/333196 def disable_initialize_with_sast - return unless has_element?(:initialize_with_sast_checkbox, visible: false) + return unless has_element?('initialize-with-sast-checkbox', visible: false) - uncheck_element(:initialize_with_sast_checkbox, true) + uncheck_element('initialize-with-sast-checkbox', true) end def click_github_link @@ -99,7 +103,7 @@ module QA end def disable_initialize_with_readme - uncheck_element(:initialize_with_readme_checkbox, true) + uncheck_element('initialize-with-readme-checkbox', true) end end end diff --git a/qa/qa/page/project/packages/index.rb b/qa/qa/page/project/packages/index.rb index e58ffba3cd5..f3a8bc8c175 100644 --- a/qa/qa/page/project/packages/index.rb +++ b/qa/qa/page/project/packages/index.rb @@ -6,27 +6,27 @@ module QA module Packages class Index < QA::Page::Base view 'app/assets/javascripts/packages_and_registries/package_registry/components/list/package_list_row.vue' do - element :package_link + element 'details-link' end view 'app/assets/javascripts/packages_and_registries/infrastructure_registry/shared/package_list_row.vue' do - element :package_link + element 'details-link' end def click_package(name) - click_element(:package_link, text: name) + click_element('details-link', text: name) end def has_package?(name) - has_element?(:package_link, text: name, wait: 20) + has_element?('details-link', text: name, wait: 20) end def has_module?(name) - has_element?(:package_link, text: name, wait: 20) + has_element?('details-link', text: name, wait: 20) end def has_no_package?(name) - has_no_element?(:package_link, text: name) + has_no_element?('details-link', text: name) end end end diff --git a/qa/qa/page/project/packages/show.rb b/qa/qa/page/project/packages/show.rb index 5ba9ad7df40..6c265c2a66d 100644 --- a/qa/qa/page/project/packages/show.rb +++ b/qa/qa/page/project/packages/show.rb @@ -6,19 +6,19 @@ module QA module Packages class Show < QA::Page::Base view 'app/assets/javascripts/packages_and_registries/package_registry/pages/details.vue' do - element :delete_button - element :delete_modal_button - element :package_information_content + element 'delete-package' + element 'delete-modal-button' + element 'package-information-content' end def has_package_info?(name, version) - has_element?(:package_information_content, text: /#{name}.*#{version}/) + has_element?('package-information-content', text: /#{name}.*#{version}/) end def click_delete - click_element(:delete_button) - wait_for_animated_element(:delete_modal_button) - click_element(:delete_modal_button) + click_element('delete-package') + wait_for_animated_element('delete-modal-button') + click_element('delete-modal-button') end end end diff --git a/qa/qa/page/project/registry/show.rb b/qa/qa/page/project/registry/show.rb index 95850f34962..0deeb5b4ae0 100644 --- a/qa/qa/page/project/registry/show.rb +++ b/qa/qa/page/project/registry/show.rb @@ -6,34 +6,34 @@ module QA module Registry class Show < QA::Page::Base view 'app/assets/javascripts/packages_and_registries/container_registry/explorer/components/list_page/image_list_row.vue' do - element :registry_image_content + element 'details-link' end view 'app/assets/javascripts/packages_and_registries/container_registry/explorer/components/details_page/tags_list_row.vue' do - element :more_actions_menu - element :tag_delete_button - element :tag_name_content + element 'additional-actions' + element 'single-delete-button' + element :name end def has_registry_repository?(name) - find_element(:registry_image_content, text: name) + find_element('details-link', text: name) end def click_on_image(name) - click_element(:registry_image_content, text: name) + click_element('details-link', text: name) end def has_tag?(tag_name) - has_element?(:tag_name_content, text: tag_name) + has_element?(:name, text: tag_name) end def has_no_tag?(tag_name) - has_no_element?(:tag_name_content, text: tag_name) + has_no_element?(:name, text: tag_name) end def click_delete - click_element(:more_actions_menu) - click_element(:tag_delete_button) + click_element('additional-actions') + click_element('single-delete-button') find_button('Delete').click end end diff --git a/qa/qa/page/project/secure/configuration_form.rb b/qa/qa/page/project/secure/configuration_form.rb index 70eff31bfa9..32609943f3e 100644 --- a/qa/qa/page/project/secure/configuration_form.rb +++ b/qa/qa/page/project/secure/configuration_form.rb @@ -8,30 +8,30 @@ module QA include QA::Page::Settings::Common view 'app/assets/javascripts/security_configuration/components/app.vue' do - element :security_configuration_container - element :security_view_history_link + element 'security-configuration-container' + element 'security-view-history-link' end view 'app/assets/javascripts/security_configuration/components/feature_card.vue' do - element :feature_status + element 'feature-status' element :sast_enable_button, "`${feature.type}_enable_button`" # rubocop:disable QA/ElementWithPattern element :dependency_scanning_mr_button, "`${feature.type}_mr_button`" # rubocop:disable QA/ElementWithPattern end view 'app/assets/javascripts/security_configuration/components/auto_dev_ops_alert.vue' do - element :autodevops_container + element 'autodevops-container' end def has_security_configuration_history_link? - has_element?(:security_view_history_link) + has_element?('security-view-history-link') end def has_no_security_configuration_history_link? - has_no_element?(:security_view_history_link) + has_no_element?('security-view-history-link') end def click_security_configuration_history_link - click_element(:security_view_history_link) + click_element('security-view-history-link') end def click_sast_enable_button @@ -43,31 +43,31 @@ module QA end def has_true_sast_status? - has_element?(:feature_status, feature: 'sast_true_status') + has_element?('feature-status', feature: 'sast_true_status') end def has_false_sast_status? - has_element?(:feature_status, feature: 'sast_false_status') + has_element?('feature-status', feature: 'sast_false_status') end def has_true_dependency_scanning_status? - has_element?(:feature_status, feature: 'dependency_scanning_true_status') + has_element?('feature-status', feature: 'dependency_scanning_true_status') end def has_false_dependency_scanning_status? - has_element?(:feature_status, feature: 'dependency_scanning_false_status') + has_element?('feature-status', feature: 'dependency_scanning_false_status') end def has_auto_devops_container? - has_element?(:autodevops_container) + has_element?('autodevops-container') end def has_no_auto_devops_container? - has_no_element?(:autodevops_container) + has_no_element?('autodevops-container') end def has_auto_devops_container_description? - within_element(:autodevops_container) do + within_element('autodevops-container') do has_text?('Quickly enable all continuous testing and compliance tools by enabling Auto DevOps') end end @@ -79,7 +79,7 @@ module QA private def go_to_tab(name) - within_element(:security_configuration_container) do + within_element('security-configuration-container') do find('.nav-item', text: name).click end end diff --git a/qa/qa/page/project/settings/ci_variables.rb b/qa/qa/page/project/settings/ci_variables.rb index 4b587e28382..36c667866b5 100644 --- a/qa/qa/page/project/settings/ci_variables.rb +++ b/qa/qa/page/project/settings/ci_variables.rb @@ -19,8 +19,7 @@ module QA click_ci_variable_save_button wait_until(reload: false) do - # Using data-testid="ci-variable-table" - within_element(:ci_variable_table) { has_element?(:edit_ci_variable_button) } + within_element('ci-variable-table') { has_element?(:edit_ci_variable_button) } end end @@ -29,8 +28,7 @@ module QA end def click_edit_ci_variable - # Using data-testid="ci-variable-table" - within_element(:ci_variable_table) do + within_element('ci-variable-table') do click_element :edit_ci_variable_button end end diff --git a/qa/qa/page/project/settings/deploy_keys.rb b/qa/qa/page/project/settings/deploy_keys.rb index b94dbbea533..d8369c12268 100644 --- a/qa/qa/page/project/settings/deploy_keys.rb +++ b/qa/qa/page/project/settings/deploy_keys.rb @@ -6,65 +6,70 @@ module QA module Settings class DeployKeys < Page::Base view 'app/views/shared/deploy_keys/_form.html.haml' do - element :deploy_key_title_field - element :deploy_key_field + element 'deploy-key-title-field' + element 'deploy-key-field' end view 'app/views/shared/deploy_keys/_project_group_form.html.haml' do - element :deploy_key_title_field - element :deploy_key_field - element :deploy_key_expires_at_field - element :add_deploy_key_button + element 'deploy-key-title-field' + element 'deploy-key-field' + element 'deploy-key-expires-at-field' + element 'add-deploy-key-button' end view 'app/assets/javascripts/deploy_keys/components/app.vue' do - element :project_deploy_keys_container + element 'project-deploy-keys-container' + element 'add-new-deploy-key-button' end view 'app/assets/javascripts/deploy_keys/components/key.vue' do - element :key_container - element :key_title_content - element :key_sha256_fingerprint_content + element 'key-container' + element 'key-title-content' + element 'key-sha256-fingerprint-content' + end + + def add_new_key + click_element('add-new-deploy-key-button') end def add_key - click_element(:add_deploy_key_button) + click_element('add-deploy-key-button') end def fill_key_title(title) - fill_element(:deploy_key_title_field, title) + fill_element('deploy-key-title-field', title) end def fill_key_value(key) - fill_element(:deploy_key_field, key) + fill_element('deploy-key-field', key) end def find_sha256_fingerprint(title) within_project_deploy_keys do - find_element(:key_container, text: title) - .find(element_selector_css(:key_sha256_fingerprint_content)).text + find_element('key-container', text: title) + .find(element_selector_css('key-sha256-fingerprint-content')).text end end def has_key?(title, sha256_fingerprint) within_project_deploy_keys do - find_element(:key_container, text: title) - .has_css?(element_selector_css(:key_sha256_fingerprint_content), text: sha256_fingerprint) + find_element('key-container', text: title) + .has_css?(element_selector_css('key-sha256-fingerprint-content'), text: sha256_fingerprint) end end def key_title within_project_deploy_keys do - find_element(:key_title_content).text + find_element('key-title-content').text end end private def within_project_deploy_keys - has_element?(:project_deploy_keys_container, wait: QA::Support::Repeater::DEFAULT_MAX_WAIT_TIME) + has_element?('project-deploy-keys-container', wait: QA::Support::Repeater::DEFAULT_MAX_WAIT_TIME) - within_element(:project_deploy_keys_container) do + within_element('project-deploy-keys-container') do yield end end diff --git a/qa/qa/page/project/settings/mirroring_repositories.rb b/qa/qa/page/project/settings/mirroring_repositories.rb index c9ce80076e2..85b413ba880 100644 --- a/qa/qa/page/project/settings/mirroring_repositories.rb +++ b/qa/qa/page/project/settings/mirroring_repositories.rb @@ -13,6 +13,7 @@ module QA view 'app/views/projects/mirrors/_mirror_repos.html.haml' do element :mirror_repository_url_field element :mirror_repository_button + element 'add-new-mirror' end view 'app/views/projects/mirrors/_mirror_repos_list.html.haml' do @@ -37,6 +38,7 @@ module QA end def repository_url=(value) + click_element 'add-new-mirror' fill_element :mirror_repository_url_field, value end diff --git a/qa/qa/page/project/settings/protected_branches.rb b/qa/qa/page/project/settings/protected_branches.rb index e6b13ed77a0..93522c1deac 100644 --- a/qa/qa/page/project/settings/protected_branches.rb +++ b/qa/qa/page/project/settings/protected_branches.rb @@ -5,6 +5,10 @@ module QA module Project module Settings class ProtectedBranches < Page::Base + view 'app/views/protected_branches/shared/_index.html.haml' do + element 'add-protected-branch-button' + end + view 'app/views/protected_branches/shared/_dropdown.html.haml' do element :protected_branch_dropdown element :protected_branch_dropdown_content @@ -22,6 +26,7 @@ module QA end def select_branch(branch_name) + click_element 'add-protected-branch-button' click_element :protected_branch_dropdown within_element(:protected_branch_dropdown_content) do diff --git a/qa/qa/page/project/settings/protected_tags.rb b/qa/qa/page/project/settings/protected_tags.rb index d9f383154f9..49fdae5f8a3 100644 --- a/qa/qa/page/project/settings/protected_tags.rb +++ b/qa/qa/page/project/settings/protected_tags.rb @@ -21,6 +21,7 @@ module QA end def set_tag(tag_name) + click_button 'Add tag' click_element :tags_dropdown filter_and_select(tag_name) end @@ -32,6 +33,7 @@ module QA within_element(:access_levels_content) do click_on role end + click_element :access_levels_dropdown end def click_protect_tag_button diff --git a/qa/qa/page/project/settings/repository.rb b/qa/qa/page/project/settings/repository.rb index d9aaacbde32..4e53ea1aee9 100644 --- a/qa/qa/page/project/settings/repository.rb +++ b/qa/qa/page/project/settings/repository.rb @@ -20,7 +20,7 @@ module QA end view 'app/views/shared/deploy_keys/_index.html.haml' do - element :deploy_keys_settings_content + element 'deploy-keys-settings-content' end view 'app/views/projects/protected_tags/shared/_index.html.haml' do @@ -38,7 +38,7 @@ module QA end def expand_deploy_keys(&block) - expand_content(:deploy_keys_settings_content) do + expand_content('deploy-keys-settings-content') do Settings::DeployKeys.perform(&block) end end diff --git a/qa/qa/page/project/show.rb b/qa/qa/page/project/show.rb index 95a6c840684..59cccfd665a 100644 --- a/qa/qa/page/project/show.rb +++ b/qa/qa/page/project/show.rb @@ -26,7 +26,7 @@ module QA end view 'app/views/layouts/header/_new_dropdown.html.haml' do - element :new_menu_toggle + element 'new-menu-toggle' end view 'app/views/projects/_last_push.html.haml' do @@ -49,8 +49,8 @@ module QA element :forked_from_link end - view 'app/views/projects/buttons/_fork.html.haml' do - element :fork_button + view 'app/assets/javascripts/forks/components/forks_button.vue' do + element 'fork-button' end view 'app/views/projects/empty.html.haml' do @@ -93,7 +93,7 @@ module QA # Change back to regular click_element when vscode_web_ide FF is removed # Rollout issue: https://gitlab.com/gitlab-org/gitlab/-/issues/371084 def fork_project - fork_button = find_element(:fork_button) + fork_button = find_element('fork-button') click_by_javascript(fork_button) end diff --git a/qa/qa/page/project/sub_menus/common.rb b/qa/qa/page/project/sub_menus/common.rb index e8952f9e064..280d28a697d 100644 --- a/qa/qa/page/project/sub_menus/common.rb +++ b/qa/qa/page/project/sub_menus/common.rb @@ -6,12 +6,13 @@ module QA module SubMenus module Common extend QA::Page::PageConcern - include QA::Page::SubMenus::Common def self.included(base) super base.class_eval do + include QA::Page::SubMenus::Common + view 'app/views/shared/nav/_sidebar_menu_item.html.haml' do element :sidebar_menu_item_link end @@ -25,12 +26,6 @@ module QA end end end - - private - - def sidebar_element - QA::Runtime::Env.super_sidebar_enabled? ? :navbar : :project_sidebar - end end end end diff --git a/qa/qa/page/sub_menus/common.rb b/qa/qa/page/sub_menus/common.rb index 28b4cb37333..19d07e885c6 100644 --- a/qa/qa/page/sub_menus/common.rb +++ b/qa/qa/page/sub_menus/common.rb @@ -6,6 +6,16 @@ module QA module Common prepend Mobile::Page::SubMenus::Common if QA::Runtime::Env.mobile_layout? + def self.included(base) + super + + base.class_eval do + view 'app/assets/javascripts/super_sidebar/components/super_sidebar.vue' do + element :navbar + end + end + end + def hover_element(element) within_sidebar do find_element(element).hover @@ -16,7 +26,7 @@ module QA def within_sidebar(&block) wait_for_requests - within_element(sidebar_element, &block) + within_element(:navbar, &block) end def within_submenu(element = nil, &block) @@ -33,7 +43,7 @@ module QA # # @return [void] def within_new_item_menu - click_element(:new_menu_toggle) + click_element('new-menu-toggle') yield end @@ -58,10 +68,6 @@ module QA def within_submenu_without_element(&block) has_css?('.fly-out-list') ? within('.fly-out-list', &block) : yield end - - def sidebar_element - raise NotImplementedError - end end end end diff --git a/qa/qa/page/sub_menus/super_sidebar/context_switcher.rb b/qa/qa/page/sub_menus/super_sidebar/context_switcher.rb index e5f2e702e60..af06438782d 100644 --- a/qa/qa/page/sub_menus/super_sidebar/context_switcher.rb +++ b/qa/qa/page/sub_menus/super_sidebar/context_switcher.rb @@ -12,8 +12,11 @@ module QA base.class_eval do view 'app/assets/javascripts/super_sidebar/components/context_switcher_toggle.vue' do - element :context_switcher - element :context_navigation + element 'context-switcher' + end + + view 'app/assets/javascripts/super_sidebar/components/context_switcher.vue' do + element 'context-navigation' end end end @@ -44,7 +47,7 @@ module QA end def open_context_switcher - click_element(:context_switcher) unless has_element?(:context_navigation, wait: 0) + click_element('context-switcher') unless has_element?('context-navigation', wait: 0) end end end diff --git a/qa/qa/resource/api_fabricator.rb b/qa/qa/resource/api_fabricator.rb index 3f9d2b92a0a..5f431103df3 100644 --- a/qa/qa/resource/api_fabricator.rb +++ b/qa/qa/resource/api_fabricator.rb @@ -26,7 +26,10 @@ module QA raise NotImplementedError, "Resource #{self.class.name} does not support fabrication via the API!" end - resource_web_url(api_post) + resource_web_url = resource_web_url(api_post) + wait_for_resource_availability(resource_web_url) + + resource_web_url end def reload! @@ -222,6 +225,22 @@ module QA v.is_a?(Hash) ? a.merge(flatten_hash(v)) : a.merge(k.to_sym => v) end end + + # Given a URL, wait for the given URL to return 200 + # @param [String] resource_web_url the URL to check + # @example + # wait_for_resource_availability('https://gitlab.com/api/v4/projects/1234') + # @example + # wait_for_resource_availability(resource_web_url(Resource::Issue.fabricate_via_api!)) + def wait_for_resource_availability(resource_web_url) + return unless Runtime::Address.valid?(resource_web_url) + + Support::Retrier.retry_until(sleep_interval: 3, max_attempts: 5, raise_on_failure: false) do + response_check = get(resource_web_url) + Runtime::Logger.debug("Resource availability check ... #{response_check.code}") + response_check.code == HTTP_STATUS_OK + end + end end end end diff --git a/qa/qa/resource/badge_base.rb b/qa/qa/resource/badge_base.rb index bc0adf0857d..8139cc2ec7b 100644 --- a/qa/qa/resource/badge_base.rb +++ b/qa/qa/resource/badge_base.rb @@ -11,6 +11,7 @@ module QA def fabricate! Page::Component::Badges.perform do |badges| + badges.show_badge_add_form badges.fill_name(name) badges.fill_link_url(link_url) badges.fill_image_url(image_url) diff --git a/qa/qa/resource/clusters/agent.rb b/qa/qa/resource/clusters/agent.rb index 9574289a2ed..9d3f2a32aaf 100644 --- a/qa/qa/resource/clusters/agent.rb +++ b/qa/qa/resource/clusters/agent.rb @@ -33,6 +33,10 @@ module QA "/projects/#{project.id}/cluster_agents" end + def api_delete_path + api_get_path + end + def api_post_body { id: project.id, diff --git a/qa/qa/resource/clusters/agent_token.rb b/qa/qa/resource/clusters/agent_token.rb index cbd2964c31d..a6eea44100b 100644 --- a/qa/qa/resource/clusters/agent_token.rb +++ b/qa/qa/resource/clusters/agent_token.rb @@ -27,6 +27,10 @@ module QA "/projects/#{agent.project.id}/cluster_agents/#{agent.id}/tokens" end + def api_delete_path + api_get_path + end + def api_post_body { id: agent.project.id, diff --git a/qa/qa/resource/deploy_key.rb b/qa/qa/resource/deploy_key.rb index b194f97ef1b..36d1221dfda 100644 --- a/qa/qa/resource/deploy_key.rb +++ b/qa/qa/resource/deploy_key.rb @@ -29,6 +29,7 @@ module QA Page::Project::Settings::Repository.perform do |setting| setting.expand_deploy_keys do |page| + page.add_new_key page.fill_key_title(title) page.fill_key_value(key) diff --git a/qa/qa/resource/group_access_token.rb b/qa/qa/resource/group_access_token.rb index a1079b16971..cfb2d1a1bca 100644 --- a/qa/qa/resource/group_access_token.rb +++ b/qa/qa/resource/group_access_token.rb @@ -84,6 +84,7 @@ module QA Page::Group::Menu.perform(&:go_to_access_token_settings) Page::Group::Settings::AccessTokens.perform do |token_page| + token_page.click_add_new_token_button token_page.fill_token_name(name) token_page.check_api token_page.fill_expiry_date(expires_at) diff --git a/qa/qa/resource/impersonation_token.rb b/qa/qa/resource/impersonation_token.rb index 99a9cd7bbab..07fb7e0d199 100644 --- a/qa/qa/resource/impersonation_token.rb +++ b/qa/qa/resource/impersonation_token.rb @@ -82,6 +82,7 @@ module QA Page::Admin::Overview::Users::Show.perform do |show| show.go_to_impersonation_tokens do |impersonation_tokens| + impersonation_tokens.click_add_new_token_button impersonation_tokens.fill_token_name(name) impersonation_tokens.check_api impersonation_tokens.fill_expiry_date(expires_at) diff --git a/qa/qa/resource/issue.rb b/qa/qa/resource/issue.rb index a39e04c61a3..72b57801053 100644 --- a/qa/qa/resource/issue.rb +++ b/qa/qa/resource/issue.rb @@ -20,6 +20,10 @@ module QA :title, :description + attribute :confidential do + false + end + def initialize @assignee_ids = [] @labels = [] @@ -57,7 +61,8 @@ module QA { assignee_ids: assignee_ids, labels: labels, - title: title + title: title, + confidential: confidential }.tap do |hash| hash[:milestone_id] = @milestone.id if @milestone hash[:weight] = @weight if @weight diff --git a/qa/qa/resource/merge_request.rb b/qa/qa/resource/merge_request.rb index 93e8c4f3be6..fdf1a2a97ac 100644 --- a/qa/qa/resource/merge_request.rb +++ b/qa/qa/resource/merge_request.rb @@ -25,6 +25,7 @@ module QA :description, :merge_when_pipeline_succeeds, :detailed_merge_status, + :prepared_at, :state, :reviewers @@ -110,7 +111,9 @@ module QA rescue ResourceNotFoundError, NoValueError # rescue if iid not populated populate_target_and_source_if_required - super + url = super + wait_for_preparation + url end def api_merge_path @@ -265,6 +268,18 @@ module QA raise Support::Repeater::WaitExceededError, "Timed out waiting for merge of MR with id '#{iid}'. Final status was '#{detailed_merge_status}'" end + + # Wait until the merge request is prepared. Raises WaitExceededError if the MR is not prepared within 60 seconds + # https://docs.gitlab.com/ee/api/merge_requests.html#preparation-steps + # + # @return [void] + def wait_for_preparation + return if Support::Waiter.wait_until(sleep_interval: 1, raise_on_failure: false, log: false) do + reload!.prepared_at + end + + raise Support::Repeater::WaitExceededError, "Timed out waiting for MR with id '#{iid}' to be prepared." + end end end end diff --git a/qa/qa/resource/personal_access_token.rb b/qa/qa/resource/personal_access_token.rb index 33044774c59..9152e28e515 100644 --- a/qa/qa/resource/personal_access_token.rb +++ b/qa/qa/resource/personal_access_token.rb @@ -105,6 +105,7 @@ module QA Page::Profile::Menu.perform(&:click_access_tokens) Page::Profile::PersonalAccessTokens.perform do |token_page| + token_page.click_add_new_token_button token_page.fill_token_name(name || 'api-test-token') token_page.check_api token_page.fill_expiry_date(expires_at) diff --git a/qa/qa/resource/project_access_token.rb b/qa/qa/resource/project_access_token.rb index 1ccf2103d1d..8bb782ee6db 100644 --- a/qa/qa/resource/project_access_token.rb +++ b/qa/qa/resource/project_access_token.rb @@ -84,6 +84,7 @@ module QA Page::Project::Menu.perform(&:go_to_access_token_settings) Page::Project::Settings::AccessTokens.perform do |token_page| + token_page.click_add_new_token_button token_page.fill_token_name(name) token_page.check_api token_page.fill_expiry_date(expires_at) diff --git a/qa/qa/runtime/allure_report.rb b/qa/qa/runtime/allure_report.rb index e726f7a316f..b75163deb67 100644 --- a/qa/qa/runtime/allure_report.rb +++ b/qa/qa/runtime/allure_report.rb @@ -35,6 +35,9 @@ module QA config.issue_tag = :issue config.link_issue_pattern = '{}' + # custom grouping of failures, https://docs.qameta.io/allure-report/#_categories_2 + config.categories = File.new(File.join(Runtime::Path.qa_root, "allure", "categories.json")) + if Env.running_in_ci? config.environment_properties = environment_info # Set custom environment name to separate same specs executed in different jobs diff --git a/qa/qa/runtime/env.rb b/qa/qa/runtime/env.rb index 517cb00df41..7c9a6c93335 100644 --- a/qa/qa/runtime/env.rb +++ b/qa/qa/runtime/env.rb @@ -451,6 +451,56 @@ module QA %w[GCLOUD_ACCOUNT_KEY GCLOUD_ACCOUNT_EMAIL].none? { |var| ENV[var].to_s.empty? } end + # ENV variables for workspaces to run against existing cluster or creating new cluster + def workspaces_cluster_available? + enabled?(ENV['WORKSPACES_CLUSTER_AVAILABLE'], default: false) + end + + def workspaces_cluster_name + ENV.fetch("WORKSPACES_CLUSTER_NAME") + end + + def workspaces_cluster_region + ENV.fetch("WORKSPACES_CLUSTER_REGION") + end + + # ENV variables for workspaces OAuth App and the domain + def workspaces_oauth_app_id + ENV.fetch("WORKSPACES_OAUTH_APP_ID") + end + + def workspaces_oauth_app_secret + ENV.fetch("WORKSPACES_OAUTH_APP_SECRET") + end + + def workspaces_oauth_redirect_uri + ENV.fetch("WORKSPACES_OAUTH_REDIRECT_URI") + end + + def workspaces_oauth_signing_key + ENV.fetch("WORKSPACES_OAUTH_SIGNING_KEY") + end + + def workspaces_proxy_domain + ENV.fetch("WORKSPACES_PROXY_DOMAIN") + end + + def workspaces_domain_cert + ENV.fetch("WORKSPACES_DOMAIN_CERT") + end + + def workspaces_domain_key + ENV.fetch("WORKSPACES_DOMAIN_KEY") + end + + def workspaces_wildcard_cert + ENV.fetch("WORKSPACES_WILDCARD_CERT") + end + + def workspaces_wildcard_key + ENV.fetch("WORKSPACES_WILDCARD_KEY") + end + # Specifies the token that can be used for the GitHub API def github_access_token ENV['QA_GITHUB_ACCESS_TOKEN'].to_s.strip @@ -570,6 +620,10 @@ module QA enabled?(ENV['QA_SKIP_SMOKE_RELIABLE'], default: false) end + def fips? + enabled?(ENV['FIPS'], default: false) + end + def container_registry_host ENV.fetch('QA_CONTAINER_REGISTRY_HOST', 'registry.gitlab.com') end diff --git a/qa/qa/runtime/fixtures.rb b/qa/qa/runtime/fixtures.rb index 4319f142bba..7075abc4863 100644 --- a/qa/qa/runtime/fixtures.rb +++ b/qa/qa/runtime/fixtures.rb @@ -38,6 +38,10 @@ module QA File.read(Runtime::Path.fixture(fixture_path, file_name)) end + def read_ee_fixture(fixture_path, file_name) + File.read(File.join(EE::Runtime::Path.fixtures_path, fixture_path, file_name)) + end + private def api_client diff --git a/qa/qa/service/cluster_provider/gcloud.rb b/qa/qa/service/cluster_provider/gcloud.rb index d33ae4915b5..28eb902b89e 100644 --- a/qa/qa/service/cluster_provider/gcloud.rb +++ b/qa/qa/service/cluster_provider/gcloud.rb @@ -27,20 +27,29 @@ module QA def setup login_if_not_already_logged_in create_cluster + install_helm end def teardown delete_cluster end - def install_kubernetes_agent(agent_token:, kas_address:) - install_helm + def connect + login_if_not_already_logged_in + + shell <<~CMD.tr("\n", ' ') + gcloud container clusters get-credentials + --region #{Runtime::Env.workspaces_cluster_region} + #{Runtime::Env.workspaces_cluster_name} + CMD + end + def install_kubernetes_agent(agent_token:, kas_address:, agent_name: "gitlab-agent") shell <<~CMD.tr("\n", ' ') helm repo add gitlab https://charts.gitlab.io && helm repo update && - helm upgrade --install test gitlab/gitlab-agent - --namespace gitlab-agent + helm upgrade --install gitlab-agent gitlab/gitlab-agent + --namespace "#{agent_name}" --create-namespace --set image.tag=#{Runtime::Env.gitlab_agentk_version} --set config.token=#{agent_token} @@ -49,6 +58,68 @@ module QA CMD end + def uninstall_kubernetes_agent(agent_name: "gitlab-agent") + shell <<~CMD.tr("\n", ' ') + helm uninstall gitlab-agent \ + --namespace "#{agent_name}" + CMD + end + + def install_ngnix_ingress + shell <<~CMD.tr("\n", ' ') + helm repo add ingress-nginx https://kubernetes.github.io/ingress-nginx && + helm repo update && + helm install \ + ingress-nginx ingress-nginx/ingress-nginx \ + --namespace ingress-nginx \ + --create-namespace \ + --version 4.3.0 + CMD + end + + def install_gitlab_workspaces_proxy + shell <<~CMD.tr("\n", ' ') + helm repo add gitlab-workspaces-proxy \ + https://gitlab.com/api/v4/projects/gitlab-org%2fremote-development%2fgitlab-workspaces-proxy/packages/helm/devel && + helm repo update && + helm upgrade --install gitlab-workspaces-proxy \ + gitlab-workspaces-proxy/gitlab-workspaces-proxy \ + --version 0.1.6 \ + --namespace=gitlab-workspaces \ + --create-namespace \ + --set="auth.client_id=#{Runtime::Env.workspaces_oauth_app_id}" \ + --set="auth.client_secret=#{Runtime::Env.workspaces_oauth_app_secret}" \ + --set="auth.host=#{Runtime::Env.gitlab_url}" \ + --set="auth.redirect_uri=https://#{Runtime::Env.workspaces_proxy_domain}/auth/callback" \ + --set="auth.signing_key=#{Runtime::Env.workspaces_oauth_signing_key}" \ + --set="ingress.host.workspaceDomain=#{Runtime::Env.workspaces_proxy_domain}" \ + --set="ingress.host.wildcardDomain=*.#{Runtime::Env.workspaces_proxy_domain}" \ + --set="ingress.tls.workspaceDomainCert=#{Runtime::Env.workspaces_domain_cert}" \ + --set="ingress.tls.workspaceDomainKey=#{Runtime::Env.workspaces_domain_key}" \ + --set="ingress.tls.wildcardDomainCert=#{Runtime::Env.workspaces_wildcard_cert}" \ + --set="ingress.tls.wildcardDomainKey=#{Runtime::Env.workspaces_wildcard_key}" \ + --set="ingress.className=nginx" + CMD + end + + def update_dns(load_balancer_ip) + shell <<~CMD.tr("\n", ' ') + gcloud dns record-sets update #{Runtime::Env.workspaces_proxy_domain} \ + --rrdatas=#{load_balancer_ip} \ + --ttl=300 \ + --type=A \ + --zone=gitlabqa-dev + CMD + + shell <<~CMD.tr("\n", ' ') + gcloud dns record-sets update "*.#{Runtime::Env.workspaces_proxy_domain}" \ + --rrdatas=#{load_balancer_ip} \ + --ttl=300 \ + --type=A \ + --zone=gitlabqa-dev + CMD + end + private def install_helm @@ -99,7 +170,7 @@ module QA create #{cluster_name} #{auth_options} --region #{@region} - --disk-size 10GB + --disk-size 15GB --num-nodes #{Runtime::Env.gcloud_num_nodes} && gcloud container clusters get-credentials diff --git a/qa/qa/service/docker_run/base.rb b/qa/qa/service/docker_run/base.rb index d6b50db7fa9..3bd7912958f 100644 --- a/qa/qa/service/docker_run/base.rb +++ b/qa/qa/service/docker_run/base.rb @@ -111,8 +111,14 @@ module QA # @return [String] def host_ip docker_host = shell("docker context inspect --format='{{json .Endpoints.docker.Host}}'").delete('"') - ip = Addrinfo.tcp(URI(docker_host).host, nil).ip_address + hostname = URI(docker_host).host + # The docker host could be bound to a Unix socket, in which case as a URI it has no host + host = hostname.presence || Socket.gethostname + ip = Addrinfo.tcp(host, nil).ip_address ip == '0.0.0.0' ? '127.0.0.1' : ip + rescue SocketError + # If the host could not be resolved, fallback on localhost + '127.0.0.1' end end end diff --git a/qa/qa/service/docker_run/gitlab_runner.rb b/qa/qa/service/docker_run/gitlab_runner.rb index b0bb999e5d6..b3f9d91e933 100644 --- a/qa/qa/service/docker_run/gitlab_runner.rb +++ b/qa/qa/service/docker_run/gitlab_runner.rb @@ -40,7 +40,7 @@ module QA raise("Missing runner token value!") unless token cmd = <<~CMD.tr("\n", ' ') - docker run -d --rm --network #{network} --name #{@name} + docker run -d --rm --network #{network} --name #{@name} #{'--user=root' if Runtime::Env.fips?} #{'-v /var/run/docker.sock:/var/run/docker.sock' if @executor == :docker} --privileged #{"--add-host gdk.test:#{gdk_host_ip}" if gdk_network} diff --git a/qa/qa/service/docker_run/smocker.rb b/qa/qa/service/docker_run/smocker.rb index 59f32e29b44..dbc32a22c6e 100644 --- a/qa/qa/service/docker_run/smocker.rb +++ b/qa/qa/service/docker_run/smocker.rb @@ -45,9 +45,11 @@ module QA attr_reader :public_port, :admin_port def host_name - return host_ip unless QA::Runtime::Env.running_in_ci? || QA::Runtime::Env.qa_hostname - - "#{@name}.#{@network_cache}" + @host_name ||= if QA::Runtime::Env.running_in_ci? || QA::Runtime::Env.qa_hostname + "#{@name}.#{@network_cache}" + else + host_ip + end end def wait_for_running diff --git a/qa/qa/service/kubernetes_cluster.rb b/qa/qa/service/kubernetes_cluster.rb index ed57d825643..d1cabc58f76 100644 --- a/qa/qa/service/kubernetes_cluster.rb +++ b/qa/qa/service/kubernetes_cluster.rb @@ -24,6 +24,15 @@ module QA self end + def connect! + validate_dependencies + + @provider.validate_dependencies + @provider.connect + + self + end + def remove! @provider.teardown end @@ -36,8 +45,24 @@ module QA cluster_name end - def install_kubernetes_agent(agent_token) - @provider.install_kubernetes_agent(agent_token: agent_token, kas_address: fetch_kas_address) + def install_kubernetes_agent(agent_token, agent_name) + @provider.install_kubernetes_agent(agent_token: agent_token, kas_address: fetch_kas_address, + agent_name: agent_name) + end + + def uninstall_kubernetes_agent(agent_name) + @provider.uninstall_kubernetes_agent(agent_name: agent_name) + end + + def setup_workspaces_in_cluster + @provider.install_ngnix_ingress + @provider.install_gitlab_workspaces_proxy + end + + def update_dns_with_load_balancer_ip + load_balancer_ip = shell("kubectl -n ingress-nginx get svc ingress-nginx-controller \ + -o jsonpath='{.status.loadBalancer.ingress[0].ip}'") + @provider.update_dns(load_balancer_ip) end def create_secret(secret, secret_name) 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 425ab0fa162..6990aa0e08e 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 @@ -34,11 +34,7 @@ module QA let(:source_storage) { { type: :gitaly, name: 'default' } } let(:destination_storage) { { type: :gitaly, name: QA::Runtime::Env.additional_repository_storage } } let(:project) do - Resource::Project.fabricate_via_api! do |project| - project.name = 'repo-storage-move-status' - project.initialize_with_readme = true - project.api_client = Runtime::API::Client.as_admin - end + create(:project, :with_readme, name: 'repo-storage-move-status', api_client: Runtime::API::Client.as_admin) end before do @@ -56,12 +52,11 @@ module QA let(:source_storage) { { type: :gitaly, name: QA::Runtime::Env.non_cluster_repository_storage } } let(:destination_storage) { { type: :praefect, name: QA::Runtime::Env.praefect_repository_storage } } let(:project) do - Resource::Project.fabricate_via_api! do |project| - project.name = 'repo-storage-move' - project.initialize_with_readme = true - project.repository_storage = source_storage[:name] - project.api_client = Runtime::API::Client.as_admin - end + create(:project, + :with_readme, + name: 'repo-storage-move', + repository_storage: source_storage[:name], + api_client: Runtime::API::Client.as_admin) end before do @@ -79,12 +74,11 @@ module QA let(:source_storage) { { type: :praefect, name: QA::Runtime::Env.praefect_repository_storage } } let(:destination_storage) { { type: :gitaly, name: QA::Runtime::Env.non_cluster_repository_storage } } let(:project) do - Resource::Project.fabricate_via_api! do |project| - project.name = 'repo-storage-move' - project.initialize_with_readme = true - project.repository_storage = source_storage[:name] - project.api_client = Runtime::API::Client.as_admin - end + create(:project, + :with_readme, + name: 'repo-storage-move', + repository_storage: source_storage[:name], + api_client: Runtime::API::Client.as_admin) end before do diff --git a/qa/qa/specs/features/api/1_manage/migration/gitlab_migration_group_spec.rb b/qa/qa/specs/features/api/1_manage/migration/gitlab_migration_group_spec.rb index ac85795b2bb..75203584edd 100644 --- a/qa/qa/specs/features/api/1_manage/migration/gitlab_migration_group_spec.rb +++ b/qa/qa/specs/features/api/1_manage/migration/gitlab_migration_group_spec.rb @@ -7,11 +7,10 @@ module QA describe "Gitlab migration" do context 'with subgroups and labels' do let(:subgroup) do - Resource::Group.fabricate_via_api! do |group| - group.api_client = source_admin_api_client - group.sandbox = source_group - group.path = "subgroup-for-import-#{SecureRandom.hex(4)}" - end + create(:group, + path: "subgroup-for-import-#{SecureRandom.hex(4)}", + sandbox: source_group, + api_client: source_admin_api_client) end let(:imported_subgroup) 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 7cbccf9be44..100b50abfdb 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 @@ -13,19 +13,14 @@ module QA # do not use top level group (sandbox) to avoid issues when applying permissions etc. because it will contain # a lot subgroups and projects on live envs - let!(:source_sandbox) do - Resource::Group.fabricate_via_api! do |group| - group.api_client = admin_api_client - end - end + let!(:source_sandbox) { create(:group, api_client: admin_api_client) } let!(:source_group) do - Resource::Group.fabricate_via_api! do |group| - group.api_client = admin_api_client - group.sandbox = source_sandbox - group.path = "source-group-for-import-#{SecureRandom.hex(4)}" - group.avatar = File.new(Runtime::Path.fixture('designs', 'tanuki.jpg'), 'r') - end + create(:group, + api_client: admin_api_client, + sandbox: source_sandbox, + path: "source-group-for-import-#{SecureRandom.hex(4)}", + avatar: File.new(Runtime::Path.fixture('designs', 'tanuki.jpg'), 'r')) end let!(:target_sandbox) { source_sandbox } 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 eeeb78e17d7..af0eef290f7 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 @@ -5,9 +5,7 @@ module QA 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::Project.fabricate_via_api! do |project| - project.initialize_with_readme = true - end + pat.project = create(:project, :with_readme) end @user_api_client = Runtime::API::Client.new(:gitlab, personal_access_token: @project_access_token.token) 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 8759c36f43f..578891b2722 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 @@ -13,23 +13,13 @@ module QA @user_api_client = Runtime::API::Client.new(:gitlab, user: @user) - @sandbox = Resource::Sandbox.fabricate! do |sandbox_group| - sandbox_group.path = "sandbox-for-access-termination-#{SecureRandom.hex(4)}" - sandbox_group.api_client = admin_api_client - end + @sandbox = create(:sandbox, path: "sandbox-for-access-termination-#{SecureRandom.hex(4)}", api_client: admin_api_client) - group = QA::Resource::Group.fabricate_via_api! do |group| - group.path = "group-to-test-access-termination-#{SecureRandom.hex(8)}" - group.sandbox = @sandbox - end + group = create(:group, path: "group-to-test-access-termination-#{SecureRandom.hex(8)}", sandbox: @sandbox) @sandbox.add_member(@user) - @project = Resource::Project.fabricate_via_api! do |project| - project.group = group - project.name = "project-for-user-group-access-termination" - project.initialize_with_readme = true - end + @project = create(:project, :with_readme, name: 'project-for-user-group-access-termination', group: group) end context 'after parent group membership termination' do 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 fc00d851087..1edf1d942be 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', product_group: :code_review do + describe 'Merge request push options', :reliable, 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 @@ -10,11 +10,7 @@ module QA let(:branch) { "push-options-test-#{SecureRandom.hex(8)}" } let(:title) { "MR push options test #{SecureRandom.hex(8)}" } let(:commit_message) { 'Add README.md' } - let(:project) do - Resource::Project.fabricate_via_api! do |project| - project.initialize_with_readme = true - end - end + let(:project) { create(:project, :with_readme) } def create_new_mr_via_push Resource::Repository::ProjectPush.fabricate! do |push| 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 9fed6787ade..5c4fc8cef56 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 @@ -10,12 +10,7 @@ module QA let(:branch) { "push-options-test-#{SecureRandom.hex(8)}" } let(:title) { "MR push options test #{SecureRandom.hex(8)}" } - let(:project) do - Resource::Project.fabricate_via_api! do |project| - project.name = 'merge-request-push-options' - project.initialize_with_readme = true - end - end + let(:project) { create(:project, :with_readme, name: 'merge-request-push-options') } let!(:runner) do Resource::ProjectRunner.fabricate! do |runner| @@ -74,7 +69,14 @@ module QA end end - it 'merges when pipeline succeeds', testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347842' do + it( + 'merges when pipeline succeeds', + testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347842', + quarantine: { + type: :flaky, + issue: "https://gitlab.com/gitlab-org/gitlab/-/issues/346425" + } + ) do Resource::Repository::Commit.fabricate_via_api! do |commit| commit.project = project commit.commit_message = 'Add .gitlab-ci.yml' 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 11328c2f517..9c27793a52d 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,20 +2,14 @@ module QA RSpec.describe 'Create' do - describe 'Merge request push options', product_group: :code_review do + describe 'Merge request push options', :reliable, 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 let(:branch) { "push-options-test-#{SecureRandom.hex(8)}" } let(:title) { "MR push options test #{SecureRandom.hex(8)}" } - - let(:project) do - Resource::Project.fabricate_via_api! do |project| - project.name = 'merge-request-push-options' - project.initialize_with_readme = true - end - end + let(:project) { create(:project, :with_readme, name: 'merge-request-push-options') } it 'removes the source branch', testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347841' do Resource::Repository::ProjectPush.fabricate! do |push| 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 eb7d3da0f97..1a5b6f88f4f 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,19 +2,14 @@ module QA RSpec.describe 'Create' do - describe 'Merge request push options', product_group: :code_review do + describe 'Merge request push options', :reliable, 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 let(:title) { "MR push options test #{SecureRandom.hex(8)}" } - let(:project) do - Resource::Project.fabricate_via_api! do |project| - project.name = 'merge-request-push-options' - project.initialize_with_readme = true - end - end + let(:project) { create(:project, :with_readme, name: 'merge-request-push-options') } it 'sets a target branch', testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347726' do target_branch = "push-options-test-target-#{SecureRandom.hex(8)}" 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 dd297f47975..4e8a5a426d4 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,17 +2,12 @@ module QA RSpec.describe 'Create' do - describe 'Merge request push options', product_group: :code_review do + describe 'Merge request push options', :reliable, 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 - let(:project) do - Resource::Project.fabricate_via_api! do |project| - project.name = 'merge-request-push-options' - project.initialize_with_readme = true - end - end + let(:project) { create(:project, :with_readme, name: 'merge-request-push-options') } it 'sets title and description', testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347844' do description = "This is a test of MR push options" diff --git a/qa/qa/specs/features/api/3_create/repository/add_list_delete_branches_spec.rb b/qa/qa/specs/features/api/3_create/repository/add_list_delete_branches_spec.rb index f69a8a4dfa5..2f7cef2112e 100644 --- a/qa/qa/specs/features/api/3_create/repository/add_list_delete_branches_spec.rb +++ b/qa/qa/specs/features/api/3_create/repository/add_list_delete_branches_spec.rb @@ -2,12 +2,7 @@ module QA RSpec.describe 'Create' do - let(:project) do - Resource::Project.fabricate_via_api! do |project| - project.name = 'project-qa-test' - project.description = 'project for qa test' - end - end + let(:project) { create(:project, name: 'project-qa-test', description: 'project for qa test') } describe 'Create, Retrieve and Delete branches via API', :requires_admin, product_group: :source_code do created_branch = 'create-branch' diff --git a/qa/qa/specs/features/api/3_create/repository/commit_to_templated_project_spec.rb b/qa/qa/specs/features/api/3_create/repository/commit_to_templated_project_spec.rb index 4ee436a597a..74d1c9e3e94 100644 --- a/qa/qa/specs/features/api/3_create/repository/commit_to_templated_project_spec.rb +++ b/qa/qa/specs/features/api/3_create/repository/commit_to_templated_project_spec.rb @@ -3,12 +3,7 @@ module QA RSpec.describe 'Create' do describe 'Create a new project from a template', product_group: :source_code do - let(:project) do - Resource::Project.fabricate_via_api! do |project| - project.name = 'templated-project' - project.template_name = 'dotnetcore' - end - end + let(:project) { create(:project, name: 'templated-project', template_name: 'dotnetcore') } it 'commits via the api', testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/357234' do expect do diff --git a/qa/qa/specs/features/api/3_create/repository/default_branch_name_setting_spec.rb b/qa/qa/specs/features/api/3_create/repository/default_branch_name_setting_spec.rb index 123a4a625ab..a512bb76560 100644 --- a/qa/qa/specs/features/api/3_create/repository/default_branch_name_setting_spec.rb +++ b/qa/qa/specs/features/api/3_create/repository/default_branch_name_setting_spec.rb @@ -12,10 +12,7 @@ module QA end it 'sets the default branch name for a new project', testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347837' do - project = Resource::Project.fabricate_via_api! do |project| - project.name = "default-branch-name" - project.initialize_with_readme = true - end + project = create(:project, :with_readme, name: 'default-branch-name') # It takes a moment to create the project. We wait until we # know it exists before we try to clone it @@ -32,7 +29,7 @@ module QA it 'allows a project to be created via the CLI with a different default branch name', testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347838' do project_name = "default-branch-name-via-cli-#{SecureRandom.hex(8)}" - group = Resource::Group.fabricate_via_api! + group = create(:group) Git::Repository.perform do |repository| repository.init_repository diff --git a/qa/qa/specs/features/api/3_create/repository/project_archive_compare_spec.rb b/qa/qa/specs/features/api/3_create/repository/project_archive_compare_spec.rb index d72672e2104..87faec86947 100644 --- a/qa/qa/specs/features/api/3_create/repository/project_archive_compare_spec.rb +++ b/qa/qa/specs/features/api/3_create/repository/project_archive_compare_spec.rb @@ -46,12 +46,7 @@ module QA end def create_project(user, api_client, project_name) - project = Resource::Project.fabricate_via_api! do |project| - project.personal_namespace = user.username - project.add_name_uuid = false - project.name = project_name - project.api_client = api_client - end + project = create(:project, name: project_name, api_client: api_client, add_name_uuid: false, personal_namespace: user.username) Resource::Repository::Commit.fabricate_via_api! do |commit| commit.project = project diff --git a/qa/qa/specs/features/api/3_create/repository/push_postreceive_idempotent_spec.rb b/qa/qa/specs/features/api/3_create/repository/push_postreceive_idempotent_spec.rb index 1d41184df98..df61dd43bb0 100644 --- a/qa/qa/specs/features/api/3_create/repository/push_postreceive_idempotent_spec.rb +++ b/qa/qa/specs/features/api/3_create/repository/push_postreceive_idempotent_spec.rb @@ -6,12 +6,7 @@ module QA # Tests that a push does not result in multiple changes from repeated PostReceive executions. # One of the consequences would be duplicate push events - let(:project) do - Resource::Project.fabricate_via_api! do |project| - project.name = 'push-postreceive-idempotent' - project.initialize_with_readme = true - end - end + let(:project) { create(:project, :with_readme, name: 'push-postreceive-idempotent') } after do project&.remove_via_api! 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 8c7a58be43a..72ce2dda053 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 @@ -30,9 +30,7 @@ module QA # attempt to detect large differences that could indicate a regression to previous behavior. it 'matches cloned repo usage to reported usage', testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/365196' do - project = Resource::Project.fabricate_via_api! do |project| - project.name = project_name - end + project = create(:project, name: project_name) shared_data = SecureRandom.random_bytes(500000) diff --git a/qa/qa/specs/features/api/3_create/repository/tag_revision_trigger_prereceive_hook_spec.rb b/qa/qa/specs/features/api/3_create/repository/tag_revision_trigger_prereceive_hook_spec.rb index 700cf69da80..d0f1ee66488 100644 --- a/qa/qa/specs/features/api/3_create/repository/tag_revision_trigger_prereceive_hook_spec.rb +++ b/qa/qa/specs/features/api/3_create/repository/tag_revision_trigger_prereceive_hook_spec.rb @@ -3,11 +3,7 @@ module QA RSpec.describe 'Create' do describe 'Prereceive hook', product_group: :source_code do - let(:project) do - Resource::Project.fabricate_via_api! do |project| - project.initialize_with_readme = true - end - end + let(:project) { create(:project, :with_readme) } context 'when creating a tag for a ref' do context 'when it triggers a prereceive hook configured with a custom error' do 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 a360c662cf8..5b0e0573016 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 @@ -12,11 +12,7 @@ module QA end end - let(:project) do - Resource::Project.fabricate_via_api! do |project| - project.name = 'project-for-canceled-schedule' - end - end + let(:project) { create(:project, name: 'project-for-canceled-schedule') } before do project.add_member(user, Resource::Members::AccessLevel::MAINTAINER) diff --git a/qa/qa/specs/features/api/4_verify/file_variable_downstream_pipeline_spec.rb b/qa/qa/specs/features/api/4_verify/file_variable_downstream_pipeline_spec.rb new file mode 100644 index 00000000000..289133b33cc --- /dev/null +++ b/qa/qa/specs/features/api/4_verify/file_variable_downstream_pipeline_spec.rb @@ -0,0 +1,231 @@ +# frozen_string_literal: true + +module QA + RSpec.describe 'Verify', :runner, product_group: :pipeline_security, feature_flag: { + name: 'ci_prevent_file_var_expansion_downstream_pipeline', + scope: :project + } do + describe 'Pipeline with file variables and downstream pipelines' do + let(:random_string) { Faker::Alphanumeric.alphanumeric(number: 8) } + let(:executor) { "qa-runner-#{Faker::Alphanumeric.alphanumeric(number: 8)}" } + let!(:project) { create(:project, name: 'upstream-project-with-file-variables') } + let!(:downstream_project) { create(:project, name: 'downstream-project') } + + let!(:project_runner) do + Resource::ProjectRunner.fabricate! do |runner| + runner.project = project + runner.name = executor + runner.tags = [executor] + end + end + + let!(:downstream_project_runner) do + Resource::ProjectRunner.fabricate! do |runner| + runner.project = downstream_project + runner.name = "#{executor}-downstream" + runner.tags = [executor] + end + end + + let(:add_ci_file) do + Resource::Repository::Commit.fabricate_via_api! do |commit| + commit.project = project + commit.commit_message = 'Add .gitlab-ci.yml and child.yml' + commit.add_files( + [ + { + file_path: '.gitlab-ci.yml', + content: <<~YAML + default: + tags: [#{executor}] + + variables: + EXTRA_ARGS: "-f $TEST_PROJECT_FILE" + DOCKER_REMOTE_ARGS: --tlscacert="$DOCKER_CA_CERT" + EXTRACTED_CRT_FILE: ${DOCKER_CA_CERT}.crt + MY_FILE_VAR: $TEST_PROJECT_FILE + + trigger_child: + trigger: + strategy: depend + include: + - local: child.yml + + trigger_downstream_project: + trigger: + strategy: depend + project: #{downstream_project.path_with_namespace} + + YAML + }, + { + file_path: 'child.yml', + content: <<~YAML + default: + tags: [#{executor}] + + child_job_echo: + script: + - echo "run something $EXTRA_ARGS" + - echo "docker run $DOCKER_REMOTE_ARGS" + - echo "run --output=$EXTRACTED_CRT_FILE" + - echo "Will read private key from $MY_FILE_VAR" + + child_job_cat: + script: + - cat "$MY_FILE_VAR" + - cat "$DOCKER_CA_CERT" + YAML + } + ] + ) + end + end + + let(:add_downstream_project_ci_file) do + Resource::Repository::Commit.fabricate_via_api! do |commit| + commit.project = downstream_project + commit.commit_message = 'Add .gitlab-ci.yml' + commit.add_files( + [ + { + file_path: '.gitlab-ci.yml', + content: <<~YAML + default: + tags: [#{executor}] + + downstream_job_echo: + script: + - echo "run something $EXTRA_ARGS" + - echo "docker run $DOCKER_REMOTE_ARGS" + - echo "run --output=$EXTRACTED_CRT_FILE" + - echo "Will read private key from $MY_FILE_VAR" + + downstream_job_cat: + script: + - cat "$MY_FILE_VAR" + - cat "$DOCKER_CA_CERT" + YAML + } + ] + ) + end + end + + let(:add_project_file_variables) do + { + 'TEST_PROJECT_FILE' => "hello, this is test\n", + 'DOCKER_CA_CERT' => "This is secret\n" + }.each do |file_name, content| + add_file_variable_to_project(project, file_name, content) + end + end + + let(:upstream_pipeline) do + Resource::Pipeline.fabricate_via_api! do |pipeline| + pipeline.project = project + end + end + + def child_pipeline + Resource::Pipeline.fabricate_via_api! do |pipeline| + pipeline.project = project + pipeline.id = upstream_pipeline.downstream_pipeline_id(bridge_name: 'trigger_child') + end + end + + def downstream_project_pipeline + Resource::Pipeline.fabricate_via_api! do |pipeline| + pipeline.project = downstream_project + pipeline.id = upstream_pipeline.downstream_pipeline_id(bridge_name: 'trigger_downstream_project') + end + end + + around do |example| + Runtime::Feature.enable(:ci_prevent_file_var_expansion_downstream_pipeline, project: project) + example.run + Runtime::Feature.disable(:ci_prevent_file_var_expansion_downstream_pipeline, project: project) + end + + before do + add_project_file_variables + add_downstream_project_ci_file + add_ci_file + upstream_pipeline + wait_for_pipelines + end + + after do + project_runner.remove_via_api! + downstream_project_runner.remove_via_api! + end + + it( + 'creates variable with file path in downstream pipelines and can read file variable content', + testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/416337' + ) do + child_echo_job = Resource::Job.fabricate_via_api! do |job| + job.project = project + job.id = project.job_by_name('child_job_echo')[:id] + end + + child_cat_job = Resource::Job.fabricate_via_api! do |job| + job.project = project + job.id = project.job_by_name('child_job_cat')[:id] + end + + downstream_project_echo_job = Resource::Job.fabricate_via_api! do |job| + job.project = downstream_project + job.id = downstream_project.job_by_name('downstream_job_echo')[:id] + end + + downstream_project_cat_job = Resource::Job.fabricate_via_api! do |job| + job.project = downstream_project + job.id = downstream_project.job_by_name('downstream_job_cat')[:id] + end + + aggregate_failures do + trace = child_echo_job.trace + expect(trace).to include('run something -f', "#{project.name}.tmp/TEST_PROJECT_FILE") + expect(trace).to include('docker run --tlscacert=', "#{project.name}.tmp/DOCKER_CA_CERT") + expect(trace).to include('run --output=', "#{project.name}.tmp/DOCKER_CA_CERT.crt") + expect(trace).to include('Will read private key from', "#{project.name}.tmp/TEST_PROJECT_FILE") + + trace = child_cat_job.trace + expect(trace).to have_content('hello, this is test') + expect(trace).to have_content('This is secret') + + trace = downstream_project_echo_job.trace + expect(trace).to include('run something -f', "#{downstream_project.name}.tmp/TEST_PROJECT_FILE") + expect(trace).to include('docker run --tlscacert=', "#{downstream_project.name}.tmp/DOCKER_CA_CERT") + expect(trace).to include('run --output=', "#{downstream_project.name}.tmp/DOCKER_CA_CERT.crt") + expect(trace).to include('Will read private key from', "#{downstream_project.name}.tmp/TEST_PROJECT_FILE") + + trace = downstream_project_cat_job.trace + expect(trace).to have_content('hello, this is test') + expect(trace).to have_content('This is secret') + end + end + + private + + def add_file_variable_to_project(project, key, value) + Resource::CiVariable.fabricate_via_api! do |ci_variable| + ci_variable.project = project + ci_variable.key = key + ci_variable.value = value + ci_variable.variable_type = 'file' + end + end + + def wait_for_pipelines + Support::Waiter.wait_until(max_duration: 300, sleep_interval: 10) do + upstream_pipeline.reload! + upstream_pipeline.status == 'success' && + child_pipeline.status == 'success' && + downstream_project_pipeline.status == 'success' + end + end + end + end +end 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 2d9deec399c..d7adc1d8454 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 @@ -4,12 +4,7 @@ module QA RSpec.describe 'Verify', :runner, product_group: :pipeline_security do describe 'Pipeline with project file variables' do let(:executor) { "qa-runner-#{Faker::Alphanumeric.alphanumeric(number: 8)}" } - - let(:project) do - Resource::Project.fabricate_via_api! do |project| - project.name = 'project-with-file-variables' - end - end + let(:project) { create(:project, name: 'project-with-file-variables') } let!(:runner) do Resource::ProjectRunner.fabricate! do |runner| diff --git a/qa/qa/specs/features/api/5_package/container_registry/saas/container_registry_spec.rb b/qa/qa/specs/features/api/5_package/container_registry/saas/container_registry_spec.rb index 23d8585d07a..d2b1cbd2c95 100644 --- a/qa/qa/specs/features/api/5_package/container_registry/saas/container_registry_spec.rb +++ b/qa/qa/specs/features/api/5_package/container_registry/saas/container_registry_spec.rb @@ -12,11 +12,7 @@ module QA let(:api_client) { Runtime::API::Client.new(:gitlab) } let(:project) do - Resource::Project.fabricate_via_api! do |project| - project.name = 'project-with-registry-api' - project.template_name = 'express' - project.api_client = api_client - end + create(:project, name: 'project-with-registry-api', template_name: 'express', api_client: api_client) end let!(:runner) do diff --git a/qa/qa/specs/features/api/9_data_stores/user_inherited_access_spec.rb b/qa/qa/specs/features/api/9_data_stores/user_inherited_access_spec.rb index 48e9d3dc164..6f8b6df6658 100644 --- a/qa/qa/specs/features/api/9_data_stores/user_inherited_access_spec.rb +++ b/qa/qa/specs/features/api/9_data_stores/user_inherited_access_spec.rb @@ -5,17 +5,10 @@ module QA describe 'User', :requires_admin, product_group: :tenant_scale do let(:admin_api_client) { Runtime::API::Client.as_admin } - let!(:parent_group) do - QA::Resource::Group.fabricate_via_api! do |group| - group.path = "parent-group-to-test-user-access-#{SecureRandom.hex(8)}" - end - end + let!(:parent_group) { create(:group, path: "parent-group-to-test-user-access-#{SecureRandom.hex(8)}") } let!(:sub_group) do - QA::Resource::Group.fabricate_via_api! do |group| - group.path = "sub-group-to-test-user-access-#{SecureRandom.hex(8)}" - group.sandbox = parent_group - end + create(:group, path: "sub-group-to-test-user-access-#{SecureRandom.hex(8)}", sandbox: parent_group) end context 'when added to parent group' do @@ -30,11 +23,7 @@ module QA end let!(:sub_group_project) do - Resource::Project.fabricate_via_api! do |project| - project.group = sub_group - project.name = "sub-group-project-to-test-user-access" - project.initialize_with_readme = true - end + create(:project, :with_readme, name: 'sub-groupd-project-to-test-user-access', group: sub_group) end before do @@ -106,11 +95,7 @@ module QA context 'when added to sub-group' do let!(:parent_group_project) do - Resource::Project.fabricate_via_api! do |project| - project.group = parent_group - project.name = "parent-group-project-to-test-user-access" - project.initialize_with_readme = true - end + create(:project, :with_readme, name: 'parent-group-project-to-test-user-access', group: parent_group) end let!(:sub_group_user) do diff --git a/qa/qa/specs/features/browser_ui/1_manage/integrations/jenkins/jenkins_build_status_spec.rb b/qa/qa/specs/features/browser_ui/1_manage/integrations/jenkins/jenkins_build_status_spec.rb index 63c57ad455b..f40d953acd2 100644 --- a/qa/qa/specs/features/browser_ui/1_manage/integrations/jenkins/jenkins_build_status_spec.rb +++ b/qa/qa/specs/features/browser_ui/1_manage/integrations/jenkins/jenkins_build_status_spec.rb @@ -15,18 +15,9 @@ module QA end let(:jenkins_project_name) { "gitlab_jenkins_#{SecureRandom.hex(5)}" } - let(:connection_name) { 'gitlab-connection' } - let(:project_name) { "project_with_jenkins_#{SecureRandom.hex(4)}" } - - let(:project) do - Resource::Project.fabricate_via_api! do |project| - project.name = project_name - project.initialize_with_readme = true - project.auto_devops_enabled = false - end - end + let(:project) { create(:project, :with_readme, name: project_name) } let(:access_token) do Runtime::Env.personal_access_token ||= fabricate_access_token diff --git a/qa/qa/specs/features/browser_ui/1_manage/integrations/jira/jira_basic_integration_spec.rb b/qa/qa/specs/features/browser_ui/1_manage/integrations/jira/jira_basic_integration_spec.rb index 1bd819ad87d..f336a0d5d82 100644 --- a/qa/qa/specs/features/browser_ui/1_manage/integrations/jira/jira_basic_integration_spec.rb +++ b/qa/qa/specs/features/browser_ui/1_manage/integrations/jira/jira_basic_integration_spec.rb @@ -6,11 +6,7 @@ module QA describe 'Jira integration', :jira, :orchestrated, :requires_admin, product_group: :import_and_integrate do let(:jira_project_key) { 'JITP' } - let(:project) do - Resource::Project.fabricate_via_api! do |project| - project.name = "project_with_jira_integration" - end - end + let(:project) { create(:project, name: 'project_with_jira_integration') } before do page.visit Vendor::Jira::JiraAPI.perform(&:base_url) diff --git a/qa/qa/specs/features/browser_ui/1_manage/integrations/jira/jira_issue_import_spec.rb b/qa/qa/specs/features/browser_ui/1_manage/integrations/jira/jira_issue_import_spec.rb index 02224406e6d..15b6d74c7f1 100644 --- a/qa/qa/specs/features/browser_ui/1_manage/integrations/jira/jira_issue_import_spec.rb +++ b/qa/qa/specs/features/browser_ui/1_manage/integrations/jira/jira_issue_import_spec.rb @@ -8,11 +8,7 @@ module QA let(:jira_issue_description) { "This issue is for testing importing Jira issues to GitLab." } let(:jira_issue_label_1) { "jira-import::#{jira_project_key}-1" } let(:jira_issue_label_2) { "QA" } - let(:project) do - Resource::Project.fabricate_via_api! do |project| - project.name = "jira_issue_import" - end - end + let(:project) { create(:project, name: "jira_issue_import") } it 'imports issues from Jira', testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347966' do set_up_jira_integration diff --git a/qa/qa/specs/features/browser_ui/1_manage/integrations/pipeline_status_emails_spec.rb b/qa/qa/specs/features/browser_ui/1_manage/integrations/pipeline_status_emails_spec.rb index 1ea19144a74..c19ebd9f7a7 100644 --- a/qa/qa/specs/features/browser_ui/1_manage/integrations/pipeline_status_emails_spec.rb +++ b/qa/qa/specs/features/browser_ui/1_manage/integrations/pipeline_status_emails_spec.rb @@ -28,12 +28,7 @@ module QA describe 'Pipeline status emails' do let(:executor) { "qa-runner-#{Time.now.to_i}" } let(:emails) { %w[foo@bar.com baz@buzz.com] } - - let(:project) do - Resource::Project.fabricate_via_api! do |project| - project.name = 'pipeline-status-project' - end - end + let(:project) { create(:project, name: 'pipeline-status-project') } let!(:runner) do Resource::ProjectRunner.fabricate! do |runner| diff --git a/qa/qa/specs/features/browser_ui/1_manage/integrations/slash_commands_spec.rb b/qa/qa/specs/features/browser_ui/1_manage/integrations/slash_commands_spec.rb index f5e33cb5b1e..99be4e87251 100644 --- a/qa/qa/specs/features/browser_ui/1_manage/integrations/slash_commands_spec.rb +++ b/qa/qa/specs/features/browser_ui/1_manage/integrations/slash_commands_spec.rb @@ -10,13 +10,7 @@ module QA # state to be used in the GitLab API let(:project_name) { "project_with_slack" } - - let(:project) do - Resource::Project.fabricate_via_api! do |project| - project.name = project_name - project.initialize_with_readme = true - end - end + let(:project) { create(:project, :with_readme, name: project_name) } before(:context) do Runtime::Env.require_slack_env! @@ -101,12 +95,7 @@ module QA end context 'with target project' do - let(:target) do - Resource::Project.fabricate_via_api! do |project| - project.name = 'target_slack_project' - project.initialize_with_readme = true - end - end + let(:target) { create(:project, :with_readme, name: 'target_slack_project') } after do target.remove_via_api! 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 0f3d6a104a7..f2582d47723 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 @@ -23,11 +23,7 @@ module QA end let(:group) do - QA::Resource::Group.fabricate_via_api! do |group| - group.sandbox = sandbox_group - group.api_client = owner_api_client - group.require_two_factor_authentication = true - end + create(:group, :require_2fa, sandbox: sandbox_group, api_client: owner_api_client) end before do 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 84664cb8b94..89f15759b54 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, product_group: :authentication_and_authorization do + RSpec.describe 'Manage', :requires_admin, 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) } @@ -14,6 +14,7 @@ module QA end let(:sandbox_group) do + Flow::Login.sign_in(as: owner_user) Resource::Sandbox.fabricate! do |sandbox_group| sandbox_group.path = "gitlab-qa-2fa-sandbox-group-#{SecureRandom.hex(8)}" sandbox_group.api_client = owner_api_client @@ -21,11 +22,7 @@ module QA end let(:group) do - QA::Resource::Group.fabricate_via_api! do |group| - group.sandbox = sandbox_group - group.api_client = owner_api_client - group.path = "group-with-2fa-#{SecureRandom.hex(8)}" - end + create(:group, sandbox: sandbox_group, api_client: owner_api_client, path: "group-with-2fa-#{SecureRandom.hex(8)}") end let(:developer_user) do @@ -46,7 +43,7 @@ module QA testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347931', quarantine: { type: :bug, - only: { condition: -> { !QA::Runtime::Env.super_sidebar_enabled? } }, + only: { condition: -> { QA::Runtime::Env.super_sidebar_enabled? } }, issue: 'https://gitlab.com/gitlab-org/gitlab/-/issues/409336' } ) do 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 1a53fda4cdb..afc7e8202e2 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 @@ -9,11 +9,7 @@ module QA 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| - project.name = 'email-notification-test' - end - end + let(:project) { create(:project, name: 'email-notification-test') } before do Flow::Login.sign_in 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 2f177d12389..5d8f9f7d7b3 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 @@ -10,11 +10,7 @@ module QA end end - let!(:project) do - Resource::Project.fabricate_via_api! do |project| - project.name = 'xss-test-for-mentions-project' - end - end + let!(:project) { create(:project, name: 'xss-test-for-mentions-project') } describe 'check xss occurence in @mentions in issues', :requires_admin do before do 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 f7dc9157275..2fe88c543de 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 @@ -6,7 +6,7 @@ module QA before do Flow::Login.sign_in - Resource::Issue.fabricate_via_api!.visit! + create(:issue).visit! end it 'comments on an issue and edits the comment', testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347978' do 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 bad312bb392..c489a61ca2a 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 @@ -7,10 +7,7 @@ module QA let(:template_content) { 'This is a custom issue template test' } let(:template_project) do - Resource::Project.fabricate_via_api! do |project| - project.name = "custom-issue-template-project" - project.initialize_with_readme = true - end + create(:project, :with_readme, name: 'custom-issue-template-project') end before do 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 5e989cdb03f..45c7f307834 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 @@ -3,11 +3,7 @@ module QA RSpec.describe 'Plan', :reliable, product_group: :project_management do describe 'Issues list' do - let(:project) do - Resource::Project.fabricate_via_api! do |project| - project.name = 'project-to-test-export-issues-as-csv' - end - end + let(:project) { create(:project, name: 'project-to-test-export-issues-as-csv') } before do Flow::Login.sign_in 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 060e52276a9..d282b0dbbd5 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 @@ -5,11 +5,7 @@ module QA 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) } - let(:project) do - Resource::Project.fabricate_via_api! do |project| - project.name = 'project-to-test-assignees' - end - end + let(:project) { create(:project, name: 'project-to-test-assignees') } before do Flow::Login.sign_in 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 7377b0ff8af..92a67437d06 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 @@ -3,11 +3,7 @@ module QA 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| - project.name = 'sample-project-issue-board-focus-mode' - end - end + let(:project) { create(:project, name: 'sample-project-issue-board-focus-mode') } before do Flow::Login.sign_in 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 56e110e6f61..c3c2ad68abf 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 @@ -8,18 +8,9 @@ module QA let(:start_date) { current_date_yyyy_mm_dd } let(:due_date) { next_month_yyyy_mm_dd } - let(:group) do - Resource::Group.fabricate_via_api! do |group| - group.name = "group-to-test-milestones-#{SecureRandom.hex(4)}" - end - end + let(:group) { create(:group, name: "group-to-test-milestones-#{SecureRandom.hex(4)}") } - let(:project) do - Resource::Project.fabricate_via_api! do |project| - project.name = "project-to-test-milestones-#{SecureRandom.hex(4)}" - project.group = group - end - end + let(:project) { create(:project, name: "project-to-test-milestones-#{SecureRandom.hex(4)}", group: group) } let(:issue) do Resource::Issue.fabricate_via_api! do |issue| diff --git a/qa/qa/specs/features/browser_ui/2_plan/pages/new_static_page_spec.rb b/qa/qa/specs/features/browser_ui/2_plan/pages/new_static_page_spec.rb index 919b4b2c46e..3d4ec8a422e 100644 --- a/qa/qa/specs/features/browser_ui/2_plan/pages/new_static_page_spec.rb +++ b/qa/qa/specs/features/browser_ui/2_plan/pages/new_static_page_spec.rb @@ -12,13 +12,7 @@ module QA feature_flag: { name: 'show_pages_in_deployments_menu' } do # TODO: Convert back to :smoke once proved to be stable. Related issue: https://gitlab.com/gitlab-org/gitlab/-/issues/300906 describe 'Pages', product_group: :knowledge do - let!(:project) do - Resource::Project.fabricate_via_api! do |project| - project.name = 'gitlab-pages-project' - project.template_name = :plainhtml - end - end - + let!(:project) { create(:project, name: 'gitlab-pages-projects', template_name: :plainhtml) } let(:pipeline) do Resource::Pipeline.fabricate_via_api! do |pipeline| pipeline.project = project diff --git a/qa/qa/specs/features/browser_ui/2_plan/project_wiki/project_based_content_creation_spec.rb b/qa/qa/specs/features/browser_ui/2_plan/project_wiki/project_based_content_creation_spec.rb index e1f73acd375..19c9ac6c238 100644 --- a/qa/qa/specs/features/browser_ui/2_plan/project_wiki/project_based_content_creation_spec.rb +++ b/qa/qa/specs/features/browser_ui/2_plan/project_wiki/project_based_content_creation_spec.rb @@ -7,7 +7,7 @@ module QA let(:new_wiki_content) { "this content is changed or added" } let(:commit_message) { "this is a new addition to the wiki" } - let(:project) { Resource::Project.fabricate_via_api! } + let(:project) { create(:project) } let(:wiki) { Resource::Wiki::ProjectPage.fabricate_via_api! } before do 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 197e283c93b..87a0cf1b310 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 @@ -3,12 +3,7 @@ module QA RSpec.describe 'Plan', :reliable, product_group: :project_management do describe 'Related issues' do - let(:project) do - Resource::Project.fabricate_via_api! do |project| - project.name = 'project-to-test-related-issues' - end - end - + let(:project) { create(:project, name: 'project-to-test-related-issues') } let(:issue_1) do Resource::Issue.fabricate_via_api! do |issue| issue.project = project 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 8f99644bd24..0e5806a00ff 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,14 +2,8 @@ module QA RSpec.describe 'Create' 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' - project.initialize_with_readme = true - end - end - + describe 'Cherry picking from a merge request', :reliable, product_group: :code_review do + let(:project) { create(:project, :with_readme) } let(:feature_mr) do Resource::MergeRequest.fabricate_via_api! do |merge_request| merge_request.project = 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 111adf32a69..fa4a1293025 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,16 +2,9 @@ module QA RSpec.describe 'Create' do - describe 'Cherry picking a commit', product_group: :code_review do + describe 'Cherry picking a commit', :reliable, product_group: :code_review do let(:file_name) { "secret_file.md" } - - let(:project) do - Resource::Project.fabricate_via_api! do |project| - project.name = 'project' - project.initialize_with_readme = true - end - end - + let(:project) { create(:project, :with_readme) } let(:commit) do Resource::Repository::Commit.fabricate_via_api! do |commit| commit.project = project 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 509714fb5a4..ed44017db75 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,14 +2,11 @@ module QA RSpec.describe 'Create' do - describe 'Create a new merge request from the event notification after a push', product_group: :code_review do + describe 'Create a new merge request from the event notification after a push', :reliable, + 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 - Resource::Project.fabricate_via_api! do |project| - project.initialize_with_readme = true - end - end + let(:project) { create(:project, :with_readme) } before do Flow::Login.sign_in 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 fcce6bb291c..89b43e88bde 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 @@ -3,12 +3,7 @@ module QA RSpec.describe 'Create' 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' - end - end - + let(:project) { create(:project) } let(:merge_request_title) { 'One merge request to rule them all' } let(:merge_request_description) { '... to find them, to bring them all, and in the darkness bind them' } 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 1ce9430290f..4072416374a 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 @@ -5,13 +5,7 @@ module QA describe 'Merge request custom templates' do let(:template_name) { 'custom_merge_request_template' } let(:template_content) { 'This is a custom merge request template test' } - let(:template_project) do - Resource::Project.fabricate_via_api! do |project| - project.name = 'custom-mr-template-project' - project.initialize_with_readme = true - end - end - + let(:template_project) { create(:project, :with_readme, name: 'custom-mr-template-project') } let(:merge_request_title) { 'One merge request to rule them all' } before do 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 38831f6f158..cad50fc032b 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 @@ -5,14 +5,7 @@ module QA describe 'Merge requests' do shared_examples 'merge when pipeline succeeds' do |repeat: 1| let(:runner_name) { "qa-runner-#{Faker::Alphanumeric.alphanumeric(number: 8)}" } - - let(:project) do - Resource::Project.fabricate_via_api! do |project| - project.name = 'merge-when-pipeline-succeeds' - project.initialize_with_readme = true - end - end - + let(:project) { create(:project, :with_readme, name: 'merge-when-pipeline-succeeds') } let!(:runner) do Resource::ProjectRunner.fabricate! do |runner| runner.project = project 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 a79c56bd051..5e3260fb44f 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 @@ -4,14 +4,7 @@ module QA RSpec.describe 'Create', :reliable, product_group: :code_review do describe 'Reverting a commit' do let(:file_name) { "secret_file.md" } - - let(:project) do - Resource::Project.fabricate_via_api! do |project| - project.name = 'project' - project.initialize_with_readme = true - end - end - + let(:project) { create(:project, :with_readme) } let(:commit) do Resource::Repository::Commit.fabricate_via_api! do |commit| commit.project = project 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 a7071d5fe1b..8f85bab8677 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 @@ -3,12 +3,7 @@ module QA RSpec.describe 'Create' do describe 'Merged merge request', :requires_admin, product_group: :code_review do - let(:project) do - Resource::Project.fabricate_via_api! do |project| - project.name = 'revert' - end - end - + let(:project) { create(:project) } let(:revertible_merge_request) do Resource::MergeRequest.fabricate_via_api! do |merge_request| merge_request.project = project 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 a127b846eb9..33d5a5b050e 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,13 +2,8 @@ module QA RSpec.describe 'Create' 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" - end - end - + describe 'Merge request squashing', :reliable, product_group: :code_review do + let(:project) { create(:project, name: 'squash-before-merge') } let(:merge_request) do Resource::MergeRequest.fabricate_via_api! do |merge_request| merge_request.project = project 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 297f91be0bb..c69db9cf7b5 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 @@ -2,13 +2,8 @@ module QA RSpec.describe 'Create', :reliable, product_group: :code_review do - context 'with merge request batch suggestions' do - let(:project) do - Resource::Project.fabricate_via_api! do |project| - project.name = 'suggestions_project' - end - end - + describe 'Merge request batch suggestions' do + let(:project) { create(:project, name: 'batch-suggestions-project') } let(:merge_request) do Resource::MergeRequest.fabricate_via_api! do |merge_request| merge_request.project = 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 ce32f4aadca..8a7fb2021e6 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,15 +2,9 @@ module QA RSpec.describe 'Create' do - context 'with merge request suggestions', product_group: :code_review do + describe 'Merge request suggestions', :reliable, product_group: :code_review do let(:commit_message) { 'Applying suggested change for testing purposes.' } - - let(:project) do - Resource::Project.fabricate_via_api! do |project| - project.name = 'suggestions_project' - end - end - + let(:project) { create(:project, name: 'mr-suggestions-project') } let(:merge_request) do Resource::MergeRequest.fabricate_via_api! do |merge_request| merge_request.project = project 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 3b332e6b9f5..09967b05ffa 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', :requires_admin, product_group: :code_review do + describe 'Download merge request patch and diff', :reliable, :requires_admin, 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/repository/add_file_template_spec.rb b/qa/qa/specs/features/browser_ui/3_create/repository/add_file_template_spec.rb index 7d21c635347..0a311a42863 100644 --- a/qa/qa/specs/features/browser_ui/3_create/repository/add_file_template_spec.rb +++ b/qa/qa/specs/features/browser_ui/3_create/repository/add_file_template_spec.rb @@ -6,11 +6,10 @@ module QA include Runtime::Fixtures let(:project) do - Resource::Project.fabricate_via_api! do |project| - project.name = 'file-template-project' - project.description = 'Add file templates via the Files view' - project.initialize_with_readme = true - end + create(:project, + :with_readme, + name: 'file-template-project', + description: 'Add file templates via the Files view') end templates = [ diff --git a/qa/qa/specs/features/browser_ui/3_create/repository/add_new_branch_rule_spec.rb b/qa/qa/specs/features/browser_ui/3_create/repository/add_new_branch_rule_spec.rb index 1d9dccbddf6..6e508ba5206 100644 --- a/qa/qa/specs/features/browser_ui/3_create/repository/add_new_branch_rule_spec.rb +++ b/qa/qa/specs/features/browser_ui/3_create/repository/add_new_branch_rule_spec.rb @@ -6,12 +6,7 @@ module QA let(:branch_name) { 'new-branch' } let(:allowed_to_push_role) { Resource::ProtectedBranch::Roles::NO_ONE } let(:allowed_to_merge_role) { Resource::ProtectedBranch::Roles::MAINTAINERS } - let(:project) do - Resource::Project.fabricate_via_api! do |project| - project.name = 'branch-rule-project' - project.initialize_with_readme = true - end - end + let(:project) { create(:project, :with_readme, name: 'branch-rule-project') } before do Flow::Login.sign_in diff --git a/qa/qa/specs/features/browser_ui/3_create/repository/branch_with_unusual_name_spec.rb b/qa/qa/specs/features/browser_ui/3_create/repository/branch_with_unusual_name_spec.rb index afa9be034eb..368ac1f8cdb 100644 --- a/qa/qa/specs/features/browser_ui/3_create/repository/branch_with_unusual_name_spec.rb +++ b/qa/qa/specs/features/browser_ui/3_create/repository/branch_with_unusual_name_spec.rb @@ -4,12 +4,7 @@ module QA RSpec.describe 'Create' do describe 'Branch with unusual name', product_group: :source_code do let(:branch_name) { 'unUsually/named#br--anch' } - let(:project) do - Resource::Project.fabricate_via_api! do |resource| - resource.name = 'unusually-named-branch-project' - resource.initialize_with_readme = true - end - end + let(:project) { create(:project, :with_readme, name: 'unusually-named-branch-project') } before do Flow::Login.sign_in diff --git a/qa/qa/specs/features/browser_ui/3_create/repository/clone_spec.rb b/qa/qa/specs/features/browser_ui/3_create/repository/clone_spec.rb index b7df22fc2c2..15bd324da7c 100644 --- a/qa/qa/specs/features/browser_ui/3_create/repository/clone_spec.rb +++ b/qa/qa/specs/features/browser_ui/3_create/repository/clone_spec.rb @@ -3,12 +3,7 @@ module QA RSpec.describe 'Create' do describe 'Git clone over HTTP', product_group: :source_code do - let(:project) do - Resource::Project.fabricate_via_api! do |scenario| - scenario.name = 'project-with-code' - scenario.description = 'project for git clone tests' - end - end + let(:project) { create(:project, name: 'project-with-code', description: 'project for git clone tests') } before do Git::Repository.perform do |repository| diff --git a/qa/qa/specs/features/browser_ui/3_create/repository/file/file_with_unusual_name_spec.rb b/qa/qa/specs/features/browser_ui/3_create/repository/file/file_with_unusual_name_spec.rb index d7da29219e6..5e221d06815 100644 --- a/qa/qa/specs/features/browser_ui/3_create/repository/file/file_with_unusual_name_spec.rb +++ b/qa/qa/specs/features/browser_ui/3_create/repository/file/file_with_unusual_name_spec.rb @@ -4,12 +4,7 @@ module QA RSpec.describe 'Create' do describe 'File with unusual name', product_group: :source_code do let(:file_name) { '-un:usually;named#file?.md' } - let(:project) do - Resource::Project.fabricate_via_api! do |resource| - resource.name = 'unusually-named-file-project' - resource.initialize_with_readme = true - end - end + let(:project) { create(:project, :with_readme, name: 'unusually-named-file-project') } before do Flow::Login.sign_in diff --git a/qa/qa/specs/features/browser_ui/3_create/repository/license_detection_spec.rb b/qa/qa/specs/features/browser_ui/3_create/repository/license_detection_spec.rb index f00ef65fab4..8c8834b44a0 100644 --- a/qa/qa/specs/features/browser_ui/3_create/repository/license_detection_spec.rb +++ b/qa/qa/specs/features/browser_ui/3_create/repository/license_detection_spec.rb @@ -7,7 +7,7 @@ module QA project.remove_via_api! end - let(:project) { Resource::Project.fabricate_via_api! } + let(:project) { create(:project) } shared_examples 'project license detection' do it 'displays the name of the license on the repository' do diff --git a/qa/qa/specs/features/browser_ui/3_create/repository/move_project_create_fork_spec.rb b/qa/qa/specs/features/browser_ui/3_create/repository/move_project_create_fork_spec.rb index a13b1517740..781096323d2 100644 --- a/qa/qa/specs/features/browser_ui/3_create/repository/move_project_create_fork_spec.rb +++ b/qa/qa/specs/features/browser_ui/3_create/repository/move_project_create_fork_spec.rb @@ -4,13 +4,7 @@ module QA RSpec.describe 'Create', :orchestrated, :repository_storage, :requires_admin, product_group: :source_code do describe 'Gitaly repository storage' do let(:user) { Resource::User.fabricate_or_use(Runtime::Env.gitlab_qa_username_1, Runtime::Env.gitlab_qa_password_1) } - let(:parent_project) do - Resource::Project.fabricate_via_api! do |project| - project.name = 'parent-project' - project.initialize_with_readme = true - end - end - + let(:parent_project) { create(:project, :with_readme, name: 'parent-project') } let(:fork_project) do Resource::Fork.fabricate_via_api! do |fork| fork.user = user diff --git a/qa/qa/specs/features/browser_ui/3_create/repository/protected_tags_spec.rb b/qa/qa/specs/features/browser_ui/3_create/repository/protected_tags_spec.rb index 479c5816938..0b55ea8241e 100644 --- a/qa/qa/specs/features/browser_ui/3_create/repository/protected_tags_spec.rb +++ b/qa/qa/specs/features/browser_ui/3_create/repository/protected_tags_spec.rb @@ -3,13 +3,7 @@ module QA RSpec.describe 'Create' do describe 'Repository tags', :reliable, product_group: :source_code do - let(:project) do - Resource::Project.fabricate_via_api! do |project| - project.name = 'project-for-tags' - project.initialize_with_readme = true - end - end - + let(:project) { create(:project, :with_readme, name: 'project-for-tags') } let(:developer_user) do Resource::User.fabricate_or_use(Runtime::Env.gitlab_qa_username_1, Runtime::Env.gitlab_qa_password_1) end diff --git a/qa/qa/specs/features/browser_ui/3_create/repository/protocol_v2_push_http_spec.rb b/qa/qa/specs/features/browser_ui/3_create/repository/protocol_v2_push_http_spec.rb index 557a27c002d..2cf8c4ae154 100644 --- a/qa/qa/specs/features/browser_ui/3_create/repository/protocol_v2_push_http_spec.rb +++ b/qa/qa/specs/features/browser_ui/3_create/repository/protocol_v2_push_http_spec.rb @@ -7,9 +7,7 @@ module QA Flow::Login.sign_in # Create a project to push to - project = Resource::Project.fabricate_via_api! do |project| - project.name = 'git-protocol-project' - end + project = create(:project, name: 'git-protocol-project') file_name = 'README.md' file_content = 'Test Git protocol v2' diff --git a/qa/qa/specs/features/browser_ui/3_create/repository/protocol_v2_push_ssh_spec.rb b/qa/qa/specs/features/browser_ui/3_create/repository/protocol_v2_push_ssh_spec.rb index 2472d1cdf25..1f60eb16b01 100644 --- a/qa/qa/specs/features/browser_ui/3_create/repository/protocol_v2_push_ssh_spec.rb +++ b/qa/qa/specs/features/browser_ui/3_create/repository/protocol_v2_push_ssh_spec.rb @@ -28,9 +28,7 @@ module QA end it 'user pushes to the repository', testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347734' do - project = Resource::Project.fabricate_via_api! do |project| - project.name = 'git-protocol-project' - end + project = create(:project, name: 'git-protocol-project') file_name = 'README.md' file_content = 'Test Git protocol v2' diff --git a/qa/qa/specs/features/browser_ui/3_create/repository/push_mirroring_lfs_over_http_spec.rb b/qa/qa/specs/features/browser_ui/3_create/repository/push_mirroring_lfs_over_http_spec.rb index b8a018552c6..4f45feb1b0a 100644 --- a/qa/qa/specs/features/browser_ui/3_create/repository/push_mirroring_lfs_over_http_spec.rb +++ b/qa/qa/specs/features/browser_ui/3_create/repository/push_mirroring_lfs_over_http_spec.rb @@ -7,9 +7,7 @@ module QA Runtime::Browser.visit(:gitlab, Page::Main::Login) Page::Main::Login.perform(&:sign_in_using_credentials) - target_project = Resource::Project.fabricate_via_api! do |project| - project.name = 'push-mirror-target-project' - end + target_project = create(:project, name: 'push-mirror-target-project') target_project_uri = target_project.repository_http_location.uri target_project_uri.user = Runtime::User.username diff --git a/qa/qa/specs/features/browser_ui/3_create/repository/push_mirroring_over_http_spec.rb b/qa/qa/specs/features/browser_ui/3_create/repository/push_mirroring_over_http_spec.rb index b87c47761bd..4cd371b524d 100644 --- a/qa/qa/specs/features/browser_ui/3_create/repository/push_mirroring_over_http_spec.rb +++ b/qa/qa/specs/features/browser_ui/3_create/repository/push_mirroring_over_http_spec.rb @@ -7,9 +7,7 @@ module QA Runtime::Browser.visit(:gitlab, Page::Main::Login) Page::Main::Login.perform(&:sign_in_using_credentials) - target_project = Resource::Project.fabricate_via_api! do |project| - project.name = 'push-mirror-target-project' - end + target_project = create(:project, name: 'push-mirror-target-project') target_project_uri = target_project.repository_http_location.uri target_project_uri.user = Runtime::User.username diff --git a/qa/qa/specs/features/browser_ui/3_create/repository/push_over_http_file_size_spec.rb b/qa/qa/specs/features/browser_ui/3_create/repository/push_over_http_file_size_spec.rb index 324dbbc46ef..76aba401aaa 100644 --- a/qa/qa/specs/features/browser_ui/3_create/repository/push_over_http_file_size_spec.rb +++ b/qa/qa/specs/features/browser_ui/3_create/repository/push_over_http_file_size_spec.rb @@ -7,12 +7,7 @@ module QA describe 'push after setting the file size limit via admin/application_settings' do include Support::API - let!(:project) do - Resource::Project.fabricate_via_api! do |p| - p.name = 'project-test-push-limit' - p.initialize_with_readme = true - end - end + let!(:project) { create(:project, :with_readme, name: 'project-test-push-limit') } after(:context) do set_file_size_limit(nil) 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 edc85849356..0b689081b7f 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 @@ -23,10 +23,9 @@ module QA :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| - storage_project.name = 'specific-repository-storage' - storage_project.repository_storage = QA::Runtime::Env.praefect_repository_storage - end + project = create(:project, + name: 'specific-repository-storage', + repository_storage: Runtime::Env.praefect_repository_storage) Resource::Repository::Push.fabricate! do |push| push.repository_http_uri = project.repository_http_location.uri diff --git a/qa/qa/specs/features/browser_ui/3_create/repository/push_protected_branch_spec.rb b/qa/qa/specs/features/browser_ui/3_create/repository/push_protected_branch_spec.rb index e097e1fd2bb..b06879e9140 100644 --- a/qa/qa/specs/features/browser_ui/3_create/repository/push_protected_branch_spec.rb +++ b/qa/qa/specs/features/browser_ui/3_create/repository/push_protected_branch_spec.rb @@ -5,12 +5,7 @@ module QA describe 'Protected branch support' do let(:branch_name) { 'protected-branch' } let(:commit_message) { 'Protected push commit message' } - let(:project) do - Resource::Project.fabricate_via_api! do |resource| - resource.name = 'protected-branch-project' - resource.initialize_with_readme = true - end - end + let(:project) { create(:project, :with_readme, name: 'protected-branch-project') } before do Runtime::Browser.visit(:gitlab, Page::Main::Login) diff --git a/qa/qa/specs/features/browser_ui/3_create/repository/push_to_canary_gitaly_spec.rb b/qa/qa/specs/features/browser_ui/3_create/repository/push_to_canary_gitaly_spec.rb index d95a880c305..b20b1f8cd92 100644 --- a/qa/qa/specs/features/browser_ui/3_create/repository/push_to_canary_gitaly_spec.rb +++ b/qa/qa/specs/features/browser_ui/3_create/repository/push_to_canary_gitaly_spec.rb @@ -6,10 +6,7 @@ module QA it 'pushes to a project using a canary specific Gitaly repository storage', :smoke, :requires_admin, testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/351116' do Flow::Login.sign_in_as_admin - project = Resource::Project.fabricate_via_api! do |storage_project| - storage_project.name = 'canary-specific-repository-storage' - storage_project.repository_storage = 'nfs-file-cny01' # TODO: move to ENV var - end + project = create(:project, name: 'canary-specific-repository-storage', repository_storage: 'nfs-file-cny01') # TODO: move to ENV var Resource::Repository::Push.fabricate! do |push| push.repository_http_uri = project.repository_http_location.uri diff --git a/qa/qa/specs/features/browser_ui/3_create/repository/ssh_key_support_spec.rb b/qa/qa/specs/features/browser_ui/3_create/repository/ssh_key_support_spec.rb index 64858287285..a2fe79ae65d 100644 --- a/qa/qa/specs/features/browser_ui/3_create/repository/ssh_key_support_spec.rb +++ b/qa/qa/specs/features/browser_ui/3_create/repository/ssh_key_support_spec.rb @@ -29,7 +29,7 @@ module QA ssh_keys.remove_key(key.title) end - expect(page).not_to have_content("Title: #{key.title}") + expect(page).not_to have_content(key.title) expect(page).not_to have_content(key.sha256_fingerprint) end end diff --git a/qa/qa/specs/features/browser_ui/3_create/repository/user_views_commit_diff_patch_spec.rb b/qa/qa/specs/features/browser_ui/3_create/repository/user_views_commit_diff_patch_spec.rb index 13b42209114..4f2e657fada 100644 --- a/qa/qa/specs/features/browser_ui/3_create/repository/user_views_commit_diff_patch_spec.rb +++ b/qa/qa/specs/features/browser_ui/3_create/repository/user_views_commit_diff_patch_spec.rb @@ -2,7 +2,7 @@ module QA RSpec.describe 'Create' do - describe 'Commit data', product_group: :source_code do + describe 'Commit data', :reliable, product_group: :source_code do before(:context) do # Get the user's details to confirm they're included in the email patch @user = Resource::User.fabricate_via_api! do |user| 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 9b1df337065..bd98cb17332 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 @@ -3,13 +3,7 @@ module QA RSpec.describe 'Create' do describe 'Source editor toolbar preview', product_group: :source_code do - let(:project) do - Resource::Project.fabricate_via_api! do |project| - project.name = 'empty-project-with-md' - project.initialize_with_readme = true - end - end - + let(:project) { create(:project, :with_readme, name: 'empty-project-with-md') } let(:edited_readme_content) { 'Here is the edited content.' } before do 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 3e8f9307cec..4172aa03a72 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 @@ -8,12 +8,7 @@ module QA type: :flaky } do describe 'Add a directory in Web IDE' do - let(:project) do - Resource::Project.fabricate_via_api! do |project| - project.name = 'add-directory-project' - project.initialize_with_readme = true - end - end + let(:project) { create(:project, :with_readme, name: 'add-directory-project') } before do Flow::Login.sign_in 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 336d32bcc35..afed95e18f9 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 @@ -9,13 +9,7 @@ module QA } do describe 'Upload a file in Web IDE' do let(:file_path) { File.absolute_path(File.join('qa', 'fixtures', 'web_ide', file_name)) } - - let(:project) do - Resource::Project.fabricate_via_api! do |project| - project.name = 'upload-file-project' - project.initialize_with_readme = true - end - end + let(:project) { create(:project, :with_readme, name: 'upload-file-project') } before do Flow::Login.sign_in diff --git a/qa/qa/specs/features/browser_ui/3_create/web_ide_old/add_file_template_spec.rb b/qa/qa/specs/features/browser_ui/3_create/web_ide_old/add_file_template_spec.rb index 3e24fb496e7..18dd4d912d8 100644 --- a/qa/qa/specs/features/browser_ui/3_create/web_ide_old/add_file_template_spec.rb +++ b/qa/qa/specs/features/browser_ui/3_create/web_ide_old/add_file_template_spec.rb @@ -11,11 +11,10 @@ module QA include Runtime::Fixtures before(:all) do - @project = Resource::Project.fabricate_via_api! do |project| - project.name = 'file-template-project' - project.description = 'Add file templates via the Web IDE' - project.initialize_with_readme = true - end + @project = create(:project, + :with_readme, + name: 'file-template-project', + description: 'Add file templates via Web IDE') end templates = [ diff --git a/qa/qa/specs/features/browser_ui/3_create/web_ide_old/create_first_file_in_web_ide_spec.rb b/qa/qa/specs/features/browser_ui/3_create/web_ide_old/create_first_file_in_web_ide_spec.rb index 775e14500d5..8fe58078393 100644 --- a/qa/qa/specs/features/browser_ui/3_create/web_ide_old/create_first_file_in_web_ide_spec.rb +++ b/qa/qa/specs/features/browser_ui/3_create/web_ide_old/create_first_file_in_web_ide_spec.rb @@ -8,13 +8,7 @@ module QA end describe 'First file using Web IDE' do - let(:project) do - Resource::Project.fabricate_via_api! do |project| - project.name = 'empty-project' - project.initialize_with_readme = false - end - end - + let(:project) { create(:project, :with_readme, name: 'empty-project') } let(:file_name) { 'the very first file.txt' } before do diff --git a/qa/qa/specs/features/browser_ui/3_create/web_ide_old/link_to_line_in_web_ide_spec.rb b/qa/qa/specs/features/browser_ui/3_create/web_ide_old/link_to_line_in_web_ide_spec.rb index bea2e906d5e..57c8945d5c4 100644 --- a/qa/qa/specs/features/browser_ui/3_create/web_ide_old/link_to_line_in_web_ide_spec.rb +++ b/qa/qa/specs/features/browser_ui/3_create/web_ide_old/link_to_line_in_web_ide_spec.rb @@ -9,11 +9,7 @@ module QA 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 - Resource::Project.fabricate_via_api! do |project| - project.template_name = 'express' - end - end + let(:project) { create(:project, template_name: 'express') } before do Flow::Login.sign_in diff --git a/qa/qa/specs/features/browser_ui/3_create/web_ide_old/open_web_ide_from_diff_tab_spec.rb b/qa/qa/specs/features/browser_ui/3_create/web_ide_old/open_web_ide_from_diff_tab_spec.rb index c4ed2038f4c..10483a7cbee 100644 --- a/qa/qa/specs/features/browser_ui/3_create/web_ide_old/open_web_ide_from_diff_tab_spec.rb +++ b/qa/qa/specs/features/browser_ui/3_create/web_ide_old/open_web_ide_from_diff_tab_spec.rb @@ -23,12 +23,7 @@ module QA } ] - let(:project) do - Resource::Project.fabricate_via_api! do |project| - project.initialize_with_readme = true - end - end - + let(:project) { create(:project, :with_readme) } let(:source) do Resource::Repository::Commit.fabricate_via_api! do |commit| commit.project = project diff --git a/qa/qa/specs/features/browser_ui/3_create/web_ide_old/review_merge_request_spec.rb b/qa/qa/specs/features/browser_ui/3_create/web_ide_old/review_merge_request_spec.rb index 1043e9051e3..4044494d3da 100644 --- a/qa/qa/specs/features/browser_ui/3_create/web_ide_old/review_merge_request_spec.rb +++ b/qa/qa/specs/features/browser_ui/3_create/web_ide_old/review_merge_request_spec.rb @@ -11,13 +11,7 @@ module QA let(:new_file) { 'awesome_new_file.txt' } let(:original_text) { 'Text' } let(:review_text) { 'Reviewed ' } - - let(:project) do - Resource::Project.fabricate_via_api! do |project| - project.name = 'review-merge-request-spec-project' - project.initialize_with_readme = true - end - end + let(:project) { create(:project, :with_readme, name: 'review-mr-spec-project') } let(:merge_request) do Resource::MergeRequest.fabricate_via_api! do |mr| diff --git a/qa/qa/specs/features/browser_ui/3_create/web_ide_old/server_hooks_custom_error_message_spec.rb b/qa/qa/specs/features/browser_ui/3_create/web_ide_old/server_hooks_custom_error_message_spec.rb index 05925505610..42fcbf5352f 100644 --- a/qa/qa/specs/features/browser_ui/3_create/web_ide_old/server_hooks_custom_error_message_spec.rb +++ b/qa/qa/specs/features/browser_ui/3_create/web_ide_old/server_hooks_custom_error_message_spec.rb @@ -10,13 +10,9 @@ module QA describe 'Git Server Hooks' do let(:file_path) { Runtime::Path.fixture('web_ide', 'README.md') } - let(:project) do - Resource::Project.fabricate_via_api! do |project| - # Projects that have names that include pattern 'reject-prereceive' trigger a server hook on orchestrated env - # that returns an error string using GL-HOOK-ERR - project.name = "project-reject-prereceive-#{SecureRandom.hex(8)}" - end - end + # Projects that have names that include pattern 'reject-prereceive' trigger a server hook on orchestrated env + # that returns an error string using GL-HOOK-ERR + let(:project) { create(:project, name: "project-reject-prereceive-#{SecureRandom.hex(8)}") } before do Flow::Login.sign_in diff --git a/qa/qa/specs/features/browser_ui/3_create/web_ide_old/upload_new_file_in_web_ide_spec.rb b/qa/qa/specs/features/browser_ui/3_create/web_ide_old/upload_new_file_in_web_ide_spec.rb index c557f2fa8a6..ab035d3b52c 100644 --- a/qa/qa/specs/features/browser_ui/3_create/web_ide_old/upload_new_file_in_web_ide_spec.rb +++ b/qa/qa/specs/features/browser_ui/3_create/web_ide_old/upload_new_file_in_web_ide_spec.rb @@ -9,12 +9,7 @@ module QA describe 'Upload a file in Web IDE' do let(:file_path) { Runtime::Path.fixture('web_ide', file_name) } - let(:project) do - Resource::Project.fabricate_via_api! do |project| - project.name = 'upload-file-project' - project.initialize_with_readme = true - end - end + let(:project) { create(:project, :with_readme, name: 'upload-file-project') } before do Flow::Login.sign_in diff --git a/qa/qa/specs/features/browser_ui/4_verify/ci_job_artifacts/unlocking_job_artifacts_across_parent_child_pipelines_spec.rb b/qa/qa/specs/features/browser_ui/4_verify/ci_job_artifacts/unlocking_job_artifacts_across_parent_child_pipelines_spec.rb index b08a36b0d43..d5de93fdee6 100644 --- a/qa/qa/specs/features/browser_ui/4_verify/ci_job_artifacts/unlocking_job_artifacts_across_parent_child_pipelines_spec.rb +++ b/qa/qa/specs/features/browser_ui/4_verify/ci_job_artifacts/unlocking_job_artifacts_across_parent_child_pipelines_spec.rb @@ -2,15 +2,9 @@ module QA RSpec.describe 'Verify', :runner, product_group: :pipeline_security do - describe "Unlocking job artifacts across parent-child pipelines" do + describe 'Unlocking job artifacts across parent-child pipelines' do let(:executor) { "qa-runner-#{Faker::Alphanumeric.alphanumeric(number: 8)}" } - - let(:project) do - Resource::Project.fabricate_via_api! do |project| - project.name = 'unlock-job-artifacts-parent-child-project' - end - end - + let(:project) { create(:project, name: 'unlock-job-artifacts-parent-child-project') } let!(:runner) do Resource::ProjectRunner.fabricate! do |runner| runner.project = project @@ -249,6 +243,8 @@ module QA private def update_parent_child_ci_files(parent_job_name:, parent_script:, child_job_name:, child_script:) + original_pipeline_count = pipeline_count + Resource::Repository::Commit.fabricate_via_api! do |commit| commit.project = project commit.commit_message = 'Update parent and child pipelines CI files.' @@ -259,9 +255,13 @@ module QA ] ) end + + wait_for_pipeline_creation(original_pipeline_count) end def add_parent_child_ci_files(parent_job_name:, parent_script:, child_job_name:, child_script:) + original_pipeline_count = pipeline_count + Resource::Repository::Commit.fabricate_via_api! do |commit| commit.project = project commit.commit_message = 'Add parent and child pipelines CI files.' @@ -272,6 +272,8 @@ module QA ] ) end + + wait_for_pipeline_creation(original_pipeline_count) end def parent_ci_file(job_name, script) @@ -316,6 +318,16 @@ module QA job.id = project.job_by_name(job_name)[:id] end end + + def wait_for_pipeline_creation(original_pipeline_count) + Support::Waiter.wait_until(sleep_interval: 1, message: 'Wait for pipeline creation') do + pipeline_count > original_pipeline_count + end + end + + def pipeline_count + project.pipelines.length + end end end end diff --git a/qa/qa/specs/features/browser_ui/4_verify/ci_job_artifacts/unlocking_job_artifacts_across_pipelines_spec.rb b/qa/qa/specs/features/browser_ui/4_verify/ci_job_artifacts/unlocking_job_artifacts_across_pipelines_spec.rb index 41ce868f0d6..91e62dfba9b 100644 --- a/qa/qa/specs/features/browser_ui/4_verify/ci_job_artifacts/unlocking_job_artifacts_across_pipelines_spec.rb +++ b/qa/qa/specs/features/browser_ui/4_verify/ci_job_artifacts/unlocking_job_artifacts_across_pipelines_spec.rb @@ -4,12 +4,7 @@ module QA RSpec.describe 'Verify', :runner, product_group: :pipeline_security do describe "Unlocking job artifacts across pipelines" do let(:executor) { "qa-runner-#{Faker::Alphanumeric.alphanumeric(number: 8)}" } - - let(:project) do - Resource::Project.fabricate_via_api! do |project| - project.name = 'unlock-job-artifacts-project' - end - end + let(:project) { create(:project, name: 'unlock-job-artifacts-project') } let!(:runner) do Resource::ProjectRunner.fabricate! do |runner| 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 4515353dfc5..4ec9360be24 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 @@ -6,13 +6,7 @@ module QA let(:executor) { "qa-runner-#{Time.now.to_i}" } let(:pipeline_job_name) { 'customizable-variable' } let(:variable_custom_value) { 'Custom Foo' } - - let(:project) do - Resource::Project.fabricate_via_api! do |project| - project.name = 'project-with-customizable-variable-pipeline' - end - end - + let(:project) { create(:project, name: 'project-with-customizable-variable-pipeline') } let!(:runner) do Resource::ProjectRunner.fabricate! do |runner| runner.project = project 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 e2d25e64687..8e168ef80f6 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 @@ -5,13 +5,7 @@ module QA describe 'Pipeline with protected variable' do 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| - project.name = 'project-with-ci-variables' - project.description = 'project with CI variables' - end - end + let(:project) { create(:project, name: 'project-with-ci-vars', description: 'project with CI vars') } let!(:runner) do Resource::ProjectRunner.fabricate! do |runner| 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 b62ae85436f..8d315f66034 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 @@ -8,12 +8,7 @@ module QA let(:prefill_variable_value5) { Faker::Lorem.word } let(:prefill_variable_description2) { Faker::Lorem.sentence } let(:prefill_variable_description5) { Faker::Lorem.sentence } - let(:project) do - Resource::Project.fabricate_via_api! do |project| - project.name = 'project-with-prefill-variables' - end - end - + let(:project) { create(:project, name: 'project-with-prefill-variables') } let!(:commit) do Resource::Repository::Commit.fabricate_via_api! do |commit| commit.project = project diff --git a/qa/qa/specs/features/browser_ui/4_verify/ci_variable/raw_variables_defined_in_yaml_spec.rb b/qa/qa/specs/features/browser_ui/4_verify/ci_variable/raw_variables_defined_in_yaml_spec.rb index 15959721935..f47949e0024 100644 --- a/qa/qa/specs/features/browser_ui/4_verify/ci_variable/raw_variables_defined_in_yaml_spec.rb +++ b/qa/qa/specs/features/browser_ui/4_verify/ci_variable/raw_variables_defined_in_yaml_spec.rb @@ -5,12 +5,7 @@ module QA describe 'Pipeline with raw variables in YAML', product_group: :pipeline_security do let(:executor) { "qa-runner-#{Time.now.to_i}" } let(:pipeline_job_name) { 'rspec' } - - let(:project) do - Resource::Project.fabricate_via_api! do |project| - project.name = 'project-with-raw-variable-pipeline' - end - end + let(:project) { create(:project, name: 'project-with-raw-variable-pipeline') } let!(:runner) do Resource::ProjectRunner.fabricate! do |runner| 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 027383550a7..8cf923f543b 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 @@ -3,11 +3,7 @@ module QA RSpec.describe 'Verify' 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' - end - end + let(:project) { create(:project, name: 'project-with-pipeline') } before do Flow::Login.sign_in 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 5bbe09b3fb0..fe655f41992 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 @@ -7,17 +7,8 @@ module QA let(:expected_text) { Faker::Lorem.sentence } let(:unexpected_text) { Faker::Lorem.sentence } - let(:project) do - Resource::Project.fabricate_via_api! do |project| - project.name = 'project-with-pipeline-1' - end - end - - let(:other_project) do - Resource::Project.fabricate_via_api! do |project| - project.name = 'project-with-pipeline-2' - end - end + let(:project) { create(:project, name: 'project-with-pipeline-1') } + let(:other_project) { create(:project, name: 'project-with-pipeline-2') } let!(:runner) do Resource::ProjectRunner.fabricate! do |runner| diff --git a/qa/qa/specs/features/browser_ui/4_verify/pipeline/include_multiple_files_from_multiple_projects_spec.rb b/qa/qa/specs/features/browser_ui/4_verify/pipeline/include_multiple_files_from_multiple_projects_spec.rb index 59591fbe1cd..da7b7ec720f 100644 --- a/qa/qa/specs/features/browser_ui/4_verify/pipeline/include_multiple_files_from_multiple_projects_spec.rb +++ b/qa/qa/specs/features/browser_ui/4_verify/pipeline/include_multiple_files_from_multiple_projects_spec.rb @@ -4,25 +4,9 @@ module QA RSpec.describe 'Verify', :runner, product_group: :pipeline_authoring do describe 'Include multiple files from multiple projects' do let(:executor) { "qa-runner-#{Faker::Alphanumeric.alphanumeric(number: 8)}" } - - let(:main_project) do - Resource::Project.fabricate_via_api! do |project| - project.name = 'project-with-pipeline' - end - end - - let(:project1) do - Resource::Project.fabricate_via_api! do |project| - project.name = 'external-project-1' - end - end - - let(:project2) do - Resource::Project.fabricate_via_api! do |project| - project.name = 'external-project-2' - end - end - + let(:main_project) { create(:project, name: 'project-with-pipeline') } + let(:project1) { create(:project, name: 'external-project-1') } + let(:project2) { create(:project, name: 'external-project-2') } let!(:runner) do Resource::ProjectRunner.fabricate! do |runner| runner.project = main_project 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 ecf4826262b..3e1e2bc5b5b 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 @@ -8,13 +8,7 @@ module QA } do context 'when pipeline is blocked' do let(:executor) { "qa-runner-#{Faker::Alphanumeric.alphanumeric(number: 8)}" } - - let(:project) do - Resource::Project.fabricate_via_api! do |project| - project.name = 'project-with-blocked-pipeline' - end - end - + let(:project) { create(:project, name: 'project-with-blocked-pipeline') } let!(:runner) do Resource::ProjectRunner.fabricate! do |runner| runner.project = 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 fef90a7c8fc..52efacfd407 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 @@ -3,12 +3,7 @@ module QA 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| - project.name = 'pipeline-independent-relationship' - end - end - + let!(:project) { create(:project, name: 'pipeline-independent-relationship') } let!(:runner) do Resource::ProjectRunner.fabricate_via_api! do |runner| runner.project = 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 6295c596dda..f9a3856f810 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 @@ -5,21 +5,9 @@ module QA 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) } - let(:group) { Resource::Group.fabricate_via_api! } - - let(:upstream_project) do - Resource::Project.fabricate_via_api! do |project| - project.group = group - project.name = 'upstream-project-with-bridge' - end - end - - let(:downstream_project) do - Resource::Project.fabricate_via_api! do |project| - project.group = group - project.name = 'downstream-project-with-bridge' - end - end + let(:group) { create(:group) } + let(:upstream_project) { create(:project, group: group, name: 'upstream-project-with-bridge') } + let(:downstream_project) { create(:project, group: group, name: 'downstream-project-with-bridge') } let!(:runner) do Resource::GroupRunner.fabricate! do |runner| 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 1f7871b0900..f4847a9ec99 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 @@ -3,12 +3,7 @@ module QA RSpec.describe 'Verify' do describe 'Pipeline editor', product_group: :pipeline_authoring do - let(:project) do - Resource::Project.fabricate_via_api! do |project| - project.name = 'pipeline-editor-project' - project.initialize_with_readme = true - end - end + let(:project) { create(:project, :with_readme, name: 'pipeline-editor-project') } before do Flow::Login.sign_in @@ -27,13 +22,6 @@ module QA Page::Project::PipelineEditor::New.perform(&:create_new_ci) Page::Project::PipelineEditor::Show.perform do |show| - # Editor should display default content when project does not have CI file yet - # New MR checkbox should not be rendered when a new target branch is yet to be provided - aggregate_failures 'check editor default conditions' do - expect(show.editing_content).not_to be_empty - expect(show).to have_no_new_mr_checkbox - end - # The new MR checkbox is visible after a new branch name is set show.set_source_branch(SecureRandom.hex(10)) expect(show).to have_new_mr_checkbox 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 1abe1df5964..69d8467e6ea 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 @@ -5,13 +5,7 @@ module QA 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('-')}" } - - let(:project) do - Resource::Project.fabricate_via_api! do |project| - project.name = 'pipeline-with-image-pull-policy' - end - end - + let(:project) { create(:project, name: 'pipeline-with-image-pull-policy') } let!(:runner) do Resource::ProjectRunner.fabricate! do |runner| runner.project = project 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 9f43471035f..b96869658c9 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 @@ -5,12 +5,7 @@ module QA describe 'Run pipeline', :reliable, product_group: :pipeline_execution do context 'with web only rule' do let(:job_name) { 'test_job' } - let(:project) do - Resource::Project.fabricate_via_api! do |project| - project.name = 'web-only-pipeline' - end - end - + let(:project) { create(:project, name: 'web-only-pipeline') } let!(:ci_file) do Resource::Repository::Commit.fabricate_via_api! do |commit| commit.project = project 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 d733ac9ba72..019228da130 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 @@ -6,10 +6,7 @@ module QA let(:executor) { "qa-runner-#{SecureRandom.hex(4)}" } let(:project) do - Resource::Project.fabricate_via_api! do |project| - project.name = 'pipeline-with-manual-job' - project.description = 'Project for pipeline with manual job' - end + create(:project, name: 'pipeline-with-manual-job', description: 'Project for pipeline with manual job') end let!(:runner) do 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 3361ab98bda..09d1fd331cd 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 @@ -4,13 +4,7 @@ module QA RSpec.describe 'Verify', :runner, product_group: :pipeline_execution do describe "Trigger child pipeline with 'when:manual'" do let(:executor) { "qa-runner-#{Faker::Alphanumeric.alphanumeric(number: 8)}" } - - let(:project) do - Resource::Project.fabricate_via_api! do |project| - project.name = 'project-with-pipeline' - end - end - + let(:project) { create(:project, name: 'project-with-pipeline') } let!(:runner) do Resource::ProjectRunner.fabricate! do |runner| runner.project = 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 bd656142989..6eea6756ee7 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 @@ -4,13 +4,7 @@ module QA RSpec.describe 'Verify', :runner, product_group: :pipeline_authoring do describe 'Trigger matrix' do let(:executor) { "qa-runner-#{Faker::Alphanumeric.alphanumeric(number: 8)}" } - - let(:project) do - Resource::Project.fabricate_via_api! do |project| - project.name = 'project-with-pipeline' - end - end - + let(:project) { create(:project, name: 'project-with-pipeline') } let!(:runner) do Resource::ProjectRunner.fabricate! do |runner| runner.project = 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 a749da4608a..5c0e2a9d668 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 @@ -4,13 +4,7 @@ module QA RSpec.describe 'Verify' do describe 'Update CI file with pipeline editor', product_group: :pipeline_authoring do let(:random_test_string) { SecureRandom.hex(10) } - - let(:project) do - Resource::Project.fabricate_via_api! do |project| - project.name = 'pipeline-editor-project' - end - end - + let(:project) { create(:project, name: 'pipeline-editor-project') } let!(:runner) do Resource::ProjectRunner.fabricate_via_api! do |runner| runner.project = project 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 e2bb6c33513..da7a6c537b8 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 @@ -11,12 +11,7 @@ module QA # User views pipeline succeeds (Web read) RSpec.describe 'Verify', :runner, product_group: :pipeline_security do context 'Endpoint Coverage' do - let!(:project) do - Resource::Project.fabricate_via_api! do |project| - project.name = 'endpoint-coverage' - end - end - + let!(:project) { create(:project, name: 'endpoint-coverage') } let!(:runner) do Resource::ProjectRunner.fabricate_via_api! do |runner| runner.project = project diff --git a/qa/qa/specs/features/browser_ui/5_package/container_registry/saas/container_registry_spec.rb b/qa/qa/specs/features/browser_ui/5_package/container_registry/saas/container_registry_spec.rb index 4b2d9f96cd2..49d1434035f 100644 --- a/qa/qa/specs/features/browser_ui/5_package/container_registry/saas/container_registry_spec.rb +++ b/qa/qa/specs/features/browser_ui/5_package/container_registry/saas/container_registry_spec.rb @@ -4,50 +4,46 @@ module QA RSpec.describe 'Package' do describe 'SaaS Container Registry', only: { subdomain: %i[staging staging-canary pre] }, product_group: :container_registry do - let(:project) do - Resource::Project.fabricate_via_api! do |project| - project.name = 'project-with-registry' - project.template_name = 'express' - end - end - - let(:registry_repository) do - Resource::RegistryRepository.fabricate! do |repository| - repository.name = project.path_with_namespace.to_s - repository.project = project - end - end - + let(:project) { create(:project, name: 'project-with-registry', template_name: 'express') } let!(:gitlab_ci_yaml) do <<~YAML - build: - image: docker:24.0.1 - stage: build - services: - - docker:24.0.1-dind - variables: - IMAGE_TAG: $CI_REGISTRY_IMAGE:$CI_COMMIT_REF_SLUG - DOCKER_HOST: tcp://docker:2376 - DOCKER_TLS_CERTDIR: "/certs" - DOCKER_TLS_VERIFY: 1 - DOCKER_CERT_PATH: "$DOCKER_TLS_CERTDIR/client" - before_script: - - | - echo "Waiting for docker to start..." - for i in $(seq 1 30) - do - docker info && break - sleep 1s - done - script: - - docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY - - docker build -t $IMAGE_TAG . - - docker push $IMAGE_TAG - YAML - end + stages: + - test + - build - after do - registry_repository&.remove_via_api! + test: + image: registry.gitlab.com/gitlab-ci-utils/curl-jq:latest + stage: test + script: + - 'status_code=$(curl --header "Authorization: Bearer $CI_JOB_TOKEN" "https://${CI_SERVER_HOST}/gitlab/v1")' + - | + if [ "$status_code" -eq 404 ]; then + echo "The registry implements this API specification, but it is unavailable because the metadata database is disabled." + exit 1 + fi + build: + image: docker:24.0.1 + stage: build + services: + - docker:24.0.1-dind + variables: + IMAGE_TAG: $CI_REGISTRY_IMAGE:$CI_COMMIT_REF_SLUG + DOCKER_HOST: tcp://docker:2376 + DOCKER_TLS_CERTDIR: "/certs" + DOCKER_TLS_VERIFY: 1 + DOCKER_CERT_PATH: "$DOCKER_TLS_CERTDIR/client" + before_script: + - | + echo "Waiting for docker to start..." + for i in $(seq 1 30); do + docker info && break + sleep 1s + done + script: + - docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY + - docker build -t $IMAGE_TAG . + - docker push $IMAGE_TAG + YAML end it 'pushes project image to the container registry and deletes tag', @@ -69,11 +65,20 @@ module QA Flow::Pipeline.visit_latest_pipeline Page::Project::Pipeline::Show.perform do |pipeline| + pipeline.click_job('test') + end + Page::Project::Job::Show.perform do |job| + expect(job).to be_successful(timeout: 200) + + job.click_element(:pipeline_path) + end + + Page::Project::Pipeline::Show.perform do |pipeline| pipeline.click_job('build') end Page::Project::Job::Show.perform do |job| - expect(job).to be_successful(timeout: 800) + expect(job).to be_successful(timeout: 500) end Page::Project::Menu.perform(&:go_to_container_registry) diff --git a/qa/qa/specs/features/browser_ui/5_package/container_registry/saas/pull_container_registry_image_spec.rb b/qa/qa/specs/features/browser_ui/5_package/container_registry/saas/pull_container_registry_image_spec.rb index 85a88b54cc2..3c656d9ca75 100644 --- a/qa/qa/specs/features/browser_ui/5_package/container_registry/saas/pull_container_registry_image_spec.rb +++ b/qa/qa/specs/features/browser_ui/5_package/container_registry/saas/pull_container_registry_image_spec.rb @@ -2,16 +2,18 @@ module QA RSpec.describe 'Package' do - describe 'SaaS Container Registry', only: { subdomain: %i[staging] }, product_group: :container_registry do - let(:project) do - Resource::Project.init do |project| - project.path_with_namespace = 'gitlab-qa/container-registry-sanity' - end.reload! + describe 'SaaS Container Registry', :smoke, + only: { subdomain: :staging }, product_group: :container_registry do + before do + Flow::Login.sign_in end it 'pulls an image from an existing repository', testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/412799' do - Flow::Login.sign_in + project = Resource::Project.init do |project| + project.path_with_namespace = 'gitlab-qa/container-registry-sanity' + end.reload! + project.visit! Page::Project::Menu.perform(&:go_to_pipelines) diff --git a/qa/qa/specs/features/browser_ui/5_package/container_registry/self_managed/container_registry_spec.rb b/qa/qa/specs/features/browser_ui/5_package/container_registry/self_managed/container_registry_spec.rb index 800b3a01dc6..e4d6ba9c4db 100644 --- a/qa/qa/specs/features/browser_ui/5_package/container_registry/self_managed/container_registry_spec.rb +++ b/qa/qa/specs/features/browser_ui/5_package/container_registry/self_managed/container_registry_spec.rb @@ -5,14 +5,7 @@ module QA describe 'Self-managed Container Registry' do include Support::Helpers::MaskToken - let(:project) do - Resource::Project.fabricate_via_api! do |project| - project.name = 'project-with-registry' - project.template_name = 'express' - project.visibility = :private - end - end - + let(:project) { create(:project, :private, name: 'project-with-registry', template_name: 'express') } let(:project_deploy_token) do Resource::ProjectDeployToken.fabricate_via_api! do |deploy_token| deploy_token.name = 'registry-deploy-token' @@ -43,10 +36,6 @@ module QA project.visit! end - after do - runner.remove_via_api! - end - context "when tls is disabled" do where do { @@ -200,27 +189,27 @@ module QA file_path: '.gitlab-ci.yml', content: <<~YAML - build: - image: docker:23.0.6 - stage: build - services: + build: + image: docker:23.0.6 + stage: build + services: - name: docker:23.0.6-dind command: - - /bin/sh - - -c - - | - apk add --no-cache openssl - true | openssl s_client -showcerts -connect gitlab.test:5050 > /usr/local/share/ca-certificates/gitlab.test.crt - update-ca-certificates - dockerd-entrypoint.sh || exit - variables: - IMAGE_TAG: $CI_REGISTRY_IMAGE:$CI_COMMIT_REF_SLUG - script: - - docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD gitlab.test:5050 - - docker build -t $IMAGE_TAG . - - docker push $IMAGE_TAG - tags: - - "runner-for-#{project.name}" + - /bin/sh + - -c + - | + apk add --no-cache openssl + true | openssl s_client -showcerts -connect gitlab.test:5050 > /usr/local/share/ca-certificates/gitlab.test.crt + update-ca-certificates + dockerd-entrypoint.sh || exit + variables: + IMAGE_TAG: "$CI_REGISTRY_IMAGE:$CI_COMMIT_REF_SLUG" + script: + - docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD gitlab.test:5050 + - docker build -t $IMAGE_TAG . + - docker push $IMAGE_TAG + tags: + - "runner-for-#{project.name}" YAML } ] @@ -234,7 +223,11 @@ module QA pipeline.click_job('build') end - Support::Retrier.retry_until(max_duration: 800, sleep_interval: 10) do + Page::Project::Job::Show.perform do |job| + expect(job).to be_successful(timeout: 200) + end + + Support::Retrier.retry_until(max_duration: 500, sleep_interval: 10) do project.pipelines.last[:status] == 'success' end 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 235c3604523..dae0e17746c 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 @@ -6,13 +6,7 @@ module QA using RSpec::Parameterized::TableSyntax include Support::Helpers::MaskToken - let(:project) do - Resource::Project.fabricate_via_api! do |project| - project.name = 'dependency-proxy-project' - project.visibility = :private - end - end - + let(:project) { create(:project, :private, name: 'dependency-proxy-project') } let!(:runner) do Resource::ProjectRunner.fabricate! do |runner| runner.name = "qa-runner-#{Time.now.to_i}" @@ -35,8 +29,7 @@ module QA let(:personal_access_token) { Runtime::Env.personal_access_token } - let(:uri) { URI.parse(Runtime::Scenario.gitlab_address) } - let(:gitlab_host_with_port) { "#{uri.host}:#{uri.port}" } + let(:gitlab_host_with_port) { Support::GitlabAddress.host_with_port } let(:dependency_proxy_url) { "#{gitlab_host_with_port}/#{project.group.full_path}/dependency_proxy/containers" } let(:image_sha) { 'alpine@sha256:c3d45491770c51da4ef58318e3714da686bc7165338b7ab5ac758e75c7455efb' } 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 8dc9fb6db36..05c6694e69a 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 @@ -10,7 +10,7 @@ module QA } do include Runtime::Fixtures - let(:group) { Resource::Group.fabricate_via_api! } + let(:group) { create(:group) } let(:imported_project) do Resource::ProjectImportedFromURL.fabricate_via_browser_ui! do |project| 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 58eb63de21d..6e52208004f 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,17 +1,11 @@ # frozen_string_literal: true module QA - RSpec.describe 'Package', :object_storage, except: { job: 'relative-url' }, product_group: :package_registry do - describe 'Composer Repository' do + RSpec.describe 'Package', :object_storage, product_group: :package_registry do + describe 'Composer Repository', :external_api_calls do include Runtime::Fixtures - let(:project) do - Resource::Project.fabricate_via_api! do |project| - project.name = 'composer-package-project' - project.visibility = :private - end - end - + let(:project) { create(:project, :privtae, name: 'composer-package-project') } let(:package) do Resource::Package.init do |package| package.name = "my_package-#{SecureRandom.hex(4)}" @@ -28,10 +22,7 @@ module QA end end - let!(:gitlab_address_with_port) do - uri = URI.parse(Runtime::Scenario.gitlab_address) - "#{uri.scheme}://#{uri.host}:#{uri.port}" - end + let(:gitlab_host_with_port) { Support::GitlabAddress.host_with_port } before do Flow::Login.sign_in @@ -71,7 +62,14 @@ module QA package.remove_via_api! end - it 'publishes a composer package and deletes it', testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/348016' do + it( + 'publishes a composer package and deletes it', + testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/348016', + quarantine: { + type: :broken, + issue: "https://gitlab.com/gitlab-org/gitlab/-/issues/421885" + } + ) do Page::Project::Menu.perform(&:go_to_package_registry) Page::Project::Packages::Index.perform do |index| 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 83662e04fab..f2e19068f18 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,21 +1,15 @@ # frozen_string_literal: true module QA - RSpec.describe 'Package', :object_storage, product_group: :package_registry, quarantine: { - only: { job: %w[object_storage relative_url airgapped], condition: -> { QA::Support::FIPS.enabled? } }, + RSpec.describe 'Package', :object_storage, :external_api_calls, product_group: :package_registry, quarantine: { + only: { job: 'object_storage', condition: -> { QA::Support::FIPS.enabled? } }, issue: 'https://gitlab.com/gitlab-org/gitlab/-/issues/417584', type: :bug } do describe 'Conan Repository' do include Runtime::Fixtures - let(:project) do - Resource::Project.fabricate_via_api! do |project| - project.name = 'conan-package-project' - project.visibility = :private - end - end - + let(:project) { create(:project, :private, name: 'conan-package-project') } let(:package) do Resource::Package.init do |package| package.name = "conantest-#{SecureRandom.hex(8)}" @@ -33,8 +27,7 @@ module QA end let(:gitlab_address_with_port) do - uri = URI.parse(Runtime::Scenario.gitlab_address) - "#{uri.scheme}://#{uri.host}:#{uri.port}" + Support::GitlabAddress.address_with_port end after do 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 1253dc91ca3..3c43e97e21e 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,17 +1,11 @@ # frozen_string_literal: true module QA - RSpec.describe 'Package', :object_storage, except: { job: 'relative-url' }, product_group: :package_registry do - describe 'Generic Repository' do + RSpec.describe 'Package', :object_storage, product_group: :package_registry do + describe 'Generic Repository', :external_api_calls do include Runtime::Fixtures - let(:project) do - Resource::Project.fabricate_via_api! do |project| - project.name = 'generic-package-project' - project.visibility = :private - end - end - + let(:project) { create(:project, :private, name: 'generic-package-project') } let(:package) do Resource::Package.init do |package| package.name = "my_package-#{SecureRandom.hex(8)}" 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 7bfda7f5956..42635a9e59f 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 @@ -2,12 +2,7 @@ module QA RSpec.describe 'Package', :object_storage, product_group: :package_registry do - describe 'Helm Registry', - quarantine: { - only: { job: %w[relative_url airgapped] }, - issue: 'https://gitlab.com/gitlab-org/gitlab/-/issues/417590', - type: :investigating - } do + describe 'Helm Registry', :external_api_calls do using RSpec::Parameterized::TableSyntax include Runtime::Fixtures include Support::Helpers::MaskToken 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 ce6c54b6ed8..3cbc78ab806 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 @@ -2,12 +2,7 @@ module QA RSpec.describe 'Package', :object_storage, product_group: :package_registry do - describe 'Maven group level endpoint', - quarantine: { - only: { job: %w[relative_url airgapped] }, - issue: 'https://gitlab.com/gitlab-org/gitlab/-/issues/417600', - type: :investigating - } do + describe 'Maven group level endpoint', :external_api_calls do include Runtime::Fixtures include Support::Helpers::MaskToken include_context 'packages registry qa scenario' 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 35f80f8d447..d1663f075e0 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,7 @@ # frozen_string_literal: true module QA - RSpec.describe 'Package', :object_storage, - quarantine: { - only: { job: %w[relative_url airgapped] }, - issue: 'https://gitlab.com/gitlab-org/gitlab/-/issues/417600', - type: :investigating - } do + RSpec.describe 'Package', :object_storage, :external_api_calls do describe 'Maven project level endpoint', product_group: :package_registry do include Runtime::Fixtures include Support::Helpers::MaskToken @@ -17,15 +12,7 @@ module QA let(:package_version) { '1.3.7' } let(:package_type) { 'maven' } let(:personal_access_token) { Runtime::Env.personal_access_token } - - let(:package_project) do - Resource::Project.fabricate_via_api! do |project| - project.name = "#{package_type}_package_project" - project.initialize_with_readme = true - project.visibility = :private - end - end - + let(:package_project) { create(:project, :with_readme, :private, name: "#{package_type}_package_project") } let(:package) do Resource::Package.init do |package| package.name = package_name @@ -43,8 +30,7 @@ module QA end let(:gitlab_address_with_port) do - uri = URI.parse(Runtime::Scenario.gitlab_address) - "#{uri.scheme}://#{uri.host}:#{uri.port}" + Support::GitlabAddress.address_with_port end let(:project_deploy_token) do 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 f24466ed003..28037391aeb 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,9 +1,9 @@ # frozen_string_literal: true module QA - RSpec.describe 'Package', :object_storage, + RSpec.describe 'Package', :object_storage, :external_api_calls, quarantine: { - only: { job: 'relative_url', condition: -> { QA::Support::FIPS.enabled? } }, + only: { condition: -> { QA::Support::FIPS.enabled? } }, issue: 'https://gitlab.com/gitlab-org/gitlab/-/issues/417600', type: :investigating }, product_group: :package_registry do @@ -17,15 +17,7 @@ module QA let(:package_name) { "#{group_id}/#{artifact_id}".tr('.', '/') } let(:package_version) { '1.3.7' } let(:package_type) { 'maven_gradle' } - - let(:project) do - Resource::Project.fabricate_via_api! do |project| - project.name = "#{package_type}_project" - project.initialize_with_readme = true - project.visibility = :private - end - end - + let(:project) { create(:project, :private, :with_readme, name: "#{package_type}_project") } let(:runner) do Resource::ProjectRunner.fabricate! do |runner| runner.name = "qa-runner-#{Time.now.to_i}" @@ -36,8 +28,7 @@ module QA end let(:gitlab_address_with_port) do - uri = URI.parse(Runtime::Scenario.gitlab_address) - "#{uri.scheme}://#{uri.host}:#{uri.port}" + Support::GitlabAddress.address_with_port end let(:project_deploy_token) do diff --git a/qa/qa/specs/features/browser_ui/5_package/package_registry/npm/npm_group_level_spec.rb b/qa/qa/specs/features/browser_ui/5_package/package_registry/npm/npm_group_level_spec.rb index 1b97f7d0a6a..0550c3373da 100644 --- a/qa/qa/specs/features/browser_ui/5_package/package_registry/npm/npm_group_level_spec.rb +++ b/qa/qa/specs/features/browser_ui/5_package/package_registry/npm/npm_group_level_spec.rb @@ -2,170 +2,156 @@ module QA RSpec.describe 'Package' do - describe 'Package Registry', :object_storage, except: { job: 'relative-url' }, product_group: :package_registry do - describe 'npm group level endpoint' do - using RSpec::Parameterized::TableSyntax - include Runtime::Fixtures - include Support::Helpers::MaskToken + describe 'npm Registry group level endpoint', :object_storage, :external_api_calls, + product_group: :package_registry do + using RSpec::Parameterized::TableSyntax + include Runtime::Fixtures + include Support::Helpers::MaskToken - let!(:registry_scope) { Runtime::Namespace.sandbox_name } - let!(:personal_access_token) do - Flow::Login.sign_in unless Page::Main::Menu.perform(&:signed_in?) + let!(:registry_scope) { Runtime::Namespace.sandbox_name } + let!(:personal_access_token) do + Flow::Login.sign_in unless Page::Main::Menu.perform(&:signed_in?) - Resource::PersonalAccessToken.fabricate!.token - end - - let(:project_deploy_token) do - Resource::ProjectDeployToken.fabricate_via_api! do |deploy_token| - deploy_token.name = 'npm-deploy-token' - deploy_token.project = project - deploy_token.scopes = %w[ - read_repository - read_package_registry - write_package_registry - ] - end - end - - let(:uri) { URI.parse(Runtime::Scenario.gitlab_address) } - let(:gitlab_address_with_port) { "#{uri.scheme}://#{uri.host}:#{uri.port}" } - let(:gitlab_host_with_port) { "#{uri.host}:#{uri.port}" } + Resource::PersonalAccessToken.fabricate!.token + end - let!(:project) do - Resource::Project.fabricate_via_api! do |project| - project.name = 'npm-group-level-publish' - end + let(:project_deploy_token) do + Resource::ProjectDeployToken.fabricate_via_api! do |deploy_token| + deploy_token.name = 'npm-deploy-token' + deploy_token.project = project + deploy_token.scopes = %w[ + read_repository + read_package_registry + write_package_registry + ] end + end - let!(:another_project) do - Resource::Project.fabricate_via_api! do |another_project| - another_project.name = 'npm-group-level-install' - another_project.group = project.group - end + let(:gitlab_address_without_port) { Support::GitlabAddress.address_with_port(with_default_port: false) } + let(:gitlab_host_without_port) { Support::GitlabAddress.host_with_port(with_default_port: false) } + let!(:project) { create(:project, name: 'npm-group-level-publish') } + let!(:another_project) { create(:project, name: 'npm-group-level-install', group: project.group) } + let!(:runner) do + Resource::GroupRunner.fabricate! do |runner| + runner.name = "qa-runner-#{Time.now.to_i}" + runner.tags = ["runner-for-#{project.group.name}"] + runner.executor = :docker + runner.group = project.group end + end - let!(:runner) do - Resource::GroupRunner.fabricate! do |runner| - runner.name = "qa-runner-#{Time.now.to_i}" - runner.tags = ["runner-for-#{project.group.name}"] - runner.executor = :docker - runner.group = project.group - end + let(:package) do + Resource::Package.init do |package| + package.name = "@#{registry_scope}/#{project.name}-#{SecureRandom.hex(8)}" + package.project = project end + end - let(:package) do - Resource::Package.init do |package| - package.name = "@#{registry_scope}/#{project.name}-#{SecureRandom.hex(8)}" - package.project = project - end - end + after do + package.remove_via_api! + runner.remove_via_api! + project.remove_via_api! + another_project.remove_via_api! + end - after do - package.remove_via_api! - runner.remove_via_api! - project.remove_via_api! - another_project.remove_via_api! - end + where(:case_name, :authentication_token_type, :token_name, :testcase) do + 'using personal access token' | :personal_access_token | 'Personal Access Token' | 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/413760' + 'using ci job token' | :ci_job_token | 'CI Job Token' | 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/413761' + 'using project deploy token' | :project_deploy_token | 'Deploy Token' | 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/413762' + end - where(:case_name, :authentication_token_type, :token_name, :testcase) do - 'using personal access token' | :personal_access_token | 'Personal Access Token' | 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/413760' - 'using ci job token' | :ci_job_token | 'CI Job Token' | 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/413761' - 'using project deploy token' | :project_deploy_token | 'Deploy Token' | 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/413762' + with_them do + let(:auth_token) do + case authentication_token_type + when :personal_access_token + use_ci_variable(name: 'PERSONAL_ACCESS_TOKEN', value: personal_access_token, project: project) + use_ci_variable(name: 'PERSONAL_ACCESS_TOKEN', value: personal_access_token, project: another_project) + when :ci_job_token + '${CI_JOB_TOKEN}' + when :project_deploy_token + use_ci_variable(name: 'PROJECT_DEPLOY_TOKEN', value: project_deploy_token.token, project: project) + use_ci_variable(name: 'PROJECT_DEPLOY_TOKEN', value: project_deploy_token.token, project: another_project) + end end - with_them do - let(:auth_token) do - case authentication_token_type - when :personal_access_token - use_ci_variable(name: 'PERSONAL_ACCESS_TOKEN', value: personal_access_token, project: project) - use_ci_variable(name: 'PERSONAL_ACCESS_TOKEN', value: personal_access_token, project: another_project) - when :ci_job_token - '${CI_JOB_TOKEN}' - when :project_deploy_token - use_ci_variable(name: 'PROJECT_DEPLOY_TOKEN', value: project_deploy_token.token, project: project) - use_ci_variable(name: 'PROJECT_DEPLOY_TOKEN', value: project_deploy_token.token, project: another_project) + it 'push and pull a npm package via CI', testcase: params[:testcase] do + Support::Retrier.retry_on_exception(max_attempts: 3, sleep_interval: 2) do + npm_upload_yaml = ERB.new(read_fixture('package_managers/npm', + 'npm_upload_package_group.yaml.erb')).result(binding) + package_json = ERB.new(read_fixture('package_managers/npm', 'package.json.erb')).result(binding) + + Resource::Repository::Commit.fabricate_via_api! do |commit| + commit.project = project + commit.commit_message = 'Add files' + commit.add_files([ + { + file_path: '.gitlab-ci.yml', + content: npm_upload_yaml + }, + { + file_path: 'package.json', + content: package_json + } + ]) end end - it 'push and pull a npm package via CI', testcase: params[:testcase] do - Support::Retrier.retry_on_exception(max_attempts: 3, sleep_interval: 2) do - npm_upload_yaml = ERB.new(read_fixture('package_managers/npm', - 'npm_upload_package_group.yaml.erb')).result(binding) - package_json = ERB.new(read_fixture('package_managers/npm', 'package.json.erb')).result(binding) - - Resource::Repository::Commit.fabricate_via_api! do |commit| - commit.project = project - commit.commit_message = 'Add files' - commit.add_files([ - { - file_path: '.gitlab-ci.yml', - content: npm_upload_yaml - }, - { - file_path: 'package.json', - content: package_json - } - ]) - end - end - - project.visit! - Flow::Pipeline.visit_latest_pipeline + project.visit! + Flow::Pipeline.visit_latest_pipeline - Page::Project::Pipeline::Show.perform do |pipeline| - pipeline.click_job('deploy') - end + Page::Project::Pipeline::Show.perform do |pipeline| + pipeline.click_job('deploy') + end - Page::Project::Job::Show.perform do |job| - expect(job).to be_successful(timeout: 800) - end + Page::Project::Job::Show.perform do |job| + expect(job).to be_successful(timeout: 800) + end - Support::Retrier.retry_on_exception(max_attempts: 3, sleep_interval: 2) do - Resource::Repository::Commit.fabricate_via_api! do |commit| - npm_install_yaml = ERB.new(read_fixture('package_managers/npm', - 'npm_install_package_group.yaml.erb')).result(binding) - - commit.project = another_project - commit.commit_message = 'Add .gitlab-ci.yml' - commit.add_files([ - { - file_path: '.gitlab-ci.yml', - content: npm_install_yaml - } - ]) - end + Support::Retrier.retry_on_exception(max_attempts: 3, sleep_interval: 2) do + Resource::Repository::Commit.fabricate_via_api! do |commit| + npm_install_yaml = ERB.new(read_fixture('package_managers/npm', + 'npm_install_package_group.yaml.erb')).result(binding) + + commit.project = another_project + commit.commit_message = 'Add .gitlab-ci.yml' + commit.add_files([ + { + file_path: '.gitlab-ci.yml', + content: npm_install_yaml + } + ]) end + end - another_project.visit! - Flow::Pipeline.visit_latest_pipeline + another_project.visit! + Flow::Pipeline.visit_latest_pipeline - Page::Project::Pipeline::Show.perform do |pipeline| - pipeline.click_job('install') - end + Page::Project::Pipeline::Show.perform do |pipeline| + pipeline.click_job('install') + end - Page::Project::Job::Show.perform do |job| - expect(job).to be_successful(timeout: 800) - job.click_browse_button - end + Page::Project::Job::Show.perform do |job| + expect(job).to be_successful(timeout: 800) + job.click_browse_button + end - Page::Project::Artifact::Show.perform do |artifacts| - artifacts.go_to_directory('node_modules') - artifacts.go_to_directory("@#{registry_scope}") - expect(artifacts).to have_content(project.name.to_s) - end + Page::Project::Artifact::Show.perform do |artifacts| + artifacts.go_to_directory('node_modules') + artifacts.go_to_directory("@#{registry_scope}") + expect(artifacts).to have_content(project.name.to_s) + end - project.visit! - Page::Project::Menu.perform(&:go_to_package_registry) + project.visit! + Page::Project::Menu.perform(&:go_to_package_registry) - Page::Project::Packages::Index.perform do |index| - expect(index).to have_package(package.name) + Page::Project::Packages::Index.perform do |index| + expect(index).to have_package(package.name) - index.click_package(package.name) - end + index.click_package(package.name) + end - Page::Project::Packages::Show.perform do |show| - expect(show).to have_package_info(package.name, "1.0.0") - end + Page::Project::Packages::Show.perform do |show| + expect(show).to have_package_info(package.name, "1.0.0") end end end diff --git a/qa/qa/specs/features/browser_ui/5_package/package_registry/npm/npm_instance_level_spec.rb b/qa/qa/specs/features/browser_ui/5_package/package_registry/npm/npm_instance_level_spec.rb index b0702b3f089..f8e526a01b0 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,168 +2,154 @@ module QA RSpec.describe 'Package' do - describe 'Package Registry', :object_storage, except: { job: 'relative-url' }, product_group: :package_registry do - describe 'npm instance level endpoint' do - using RSpec::Parameterized::TableSyntax - include Runtime::Fixtures - include Support::Helpers::MaskToken + describe 'npm Registry instance level endpoint', :object_storage, :external_api_calls, + product_group: :package_registry do + using RSpec::Parameterized::TableSyntax + include Runtime::Fixtures + include Support::Helpers::MaskToken - let!(:registry_scope) { Runtime::Namespace.sandbox_name } - let!(:personal_access_token) do - Flow::Login.sign_in unless Page::Main::Menu.perform(&:signed_in?) + let!(:registry_scope) { Runtime::Namespace.sandbox_name } + let!(:personal_access_token) do + Flow::Login.sign_in unless Page::Main::Menu.perform(&:signed_in?) - Resource::PersonalAccessToken.fabricate!.token - end - - let(:project_deploy_token) do - Resource::ProjectDeployToken.fabricate_via_api! do |deploy_token| - deploy_token.name = 'npm-deploy-token' - deploy_token.project = project - deploy_token.scopes = %w[ - read_repository - read_package_registry - write_package_registry - ] - end - end - - let(:uri) { URI.parse(Runtime::Scenario.gitlab_address) } - let(:gitlab_address_with_port) { "#{uri.scheme}://#{uri.host}:#{uri.port}" } - let(:gitlab_host_with_port) { "#{uri.host}:#{uri.port}" } + Resource::PersonalAccessToken.fabricate!.token + end - let!(:project) do - Resource::Project.fabricate_via_api! do |project| - project.name = 'npm-instace-level-publish' - end + let(:project_deploy_token) do + Resource::ProjectDeployToken.fabricate_via_api! do |deploy_token| + deploy_token.name = 'npm-deploy-token' + deploy_token.project = project + deploy_token.scopes = %w[ + read_repository + read_package_registry + write_package_registry + ] end + end - let!(:another_project) do - Resource::Project.fabricate_via_api! do |another_project| - another_project.name = 'npm-instance-level-install' - another_project.group = project.group - end + let(:gitlab_address_without_port) { Support::GitlabAddress.address_with_port(with_default_port: false) } + let(:gitlab_host_without_port) { Support::GitlabAddress.host_with_port(with_default_port: false) } + let!(:project) { create(:project, name: 'npm-instance-level-publish') } + let!(:another_project) { create(:project, name: 'npm-instance-level-install', group: project.group) } + let!(:runner) do + Resource::GroupRunner.fabricate! do |runner| + runner.name = "qa-runner-#{Time.now.to_i}" + runner.tags = ["runner-for-#{project.group.name}"] + runner.executor = :docker + runner.group = project.group end + end - let!(:runner) do - Resource::GroupRunner.fabricate! do |runner| - runner.name = "qa-runner-#{Time.now.to_i}" - runner.tags = ["runner-for-#{project.group.name}"] - runner.executor = :docker - runner.group = project.group - end + let(:package) do + Resource::Package.init do |package| + package.name = "@#{registry_scope}/#{project.name}-#{SecureRandom.hex(8)}" + package.project = project end + end - let(:package) do - Resource::Package.init do |package| - package.name = "@#{registry_scope}/#{project.name}-#{SecureRandom.hex(8)}" - package.project = project - end - end + after do + package.remove_via_api! + runner.remove_via_api! + project.remove_via_api! + another_project.remove_via_api! + end - after do - package.remove_via_api! - runner.remove_via_api! - project.remove_via_api! - another_project.remove_via_api! - end + where(:case_name, :authentication_token_type, :token_name, :testcase) do + 'using personal access token' | :personal_access_token | 'Personal Access Token' | 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347600' + 'using ci job token' | :ci_job_token | 'CI Job Token' | 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347599' + 'using project deploy token' | :project_deploy_token | 'Deploy Token' | 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347598' + end - where(:case_name, :authentication_token_type, :token_name, :testcase) do - 'using personal access token' | :personal_access_token | 'Personal Access Token' | 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347600' - 'using ci job token' | :ci_job_token | 'CI Job Token' | 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347599' - 'using project deploy token' | :project_deploy_token | 'Deploy Token' | 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347598' + with_them do + let(:auth_token) do + case authentication_token_type + when :personal_access_token + use_ci_variable(name: 'PERSONAL_ACCESS_TOKEN', value: personal_access_token, project: project) + use_ci_variable(name: 'PERSONAL_ACCESS_TOKEN', value: personal_access_token, project: another_project) + when :ci_job_token + '${CI_JOB_TOKEN}' + when :project_deploy_token + use_ci_variable(name: 'PROJECT_DEPLOY_TOKEN', value: project_deploy_token.token, project: project) + use_ci_variable(name: 'PROJECT_DEPLOY_TOKEN', value: project_deploy_token.token, project: another_project) + end end - with_them do - let(:auth_token) do - case authentication_token_type - when :personal_access_token - use_ci_variable(name: 'PERSONAL_ACCESS_TOKEN', value: personal_access_token, project: project) - use_ci_variable(name: 'PERSONAL_ACCESS_TOKEN', value: personal_access_token, project: another_project) - when :ci_job_token - '${CI_JOB_TOKEN}' - when :project_deploy_token - use_ci_variable(name: 'PROJECT_DEPLOY_TOKEN', value: project_deploy_token.token, project: project) - use_ci_variable(name: 'PROJECT_DEPLOY_TOKEN', value: project_deploy_token.token, project: another_project) + it 'push and pull a npm package via CI', testcase: params[:testcase] do + Support::Retrier.retry_on_exception(max_attempts: 3, sleep_interval: 2) do + npm_upload_yaml = ERB.new(read_fixture('package_managers/npm', 'npm_upload_package_instance.yaml.erb')).result(binding) + package_json = ERB.new(read_fixture('package_managers/npm', 'package.json.erb')).result(binding) + + Resource::Repository::Commit.fabricate_via_api! do |commit| + commit.project = project + commit.commit_message = 'Add files' + commit.add_files([ + { + file_path: '.gitlab-ci.yml', + content: npm_upload_yaml + }, + { + file_path: 'package.json', + content: package_json + } + ]) end end - it 'push and pull a npm package via CI', testcase: params[:testcase] do - Support::Retrier.retry_on_exception(max_attempts: 3, sleep_interval: 2) do - npm_upload_yaml = ERB.new(read_fixture('package_managers/npm', 'npm_upload_package_instance.yaml.erb')).result(binding) - package_json = ERB.new(read_fixture('package_managers/npm', 'package.json.erb')).result(binding) - - Resource::Repository::Commit.fabricate_via_api! do |commit| - commit.project = project - commit.commit_message = 'Add files' - commit.add_files([ - { - file_path: '.gitlab-ci.yml', - content: npm_upload_yaml - }, - { - file_path: 'package.json', - content: package_json - } - ]) - end - end - - project.visit! - Flow::Pipeline.visit_latest_pipeline + project.visit! + Flow::Pipeline.visit_latest_pipeline - Page::Project::Pipeline::Show.perform do |pipeline| - pipeline.click_job('deploy') - end + Page::Project::Pipeline::Show.perform do |pipeline| + pipeline.click_job('deploy') + end - Page::Project::Job::Show.perform do |job| - expect(job).to be_successful(timeout: 800) - end + Page::Project::Job::Show.perform do |job| + expect(job).to be_successful(timeout: 800) + end - Support::Retrier.retry_on_exception(max_attempts: 3, sleep_interval: 2) do - Resource::Repository::Commit.fabricate_via_api! do |commit| - npm_install_yaml = ERB.new(read_fixture('package_managers/npm', 'npm_install_package_instance.yaml.erb')).result(binding) - - commit.project = another_project - commit.commit_message = 'Add .gitlab-ci.yml' - commit.add_files([ - { - file_path: '.gitlab-ci.yml', - content: npm_install_yaml - } - ]) - end + Support::Retrier.retry_on_exception(max_attempts: 3, sleep_interval: 2) do + Resource::Repository::Commit.fabricate_via_api! do |commit| + npm_install_yaml = ERB.new(read_fixture('package_managers/npm', 'npm_install_package_instance.yaml.erb')).result(binding) + + commit.project = another_project + commit.commit_message = 'Add .gitlab-ci.yml' + commit.add_files([ + { + file_path: '.gitlab-ci.yml', + content: npm_install_yaml + } + ]) end + end - another_project.visit! - Flow::Pipeline.visit_latest_pipeline + another_project.visit! + Flow::Pipeline.visit_latest_pipeline - Page::Project::Pipeline::Show.perform do |pipeline| - pipeline.click_job('install') - end + Page::Project::Pipeline::Show.perform do |pipeline| + pipeline.click_job('install') + end - Page::Project::Job::Show.perform do |job| - expect(job).to be_successful(timeout: 800) - job.click_browse_button - end + Page::Project::Job::Show.perform do |job| + expect(job).to be_successful(timeout: 800) + job.click_browse_button + end - Page::Project::Artifact::Show.perform do |artifacts| - artifacts.go_to_directory('node_modules') - artifacts.go_to_directory("@#{registry_scope}") - expect(artifacts).to have_content(project.name.to_s) - end + Page::Project::Artifact::Show.perform do |artifacts| + artifacts.go_to_directory('node_modules') + artifacts.go_to_directory("@#{registry_scope}") + expect(artifacts).to have_content(project.name.to_s) + end - project.visit! - Page::Project::Menu.perform(&:go_to_package_registry) + project.visit! + Page::Project::Menu.perform(&:go_to_package_registry) - Page::Project::Packages::Index.perform do |index| - expect(index).to have_package(package.name) + Page::Project::Packages::Index.perform do |index| + expect(index).to have_package(package.name) - index.click_package(package.name) - end + index.click_package(package.name) + end - Page::Project::Packages::Show.perform do |show| - expect(show).to have_package_info(package.name, "1.0.0") - end + Page::Project::Packages::Show.perform do |show| + expect(show).to have_package_info(package.name, "1.0.0") end end end 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 1eed68d1b88..11df6dcb303 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,141 +2,132 @@ module QA RSpec.describe 'Package' do - describe 'Package Registry', :object_storage, except: { job: 'relative-url' }, product_group: :package_registry do - describe 'npm project level endpoint' do - using RSpec::Parameterized::TableSyntax - include Runtime::Fixtures - include Support::Helpers::MaskToken + describe 'npm Registry project level endpoint', :object_storage, :external_api_calls, + product_group: :package_registry do + using RSpec::Parameterized::TableSyntax + include Runtime::Fixtures + include Support::Helpers::MaskToken - let!(:registry_scope) { Runtime::Namespace.sandbox_name } - let!(:personal_access_token) do - Flow::Login.sign_in unless Page::Main::Menu.perform(&:signed_in?) + let!(:registry_scope) { Runtime::Namespace.sandbox_name } + let!(:personal_access_token) do + Flow::Login.sign_in unless Page::Main::Menu.perform(&:signed_in?) - Resource::PersonalAccessToken.fabricate!.token + Resource::PersonalAccessToken.fabricate!.token + end + + let(:project_deploy_token) do + Resource::ProjectDeployToken.fabricate_via_api! do |deploy_token| + deploy_token.name = 'npm-deploy-token' + deploy_token.project = project + deploy_token.scopes = %w[ + read_repository + read_package_registry + write_package_registry + ] end + end - let(:project_deploy_token) do - Resource::ProjectDeployToken.fabricate_via_api! do |deploy_token| - deploy_token.name = 'npm-deploy-token' - deploy_token.project = project - deploy_token.scopes = %w[ - read_repository - read_package_registry - write_package_registry - ] - end + let(:gitlab_address_without_port) { Support::GitlabAddress.address_with_port(with_default_port: false) } + let(:gitlab_host_without_port) { Support::GitlabAddress.host_with_port(with_default_port: false) } + let!(:project) { create(:project, :private, name: 'npm-project-level') } + let!(:runner) do + Resource::ProjectRunner.fabricate! do |runner| + runner.name = "qa-runner-#{Time.now.to_i}" + runner.tags = ["runner-for-#{project.name}"] + runner.executor = :docker + runner.project = project end + end - let(:uri) { URI.parse(Runtime::Scenario.gitlab_address) } - let(:gitlab_address_with_port) { "#{uri.scheme}://#{uri.host}:#{uri.port}" } - let(:gitlab_host_with_port) { "#{uri.host}:#{uri.port}" } + let(:package) do + Resource::Package.init do |package| + package.name = "@#{registry_scope}/mypackage-#{SecureRandom.hex(8)}" + package.project = project + end + end - let!(:project) do - Resource::Project.fabricate_via_api! do |project| - project.name = 'npm-project-level' - project.visibility = :private + after do + package.remove_via_api! + runner.remove_via_api! + project.remove_via_api! + end + + where(:case_name, :authentication_token_type, :token_name, :testcase) do + 'using personal access token' | :personal_access_token | 'Personal Access Token' | 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347592' + 'using ci job token' | :ci_job_token | 'CI Job Token' | 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347594' + 'using project deploy token' | :project_deploy_token | 'Deploy Token' | 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347593' + end + + with_them do + let(:auth_token) do + case authentication_token_type + when :personal_access_token + use_ci_variable(name: 'PERSONAL_ACCESS_TOKEN', value: personal_access_token, project: project) + when :ci_job_token + '${CI_JOB_TOKEN}' + when :project_deploy_token + use_ci_variable(name: 'PROJECT_DEPLOY_TOKEN', value: project_deploy_token.token, project: project) end end - let!(:runner) do - Resource::ProjectRunner.fabricate! do |runner| - runner.name = "qa-runner-#{Time.now.to_i}" - runner.tags = ["runner-for-#{project.name}"] - runner.executor = :docker - runner.project = project + it 'push and pull a npm package via CI', testcase: params[:testcase] do + Resource::Repository::Commit.fabricate_via_api! do |commit| + npm_upload_install_yaml = ERB.new(read_fixture('package_managers/npm', 'npm_upload_install_package_project.yaml.erb')).result(binding) + package_json = ERB.new(read_fixture('package_managers/npm', 'package.json.erb')).result(binding) + + commit.project = project + commit.commit_message = 'Add .gitlab-ci.yml' + commit.add_files([ + { + file_path: '.gitlab-ci.yml', + content: npm_upload_install_yaml + }, + { + file_path: 'package.json', + content: package_json + } + ]) end - end - let(:package) do - Resource::Package.init do |package| - package.name = "@#{registry_scope}/mypackage-#{SecureRandom.hex(8)}" - package.project = project + project.visit! + Flow::Pipeline.visit_latest_pipeline + + Page::Project::Pipeline::Show.perform do |pipeline| + pipeline.click_job('deploy') end - end - after do - package.remove_via_api! - runner.remove_via_api! - project.remove_via_api! - end + Page::Project::Job::Show.perform do |job| + expect(job).to be_successful(timeout: 800) + end - where(:case_name, :authentication_token_type, :token_name, :testcase) do - 'using personal access token' | :personal_access_token | 'Personal Access Token' | 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347592' - 'using ci job token' | :ci_job_token | 'CI Job Token' | 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347594' - 'using project deploy token' | :project_deploy_token | 'Deploy Token' | 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347593' - end + Flow::Pipeline.visit_latest_pipeline + + Page::Project::Pipeline::Show.perform do |pipeline| + pipeline.click_job('install') + end + + Page::Project::Job::Show.perform do |job| + expect(job).to be_successful(timeout: 800) + job.click_browse_button + end + + Page::Project::Artifact::Show.perform do |artifacts| + artifacts.go_to_directory('node_modules') + artifacts.go_to_directory("@#{registry_scope}") + expect(artifacts).to have_content('mypackage') + end + + project.visit! + Page::Project::Menu.perform(&:go_to_package_registry) + + Page::Project::Packages::Index.perform do |index| + expect(index).to have_package(package.name) - with_them do - let(:auth_token) do - case authentication_token_type - when :personal_access_token - use_ci_variable(name: 'PERSONAL_ACCESS_TOKEN', value: personal_access_token, project: project) - when :ci_job_token - '${CI_JOB_TOKEN}' - when :project_deploy_token - use_ci_variable(name: 'PROJECT_DEPLOY_TOKEN', value: project_deploy_token.token, project: project) - end + index.click_package(package.name) end - it 'push and pull a npm package via CI', testcase: params[:testcase] do - Resource::Repository::Commit.fabricate_via_api! do |commit| - npm_upload_install_yaml = ERB.new(read_fixture('package_managers/npm', 'npm_upload_install_package_project.yaml.erb')).result(binding) - package_json = ERB.new(read_fixture('package_managers/npm', 'package.json.erb')).result(binding) - - commit.project = project - commit.commit_message = 'Add .gitlab-ci.yml' - commit.add_files([ - { - file_path: '.gitlab-ci.yml', - content: npm_upload_install_yaml - }, - { - file_path: 'package.json', - content: package_json - } - ]) - end - - project.visit! - Flow::Pipeline.visit_latest_pipeline - - Page::Project::Pipeline::Show.perform do |pipeline| - pipeline.click_job('deploy') - end - - Page::Project::Job::Show.perform do |job| - expect(job).to be_successful(timeout: 800) - end - - Flow::Pipeline.visit_latest_pipeline - - Page::Project::Pipeline::Show.perform do |pipeline| - pipeline.click_job('install') - end - - Page::Project::Job::Show.perform do |job| - expect(job).to be_successful(timeout: 800) - job.click_browse_button - end - - Page::Project::Artifact::Show.perform do |artifacts| - artifacts.go_to_directory('node_modules') - artifacts.go_to_directory("@#{registry_scope}") - expect(artifacts).to have_content('mypackage') - end - - project.visit! - Page::Project::Menu.perform(&:go_to_package_registry) - - Page::Project::Packages::Index.perform do |index| - expect(index).to have_package(package.name) - - index.click_package(package.name) - end - - Page::Project::Packages::Show.perform do |show| - expect(show).to have_package_info(package.name, "1.0.0") - end + Page::Project::Packages::Show.perform do |show| + expect(show).to have_package_info(package.name, "1.0.0") end end end 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 5413ae85dcd..04e020178ee 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,20 +1,13 @@ # frozen_string_literal: true module QA - RSpec.describe 'Package', :object_storage, except: { job: 'relative-url' }, product_group: :package_registry do - describe 'NuGet group level endpoint' do + RSpec.describe 'Package', :object_storage, product_group: :package_registry do + describe 'NuGet group level endpoint', :external_api_calls do using RSpec::Parameterized::TableSyntax include Runtime::Fixtures include Support::Helpers::MaskToken - let(:project) do - Resource::Project.fabricate_via_api! do |project| - project.name = 'nuget-package-project' - project.template_name = 'dotnetcore' - project.visibility = :private - end - end - + let(:project) { create(:project, :private, name: 'nuget-package-project', template_name: 'dotnetcore') } let(:personal_access_token) do unless Page::Main::Menu.perform(&:signed_in?) Flow::Login.sign_in @@ -42,14 +35,7 @@ module QA end end - let(:another_project) do - Resource::Project.fabricate_via_api! do |another_project| - another_project.name = 'nuget-package-install-project' - another_project.template_name = 'dotnetcore' - another_project.group = project.group - end - end - + let(:another_project) { create(:project, name: 'nuget-package-install-project', template_name: 'dotnetcore', group: project.group) } let(:package_project_inbound_job_token_disabled) do Resource::CICDSettings.fabricate_via_api! do |settings| settings.project_path = project.full_path 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 9a192bc005f..b4cac8af1dc 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,20 +1,12 @@ # frozen_string_literal: true module QA - RSpec.describe 'Package', :object_storage, except: { job: 'relative-url' }, product_group: :package_registry do - describe 'NuGet project level endpoint' do + RSpec.describe 'Package', :object_storage, product_group: :package_registry do + describe 'NuGet project level endpoint', :external_api_calls do include Support::Helpers::MaskToken - let(:project) do - Resource::Project.fabricate_via_api! do |project| - project.name = 'nuget-package-project' - project.template_name = 'dotnetcore' - project.visibility = :private - end - end - + let(:project) { create(:project, :private, name: 'nuget-package-project', template_name: 'dotnetcore') } let(:personal_access_token) { Resource::PersonalAccessToken.fabricate! } - let(:project_deploy_token) do Resource::ProjectDeployToken.fabricate_via_api! do |deploy_token| deploy_token.name = 'package-deploy-token' 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 7e2885d3724..80439501299 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 @@ -2,22 +2,11 @@ module QA RSpec.describe 'Package', :object_storage, product_group: :package_registry do - describe 'PyPI Repository', - quarantine: { - only: { job: %w[relative_url airgapped] }, - issue: 'https://gitlab.com/gitlab-org/gitlab/-/issues/417592', - type: :investigating - } do + describe 'PyPI Repository', :external_api_calls do include Runtime::Fixtures include Support::Helpers::MaskToken - let(:project) do - Resource::Project.fabricate_via_api! do |project| - project.name = 'pypi-package-project' - project.visibility = :private - end - end - + let(:project) { create(:project, :private, name: 'pypi-package-project') } let(:package) do Resource::Package.init do |package| package.name = "mypypipackage-#{SecureRandom.hex(8)}" @@ -40,15 +29,8 @@ module QA use_ci_variable(name: 'PERSONAL_ACCESS_TOKEN', value: Runtime::Env.personal_access_token, project: project) end - let(:gitlab_address_with_port) { "#{uri.scheme}://#{uri.host}:#{uri.port}" } - let(:gitlab_host_with_port) do - # Don't specify port if it is a standard one - if uri.port == 80 || uri.port == 443 - uri.host - else - "#{uri.host}:#{uri.port}" - end - end + let(:gitlab_address_with_port) { Support::GitlabAddress.address_with_port } + let(:gitlab_host_with_port) { Support::GitlabAddress.host_with_port(with_default_port: false) } before do Flow::Login.sign_in 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 0c58d41d96e..c77bb9b1b4b 100644 --- a/qa/qa/specs/features/browser_ui/5_package/package_registry/rubygems_registry_spec.rb +++ b/qa/qa/specs/features/browser_ui/5_package/package_registry/rubygems_registry_spec.rb @@ -1,18 +1,12 @@ # frozen_string_literal: true module QA - RSpec.describe 'Package', :object_storage, except: { job: 'relative-url' }, + RSpec.describe 'Package', :object_storage, :external_api_calls, feature_flag: { name: 'rubygem_packages', scope: :project } do describe 'RubyGems Repository', product_group: :package_registry do include Runtime::Fixtures - let(:project) do - Resource::Project.fabricate_via_api! do |project| - project.name = 'rubygems-package-project' - project.visibility = :private - end - end - + let(:project) { create(:project, :private, name: 'rubygems-package-project') } let(:package) do Resource::Package.init do |package| package.name = "mygem-#{SecureRandom.hex(8)}" @@ -30,8 +24,7 @@ module QA end let(:gitlab_address_with_port) do - uri = URI.parse(Runtime::Scenario.gitlab_address) - "#{uri.scheme}://#{uri.host}:#{uri.port}" + Support::GitlabAddress.address_with_port end before do diff --git a/qa/qa/specs/features/browser_ui/6_release/deploy_key/clone_using_deploy_key_spec.rb b/qa/qa/specs/features/browser_ui/6_release/deploy_key/clone_using_deploy_key_spec.rb index 51006dd1e38..d9a1f1cd4a6 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 @@ -7,13 +7,7 @@ module QA describe 'Git clone using a deploy key' do let(:runner_name) { "qa-runner-#{SecureRandom.hex(4)}" } let(:repository_location) { project.repository_ssh_location } - - let(:project) do - Resource::Project.fabricate_via_api! do |project| - project.name = 'deploy-key-clone-project' - end - end - + let(:project) { create(:project, name: 'deploy-key-clone-project') } let!(:runner) do Resource::ProjectRunner.fabricate_via_api! do |resource| resource.project = project 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 42a64099a3d..7e941a135f1 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 @@ -25,12 +25,11 @@ module QA with_them do let!(:project) do - Resource::Project.fabricate_via_api! do |project| - project.name = "#{template}-autodevops-project-template" - project.template_name = template - project.description = "Let's see if the #{template} project works..." - project.auto_devops_enabled = true - end + create(:project, + :auto_devops, + name: "#{template}-autodevops-project-template", + template_name: template, + description: "Let's see if the #{template} project works") end let(:pipeline) do 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 0a9f30f0529..8ee77f5c054 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 @@ -4,16 +4,8 @@ module QA RSpec.describe 'Configure', only: { pipeline: %i[staging staging-canary canary production] }, product_group: :configure do describe 'Auto DevOps with a Kubernetes Agent' do - let!(:app_project) do - Resource::Project.fabricate_via_api! do |project| - project.name = 'autodevops-app-project' - project.template_name = 'express' - project.auto_devops_enabled = true - end - end - + let!(:app_project) { create(:project, :auto_devops, name: 'autodevops-app-project', template_name: 'express') } let!(:cluster) { Service::KubernetesCluster.new(provider_class: Service::ClusterProvider::Gcloud).create! } - let!(:kubernetes_agent) do Resource::Clusters::Agent.fabricate_via_api! do |agent| agent.name = 'agent1' @@ -28,7 +20,7 @@ module QA end before do - cluster.install_kubernetes_agent(agent_token.token) + cluster.install_kubernetes_agent(agent_token.token, kubernetes_agent.name) upload_agent_config(app_project, kubernetes_agent.name) set_kube_ingress_base_domain(app_project) diff --git a/qa/qa/specs/features/browser_ui/8_monitor/alert_management/alert_settings_create_new_alerts_spec.rb b/qa/qa/specs/features/browser_ui/8_monitor/alert_management/alert_settings_create_new_alerts_spec.rb index b44020ddfce..79739006928 100644 --- a/qa/qa/specs/features/browser_ui/8_monitor/alert_management/alert_settings_create_new_alerts_spec.rb +++ b/qa/qa/specs/features/browser_ui/8_monitor/alert_management/alert_settings_create_new_alerts_spec.rb @@ -12,13 +12,7 @@ module QA end end - let(:project) do - Resource::Project.fabricate_via_api! do |project| - project.name = 'project-for-alerts' - project.description = 'Project for alerts' - end - end - + let(:project) { create(:project, name: 'project-for-alerts', description: 'Project for alerts') } let(:alert_title) { Faker::Lorem.word } before do diff --git a/qa/qa/specs/features/browser_ui/8_monitor/alert_management/automatically_creates_incident_for_alert_spec.rb b/qa/qa/specs/features/browser_ui/8_monitor/alert_management/automatically_creates_incident_for_alert_spec.rb index 565f56b90ec..dff130a5793 100644 --- a/qa/qa/specs/features/browser_ui/8_monitor/alert_management/automatically_creates_incident_for_alert_spec.rb +++ b/qa/qa/specs/features/browser_ui/8_monitor/alert_management/automatically_creates_incident_for_alert_spec.rb @@ -12,12 +12,7 @@ module QA end end - let(:project) do - Resource::Project.fabricate_via_api! do |project| - project.name = 'project-for-alerts' - project.description = 'Project for alerts' - end - end + let(:project) { create(:project, name: 'project-for-alerts', description: 'Project for alerts') } before do Flow::Login.sign_in diff --git a/qa/qa/specs/features/browser_ui/8_monitor/alert_management/create_alert_using_authorization_key_spec.rb b/qa/qa/specs/features/browser_ui/8_monitor/alert_management/create_alert_using_authorization_key_spec.rb index 96db10c1683..dfc41fdad85 100644 --- a/qa/qa/specs/features/browser_ui/8_monitor/alert_management/create_alert_using_authorization_key_spec.rb +++ b/qa/qa/specs/features/browser_ui/8_monitor/alert_management/create_alert_using_authorization_key_spec.rb @@ -28,15 +28,8 @@ module QA end end - let(:project) do - Resource::Project.fabricate_via_api! do |project| - project.name = 'project-for-alerts' - project.description = 'Project for alerts' - end - end - + let(:project) { create(:project, name: 'project-for-alerts', description: 'Project for alerts') } let(:alert_title) { Faker::Lorem.word } - let(:credentials) do Flow::AlertSettings.integration_credentials end diff --git a/qa/qa/specs/features/browser_ui/8_monitor/alert_management/email_notification_for_alert_spec.rb b/qa/qa/specs/features/browser_ui/8_monitor/alert_management/email_notification_for_alert_spec.rb index 008d8f808b3..85aa12062d5 100644 --- a/qa/qa/specs/features/browser_ui/8_monitor/alert_management/email_notification_for_alert_spec.rb +++ b/qa/qa/specs/features/browser_ui/8_monitor/alert_management/email_notification_for_alert_spec.rb @@ -19,13 +19,7 @@ module QA end end - let(:project) do - Resource::Project.fabricate_via_api! do |project| - project.name = 'project-for-alerts' - project.description = 'Project for alerts' - end - end - + let(:project) { create(:project, name: 'project-for-alerts', description: 'Project for alerts') } let(:alert_title) { Faker::Lorem.word } let(:mail_hog_api) { Vendor::MailHog::API.new } let(:alert_email_subject) { "#{project.name} | Alert: #{alert_title}" } diff --git a/qa/qa/specs/features/browser_ui/9_data_stores/group/group_member_access_request_spec.rb b/qa/qa/specs/features/browser_ui/9_data_stores/group/group_member_access_request_spec.rb index 1206898431a..0c977e5259c 100644 --- a/qa/qa/specs/features/browser_ui/9_data_stores/group/group_member_access_request_spec.rb +++ b/qa/qa/specs/features/browser_ui/9_data_stores/group/group_member_access_request_spec.rb @@ -12,10 +12,7 @@ module QA end let!(:group) do - Resource::Group.fabricate_via_api! do |group| - group.path = "group-for-access-request-#{SecureRandom.hex(8)}" - group.api_client = admin_api_client - end + create(:group, path: "group-for-access-request-#{SecureRandom.hex(8)}", api_client: admin_api_client) end before do @@ -27,7 +24,7 @@ module QA Flow::Login.sign_in_as_admin Page::Main::Menu.perform do |menu| - menu.go_to_page_by_shortcut(:todos_shortcut_button) + menu.go_to_page_by_shortcut('todos-shortcut-button') end Page::Dashboard::Todos.perform do |todos| diff --git a/qa/qa/specs/features/browser_ui/9_data_stores/group/transfer_group_spec.rb b/qa/qa/specs/features/browser_ui/9_data_stores/group/transfer_group_spec.rb index 2f14e2c10da..2a1f8a58108 100644 --- a/qa/qa/specs/features/browser_ui/9_data_stores/group/transfer_group_spec.rb +++ b/qa/qa/specs/features/browser_ui/9_data_stores/group/transfer_group_spec.rb @@ -3,23 +3,12 @@ module QA RSpec.describe 'Data Stores' do describe 'Subgroup transfer', product_group: :tenant_scale do - let(:source_group) do - Resource::Group.fabricate_via_api! do |group| - group.path = "source-group-for-transfer_#{SecureRandom.hex(8)}" - end - end + let(:source_group) { create(:group, path: "source-group-for-transfer_#{SecureRandom.hex(8)}") } - let!(:target_group) do - Resource::Group.fabricate_via_api! do |group| - group.path = "target-group-for-transfer_#{SecureRandom.hex(8)}" - end - end + let!(:target_group) { create(:group, path: "target-group-for-transfer_#{SecureRandom.hex(8)}") } let(:sub_group_for_transfer) do - Resource::Group.fabricate_via_api! do |group| - group.path = "subgroup-for-transfer_#{SecureRandom.hex(8)}" - group.sandbox = source_group - end + create(:group, path: "subgroup-for-transfer_#{SecureRandom.hex(8)}", sandbox: source_group) end before do diff --git a/qa/qa/specs/features/browser_ui/9_data_stores/group/transfer_project_spec.rb b/qa/qa/specs/features/browser_ui/9_data_stores/group/transfer_project_spec.rb index 02e1598d6e7..6de1d08e674 100644 --- a/qa/qa/specs/features/browser_ui/9_data_stores/group/transfer_project_spec.rb +++ b/qa/qa/specs/features/browser_ui/9_data_stores/group/transfer_project_spec.rb @@ -2,26 +2,10 @@ module QA RSpec.describe 'Data Stores' do - describe 'Project transfer between groups', :reliable, product_group: :tenant_scale do - let(:source_group) do - Resource::Group.fabricate_via_api! do |group| - group.path = "source-group-#{SecureRandom.hex(8)}" - end - end - - let!(:target_group) do - Resource::Group.fabricate_via_api! do |group| - group.path = "target-group-for-transfer_#{SecureRandom.hex(8)}" - end - end - - let(:project) do - Resource::Project.fabricate_via_api! do |project| - project.group = source_group - project.name = 'transfer-project' - end - end - + describe 'Project transfer', :reliable, product_group: :tenant_scale do + let(:project) { create(:project, name: 'transfer-project', group: source_group) } + let(:source_group) { create(:group, path: "source-group-#{SecureRandom.hex(8)}") } + let!(:target_group) { create(:group, path: "target-group-for-transfer_#{SecureRandom.hex(8)}") } let(:readme_content) { 'Here is the edited content.' } before do diff --git a/qa/qa/specs/features/browser_ui/9_data_stores/project/add_project_member_spec.rb b/qa/qa/specs/features/browser_ui/9_data_stores/project/add_project_member_spec.rb index 0beb297ffdb..7fb970c3f25 100644 --- a/qa/qa/specs/features/browser_ui/9_data_stores/project/add_project_member_spec.rb +++ b/qa/qa/specs/features/browser_ui/9_data_stores/project/add_project_member_spec.rb @@ -2,16 +2,13 @@ module QA RSpec.describe 'Data Stores', :reliable, product_group: :tenant_scale do - describe 'Add project member' do - it 'user adds project member', testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347887' do + describe 'Project Member' do + it 'adds a project member', testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347887' do Flow::Login.sign_in user = Resource::User.fabricate_or_use(Runtime::Env.gitlab_qa_username_1, Runtime::Env.gitlab_qa_password_1) - project = Resource::Project.fabricate_via_api! do |project| - project.name = 'add-member-project' - end - + project = create(:project, name: 'add-member-project') project.visit! Page::Project::Menu.perform(&:click_members) diff --git a/qa/qa/specs/features/browser_ui/9_data_stores/project/create_project_badge_spec.rb b/qa/qa/specs/features/browser_ui/9_data_stores/project/create_project_badge_spec.rb index 87492af089e..22f8cc93737 100644 --- a/qa/qa/specs/features/browser_ui/9_data_stores/project/create_project_badge_spec.rb +++ b/qa/qa/specs/features/browser_ui/9_data_stores/project/create_project_badge_spec.rb @@ -2,26 +2,21 @@ module QA RSpec.describe 'Data Stores' do - describe 'Create project badge', :reliable, product_group: :tenant_scale do + describe 'Project badge', :reliable, product_group: :tenant_scale do let(:badge_name) { "project-badge-#{SecureRandom.hex(8)}" } let(:expected_badge_link_url) { "#{Runtime::Scenario.gitlab_address}/#{project.path_with_namespace}" } let(:expected_badge_image_url) do "#{Runtime::Scenario.gitlab_address}/#{project.path_with_namespace}/badges/main/pipeline.svg" end - let(:project) do - Resource::Project.fabricate_via_api! do |project| - project.name = 'badge-test-project' - project.initialize_with_readme = true - end - end + let(:project) { create(:project, :with_readme, name: 'badge-test-project') } before do Flow::Login.sign_in project.visit! end - it 'creates project badge successfully', + it 'creates project badge', testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/350065' do Resource::ProjectBadge.fabricate! do |badge| badge.name = badge_name diff --git a/qa/qa/specs/features/browser_ui/9_data_stores/project/dashboard_images_spec.rb b/qa/qa/specs/features/browser_ui/9_data_stores/project/dashboard_images_spec.rb index f2136773f59..2ea96dfef95 100644 --- a/qa/qa/specs/features/browser_ui/9_data_stores/project/dashboard_images_spec.rb +++ b/qa/qa/specs/features/browser_ui/9_data_stores/project/dashboard_images_spec.rb @@ -16,7 +16,7 @@ module QA user.remove_via_api! end - it 'loads all images' do + it do Flow::Login.sign_in(as: user) Page::Dashboard::Welcome.perform do |welcome| @@ -32,14 +32,14 @@ module QA describe 'Check for broken images', :requires_admin, :reliable do context( - 'when logged in as a new user', + 'when a new user logs in', testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347885' ) do it_behaves_like 'loads all images', false end context( - 'when logged in as a new admin', + 'when a new admin logs in', testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347884' ) do it_behaves_like 'loads all images', true diff --git a/qa/qa/specs/features/browser_ui/9_data_stores/project/invite_group_to_project_spec.rb b/qa/qa/specs/features/browser_ui/9_data_stores/project/invite_group_to_project_spec.rb index c7501d437eb..29e39d48c67 100644 --- a/qa/qa/specs/features/browser_ui/9_data_stores/project/invite_group_to_project_spec.rb +++ b/qa/qa/specs/features/browser_ui/9_data_stores/project/invite_group_to_project_spec.rb @@ -4,7 +4,7 @@ module QA RSpec.describe 'Data Stores' do describe 'Invite group', :reliable, product_group: :tenant_scale do shared_examples 'invites group to project' do - it 'verifies group is added and members can access project with correct access level' do + it 'grants group and members correct access level' do Page::Project::Menu.perform(&:click_members) Page::Project::Members.perform do |project_members| project_members.invite_group(group.path, 'Developer') @@ -40,19 +40,14 @@ module QA context 'with a personal namespace project', testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/349223' do - let(:group) do - Resource::Group.fabricate_via_api! do |group| - group.path = "group-for-personal-project-#{SecureRandom.hex(8)}" - end - end + let(:group) { create(:group, path: "group-for-personal-project-#{SecureRandom.hex(8)}") } let(:project) do - Resource::Project.fabricate_via_api! do |project| - project.name = 'personal-namespace-project' - project.personal_namespace = Runtime::User.username - project.visibility = :private - project.description = 'test personal namespace project' - end + create(:project, + :private, + name: 'personal-namespace-project', + description: 'test personal namespace project', + personal_namespace: Runtime::User.username) end after do @@ -64,19 +59,9 @@ module QA end context 'with a group project', testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/349340' do - let(:group) do - Resource::Group.fabricate_via_api! do |group| - group.path = "group-for-group-project-#{SecureRandom.hex(8)}" - end - end + let(:group) { create(:group, path: "group-for-group-project-#{SecureRandom.hex(8)}") } - let(:project) do - Resource::Project.fabricate_via_api! do |project| - project.name = 'group-project' - project.visibility = :private - project.description = 'test group project' - end - end + let(:project) { create(:project, :private, name: 'group-project', description: 'test group project') } after do project.remove_via_api! diff --git a/qa/qa/specs/features/browser_ui/9_data_stores/project/project_owner_permissions_spec.rb b/qa/qa/specs/features/browser_ui/9_data_stores/project/project_owner_permissions_spec.rb index 2793b0440a4..310b8747584 100644 --- a/qa/qa/specs/features/browser_ui/9_data_stores/project/project_owner_permissions_spec.rb +++ b/qa/qa/specs/features/browser_ui/9_data_stores/project/project_owner_permissions_spec.rb @@ -13,7 +13,7 @@ module QA Resource::User.fabricate_or_use(Runtime::Env.gitlab_qa_username_2, Runtime::Env.gitlab_qa_password_2) end - shared_examples 'when user is added as owner' do |project_type, testcase| + shared_examples 'adds user as owner' do |project_type, testcase| let!(:issue) do Resource::Issue.fabricate_via_api! do |issue| issue.api_client = owner_api_client @@ -27,7 +27,7 @@ module QA Flow::Login.sign_in(as: owner) end - it "has owner role with owner permissions", testcase: testcase do + it "has owner role and permissions", testcase: testcase do Page::Dashboard::Projects.perform do |projects| projects.filter_by_name(project.name) @@ -44,7 +44,7 @@ module QA end end - shared_examples 'when user is added as maintainer' do |testcase| + shared_examples 'adds user as maintainer' do |testcase| let!(:issue) do Resource::Issue.fabricate_via_api! do |issue| issue.api_client = owner_api_client @@ -82,12 +82,12 @@ module QA end end - it_behaves_like 'when user is added as owner', :personal_project, 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/352542' - it_behaves_like 'when user is added as maintainer', 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/352607' + it_behaves_like 'adds user as owner', :personal_project, 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/352542' + it_behaves_like 'adds user as maintainer', 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/352607' end context 'for group projects' do - let!(:group) { Resource::Group.fabricate_via_api! } + let!(:group) { create(:group) } let!(:project) do Resource::Project.fabricate_via_api! do |project| @@ -96,8 +96,8 @@ module QA end end - it_behaves_like 'when user is added as owner', :group_project, 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/366436' - it_behaves_like 'when user is added as maintainer', 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/366435' + it_behaves_like 'adds user as owner', :group_project, 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/366436' + it_behaves_like 'adds user as maintainer', 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/366435' end end end diff --git a/qa/qa/specs/features/browser_ui/9_data_stores/project/view_project_activity_spec.rb b/qa/qa/specs/features/browser_ui/9_data_stores/project/view_project_activity_spec.rb index 4945ef533a4..5cdb88407fb 100644 --- a/qa/qa/specs/features/browser_ui/9_data_stores/project/view_project_activity_spec.rb +++ b/qa/qa/specs/features/browser_ui/9_data_stores/project/view_project_activity_spec.rb @@ -3,22 +3,24 @@ module QA RSpec.describe 'Data Stores' do describe 'Project activity', :reliable, product_group: :tenant_scale do - it 'user creates an event in the activity page upon Git push', - testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347879' do - Flow::Login.sign_in + context 'with git push' do + it 'creates an event in the activity page', + testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347879' do + Flow::Login.sign_in - project = Resource::Repository::ProjectPush.fabricate! do |push| - push.file_name = 'README.md' - push.file_content = '# This is a test project' - push.commit_message = 'Add README.md' - end.project + project = Resource::Repository::ProjectPush.fabricate! do |push| + push.file_name = 'README.md' + push.file_content = '# This is a test project' + push.commit_message = 'Add README.md' + end.project - project.visit! - Page::Project::Menu.perform(&:click_activity) - Page::Project::Activity.perform do |activity| - activity.click_push_events + project.visit! + Page::Project::Menu.perform(&:click_activity) + Page::Project::Activity.perform do |activity| + activity.click_push_events - expect(activity).to have_content("pushed new branch #{project.default_branch}") + expect(activity).to have_content("pushed new branch #{project.default_branch}") + end end end end diff --git a/qa/qa/specs/features/browser_ui/9_data_stores/user/follow_user_activity_spec.rb b/qa/qa/specs/features/browser_ui/9_data_stores/user/follow_user_activity_spec.rb index c78151b94b7..a119d600667 100644 --- a/qa/qa/specs/features/browser_ui/9_data_stores/user/follow_user_activity_spec.rb +++ b/qa/qa/specs/features/browser_ui/9_data_stores/user/follow_user_activity_spec.rb @@ -22,10 +22,9 @@ module QA end let(:group) do - group = QA::Resource::Group.fabricate_via_api! do |group| - group.path = "group_for_follow_user_activity_#{SecureRandom.hex(8)}" - group.api_client = admin_api_client - end + group = create(:group, + path: "group_for_follow_user_activity_#{SecureRandom.hex(8)}", + api_client: admin_api_client) group.add_member(followed_user, Resource::Members::AccessLevel::MAINTAINER) group end diff --git a/qa/qa/specs/features/browser_ui/9_data_stores/user/parent_group_access_termination_spec.rb b/qa/qa/specs/features/browser_ui/9_data_stores/user/parent_group_access_termination_spec.rb index 7e88f3a9ac3..562bd1b1aa1 100644 --- a/qa/qa/specs/features/browser_ui/9_data_stores/user/parent_group_access_termination_spec.rb +++ b/qa/qa/specs/features/browser_ui/9_data_stores/user/parent_group_access_termination_spec.rb @@ -11,11 +11,7 @@ module QA end end - let!(:group) do - QA::Resource::Group.fabricate_via_api! do |group| - group.path = "group-to-test-access-termination-#{SecureRandom.hex(8)}" - end - end + let!(:group) { create(:group, path: "group-to-test-access-termination-#{SecureRandom.hex(8)}") } let!(:project) do Resource::Project.fabricate_via_api! do |project| @@ -25,7 +21,7 @@ module QA end end - context 'when parent group membership is terminated' do + context 'with terminated parent group membership' do before do group.add_member(user) @@ -40,7 +36,7 @@ module QA end end - it 'is not allowed to edit the project files', + it 'can not edit the project files', testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347866' do Flow::Login.sign_in(as: user) project.visit! diff --git a/qa/qa/specs/features/browser_ui/9_data_stores/user/user_inherited_access_spec.rb b/qa/qa/specs/features/browser_ui/9_data_stores/user/user_inherited_access_spec.rb index 78baba403fd..8553e1739ce 100644 --- a/qa/qa/specs/features/browser_ui/9_data_stores/user/user_inherited_access_spec.rb +++ b/qa/qa/specs/features/browser_ui/9_data_stores/user/user_inherited_access_spec.rb @@ -6,16 +6,11 @@ module QA let(:admin_api_client) { Runtime::API::Client.as_admin } let!(:parent_group) do - QA::Resource::Group.fabricate_via_api! do |group| - group.path = "parent-group-to-test-user-access-#{SecureRandom.hex(8)}" - end + create(:group, path: "parent-group-to-test-user-access-#{SecureRandom.hex(8)}") end let!(:sub_group) do - QA::Resource::Group.fabricate_via_api! do |group| - group.path = "sub-group-to-test-user-access-#{SecureRandom.hex(8)}" - group.sandbox = parent_group - end + create(:group, path: "sub-group-to-test-user-access-#{SecureRandom.hex(8)}", sandbox: parent_group) end context 'when added to parent group' do diff --git a/qa/qa/specs/features/shared_contexts/import/github_import_shared_context.rb b/qa/qa/specs/features/shared_contexts/import/github_import_shared_context.rb index 55ed9abb0da..445586d31ac 100644 --- a/qa/qa/specs/features/shared_contexts/import/github_import_shared_context.rb +++ b/qa/qa/specs/features/shared_contexts/import/github_import_shared_context.rb @@ -10,10 +10,7 @@ module QA 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 + create(:group, api_client: api_client, path: "destination-group-for-import-#{SecureRandom.hex(4)}") end let!(:user) do diff --git a/qa/qa/specs/features/shared_contexts/packages_registry_shared_context.rb b/qa/qa/specs/features/shared_contexts/packages_registry_shared_context.rb index 5ab7bb331c0..3905a05633f 100644 --- a/qa/qa/specs/features/shared_contexts/packages_registry_shared_context.rb +++ b/qa/qa/specs/features/shared_contexts/packages_registry_shared_context.rb @@ -51,8 +51,7 @@ module QA end let(:gitlab_address_with_port) do - uri = URI.parse(Runtime::Scenario.gitlab_address) - "#{uri.scheme}://#{uri.host}:#{uri.port}" + Support::GitlabAddress.address_with_port end let(:project_deploy_token) do diff --git a/qa/qa/specs/features/shared_contexts/variable_inheritance_shared_context.rb b/qa/qa/specs/features/shared_contexts/variable_inheritance_shared_context.rb index 2219031e9c6..69786c55be8 100644 --- a/qa/qa/specs/features/shared_contexts/variable_inheritance_shared_context.rb +++ b/qa/qa/specs/features/shared_contexts/variable_inheritance_shared_context.rb @@ -5,12 +5,7 @@ module QA let(:key) { 'TEST_VAR' } let(:value) { 'This is great!' } let(:random_string) { Faker::Alphanumeric.alphanumeric(number: 8) } - - let(:group) do - Resource::Group.fabricate_via_api! do |group| - group.path = "group-for-variable-inheritance-#{random_string}" - end - end + let(:group) { create(:group, path: "group-for-variable-inheritance-#{random_string}") } let(:upstream_project) do Resource::Project.fabricate_via_api! do |project| diff --git a/qa/qa/specs/features/shared_examples/create_and_terminate_workspace_shared_examples.rb b/qa/qa/specs/features/shared_examples/create_and_terminate_workspace_shared_examples.rb new file mode 100644 index 00000000000..7a9a485d611 --- /dev/null +++ b/qa/qa/specs/features/shared_examples/create_and_terminate_workspace_shared_examples.rb @@ -0,0 +1,38 @@ +# frozen_string_literal: true + +module QA + RSpec.shared_examples 'workspaces actions' do + it 'creates a new workspace and then stops and terminates it' do + QA::Page::Main::Menu.perform(&:go_to_workspaces) + workspace_name = "" + + QA::EE::Page::Workspace::List.perform do |list| + existing_workspaces = list.get_workspaces_list + list.create_workspace(kubernetes_agent.name, devfile_project.name) + updated_workspaces = list.get_workspaces_list + workspace_name = (updated_workspaces - existing_workspaces).fetch(0, '').to_s + raise "Workspace name is empty" if workspace_name == '' + + expect(list).to have_workspace_state(workspace_name, "Creating") + list.wait_for_workspaces_creation(workspace_name) + expect(list).to have_workspace_state(workspace_name, "Running") + end + + QA::EE::Page::Workspace::Action.perform do |workspace| + workspace.click_workspace_action(workspace_name, "stop") + end + + QA::EE::Page::Workspace::List.perform do |list_item| + expect(list_item).to have_workspace_state(workspace_name, "Stopped") + end + + QA::EE::Page::Workspace::Action.perform do |workspace| + workspace.click_workspace_action(workspace_name, "terminate") + end + + QA::EE::Page::Workspace::List.perform do |list_item| + expect(list_item).to have_workspace_state(workspace_name, "Terminated") + end + end + end +end diff --git a/qa/qa/specs/spec_helper.rb b/qa/qa/specs/spec_helper.rb index 1601dd46c62..965e3c2f88c 100644 --- a/qa/qa/specs/spec_helper.rb +++ b/qa/qa/specs/spec_helper.rb @@ -1,7 +1,12 @@ # frozen_string_literal: true -require_relative '../../qa' require 'active_support/testing/time_helpers' +require 'factory_bot' + +require_relative '../../qa' + +# Require shared test tooling from Rails test suite +require_relative '../../../spec/support/fast_quarantine' QA::Specs::QaDeprecationToolkitEnv.configure! @@ -24,6 +29,9 @@ RSpec.configure do |config| config.include ActiveSupport::Testing::TimeHelpers config.include QA::Support::Matchers::EventuallyMatcher config.include QA::Support::Matchers::HaveMatcher + config.include FactoryBot::Syntax::Methods + + FactoryBot.definition_file_paths = ['qa/factories'] config.add_formatter QA::Support::Formatters::ContextFormatter config.add_formatter QA::Support::Formatters::QuarantineFormatter @@ -41,6 +49,10 @@ RSpec.configure do |config| Thread.current[:browser_ui_fabrication] = 0 end + config.before(:suite) do + FactoryBot.find_definitions + end + config.after do # If a .netrc file was created during the test, delete it so that subsequent tests don't try to use the same logins QA::Git::Repository.new.delete_netrc diff --git a/qa/qa/support/api.rb b/qa/qa/support/api.rb index 0081b1c1d46..f0a73391d5d 100644 --- a/qa/qa/support/api.rb +++ b/qa/qa/support/api.rb @@ -99,6 +99,15 @@ module QA url.sub(/private_token=[^&]*/, "private_token=[****]") end + # Returns the response body with secrets masked. + # + # @param [String] response the response body as the string value of a JSON hash + # @param [Array<Symbol>] mask_by_key the keys of the JSON parsed response body whose values will be masked + # @return [Hash] the response body with the specified secrets values replaced with `****` + def masked_parsed_response(response, mask_by_key:) + Helpers::Masker.mask(parse_body(response), by_key: Array(mask_by_key)) + end + # Merges the gitlab_canary cookie into existing cookies for mixed environment testing. # # @param [Hash] args the existing args passed to method diff --git a/qa/qa/support/formatters/test_metrics_formatter.rb b/qa/qa/support/formatters/test_metrics_formatter.rb index cdc0e83dc02..5b3f5d1d77a 100644 --- a/qa/qa/support/formatters/test_metrics_formatter.rb +++ b/qa/qa/support/formatters/test_metrics_formatter.rb @@ -74,11 +74,15 @@ module QA def save_test_metrics return log(:debug, "Saving test metrics json not enabled, skipping") unless save_metrics_json? - File.write("tmp/test-metrics-#{env('CI_JOB_NAME_SLUG') || 'local'}.json", execution_data.to_json) + file = "tmp/test-metrics-#{env('CI_JOB_NAME_SLUG') || 'local'}.json" + + File.write(file, execution_data.to_json) && log(:debug, "Saved test metrics to #{file}") rescue StandardError => e log(:error, "Failed to save test execution metrics, error: #{e}") end + # rubocop:disable Metrics/AbcSize + # Transform example to influxdb compatible metrics data # https://github.com/influxdata/influxdb-client-ruby#data-format # @@ -123,6 +127,7 @@ module QA pipeline_id: env('CI_PIPELINE_ID'), job_id: env('CI_JOB_ID'), merge_request_iid: merge_request_iid, + failure_exception: example.execution_result.exception.to_s.delete("\n"), **custom_metrics_fields(example.metadata) } } @@ -131,6 +136,8 @@ module QA nil end + # rubocop:enable Metrics/AbcSize + # Resource fabrication data point # # @param [String] resource diff --git a/qa/qa/support/gitlab_address.rb b/qa/qa/support/gitlab_address.rb index d978bb2eee5..0dff8413706 100644 --- a/qa/qa/support/gitlab_address.rb +++ b/qa/qa/support/gitlab_address.rb @@ -13,17 +13,43 @@ module QA validate_address(address) - Runtime::Scenario.define(:gitlab_address, address) + Runtime::Scenario.define(:gitlab_address, address_with_port(address, with_default_port: false)) # Define the "About" page as an `about` subdomain. # @example # Given *gitlab_address* = 'https://gitlab.com/' #=> https://about.gitlab.com/ # Given *gitlab_address* = 'https://staging.gitlab.com/' #=> https://about.staging.gitlab.com/ # Given *gitlab_address* = 'http://gitlab-abc123.test/' #=> http://about.gitlab-abc123.test/ - Runtime::Scenario.define(:about_address, URI(address).tap { |uri| uri.host = "about.#{uri.host}" }.to_s) + Runtime::Scenario.define( + :about_address, + URI(address).then { |uri| "#{uri.scheme}://about.#{host_with_port(address, with_default_port: false)}" } + ) @initialized = true end + # Get gitlab address with port and path + # + # @param [String] address + # @param [Boolean] with_default_port keep default port 80 or 443 + # @return [String] + def address_with_port(address = Runtime::Scenario.gitlab_address, with_default_port: true) + uri = URI.parse(address) + + "#{uri.scheme}://#{host_with_port(uri, with_default_port: with_default_port)}" + end + + # Get gitlab host with port and path + # + # @param [<String, URI>] address + # @param [Boolean] with_default_port keep default port 80 or 443 + # @return [String] + def host_with_port(address = Runtime::Scenario.gitlab_address, with_default_port: true) + uri = address.is_a?(URI) ? address : URI.parse(address) + port = !with_default_port && [80, 443].include?(uri.port) ? "" : ":#{uri.port}" + + "#{uri.host}#{port}#{uri.path}" + end + private # Gitlab address already set up diff --git a/qa/qa/support/helpers/masker.rb b/qa/qa/support/helpers/masker.rb new file mode 100644 index 00000000000..8a01336483f --- /dev/null +++ b/qa/qa/support/helpers/masker.rb @@ -0,0 +1,76 @@ +# frozen_string_literal: true + +module QA + module Support + module Helpers + # A helper class to mask secrets. + class Masker + # Returns the content with secrets masked. + # + # @param [Object] content the content to mask + # @param [Array<Symbol>] by_key the keys of the content whose values will be masked + # @param [Array<String>] by_value the content to be masked. Masks whole- or sub-strings + # @param [String] mask the string used to replace secrets (default '****') + # @return [Object] the content with the specified secrets replaced with the mask + def self.mask(content, by_key: [], by_value: [], mask: '****') + new(by_key: by_key, by_value: by_value, mask: mask).mask(content) + end + + # @param [Array<Symbol>] by_key the keys of the content whose values will be masked + # @param [Array<String>] by_value the content to be masked. Masks whole- or sub-strings + # @param [String] mask the string used to replace secrets (default '****') + def initialize(by_key: [], by_value: [], mask: '****') + by_key.present? || by_value.present? || + raise(ArgumentError, 'Please specify `by_key` or `by_value`') + + @by_key = Array(by_key) + @by_value = Array(by_value) + @mask = mask + end + + # @param [Object] content the content to mask + # @return [Object] the content with the specified secrets replaced with the mask + def mask(content) + return content if content.blank? || [true, false].include?(content) + + @content = content + @content = mask_by_key(@content) if @by_key.present? + @content = mask_by_value(@content) if @by_value.present? + @content + end + + private + + attr_reader :by_key, :by_value + + # Masks by using the given secrets as hash keys. If the key exists, the corresponding value is replaced with the + # mask. Recursively masks nested hashes and arrays. + def mask_by_key(content) + case content + when Hash + ActiveSupport::ParameterFilter.new(by_key, mask: @mask).filter(content) + when Array + content.map { |item| mask_by_key(item) } + else + content + end + end + + # Masks by substituting the given secrets found in the content. If a secret exists as substrings, the substrings + # are replaced with the mask. Recursively masks nested hashes and arrays, and each element of arrays. + def mask_by_value(content) + case content + when Hash + content.each { |k, v| content[k] = mask_by_value(v) } + when Array + content.map { |item| mask_by_value(item) } + when String + by_value.reduce(content) { |s, secret| s.gsub(secret.to_s, @mask) } + else + by_value.include?(content) ? @mask : content + end + end + end + end + end +end diff --git a/qa/qa/support/helpers/plan.rb b/qa/qa/support/helpers/plan.rb index b6950c6bacd..c3867b4a1b8 100644 --- a/qa/qa/support/helpers/plan.rb +++ b/qa/qa/support/helpers/plan.rb @@ -56,6 +56,14 @@ module QA storage: 10 }.freeze + CODE_SUGGESTIONS = { + # Annual plan, rate and price + plan_id: '8a8aa0ac8874ddc4018878da1f736782', + rate_charge_id: '8a8aa0ac8874ddc4018878da1f9a6784', + name: 'code suggestions', + price: 108 + }.freeze + LICENSE_TYPE = { legacy_license: 'legacy license', online_cloud: 'online license', diff --git a/qa/qa/support/matchers/have_matcher.rb b/qa/qa/support/matchers/have_matcher.rb index c77b585ada8..6fa88ef205b 100644 --- a/qa/qa/support/matchers/have_matcher.rb +++ b/qa/qa/support/matchers/have_matcher.rb @@ -30,6 +30,7 @@ module QA alert_with_title incident framework + delete_issue_button ].each do |predicate| RSpec::Matchers.define "have_#{predicate}" do |*args, **kwargs| match do |page_object| diff --git a/qa/qa/support/wait_for_requests.rb b/qa/qa/support/wait_for_requests.rb index 2856602629a..8c7d87e960a 100644 --- a/qa/qa/support/wait_for_requests.rb +++ b/qa/qa/support/wait_for_requests.rb @@ -7,9 +7,10 @@ module QA DEFAULT_MAX_WAIT_TIME = 60 - def wait_for_requests(skip_finished_loading_check: false, skip_resp_code_check: false) + def wait_for_requests(skip_finished_loading_check: false, skip_resp_code_check: false, finish_loading_wait: 1) Waiter.wait_until(log: false) do - finished_all_ajax_requests? && (!skip_finished_loading_check ? finished_loading?(wait: 1) : true) + finished_all_ajax_requests? && + (!skip_finished_loading_check ? finished_loading?(wait: finish_loading_wait) : true) end rescue Repeater::WaitExceededError raise $!, 'Page did not fully load. This could be due to an unending async request or loading icon.' diff --git a/qa/qa/tools/ci/helpers.rb b/qa/qa/tools/ci/helpers.rb index 55bb123de20..4650532f89a 100644 --- a/qa/qa/tools/ci/helpers.rb +++ b/qa/qa/tools/ci/helpers.rb @@ -17,33 +17,6 @@ module QA source: "CI Tools" ) end - - # Api get request - # - # @param [String] path - # @param [Hash] args - # @return [Hash, Array] - def api_get(path, **args) - response = get("#{api_url}/#{path}", { headers: { "PRIVATE-TOKEN" => access_token }, **args }) - response = response.follow_redirection if response.code == Support::API::HTTP_STATUS_PERMANENT_REDIRECT - raise "Request failed: '#{response.body}'" unless response.code == Support::API::HTTP_STATUS_OK - - args[:raw_response] ? response : parse_body(response) - end - - # Gitlab api url - # - # @return [String] - def api_url - @api_url ||= ENV.fetch('CI_API_V4_URL', 'https://gitlab.com/api/v4') - end - - # Api access token - # - # @return [String] - def access_token - @access_token ||= ENV.fetch('QA_GITLAB_CI_TOKEN') { raise('Variable QA_GITLAB_CI_TOKEN missing') } - end end end end diff --git a/qa/qa/vendor/saml_idp/page/login.rb b/qa/qa/vendor/saml_idp/page/login.rb index 9b4fbe15366..dda9cd3758f 100644 --- a/qa/qa/vendor/saml_idp/page/login.rb +++ b/qa/qa/vendor/saml_idp/page/login.rb @@ -11,12 +11,6 @@ module QA fill_in 'username', with: username fill_in 'password', with: password click_on 'Login' - - if Runtime::Env.super_sidebar_enabled? - QA::Page::Main::Menu.perform(&:enable_new_navigation) - else - QA::Page::Main::Menu.perform(&:disable_new_navigation) - end end def login_if_required(username, password) diff --git a/qa/spec/page/element_spec.rb b/qa/spec/page/element_spec.rb index da1fd224564..c354d55fb19 100644 --- a/qa/spec/page/element_spec.rb +++ b/qa/spec/page/element_spec.rb @@ -1,17 +1,10 @@ # frozen_string_literal: true RSpec.describe QA::Page::Element do - describe '#selector' do - it 'transforms element name into QA-specific selector' do - expect(described_class.new(:sign_in_button).selector) - .to eq 'qa-sign-in-button' - end - end - describe '#selector_css' do it 'transforms element name into QA-specific clickable css selector' do expect(described_class.new(:sign_in_button).selector_css) - .to include('.qa-sign-in-button') + .to eq('[data-testid="sign_in_button"],[data-qa-selector="sign_in_button"]') end end @@ -42,10 +35,6 @@ RSpec.describe QA::Page::Element do context 'when pattern is not provided' do subject { described_class.new(:some_name) } - it 'matches when QA specific selector is present' do - expect(subject.matches?('some qa-some-name selector')).to be true - end - it 'does not match if QA selector is not there' do expect(subject.matches?('some_name selector')).to be false end @@ -53,15 +42,18 @@ RSpec.describe QA::Page::Element do it 'matches when element name is specified' do expect(subject.matches?('data:{qa:{selector:"some_name"}}')).to be true end + + it 'matches when element name is specified (single quotes)' do + expect(subject.matches?("data:{qa:{selector:'some_name'}}")).to be true + end end describe 'attributes' do context 'element with no args' do subject { described_class.new(:something) } - it 'defaults pattern to #selector' do - expect(subject.attributes[:pattern]).to eq 'qa-something' - expect(subject.attributes[:pattern]).to eq subject.selector + it 'has no attribute[pattern]' do + expect(subject.attributes[:pattern]).to be(nil) end it 'is not required by default' do @@ -84,11 +76,6 @@ RSpec.describe QA::Page::Element do context 'element with requirement; no pattern' do subject { described_class.new(:something, required: true) } - it 'has an attribute[pattern] of the selector' do - expect(subject.attributes[:pattern]).to eq 'qa-something' - expect(subject.attributes[:pattern]).to eq subject.selector - end - it 'is required' do expect(subject.required?).to be true end @@ -104,10 +91,6 @@ RSpec.describe QA::Page::Element do it 'is required' do expect(subject.required?).to be true end - - it 'has a selector of the name' do - expect(subject.selector).to eq 'qa-something' - end end end @@ -126,18 +109,20 @@ RSpec.describe QA::Page::Element do let(:element) { described_class.new(:my_element, index: 3, another_match: 'something') } let(:required_element) { described_class.new(:my_element, required: true, index: 3) } - it 'matches on additional data-qa properties' do - expect(element.selector_css).to include(%q([data-qa-selector="my_element"][data-qa-index="3"])) + it 'matches on additional data-qa properties translating snake_case to kebab-case' do + expect(element.selector_css) + .to include('[data-testid="my_element"][data-qa-index="3"][data-qa-another-match="something"]') + expect(element.selector_css) + .to include('[data-qa-selector="my_element"][data-qa-index="3"][data-qa-another-match="something"]') end it 'doesnt conflict with element requirement' do + expect(element).not_to be_required + expect(element.selector_css).not_to include(%q(data-qa-required)) + expect(required_element).to be_required expect(required_element.selector_css).not_to include(%q(data-qa-required)) end - - it 'translates snake_case to kebab-case' do - expect(element.selector_css).to include(%q(data-qa-another-match)) - end end end end diff --git a/qa/spec/support/api_spec.rb b/qa/spec/support/api_spec.rb new file mode 100644 index 00000000000..5bf09da9020 --- /dev/null +++ b/qa/spec/support/api_spec.rb @@ -0,0 +1,29 @@ +# frozen_string_literal: true + +module QA + RSpec.describe QA::Support::API do + describe ".masked_parsed_response" do + let(:response) { Struct.new(:body).new('{ "secret": "foobar", "name": "gitlab" }') } + + it 'calls Masker to mask secrets' do + expect(QA::Support::Helpers::Masker).to receive(:mask) + .with( + JSON.parse(response.body, symbolize_names: true), + by_key: [:secret] + ) + + described_class.masked_parsed_response(response, mask_by_key: [:secret]) + end + + it 'accepts a single secret key' do + expect(QA::Support::Helpers::Masker).to receive(:mask) + .with( + JSON.parse(response.body, symbolize_names: true), + by_key: ['secret'] + ) + + described_class.masked_parsed_response(response, mask_by_key: 'secret') + end + end + end +end diff --git a/qa/spec/support/formatters/test_metrics_formatter_spec.rb b/qa/spec/support/formatters/test_metrics_formatter_spec.rb index 2b8a0791dc5..5342cfe12e3 100644 --- a/qa/spec/support/formatters/test_metrics_formatter_spec.rb +++ b/qa/spec/support/formatters/test_metrics_formatter_spec.rb @@ -68,7 +68,8 @@ describe QA::Support::Formatters::TestMetricsFormatter do pipeline_url: ci_pipeline_url, pipeline_id: ci_pipeline_id, job_id: ci_job_id, - merge_request_iid: nil + merge_request_iid: nil, + failure_exception: '' } } end diff --git a/qa/spec/support/gitlab_address_spec.rb b/qa/spec/support/gitlab_address_spec.rb new file mode 100644 index 00000000000..c3a470b7547 --- /dev/null +++ b/qa/spec/support/gitlab_address_spec.rb @@ -0,0 +1,61 @@ +# frozen_string_literal: true + +RSpec.describe QA::Support::GitlabAddress do + subject(:gitlab_address) { described_class } + + describe ".define_gitlab_address_attribute!" do + let(:address) { "http://example.com" } + + before do + allow(QA::Runtime::Scenario).to receive(:define) + + gitlab_address.instance_variable_set(:@initialized, initialized) + gitlab_address.define_gitlab_address_attribute!(address) + end + + context "with attribute not initialized" do + let(:initialized) { nil } + + it "initializes gitlab address attribute", :aggregate_failures do + expect(QA::Runtime::Scenario).to have_received(:define).with(:gitlab_address, address) + expect(QA::Runtime::Scenario).to have_received(:define).with(:about_address, "http://about.example.com") + end + end + + context "with attribute already initialized" do + let(:initialized) { true } + + it "skips setting gitlab address attribute" do + expect(QA::Runtime::Scenario).not_to have_received(:define) + end + end + end + + describe ".address_with_port" do + context "when fetching address" do + let(:address) { gitlab_address.address_with_port("http://example.com/relative") } + + it { expect(address).to eq("http://example.com:80/relative") } + end + end + + describe ".host_with_port" do + context "when fetching host with default port" do + let(:host) { gitlab_address.host_with_port("http://example.com/relative") } + + it { expect(host).to eq("example.com:80/relative") } + end + + context "when fetching host with default port ommitted" do + let(:host) { gitlab_address.host_with_port("http://example.com/relative", with_default_port: false) } + + it { expect(host).to eq("example.com/relative") } + end + + context "when fetching host for address with custom port" do + let(:host) { gitlab_address.host_with_port("http://example.com:3322/relative", with_default_port: false) } + + it { expect(host).to eq("example.com:3322/relative") } + end + end +end diff --git a/qa/spec/support/helpers/masker_spec.rb b/qa/spec/support/helpers/masker_spec.rb new file mode 100644 index 00000000000..3d89f152891 --- /dev/null +++ b/qa/spec/support/helpers/masker_spec.rb @@ -0,0 +1,169 @@ +# frozen_string_literal: true + +module QA + RSpec.describe QA::Support::Helpers::Masker do + let(:secrets) { [:secret_content, 'secret'] } + let(:content) do + { + numeric_content: 1, + secret_content: 'a-private-token', + public_content: 'gitlab', + array_content: ['secret', :foo], + private: 'hide me', + hash_content: { + secret: 'a-private-key', + public: 'gitlab', + array: ['secret', :bar], + hash: { foo: 'secret' } + } + } + end + + subject { described_class.new(by_key: secrets).mask(content) } + + shared_examples 'masks secrets' do + it 'masks secrets' do + expect(subject).to match(a_hash_including(expected)) + end + end + + describe '.mask' do + it 'instantiates an object and calls the mask instance method' do + instance = instance_double('QA::Support::Helpers::Masker') + + expect(described_class).to receive(:new) + .with(by_key: secrets, by_value: nil, mask: nil) + .and_return(instance) + expect(instance).to receive(:mask).with(content) + + described_class.mask(content, by_key: secrets, by_value: nil, mask: nil) + end + end + + describe '#initialize' do + it 'requires by_key or by_key' do + expect { described_class.new }.to raise_error(ArgumentError, /Please specify `by_key` or `by_value`/) + end + end + + describe '#mask' do + context 'when content is blank' do + let(:content) { [] } + + it 'returns content' do + expect(subject).to match([]) + end + end + + context 'when masking by key' do + subject { described_class.new(by_key: secrets).mask(content) } + + let(:secrets) { [:secret_content, 'secret'] } + + it 'masks secrets' do + expect(subject).to match(a_hash_including({ + secret_content: '****', + hash_content: { + secret: '****', + public: 'gitlab', + array: ['secret', :bar], + hash: { foo: 'secret' } + } + })) + end + + it 'does not mask by value' do + expect(subject).to match(a_hash_including({ + array_content: ['secret', :foo], + hash_content: { + secret: '****', + public: 'gitlab', + array: ['secret', :bar], + hash: { foo: 'secret' } + } + })) + end + + context 'with values that are not strings' do + let(:secrets) { [:numeric_content] } + let(:expected) { { numeric_content: '****' } } + + include_examples 'masks secrets' + end + + context 'when by_key is not an array' do + let(:secrets) { :secret_content } + let(:expected) { { secret_content: '****' } } + + include_examples 'masks secrets' + end + end + + context 'when masking by value' do + shared_examples 'does not mask' do + it 'does not mask' do + expect(subject).to eq(content) + end + end + + subject { described_class.new(by_value: secrets).mask(content) } + + let(:secrets) { [:private, 'secret'] } + + it 'masks secrets' do + expect(subject).to match(a_hash_including({ + secret_content: 'a-****-token', + array_content: ['****', :foo], + private: 'hide me', + hash_content: { + secret: 'a-****-key', + public: 'gitlab', + array: ['****', :bar], + hash: { foo: '****' } + } + })) + end + + it 'does not mask by key' do + expect(subject).to match(a_hash_including(private: 'hide me')) + expect(subject.fetch(:hash_content)).to match(a_hash_including(secret: 'a-****-key')) + end + + context 'when content is an Array' do + let(:content) { %w[secret not-secret] } + + it 'masks secrets' do + expect(subject).to match_array(%w[**** not-****]) + end + end + + context 'when content is a String' do + let(:content) { 'secret' } + let(:expected) { '****' } + + it 'masks secret values' do + expect(subject).to eq(expected) + end + end + + context 'when content is an Integer' do + let(:content) { 1 } + + include_examples 'does not mask' + end + + context 'when content is a Float' do + let(:content) { 1.0 } + + include_examples 'does not mask' + end + + context 'when content is a Boolean' do + let(:content) { false } + + include_examples 'does not mask' + end + end + end + end +end |