gitlab-qa 12.4.1 → 12.5.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 367b59ae508a9c2c33e9703ef5838f654326938179b0fff4e9854394dec28566
4
- data.tar.gz: 72498fa54bd13f7ea378bc74307b9d08a8078f75ac185893e36a6ed2717f5f72
3
+ metadata.gz: 886c387d7119bbeaff903a9396e315d79563805e6582a9d479cb0d827cc3526d
4
+ data.tar.gz: e0a58c2a59421fbb55ba7d64613dc8240368af30e544a6d573f0ef64baf81f0b
5
5
  SHA512:
6
- metadata.gz: 920ac1c0445f1ba5cecb1864e759df9c5cf5c48fbb89ba24ff04fc1960b8a21c771d7d6f981205125ac7cea882d15ab533ec906a90478da3336ddc345a795a2c
7
- data.tar.gz: e48d7d55d2ccb5dfcf280a4626f1e2c798af68afaeea345c248b14947951942229d3a23add3e408dcd2faa68e0a5f0b7230333d7e6d5b6eefb6fc74d37193c8c
6
+ metadata.gz: 0b61da0814b8ce32f7fadc0f7dac3aaeb1beb280d64bbd051cae5027d3c94942977b3dae19833f4e516b9aff7e084eb3d2acb239783f33eecb64b2eed11d7ab7
7
+ data.tar.gz: 0ee1817892437a9157cd90ea1139040b171df703c8d4c4733287eb09c6b0c86aa8fa10cb412bd387f2e34606319399b1e09190259d2eddef0e9078b9fd5bddf3
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- gitlab-qa (12.4.1)
4
+ gitlab-qa (12.5.0)
5
5
  activesupport (>= 6.1, < 7.1)
6
6
  gitlab (~> 4.19)
7
7
  http (~> 5.0)
data/README.md CHANGED
@@ -92,6 +92,7 @@ of tests.
92
92
  - [Trainings](docs/trainings.md)
93
93
  - [Waits](docs/waits.md)
94
94
  - [What tests can be run?](docs/what_tests_can_be_run.md)
95
+ - [Specifics for Mac OS with M1, M2 processors & Docker Desktop](docs/specifics_for_macos_m1_m2.md)
95
96
 
96
97
  ## How do we use it
97
98
 
@@ -83,6 +83,36 @@ Notes:
83
83
  - Extending the class from `Default` is only a nicety that adds a singleton method called `Registry.configuration` and returns the configuration.
84
84
  It is recommended to extend from `Default`, but you may also extend from any other Omnibus Configuration class, including `Runtime::OmnibusConfiguration`.
85
85
 
86
+ ## Setting variables from components in Omnibus configuration using ERB template
87
+
88
+ Omnibus configurations can use ERB templates to serve as a placeholder for variables. These variable can be replaced with actual value in a component
89
+ when preparing the omnibus config.
90
+
91
+ for example:
92
+
93
+ ```ruby
94
+ #=> lib/gitlab/qa/runtime/omnibus_configurations/github_oauth.rb
95
+
96
+ module Gitlab
97
+ module QA
98
+ module Runtime
99
+ module OmnibusConfigurations
100
+ class GithubOauth < Default
101
+ def configuration
102
+ <<~OMNIBUS
103
+ ...
104
+ external_url '<%= gitlab.address %>';
105
+ OMNIBUS
106
+ end
107
+ end
108
+ end
109
+ end
110
+ end
111
+ end
112
+ ```
113
+
114
+ Here, `<%= gitlab.address %>` will be replaced by calling the `address` method on an instance of the `gitlab` component.
115
+
86
116
  ## Running tests with Omnibus Configured
87
117
 
88
118
  All Omnibus Configurators can be called by passing arguments into the `gitlab-qa` executable.
@@ -0,0 +1,44 @@
1
+ # Specifics for Mac OS with M1, M2 processors & Docker Desktop
2
+
3
+ You might encounter the following errors when running tests locally, using Gitlab QA, on Mac OS with M1 or M2 processors. These errors usually stem from using Docker images that are based on Linux/AMD64 platforms.
4
+
5
+ - `MADV_DONTNEED` does not work (memset will be used instead)
6
+
7
+ ```
8
+ <jemalloc>: MADV_DONTNEED does not work (memset will be used instead)
9
+ <jemalloc>: (This is the expected behaviour if you are running under QEMU)
10
+ bundler: failed to load command: bin/qa (bin/qa)
11
+ #0 0x004000724133 <unknown>: unknown error: Chrome failed to start: crashed. (Selenium::WebDriver::Error::UnknownError)
12
+ (unknown error: DevToolsActivePort file doesn't exist)
13
+ (The process started from chrome location /usr/bin/google-chrome is no longer running,
14
+ so ChromeDriver is assuming that Chrome has crashed.)
15
+ ```
16
+
17
+ - `QA::Support::Repeater::WaitExceededError`
18
+
19
+ ```
20
+ QA::Support::Repeater::WaitExceededError:
21
+ Page did not fully load. This could be due to an unending async request or loading icon.
22
+ ```
23
+
24
+ - `Selenium::WebDriver::Error::UnknownError`
25
+
26
+ ```
27
+ Selenium::WebDriver::Error::UnknownError:
28
+ unknown error: session deleted because of page crash
29
+ from tab crashed
30
+ (Session info: headless chrome=113.0.5672.126)
31
+ ```
32
+
33
+ To resolve these issues:
34
+
35
+ 1. Do not use `/dev/shm` shared memory. Set `CHROME_DISABLE_DEV_SHM` environment variable to `true`.
36
+ ```shell
37
+ $ export CHROME_DISABLE_DEV_SHM=true
38
+ # Disable Chrome shared memory
39
+ ```
40
+ 2. Enable **Use Rosetta for x86/amd64 emulation on Apple Silicon** option in Docker (Using Docker Desktop ~v4.22.1).
41
+ 1. Open **Settings** in Docker Desktop
42
+ 1. Go to **Features in development**
43
+ 1. Enable **Use Rosetta for x86/amd64 emulation on Apple Silicon** setting
44
+ 1. Select **Apply & restart**
@@ -129,6 +129,7 @@ module Gitlab
129
129
  end
130
130
 
131
131
  def prepare_gitlab_omnibus_config
132
+ @omnibus_configuration.expand_config_template(self)
132
133
  set_formless_login_token
133
134
  set_license_mode
134
135
  set_qa_user_agent
@@ -20,15 +20,12 @@ module Gitlab
20
20
  @env = {}
21
21
  @volumes = {}
22
22
  @additional_hosts = []
23
- @default_volumes = { '/var/run/docker.sock' => '/var/run/docker.sock' }
23
+ @volumes = { '/var/run/docker.sock' => '/var/run/docker.sock' }
24
24
 
25
- if Runtime::Env.qa_rspec_report_path.present? # rubocop:disable Style/IfUnlessModifier
26
- @default_volumes[Runtime::Env.qa_rspec_report_path] = File.join(Docker::Volumes::QA_CONTAINER_WORKDIR, 'rspec')
27
- end
28
-
29
- return if Runtime::Env.qa_knapsack_report_path.blank?
30
-
31
- @default_volumes[Runtime::Env.qa_knapsack_report_path] = File.join(Docker::Volumes::QA_CONTAINER_WORKDIR, 'knapsack')
25
+ include_optional_volumes(
26
+ Runtime::Env.qa_rspec_report_path => 'rspec',
27
+ Runtime::Env.qa_knapsack_report_path => 'knapsack'
28
+ )
32
29
  end
33
30
 
34
31
  def perform
@@ -70,7 +67,11 @@ module Gitlab
70
67
  feature_flag_sets << [] unless feature_flag_sets.any?
71
68
 
72
69
  feature_flag_sets.each do |feature_flag_set|
73
- @docker.run(image: qa_image, args: [suite, *args_with_flags(args, feature_flag_set)]) do |command|
70
+ @docker.run(
71
+ image: qa_image,
72
+ args: [suite, *args_with_flags(args, feature_flag_set)],
73
+ mask_secrets: Runtime::Env.variables_to_mask
74
+ ) do |command|
74
75
  command << "-t --rm --net=#{network || 'bridge'}"
75
76
 
76
77
  unless hostname.nil?
@@ -92,7 +93,7 @@ module Gitlab
92
93
  File.join(Docker::Volumes::QA_CONTAINER_WORKDIR, 'tmp')
93
94
  )
94
95
 
95
- volumes.to_h.merge(default_volumes).each { |to, from| command.volume(to, from) }
96
+ volumes.to_h.each { |to, from| command.volume(to, from) }
96
97
 
97
98
  command.name(name)
98
99
  end
@@ -101,8 +102,6 @@ module Gitlab
101
102
 
102
103
  private
103
104
 
104
- attr_reader :default_volumes
105
-
106
105
  def docker_pull_qa_image_if_needed
107
106
  @docker.login(**release.login_params) if release.login_params
108
107
 
@@ -129,6 +128,16 @@ module Gitlab
129
128
  "#{release.qa_image}:#{release.qa_tag}"
130
129
  end
131
130
  end
131
+
132
+ # Adds volumes to the volumes hash if the relevant host paths exist
133
+ #
134
+ # @param [Array] *args volume host_path => container_path pairs
135
+ # @return [void]
136
+ def include_optional_volumes(args)
137
+ args.each do |host_path, container_path|
138
+ host_path.present? && volumes[host_path] = File.join(Docker::Volumes::QA_CONTAINER_WORKDIR, container_path)
139
+ end
140
+ end
132
141
  end
133
142
  end
134
143
  end
@@ -13,7 +13,7 @@ module Gitlab
13
13
  # @param [Boolean] stream_output stream command output to stdout directly instead of logger
14
14
  def initialize(cmd = nil, mask_secrets: nil, stream_output: false)
15
15
  @args = Array(cmd)
16
- @mask_secrets = Array(mask_secrets)
16
+ @mask_secrets = mask_secrets
17
17
  @stream_output = stream_output
18
18
  end
19
19
 
@@ -31,8 +31,8 @@ module Gitlab
31
31
  end
32
32
  end
33
33
 
34
- def run(image:, tag: nil, args: [])
35
- Docker::Command.new('run', stream_output: stream_output).tap do |command|
34
+ def run(image:, tag: nil, args: [], mask_secrets: nil)
35
+ Docker::Command.new('run', stream_output: stream_output, mask_secrets: mask_secrets).tap do |command|
36
36
  yield command if block_given?
37
37
 
38
38
  command << full_image_name(image, tag)
@@ -161,26 +161,17 @@ module Gitlab
161
161
  'WORKSPACES_OAUTH_APP_SECRET' => :workspaces_oauth_app_secret,
162
162
  'WORKSPACES_OAUTH_SIGNING_KEY' => :workspaces_oauth_signing_key,
163
163
  'WORKSPACES_PROXY_DOMAIN' => :workspaces_proxy_domain,
164
- 'WORKSPACES_DOMAIN_CERT' => :workspaces_domain_cert,
165
- 'WORKSPACES_DOMAIN_KEY' => :workspaces_domain_key,
166
- 'WORKSPACES_WILDCARD_CERT' => :workspaces_wildcard_cert,
167
- 'WORKSPACES_WILDCARD_KEY' => :workspaces_wildcard_key
164
+ 'WORKSPACES_DOMAIN_CERT' => { name: :workspaces_domain_cert, type: :file },
165
+ 'WORKSPACES_DOMAIN_KEY' => { name: :workspaces_domain_key, type: :file },
166
+ 'WORKSPACES_WILDCARD_CERT' => { name: :workspaces_wildcard_cert, type: :file },
167
+ 'WORKSPACES_WILDCARD_KEY' => { name: :workspaces_wildcard_key, type: :file }
168
168
  }.freeze
169
169
 
170
- ENV_VARIABLES.each do |env_name, method_name|
171
- attr_writer(method_name)
172
-
173
- define_method(method_name) do
174
- env_var_value_if_defined(env_name) || (instance_variable_get("@#{method_name}") if instance_variable_defined?("@#{method_name}"))
175
- end
176
- end
177
-
178
170
  def variables
179
- defined_variables = ENV_VARIABLES.each_with_object({}) do |(name, attribute), vars|
180
- # Variables that are overridden in the environment take precedence
181
- # over the defaults specified by the QA runtime.
182
- value = env_var_name_if_defined(name) || send(attribute) # rubocop:disable GitlabSecurity/PublicSend
183
- vars[name] = value if value
171
+ defined_variables = ENV_VARIABLES.each_with_object({}) do |(env_var_name, attributes), vars|
172
+ method_name, value = method_name_and_value(env_var_name, attributes, name_as_value: true)
173
+ value ||= send(method_name) # rubocop:disable GitlabSecurity/PublicSend
174
+ vars[env_var_name] = value if value
184
175
  end
185
176
  qa_variables = ENV.each_with_object({}) do |(name, _value), vars|
186
177
  next unless name.start_with?('QA_')
@@ -192,6 +183,14 @@ module Gitlab
192
183
  qa_variables.merge(defined_variables)
193
184
  end
194
185
 
186
+ # Variables that should be masked
187
+ #
188
+ # @return [Array] the values of the variables that should be masked
189
+ def variables_to_mask
190
+ # Consider all file variables to need masking by default because they're likely to be secrets
191
+ variables.select { |k, _| ENV_VARIABLES[k].is_a?(Hash) && ENV_VARIABLES[k][:type] == :file }.values
192
+ end
193
+
195
194
  def debug?
196
195
  enabled?(ENV.fetch('QA_DEBUG', nil), default: true)
197
196
  end
@@ -306,6 +305,26 @@ module Gitlab
306
305
  end
307
306
  end
308
307
 
308
+ def require_facebook_environment!
309
+ %w[QA_FACEBOOK_USERNAME QA_FACEBOOK_PASSWORD QA_FACEBOOK_OAUTH_APP_SECRET
310
+ QA_FACEBOOK_OAUTH_APP_ID].each do |env_key|
311
+ unless ENV.key?(env_key)
312
+ raise ArgumentError,
313
+ "Environment variable #{env_key} must be set to run OAuth specs"
314
+ end
315
+ end
316
+ end
317
+
318
+ def require_github_oauth_environment!
319
+ %w[QA_GITHUB_OAUTH_APP_ID QA_GITHUB_OAUTH_APP_SECRET QA_GITHUB_USERNAME
320
+ QA_GITHUB_PASSWORD QA_1P_EMAIL QA_1P_PASSWORD QA_1P_SECRET QA_1P_GITHUB_UUID].each do |env_key|
321
+ unless ENV.key?(env_key)
322
+ raise ArgumentError,
323
+ "Environment variable #{env_key} must be set to run OAuth specs"
324
+ end
325
+ end
326
+ end
327
+
309
328
  def require_initial_password!
310
329
  return unless env_var_value_if_defined('GITLAB_INITIAL_ROOT_PASSWORD').to_s.strip.empty?
311
330
 
@@ -459,6 +478,49 @@ module Gitlab
459
478
  # Pass through the variables if they are defined and not empty in the environment
460
479
  return "$#{variable}" if env_var_value_valid?(variable)
461
480
  end
481
+
482
+ def method_name_and_value(env_var_name, attributes, name_as_value: false)
483
+ method_name, type = method_name_and_type(attributes)
484
+
485
+ # Variables that are overridden in the environment take precedence
486
+ # over the defaults specified by the QA runtime.
487
+ value = if type == :file
488
+ # If it's a file variable we pass the content of the file to avoid trying to access an invalid
489
+ # path from inside the specs Docker container
490
+ path = env_var_value_if_defined(env_var_name)
491
+ if path.present?
492
+ full_path = File.expand_path(path)
493
+ File.read(full_path).strip if full_path && File.exist?(full_path)
494
+ end
495
+ elsif name_as_value
496
+ env_var_name_if_defined(env_var_name)
497
+ else
498
+ env_var_value_if_defined(env_var_name)
499
+ end
500
+
501
+ [method_name, value]
502
+ end
503
+
504
+ def method_name_and_type(attributes)
505
+ if attributes.is_a?(Hash) && attributes[:type] == :file
506
+ [attributes[:name], :file]
507
+ else
508
+ [attributes, :env_var]
509
+ end
510
+ end
511
+
512
+ # Define methods for each variable last so we can use the methods defined just above
513
+ ENV_VARIABLES.each do |env_var_name, attributes|
514
+ method_name, _ = method_name_and_type(attributes)
515
+ next if method_defined?(method_name) # Don't replace methods that were explicitly defined above
516
+
517
+ writer_names = attr_writer(method_name)
518
+ define_method(method_name) do
519
+ _, value = method_name_and_value(env_var_name, attributes)
520
+ value || (instance_variable_get("@#{method_name}") if instance_variable_defined?("@#{method_name}"))
521
+ end
522
+ public(*writer_names, method_name)
523
+ end
462
524
  end
463
525
  end
464
526
  end
@@ -2,6 +2,8 @@
2
2
 
3
3
  require 'active_support'
4
4
  require 'active_support/core_ext/object/blank'
5
+ require 'active_support/core_ext/string/inflections'
6
+ require 'erb'
5
7
 
6
8
  module Gitlab
7
9
  module QA
@@ -25,6 +27,21 @@ module Gitlab
25
27
  sanitize!.join("\n")
26
28
  end
27
29
 
30
+ ERB_PATTERN = /<%=?\s?(\S+)\s?%>/
31
+
32
+ # Execute the ERB code to produce completed template
33
+ # @example
34
+ # external_url '<%= gitlab.address %>' #=> external_url 'http://gitlab-ee-09d62235.test'
35
+ #
36
+ # @param [GitLab::QA::Component::Gitlab] gitlab
37
+ #
38
+ # @return [Array]
39
+ def expand_config_template(gitlab)
40
+ @config.map! do |item|
41
+ item.match(ERB_PATTERN) ? ERB.new(item).result(binding) : item
42
+ end
43
+ end
44
+
28
45
  def configuration
29
46
  raise NotImplementedError
30
47
  end
@@ -45,6 +62,7 @@ module Gitlab
45
62
  def sanitize!
46
63
  sanitized = @config.map do |config|
47
64
  next config if config.start_with?('#') || config.match(/\w+\(/) # allow for comments and method invocations
65
+ next config if config.match(ERB_PATTERN)
48
66
 
49
67
  # sometimes "=" is part of a Hash. Only split based on the first "="
50
68
  k, v = config.split("=", 2)
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Gitlab
4
+ module QA
5
+ module Runtime
6
+ module OmnibusConfigurations
7
+ class FacebookOauth < Default
8
+ def configuration
9
+ Runtime::Env.require_github_oauth_environment!
10
+
11
+ <<~OMNIBUS
12
+ gitlab_rails['omniauth_enabled'] = true;
13
+ gitlab_rails['omniauth_allow_single_sign_on'] = [facebook'];
14
+ gitlab_rails['omniauth_block_auto_created_users'] = false;
15
+ gitlab_rails['omniauth_providers'] = [
16
+ {
17
+ name: 'facebook',
18
+ app_id: '$QA_FACEBOOK_OAUTH_APP_ID',
19
+ app_secret: '$QA_FACEBOOK_OAUTH_APP_SECRET',
20
+ verify_ssl: false
21
+ }
22
+ ];
23
+ letsencrypt['enable'] = false;
24
+ external_url '<%= gitlab.address %>';
25
+ OMNIBUS
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Gitlab
4
+ module QA
5
+ module Runtime
6
+ module OmnibusConfigurations
7
+ class GithubOauth < Default
8
+ def configuration
9
+ Runtime::Env.require_github_oauth_environment!
10
+
11
+ <<~OMNIBUS
12
+ gitlab_rails['omniauth_enabled'] = true
13
+ gitlab_rails['omniauth_allow_single_sign_on'] = ['github']
14
+ gitlab_rails['omniauth_block_auto_created_users'] = false
15
+ gitlab_rails['omniauth_providers'] = [
16
+ {
17
+ name: 'github',
18
+ app_id: '$QA_GITHUB_OAUTH_APP_ID',
19
+ app_secret: '$QA_GITHUB_OAUTH_APP_SECRET',
20
+ url: 'https://github.com/',
21
+ verify_ssl: false,
22
+ args: { scope: 'user:email' }
23
+ }
24
+ ]
25
+ letsencrypt['enable'] = false
26
+ external_url '<%= gitlab.address %>'
27
+ OMNIBUS
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Gitlab
4
4
  module QA
5
- VERSION = '12.4.1'
5
+ VERSION = '12.5.0'
6
6
  end
7
7
  end
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: 12.4.1
4
+ version: 12.5.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: 2023-09-08 00:00:00.000000000 Z
11
+ date: 2023-10-25 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: climate_control
@@ -370,6 +370,7 @@ files:
370
370
  - docs/release_process.md
371
371
  - docs/run_qa_against_gdk.md
372
372
  - docs/running_against_remote_grid.md
373
+ - docs/specifics_for_macos_m1_m2.md
373
374
  - docs/trainings.md
374
375
  - docs/waits.md
375
376
  - docs/what_tests_can_be_run.md
@@ -418,6 +419,8 @@ files:
418
419
  - lib/gitlab/qa/runtime/omnibus_configurations/decomposition_multiple_db.rb
419
420
  - lib/gitlab/qa/runtime/omnibus_configurations/decomposition_single_db.rb
420
421
  - lib/gitlab/qa/runtime/omnibus_configurations/default.rb
422
+ - lib/gitlab/qa/runtime/omnibus_configurations/facebook_oauth.rb
423
+ - lib/gitlab/qa/runtime/omnibus_configurations/github_oauth.rb
421
424
  - lib/gitlab/qa/runtime/omnibus_configurations/object_storage.rb
422
425
  - lib/gitlab/qa/runtime/omnibus_configurations/object_storage_aws.rb
423
426
  - lib/gitlab/qa/runtime/omnibus_configurations/object_storage_gcs.rb