diff options
Diffstat (limited to 'qa/qa/specs')
44 files changed, 700 insertions, 234 deletions
diff --git a/qa/qa/specs/features/api/1_manage/import_github_repo_spec.rb b/qa/qa/specs/features/api/1_manage/import_github_repo_spec.rb index 79509bdbe01..df34bf32421 100644 --- a/qa/qa/specs/features/api/1_manage/import_github_repo_spec.rb +++ b/qa/qa/specs/features/api/1_manage/import_github_repo_spec.rb @@ -65,10 +65,8 @@ module QA end def verify_repository_import - expect(imported_project.api_response).to include( - description: 'Project for github import test', - import_error: nil - ) + expect(imported_project.reload!.description).to eq('Project for github import test') + expect(imported_project.api_response[:import_error]).to be_nil end def verify_commits_import diff --git a/qa/qa/specs/features/api/1_manage/import_large_github_repo_spec.rb b/qa/qa/specs/features/api/1_manage/import_large_github_repo_spec.rb index c47afbd23f0..de460a39ccf 100644 --- a/qa/qa/specs/features/api/1_manage/import_large_github_repo_spec.rb +++ b/qa/qa/specs/features/api/1_manage/import_large_github_repo_spec.rb @@ -8,9 +8,14 @@ module QA describe 'Project import' do let(:logger) { Runtime::Logger.logger } let(:differ) { RSpec::Support::Differ.new(color: true) } + let(:gitlab_address) { QA::Runtime::Scenario.gitlab_address } + let(:dummy_url) { "https://example.com" } let(:created_by_pattern) { /\*Created by: \S+\*\n\n/ } let(:suggestion_pattern) { /suggestion:-\d+\+\d+/ } + let(:gh_link_pattern) { %r{https://github.com/#{github_repo}/(issues|pull)} } + let(:gl_link_pattern) { %r{#{gitlab_address}/#{imported_project.path_with_namespace}/-/(issues|merge_requests)} } + let(:event_pattern) { %r{(un)?assigned( to)? @\S+|mentioned in (issue|merge request) [!#]\d+|changed title from \*\*.*\*\* to \*\*.*\*\*} } # rubocop:disable Layout/LineLength let(:api_client) { Runtime::API::Client.as_admin } @@ -83,14 +88,14 @@ module QA let(:gh_issue_comments) do logger.debug("= Fetching issue comments =") github_client.issues_comments(github_repo).each_with_object(Hash.new { |h, k| h[k] = [] }) do |c, hash| - hash[c.html_url.gsub(/\#\S+/, "")] << c.body # use base html url as key + hash[c.html_url.gsub(/\#\S+/, "")] << c.body&.gsub(gh_link_pattern, dummy_url) # use base html url as key end end let(:gh_pr_comments) do logger.debug("= Fetching pr comments =") github_client.pull_requests_comments(github_repo).each_with_object(Hash.new { |h, k| h[k] = [] }) do |c, hash| - hash[c.html_url.gsub(/\#\S+/, "")] << c.body # use base html url as key + hash[c.html_url.gsub(/\#\S+/, "")] << c.body&.gsub(gh_link_pattern, dummy_url) # use base html url as key end end @@ -135,7 +140,7 @@ module QA target: { name: "GitLab", project_name: imported_project.path_with_namespace, - address: QA::Runtime::Scenario.gitlab_address, + address: gitlab_address, data: { branches: gl_branches.length, commits: gl_commits.length, @@ -381,15 +386,16 @@ module QA end logger.debug("Fetching comments for mr '#{mr[:title]}'") + comments = resource + .comments(auto_paginate: true, attempts: 2) + .reject { |c| c[:system] || c[:body].match?(/^(\*\*Review:\*\*)|(\*Merged by:).*/) } + [mr[:iid], { url: mr[:web_url], title: mr[:title], body: sanitize_description(mr[:description]) || '', - comments: resource - .comments(auto_paginate: true, attempts: 2) - # remove system notes - .reject { |c| c[:system] || c[:body].match?(/^(\*\*Review:\*\*)|(\*Merged by:).*/) } - .map { |c| sanitize_comment(c[:body]) } + events: events(comments), + comments: non_event_comments(comments) }] end.to_h end @@ -412,24 +418,54 @@ module QA end logger.debug("Fetching comments for issue '#{issue[:title]}'") + comments = resource.comments(auto_paginate: true, attempts: 2) + [issue[:iid], { url: issue[:web_url], title: issue[:title], body: sanitize_description(issue[:description]) || '', - comments: resource - .comments(auto_paginate: true, attempts: 2) - .map { |c| sanitize_comment(c[:body]) } + events: events(comments), + comments: non_event_comments(comments) }] end.to_h end end - # Remove added prefixes and legacy diff format from comments + # Fetch comments without events + # + # @param [Array] comments + # @return [Array] + def non_event_comments(comments) + comments + .reject { |c| c[:body].match?(event_pattern) } + .map { |c| sanitize_comment(c[:body]) } + end + + # Events + # + # @param [Array] comments + # @return [Array] + def events(comments) + comments + .select { |c| c[:body].match?(event_pattern) } + .map { |c| c[:body] } + end + + # Normalize comments and make them directly comparable + # + # * remove created by prefixes + # * unify suggestion format + # * replace github and gitlab urls - some of the links to objects get transformed to gitlab entities, some don't, + # update all links to example.com for now # # @param [String] body # @return [String] def sanitize_comment(body) - body.gsub(created_by_pattern, "").gsub(suggestion_pattern, "suggestion\r") + body + .gsub(created_by_pattern, "") + .gsub(suggestion_pattern, "suggestion\r") + .gsub(gl_link_pattern, dummy_url) + .gsub(gh_link_pattern, dummy_url) end # Remove created by prefix from descripion diff --git a/qa/qa/specs/features/api/1_manage/rate_limits_spec.rb b/qa/qa/specs/features/api/1_manage/rate_limits_spec.rb index fc221c963b1..874626e01f1 100644 --- a/qa/qa/specs/features/api/1_manage/rate_limits_spec.rb +++ b/qa/qa/specs/features/api/1_manage/rate_limits_spec.rb @@ -2,7 +2,7 @@ module QA RSpec.describe 'Manage', :requires_admin, :skip_live_env, except: { job: 'review-qa-*' } do - describe 'rate limits' do + describe 'rate limits', :reliable do let(:rate_limited_user) { Resource::User.fabricate_via_api! } let(:api_client) { Runtime::API::Client.new(:gitlab, user: rate_limited_user) } let!(:request) { Runtime::API::Request.new(api_client, '/users') } diff --git a/qa/qa/specs/features/api/1_manage/user_inherited_access_spec.rb b/qa/qa/specs/features/api/1_manage/user_inherited_access_spec.rb index faef321c89d..444d86f63d3 100644 --- a/qa/qa/specs/features/api/1_manage/user_inherited_access_spec.rb +++ b/qa/qa/specs/features/api/1_manage/user_inherited_access_spec.rb @@ -36,6 +36,7 @@ module QA it( 'is allowed to push code to sub-group project via the CLI', + :reliable, testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/363345' ) do expect do @@ -52,6 +53,7 @@ module QA it( 'is allowed to create a file in sub-group project via the API', + :reliable, testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/363348' ) do expect do @@ -68,6 +70,7 @@ module QA it( 'is allowed to commit to sub-group project via the API', + :reliable, testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/363349' ) do expect do @@ -116,6 +119,7 @@ module QA it( 'is not allowed to push code to parent group project via the CLI', + :reliable, testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/363344' ) do expect do @@ -148,6 +152,7 @@ module QA it( 'is not allowed to commit to parent group project via the API', + :reliable, testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/363342' ) do expect do diff --git a/qa/qa/specs/features/api/3_create/gitaly/changing_repository_storage_spec.rb b/qa/qa/specs/features/api/3_create/gitaly/changing_repository_storage_spec.rb index cd1b7730fa9..5ee6dfdb8d8 100644 --- a/qa/qa/specs/features/api/3_create/gitaly/changing_repository_storage_spec.rb +++ b/qa/qa/specs/features/api/3_create/gitaly/changing_repository_storage_spec.rb @@ -67,6 +67,28 @@ module QA it_behaves_like 'repository storage move' end + + # Note: This test doesn't have the :orchestrated tag because it runs in the Test::Integration::Praefect + # scenario with other tests that aren't considered orchestrated. + # It also runs on staging using nfs-file07 as non-cluster storage and nfs-file22 as cluster/praefect storage + context 'when moving from Gitaly Cluster to Gitaly', :requires_praefect, testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/369204' do + 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 + end + + before do + praefect_manager.gitlab = 'gitlab-gitaly-cluster' + end + + it_behaves_like 'repository storage move' + end end end end diff --git a/qa/qa/specs/features/api/3_create/gitaly/distributed_reads_spec.rb b/qa/qa/specs/features/api/3_create/gitaly/distributed_reads_spec.rb index 150378016e1..2b96c35415e 100644 --- a/qa/qa/specs/features/api/3_create/gitaly/distributed_reads_spec.rb +++ b/qa/qa/specs/features/api/3_create/gitaly/distributed_reads_spec.rb @@ -20,11 +20,6 @@ module QA praefect_manager.wait_for_replication(project.id) end - after do - # Leave the cluster in a suitable state for subsequent tests - praefect_manager.start_all_nodes - end - it 'reads from each node', testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347833' do pre_read_data = praefect_manager.query_read_distribution @@ -42,14 +37,12 @@ module QA context 'when a node is unhealthy' do before do - praefect_manager.start_all_nodes praefect_manager.stop_secondary_node - praefect_manager.wait_for_secondary_node_health_check_failure end after do # Leave the cluster in a suitable state for subsequent tests - praefect_manager.start_all_nodes + praefect_manager.start_secondary_node end it 'does not read from the unhealthy node', testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347834' do diff --git a/qa/qa/specs/features/api/3_create/gitaly/praefect_replication_queue_spec.rb b/qa/qa/specs/features/api/3_create/gitaly/praefect_replication_queue_spec.rb index b6296b5a263..a53614960cd 100644 --- a/qa/qa/specs/features/api/3_create/gitaly/praefect_replication_queue_spec.rb +++ b/qa/qa/specs/features/api/3_create/gitaly/praefect_replication_queue_spec.rb @@ -3,10 +3,7 @@ require 'parallel' module QA - RSpec.describe 'Create', quarantine: { - issue: 'https://gitlab.com/gitlab-org/gitlab/-/issues/361382', - type: :investigating - } do + RSpec.describe 'Create' do context 'Gitaly Cluster replication queue', :orchestrated, :gitaly_cluster, :skip_live_env do let(:praefect_manager) { Service::PraefectManager.new } let(:project) do @@ -35,6 +32,9 @@ module QA # to `in_progress`, and create a job lock for each one. queue_size_target = 10 + # During normal operations we avoid create a replication event + # https://gitlab.com/groups/gitlab-org/-/epics/7741 + praefect_manager.stop_secondary_node Git::Repository.perform do |repository| repository.uri = project.repository_http_location.uri repository.use_default_credentials @@ -46,11 +46,12 @@ module QA end repository.push_all_branches end + praefect_manager.start_secondary_node - count = 0 - while count < 1 + Support::Retrier.retry_until(max_duration: 60) do count = praefect_manager.replication_queue_lock_count QA::Runtime::Logger.debug("Lock count: #{count}") + count >= 1 end praefect_manager.stop_praefect @@ -58,12 +59,12 @@ module QA praefect_manager.start_praefect - # Create a new project, push to it, and check that replication occurs - project_push = Resource::Repository::ProjectPush.fabricate! do |push| - push.project_name = "gitaly_cluster" + # Create a new project, and check that replication occurs + new_project = Resource::Project.fabricate! do |project| + project.initialize_with_readme = true end - expect(praefect_manager.replicated?(project_push.project.id)).to be true + expect(praefect_manager.replicated?(new_project.id, new_project.name)).to be true end end end diff --git a/qa/qa/specs/features/api/3_create/gitaly/praefect_repo_sync_spec.rb b/qa/qa/specs/features/api/3_create/gitaly/praefect_repo_sync_spec.rb index e27f37abedf..47be7e0620b 100644 --- a/qa/qa/specs/features/api/3_create/gitaly/praefect_repo_sync_spec.rb +++ b/qa/qa/specs/features/api/3_create/gitaly/praefect_repo_sync_spec.rb @@ -15,7 +15,6 @@ module QA end after do - praefect_manager.start_all_nodes praefect_manager.remove_repo_from_disk(repo1["relative_path"]) praefect_manager.remove_repo_from_disk(repo2["relative_path"]) praefect_manager.remove_repository_from_praefect_database(repo1["relative_path"]) 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 new file mode 100644 index 00000000000..98612d84b21 --- /dev/null +++ b/qa/qa/specs/features/api/3_create/repository/tag_revision_trigger_prereceive_hook_spec.rb @@ -0,0 +1,32 @@ +# frozen_string_literal: true + +module QA + RSpec.describe 'Create' do + let(:project) do + Resource::Project.fabricate_via_api! do |project| + project.initialize_with_readme = true + end + end + + context 'when creating a tag for a ref' do + context 'when it triggers a prereceive hook configured with a custom error' do + before do + # The configuration test prereceive hook must match a specific naming pattern + # In this test we create a project with a different name and then change the path. + # Otherwise we wouldn't be able create any commits to be tagged due to the hook. + project.change_path("project-reject-prereceive-#{SecureRandom.hex(8)}") + end + + it 'returns a custom server hook error', + :skip_live_env, + except: { job: 'review-qa-*' }, + testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/369053' do + expect { project.create_repository_tag('v1.2.3') }.to raise_error + .with_message( + /rejecting prereceive hook for projects with GL_PROJECT_PATH matching pattern reject-prereceive/ + ) + end + end + end + end +end diff --git a/qa/qa/specs/features/api/5_package/container_registry_spec.rb b/qa/qa/specs/features/api/5_package/container_registry_spec.rb index 79384e374d7..8412c0b2872 100644 --- a/qa/qa/specs/features/api/5_package/container_registry_spec.rb +++ b/qa/qa/specs/features/api/5_package/container_registry_spec.rb @@ -3,7 +3,7 @@ require 'airborne' module QA - RSpec.describe 'Package', only: { subdomain: %i[staging pre] } do + RSpec.describe 'Package', :reliable, only: { subdomain: %i[staging staging-canary pre] } do include Support::API include Support::Helpers::MaskToken @@ -41,7 +41,7 @@ module QA stages: - build - test - + build: image: docker:19.03.12 stage: build @@ -60,7 +60,7 @@ module QA - docker build -t $IMAGE_TAG . - docker push $IMAGE_TAG - docker pull $IMAGE_TAG - + test: image: dwdraju/alpine-curl-jq:latest stage: test @@ -72,7 +72,7 @@ module QA - 'status_code=$(curl --request DELETE --head --output /dev/null --write-out "%{http_code}\n" --header "PRIVATE-TOKEN: #{masked_token}" "https://${CI_SERVER_HOST}/api/v4/projects/#{project.id}/registry/repositories/$id/tags/master")' - if [ $status_code -ne 200 ]; then exit 1; fi; - 'status_code=$(curl --head --output /dev/null --write-out "%{http_code}\n" --header "PRIVATE-TOKEN: #{masked_token}" "https://${CI_SERVER_HOST}/api/v4/projects/#{project.id}/registry/repositories/$id/tags/master")' - - if [ $status_code -ne 404 ]; then exit 1; fi; + - if [ $status_code -ne 404 ]; then exit 1; fi; YAML end diff --git a/qa/qa/specs/features/api/8_monitor/metrics_spec.rb b/qa/qa/specs/features/api/8_monitor/metrics_spec.rb new file mode 100644 index 00000000000..1235b996958 --- /dev/null +++ b/qa/qa/specs/features/api/8_monitor/metrics_spec.rb @@ -0,0 +1,50 @@ +# frozen_string_literal: true + +module QA + RSpec.describe 'GitLab Metrics', :aggregate_failures, :orchestrated, :metrics do + let(:web_uri) { URI.parse(Runtime::Scenario.gitlab_address) } + let(:endpoint) do + "#{web_uri.scheme}://#{web_uri.host}:#{port}#{path}" + end + + let(:response) { RestClient.get(endpoint) } + + describe 'Web metrics' do + describe 'via Rails controller endpoint' do + let(:port) { web_uri.port } + let(:path) { '/-/metrics' } + + it 'returns 200 OK and serves metrics', + testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/362911' do + # This does not currently work because it requires a special auth token to + # make an internal endpoint request. But we should probably test this, too. + skip + end + end + + describe 'via dedicated server' do + let(:port) { '8083' } + let(:path) { '/metrics' } + + it 'returns 200 OK and serves metrics', + testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/362912' do + expect(response.code).to be(200) + expect(response.body).to match(/^puma_/) + end + end + end + + describe 'Sidekiq metrics' do + describe 'via dedicated server' do + let(:port) { '8082' } + let(:path) { '/metrics' } + + it 'returns 200 OK and serves metrics', + testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/362913' do + expect(response.code).to be(200) + expect(response.body).to match(/^sidekiq_/) + end + end + end + end +end diff --git a/qa/qa/specs/features/browser_ui/14_product_intelligence/performance_bar_spec.rb b/qa/qa/specs/features/browser_ui/14_analytics/performance_bar_spec.rb index 10076a329bc..867c54102ae 100644 --- a/qa/qa/specs/features/browser_ui/14_product_intelligence/performance_bar_spec.rb +++ b/qa/qa/specs/features/browser_ui/14_analytics/performance_bar_spec.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true module QA - RSpec.describe 'Product Intelligence' do + RSpec.describe 'Analytics' do describe 'Performance bar display', :requires_admin, :skip_live_env do context 'when logged in as an admin user' do # performance metrics: pg, gitaly, redis, rugged (feature flagged), total (not always provided) diff --git a/qa/qa/specs/features/browser_ui/14_product_intelligence/service_ping_default_enabled_spec.rb b/qa/qa/specs/features/browser_ui/14_analytics/service_ping_default_enabled_spec.rb index cc2888063ca..7826aca3601 100644 --- a/qa/qa/specs/features/browser_ui/14_product_intelligence/service_ping_default_enabled_spec.rb +++ b/qa/qa/specs/features/browser_ui/14_analytics/service_ping_default_enabled_spec.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true module QA - RSpec.describe 'Product Intelligence' do + RSpec.describe 'Analytics' do describe 'Service ping default enabled' do context 'when using default enabled from gitlab.yml config', :requires_admin, except: { job: 'review-qa-*' } do before do diff --git a/qa/qa/specs/features/browser_ui/14_product_intelligence/service_ping_disabled_spec.rb b/qa/qa/specs/features/browser_ui/14_analytics/service_ping_disabled_spec.rb index f762adf52a1..8b30d6a7ad7 100644 --- a/qa/qa/specs/features/browser_ui/14_product_intelligence/service_ping_disabled_spec.rb +++ b/qa/qa/specs/features/browser_ui/14_analytics/service_ping_disabled_spec.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true module QA - RSpec.describe 'Product Intelligence' do + RSpec.describe 'Analytics' do describe 'Service ping disabled', :orchestrated, :service_ping_disabled, :requires_admin do context 'when disabled from gitlab.yml config' do before do diff --git a/qa/qa/specs/features/browser_ui/1_manage/group/transfer_project_spec.rb b/qa/qa/specs/features/browser_ui/1_manage/group/transfer_project_spec.rb index db02d1e8390..2c331584cf7 100644 --- a/qa/qa/specs/features/browser_ui/1_manage/group/transfer_project_spec.rb +++ b/qa/qa/specs/features/browser_ui/1_manage/group/transfer_project_spec.rb @@ -9,7 +9,7 @@ module QA end end - let(:target_group) do + let!(:target_group) do Resource::Group.fabricate_via_api! do |group| group.path = "target-group-for-transfer_#{SecureRandom.hex(8)}" end @@ -19,48 +19,39 @@ module QA Resource::Project.fabricate_via_api! do |project| project.group = source_group project.name = 'transfer-project' - project.initialize_with_readme = true end end - let(:edited_readme_content) { 'Here is the edited content.' } + let(:readme_content) { 'Here is the edited content.' } before do - Flow::Login.sign_in - - project.visit! - - Page::Project::Show.perform do |project| - project.click_file('README.md') + Resource::Repository::Commit.fabricate_via_api! do |commit| + commit.project = project + commit.add_files([ + { file_path: 'README.md', content: readme_content } + ]) end - Page::File::Show.perform(&:click_edit) + Flow::Login.sign_in - Page::File::Edit.perform do |file| - file.remove_content - file.add_content(edited_readme_content) - file.commit_changes - end + project.visit! end it 'user transfers a project between groups', testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347878' do - # Retry is needed here as the target group is not avaliable for transfer right away. - QA::Support::Retrier.retry_on_exception(reload_page: page) do - Page::File::Show.perform(&:go_to_general_settings) + Page::File::Show.perform(&:go_to_general_settings) - Page::Project::Settings::Main.perform(&:expand_advanced_settings) + Page::Project::Settings::Main.perform(&:expand_advanced_settings) - Page::Project::Settings::Advanced.perform do |advanced| - advanced.transfer_project!(project.name, target_group.full_path) - end + Page::Project::Settings::Advanced.perform do |advanced| + advanced.transfer_project!(project.name, target_group.full_path) end Page::Project::Settings::Main.perform(&:click_project) Page::Project::Show.perform do |project| expect(project).to have_breadcrumb(target_group.path) - expect(project).to have_readme_content(edited_readme_content) + expect(project).to have_readme_content(readme_content) end end end diff --git a/qa/qa/specs/features/browser_ui/1_manage/login/2fa_ssh_recovery_spec.rb b/qa/qa/specs/features/browser_ui/1_manage/login/2fa_ssh_recovery_spec.rb index f85c07001e2..6c69e4c59d9 100644 --- a/qa/qa/specs/features/browser_ui/1_manage/login/2fa_ssh_recovery_spec.rb +++ b/qa/qa/specs/features/browser_ui/1_manage/login/2fa_ssh_recovery_spec.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true module QA - context 'Manage', :requires_admin, :skip_live_env do + context 'Manage', :reliable, :requires_admin, :skip_live_env do describe '2FA' do let!(:user) { Resource::User.fabricate_via_api! } let!(:user_api_client) { Runtime::API::Client.new(:gitlab, user: user) } diff --git a/qa/qa/specs/features/browser_ui/1_manage/login/maintain_log_in_mixed_env_spec.rb b/qa/qa/specs/features/browser_ui/1_manage/login/maintain_log_in_mixed_env_spec.rb index 2c7656e20f1..1d30b915594 100644 --- a/qa/qa/specs/features/browser_ui/1_manage/login/maintain_log_in_mixed_env_spec.rb +++ b/qa/qa/specs/features/browser_ui/1_manage/login/maintain_log_in_mixed_env_spec.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true module QA - RSpec.describe 'Manage', only: { subdomain: :staging }, quarantine: { issue: 'https://gitlab.com/gitlab-org/gitlab/-/issues/344213', type: :stale } do + RSpec.describe 'Manage', only: { subdomain: %i[staging staging-canary] }, quarantine: { issue: 'https://gitlab.com/gitlab-org/gitlab/-/issues/344213', type: :stale } do describe 'basic user' do it 'remains logged in when redirected from canary to non-canary node', testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347626' do Runtime::Browser.visit(:gitlab, Page::Main::Login) diff --git a/qa/qa/specs/features/browser_ui/1_manage/login/register_spec.rb b/qa/qa/specs/features/browser_ui/1_manage/login/register_spec.rb index 85ab466078a..8cc772ed022 100644 --- a/qa/qa/specs/features/browser_ui/1_manage/login/register_spec.rb +++ b/qa/qa/specs/features/browser_ui/1_manage/login/register_spec.rb @@ -2,7 +2,7 @@ module QA RSpec.shared_examples 'registration and login' do - it 'allows the user to registers and login' do + it 'allows the user to register and login' do Runtime::Browser.visit(:gitlab, Page::Main::Login) Resource::User.fabricate_via_browser_ui! @@ -39,7 +39,7 @@ module QA end end - describe 'standard', testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347867' do + describe 'standard', :reliable, testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347867' do context 'when admin approval is not required' do before(:all) do set_require_admin_approval_after_user_signup_via_api(false) @@ -69,7 +69,7 @@ module QA Support::Waiter.wait_until(retry_on_exception: true, sleep_interval: 3) { !user.exists? } end - it 'allows recreating with same credentials', testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347868' do + it 'allows recreating with same credentials', :reliable, testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347868' do expect(Page::Main::Menu.perform(&:signed_in?)).to be_falsy Flow::Login.sign_in(as: user, skip_page_validation: true) diff --git a/qa/qa/specs/features/browser_ui/1_manage/project/create_project_badge_spec.rb b/qa/qa/specs/features/browser_ui/1_manage/project/create_project_badge_spec.rb index 3921595204c..f624f2fb44f 100644 --- a/qa/qa/specs/features/browser_ui/1_manage/project/create_project_badge_spec.rb +++ b/qa/qa/specs/features/browser_ui/1_manage/project/create_project_badge_spec.rb @@ -42,10 +42,6 @@ module QA expect(project.asset_exists?(expected_badge_image_url)).to be_truthy end end - - after do - project&.remove_via_api! - end end end end diff --git a/qa/qa/specs/features/browser_ui/1_manage/project/create_project_spec.rb b/qa/qa/specs/features/browser_ui/1_manage/project/create_project_spec.rb index 0063ce2613a..d07fff80b19 100644 --- a/qa/qa/specs/features/browser_ui/1_manage/project/create_project_spec.rb +++ b/qa/qa/specs/features/browser_ui/1_manage/project/create_project_spec.rb @@ -10,7 +10,6 @@ module QA expect(project_page).to have_content( /Project \S?#{project_name}\S+ was successfully created/ ) - expect(project_page).to have_content('create awesome project test') expect(project_page).to have_content('The repository for this project is empty') end end @@ -26,7 +25,7 @@ module QA let(:project) do Resource::Project.fabricate_via_browser_ui! do |project| project.name = project_name - project.description = 'create awesome project test' + project.description = nil end end @@ -38,17 +37,13 @@ module QA let(:project) do Resource::Project.fabricate_via_browser_ui! do |project| project.name = project_name - project.description = 'create awesome project test' project.personal_namespace = Runtime::User.username + project.description = nil end end it_behaves_like 'successful project creation' end - - after do - project.remove_via_api! - end end end end diff --git a/qa/qa/specs/features/browser_ui/1_manage/project/invite_group_to_project_spec.rb b/qa/qa/specs/features/browser_ui/1_manage/project/invite_group_to_project_spec.rb index 8201e2772aa..dbfb114dc82 100644 --- a/qa/qa/specs/features/browser_ui/1_manage/project/invite_group_to_project_spec.rb +++ b/qa/qa/specs/features/browser_ui/1_manage/project/invite_group_to_project_spec.rb @@ -2,7 +2,7 @@ module QA RSpec.describe 'Manage' do - describe 'Invite group' do + describe 'Invite group', :reliable do shared_examples 'invites group to project' do it 'verifies group is added and members can access project with correct access level' do Page::Project::Menu.perform(&:click_members) diff --git a/qa/qa/specs/features/browser_ui/1_manage/project/project_owner_permissions_spec.rb b/qa/qa/specs/features/browser_ui/1_manage/project/project_owner_permissions_spec.rb index 2f148c4051c..29e590976d2 100644 --- a/qa/qa/specs/features/browser_ui/1_manage/project/project_owner_permissions_spec.rb +++ b/qa/qa/specs/features/browser_ui/1_manage/project/project_owner_permissions_spec.rb @@ -2,7 +2,7 @@ module QA RSpec.describe 'Manage' do - describe 'Project owner permissions' do + describe 'Project owner permissions', :reliable do let!(:owner) 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/1_manage/user/impersonation_token_spec.rb b/qa/qa/specs/features/browser_ui/1_manage/user/impersonation_token_spec.rb new file mode 100644 index 00000000000..5bcea1ff094 --- /dev/null +++ b/qa/qa/specs/features/browser_ui/1_manage/user/impersonation_token_spec.rb @@ -0,0 +1,32 @@ +# frozen_string_literal: true + +module QA + RSpec.describe 'Manage' do + describe 'Impersonation tokens', :requires_admin do + let(:admin_api_client) { Runtime::API::Client.as_admin } + + let!(:user) do + Resource::User.fabricate_via_api! do |usr| + usr.api_client = admin_api_client + usr.hard_delete_on_api_removal = true + end + end + + it( + 'can be created and revoked via the UI', + testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/368888' + ) do + impersonation_token = QA::Resource::ImpersonationToken.fabricate_via_browser_ui! do |impersonation_token| + impersonation_token.api_client = admin_api_client + impersonation_token.user = user + end + + expect(impersonation_token.token).not_to be_nil + + impersonation_token.revoke_via_browser_ui! + + expect(page).to have_text("Revoked impersonation token #{impersonation_token.name}!") + end + end + end +end diff --git a/qa/qa/specs/features/browser_ui/3_create/design_management/add_design_content_spec.rb b/qa/qa/specs/features/browser_ui/2_plan/design_management/add_design_content_spec.rb index 71415c4bb57..66208921f0e 100644 --- a/qa/qa/specs/features/browser_ui/3_create/design_management/add_design_content_spec.rb +++ b/qa/qa/specs/features/browser_ui/2_plan/design_management/add_design_content_spec.rb @@ -1,12 +1,12 @@ # frozen_string_literal: true module QA - RSpec.describe 'Create', quarantine: { + RSpec.describe 'Plan', quarantine: { issue: 'https://gitlab.com/gitlab-org/gitlab/-/issues/366839', type: :test_environment, only: { job: 'review-qa-*' } } do - context 'Design Management' do + describe 'Design Management' do let(:issue) { Resource::Issue.fabricate_via_api! } let(:design_filename) { 'banana_sample.gif' } let(:design) { File.absolute_path(File.join('qa', 'fixtures', 'designs', design_filename)) } @@ -16,7 +16,8 @@ module QA Flow::Login.sign_in end - it 'user adds a design and annotates it', testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347822' do + it 'user adds a design and annotates it', + testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347822' do issue.visit! Page::Project::Issue::Show.perform do |issue| diff --git a/qa/qa/specs/features/browser_ui/3_create/design_management/archive_design_content_spec.rb b/qa/qa/specs/features/browser_ui/2_plan/design_management/archive_design_content_spec.rb index 9b969f563a2..8cbc6d7209c 100644 --- a/qa/qa/specs/features/browser_ui/3_create/design_management/archive_design_content_spec.rb +++ b/qa/qa/specs/features/browser_ui/2_plan/design_management/archive_design_content_spec.rb @@ -1,12 +1,12 @@ # frozen_string_literal: true module QA - RSpec.describe 'Create', quarantine: { + RSpec.describe 'Plan', quarantine: { issue: 'https://gitlab.com/gitlab-org/gitlab/-/issues/366839', type: :test_environment, only: { job: 'review-qa-*' } } do - context 'Design Management' do + describe 'Design Management' do let(:first_design) { Resource::Design.fabricate! } let(:second_design) do diff --git a/qa/qa/specs/features/browser_ui/3_create/design_management/modify_design_content_spec.rb b/qa/qa/specs/features/browser_ui/2_plan/design_management/modify_design_content_spec.rb index 6a0c51245ad..8f4902026d2 100644 --- a/qa/qa/specs/features/browser_ui/3_create/design_management/modify_design_content_spec.rb +++ b/qa/qa/specs/features/browser_ui/2_plan/design_management/modify_design_content_spec.rb @@ -1,12 +1,12 @@ # frozen_string_literal: true module QA - RSpec.describe 'Create', quarantine: { + RSpec.describe 'Plan', quarantine: { issue: 'https://gitlab.com/gitlab-org/gitlab/-/issues/366839', type: :test_environment, only: { job: 'review-qa-*' } } do - context 'Design Management' do + describe 'Design Management' do let(:design) do Resource::Design.fabricate_via_browser_ui! do |design| design.filename = 'testfile.png' diff --git a/qa/qa/specs/features/browser_ui/2_plan/issue/create_issue_spec.rb b/qa/qa/specs/features/browser_ui/2_plan/issue/create_issue_spec.rb index b8f1824126d..ed271533f87 100644 --- a/qa/qa/specs/features/browser_ui/2_plan/issue/create_issue_spec.rb +++ b/qa/qa/specs/features/browser_ui/2_plan/issue/create_issue_spec.rb @@ -1,11 +1,7 @@ # frozen_string_literal: true module QA - RSpec.describe( - 'Plan', - :smoke, - quarantine: { issue: 'https://gitlab.com/gitlab-com/gl-infra/production/-/issues/7099', type: :investigating, only: { subdomain: 'pre' } } - ) do + RSpec.describe 'Plan', :smoke do describe 'Issue creation' do let(:project) { Resource::Project.fabricate_via_api! } let(:closed_issue) { Resource::Issue.fabricate_via_api! { |issue| issue.project = project } } 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 36b7378ee2a..206e6b8a456 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 @@ -3,7 +3,7 @@ module QA RSpec.describe 'Plan', :reliable do describe 'Custom issue templates' do - let(:template_name) { 'custom_issue_template'} + let(:template_name) { 'custom_issue_template' } let(:template_content) { 'This is a custom issue template test' } let(:template_project) do diff --git a/qa/qa/specs/features/browser_ui/3_create/jenkins/jenkins_build_status_spec.rb b/qa/qa/specs/features/browser_ui/3_create/jenkins/jenkins_build_status_spec.rb index ea531d84634..4bfd253c992 100644 --- a/qa/qa/specs/features/browser_ui/3_create/jenkins/jenkins_build_status_spec.rb +++ b/qa/qa/specs/features/browser_ui/3_create/jenkins/jenkins_build_status_spec.rb @@ -1,8 +1,23 @@ # frozen_string_literal: true module QA - RSpec.describe 'Create', :requires_admin, :skip_live_env, quarantine: { issue: 'https://gitlab.com/gitlab-org/gitlab/-/issues/195179', type: :flaky } do + RSpec.describe 'Create', :requires_admin, :skip_live_env, except: { job: 'review-qa-*' } do describe 'Jenkins integration' do + let(:jenkins_server) { Service::DockerRun::Jenkins.new } + + let(:jenkins_client) do + Vendor::Jenkins::Client.new( + jenkins_server.host_name, + port: jenkins_server.port, + user: Runtime::Env.jenkins_admin_username, + password: Runtime::Env.jenkins_admin_password + ) + 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 @@ -13,97 +28,82 @@ module QA end end - before do - jenkins_server = run_jenkins_server + let(:access_token) do + Runtime::Env.personal_access_token ||= fabricate_access_token + end - Vendor::Jenkins::Page::Base.host = jenkins_server.host_address + before do + toggle_local_requests(true) + jenkins_server.register! - Runtime::Env.personal_access_token ||= fabricate_personal_access_token + Support::Waiter.wait_until(max_duration: 30, reload_page: false, retry_on_exception: true) do + jenkins_client.ready? + end - allow_requests_to_local_networks + configure_gitlab_jenkins + end - setup_jenkins + after do + jenkins_server&.remove! + toggle_local_requests(false) end it 'integrates and displays build status for MR pipeline in GitLab', testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347788' do - login_to_gitlab + setup_project_integration - setup_project_integration_with_jenkins + jenkins_integration = project.find_integration('jenkins') + expect(jenkins_integration).not_to be(nil), 'Jenkins integration did not save' + expect(jenkins_integration[:active]).to be(true), 'Jenkins integration is not active' - expect(page).to have_text("Jenkins settings saved and active.") + job = create_jenkins_job - QA::Support::Retrier.retry_on_exception do - Resource::Repository::ProjectPush.fabricate! do |push| - push.project = project - push.new_branch = false - push.file_name = "file_#{SecureRandom.hex(4)}.txt" - end - - Vendor::Jenkins::Page::LastJobConsole.perform do |job_console| - job_console.job_name = project_name + Resource::Repository::ProjectPush.fabricate! do |push| + push.project = project + push.new_branch = false + push.file_name = "file_#{SecureRandom.hex(4)}.txt" + end - job_console.visit! + Support::Waiter.wait_until(max_duration: 60, raise_on_failure: false, reload_page: false) do + job.status == :success + end - Support::Waiter.wait_until(sleep_interval: 2, reload_page: page) do - job_console.has_successful_build? && job_console.no_failed_status_update? - end - end + expect(job.status).to eql(:success), "Build failed or is not found: #{job.log}" - project.visit! + project.visit! - Flow::Pipeline.visit_latest_pipeline + Flow::Pipeline.visit_latest_pipeline - Page::Project::Pipeline::Show.perform do |show| - expect(show).to have_build('jenkins', status: :success, wait: 15) - end + Page::Project::Pipeline::Show.perform do |show| + expect(show).to have_build('jenkins', status: :success, wait: 15) end end - after do - remove_jenkins_server - end + private - def setup_jenkins - Vendor::Jenkins::Page::Login.perform do |login_page| - login_page.visit! - login_page.login - end - - token_description = "token-#{SecureRandom.hex(8)}" - - Vendor::Jenkins::Page::NewCredentials.perform do |new_credentials| - new_credentials.visit_and_set_gitlab_api_token(Runtime::Env.personal_access_token, token_description) - end - - Vendor::Jenkins::Page::Configure.perform do |configure| - configure.visit_and_setup_gitlab_connection(patch_host_name(Runtime::Scenario.gitlab_address, 'gitlab'), token_description) do - configure.click_test_connection - expect(configure).to have_success - end - end + def setup_project_integration + login_to_gitlab - Vendor::Jenkins::Page::NewJob.perform do |new_job| - new_job.visit_and_create_new_job_with_name(project_name) - end + project.visit! - Vendor::Jenkins::Page::ConfigureJob.perform do |configure_job| - configure_job.job_name = project_name - configure_job.configure(scm_url: patch_host_name(project.repository_http_location.git_uri, 'gitlab')) - end - end + Page::Project::Menu.perform(&:click_project) + Page::Project::Menu.perform(&:go_to_integrations_settings) + Page::Project::Settings::Integrations.perform(&:click_jenkins_ci_link) - def run_jenkins_server - Service::DockerRun::Jenkins.new.tap do |runner| - runner.pull - runner.register! + QA::Page::Project::Settings::Services::Jenkins.perform do |jenkins| + jenkins.setup_service_with( + jenkins_url: patch_host_name(jenkins_server.host_address, 'jenkins-server'), + project_name: jenkins_project_name, + username: jenkins_server.username, + password: jenkins_server.password + ) end end - def remove_jenkins_server - Service::DockerRun::Jenkins.new.remove! + def login_to_gitlab + Flow::Login.sign_in end - def fabricate_personal_access_token + def fabricate_access_token login_to_gitlab token = Resource::PersonalAccessToken.fabricate!.token @@ -111,8 +111,23 @@ module QA token end - def login_to_gitlab - Flow::Login.sign_in + def create_jenkins_job + jenkins_client.create_job jenkins_project_name do |job| + job.gitlab_connection = connection_name + job.description = 'Just a job' + job.repo_url = patch_host_name(project.repository_http_location.git_uri, 'gitlab') + job.shell_command = 'sleep 5' + end + end + + def configure_gitlab_jenkins + jenkins_client.configure_gitlab_plugin( + patch_host_name(Runtime::Scenario.gitlab_address, 'gitlab'), + connection_name: connection_name, + access_token: access_token, + read_timeout: 20, + connection_timeout: 10 + ) end def patch_host_name(host_name, container_name) @@ -122,32 +137,8 @@ module QA host_name.gsub('localhost', ip_address) end - def setup_project_integration_with_jenkins - project.visit! - - Page::Project::Menu.perform(&:click_project) - Page::Project::Menu.perform(&:go_to_integrations_settings) - Page::Project::Settings::Integrations.perform(&:click_jenkins_ci_link) - - QA::Page::Project::Settings::Services::Jenkins.perform do |jenkins| - jenkins.setup_service_with(jenkins_url: patch_host_name(Vendor::Jenkins::Page::Base.host, 'jenkins-server'), - project_name: project_name) - end - end - - def allow_requests_to_local_networks - Page::Main::Menu.perform(&:sign_out_if_signed_in) - Flow::Login.sign_in_as_admin - Page::Main::Menu.perform(&:go_to_admin_area) - Page::Admin::Menu.perform(&:go_to_network_settings) - - Page::Admin::Settings::Network.perform do |network| - network.expand_outbound_requests do |outbound_requests| - outbound_requests.allow_requests_to_local_network_from_services - end - end - - Page::Main::Menu.perform(&:sign_out) + def toggle_local_requests(on) + Runtime::ApplicationSettings.set_application_settings(allow_local_requests_from_web_hooks_and_services: on) end end end diff --git a/qa/qa/specs/features/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 3373f4f4233..6ce4217f8ac 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 @@ -3,7 +3,7 @@ module QA RSpec.describe 'Create', :reliable do describe 'Merge request custom templates' do - let(:template_name) { 'custom_merge_request_template'} + 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| 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 d73fb57a581..aa637ac4d55 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 @@ -52,7 +52,12 @@ module QA merge_request.click_commits_tab - expect(merge_request).to have_content(commit_message) + # Commit does not always display immediately and may require a page refresh + # Issue: https://gitlab.com/gitlab-org/gitlab/-/issues/368735 + # TODO: Remove page refresh logic once issue is resolved. + Support::Retrier.retry_on_exception(max_attempts: 2, reload_page: merge_request) do + expect(merge_request).to have_content(commit_message) + end end end end diff --git a/qa/qa/specs/features/browser_ui/6_release/pages/pages_pipeline_spec.rb b/qa/qa/specs/features/browser_ui/3_create/pages/pages_pipeline_spec.rb index d1d2340e5f1..191c4a096e7 100644 --- a/qa/qa/specs/features/browser_ui/6_release/pages/pages_pipeline_spec.rb +++ b/qa/qa/specs/features/browser_ui/3_create/pages/pages_pipeline_spec.rb @@ -31,7 +31,8 @@ module QA pipeline.visit! end - it 'runs a Pages-specific pipeline', testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347669' do + it('runs a Pages-specific pipeline', + testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347669') do Page::Project::Pipeline::Show.perform do |show| expect(show).to have_job(:pages) show.click_job(:pages) diff --git a/qa/qa/specs/features/browser_ui/3_create/repository/license_detecton_spec.rb b/qa/qa/specs/features/browser_ui/3_create/repository/license_detecton_spec.rb index 8074e1fa992..3db8128bc6d 100644 --- a/qa/qa/specs/features/browser_ui/3_create/repository/license_detecton_spec.rb +++ b/qa/qa/specs/features/browser_ui/3_create/repository/license_detecton_spec.rb @@ -28,16 +28,16 @@ module QA context 'on a project with a commonly used LICENSE', testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/366842' do it_behaves_like 'project license detection' do - let(:license_file_name) {'bsd-3-clause'} - let(:rendered_license_name) {'BSD 3-Clause "New" or "Revised" License'} + let(:license_file_name) { 'bsd-3-clause' } + let(:rendered_license_name) { 'BSD 3-Clause "New" or "Revised" License' } end end context 'on a project with a less commonly used LICENSE', testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/366843' do it_behaves_like 'project license detection' do - let(:license_file_name) {'GFDL-1.2-only'} - let(:rendered_license_name) {'Other'} + let(:license_file_name) { 'GFDL-1.2-only' } + let(:rendered_license_name) { 'Other' } end end end diff --git a/qa/qa/specs/features/browser_ui/1_manage/project/protected_tags_spec.rb b/qa/qa/specs/features/browser_ui/3_create/repository/protected_tags_spec.rb index f6448fea2d4..fb87ca864f4 100644 --- a/qa/qa/specs/features/browser_ui/1_manage/project/protected_tags_spec.rb +++ b/qa/qa/specs/features/browser_ui/3_create/repository/protected_tags_spec.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true module QA - RSpec.describe 'Manage' do + RSpec.describe 'Create' do describe 'Repository tags', :reliable do let(:project) do Resource::Project.fabricate_via_api! do |project| @@ -104,11 +104,8 @@ module QA end def add_members_to_project(project) - @developer_user = developer_user - @maintainer_user = maintainer_user - - project.add_member(@developer_user, Resource::Members::AccessLevel::DEVELOPER) - project.add_member(@maintainer_user, Resource::Members::AccessLevel::MAINTAINER) + project.add_member(developer_user, Resource::Members::AccessLevel::DEVELOPER) + project.add_member(maintainer_user, Resource::Members::AccessLevel::MAINTAINER) end end end 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 f374ecff3f2..55df1615f5c 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 @@ -3,7 +3,8 @@ module QA RSpec.describe 'Create' do describe 'SSH keys support', :smoke do - key_title = "key for ssh tests #{Time.now.to_f}" + let(:key_title) { "key for ssh tests #{Time.now.to_f}" } + key = nil before do diff --git a/qa/qa/specs/features/browser_ui/3_create/snippet/create_personal_snippet_spec.rb b/qa/qa/specs/features/browser_ui/3_create/snippet/create_personal_snippet_spec.rb index b4519327a62..620e6870b26 100644 --- a/qa/qa/specs/features/browser_ui/3_create/snippet/create_personal_snippet_spec.rb +++ b/qa/qa/specs/features/browser_ui/3_create/snippet/create_personal_snippet_spec.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true module QA - RSpec.describe 'Create', :smoke, quarantine: { issue: 'https://gitlab.com/gitlab-org/gitlab/-/issues/326624', type: :investigating } do + RSpec.describe 'Create', :smoke do describe 'Personal snippet creation' do let(:snippet) do Resource::Snippet.fabricate_via_browser_ui! do |snippet| 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 new file mode 100644 index 00000000000..f95f624d59a --- /dev/null +++ b/qa/qa/specs/features/browser_ui/3_create/source_editor/source_editor_toolbar_spec.rb @@ -0,0 +1,55 @@ +# frozen_string_literal: true +# tagged transient due to feature-flag caching flakiness. Remove tag along with feature flag removal. +module QA + RSpec.describe 'Create', feature_flag: { name: 'source_editor_toolbar', scope: :global } do + describe 'Source editor toolbar preview' 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(:edited_readme_content) { 'Here is the edited content.' } + + before do + Runtime::Feature.enable(:source_editor_toolbar) + Flow::Login.sign_in + end + + after do + Runtime::Feature.disable(:source_editor_toolbar) + end + + it 'can preview markdown side-by-side while editing', + testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/367749' do + project.visit! + Page::Project::Show.perform do |project| + project.click_file('README.md') + end + + Page::File::Show.perform(&:click_edit) + + # wait_until required due to feature_caching. Remove along with feature flag removal. + Page::File::Edit.perform do |file| + Support::Waiter.wait_until(sleep_interval: 2, max_duration: 60, reload_page: page, + retry_on_exception: true) do + expect(file).to have_element(:editor_toolbar_button) + end + file.remove_content + file.click_editor_toolbar + file.add_content('# ' + edited_readme_content) + file.wait_for_markdown_preview('h1', edited_readme_content) + file.commit_changes + end + + Page::File::Show.perform do |file| + aggregate_failures 'file details' do + expect(file).to have_notice('Your changes have been successfully committed.') + expect(file).to have_file_content(edited_readme_content) + end + end + end + end + end +end diff --git a/qa/qa/specs/features/browser_ui/4_verify/pipeline/pipeline_editor_lint_spec.rb b/qa/qa/specs/features/browser_ui/4_verify/pipeline/pipeline_editor_tabs_spec.rb index 02ee94381b2..bef15b46fcd 100644 --- a/qa/qa/specs/features/browser_ui/4_verify/pipeline/pipeline_editor_lint_spec.rb +++ b/qa/qa/specs/features/browser_ui/4_verify/pipeline/pipeline_editor_tabs_spec.rb @@ -2,12 +2,7 @@ module QA RSpec.describe 'Verify' do - # TODO: Remove this test when feature flag is removed - # Flag rollout issue https://gitlab.com/gitlab-org/gitlab/-/issues/364257 - describe 'Pipeline editor', :reliable, feature_flag: { - name: :simulate_pipeline, - scope: :global - } do + describe 'Pipeline editor', :reliable do let(:project) do Resource::Project.fabricate_via_api! do |project| project.name = 'pipeline-editor-project' @@ -42,19 +37,20 @@ module QA end before do - Runtime::Feature.disable(:simulate_pipeline) if Runtime::Feature.enabled?(:simulate_pipeline) + # Make sure a pipeline is created before visiting pipeline editor page. + # Otherwise, test might timeout before the page finishing fetching pipeline status. + Support::Waiter.wait_until { project.pipelines.present? } Flow::Login.sign_in project.visit! Page::Project::Menu.perform(&:go_to_pipeline_editor) end - after do - project&.remove_via_api! - end - context 'when CI has valid syntax' do - it 'shows valid validations', testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/349128' do + it( + 'shows valid validations', + testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/368332' + ) do Page::Project::PipelineEditor::Show.perform do |show| aggregate_failures do expect(show.ci_syntax_validate_message).to have_content('Pipeline syntax is correct') @@ -65,8 +61,9 @@ module QA expect(show).to have_job(job), "Pipeline graph does not have job #{job}." end - show.go_to_lint_tab - expect(show.tab_alert_message).to have_content('Syntax is correct') + show.go_to_validate_tab + show.simulate_pipeline + expect(show.tab_alert_title).to have_content('Simulation completed successfully') show.go_to_view_merged_yaml_tab expect(show).to have_source_editor @@ -76,7 +73,10 @@ module QA end context 'when CI has invalid syntax' do - it 'shows invalid validations', testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/349129' do + it( + 'shows invalid validations', + testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/368333' + ) do invalid_msg = 'syntax is invalid' Page::Project::PipelineEditor::Show.perform do |show| @@ -86,8 +86,9 @@ module QA show.go_to_visualize_tab expect(show.tab_alert_message).to have_content(invalid_msg) - show.go_to_lint_tab - expect(show.tab_alert_message).to have_content('Syntax is incorrect') + show.go_to_validate_tab + show.simulate_pipeline + expect(show.tab_alert_title).to have_content('Pipeline simulation completed with errors') show.go_to_view_merged_yaml_tab expect(show.tab_alert_message).to have_content(invalid_msg) 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 new file mode 100644 index 00000000000..412498476f0 --- /dev/null +++ b/qa/qa/specs/features/browser_ui/4_verify/pipeline/pipeline_with_image_pull_policy_spec.rb @@ -0,0 +1,175 @@ +# frozen_string_literal: true + +module QA + # TODO: remove feature flag upon rollout completion + # FF rollout issue: https://gitlab.com/gitlab-org/gitlab/-/issues/363186 + RSpec.describe 'Verify', :runner, feature_flag: { + name: 'ci_docker_image_pull_policy', + scope: :global + } do + describe 'Pipeline with image:pull_policy' do + let(:runner_name) { "qa-runner-#{Faker::Alphanumeric.alphanumeric(number: 8)}" } + let(:job_name) { "test-job-#{pull_policies.join('-')}" } + + let(:project) do + Resource::Project.fabricate_via_api! do |project| + project.name = 'pipeline-with-image-pull-policy' + end + end + + let!(:runner) do + Resource::Runner.fabricate! do |runner| + runner.project = project + runner.name = runner_name + runner.tags = [runner_name] + runner.executor = :docker + end + end + + before do + Runtime::Feature.enable(:ci_docker_image_pull_policy) + # Give the feature some time to switch + sleep(30) + + update_runner_policy(allowed_policies) + add_ci_file + Flow::Login.sign_in + project.visit! + Flow::Pipeline.visit_latest_pipeline + end + + after do + Runtime::Feature.disable(:ci_docker_image_pull_policy) + + runner.remove_via_api! + end + + context 'when policy is allowed' do + let(:allowed_policies) { %w[if-not-present always never] } + + where do + { + 'with [always] policy' => { + pull_policies: %w[always], + pull_image: true, + message: 'Pulling docker image ruby:2.6', + testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/367154' + }, + 'with [always if-not-present] policies' => { + pull_policies: %w[always if-not-present], + pull_image: true, + message: 'Pulling docker image ruby:2.6', + testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/368857' + }, + 'with [if-not-present] policy' => { + pull_policies: %w[if-not-present], + pull_image: true, + message: 'Using locally found image version due to "if-not-present" pull policy', + testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/368858' + }, + 'with [never] policy' => { + pull_policies: %w[never], + pull_image: false, + message: 'Pulling docker image', + testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/368859' + } + } + end + + with_them do + it 'applies pull policy in job correctly', testcase: params[:testcase] do + visit_job + + if pull_image + expect(job_log).to have_content(message), + "Expected to find #{message} in #{job_log}, but didn't." + else + expect(job_log).not_to have_content(message), + "Found #{message} in #{job_log}, but didn't expect to." + end + end + end + end + + context 'when policy is not allowed' do + let(:allowed_policies) { %w[never] } + let(:pull_policies) { %w[always] } + + let(:message) do + 'ERROR: Preparation failed: the configured PullPolicies ([always])'\ + ' are not allowed by AllowedPullPolicies ([never])' + end + + it( + 'fails job with policy not allowed message', + testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/368853' + ) do + visit_job + + expect(job_log).to have_content(message), + "Expected to find #{message} in #{job_log}, but didn't." + end + end + + private + + def update_runner_policy(allowed_policies) + Runtime::Logger.info('Updating runner config to allow pull policies...') + + # Copy config.toml file from docker to local + # Update local file with allowed_pull_policies config + # Copy file with new content back to docker + tempdir = Tempfile.new('config.toml') + QA::Service::Shellout.shell("docker cp #{runner_name}:/etc/gitlab-runner/config.toml #{tempdir.path}") + + File.open(tempdir.path, 'a') do |f| + f << %Q[ allowed_pull_policies = #{allowed_policies}\n] + end + + QA::Service::Shellout.shell("docker cp #{tempdir.path} #{runner_name}:/etc/gitlab-runner/config.toml") + + tempdir.close! + + # Give runner some time to pick up new configuration + sleep(30) + end + + def add_ci_file + Resource::Repository::Commit.fabricate_via_api! do |commit| + commit.project = project + commit.commit_message = 'Add .gitlab-ci.yml' + commit.add_files( + [ + { + file_path: '.gitlab-ci.yml', + content: <<~YAML + default: + image: ruby:2.6 + tags: [#{runner_name}] + + #{job_name}: + script: echo "Using pull policies #{pull_policies}" + image: + name: ruby:2.6 + pull_policy: #{pull_policies} + YAML + } + ] + ) + end + end + + def visit_job + Page::Project::Pipeline::Show.perform do |show| + Support::Waiter.wait_until { show.completed? } + + show.click_job(job_name) + end + end + + def job_log + Page::Project::Job::Show.perform(&:output) + end + end + end +end diff --git a/qa/qa/specs/features/browser_ui/5_package/container_registry/container_registry_spec.rb b/qa/qa/specs/features/browser_ui/5_package/container_registry/container_registry_spec.rb index 6918c087a4e..5a29b44e8b3 100644 --- a/qa/qa/specs/features/browser_ui/5_package/container_registry/container_registry_spec.rb +++ b/qa/qa/specs/features/browser_ui/5_package/container_registry/container_registry_spec.rb @@ -2,7 +2,7 @@ module QA RSpec.describe 'Package' do - describe 'Container Registry', :reliable, only: { subdomain: %i[staging pre] } do + describe 'Container Registry', only: { subdomain: %i[staging staging-canary pre] } do let(:project) do Resource::Project.fabricate_via_api! do |project| project.name = 'project-with-registry' @@ -37,7 +37,7 @@ module QA do docker info && break sleep 1s - done + done script: - docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY - docker build -t $IMAGE_TAG . 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 d9d75a8ae7a..ad820977747 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 @@ -4,6 +4,7 @@ module QA RSpec.describe 'Package', :orchestrated, :registry, only: { pipeline: :main } do describe 'Dependency Proxy' do using RSpec::Parameterized::TableSyntax + include Support::Helpers::MaskToken let(:project) do Resource::Project.fabricate_via_api! do |project| @@ -21,6 +22,19 @@ module QA end end + let(:group_deploy_token) do + Resource::GroupDeployToken.fabricate_via_api! do |deploy_token| + deploy_token.name = 'dp-group-deploy-token' + deploy_token.group = project.group + deploy_token.scopes = %w[ + read_registry + write_registry + ] + end + end + + 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(:dependency_proxy_url) { "#{gitlab_host_with_port}/#{project.group.full_path}/dependency_proxy/containers" } @@ -43,12 +57,92 @@ module QA runner.remove_via_api! end - where(:case_name, :docker_client_version, :testcase) do - 'using docker:19.03.12' | 'docker:19.03.12' | 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347605' - 'using docker:20.10' | 'docker:20.10' | 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347604' + where do + { + 'using docker:18.09.9 and a personal access token' => { + docker_client_version: 'docker:18.09.9', + authentication_token_type: :personal_access_token, + token_name: 'Personal Access Token', + testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/370195' + }, + 'using docker:18.09.9 and a group deploy token' => { + docker_client_version: 'docker:18.09.9', + authentication_token_type: :group_deploy_token, + token_name: 'Deploy Token', + testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/370196' + }, + 'using docker:18.09.9 and a ci job token' => { + docker_client_version: 'docker:18.09.9', + authentication_token_type: :ci_job_token, + token_name: 'Job Token', + testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/370198' + }, + 'using docker:19.03.12 and a personal access token' => { + docker_client_version: 'docker:19.03.12', + authentication_token_type: :personal_access_token, + token_name: 'Personal Access Token', + testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/370189' + }, + 'using docker:19.03.12 and a group deploy token' => { + docker_client_version: 'docker:19.03.12', + authentication_token_type: :group_deploy_token, + token_name: 'Deploy Token', + testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/370190' + }, + 'using docker:19.03.12 and a ci job token' => { + docker_client_version: 'docker:19.03.12', + authentication_token_type: :ci_job_token, + token_name: 'Job Token', + testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/370191' + }, + 'using docker:20.10 and a personal access token' => { + docker_client_version: 'docker:20.10', + authentication_token_type: :personal_access_token, + token_name: 'Personal Access Token', + testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/370192' + }, + 'using docker:20.10 and a group deploy token' => { + docker_client_version: 'docker:20.10', + authentication_token_type: :group_deploy_token, + token_name: 'Deploy Token', + testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/370193' + }, + 'using docker:20.10 and a ci job token' => { + docker_client_version: 'docker:20.10', + authentication_token_type: :ci_job_token, + token_name: 'Job Token', + testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/370194' + } + } 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 :group_deploy_token + use_group_ci_variable( + name: "GROUP_DEPLOY_TOKEN_#{group_deploy_token.id}", + value: group_deploy_token.token, + group: project.group + ) + when :ci_job_token + '$CI_JOB_TOKEN' + end + end + + let(:auth_user) do + case authentication_token_type + when :personal_access_token + "$CI_REGISTRY_USER" + when :group_deploy_token + "\"#{group_deploy_token.username}\"" + when :ci_job_token + 'gitlab-ci-token' + end + end + it "pulls an image using the dependency proxy", testcase: params[:testcase] do Support::Retrier.retry_on_exception(max_attempts: 3, sleep_interval: 2) do Resource::Repository::Commit.fabricate_via_api! do |commit| @@ -65,8 +159,7 @@ module QA command: ["--insecure-registry=gitlab.test:80"] before_script: - apk add curl jq grep - - echo $CI_DEPENDENCY_PROXY_SERVER - - docker login -u "$CI_DEPENDENCY_PROXY_USER" -p "$CI_DEPENDENCY_PROXY_PASSWORD" gitlab.test:80 + - docker login -u #{auth_user} -p #{auth_token} gitlab.test:80 script: - docker pull #{dependency_proxy_url}/#{image_sha} - TOKEN=$(curl "https://auth.docker.io/token?service=registry.docker.io&scope=repository:ratelimitpreview/test:pull" | jq --raw-output .token) 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 980c6da2576..608dd7e089f 100644 --- a/qa/qa/specs/features/browser_ui/7_configure/auto_devops/auto_devops_templates_spec.rb +++ b/qa/qa/specs/features/browser_ui/7_configure/auto_devops/auto_devops_templates_spec.rb @@ -2,7 +2,7 @@ module QA RSpec.describe 'Configure' do - describe 'AutoDevOps Templates', only: { subdomain: :staging } do + describe 'AutoDevOps Templates', only: { subdomain: %i[staging staging-canary] } do using RSpec::Parameterized::TableSyntax # specify jobs to be disabled in the pipeline. diff --git a/qa/qa/specs/features/browser_ui/7_configure/auto_devops/create_project_with_auto_devops_spec.rb b/qa/qa/specs/features/browser_ui/7_configure/auto_devops/create_project_with_auto_devops_spec.rb index dca6f961047..f1a2eb71390 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 @@ -2,7 +2,7 @@ module QA RSpec.describe 'Configure', - only: { subdomain: :staging }, + only: { subdomain: %i[staging staging-canary] }, quarantine: { issue: 'https://gitlab.com/gitlab-org/quality/team-tasks/-/issues/1198', type: :waiting_on diff --git a/qa/qa/specs/features/sanity/feature_flags_spec.rb b/qa/qa/specs/features/sanity/feature_flags_spec.rb index f771978802e..acb9528fe6a 100644 --- a/qa/qa/specs/features/sanity/feature_flags_spec.rb +++ b/qa/qa/specs/features/sanity/feature_flags_spec.rb @@ -26,7 +26,7 @@ module QA end let(:flag) { Pathname.new(file.path).basename('.yml').to_s } - let(:root) { '..'} + let(:root) { '..' } before do definition = <<~YAML @@ -78,7 +78,7 @@ module QA end context 'with an EE feature flag' do - let(:root) { '../ee'} + let(:root) { '../ee' } include_examples 'gets flag value' end |