gitlab-qa 7.14.0 → 7.16.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.gitlab-ci.yml +29 -3
- data/docs/run_qa_against_gdk.md +11 -1
- data/docs/what_tests_can_be_run.md +1 -0
- data/lib/gitlab/qa/component/elasticsearch.rb +1 -0
- data/lib/gitlab/qa/report/generate_test_session.rb +5 -0
- data/lib/gitlab/qa/report/relate_failure_issue.rb +2 -1
- data/lib/gitlab/qa/report/report_as_issue.rb +10 -3
- data/lib/gitlab/qa/report/report_results.rb +71 -0
- data/lib/gitlab/qa/report/results_in_issues.rb +24 -142
- data/lib/gitlab/qa/report/results_in_testcases.rb +67 -0
- data/lib/gitlab/qa/report/results_reporter_shared.rb +65 -0
- data/lib/gitlab/qa/reporter.rb +15 -7
- data/lib/gitlab/qa/runtime/env.rb +2 -1
- data/lib/gitlab/qa/scenario/test/integration/service_ping_disabled.rb +33 -0
- data/lib/gitlab/qa/version.rb +1 -1
- data/lib/gitlab/qa.rb +4 -0
- metadata +6 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 025a32906db8c2ddc296e638c08d4d78e3d9d4dcb2c80c2b1a28772e819e8748
|
|
4
|
+
data.tar.gz: 4c7e61f511f27a75e4e035553f72fb38aab26460b0ead21c3574acb2a9b1a2c4
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 18ec099f17557d2bf50b270b5e086f81952fca84aa3ffa9a8b376d3fcd19a08ab770405a85118be35f642e0d3097898b8f0fb9cfc3339eabf95eaa0b4207d6ad
|
|
7
|
+
data.tar.gz: 5122d793ec7d8e2c4dfd8a29157e03f1595984bf83041c0c010971917e70a6180c06b81ec6b6d601a9a15a235ad312d9caa14ba241c70d348f450d725b7756c5
|
data/.gitlab-ci.yml
CHANGED
|
@@ -46,7 +46,8 @@ variables:
|
|
|
46
46
|
QA_CAN_TEST_GIT_PROTOCOL_V2: "true"
|
|
47
47
|
QA_CAN_TEST_PRAEFECT: "false"
|
|
48
48
|
QA_GENERATE_ALLURE_REPORT: "true"
|
|
49
|
-
QA_TESTCASES_REPORTING_PROJECT: "gitlab-org/
|
|
49
|
+
QA_TESTCASES_REPORTING_PROJECT: "gitlab-org/gitlab"
|
|
50
|
+
QA_TEST_RESULTS_ISSUES_PROJECT: "gitlab-org/quality/testcases"
|
|
50
51
|
QA_TESTCASE_SESSIONS_PROJECT: "gitlab-org/quality/testcase-sessions"
|
|
51
52
|
# QA_DEFAULT_BRANCH is the default branch name of the instance under test.
|
|
52
53
|
QA_DEFAULT_BRANCH: "master"
|
|
@@ -66,6 +67,7 @@ rspec:
|
|
|
66
67
|
|
|
67
68
|
.test:
|
|
68
69
|
stage: test
|
|
70
|
+
timeout: 1 hour 30 minutes
|
|
69
71
|
services:
|
|
70
72
|
- docker:20.10.5-dind
|
|
71
73
|
tags:
|
|
@@ -83,7 +85,7 @@ rspec:
|
|
|
83
85
|
- bundle exec exe/gitlab-qa ${QA_SCENARIO:=Test::Instance::Image} ${RELEASE:=$DEFAULT_RELEASE} $GITLAB_QA_OPTIONS -- $QA_TESTS $QA_RSPEC_TAGS $RSPEC_REPORT_OPTS || test_run_exit_code=$?
|
|
84
86
|
- bundle exec exe/gitlab-qa-report --update-screenshot-path "gitlab-qa-run-*/**/rspec-*.xml"
|
|
85
87
|
- export GITLAB_QA_ACCESS_TOKEN="$GITLAB_QA_PRODUCTION_ACCESS_TOKEN"
|
|
86
|
-
- if [ "$TOP_UPSTREAM_SOURCE_REF" == $TOP_UPSTREAM_DEFAULT_BRANCH ] || [[ "$TOP_UPSTREAM_SOURCE_JOB" == https://ops.gitlab.net* ]]; then exe/gitlab-qa-report --report-
|
|
88
|
+
- if [ "$TOP_UPSTREAM_SOURCE_REF" == $TOP_UPSTREAM_DEFAULT_BRANCH ] || [[ "$TOP_UPSTREAM_SOURCE_JOB" == https://ops.gitlab.net* ]]; then exe/gitlab-qa-report --report-results "gitlab-qa-run-*/**/rspec-*.json" --test-case-project "$QA_TESTCASES_REPORTING_PROJECT" --results-issue-project "$QA_TEST_RESULTS_ISSUES_PROJECT" || true; fi
|
|
87
89
|
- exit $test_run_exit_code
|
|
88
90
|
|
|
89
91
|
# For jobs that shouldn't report results in issues, e.g., manually run custom jobs
|
|
@@ -106,7 +108,7 @@ rspec:
|
|
|
106
108
|
- bundle exec exe/gitlab-qa Test::Omnibus::Update ${RELEASE:=$DEFAULT_RELEASE} ${RELEASE:=$DEFAULT_RELEASE} $GITLAB_QA_OPTIONS -- $QA_TESTS $QA_RSPEC_TAGS $RSPEC_REPORT_OPTS || test_run_exit_code=$?
|
|
107
109
|
- bundle exec exe/gitlab-qa-report --update-screenshot-path "gitlab-qa-run-*/**/rspec-*.xml"
|
|
108
110
|
- export GITLAB_QA_ACCESS_TOKEN="$GITLAB_QA_PRODUCTION_ACCESS_TOKEN"
|
|
109
|
-
- if [ "$TOP_UPSTREAM_SOURCE_REF" == $TOP_UPSTREAM_DEFAULT_BRANCH ] || [[ "$TOP_UPSTREAM_SOURCE_JOB" == https://ops.gitlab.net* ]]; then exe/gitlab-qa-report --report-
|
|
111
|
+
- if [ "$TOP_UPSTREAM_SOURCE_REF" == $TOP_UPSTREAM_DEFAULT_BRANCH ] || [[ "$TOP_UPSTREAM_SOURCE_JOB" == https://ops.gitlab.net* ]]; then exe/gitlab-qa-report --report-results "gitlab-qa-run-*/**/rspec-*.json" --test-case-project "$QA_TESTCASES_REPORTING_PROJECT" --results-issue-project "$QA_TEST_RESULTS_ISSUES_PROJECT" || true; fi
|
|
110
112
|
- exit $test_run_exit_code
|
|
111
113
|
|
|
112
114
|
.ce-variables:
|
|
@@ -527,6 +529,26 @@ ee:mattermost-quarantine:
|
|
|
527
529
|
variables:
|
|
528
530
|
QA_SCENARIO: "Test::Integration::Mattermost"
|
|
529
531
|
|
|
532
|
+
ce:service_ping_disabled:
|
|
533
|
+
extends:
|
|
534
|
+
- .rules:ce-never-when-triggered-by-feature-flag-definition-change
|
|
535
|
+
- .test
|
|
536
|
+
- .high-capacity
|
|
537
|
+
- .ce-variables
|
|
538
|
+
- .rspec-report-opts
|
|
539
|
+
variables:
|
|
540
|
+
QA_SCENARIO: "Test::Integration::ServicePingDisabled"
|
|
541
|
+
|
|
542
|
+
ee:service_ping_disabled:
|
|
543
|
+
extends:
|
|
544
|
+
- .rules:ee-never-when-triggered-by-feature-flag-definition-change
|
|
545
|
+
- .test
|
|
546
|
+
- .high-capacity
|
|
547
|
+
- .ee-variables
|
|
548
|
+
- .rspec-report-opts
|
|
549
|
+
variables:
|
|
550
|
+
QA_SCENARIO: "Test::Integration::ServicePingDisabled"
|
|
551
|
+
|
|
530
552
|
# Disabling geo jobs temporarily due to https://gitlab.com/gitlab-org/gitlab/-/issues/273063
|
|
531
553
|
# ee:geo:
|
|
532
554
|
# extends:
|
|
@@ -1066,6 +1088,7 @@ ce:gitaly-cluster:
|
|
|
1066
1088
|
- .rspec-report-opts
|
|
1067
1089
|
variables:
|
|
1068
1090
|
QA_SCENARIO: "Test::Integration::GitalyCluster"
|
|
1091
|
+
QA_LOG_PATH: "tmp/gitaly_cluster.log"
|
|
1069
1092
|
|
|
1070
1093
|
ce:gitaly-cluster-quarantine:
|
|
1071
1094
|
extends:
|
|
@@ -1077,6 +1100,7 @@ ce:gitaly-cluster-quarantine:
|
|
|
1077
1100
|
- .rspec-report-opts
|
|
1078
1101
|
variables:
|
|
1079
1102
|
QA_SCENARIO: "Test::Integration::GitalyCluster"
|
|
1103
|
+
QA_LOG_PATH: "tmp/gitaly_cluster.log"
|
|
1080
1104
|
|
|
1081
1105
|
ee:gitaly-cluster:
|
|
1082
1106
|
extends:
|
|
@@ -1087,6 +1111,7 @@ ee:gitaly-cluster:
|
|
|
1087
1111
|
- .rspec-report-opts
|
|
1088
1112
|
variables:
|
|
1089
1113
|
QA_SCENARIO: "Test::Integration::GitalyCluster"
|
|
1114
|
+
QA_LOG_PATH: "tmp/gitaly_cluster.log"
|
|
1090
1115
|
|
|
1091
1116
|
ee:gitaly-cluster-quarantine:
|
|
1092
1117
|
extends:
|
|
@@ -1098,6 +1123,7 @@ ee:gitaly-cluster-quarantine:
|
|
|
1098
1123
|
- .rspec-report-opts
|
|
1099
1124
|
variables:
|
|
1100
1125
|
QA_SCENARIO: "Test::Integration::GitalyCluster"
|
|
1126
|
+
QA_LOG_PATH: "tmp/gitaly_cluster.log"
|
|
1101
1127
|
|
|
1102
1128
|
ce:mtls:
|
|
1103
1129
|
extends:
|
data/docs/run_qa_against_gdk.md
CHANGED
|
@@ -49,6 +49,16 @@ make a few changes to your `gdk/gitlab/config/gitlab.yml` file.
|
|
|
49
49
|
**Note:** The hostname of the URL provided to `gitlab-qa` must match the hostname configured for GDK.
|
|
50
50
|
If they do not match, a test will be signed out when it visits a page directly because the hostname of the URL visited will be different from the hostname that was used when signing in.
|
|
51
51
|
|
|
52
|
+
**Note:** When you log into your GDK instance of GitLab for the first time, the root password requires a change.
|
|
53
|
+
GitLab QA expects the default initial password to be used in tests; see all default values listed in
|
|
54
|
+
[Supported GitLab environment variables](what_tests_can_be_run.md#supported-gitlab-environment-variables).
|
|
55
|
+
If you have changed your root password, you must set the `GITLAB_INITIAL_ROOT_PASSWORD` environment
|
|
56
|
+
variable.
|
|
57
|
+
|
|
58
|
+
```
|
|
59
|
+
export GITLAB_INITIAL_ROOT_PASSWORD="<GDK root password>"
|
|
60
|
+
```
|
|
61
|
+
|
|
52
62
|
### Running EE tests
|
|
53
63
|
|
|
54
64
|
When running EE tests you'll need to have a license available. GitLab engineers can [request a license](https://about.gitlab.com/handbook/developer-onboarding/#working-on-gitlab-ee).
|
|
@@ -101,7 +111,7 @@ your DNS and point to the IP/port of `dnsdock` application.
|
|
|
101
111
|
|
|
102
112
|
### Docker on macOS caveats
|
|
103
113
|
|
|
104
|
-
When using OS X Docker, you need to go to Preferences > Advanced and allocate at least **5.0 GB**,
|
|
114
|
+
When using OS X Docker, you need to go to Preferences > Resources > Advanced and allocate at least **5.0 GB**,
|
|
105
115
|
otherwise some steps may fail to execute the `chrome-webdriver`.
|
|
106
116
|
|
|
107
117
|
When using docker-machine, see [this StackOverflow link for increasing memory](https://stackoverflow.com/questions/32834082/how-to-increase-docker-machine-memory-mac/36982696#36982696).
|
|
@@ -62,6 +62,7 @@ All environment variables used by GitLab QA should be defined in [`lib/gitlab/qa
|
|
|
62
62
|
| `QA_ARTIFACTS_DIR` |`/tmp/gitlab-qa`| Path to a directory where artifacts (logs and screenshots) for failing tests will be saved. | No|
|
|
63
63
|
| `DOCKER_HOST` |`http://localhost`| Docker host to run tests against. | No|
|
|
64
64
|
| `WEBDRIVER_HEADLESS` |- | When running locally, set to `false` to allow Chrome tests to be visible - watch your tests being run. | No|
|
|
65
|
+
| `CHROME_DISABLE_DEV_SHM` | `false` | Set to `true` to disable `/dev/shm` usage in Chrome on Linux. | No|
|
|
65
66
|
| `QA_ADDITIONAL_REPOSITORY_STORAGE` |- | The name of additional, non-default storage to be used with tests tagged `repository_storage`, run via the `Test::Instance::RepositoryStorage` scenario. Note: Admin access is required to change repository storage. | No|
|
|
66
67
|
| `QA_PRAEFECT_REPOSITORY_STORAGE` |- | The name of repository storage using Praefect. Note: Admin access is required to change repository storage. | No|
|
|
67
68
|
| `QA_COOKIES` |- | Optionally set to "cookie1=value;cookie2=value" in order to add a cookie to every request. This can be used to set the canary cookie by setting it to "gitlab_canary=true". | No|
|
|
@@ -19,6 +19,7 @@ module Gitlab
|
|
|
19
19
|
def initialize(max_diff_ratio: DEFAULT_MAX_DIFF_RATIO_FOR_DETECTION, **kwargs)
|
|
20
20
|
super
|
|
21
21
|
@max_diff_ratio = max_diff_ratio.to_f
|
|
22
|
+
@issue_type = 'issue'
|
|
22
23
|
end
|
|
23
24
|
|
|
24
25
|
private
|
|
@@ -63,7 +64,7 @@ module Gitlab
|
|
|
63
64
|
puts " => Found issue #{issue.web_url} for test '#{test.name}' with a diff ratio of #{(diff_ratio * 100).round(2)}%."
|
|
64
65
|
else
|
|
65
66
|
issue = create_issue(test)
|
|
66
|
-
puts "
|
|
67
|
+
puts "for test '#{test.name}'."
|
|
67
68
|
end
|
|
68
69
|
|
|
69
70
|
issue
|
|
@@ -22,7 +22,7 @@ module Gitlab
|
|
|
22
22
|
|
|
23
23
|
private
|
|
24
24
|
|
|
25
|
-
attr_reader :gitlab, :files, :project
|
|
25
|
+
attr_reader :gitlab, :files, :project, :issue_type
|
|
26
26
|
|
|
27
27
|
def run!
|
|
28
28
|
raise NotImplementedError
|
|
@@ -77,11 +77,18 @@ module Gitlab
|
|
|
77
77
|
end
|
|
78
78
|
|
|
79
79
|
def create_issue(test)
|
|
80
|
-
gitlab.create_issue(
|
|
80
|
+
issue = gitlab.create_issue(
|
|
81
81
|
title: title_from_test(test),
|
|
82
82
|
description: new_issue_description(test),
|
|
83
|
-
labels: new_issue_labels(test).to_a
|
|
83
|
+
labels: new_issue_labels(test).to_a,
|
|
84
|
+
issue_type: issue_type
|
|
84
85
|
)
|
|
86
|
+
|
|
87
|
+
new_link = issue_type == 'test_case' ? issue.web_url.sub('/issues/', '/quality/test_cases/') : issue.web_url
|
|
88
|
+
|
|
89
|
+
puts "Created new #{issue_type}: #{new_link}"
|
|
90
|
+
|
|
91
|
+
issue
|
|
85
92
|
end
|
|
86
93
|
|
|
87
94
|
def issue_labels(issue)
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Gitlab
|
|
4
|
+
module QA
|
|
5
|
+
module Report
|
|
6
|
+
# Uses the API to create or update GitLab test cases and issues with the results of tests from RSpec report files.
|
|
7
|
+
class ReportResults < ReportAsIssue
|
|
8
|
+
# TODO: Remove old_testcase_project_reporter once all test case links are updated to the gitlab project. See https://gitlab.com/gitlab-org/quality/team-tasks/-/issues/1079
|
|
9
|
+
attr_accessor :testcase_project_reporter, :results_issue_project_reporter, :files, :test_case_project, :results_issue_project, :gitlab, :old_testcase_project_reporter
|
|
10
|
+
|
|
11
|
+
def initialize(token:, input_files:, test_case_project:, results_issue_project:, dry_run: false, **kwargs)
|
|
12
|
+
@testcase_project_reporter = Gitlab::QA::Report::ResultsInTestCases.new(token: token, input_files: input_files, project: test_case_project, dry_run: dry_run, **kwargs)
|
|
13
|
+
# TODO: Remove the line below once all test case links are updated to the gitlab project. See https://gitlab.com/gitlab-org/quality/team-tasks/-/issues/1079
|
|
14
|
+
@old_testcase_project_reporter = Gitlab::QA::Report::ResultsInTestCases.new(token: token, input_files: input_files, project: results_issue_project, dry_run: dry_run, **kwargs)
|
|
15
|
+
@results_issue_project_reporter = Gitlab::QA::Report::ResultsInIssues.new(token: token, input_files: input_files, project: results_issue_project, dry_run: dry_run, **kwargs)
|
|
16
|
+
@test_case_project = test_case_project
|
|
17
|
+
@results_issue_project = results_issue_project
|
|
18
|
+
@files = Array(input_files)
|
|
19
|
+
@gitlab = testcase_project_reporter.gitlab
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def assert_project!
|
|
23
|
+
return if test_case_project && results_issue_project
|
|
24
|
+
|
|
25
|
+
abort "Please provide valid project IDs or paths with the `--results-issue-project` and `--test-case-project` options!"
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def run!
|
|
29
|
+
puts "Reporting test results in `#{files.join(',')}` as test cases in project `#{test_case_project}`"\
|
|
30
|
+
" and issues in project `#{results_issue_project}` via the API at `#{Runtime::Env.gitlab_api_base}`."
|
|
31
|
+
|
|
32
|
+
test_results_per_file do |test_results|
|
|
33
|
+
puts "Reporting tests in #{test_results.path}"
|
|
34
|
+
|
|
35
|
+
test_results.each do |test|
|
|
36
|
+
puts "Reporting test: #{test.file} | #{test.name}\n"
|
|
37
|
+
|
|
38
|
+
report_test(test) unless test.skipped
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
test_results.write
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
private
|
|
46
|
+
|
|
47
|
+
def report_test(test)
|
|
48
|
+
# TODO: Remove the line below and replace correct_testcase_project_reporter with testcase_project_reporter
|
|
49
|
+
# once all test case links are updated to the gitlab project. See https://gitlab.com/gitlab-org/quality/team-tasks/-/issues/1079
|
|
50
|
+
correct_testcase_project_reporter = using_old_testcase_link(test) ? old_testcase_project_reporter : testcase_project_reporter
|
|
51
|
+
|
|
52
|
+
testcase = correct_testcase_project_reporter.find_or_create_testcase(test)
|
|
53
|
+
# The API returns the test case with an issue URL since it is technically a type of issue.
|
|
54
|
+
# This updates the URL to a valid test case link.
|
|
55
|
+
test.testcase = testcase.web_url.sub('/issues/', '/quality/test_cases/')
|
|
56
|
+
|
|
57
|
+
issue, is_new = results_issue_project_reporter.get_related_issue(testcase, test)
|
|
58
|
+
|
|
59
|
+
correct_testcase_project_reporter.add_issue_link_to_testcase(testcase, issue, test) if is_new
|
|
60
|
+
|
|
61
|
+
correct_testcase_project_reporter.update_testcase(testcase, test)
|
|
62
|
+
results_issue_project_reporter.update_issue(issue, test)
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def using_old_testcase_link(test)
|
|
66
|
+
test.testcase&.include?(results_issue_project)
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
end
|
|
@@ -1,120 +1,62 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require 'nokogiri'
|
|
4
|
-
require 'active_support/core_ext/enumerable'
|
|
5
|
-
|
|
6
3
|
module Gitlab
|
|
7
4
|
module QA
|
|
8
5
|
module Report
|
|
9
|
-
# Uses the API to create or update GitLab issues with the results of tests from RSpec report files.
|
|
6
|
+
# Uses the API to create or update GitLab test result issues with the results of tests from RSpec report files.
|
|
10
7
|
class ResultsInIssues < ReportAsIssue
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
RESULTS_SECTION_TEMPLATE = "\n\n### DO NOT EDIT BELOW THIS LINE\n\nActive and historical test results:"
|
|
14
|
-
|
|
15
|
-
def run!
|
|
16
|
-
puts "Reporting test results in `#{files.join(',')}` as issues in project `#{project}` via the API at `#{Runtime::Env.gitlab_api_base}`."
|
|
17
|
-
|
|
18
|
-
test_results_per_file do |test_results|
|
|
19
|
-
puts "Reporting tests in #{test_results.path}"
|
|
8
|
+
include ResultsReporterShared
|
|
20
9
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
report_test(test) unless test.skipped
|
|
25
|
-
end
|
|
26
|
-
|
|
27
|
-
test_results.write
|
|
28
|
-
end
|
|
10
|
+
def initialize(**kwargs)
|
|
11
|
+
super
|
|
12
|
+
@issue_type = 'issue'
|
|
29
13
|
end
|
|
30
14
|
|
|
31
|
-
def
|
|
32
|
-
testcase = find_testcase(test) || create_testcase(test)
|
|
33
|
-
test.testcase ||= testcase.web_url.sub('/issues/', '/quality/test_cases/')
|
|
34
|
-
|
|
15
|
+
def get_related_issue(testcase, test)
|
|
35
16
|
issue = find_linked_results_issue_by_iid(testcase, test)
|
|
17
|
+
is_new = false
|
|
36
18
|
|
|
37
19
|
if issue
|
|
38
|
-
issue = update_issue_title(issue, test
|
|
20
|
+
issue = update_issue_title(issue, test) if issue_title_needs_updating?(issue, test)
|
|
39
21
|
else
|
|
40
22
|
puts "No valid issue link found"
|
|
41
23
|
issue = find_or_create_results_issue(test)
|
|
42
|
-
|
|
43
|
-
add_issue_to_testcase(testcase, issue)
|
|
24
|
+
is_new = true
|
|
44
25
|
end
|
|
45
26
|
|
|
46
|
-
|
|
47
|
-
update_issue(issue, test)
|
|
27
|
+
[issue, is_new]
|
|
48
28
|
end
|
|
49
29
|
|
|
50
|
-
def
|
|
51
|
-
|
|
30
|
+
def update_issue(issue, test)
|
|
31
|
+
new_labels = issue_labels(issue)
|
|
32
|
+
new_labels |= ['Testcase Linked']
|
|
52
33
|
|
|
53
|
-
|
|
54
|
-
|
|
34
|
+
labels_updated = update_labels(issue, test, new_labels)
|
|
35
|
+
note_posted = note_status(issue, test)
|
|
36
|
+
|
|
37
|
+
if labels_updated || note_posted
|
|
38
|
+
puts "Issue updated."
|
|
55
39
|
else
|
|
56
|
-
|
|
40
|
+
puts "Test passed, no results issue update needed."
|
|
57
41
|
end
|
|
58
|
-
|
|
59
|
-
testcase
|
|
60
42
|
end
|
|
61
43
|
|
|
62
|
-
|
|
63
|
-
iid = testcase_iid_from_url(test.testcase)
|
|
64
|
-
|
|
65
|
-
return unless iid
|
|
66
|
-
|
|
67
|
-
find_issue_by_iid(iid, 'test_case')
|
|
68
|
-
end
|
|
44
|
+
private
|
|
69
45
|
|
|
70
46
|
def find_linked_results_issue_by_iid(testcase, test)
|
|
71
47
|
iid = issue_iid_from_testcase(testcase)
|
|
72
48
|
|
|
73
49
|
return unless iid
|
|
74
50
|
|
|
75
|
-
find_issue_by_iid(iid
|
|
76
|
-
end
|
|
77
|
-
|
|
78
|
-
def find_issue_by_iid(iid, issue_type)
|
|
79
|
-
issues = gitlab.find_issues(iid: iid) do |issue|
|
|
80
|
-
issue.state == 'opened' && issue.issue_type == issue_type
|
|
81
|
-
end
|
|
82
|
-
|
|
83
|
-
warn(%(#{issue_type} iid "#{iid}" not valid)) if issues.empty?
|
|
84
|
-
|
|
85
|
-
issues.first
|
|
86
|
-
end
|
|
87
|
-
|
|
88
|
-
def update_issue_title(issue, test, issue_type)
|
|
89
|
-
warn(%(#{issue_type} title needs to be updated from '#{issue.title.strip}' to '#{title_from_test(test)}'))
|
|
90
|
-
|
|
91
|
-
gitlab.edit_issue(iid: issue.iid, options: { title: title_from_test(test) })
|
|
92
|
-
end
|
|
93
|
-
|
|
94
|
-
def create_testcase(test)
|
|
95
|
-
title = title_from_test(test)
|
|
96
|
-
puts "Creating test case '#{title}' ..."
|
|
97
|
-
|
|
98
|
-
gitlab.create_issue(
|
|
99
|
-
title: title,
|
|
100
|
-
description: new_testcase_description(test),
|
|
101
|
-
labels: new_issue_labels(test),
|
|
102
|
-
issue_type: 'test_case'
|
|
103
|
-
)
|
|
104
|
-
end
|
|
105
|
-
|
|
106
|
-
def testcase_iid_from_url(url)
|
|
107
|
-
return warn(%(\nPlease update #{url} to test case url")) if url&.include?('/-/issues/')
|
|
108
|
-
|
|
109
|
-
url && url.split('/').last.to_i
|
|
51
|
+
find_issue_by_iid(iid)
|
|
110
52
|
end
|
|
111
53
|
|
|
112
|
-
def
|
|
113
|
-
|
|
54
|
+
def find_or_create_results_issue(test)
|
|
55
|
+
find_issue(test) || create_issue(test)
|
|
114
56
|
end
|
|
115
57
|
|
|
116
58
|
def issue_iid_from_testcase(testcase)
|
|
117
|
-
results = testcase.description.partition(
|
|
59
|
+
results = testcase.description.partition(TEST_CASE_RESULTS_SECTION_TEMPLATE).last if testcase.description.include?(TEST_CASE_RESULTS_SECTION_TEMPLATE)
|
|
118
60
|
|
|
119
61
|
return puts "No issue link found" unless results
|
|
120
62
|
|
|
@@ -123,66 +65,6 @@ module Gitlab
|
|
|
123
65
|
issue_iid&.to_i
|
|
124
66
|
end
|
|
125
67
|
|
|
126
|
-
def find_or_create_results_issue(test)
|
|
127
|
-
issue = find_issue(test, 'issue')
|
|
128
|
-
|
|
129
|
-
if issue
|
|
130
|
-
puts "Found existing issue: #{issue.web_url}"
|
|
131
|
-
else
|
|
132
|
-
issue = create_issue(test)
|
|
133
|
-
puts "Created new issue: #{issue.web_url}"
|
|
134
|
-
end
|
|
135
|
-
|
|
136
|
-
issue
|
|
137
|
-
end
|
|
138
|
-
|
|
139
|
-
def find_issue(test, issue_type)
|
|
140
|
-
issues = gitlab.find_issues(options: { search: search_term(test) }) do |issue|
|
|
141
|
-
issue.state == 'opened' && issue.issue_type == issue_type && issue.title.strip == title_from_test(test)
|
|
142
|
-
end
|
|
143
|
-
|
|
144
|
-
warn(%(Too many #{issue_type}s found with the file path "#{test.file}" and name "#{test.name}")) if issues.many?
|
|
145
|
-
|
|
146
|
-
issues.first
|
|
147
|
-
end
|
|
148
|
-
|
|
149
|
-
def add_issue_to_testcase(testcase, issue)
|
|
150
|
-
results_section = testcase.description.include?(RESULTS_SECTION_TEMPLATE) ? '' : RESULTS_SECTION_TEMPLATE
|
|
151
|
-
|
|
152
|
-
gitlab.edit_issue(iid: testcase.iid, options: { description: (testcase.description + results_section + "\n\n#{issue.web_url}") })
|
|
153
|
-
|
|
154
|
-
puts "Added issue #{issue.web_url} to testcase #{testcase.web_url}"
|
|
155
|
-
end
|
|
156
|
-
|
|
157
|
-
def update_issue(issue, test)
|
|
158
|
-
new_labels = issue_labels(issue)
|
|
159
|
-
new_labels |= ['Testcase Linked']
|
|
160
|
-
|
|
161
|
-
labels_updated = update_labels(issue, test, new_labels)
|
|
162
|
-
note_posted = note_status(issue, test)
|
|
163
|
-
|
|
164
|
-
if labels_updated || note_posted
|
|
165
|
-
puts "Issue updated."
|
|
166
|
-
else
|
|
167
|
-
puts "Test passed, no update needed."
|
|
168
|
-
end
|
|
169
|
-
end
|
|
170
|
-
|
|
171
|
-
def new_issue_labels(test)
|
|
172
|
-
['Quality', "devops::#{test.stage}", 'status::automated']
|
|
173
|
-
end
|
|
174
|
-
|
|
175
|
-
def up_to_date_labels(test:, issue: nil, new_labels: Set.new)
|
|
176
|
-
labels = super
|
|
177
|
-
labels |= new_issue_labels(test).to_set
|
|
178
|
-
labels.delete_if { |label| label.start_with?("#{pipeline}::") }
|
|
179
|
-
labels << (test.failures.empty? ? "#{pipeline}::passed" : "#{pipeline}::failed")
|
|
180
|
-
end
|
|
181
|
-
|
|
182
|
-
def search_term(test)
|
|
183
|
-
%("#{partial_file_path(test.file)}" "#{search_safe(test.name)}")
|
|
184
|
-
end
|
|
185
|
-
|
|
186
68
|
def note_status(issue, test)
|
|
187
69
|
return false if test.skipped
|
|
188
70
|
return false if test.failures.empty?
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Gitlab
|
|
4
|
+
module QA
|
|
5
|
+
module Report
|
|
6
|
+
# Uses the API to create or update GitLab test cases with the results of tests from RSpec report files.
|
|
7
|
+
class ResultsInTestCases < ReportAsIssue
|
|
8
|
+
attr_reader :issue_type, :gitlab
|
|
9
|
+
|
|
10
|
+
include ResultsReporterShared
|
|
11
|
+
|
|
12
|
+
def initialize(**kwargs)
|
|
13
|
+
super
|
|
14
|
+
@issue_type = 'test_case'
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def find_or_create_testcase(test)
|
|
18
|
+
find_testcase(test) || create_issue(test)
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def add_issue_link_to_testcase(testcase, issue, test)
|
|
22
|
+
results_section = testcase.description.include?(TEST_CASE_RESULTS_SECTION_TEMPLATE) ? '' : TEST_CASE_RESULTS_SECTION_TEMPLATE
|
|
23
|
+
|
|
24
|
+
gitlab.edit_issue(iid: testcase.iid, options: { description: (testcase.description + results_section + "\n\n#{issue.web_url}") })
|
|
25
|
+
# We are using test.testcase for the url here instead of testcase.web_url since it has the updated test case path
|
|
26
|
+
puts "Added results issue #{issue.web_url} link to test case #{test.testcase}"
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def update_testcase(testcase, test)
|
|
30
|
+
puts "Test case labels updated." if update_labels(testcase, test)
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
private
|
|
34
|
+
|
|
35
|
+
def find_testcase(test)
|
|
36
|
+
testcase = find_testcase_by_iid(test)
|
|
37
|
+
|
|
38
|
+
if testcase
|
|
39
|
+
testcase = update_issue_title(testcase, test) if issue_title_needs_updating?(testcase, test)
|
|
40
|
+
else
|
|
41
|
+
testcase = find_issue(test)
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
testcase
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def find_testcase_by_iid(test)
|
|
48
|
+
iid = testcase_iid_from_url(test.testcase)
|
|
49
|
+
|
|
50
|
+
return unless iid
|
|
51
|
+
|
|
52
|
+
find_issue_by_iid(iid)
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def testcase_iid_from_url(url)
|
|
56
|
+
return warn(%(\nPlease update #{url} to test case url")) if url&.include?('/-/issues/')
|
|
57
|
+
|
|
58
|
+
url && url.split('/').last.to_i
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def new_issue_description(test)
|
|
62
|
+
"#{super}#{TEST_CASE_RESULTS_SECTION_TEMPLATE}"
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
end
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'active_support/core_ext/enumerable'
|
|
4
|
+
|
|
5
|
+
module Gitlab
|
|
6
|
+
module QA
|
|
7
|
+
module Report
|
|
8
|
+
module ResultsReporterShared
|
|
9
|
+
TEST_CASE_RESULTS_SECTION_TEMPLATE = "\n\n### DO NOT EDIT BELOW THIS LINE\n\nActive and historical test results:"
|
|
10
|
+
|
|
11
|
+
def find_issue(test)
|
|
12
|
+
issues = search_for_issues(test)
|
|
13
|
+
|
|
14
|
+
warn(%(Too many #{issue_type}s found with the file path "#{test.file}" and name "#{test.name}")) if issues.many?
|
|
15
|
+
puts "Found existing #{issue_type}: #{issues.first.web_url}" unless issues.empty?
|
|
16
|
+
|
|
17
|
+
issues.first
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def find_issue_by_iid(iid)
|
|
21
|
+
issues = gitlab.find_issues(iid: iid) do |issue|
|
|
22
|
+
issue.state == 'opened' && issue.issue_type == issue_type
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
warn(%(#{issue_type} iid "#{iid}" not valid)) if issues.empty?
|
|
26
|
+
|
|
27
|
+
issues.first
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def issue_title_needs_updating?(issue, test)
|
|
31
|
+
issue.title.strip != title_from_test(test) && !%w[canary production preprod release].include?(pipeline)
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def new_issue_labels(test)
|
|
35
|
+
['Quality', "devops::#{test.stage}", 'status::automated']
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def search_term(test)
|
|
39
|
+
%("#{partial_file_path(test.file)}" "#{search_safe(test.name)}")
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def up_to_date_labels(test:, issue: nil, new_labels: Set.new)
|
|
43
|
+
labels = super
|
|
44
|
+
labels |= new_issue_labels(test).to_set
|
|
45
|
+
labels.delete_if { |label| label.start_with?("#{pipeline}::") }
|
|
46
|
+
labels << (test.failures.empty? ? "#{pipeline}::passed" : "#{pipeline}::failed")
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def update_issue_title(issue, test)
|
|
50
|
+
warn(%(#{issue_type} title needs to be updated from '#{issue.title.strip}' to '#{title_from_test(test)}'))
|
|
51
|
+
|
|
52
|
+
gitlab.edit_issue(iid: issue.iid, options: { title: title_from_test(test) })
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
private
|
|
56
|
+
|
|
57
|
+
def search_for_issues(test)
|
|
58
|
+
gitlab.find_issues(options: { search: search_term(test) }) do |issue|
|
|
59
|
+
issue.state == 'opened' && issue.issue_type == issue_type && issue.title.strip == title_from_test(test)
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
end
|
data/lib/gitlab/qa/reporter.rb
CHANGED
|
@@ -17,8 +17,8 @@ module Gitlab
|
|
|
17
17
|
report_options[:input_files] = files if files
|
|
18
18
|
end
|
|
19
19
|
|
|
20
|
-
opts.on('--report-
|
|
21
|
-
report_options[:
|
|
20
|
+
opts.on('--report-results FILES', String, 'Report test results from JUnit XML files in GitLab test cases and results issues') do |files|
|
|
21
|
+
report_options[:report_results] = true
|
|
22
22
|
report_options[:input_files] = files if files
|
|
23
23
|
end
|
|
24
24
|
|
|
@@ -31,16 +31,24 @@ module Gitlab
|
|
|
31
31
|
report_options[:max_diff_ratio] = value
|
|
32
32
|
end
|
|
33
33
|
|
|
34
|
-
opts.on('-p', '--project PROJECT_ID', String, 'A valid project ID. Can be an integer or a group/project string. Required by --
|
|
34
|
+
opts.on('-p', '--project PROJECT_ID', String, 'A valid project ID. Can be an integer or a group/project string. Required by --relate-failure-issue') do |value|
|
|
35
35
|
report_options[:project] = value
|
|
36
36
|
end
|
|
37
37
|
|
|
38
|
+
opts.on('--results-issue-project RESULTS_ISSUE_PROJECT_ID', String, 'A valid project ID. Can be an integer or a group/project string. Required by --report-results') do |value|
|
|
39
|
+
report_options[:results_issue_project] = value
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
opts.on('--test-case-project TEST_CASE_PROJECT_ID', String, 'A valid project ID. Can be an integer or a group/project string. Required by --report-results') do |value|
|
|
43
|
+
report_options[:test_case_project] = value
|
|
44
|
+
end
|
|
45
|
+
|
|
38
46
|
opts.on('--generate-test-session FILES', String, 'Generate test session report') do |files|
|
|
39
47
|
report_options[:generate_test_session] = true
|
|
40
48
|
report_options[:input_files] = files if files
|
|
41
49
|
end
|
|
42
50
|
|
|
43
|
-
opts.on('-t', '--token ACCESS_TOKEN', String, 'A valid access token. Required by --report-
|
|
51
|
+
opts.on('-t', '--token ACCESS_TOKEN', String, 'A valid access token. Required by --report-results and --relate-failure-issue') do |value|
|
|
44
52
|
report_options[:token] = value
|
|
45
53
|
end
|
|
46
54
|
|
|
@@ -60,7 +68,7 @@ module Gitlab
|
|
|
60
68
|
report_options[:files] = files
|
|
61
69
|
end
|
|
62
70
|
|
|
63
|
-
opts.on('--dry-run', "Perform a dry-run (don't create or update issues)") do |files|
|
|
71
|
+
opts.on('--dry-run', "Perform a dry-run (don't create or update issues or test cases)") do |files|
|
|
64
72
|
report_options[:dry_run] = true
|
|
65
73
|
end
|
|
66
74
|
|
|
@@ -86,9 +94,9 @@ module Gitlab
|
|
|
86
94
|
report_options[:token] = Runtime::TokenFinder.find_token!(report_options[:token])
|
|
87
95
|
Gitlab::QA::Report::RelateFailureIssue.new(**report_options).invoke!
|
|
88
96
|
|
|
89
|
-
elsif report_options.delete(:
|
|
97
|
+
elsif report_options.delete(:report_results)
|
|
90
98
|
report_options[:token] = Runtime::TokenFinder.find_token!(report_options[:token])
|
|
91
|
-
Gitlab::QA::Report::
|
|
99
|
+
Gitlab::QA::Report::ReportResults.new(**report_options).invoke!
|
|
92
100
|
|
|
93
101
|
elsif report_options.delete(:generate_test_session)
|
|
94
102
|
report_options[:token] = Runtime::TokenFinder.find_token!(report_options[:token])
|
|
@@ -123,7 +123,8 @@ module Gitlab
|
|
|
123
123
|
'GOOGLE_JSON_KEY' => :google_json_key,
|
|
124
124
|
'GCS_BUCKET_NAME' => :gcs_bucket_name,
|
|
125
125
|
'SMOKE_ONLY' => :smoke_only,
|
|
126
|
-
'NO_ADMIN' => :no_admin
|
|
126
|
+
'NO_ADMIN' => :no_admin,
|
|
127
|
+
'CHROME_DISABLE_DEV_SHM' => :chrome_disable_dev_shm
|
|
127
128
|
}.freeze
|
|
128
129
|
|
|
129
130
|
ENV_VARIABLES.each do |env_name, method_name|
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Gitlab
|
|
4
|
+
module QA
|
|
5
|
+
module Scenario
|
|
6
|
+
module Test
|
|
7
|
+
module Integration
|
|
8
|
+
class ServicePingDisabled < Scenario::Template
|
|
9
|
+
def perform(release, *rspec_args)
|
|
10
|
+
Component::Gitlab.perform do |gitlab|
|
|
11
|
+
gitlab.release = release
|
|
12
|
+
gitlab.network = 'test'
|
|
13
|
+
|
|
14
|
+
gitlab.omnibus_configuration << <<~OMNIBUS
|
|
15
|
+
gitlab_rails['usage_ping_enabled'] = false;
|
|
16
|
+
OMNIBUS
|
|
17
|
+
|
|
18
|
+
gitlab.instance do
|
|
19
|
+
Component::Specs.perform do |specs|
|
|
20
|
+
specs.suite = 'Test::Integration::ServicePingDisabled'
|
|
21
|
+
specs.release = gitlab.release
|
|
22
|
+
specs.network = gitlab.network
|
|
23
|
+
specs.args = [gitlab.address, *rspec_args]
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
data/lib/gitlab/qa/version.rb
CHANGED
data/lib/gitlab/qa.rb
CHANGED
|
@@ -72,6 +72,7 @@ module Gitlab
|
|
|
72
72
|
autoload :ClientSSL, 'gitlab/qa/scenario/test/integration/client_ssl'
|
|
73
73
|
autoload :Registry, 'gitlab/qa/scenario/test/integration/registry'
|
|
74
74
|
autoload :RegistryTLS, 'gitlab/qa/scenario/test/integration/registry_tls'
|
|
75
|
+
autoload :ServicePingDisabled, 'gitlab/qa/scenario/test/integration/service_ping_disabled'
|
|
75
76
|
end
|
|
76
77
|
|
|
77
78
|
module Sanity
|
|
@@ -122,7 +123,10 @@ module Gitlab
|
|
|
122
123
|
autoload :JUnitTestResults, 'gitlab/qa/report/junit_test_results'
|
|
123
124
|
autoload :PrepareStageReports, 'gitlab/qa/report/prepare_stage_reports'
|
|
124
125
|
autoload :ReportAsIssue, 'gitlab/qa/report/report_as_issue'
|
|
126
|
+
autoload :ReportResults, 'gitlab/qa/report/report_results'
|
|
125
127
|
autoload :ResultsInIssues, 'gitlab/qa/report/results_in_issues'
|
|
128
|
+
autoload :ResultsInTestCases, 'gitlab/qa/report/results_in_testcases'
|
|
129
|
+
autoload :ResultsReporterShared, 'gitlab/qa/report/results_reporter_shared'
|
|
126
130
|
autoload :GenerateTestSession, 'gitlab/qa/report/generate_test_session'
|
|
127
131
|
autoload :SummaryTable, 'gitlab/qa/report/summary_table'
|
|
128
132
|
autoload :TestResult, 'gitlab/qa/report/test_result'
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: gitlab-qa
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 7.
|
|
4
|
+
version: 7.16.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- GitLab Quality
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: exe
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2021-
|
|
11
|
+
date: 2021-12-10 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: climate_control
|
|
@@ -256,7 +256,10 @@ files:
|
|
|
256
256
|
- lib/gitlab/qa/report/prepare_stage_reports.rb
|
|
257
257
|
- lib/gitlab/qa/report/relate_failure_issue.rb
|
|
258
258
|
- lib/gitlab/qa/report/report_as_issue.rb
|
|
259
|
+
- lib/gitlab/qa/report/report_results.rb
|
|
259
260
|
- lib/gitlab/qa/report/results_in_issues.rb
|
|
261
|
+
- lib/gitlab/qa/report/results_in_testcases.rb
|
|
262
|
+
- lib/gitlab/qa/report/results_reporter_shared.rb
|
|
260
263
|
- lib/gitlab/qa/report/summary_table.rb
|
|
261
264
|
- lib/gitlab/qa/report/test_result.rb
|
|
262
265
|
- lib/gitlab/qa/report/update_screenshot_path.rb
|
|
@@ -309,6 +312,7 @@ files:
|
|
|
309
312
|
- lib/gitlab/qa/scenario/test/integration/registry.rb
|
|
310
313
|
- lib/gitlab/qa/scenario/test/integration/registry_tls.rb
|
|
311
314
|
- lib/gitlab/qa/scenario/test/integration/saml.rb
|
|
315
|
+
- lib/gitlab/qa/scenario/test/integration/service_ping_disabled.rb
|
|
312
316
|
- lib/gitlab/qa/scenario/test/integration/smtp.rb
|
|
313
317
|
- lib/gitlab/qa/scenario/test/integration/ssh_tunnel.rb
|
|
314
318
|
- lib/gitlab/qa/scenario/test/omnibus/image.rb
|