gitlab-qa 9.1.2 → 10.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (80) hide show
  1. checksums.yaml +4 -4
  2. data/.gitlab-ci.yml +106 -149
  3. data/.simplecov +9 -0
  4. data/Gemfile.lock +15 -1
  5. data/README.md +5 -4
  6. data/docs/what_tests_can_be_run.md +73 -35
  7. data/gitlab-qa.gemspec +3 -0
  8. data/lib/gitlab/qa/component/base.rb +8 -1
  9. data/lib/gitlab/qa/component/gitaly.rb +1 -1
  10. data/lib/gitlab/qa/component/gitlab.rb +2 -2
  11. data/lib/gitlab/qa/component/mock_server.rb +13 -0
  12. data/lib/gitlab/qa/report/gitlab_issue_client.rb +1 -1
  13. data/lib/gitlab/qa/report/relate_failure_issue.rb +116 -20
  14. data/lib/gitlab/qa/report/report_as_issue.rb +1 -1
  15. data/lib/gitlab/qa/report/test_result.rb +2 -1
  16. data/lib/gitlab/qa/reporter.rb +8 -0
  17. data/lib/gitlab/qa/runtime/env.rb +17 -4
  18. data/lib/gitlab/qa/runtime/omnibus_configurations/decomposition_multiple_db.rb +1 -1
  19. data/lib/gitlab/qa/scenario/test/integration/oauth.rb +68 -0
  20. data/lib/gitlab/qa/scenario/test/omnibus/update_from_previous.rb +3 -2
  21. data/lib/gitlab/qa/system_logs/finders/json_log_finder.rb +65 -0
  22. data/lib/gitlab/qa/system_logs/finders/rails/api_log_finder.rb +21 -0
  23. data/lib/gitlab/qa/system_logs/finders/rails/application_log_finder.rb +21 -0
  24. data/lib/gitlab/qa/system_logs/finders/rails/exception_log_finder.rb +21 -0
  25. data/lib/gitlab/qa/system_logs/finders/rails/graphql_log_finder.rb +21 -0
  26. data/lib/gitlab/qa/system_logs/log_types/log.rb +38 -0
  27. data/lib/gitlab/qa/system_logs/log_types/rails/api_log.rb +34 -0
  28. data/lib/gitlab/qa/system_logs/log_types/rails/application_log.rb +27 -0
  29. data/lib/gitlab/qa/system_logs/log_types/rails/exception_log.rb +23 -0
  30. data/lib/gitlab/qa/system_logs/log_types/rails/graphql_log.rb +30 -0
  31. data/lib/gitlab/qa/system_logs/shared_fields.rb +29 -0
  32. data/lib/gitlab/qa/system_logs/system_logs_formatter.rb +65 -0
  33. data/lib/gitlab/qa/version.rb +1 -1
  34. data/scripts/build-package-and-test-env +15 -0
  35. metadata +59 -47
  36. data/.gitlab/ci/jobs/airgapped.gitlab-ci.yml +0 -23
  37. data/.gitlab/ci/jobs/base.gitlab-ci.yml +0 -273
  38. data/.gitlab/ci/jobs/chaos.gitlab-ci.yml +0 -22
  39. data/.gitlab/ci/jobs/cloud_activation.gitlab-ci.yml +0 -24
  40. data/.gitlab/ci/jobs/custom_parallel.gitlab-ci.yml +0 -21
  41. data/.gitlab/ci/jobs/decomposition_multiple_db.gitlab-ci.yml +0 -27
  42. data/.gitlab/ci/jobs/decomposition_single_db.gitlab-ci.yml +0 -25
  43. data/.gitlab/ci/jobs/ee_previous_to_ce_update.gitlab-ci.yml +0 -18
  44. data/.gitlab/ci/jobs/elasticsearch.gitlab-ci.yml +0 -20
  45. data/.gitlab/ci/jobs/geo.gitlab-ci.yml +0 -18
  46. data/.gitlab/ci/jobs/gitaly_cluster.gitlab-ci.yml +0 -41
  47. data/.gitlab/ci/jobs/gitlab_pages.gitlab-ci.yml +0 -19
  48. data/.gitlab/ci/jobs/group_saml.gitlab-ci.yml +0 -20
  49. data/.gitlab/ci/jobs/instance.gitlab-ci.yml +0 -55
  50. data/.gitlab/ci/jobs/instance_saml.gitlab-ci.yml +0 -41
  51. data/.gitlab/ci/jobs/integrations.gitlab-ci.yml +0 -14
  52. data/.gitlab/ci/jobs/jira.gitlab-ci.yml +0 -41
  53. data/.gitlab/ci/jobs/large_setup.gitlab-ci.yml +0 -19
  54. data/.gitlab/ci/jobs/ldap_no_server.gitlab-ci.yml +0 -20
  55. data/.gitlab/ci/jobs/ldap_no_tls.gitlab-ci.yml +0 -41
  56. data/.gitlab/ci/jobs/ldap_tls.gitlab-ci.yml +0 -41
  57. data/.gitlab/ci/jobs/mattermost.gitlab-ci.yml +0 -41
  58. data/.gitlab/ci/jobs/metrics.gitlab-ci.yml +0 -41
  59. data/.gitlab/ci/jobs/mtls.gitlab-ci.yml +0 -19
  60. data/.gitlab/ci/jobs/object_storage.gitlab-ci.yml +0 -49
  61. data/.gitlab/ci/jobs/object_storage_aws.gitlab-ci.yml +0 -25
  62. data/.gitlab/ci/jobs/object_storage_gcs.gitlab-ci.yml +0 -23
  63. data/.gitlab/ci/jobs/object_storage_registry_tls.gitlab-ci.yml +0 -41
  64. data/.gitlab/ci/jobs/omnibus_image.gitlab-ci.yml +0 -15
  65. data/.gitlab/ci/jobs/omnibus_upgrade.gitlab-ci.yml +0 -28
  66. data/.gitlab/ci/jobs/opensearch.gitlab-ci.yml +0 -20
  67. data/.gitlab/ci/jobs/packages.gitlab-ci.yml +0 -25
  68. data/.gitlab/ci/jobs/praefect.gitlab-ci.yml +0 -71
  69. data/.gitlab/ci/jobs/registry.gitlab-ci.yml +0 -41
  70. data/.gitlab/ci/jobs/registry_with_cdn.gitlab-ci.yml +0 -55
  71. data/.gitlab/ci/jobs/relative_url.gitlab-ci.yml +0 -65
  72. data/.gitlab/ci/jobs/repository_storage.gitlab-ci.yml +0 -41
  73. data/.gitlab/ci/jobs/sanity_framework.gitlab-ci.yml +0 -24
  74. data/.gitlab/ci/jobs/service_ping_disabled.gitlab-ci.yml +0 -19
  75. data/.gitlab/ci/jobs/smtp.gitlab-ci.yml +0 -19
  76. data/.gitlab/ci/jobs/staging.gitlab-ci.yml +0 -10
  77. data/.gitlab/ci/jobs/update.gitlab-ci.yml +0 -60
  78. data/.gitlab/ci/rules.gitlab-ci.yml +0 -183
  79. data/lib/gitlab/qa/scenario/test/omnibus/update.rb +0 -72
  80. data/scripts/generate-qa-jobs.rb +0 -99
@@ -13,15 +13,19 @@ module Gitlab
13
13
  include FindSetDri
14
14
 
15
15
  DEFAULT_MAX_DIFF_RATIO_FOR_DETECTION = 0.15
16
+ SPAM_THRESHOLD_FOR_FAILURE_ISSUES = 3
16
17
  FAILURE_STACKTRACE_REGEX = %r{((.*Failure\/Error:(?<stacktrace>.+))|(?<stacktrace>.+))}m.freeze
17
18
  ISSUE_STACKTRACE_REGEX = /### Stack trace\s*(```)#{FAILURE_STACKTRACE_REGEX}(```)/m.freeze
19
+ FAILED_JOB_DESCRIPTION_REGEX = %r{First happened in https?:\/\/\S+\.}m.freeze
20
+ FAILED_JOB_NOTE_REGEX = %r{Failed most recently in \D+ pipeline: https?:\/\/\S+}.freeze
18
21
  NEW_ISSUE_LABELS = Set.new(%w[QA Quality test failure::new priority::2]).freeze
19
22
  IGNORE_EXCEPTIONS = ['Net::ReadTimeout'].freeze
20
23
 
21
24
  MultipleIssuesFound = Class.new(StandardError)
22
25
 
23
- def initialize(max_diff_ratio: DEFAULT_MAX_DIFF_RATIO_FOR_DETECTION, **kwargs)
26
+ def initialize(system_logs: [], max_diff_ratio: DEFAULT_MAX_DIFF_RATIO_FOR_DETECTION, **kwargs)
24
27
  super
28
+ @system_logs = Dir.glob(system_logs)
25
29
  @max_diff_ratio = max_diff_ratio.to_f
26
30
  @issue_type = 'issue'
27
31
  @commented_issue_list = Set.new
@@ -60,17 +64,34 @@ module Gitlab
60
64
 
61
65
  def find_and_link_issue(test)
62
66
  issue, diff_ratio = find_failure_issue(test)
67
+ issue_already_commented = issue ? @commented_issue_list.include?(issue.web_url) : nil
63
68
 
64
- if issue
69
+ if issue && !issue_already_commented
65
70
  puts " => Found issue #{issue.web_url} for test '#{test.name}' with a diff ratio of #{(diff_ratio * 100).round(2)}%."
66
- @commented_issue_list.include?(issue.web_url) ? (puts " => Failure already commented on issue.") : post_or_update_failed_job_note(issue, test)
71
+ post_or_update_failed_job_note(issue, test)
67
72
  @commented_issue_list.add(issue.web_url)
73
+ else
74
+ puts " => Failure already commented on issue." if issue_already_commented
75
+
76
+ return false
68
77
  end
69
78
 
70
79
  issue
71
80
  end
72
81
 
73
82
  def create_issue(test)
83
+ similar_issues = pipeline_issues_with_similar_stacktrace(test)
84
+
85
+ if similar_issues.size >= SPAM_THRESHOLD_FOR_FAILURE_ISSUES
86
+ puts " => Similar failure issues have already been opened for same pipeline environment"
87
+ puts " => Will not create new issue for this failing spec"
88
+ similar_issues.each do |similar_issue|
89
+ puts "Please check issue: #{similar_issue.web_url}"
90
+ gitlab.create_issue_note(iid: similar_issue.iid, note: "This failed job is most likely related: #{test.ci_job_url}")
91
+ end
92
+ return
93
+ end
94
+
74
95
  issue = super
75
96
  puts "for test '#{test.name}'."
76
97
 
@@ -81,6 +102,50 @@ module Gitlab
81
102
  issue
82
103
  end
83
104
 
105
+ def pipeline_issues_with_similar_stacktrace(test)
106
+ gitlab.find_issues(options: { state: 'opened', labels: 'QA,failure::new', created_after: past_timestamp(2) }).select do |issue|
107
+ job_url_from_issue = failed_issue_job_url(issue)
108
+ next unless pipeline == pipeline_env_from_job_url(job_url_from_issue)
109
+
110
+ stack_trace_from_issue = cleaned_stack_trace_from_issue(issue)
111
+ stack_trace_from_test = cleaned_stacktrace_from_test(test)
112
+ diff_ratio = compare_stack_traces(stack_trace_from_test, stack_trace_from_issue)
113
+ diff_ratio < max_diff_ratio
114
+ end
115
+ end
116
+
117
+ def failed_issue_job_url(issue)
118
+ existing_note = existing_failure_note(issue)
119
+ if existing_note
120
+ job_url_string = existing_note.body
121
+ matched = job_url_string.match(FAILED_JOB_NOTE_REGEX)
122
+ else
123
+ job_url_string = issue.description
124
+ matched = job_url_string.match(FAILED_JOB_DESCRIPTION_REGEX)
125
+ end
126
+
127
+ return unless matched
128
+
129
+ job_url = matched[0].chop.split(" ").last
130
+ puts "=> Found failed job url in the issue: #{job_url}"
131
+ job_url
132
+ end
133
+
134
+ def pipeline_env_from_job_url(job_url)
135
+ return if job_url.nil?
136
+
137
+ if job_url.include?('/quality/')
138
+ job_url.partition('/quality/').last.partition('/').first
139
+ else
140
+ 'master'
141
+ end
142
+ end
143
+
144
+ def past_timestamp(hours_ago)
145
+ timestamp = Time.now - (hours_ago * 60 * 60)
146
+ timestamp.utc.strftime("%Y-%m-%dT%H:%M:%SZ")
147
+ end
148
+
84
149
  def failure_issues(test)
85
150
  gitlab.find_issues(options: { state: 'opened', labels: 'QA' }).select do |issue|
86
151
  issue_title = issue.title.strip
@@ -96,20 +161,36 @@ module Gitlab
96
161
  end
97
162
  end
98
163
 
99
- def find_relevant_failure_issues(test) # rubocop:disable Metrics/AbcSize
100
- ld = Class.new.extend(Gem::Text).method(:levenshtein_distance)
164
+ def cleaned_stack_trace_from_issue(issue)
165
+ relevant_issue_stacktrace = find_issue_stacktrace(issue)
166
+ return unless relevant_issue_stacktrace
167
+
168
+ remove_unique_resource_names(relevant_issue_stacktrace)
169
+ end
170
+
171
+ def cleaned_stacktrace_from_test(test)
101
172
  first_test_failure_stacktrace = sanitize_stacktrace(full_stacktrace(test), FAILURE_STACKTRACE_REGEX) || full_stacktrace(test)
102
- clean_first_test_failure_stacktrace = remove_unique_resource_names(first_test_failure_stacktrace)
173
+ remove_unique_resource_names(first_test_failure_stacktrace)
174
+ end
175
+
176
+ def compare_stack_traces(stack_trace_first, stack_trace_second)
177
+ calculate_diff_ratio(stack_trace_first, stack_trace_second)
178
+ end
179
+
180
+ def calculate_diff_ratio(stack_trace_first, stack_trace_second)
181
+ ld = Class.new.extend(Gem::Text).method(:levenshtein_distance)
182
+ distance = ld.call(stack_trace_first, stack_trace_second)
183
+ distance.zero? ? 0.0 : (distance.to_f / stack_trace_first.size).round(3)
184
+ end
103
185
 
186
+ def find_relevant_failure_issues(test) # rubocop:disable Metrics/AbcSize
187
+ clean_first_test_failure_stacktrace = cleaned_stacktrace_from_test(test)
104
188
  # Search with the `search` param returns 500 errors, so we filter by ~QA and then filter further in Ruby
105
189
  failure_issues(test).each_with_object({}) do |issue, memo|
106
- relevant_issue_stacktrace = find_issue_stacktrace(issue)
107
- next unless relevant_issue_stacktrace
108
-
109
- clean_relevant_issue_stacktrace = remove_unique_resource_names(relevant_issue_stacktrace)
110
- distance = ld.call(clean_first_test_failure_stacktrace, clean_relevant_issue_stacktrace)
111
- diff_ratio = distance.zero? ? 0.0 : (distance.to_f / clean_first_test_failure_stacktrace.size).round(3)
190
+ clean_relevant_issue_stacktrace = cleaned_stack_trace_from_issue(issue)
191
+ next if clean_relevant_issue_stacktrace.nil?
112
192
 
193
+ diff_ratio = compare_stack_traces(clean_first_test_failure_stacktrace, clean_relevant_issue_stacktrace)
113
194
  if diff_ratio <= max_diff_ratio
114
195
  puts " => [DEBUG] Issue #{issue.web_url} has an acceptable diff ratio of #{(diff_ratio * 100).round(2)}%."
115
196
  # The `Gitlab::ObjectifiedHash` class overrides `#hash` which is used by `Hash#[]=` to compute the hash key.
@@ -120,8 +201,8 @@ module Gitlab
120
201
  memo[issue.to_h] = diff_ratio
121
202
  else
122
203
  puts " => [DEBUG] Found issue #{issue.web_url} but stacktraces are too different (#{(diff_ratio * 100).round(2)}%).\n"
123
- puts " => [DEBUG] Issue stacktrace:\n----------------\n#{relevant_issue_stacktrace}\n----------------\n"
124
- puts " => [DEBUG] Failure stacktrace:\n----------------\n#{first_test_failure_stacktrace}\n----------------\n"
204
+ puts " => [DEBUG] Issue stacktrace:\n----------------\n#{clean_relevant_issue_stacktrace}\n----------------\n"
205
+ puts " => [DEBUG] Failure stacktrace:\n----------------\n#{clean_first_test_failure_stacktrace}\n----------------\n"
125
206
  end
126
207
  end
127
208
  end
@@ -137,7 +218,7 @@ module Gitlab
137
218
  stacktrace_match = stacktrace.match(regex)
138
219
 
139
220
  if stacktrace_match
140
- stacktrace_match[:stacktrace].gsub(/^\s*#.*$/, '').gsub(/^[[:space:]]+/, '').strip
221
+ stacktrace_match[:stacktrace].split('First happened in')[0].gsub(/^\s*#.*$/, '').gsub(/^[[:space:]]+/, '').strip
141
222
  else
142
223
  puts " => [DEBUG] Stacktrace doesn't match the expected regex (#{regex}):\n----------------\n#{stacktrace}\n----------------\n"
143
224
  end
@@ -172,10 +253,27 @@ module Gitlab
172
253
  "```\n#{full_stacktrace(test)}\n```",
173
254
  "First happened in #{test.ci_job_url}.",
174
255
  "Related test case: #{test.testcase}.",
175
- screenshot_section(test)
256
+ screenshot_section(test),
257
+ system_log_errors_section(test)
176
258
  ].join("\n\n")
177
259
  end
178
260
 
261
+ def system_log_errors_section(test)
262
+ correlation_id = test.failures.first['correlation_id']
263
+ section = ''
264
+
265
+ if @system_logs.any? && !correlation_id.nil?
266
+ section = SystemLogs::SystemLogsFormatter.new(
267
+ @system_logs,
268
+ correlation_id
269
+ ).system_logs_summary_markdown
270
+ end
271
+
272
+ puts " => No system logs or correlation id provided, skipping this section in issue description" if section.empty?
273
+
274
+ section
275
+ end
276
+
179
277
  def new_issue_labels(test)
180
278
  up_to_date_labels(test: test, new_labels: NEW_ISSUE_LABELS)
181
279
  end
@@ -202,11 +300,9 @@ module Gitlab
202
300
  end
203
301
 
204
302
  def existing_failure_note(issue)
205
- gitlab.find_issue_notes(iid: issue.iid).each do |note|
206
- return note if note.body.include?('Failed most recently in')
303
+ gitlab.find_issue_notes(iid: issue.iid)&.find do |note|
304
+ note.body.include?('Failed most recently in')
207
305
  end
208
-
209
- false
210
306
  end
211
307
 
212
308
  def screenshot_section(test)
@@ -140,7 +140,7 @@ module Gitlab
140
140
  end
141
141
 
142
142
  def partial_file_path(path)
143
- path.match(/((api|browser_ui).*)/i)[1]
143
+ path.match(/((ee|api|browser_ui).*)/i)[1]
144
144
  end
145
145
 
146
146
  def title_from_test(test)
@@ -128,7 +128,8 @@ module Gitlab
128
128
  {
129
129
  'message' => "#{exception['class']}: #{exception['message']}",
130
130
  'message_lines' => exception['message_lines'],
131
- 'stacktrace' => "#{format_message_lines(exception['message_lines'])}\n#{exception['backtrace'].slice(0..spec_file_first_index).join("\n")}"
131
+ 'stacktrace' => "#{format_message_lines(exception['message_lines'])}\n#{exception['backtrace'].slice(0..spec_file_first_index).join("\n")}",
132
+ 'correlation_id' => exception['correlation_id']
132
133
  }
133
134
  end
134
135
  end
@@ -7,6 +7,7 @@ module Gitlab
7
7
  class Reporter
8
8
  # rubocop:disable Metrics/AbcSize
9
9
  # rubocop:disable Metrics/PerceivedComplexity
10
+ # rubocop:disable Metrics/CyclomaticComplexity
10
11
  def self.invoke(args)
11
12
  report_options = {}
12
13
  slack_options = {}
@@ -65,6 +66,12 @@ module Gitlab
65
66
  slack_options[:message] = slack_options[:message] + "\n\n" + Gitlab::QA::Report::SummaryTable.create(input_files: files)
66
67
  end
67
68
 
69
+ opts.on('--include-system-log-errors FILES', String, 'Include errors from system logs in failure issues. To be used with --relate-failure-issue') do |files|
70
+ raise 'This option should be used with --relate-failure-issue.' unless report_options[:relate_failure_issue]
71
+
72
+ report_options[:system_logs] = files if files
73
+ end
74
+
68
75
  opts.on('--update-screenshot-path FILES', "Update the path to screenshots to container's host") do |files|
69
76
  report_options[:update_screenshot_path] = true
70
77
  report_options[:files] = files
@@ -116,6 +123,7 @@ module Gitlab
116
123
  exit 1
117
124
  end
118
125
  end
126
+ # rubocop:enable Metrics/CyclomaticComplexity
119
127
  # rubocop:enable Metrics/PerceivedComplexity
120
128
  # rubocop:enable Metrics/AbcSize
121
129
  end
@@ -73,8 +73,8 @@ module Gitlab
73
73
  'GITLAB_QA_PASSWORD_1' => :gitlab_qa_password_1,
74
74
  'GITLAB_QA_USERNAME_2' => :gitlab_qa_username_2,
75
75
  'GITLAB_QA_PASSWORD_2' => :gitlab_qa_password_2,
76
- 'GITHUB_USERNAME' => :github_username,
77
- 'GITHUB_PASSWORD' => :github_password,
76
+ 'QA_GITHUB_USERNAME' => :qa_github_username,
77
+ 'QA_GITHUB_PASSWORD' => :qa_github_password,
78
78
  'KNAPSACK_GENERATE_REPORT' => :knapsack_generate_report,
79
79
  'KNAPSACK_REPORT_PATH' => :knapsack_report_path,
80
80
  'KNAPSACK_TEST_FILE_PATTERN' => :knapsack_test_file_pattern,
@@ -138,7 +138,13 @@ module Gitlab
138
138
  'CHROME_DISABLE_DEV_SHM' => :chrome_disable_dev_shm,
139
139
  'COLORIZED_LOGS' => :colorized_logs,
140
140
  'FIPS' => :fips,
141
- 'JH_ENV' => :jh_env
141
+ 'JH_ENV' => :jh_env,
142
+ 'QA_GITHUB_OAUTH_APP_ID' => :github_oauth_app_id,
143
+ 'QA_GITHUB_OAUTH_APP_SECRET' => :github_oauth_app_secret,
144
+ 'QA_1P_EMAIL' => :qa_1p_email,
145
+ 'QA_1P_PASSWORD' => :qa_1p_password,
146
+ 'QA_1P_SECRET' => :qa_1p_secret,
147
+ 'QA_1P_GITHUB_UUID' => :qa_1p_github_uuid
142
148
  }.freeze
143
149
 
144
150
  ENV_VARIABLES.each do |env_name, method_name|
@@ -304,6 +310,13 @@ module Gitlab
304
310
  end
305
311
  end
306
312
 
313
+ def require_oauth_environment!
314
+ %w[QA_GITHUB_OAUTH_APP_ID QA_GITHUB_OAUTH_APP_SECRET QA_GITHUB_USERNAME
315
+ QA_GITHUB_PASSWORD QA_1P_EMAIL QA_1P_PASSWORD QA_1P_SECRET QA_1P_GITHUB_UUID].each do |env_key|
316
+ raise ArgumentError, "Environment variable #{env_key} must be set to run OAuth specs" unless ENV.key?(env_key)
317
+ end
318
+ end
319
+
307
320
  def require_initial_password!
308
321
  return unless env_var_value_if_defined('GITLAB_INITIAL_ROOT_PASSWORD').to_s.strip.empty?
309
322
 
@@ -406,7 +419,7 @@ module Gitlab
406
419
  end
407
420
 
408
421
  def mock_github_enabled?
409
- enabled?(env_var_value_if_defined('QA_MOCK_GITHUB'), default: false)
422
+ enabled?(env_var_value_if_defined('QA_MOCK_GITHUB'), default: true)
410
423
  end
411
424
 
412
425
  private
@@ -32,7 +32,7 @@ module Gitlab
32
32
  "gitlab-psql -d gitlabhq_production_ci -c 'create extension if not exists btree_gist'",
33
33
  "gitlab-psql -d gitlabhq_production_ci -c 'create extension if not exists pg_trgm'",
34
34
  # Load schema only if it does not exist.
35
- "#{SCHEMA_EXISTENCE_CHECK_COMMAND} || gitlab-rake db:schema:load:ci",
35
+ "#{SCHEMA_EXISTENCE_CHECK_COMMAND} || DISABLE_DATABASE_ENVIRONMENT_CHECK=1 gitlab-rake db:schema:load:ci",
36
36
  "gitlab-ctl restart"
37
37
  ].freeze
38
38
  end
@@ -0,0 +1,68 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'yaml'
4
+
5
+ module Gitlab
6
+ module QA
7
+ module Scenario
8
+ module Test
9
+ module Integration
10
+ class OAuth < Scenario::Template
11
+ attr_reader :gitlab_name
12
+
13
+ def initialize
14
+ @gitlab_name = 'gitlab-oauth'
15
+ end
16
+
17
+ def perform(release, *rspec_args)
18
+ Runtime::Env.require_oauth_environment!
19
+
20
+ release = Release.new(release)
21
+
22
+ Component::Gitlab.perform do |gitlab|
23
+ gitlab.release = release
24
+ gitlab.network = 'test'
25
+ gitlab.name = gitlab_name
26
+
27
+ gitlab.omnibus_configuration << gitlab_omnibus_configuration
28
+
29
+ gitlab.instance do
30
+ Runtime::Logger.info('Running OAuth specs!')
31
+
32
+ Component::Specs.perform do |specs|
33
+ rspec_args << '--' unless rspec_args.include?('--')
34
+ rspec_args << %w[--tag oauth]
35
+ specs.suite = 'Test::Instance::All'
36
+ specs.release = release
37
+ specs.network = gitlab.network
38
+ specs.args = [gitlab.address, *rspec_args]
39
+ end
40
+ end
41
+ end
42
+ end
43
+
44
+ private
45
+
46
+ def gitlab_omnibus_configuration
47
+ <<~OMNIBUS
48
+ gitlab_rails['omniauth_enabled'] = true;
49
+ gitlab_rails['omniauth_allow_single_sign_on'] = ['github'];
50
+ gitlab_rails['omniauth_block_auto_created_users'] = false;
51
+ gitlab_rails['omniauth_providers'] = [
52
+ {
53
+ name: 'github',
54
+ app_id: '$QA_GITHUB_OAUTH_APP_ID',
55
+ app_secret: '$QA_GITHUB_OAUTH_APP_SECRET',
56
+ url: 'https://github.com/',
57
+ verify_ssl: false,
58
+ args: { scope: 'user:email' }
59
+ }
60
+ ];
61
+ OMNIBUS
62
+ end
63
+ end
64
+ end
65
+ end
66
+ end
67
+ end
68
+ end
@@ -18,14 +18,15 @@ module Gitlab
18
18
  # @param [String] release current release docker image
19
19
  # @param [String] current_version current gitlab version associated with docker image
20
20
  # @param [String] semver_component semver component for N - 1 version detection, major|minor|patch
21
+ # @param [String] from_edition gitlab edition to update from
21
22
  # @param [Array] *rspec_args rspec arguments
22
23
  # @return [void]
23
- def perform(release, current_version, semver_component, *rspec_args)
24
+ def perform(release, current_version, semver_component, from_edition = nil, *rspec_args)
24
25
  @current_release = QA::Release.new(release)
25
26
  @upgrade_path = Support::GitlabUpgradePath.new(
26
27
  current_version,
27
28
  semver_component,
28
- @current_release.edition
29
+ from_edition || @current_release.edition
29
30
  ).fetch
30
31
 
31
32
  upgrade_info = "#{[*upgrade_path, current_release].join(' => ')} (#{current_version})".bright
@@ -0,0 +1,65 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'json'
4
+
5
+ module Gitlab
6
+ module QA
7
+ module SystemLogs
8
+ module Finders
9
+ class JsonLogFinder
10
+ def initialize(base_path, file_path)
11
+ @base_path = base_path
12
+ @file_path = file_path
13
+ end
14
+
15
+ def find(correlation_id)
16
+ log_file_path = "#{@base_path}/#{@file_path}"
17
+ logs = []
18
+
19
+ if File.exist?(log_file_path) && !correlation_id.nil?
20
+ File.foreach(log_file_path) do |line|
21
+ begin
22
+ json_line = JSON.parse(line, symbolize_names: true)
23
+ rescue JSON::ParserError
24
+ Runtime::Logger.debug("JsonLogFinder#find attempted to parse invalid JSON: #{line}")
25
+
26
+ next
27
+ end
28
+
29
+ if (json_line[:correlation_id])&.casecmp?(correlation_id)
30
+ normalized_line = normalize_keys(json_line)
31
+ logs << new_log(normalized_line)
32
+ end
33
+ end
34
+ end
35
+
36
+ logs
37
+ end
38
+
39
+ def new_log(data)
40
+ raise 'abstract method new_log must be defined!'
41
+ end
42
+
43
+ private
44
+
45
+ def normalize_keys(json_line)
46
+ normalized_hash = {}
47
+
48
+ json_line.each_key do |old_key|
49
+ key_string = old_key.to_s
50
+
51
+ if key_string.include?('.')
52
+ normalized_key = key_string.tr('.', '_').to_sym
53
+ normalized_hash[normalized_key] = json_line[old_key]
54
+ else
55
+ normalized_hash[old_key] = json_line[old_key]
56
+ end
57
+ end
58
+
59
+ normalized_hash
60
+ end
61
+ end
62
+ end
63
+ end
64
+ end
65
+ end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Gitlab
4
+ module QA
5
+ module SystemLogs
6
+ module Finders
7
+ module Rails
8
+ class ApiLogFinder < JsonLogFinder
9
+ def initialize(base_path, file_path = 'gitlab-rails/api_json.log')
10
+ super(base_path, file_path)
11
+ end
12
+
13
+ def new_log(data)
14
+ LogTypes::Rails::ApiLog.new(data)
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Gitlab
4
+ module QA
5
+ module SystemLogs
6
+ module Finders
7
+ module Rails
8
+ class ApplicationLogFinder < JsonLogFinder
9
+ def initialize(base_path, file_path = 'gitlab-rails/application_json.log')
10
+ super(base_path, file_path)
11
+ end
12
+
13
+ def new_log(data)
14
+ LogTypes::Rails::ApplicationLog.new(data)
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Gitlab
4
+ module QA
5
+ module SystemLogs
6
+ module Finders
7
+ module Rails
8
+ class ExceptionLogFinder < JsonLogFinder
9
+ def initialize(base_path, file_path = 'gitlab-rails/exceptions_json.log')
10
+ super(base_path, file_path)
11
+ end
12
+
13
+ def new_log(data)
14
+ LogTypes::Rails::ExceptionLog.new(data)
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Gitlab
4
+ module QA
5
+ module SystemLogs
6
+ module Finders
7
+ module Rails
8
+ class GraphqlLogFinder < JsonLogFinder
9
+ def initialize(base_path, file_path = 'gitlab-rails/graphql_json.log')
10
+ super(base_path, file_path)
11
+ end
12
+
13
+ def new_log(data)
14
+ LogTypes::Rails::GraphqlLog.new(data)
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,38 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Gitlab
4
+ module QA
5
+ module SystemLogs
6
+ module LogTypes
7
+ class Log
8
+ def initialize(name, data)
9
+ @name = name
10
+ @data = data
11
+ end
12
+
13
+ attr_reader :name, :data
14
+
15
+ def summary_fields
16
+ [
17
+ :severity,
18
+ :correlation_id,
19
+ :time,
20
+ :message
21
+ ]
22
+ end
23
+
24
+ def summary
25
+ summary = {}
26
+
27
+ summary_fields.each do |field|
28
+ value = data[field]
29
+ summary[field] = value unless value.nil?
30
+ end
31
+
32
+ summary
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Gitlab
4
+ module QA
5
+ module SystemLogs
6
+ module LogTypes
7
+ module Rails
8
+ class ApiLog < Log
9
+ include SharedFields::Exception
10
+ include SharedFields::Meta
11
+
12
+ def initialize(data)
13
+ super('Rails API', data)
14
+ end
15
+
16
+ def summary_fields
17
+ super.concat(
18
+ [
19
+ :method,
20
+ :path,
21
+ :status,
22
+ :params,
23
+ :api_error
24
+ ],
25
+ exception_fields,
26
+ meta_fields
27
+ )
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Gitlab
4
+ module QA
5
+ module SystemLogs
6
+ module LogTypes
7
+ module Rails
8
+ class ApplicationLog < Log
9
+ include SharedFields::Exception
10
+ include SharedFields::Meta
11
+
12
+ def initialize(data)
13
+ super('Rails Application', data)
14
+ end
15
+
16
+ def summary_fields
17
+ super.concat(
18
+ exception_fields,
19
+ meta_fields
20
+ )
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end