gitlab_quality-test_tooling 1.32.1 → 1.34.0
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/Gemfile.lock +1 -1
- data/lib/gitlab_quality/test_tooling/knapsack_reports/spec_run_time.rb +38 -4
- data/lib/gitlab_quality/test_tooling/knapsack_reports/spec_run_time_report.rb +5 -1
- data/lib/gitlab_quality/test_tooling/labels_inference.rb +0 -1
- data/lib/gitlab_quality/test_tooling/report/concerns/group_and_category_labels.rb +7 -4
- data/lib/gitlab_quality/test_tooling/report/knapsack_report_issue.rb +7 -4
- data/lib/gitlab_quality/test_tooling/report/report_as_issue.rb +2 -2
- data/lib/gitlab_quality/test_tooling/report/slow_test_issue.rb +3 -3
- data/lib/gitlab_quality/test_tooling/test_meta/test_meta_updater.rb +1 -2
- data/lib/gitlab_quality/test_tooling/test_result/base_test_result.rb +51 -4
- data/lib/gitlab_quality/test_tooling/test_result/j_unit_test_result.rb +1 -52
- data/lib/gitlab_quality/test_tooling/test_result/json_test_result.rb +0 -51
- data/lib/gitlab_quality/test_tooling/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6d3f45e3af6f11c3ebca5f44f3d717960c1ac20cffdc13db75a16d68c9eecfbd
|
4
|
+
data.tar.gz: 0edf629fc7f432a779141be67a231887224a78793defedad416df50b327ecbcb
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 7570cde0cd99ea0fe3148f9a8c1f9a7035c165fb0f5506623a79d3f2c3227581d6de878fd56c9a5d5f4c4bae22191d688f49355c74e4b4926b6362ef5d3f8d06
|
7
|
+
data.tar.gz: 0112df035902806c60a82433118669b43bcd9feff89fd8dc7061ee6ffcda9c53ead791c7df4c188567b2b16ee3be8880e269088f4bee944b944aa2dafb60bfef
|
data/Gemfile.lock
CHANGED
@@ -4,19 +4,39 @@ module GitlabQuality
|
|
4
4
|
module TestTooling
|
5
5
|
module KnapsackReports
|
6
6
|
class SpecRunTime
|
7
|
-
attr_reader :
|
7
|
+
attr_reader :file, :expected, :actual, :expected_suite_duration, :actual_suite_duration, :project, :ref
|
8
8
|
|
9
9
|
ACTUAL_TO_EXPECTED_SPEC_RUN_TIME_RATIO_THRESHOLD = 1.5 # actual run time is longer than expected by 50% +
|
10
10
|
SPEC_WEIGHT_PERCENTAGE_TRESHOLD = 15 # a spec file takes 15%+ of the total test suite run time
|
11
11
|
SUITE_DURATION_THRESHOLD = 70 * 60 # if test suite takes more than 70 minutes, job risks timing out
|
12
|
-
|
13
|
-
|
14
|
-
|
12
|
+
FEATURE_CATEGORY_METADATA_REGEX = /(?<=feature_category: :)(?<feature_category>\w+)/
|
13
|
+
|
14
|
+
def initialize(
|
15
|
+
file:,
|
16
|
+
expected:,
|
17
|
+
actual:,
|
18
|
+
expected_suite_duration:,
|
19
|
+
actual_suite_duration:,
|
20
|
+
token: '',
|
21
|
+
project: Runtime::Env.ci_project_path,
|
22
|
+
ref: Runtime::Env.ci_commit_ref_name)
|
15
23
|
@file = file
|
16
24
|
@expected = expected.to_f
|
17
25
|
@actual = actual.to_f
|
18
26
|
@expected_suite_duration = expected_suite_duration.to_f
|
19
27
|
@actual_suite_duration = actual_suite_duration.to_f
|
28
|
+
@token = token
|
29
|
+
@project = project
|
30
|
+
@ref = ref
|
31
|
+
end
|
32
|
+
|
33
|
+
def feature_category
|
34
|
+
file_lines.each do |line|
|
35
|
+
match = FEATURE_CATEGORY_METADATA_REGEX.match(line)
|
36
|
+
next unless match
|
37
|
+
|
38
|
+
break match[:feature_category]
|
39
|
+
end
|
20
40
|
end
|
21
41
|
|
22
42
|
def should_report?
|
@@ -50,6 +70,8 @@ module GitlabQuality
|
|
50
70
|
|
51
71
|
private
|
52
72
|
|
73
|
+
attr_reader :token
|
74
|
+
|
53
75
|
def exceed_actual_to_expected_ratio_threshold?
|
54
76
|
actual / expected >= ACTUAL_TO_EXPECTED_SPEC_RUN_TIME_RATIO_THRESHOLD
|
55
77
|
end
|
@@ -80,6 +102,18 @@ module GitlabQuality
|
|
80
102
|
def file_link
|
81
103
|
"https://gitlab.com/#{project}/-/blob/#{Runtime::Env.ci_commit_ref_name}/#{file}"
|
82
104
|
end
|
105
|
+
|
106
|
+
def file_lines
|
107
|
+
files_client.file_contents.lines(chomp: true)
|
108
|
+
end
|
109
|
+
|
110
|
+
def files_client
|
111
|
+
@files_client ||= GitlabClient::RepositoryFilesClient.new(
|
112
|
+
token: token,
|
113
|
+
project: project,
|
114
|
+
file_path: file,
|
115
|
+
ref: ref)
|
116
|
+
end
|
83
117
|
end
|
84
118
|
end
|
85
119
|
end
|
@@ -8,10 +8,11 @@ module GitlabQuality
|
|
8
8
|
class SpecRunTimeReport
|
9
9
|
attr_reader :project, :expected_report, :actual_report
|
10
10
|
|
11
|
-
def initialize(project:, expected_report_path:, actual_report_path:)
|
11
|
+
def initialize(project:, expected_report_path:, actual_report_path:, token: '')
|
12
12
|
@project = project
|
13
13
|
@expected_report = parse(expected_report_path)
|
14
14
|
@actual_report = parse(actual_report_path)
|
15
|
+
@token = token
|
15
16
|
end
|
16
17
|
|
17
18
|
def filtered_report
|
@@ -25,6 +26,7 @@ module GitlabQuality
|
|
25
26
|
end
|
26
27
|
|
27
28
|
spec_run_time = SpecRunTime.new(
|
29
|
+
token: token,
|
28
30
|
project: project,
|
29
31
|
file: spec_file,
|
30
32
|
expected: expected_run_time,
|
@@ -39,6 +41,8 @@ module GitlabQuality
|
|
39
41
|
|
40
42
|
private
|
41
43
|
|
44
|
+
attr_reader :token
|
45
|
+
|
42
46
|
def parse(report_path)
|
43
47
|
JSON.parse(File.read(report_path))
|
44
48
|
end
|
@@ -10,7 +10,6 @@ module GitlabQuality
|
|
10
10
|
WWW_GITLAB_COM_SITE = 'https://about.gitlab.com'
|
11
11
|
WWW_GITLAB_COM_GROUPS_JSON = "#{WWW_GITLAB_COM_SITE}/groups.json".freeze
|
12
12
|
WWW_GITLAB_COM_CATEGORIES_JSON = "#{WWW_GITLAB_COM_SITE}/categories.json".freeze
|
13
|
-
FEATURE_CATEGORY_METADATA_REGEX = /(?<=feature_category: :)\w+/
|
14
13
|
|
15
14
|
def infer_labels_from_product_group(product_group)
|
16
15
|
[groups_mapping.dig(product_group, 'label')].compact.to_set
|
@@ -10,11 +10,14 @@ module GitlabQuality
|
|
10
10
|
end
|
11
11
|
|
12
12
|
def new_issue_labels(test)
|
13
|
-
|
13
|
+
debug_line = ' => [DEBUG] '
|
14
|
+
debug_line += "product_group: #{test&.product_group}; " if test.respond_to?(:product_group)
|
15
|
+
debug_line += "feature_category: #{test&.feature_category}" if test.respond_to?(:feature_category)
|
16
|
+
puts debug_line
|
14
17
|
|
15
|
-
new_labels = self.class::NEW_ISSUE_LABELS
|
16
|
-
|
17
|
-
|
18
|
+
new_labels = self.class::NEW_ISSUE_LABELS
|
19
|
+
new_labels += labels_inference.infer_labels_from_product_group(test.product_group) if test.respond_to?(:product_group)
|
20
|
+
new_labels += labels_inference.infer_labels_from_feature_category(test.feature_category) if test.respond_to?(:feature_category)
|
18
21
|
up_to_date_labels(test: test, new_labels: new_labels)
|
19
22
|
end
|
20
23
|
end
|
@@ -14,6 +14,8 @@ module GitlabQuality
|
|
14
14
|
# - If not found:
|
15
15
|
# - Create a new issue with the run time data
|
16
16
|
class KnapsackReportIssue < ReportAsIssue
|
17
|
+
include Concerns::GroupAndCategoryLabels
|
18
|
+
|
17
19
|
NEW_ISSUE_LABELS = Set.new(['test', 'type::maintenance', 'maintenance::performance', 'priority::3', 'severity::3', 'knapsack_report']).freeze
|
18
20
|
SEARCH_LABELS = %w[test maintenance::performance knapsack_report].freeze
|
19
21
|
JOB_TIMEOUT_EPIC_URL = 'https://gitlab.com/groups/gitlab-org/quality/engineering-productivity/-/epics/19'
|
@@ -36,6 +38,7 @@ module GitlabQuality
|
|
36
38
|
|
37
39
|
def search_and_create_issue
|
38
40
|
filtered_report = KnapsackReports::SpecRunTimeReport.new(
|
41
|
+
token: token,
|
39
42
|
project: project,
|
40
43
|
expected_report_path: expected_report_path,
|
41
44
|
actual_report_path: actual_report_path
|
@@ -67,10 +70,6 @@ module GitlabQuality
|
|
67
70
|
files.first
|
68
71
|
end
|
69
72
|
|
70
|
-
def new_issue_labels(_spec_run_time)
|
71
|
-
NEW_ISSUE_LABELS
|
72
|
-
end
|
73
|
-
|
74
73
|
def new_issue_title(spec_run_time)
|
75
74
|
"Job timeout risk: #{spec_run_time.file} ran much longer than expected"
|
76
75
|
end
|
@@ -110,6 +109,10 @@ module GitlabQuality
|
|
110
109
|
description: updated_description
|
111
110
|
}
|
112
111
|
|
112
|
+
# We reopen closed issues to not lose any history
|
113
|
+
state_event = issue.state == 'closed' ? 'reopen' : nil
|
114
|
+
issue_attrs[:state_event] = state_event if state_event
|
115
|
+
|
113
116
|
gitlab.edit_issue(iid: issue.iid, options: issue_attrs)
|
114
117
|
puts " => Added a report in #{issue.web_url}!"
|
115
118
|
end
|
@@ -149,14 +149,14 @@ module GitlabQuality
|
|
149
149
|
labels |= new_labels.to_set
|
150
150
|
ee_test?(test) ? labels << 'Enterprise Edition' : labels.delete('Enterprise Edition')
|
151
151
|
|
152
|
-
if test.quarantine?
|
152
|
+
if test.respond_to?(:quarantine?) && test.quarantine?
|
153
153
|
labels << 'quarantine'
|
154
154
|
labels << "quarantine::#{test.quarantine_type}"
|
155
155
|
else
|
156
156
|
labels.delete_if { |label| label.include?('quarantine') }
|
157
157
|
end
|
158
158
|
|
159
|
-
labels << 'rspec-shared-examples' if test.calls_shared_examples?
|
159
|
+
labels << 'rspec-shared-examples' if test.respond_to?(:calls_shared_examples?) && test.calls_shared_examples?
|
160
160
|
|
161
161
|
labels
|
162
162
|
end
|
@@ -44,11 +44,11 @@ module GitlabQuality
|
|
44
44
|
|
45
45
|
def health_problem_status_label_quick_action(reports_list)
|
46
46
|
case reports_list.reports_count
|
47
|
-
when
|
47
|
+
when 6099..Float::INFINITY
|
48
48
|
'/label ~"slowness::1"'
|
49
|
-
when
|
49
|
+
when 2177..6098
|
50
50
|
'/label ~"slowness::2"'
|
51
|
-
when
|
51
|
+
when 521..2176
|
52
52
|
'/label ~"slowness::3"'
|
53
53
|
else
|
54
54
|
'/label ~"slowness::4"'
|
@@ -11,7 +11,6 @@ module GitlabQuality
|
|
11
11
|
attr_reader :project, :ref, :report_issue, :processed_commits
|
12
12
|
|
13
13
|
TEST_PLATFORM_MAINTAINERS_SLACK_CHANNEL_ID = 'C0437FV9KBN' # test-platform-maintainers
|
14
|
-
BATCH_LIMIT = 10
|
15
14
|
|
16
15
|
def initialize(token:, project:, specs_file:, processor:, ref: 'master', dry_run: false)
|
17
16
|
@specs_file = specs_file
|
@@ -29,7 +28,7 @@ module GitlabQuality
|
|
29
28
|
|
30
29
|
contents['specs'].each do |spec|
|
31
30
|
processor.create_commit(spec, self)
|
32
|
-
break if processed_commits.keys.count >= BATCH_LIMIT
|
31
|
+
break if processed_commits.keys.count >= ENV.fetch('BATCH_LIMIT', 10)
|
33
32
|
end
|
34
33
|
|
35
34
|
processor.create_merge_requests(self)
|
@@ -32,10 +32,6 @@ module GitlabQuality
|
|
32
32
|
raise NotImplementedError
|
33
33
|
end
|
34
34
|
|
35
|
-
def line_number
|
36
|
-
raise NotImplementedError
|
37
|
-
end
|
38
|
-
|
39
35
|
def section
|
40
36
|
raise NotImplementedError
|
41
37
|
end
|
@@ -52,10 +48,53 @@ module GitlabQuality
|
|
52
48
|
raise NotImplementedError
|
53
49
|
end
|
54
50
|
|
51
|
+
def product_group
|
52
|
+
report['product_group'].to_s
|
53
|
+
end
|
54
|
+
|
55
|
+
def feature_category
|
56
|
+
report['feature_category']
|
57
|
+
end
|
58
|
+
|
55
59
|
def failures?
|
56
60
|
failures.any?
|
57
61
|
end
|
58
62
|
|
63
|
+
def product_group?
|
64
|
+
product_group != ''
|
65
|
+
end
|
66
|
+
|
67
|
+
def failure_issue
|
68
|
+
report['failure_issue']
|
69
|
+
end
|
70
|
+
|
71
|
+
def failure_issue=(new_failure_issue)
|
72
|
+
report['failure_issue'] = new_failure_issue
|
73
|
+
end
|
74
|
+
|
75
|
+
def line_number
|
76
|
+
report['line_number']
|
77
|
+
end
|
78
|
+
|
79
|
+
def level
|
80
|
+
report['level']
|
81
|
+
end
|
82
|
+
|
83
|
+
def run_time
|
84
|
+
report['run_time'].to_f.round(2)
|
85
|
+
end
|
86
|
+
|
87
|
+
def screenshot?
|
88
|
+
!!screenshot
|
89
|
+
end
|
90
|
+
|
91
|
+
def quarantine?
|
92
|
+
# The value for 'quarantine' could be nil, a hash, a string,
|
93
|
+
# or true (if the test just has the :quarantine tag)
|
94
|
+
# But any non-nil or false value should means the test is in quarantine
|
95
|
+
!!quarantine
|
96
|
+
end
|
97
|
+
|
59
98
|
def file
|
60
99
|
@file ||= relative_file.start_with?('qa/') ? "qa/#{relative_file}" : relative_file
|
61
100
|
end
|
@@ -98,6 +137,14 @@ module GitlabQuality
|
|
98
137
|
private
|
99
138
|
|
100
139
|
attr_reader :token, :project, :ref
|
140
|
+
|
141
|
+
def screenshot
|
142
|
+
report.fetch('screenshot', nil)
|
143
|
+
end
|
144
|
+
|
145
|
+
def quarantine
|
146
|
+
report.fetch('quarantine', nil)
|
147
|
+
end
|
101
148
|
end
|
102
149
|
end
|
103
150
|
end
|
@@ -40,64 +40,13 @@ module GitlabQuality
|
|
40
40
|
end
|
41
41
|
end
|
42
42
|
|
43
|
-
def quarantine
|
44
|
-
!report['quarantine'].nil?
|
45
|
-
end
|
46
|
-
|
47
|
-
def quarantine?
|
48
|
-
# The value for 'quarantine' could be nil, a hash, a string,
|
49
|
-
# or true (if the test just has the :quarantine tag)
|
50
|
-
# But any non-nil or false value should means the test is in quarantine
|
51
|
-
!!quarantine
|
52
|
-
end
|
53
|
-
|
54
|
-
def line_number
|
55
|
-
report['line_number']
|
56
|
-
end
|
57
|
-
|
58
|
-
def level
|
59
|
-
report['level']
|
60
|
-
end
|
61
|
-
|
62
|
-
def run_time
|
63
|
-
report['run_time'].to_f.round(2)
|
64
|
-
end
|
65
|
-
|
66
|
-
def screenshot
|
67
|
-
report['screenshot']
|
68
|
-
end
|
69
|
-
|
70
|
-
def screenshot?
|
71
|
-
!!screenshot
|
72
|
-
end
|
73
|
-
|
74
43
|
def max_duration_for_test
|
75
|
-
|
44
|
+
''
|
76
45
|
end
|
77
46
|
|
78
47
|
def ci_job_url
|
79
48
|
ENV.fetch('CI_JOB_URL', '')
|
80
49
|
end
|
81
|
-
|
82
|
-
def product_group
|
83
|
-
report['product_group'].to_s
|
84
|
-
end
|
85
|
-
|
86
|
-
def product_group?
|
87
|
-
product_group != ''
|
88
|
-
end
|
89
|
-
|
90
|
-
def feature_category
|
91
|
-
report['feature_category']
|
92
|
-
end
|
93
|
-
|
94
|
-
def failure_issue
|
95
|
-
report['failure_issue']
|
96
|
-
end
|
97
|
-
|
98
|
-
def failure_issue=(new_failure_issue)
|
99
|
-
report['failure_issue'] = new_failure_issue
|
100
|
-
end
|
101
50
|
end
|
102
51
|
end
|
103
52
|
end
|
@@ -68,21 +68,6 @@ module GitlabQuality
|
|
68
68
|
report['testcase'] = new_testcase
|
69
69
|
end
|
70
70
|
|
71
|
-
def failure_issue
|
72
|
-
report['failure_issue']
|
73
|
-
end
|
74
|
-
|
75
|
-
def failure_issue=(new_failure_issue)
|
76
|
-
report['failure_issue'] = new_failure_issue
|
77
|
-
end
|
78
|
-
|
79
|
-
def quarantine?
|
80
|
-
# The value for 'quarantine' could be nil, a hash, a string,
|
81
|
-
# or true (if the test just has the :quarantine tag)
|
82
|
-
# But any non-nil or false value should means the test is in quarantine
|
83
|
-
!!quarantine
|
84
|
-
end
|
85
|
-
|
86
71
|
def quarantine_type
|
87
72
|
quarantine['type'] if quarantine?
|
88
73
|
end
|
@@ -91,26 +76,10 @@ module GitlabQuality
|
|
91
76
|
quarantine['issue'] if quarantine?
|
92
77
|
end
|
93
78
|
|
94
|
-
def screenshot?
|
95
|
-
!!screenshot
|
96
|
-
end
|
97
|
-
|
98
79
|
def screenshot_image
|
99
80
|
screenshot['image'] if screenshot?
|
100
81
|
end
|
101
82
|
|
102
|
-
def product_group
|
103
|
-
report['product_group'].to_s
|
104
|
-
end
|
105
|
-
|
106
|
-
def product_group?
|
107
|
-
product_group != ''
|
108
|
-
end
|
109
|
-
|
110
|
-
def feature_category
|
111
|
-
report['feature_category']
|
112
|
-
end
|
113
|
-
|
114
83
|
def section
|
115
84
|
report['section']
|
116
85
|
end
|
@@ -119,22 +88,10 @@ module GitlabQuality
|
|
119
88
|
report['category']
|
120
89
|
end
|
121
90
|
|
122
|
-
def run_time
|
123
|
-
report['run_time'].to_f.round(2)
|
124
|
-
end
|
125
|
-
|
126
91
|
def example_id
|
127
92
|
report['id']
|
128
93
|
end
|
129
94
|
|
130
|
-
def line_number
|
131
|
-
report['line_number']
|
132
|
-
end
|
133
|
-
|
134
|
-
def level
|
135
|
-
report['level']
|
136
|
-
end
|
137
|
-
|
138
95
|
def ci_job_id
|
139
96
|
report['ci_job_url'].split('/').last
|
140
97
|
end
|
@@ -180,14 +137,6 @@ module GitlabQuality
|
|
180
137
|
|
181
138
|
private
|
182
139
|
|
183
|
-
def quarantine
|
184
|
-
report.fetch('quarantine', nil)
|
185
|
-
end
|
186
|
-
|
187
|
-
def screenshot
|
188
|
-
report.fetch('screenshot', nil)
|
189
|
-
end
|
190
|
-
|
191
140
|
def format_message_lines(message_lines)
|
192
141
|
message_lines.is_a?(Array) ? message_lines.join("\n") : message_lines
|
193
142
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: gitlab_quality-test_tooling
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.34.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- GitLab Quality
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-
|
11
|
+
date: 2024-08-19 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: climate_control
|