class Gitlab::QA::Component::Specs


the ‘qa/` directory located in GitLab CE / EE repositories.
This class represents GitLab QA specs image that is implemented in
#

def args_with_flags(args, feature_flag_set)

def args_with_flags(args, feature_flag_set)
  return args if feature_flag_set.empty?
  Runtime::Logger.info("Running with feature flag: #{feature_flag_set.join(' ')}")
  args_with_f = args.dup
  args_with_f.insert(1, *feature_flag_set)
end

def docker_pull_qa_image_if_needed

def docker_pull_qa_image_if_needed
  @docker.login(**release.login_params) if release.login_params
  @docker.pull(image: qa_image) unless Runtime::Env.skip_pull?
end

def include_optional_volumes(args)

Returns:
  • (void) -

Parameters:
  • *args (Array) -- volume host_path => container_path pairs
def include_optional_volumes(args)
  args.each do |host_path, container_path|
    host_path.present? && volumes[host_path] = File.join(Docker::Volumes::QA_CONTAINER_WORKDIR, container_path)
  end
end

def initialize

def initialize
  @docker = Docker::Engine.new(stream_output: true) # stream test output directly instead of through logger
  @env = {}
  @volumes = {}
  @additional_hosts = []
  @volumes = { '/var/run/docker.sock' => '/var/run/docker.sock' }
  include_optional_volumes(
    Runtime::Env.qa_rspec_report_path => 'rspec',
    Runtime::Env.qa_knapsack_report_path => 'knapsack'
  )
end

def internal_perform

def internal_perform
  return Runtime::Logger.info("Skipping tests.") if skip_tests?
  raise ArgumentError unless [suite, release].all?
  docker_pull_qa_image_if_needed
  Runtime::Logger.info("Running test suite `#{suite}` for #{release.project_name}")
  name = "#{release.project_name}-qa-#{SecureRandom.hex(4)}"
  feature_flag_sets = []
  # When `args` includes:
  #   `[..., "--disable-feature", "a", "--enable-feature", "b", "--set-feature-flags", "c=enable", ...]`
  # `feature_flag_sets` will be set to:
  #   `[["--disable-feature", "a"], ["--enable-feature", "b"], ["--set-feature-flags", "c=enable"]]`
  # This will result in tests running three times, once with each feature flag option.
  while (index = args&.index { |x| x =~ /--.*-feature/ })
    feature_flag_sets << args.slice!(index, 2)
  end
  # When `args` do not have any feature flag options, we add [] so that test is run exactly once.
  feature_flag_sets << [] unless feature_flag_sets.any?
  feature_flag_sets.each do |feature_flag_set|
    @docker.run(
      image: qa_image,
      args: [suite, *args_with_flags(args, feature_flag_set)],
      mask_secrets: Runtime::Env.variables_to_mask
    ) do |command|
      command << "-t --rm --net=#{network || 'bridge'}"
      unless hostname.nil?
        command << "--hostname #{hostname}"
        command.env('QA_HOSTNAME', hostname)
      end
      if Runtime::Env.docker_add_hosts.present? || additional_hosts.present?
        hosts = Runtime::Env.docker_add_hosts.concat(additional_hosts).map { |host| "--add-host=#{host} " }.join
        command << hosts # override /etc/hosts in docker container when test runs
      end
      Runtime::Env.variables.merge(env).each do |key, value|
        command.env(key, value)
      end
      command.volume(
        File.join(Runtime::Env.host_artifacts_dir, name),
        File.join(Docker::Volumes::QA_CONTAINER_WORKDIR, 'tmp')
      )
      volumes.to_h.each { |to, from| command.volume(to, from) }
      command.name(name)
    end
  end
end

def perform

def perform
  if Runtime::Env.use_selenoid?
    Component::Selenoid.perform do |selenoid|
      selenoid.network = network
      selenoid.instance do
        internal_perform
      end
    end
  else
    internal_perform
  end
end

def qa_image

def qa_image
  if Runtime::Scenario.attributes.include?(:qa_image)
    Runtime::Scenario.qa_image
  else
    "#{release.qa_image}:#{release.qa_tag}"
  end
end

def skip_tests?

def skip_tests?
  Runtime::Scenario.attributes.include?(:run_tests) && !Runtime::Scenario.run_tests
end