Commit 846761fb authored by Dan Davison's avatar Dan Davison

Merge branch 'ml-add-merge-trains-transient-bug-test' into 'master'

Add merge trains transient bug test

See merge request gitlab-org/gitlab!51281
parents 0ef98e28 c4bdba47
...@@ -14,31 +14,32 @@ This is a partial list of the [RSpec metadata](https://relishapp.com/rspec/rspec ...@@ -14,31 +14,32 @@ This is a partial list of the [RSpec metadata](https://relishapp.com/rspec/rspec
| Tag | Description | | Tag | Description |
|-----|-------------| |-----|-------------|
| `:elasticsearch` | The test requires an Elasticsearch service. It is used by the [instance-level scenario](https://gitlab.com/gitlab-org/gitlab-qa#definitions) [`Test::Integration::Elasticsearch`](https://gitlab.com/gitlab-org/gitlab/-/blob/72b62b51bdf513e2936301cb6c7c91ec27c35b4d/qa/qa/ee/scenario/test/integration/elasticsearch.rb) to include only tests that require Elasticsearch. | | `:elasticsearch` | The test requires an Elasticsearch service. It is used by the [instance-level scenario](https://gitlab.com/gitlab-org/gitlab-qa#definitions) [`Test::Integration::Elasticsearch`](https://gitlab.com/gitlab-org/gitlab/-/blob/72b62b51bdf513e2936301cb6c7c91ec27c35b4d/qa/qa/ee/scenario/test/integration/elasticsearch.rb) to include only tests that require Elasticsearch. |
| `:geo` | The test requires two GitLab Geo instances - a primary and a secondary - to be spun up. |
| `:gitaly_cluster` | The test runs against a GitLab instance where repositories are stored on redundant Gitaly nodes behind a Praefect node. All nodes are [separate containers](../../../administration/gitaly/praefect.md#requirements-for-configuring-a-gitaly-cluster). Tests that use this tag have a longer setup time since there are three additional containers that need to be started. | | `:gitaly_cluster` | The test runs against a GitLab instance where repositories are stored on redundant Gitaly nodes behind a Praefect node. All nodes are [separate containers](../../../administration/gitaly/praefect.md#requirements-for-configuring-a-gitaly-cluster). Tests that use this tag have a longer setup time since there are three additional containers that need to be started. |
| `:github` | The test requires a GitHub personal access token. |
| `:group_saml` | The test requires a GitLab instance that has SAML SSO enabled at the group level. Interacts with an external SAML identity provider. Paired with the `:orchestrated` tag. |
| `:instance_saml` | The test requires a GitLab instance that has SAML SSO enabled at the instance level. Interacts with an external SAML identity provider. Paired with the `:orchestrated` tag. |
| `:jira` | The test requires a Jira Server. [GitLab-QA](https://gitlab.com/gitlab-org/gitlab-qa) provisions the Jira Server in a Docker container when the `Test::Integration::Jira` test scenario is run. | `:jira` | The test requires a Jira Server. [GitLab-QA](https://gitlab.com/gitlab-org/gitlab-qa) provisions the Jira Server in a Docker container when the `Test::Integration::Jira` test scenario is run.
| `:kubernetes` | The test includes a GitLab instance that is configured to be run behind an SSH tunnel, allowing a TLS-accessible GitLab. This test also includes provisioning of at least one Kubernetes cluster to test against. _This tag is often be paired with `:orchestrated`._ | | `:kubernetes` | The test includes a GitLab instance that is configured to be run behind an SSH tunnel, allowing a TLS-accessible GitLab. This test also includes provisioning of at least one Kubernetes cluster to test against. _This tag is often be paired with `:orchestrated`._ |
| `:ldap_no_server` | The test requires a GitLab instance to be configured to use LDAP. To be used with the `:orchestrated` tag. It does not spin up an LDAP server at orchestration time. Instead, it creates the LDAP server at runtime. |
| `:ldap_no_tls` | The test requires a GitLab instance to be configured to use an external LDAP server with TLS not enabled. |
| `:ldap_tls` | The test requires a GitLab instance to be configured to use an external LDAP server with TLS enabled. |
| `:mattermost` | The test requires a GitLab Mattermost service on the GitLab instance. |
| `:object_storage` | The test requires a GitLab instance to be configured to use multiple [object storage types](../../../administration/object_storage.md). Uses MinIO as the object storage server. |
| `:only` | The test is only to be run against specific environments or pipelines. See [Environment selection](environment_selection.md) for more information. | | `:only` | The test is only to be run against specific environments or pipelines. See [Environment selection](environment_selection.md) for more information. |
| `:orchestrated` | The GitLab instance under test may be [configured by `gitlab-qa`](https://gitlab.com/gitlab-org/gitlab-qa/-/blob/master/docs/what_tests_can_be_run.md#orchestrated-tests) to be different to the default GitLab configuration, or `gitlab-qa` may launch additional services in separate Docker containers, or both. Tests tagged with `:orchestrated` are excluded when testing environments where we can't dynamically modify the GitLab configuration (for example, Staging). | | `:orchestrated` | The GitLab instance under test may be [configured by `gitlab-qa`](https://gitlab.com/gitlab-org/gitlab-qa/-/blob/master/docs/what_tests_can_be_run.md#orchestrated-tests) to be different to the default GitLab configuration, or `gitlab-qa` may launch additional services in separate Docker containers, or both. Tests tagged with `:orchestrated` are excluded when testing environments where we can't dynamically modify the GitLab configuration (for example, Staging). |
| `:packages` | The test requires a GitLab instance that has the [Package Registry](../../../administration/packages/#gitlab-package-registry-administration) enabled. |
| `:quarantine` | The test has been [quarantined](https://about.gitlab.com/handbook/engineering/quality/guidelines/debugging-qa-test-failures/#quarantining-tests), runs in a separate job that only includes quarantined tests, and is allowed to fail. The test is skipped in its regular job so that if it fails it doesn't hold up the pipeline. Note that you can also [quarantine a test only when it runs against specific environment](environment_selection.md#quarantining-a-test-for-a-specific-environment). | | `:quarantine` | The test has been [quarantined](https://about.gitlab.com/handbook/engineering/quality/guidelines/debugging-qa-test-failures/#quarantining-tests), runs in a separate job that only includes quarantined tests, and is allowed to fail. The test is skipped in its regular job so that if it fails it doesn't hold up the pipeline. Note that you can also [quarantine a test only when it runs against specific environment](environment_selection.md#quarantining-a-test-for-a-specific-environment). |
| `:relative_url` | The test requires a GitLab instance to be installed under a [relative URL](../../../install/relative_url.md). |
| `:reliable` | The test has been [promoted to a reliable test](https://about.gitlab.com/handbook/engineering/quality/guidelines/reliable-tests/#promoting-an-existing-test-to-reliable) meaning it passes consistently in all pipelines, including merge requests. | | `:reliable` | The test has been [promoted to a reliable test](https://about.gitlab.com/handbook/engineering/quality/guidelines/reliable-tests/#promoting-an-existing-test-to-reliable) meaning it passes consistently in all pipelines, including merge requests. |
| `:repository_storage` | The test requires a GitLab instance to be configured to use multiple [repository storage paths](../../../administration/repository_storage_paths.md). Paired with the `:orchestrated` tag. |
| `:requires_admin` | The test requires an admin account. Tests with the tag are excluded when run against Canary and Production environments. | | `:requires_admin` | The test requires an admin account. Tests with the tag are excluded when run against Canary and Production environments. |
| `:requires_git_protocol_v2` | The test requires that Git protocol version 2 is enabled on the server. It's assumed to be enabled by default but if not the test can be skipped by setting `QA_CAN_TEST_GIT_PROTOCOL_V2` to `false`. |
| `:requires_praefect` | The test requires that the GitLab instance uses [Gitaly Cluster](../../../administration/gitaly/praefect.md) (a.k.a. Praefect) as the repository storage . It's assumed to be used by default but if not the test can be skipped by setting `QA_CAN_TEST_PRAEFECT` to `false`. |
| `:runner` | The test depends on and sets up a GitLab Runner instance, typically to run a pipeline. | | `:runner` | The test depends on and sets up a GitLab Runner instance, typically to run a pipeline. |
| `:skip_live_env` | The test is excluded when run against live deployed environments such as Staging, Canary, and Production. | | `:skip_live_env` | The test is excluded when run against live deployed environments such as Staging, Canary, and Production. |
| `:testcase` | The link to the test case issue in the [Quality Testcases project](https://gitlab.com/gitlab-org/quality/testcases/). |
| `:mattermost` | The test requires a GitLab Mattermost service on the GitLab instance. |
| `:ldap_no_server` | The test requires a GitLab instance to be configured to use LDAP. To be used with the `:orchestrated` tag. It does not spin up an LDAP server at orchestration time. Instead, it creates the LDAP server at runtime. |
| `:ldap_no_tls` | The test requires a GitLab instance to be configured to use an external LDAP server with TLS not enabled. |
| `:ldap_tls` | The test requires a GitLab instance to be configured to use an external LDAP server with TLS enabled. |
| `:object_storage` | The test requires a GitLab instance to be configured to use multiple [object storage types](../../../administration/object_storage.md). Uses MinIO as the object storage server. |
| `:smtp` | The test requires a GitLab instance to be configured to use an SMTP server. Tests SMTP notification email delivery from GitLab by using MailHog. |
| `:group_saml` | The test requires a GitLab instance that has SAML SSO enabled at the group level. Interacts with an external SAML identity provider. Paired with the `:orchestrated` tag. |
| `:instance_saml` | The test requires a GitLab instance that has SAML SSO enabled at the instance level. Interacts with an external SAML identity provider. Paired with the `:orchestrated` tag. |
| `:skip_signup_disabled` | The test uses UI to sign up a new user and is skipped in any environment that does not allow new user registration via the UI. | | `:skip_signup_disabled` | The test uses UI to sign up a new user and is skipped in any environment that does not allow new user registration via the UI. |
| `:smoke` | The test belongs to the test suite which verifies basic functionality of a GitLab instance.| | `:smoke` | The test belongs to the test suite which verifies basic functionality of a GitLab instance.|
| `:github` | The test requires a GitHub personal access token. | | `:smtp` | The test requires a GitLab instance to be configured to use an SMTP server. Tests SMTP notification email delivery from GitLab by using MailHog. |
| `:repository_storage` | The test requires a GitLab instance to be configured to use multiple [repository storage paths](../../../administration/repository_storage_paths.md). Paired with the `:orchestrated` tag. | | `:testcase` | The link to the test case issue in the [Quality Testcases project](https://gitlab.com/gitlab-org/quality/testcases/). |
| `:geo` | The test requires two GitLab Geo instances - a primary and a secondary - to be spun up. | | `:transient` | The test tests transient bugs. It is excluded by default. |
| `:relative_url` | The test requires a GitLab instance to be installed under a [relative URL](../../../install/relative_url.md). |
| `:requires_git_protocol_v2` | The test requires that Git protocol version 2 is enabled on the server. It's assumed to be enabled by default but if not the test can be skipped by setting `QA_CAN_TEST_GIT_PROTOCOL_V2` to `false`. |
| `:requires_praefect` | The test requires that the GitLab instance uses [Gitaly Cluster](../../../administration/gitaly/praefect.md) (a.k.a. Praefect) as the repository storage . It's assumed to be used by default but if not the test can be skipped by setting `QA_CAN_TEST_PRAEFECT` to `false`. |
| `:packages` | The test requires a GitLab instance that has the [Package Registry](../../../administration/packages/#gitlab-package-registry-administration) enabled. |
...@@ -86,6 +86,8 @@ module QA ...@@ -86,6 +86,8 @@ module QA
end end
def fabricate_via_api! def fabricate_via_api!
raise ResourceNotFoundError unless id
resource_web_url(api_get) resource_web_url(api_get)
rescue ResourceNotFoundError rescue ResourceNotFoundError
populate_target_and_source_if_required populate_target_and_source_if_required
......
...@@ -411,6 +411,10 @@ module QA ...@@ -411,6 +411,10 @@ module QA
ENV.fetch('GITLAB_AGENTK_VERSION', 'v13.7.0') ENV.fetch('GITLAB_AGENTK_VERSION', 'v13.7.0')
end end
def transient_trials
ENV.fetch('GITLAB_QA_TRANSIENT_TRIALS', 10).to_i
end
private private
def remote_grid_credentials def remote_grid_credentials
......
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
require 'securerandom' require 'securerandom'
module QA module QA
RSpec.describe 'Release', :runner do RSpec.describe 'Verify', :runner do
describe 'Pipelines for merged results and merge trains' do describe 'Pipelines for merged results and merge trains' do
let(:group) { Resource::Group.fabricate_via_api! } let(:group) { Resource::Group.fabricate_via_api! }
......
# frozen_string_literal: true
require 'securerandom'
module QA
RSpec.describe 'Verify', :runner, :transient do
describe 'Merge trains transient bugs' do
let(:group) { Resource::Group.fabricate_via_api! }
let!(:runner) do
Resource::Runner.fabricate_via_api! do |runner|
runner.token = group.reload!.runners_token
runner.name = group.name
runner.tags = [group.name]
runner.project = project
end
end
let(:project) do
Resource::Project.fabricate_via_api! do |project|
project.name = 'merge-trains-transient-bugs'
project.group = group
end
end
before do
Resource::Repository::Commit.fabricate_via_api! do |commit|
commit.project = project
commit.commit_message = 'Add .gitlab-ci.yml'
commit.add_files(
[
{
file_path: '.gitlab-ci.yml',
content: <<~EOF
test:
tags: [#{group.name}]
script: echo 'OK'
only:
- merge_requests
EOF
}
]
)
end
Flow::Login.sign_in
project.visit!
Page::Project::Menu.perform(&:go_to_general_settings)
Page::Project::Settings::Main.perform do |main|
main.expand_merge_requests_settings do |settings|
settings.click_pipelines_for_merged_results_checkbox
settings.click_merge_trains_checkbox
settings.click_save_changes
end
end
end
after do
runner.remove_via_api! if runner
project.remove_via_api!
group.remove_via_api!
end
it 'confirms that a merge train consistently completes and updates the UI', testcase: 'https://gitlab.com/gitlab-org/quality/testcases/-/issues/1608' do
Runtime::Env.transient_trials.times do |i|
QA::Runtime::Logger.info("Transient bug test action - Trial #{i}")
random_string_for_this_trial = SecureRandom.hex(8)
branch_name = "merge-train-#{random_string_for_this_trial}"
title = "merge train transient bug test #{random_string_for_this_trial}"
# Create a branch that will be merged into the default branch
Resource::Repository::ProjectPush.fabricate! do |project_push|
project_push.project = project
project_push.new_branch = true
project_push.branch_name = branch_name
project_push.file_name = "file-#{random_string_for_this_trial}.txt"
project_push.file_content = "merge me"
end
# Create a merge request to merge the branch we just created
Resource::MergeRequest.fabricate_via_api! do |merge_request|
merge_request.project = project
merge_request.source_branch = branch_name
merge_request.no_preparation = true
merge_request.title = title
end.visit!
Page::MergeRequest::Show.perform do |show|
pipeline_passed = show.retry_until(max_attempts: 5, sleep_interval: 5) do
show.has_pipeline_status?(/Merged result pipeline #\d+ passed/)
end
expect(pipeline_passed).to be_truthy, "Expected the merged result pipeline to pass."
show.merge_via_merge_train
# This is also tested in pipelines_for_merged_results_and_merge_trains_spec.rb as a regular e2e test.
# That test reloads the page at this point to avoid the problem of the merge status failing to update
# That's the transient UX issue this test is checking for, so if the MR is merged but the UI still shows the
# status as unmerged, the test will fail.
merge_request = project.merge_request_with_title(title)
expect(merge_request).not_to be_nil, "There was a problem fetching the merge request"
# We use the API to wait until the MR has been merged so that we know the UI should be ready to update
show.wait_until(reload: false) do
mr = Resource::MergeRequest.fabricate_via_api! do |mr|
mr.project = project
mr.id = merge_request[:iid]
end
mr.state == 'merged'
end
expect(show).to be_merged, "Expected content 'The changes were merged' but it did not appear."
expect(show).to have_pipeline_status(/Merge train pipeline #\d+ passed/)
end
end
end
end
end
end
...@@ -37,7 +37,7 @@ module QA ...@@ -37,7 +37,7 @@ module QA
if tags.any? if tags.any?
tags.each { |tag| tags_for_rspec.push(['--tag', tag.to_s]) } tags.each { |tag| tags_for_rspec.push(['--tag', tag.to_s]) }
else else
tags_for_rspec.push(%w[--tag ~orchestrated]) unless (%w[-t --tag] & options).any? tags_for_rspec.push(%w[--tag ~orchestrated --tag ~transient]) unless (%w[-t --tag] & options).any?
end end
tags_for_rspec.push(%w[--tag ~geo]) unless QA::Runtime::Env.geo_environment? tags_for_rspec.push(%w[--tag ~geo]) unless QA::Runtime::Env.geo_environment?
......
...@@ -3,9 +3,9 @@ ...@@ -3,9 +3,9 @@
require 'active_support/core_ext/hash' require 'active_support/core_ext/hash'
RSpec.describe QA::Specs::Runner do RSpec.describe QA::Specs::Runner do
shared_examples 'excludes orchestrated and geo' do shared_examples 'excludes orchestrated, transient, and geo' do
it 'excludes the orchestrated and geo tags and includes default args' do it 'excludes the orchestrated, transient, and geo tags, and includes default args' do
expect_rspec_runner_arguments(['--tag', '~orchestrated', '--tag', '~geo', *described_class::DEFAULT_TEST_PATH_ARGS]) expect_rspec_runner_arguments(['--tag', '~orchestrated', '--tag', '~transient', '--tag', '~geo', *described_class::DEFAULT_TEST_PATH_ARGS])
subject.perform subject.perform
end end
...@@ -18,13 +18,13 @@ RSpec.describe QA::Specs::Runner do ...@@ -18,13 +18,13 @@ RSpec.describe QA::Specs::Runner do
QA::Runtime::Scenario.define(:gitlab_address, "http://gitlab.test") QA::Runtime::Scenario.define(:gitlab_address, "http://gitlab.test")
end end
it_behaves_like 'excludes orchestrated and geo' it_behaves_like 'excludes orchestrated, transient, and geo'
context 'when tty is set' do context 'when tty is set' do
subject { described_class.new.tap { |runner| runner.tty = true } } subject { described_class.new.tap { |runner| runner.tty = true } }
it 'sets the `--tty` flag' do it 'sets the `--tty` flag' do
expect_rspec_runner_arguments(['--tty', '--tag', '~orchestrated', '--tag', '~geo', *described_class::DEFAULT_TEST_PATH_ARGS]) expect_rspec_runner_arguments(['--tty', '--tag', '~orchestrated', '--tag', '~transient', '--tag', '~geo', *described_class::DEFAULT_TEST_PATH_ARGS])
subject.perform subject.perform
end end
...@@ -43,7 +43,7 @@ RSpec.describe QA::Specs::Runner do ...@@ -43,7 +43,7 @@ RSpec.describe QA::Specs::Runner do
context 'when "--tag smoke" is set as options' do context 'when "--tag smoke" is set as options' do
subject { described_class.new.tap { |runner| runner.options = %w[--tag smoke] } } subject { described_class.new.tap { |runner| runner.options = %w[--tag smoke] } }
it 'focuses on the given tag without excluded the orchestrated tag' do it 'focuses on the given tag without excluded tags' do
expect_rspec_runner_arguments(['--tag', '~geo', '--tag', 'smoke', *described_class::DEFAULT_TEST_PATH_ARGS]) expect_rspec_runner_arguments(['--tag', '~geo', '--tag', 'smoke', *described_class::DEFAULT_TEST_PATH_ARGS])
subject.perform subject.perform
...@@ -53,8 +53,8 @@ RSpec.describe QA::Specs::Runner do ...@@ -53,8 +53,8 @@ RSpec.describe QA::Specs::Runner do
context 'when "qa/specs/features/foo" is set as options' do context 'when "qa/specs/features/foo" is set as options' do
subject { described_class.new.tap { |runner| runner.options = %w[qa/specs/features/foo] } } subject { described_class.new.tap { |runner| runner.options = %w[qa/specs/features/foo] } }
it 'passes the given tests path and excludes the orchestrated and geo tags' do it 'passes the given tests path and excludes the orchestrated, transient, and geo tags' do
expect_rspec_runner_arguments(['--tag', '~orchestrated', '--tag', '~geo', 'qa/specs/features/foo']) expect_rspec_runner_arguments(['--tag', '~orchestrated', '--tag', '~transient', '--tag', '~geo', 'qa/specs/features/foo'])
subject.perform subject.perform
end end
...@@ -63,7 +63,7 @@ RSpec.describe QA::Specs::Runner do ...@@ -63,7 +63,7 @@ RSpec.describe QA::Specs::Runner do
context 'when "--tag smoke" and "qa/specs/features/foo" are set as options' do context 'when "--tag smoke" and "qa/specs/features/foo" are set as options' do
subject { described_class.new.tap { |runner| runner.options = %w[--tag smoke qa/specs/features/foo] } } subject { described_class.new.tap { |runner| runner.options = %w[--tag smoke qa/specs/features/foo] } }
it 'focuses on the given tag and includes the path without excluding the orchestrated tag' do it 'focuses on the given tag and includes the path without excluding the orchestrated or transient tags' do
expect_rspec_runner_arguments(['--tag', '~geo', '--tag', 'smoke', 'qa/specs/features/foo']) expect_rspec_runner_arguments(['--tag', '~geo', '--tag', 'smoke', 'qa/specs/features/foo'])
subject.perform subject.perform
...@@ -76,7 +76,7 @@ RSpec.describe QA::Specs::Runner do ...@@ -76,7 +76,7 @@ RSpec.describe QA::Specs::Runner do
end end
it 'includes default args and excludes the skip_signup_disabled tag' do it 'includes default args and excludes the skip_signup_disabled tag' do
expect_rspec_runner_arguments(['--tag', '~orchestrated', '--tag', '~geo', '--tag', '~skip_signup_disabled', *described_class::DEFAULT_TEST_PATH_ARGS]) expect_rspec_runner_arguments(['--tag', '~orchestrated', '--tag', '~transient', '--tag', '~geo', '--tag', '~skip_signup_disabled', *described_class::DEFAULT_TEST_PATH_ARGS])
subject.perform subject.perform
end end
...@@ -88,7 +88,7 @@ RSpec.describe QA::Specs::Runner do ...@@ -88,7 +88,7 @@ RSpec.describe QA::Specs::Runner do
end end
it 'includes default args and excludes the skip_live_env tag' do it 'includes default args and excludes the skip_live_env tag' do
expect_rspec_runner_arguments(['--tag', '~orchestrated', '--tag', '~geo', '--tag', '~skip_live_env', *described_class::DEFAULT_TEST_PATH_ARGS]) expect_rspec_runner_arguments(['--tag', '~orchestrated', '--tag', '~transient', '--tag', '~geo', '--tag', '~skip_live_env', *described_class::DEFAULT_TEST_PATH_ARGS])
subject.perform subject.perform
end end
end end
...@@ -121,7 +121,7 @@ RSpec.describe QA::Specs::Runner do ...@@ -121,7 +121,7 @@ RSpec.describe QA::Specs::Runner do
end end
it 'includes default args and excludes all unsupported tags' do it 'includes default args and excludes all unsupported tags' do
expect_rspec_runner_arguments(['--tag', '~orchestrated', '--tag', '~geo', *excluded_feature_tags_except(feature), *described_class::DEFAULT_TEST_PATH_ARGS]) expect_rspec_runner_arguments(['--tag', '~orchestrated', '--tag', '~transient', '--tag', '~geo', *excluded_feature_tags_except(feature), *described_class::DEFAULT_TEST_PATH_ARGS])
subject.perform subject.perform
end end
...@@ -146,11 +146,11 @@ RSpec.describe QA::Specs::Runner do ...@@ -146,11 +146,11 @@ RSpec.describe QA::Specs::Runner do
end end
end end
it_behaves_like 'excludes orchestrated and geo' it_behaves_like 'excludes orchestrated, transient, and geo'
end end
context 'when features are not specified' do context 'when features are not specified' do
it_behaves_like 'excludes orchestrated and geo' it_behaves_like 'excludes orchestrated, transient, and geo'
end end
end end
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment