gitlab-qa 9.1.2 → 10.1.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.
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