260 lines
8.4 KiB
Ruby
Raw Normal View History

# typed: true
# frozen_string_literal: true
2019-04-17 18:25:08 +09:00
require "cli/parser"
require "fileutils"
module Homebrew
2020-10-20 12:03:48 +02:00
extend T::Sig
2016-09-26 01:44:51 +02:00
module_function
2020-10-20 12:03:48 +02:00
sig { returns(CLI::Parser) }
def tests_args
Homebrew::CLI::Parser.new do
description <<~EOS
Run Homebrew's unit and integration tests.
2018-09-28 21:39:52 +05:30
EOS
switch "--coverage",
2019-04-30 08:44:35 +01:00
description: "Generate code coverage reports."
2018-09-28 21:39:52 +05:30
switch "--generic",
2019-04-30 08:44:35 +01:00
description: "Run only OS-agnostic tests."
2018-09-28 21:39:52 +05:30
switch "--online",
2022-06-28 10:09:59 +01:00
description: "Include tests that use the GitHub API and tests that use any of the taps for " \
2019-04-30 08:44:35 +01:00
"official external commands."
2020-05-18 16:28:43 +05:30
switch "--byebug",
description: "Enable debugging using byebug."
switch "--changed",
description: "Only runs tests on files that were changed from the master branch."
2018-09-28 21:39:52 +05:30
flag "--only=",
2022-06-28 10:09:59 +01:00
description: "Run only <test_script>`_spec.rb`. Appending `:`<line_number> will start at a " \
2019-04-30 08:44:35 +01:00
"specific line."
2018-09-28 21:39:52 +05:30
flag "--seed=",
description: "Randomise tests with the specified <value> instead of a random seed."
2020-07-30 18:40:10 +02:00
conflicts "--changed", "--only"
2021-01-10 14:26:40 -05:00
named_args :none
end
end
2018-09-08 22:21:04 +05:30
def use_buildpulse?
return @use_buildpulse if defined?(@use_buildpulse)
@use_buildpulse = ENV["HOMEBREW_BUILDPULSE_ACCESS_KEY_ID"].present? &&
ENV["HOMEBREW_BUILDPULSE_SECRET_ACCESS_KEY"].present? &&
ENV["HOMEBREW_BUILDPULSE_ACCOUNT_ID"].present? &&
ENV["HOMEBREW_BUILDPULSE_REPOSITORY_ID"].present?
end
def run_buildpulse
require "formula"
with_env(HOMEBREW_NO_AUTO_UPDATE: "1", HOMEBREW_NO_BOOTSNAP: "1") do
ensure_formula_installed!("buildpulse-test-reporter",
reason: "reporting test flakiness")
end
2022-05-30 04:37:09 +01:00
ENV["BUILDPULSE_ACCESS_KEY_ID"] = ENV.fetch("HOMEBREW_BUILDPULSE_ACCESS_KEY_ID")
ENV["BUILDPULSE_SECRET_ACCESS_KEY"] = ENV.fetch("HOMEBREW_BUILDPULSE_SECRET_ACCESS_KEY")
ohai "Sending test results to BuildPulse"
# TODO: make this use `system_command!` when https://github.com/buildpulse/buildpulse-action/issues/4 is fixed
system_command Formula["buildpulse-test-reporter"].opt_bin/"buildpulse-test-reporter",
args: [
"submit", "#{HOMEBREW_LIBRARY_PATH}/test/junit",
"--account-id", ENV.fetch("HOMEBREW_BUILDPULSE_ACCOUNT_ID"),
"--repository-id", ENV.fetch("HOMEBREW_BUILDPULSE_REPOSITORY_ID")
]
end
def changed_test_files
changed_files = Utils.popen_read("git", "diff", "--name-only", "master")
raise UsageError, "No files have been changed from the master branch!" if changed_files.blank?
filestub_regex = %r{Library/Homebrew/([\w/-]+).rb}
changed_files.scan(filestub_regex).map(&:last).map do |filestub|
if filestub.start_with?("test/")
# Only run tests on *_spec.rb files in test/ folder
filestub.end_with?("_spec") ? Pathname("#{filestub}.rb") : nil
else
# For all other changed .rb files guess the associated test file name
Pathname("test/#{filestub}_spec.rb")
end
end.compact.select(&:exist?)
end
def tests
2020-07-30 18:40:10 +02:00
args = tests_args.parse
2018-03-25 13:18:23 +05:30
Homebrew.install_bundler_gems!
2020-05-18 16:28:43 +05:30
require "byebug" if args.byebug?
2016-10-21 08:57:39 +02:00
HOMEBREW_LIBRARY_PATH.cd do
2022-11-09 14:45:43 +00:00
setup_environment!(args)
2017-02-28 14:33:39 +01:00
parallel = true
2018-03-25 13:18:23 +05:30
files = if args.only
test_name, line = args.only.split(":", 2)
2017-02-28 14:33:39 +01:00
if line.nil?
Dir.glob("test/{#{test_name},#{test_name}/**/*}_spec.rb")
else
parallel = false
["test/#{test_name}_spec.rb:#{line}"]
end
elsif args.changed?
changed_test_files
2017-02-28 14:33:39 +01:00
else
Dir.glob("test/**/*_spec.rb")
end
if files.blank?
2023-02-10 23:15:40 -05:00
raise UsageError, "The `--only` argument requires a valid file or folder name!" if args.only
if args.changed?
opoo "No tests are directly associated with the changed files!"
return
end
end
parallel_rspec_log_name = "parallel_runtime_rspec"
parallel_rspec_log_name = "#{parallel_rspec_log_name}.generic" if args.generic?
parallel_rspec_log_name = "#{parallel_rspec_log_name}.online" if args.online?
parallel_rspec_log_name = "#{parallel_rspec_log_name}.log"
2021-04-03 19:03:35 +09:00
parallel_rspec_log_path = if ENV["CI"]
"tests/#{parallel_rspec_log_name}"
2021-04-01 23:15:51 +09:00
else
"#{HOMEBREW_CACHE}/#{parallel_rspec_log_name}"
2021-04-01 23:15:51 +09:00
end
Enhance test suite to emit JUnit XML test reports In preparation for detecting flaky tests with BuildPulse, this commit sets up the rspec_junit_formatter gem to output JUnit XML reports of the test suite, which is the format used by BuildPulse and various other tooling that interprets test results. Because the test suite uses the parallel_tests gem, this commit incorporates some related changes to make all the parallel_tests gem and the rspec_junit_formatter gem to cooperate with each other. rspec_junit_formatter writes everything to a single XML file. That works fine when there's only one process writing to the file. By default, whatever process finishes last will write to the file and clobber the output of all the other processes that wrote to the file. 🙈 To prevent this issue, the parallel_tests wiki recommends adding a `.rspec_parallel` file to specify its RSpec options (https://github.com/grosser/parallel_tests/wiki#with-rspec_junit_formatter----by-jgarber), then the project can specify different files for each process to write to like so: --format RspecJunitFormatter --out tmp/rspec<%= ENV['TEST_ENV_NUMBER'] %>.xml However, prior to this commit, the Homebrew/brew test suite specified its RSpec options via the command line. Unfortunately though, there's no way (AFAICT) to set the equivalent of these options via the command line: --format RspecJunitFormatter --out tmp/rspec<%= ENV['TEST_ENV_NUMBER'] %>.xml So, we need to use a `.rspec_parallel` file to specify these options ☝️. However, it appears that RSpec allows you to specify formatters _either_ in an options file (like `.rspec_parallel`) _or_ via command-line args. But if you specify any formatters via command-line args, then all formatters in the options file are ignored. (I suspect that's somehow related to this bit of code in rspec-core: https://github.com/rspec/rspec-core/blob/v3.10.0/lib/rspec/core/configuration_options.rb#L64.) With that in mind, in order to have the RspecJunitFormatter configured in `.rspec_parallel`, we need to move the other formatters into `.rpsec_parallel` as well, instead of passing them as command-line args. Therefore, this commit moves all the formatters into a `.rspec_parallel` file.
2021-06-21 12:58:09 -04:00
ENV["PARALLEL_RSPEC_LOG_PATH"] = parallel_rspec_log_path
2021-04-01 23:15:51 +09:00
parallel_args = if ENV["CI"]
2021-04-01 23:15:51 +09:00
%W[
--combine-stderr
--serialize-stdout
2021-04-08 20:23:50 +09:00
--runtime-log #{parallel_rspec_log_path}
]
else
%w[
--nice
]
2017-02-28 14:33:39 +01:00
end
2017-02-10 21:21:57 +01:00
# Generate seed ourselves and output later to avoid multiple different
# seeds being output when running parallel tests.
2018-06-06 23:34:19 -04:00
seed = args.seed || rand(0xFFFF).to_i
bundle_args = ["-I", HOMEBREW_LIBRARY_PATH/"test"]
bundle_args += %W[
--seed #{seed}
--color
--require spec_helper
2017-02-10 21:21:57 +01:00
]
# TODO: Refactor and move to extend/os
# rubocop:disable Homebrew/MoveToExtendOS
2017-02-28 14:33:39 +01:00
unless OS.mac?
2018-08-09 15:00:19 +02:00
bundle_args << "--tag" << "~needs_macos" << "--tag" << "~cask"
files = files.grep_v(%r{^test/(os/mac|cask)(/.*|_spec\.rb)$})
end
2017-02-28 14:33:39 +01:00
2017-03-05 20:45:48 -08:00
unless OS.linux?
bundle_args << "--tag" << "~needs_linux"
files = files.grep_v(%r{^test/os/linux(/.*|_spec\.rb)$})
2017-03-05 20:45:48 -08:00
end
# rubocop:enable Homebrew/MoveToExtendOS
2017-03-05 20:45:48 -08:00
bundle_args << "--tag" << "~needs_network" unless args.online?
unless ENV["CI"]
bundle_args << "--tag" << "~needs_ci" \
<< "--tag" << "~needs_svn"
end
puts "Randomized with seed #{seed}"
# Submit test flakiness information using BuildPulse
# BUILDPULSE used in spec_helper.rb
if use_buildpulse?
ENV["BUILDPULSE"] = "1"
ohai "Running tests with BuildPulse-friendly settings"
end
if parallel
system "bundle", "exec", "parallel_rspec", *parallel_args, "--", *bundle_args, "--", *files
else
system "bundle", "exec", "rspec", *bundle_args, "--", *files
2017-02-28 14:33:39 +01:00
end
success = $CHILD_STATUS.success?
2017-02-28 14:33:39 +01:00
run_buildpulse if use_buildpulse?
return if success
2018-09-17 02:45:00 +02:00
2017-02-28 14:33:39 +01:00
Homebrew.failed = true
end
end
2022-11-09 14:45:43 +00:00
def setup_environment!(args)
# Cleanup any unwanted user configuration.
allowed_test_env = %w[
HOMEBREW_GITHUB_API_TOKEN
HOMEBREW_CACHE
HOMEBREW_LOGS
HOMEBREW_TEMP
HOMEBREW_USE_RUBY_FROM_PATH
]
Homebrew::EnvConfig::ENVS.keys.map(&:to_s).each do |env|
next if allowed_test_env.include?(env)
ENV.delete(env)
end
# Codespaces HOMEBREW_PREFIX and /tmp are mounted 755 which makes Ruby warn constantly.
if (ENV["HOMEBREW_CODESPACES"] == "true") && (HOMEBREW_TEMP.to_s == "/tmp")
# Need to keep this fairly short to avoid socket paths being too long in tests.
homebrew_prefix_tmp = "/home/linuxbrew/tmp"
ENV["HOMEBREW_TEMP"] = homebrew_prefix_tmp
FileUtils.mkdir_p homebrew_prefix_tmp
system "chmod", "-R", "g-w,o-w", HOMEBREW_PREFIX, homebrew_prefix_tmp
end
ENV["HOMEBREW_TESTS"] = "1"
ENV["HOMEBREW_NO_AUTO_UPDATE"] = "1"
ENV["HOMEBREW_NO_ANALYTICS_THIS_RUN"] = "1"
ENV["HOMEBREW_TEST_GENERIC_OS"] = "1" if args.generic?
ENV["HOMEBREW_TEST_ONLINE"] = "1" if args.online?
ENV["HOMEBREW_SORBET_RUNTIME"] = "1"
# TODO: remove this and fix tests when possible.
ENV["HOMEBREW_NO_INSTALL_FROM_API"] = "1"
2022-11-09 14:45:43 +00:00
ENV["USER"] ||= system_command!("id", args: ["-nu"]).stdout.chomp
# Avoid local configuration messing with tests, e.g. git being configured
# to use GPG to sign by default
ENV["HOME"] = "#{HOMEBREW_LIBRARY_PATH}/test"
# Print verbose output when requesting debug or verbose output.
ENV["HOMEBREW_VERBOSE_TESTS"] = "1" if args.debug? || args.verbose?
if args.coverage?
ENV["HOMEBREW_TESTS_COVERAGE"] = "1"
FileUtils.rm_f "test/coverage/.resultset.json"
end
# Override author/committer as global settings might be invalid and thus
# will cause silent failure during the setup of dummy Git repositories.
%w[AUTHOR COMMITTER].each do |role|
ENV["GIT_#{role}_NAME"] = "brew tests"
ENV["GIT_#{role}_EMAIL"] = "brew-tests@localhost"
ENV["GIT_#{role}_DATE"] = "Sun Jan 22 19:59:13 2017 +0000"
end
end
end