2023-03-09 20:32:46 -08:00
|
|
|
# typed: true
|
2019-04-19 15:38:03 +09:00
|
|
|
# frozen_string_literal: true
|
|
|
|
|
2019-04-17 18:25:08 +09:00
|
|
|
require "cli/parser"
|
2016-01-18 15:33:59 +01:00
|
|
|
require "fileutils"
|
2024-01-31 14:54:56 -08:00
|
|
|
require "system_command"
|
2016-01-18 15:33:59 +01:00
|
|
|
|
2014-06-18 22:41:47 -05:00
|
|
|
module Homebrew
|
2024-01-31 14:54:56 -08:00
|
|
|
extend SystemCommand::Mixin
|
2016-09-26 01:44:51 +02:00
|
|
|
|
2020-10-20 12:03:48 +02:00
|
|
|
sig { returns(CLI::Parser) }
|
2024-01-31 14:54:56 -08:00
|
|
|
def self.tests_args
|
2018-07-30 18:25:38 +05:30
|
|
|
Homebrew::CLI::Parser.new do
|
2021-01-15 15:04:02 -05:00
|
|
|
description <<~EOS
|
2018-10-08 22:49:03 -04:00
|
|
|
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."
|
2022-04-14 20:33:39 -07:00
|
|
|
switch "--changed",
|
|
|
|
description: "Only runs tests on files that were changed from the master branch."
|
2023-08-10 15:47:51 +01:00
|
|
|
switch "--fail-fast",
|
|
|
|
description: "Exit early on the first failing test."
|
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."
|
2024-01-06 12:51:15 -08:00
|
|
|
flag "--profile=",
|
|
|
|
description: "Run the test suite serially to find the <n> slowest tests."
|
2018-09-28 21:39:52 +05:30
|
|
|
flag "--seed=",
|
2019-08-20 00:04:14 -04:00
|
|
|
description: "Randomise tests with the specified <value> instead of a random seed."
|
2020-07-30 18:40:10 +02:00
|
|
|
|
2022-04-14 20:33:39 -07:00
|
|
|
conflicts "--changed", "--only"
|
|
|
|
|
2021-01-10 14:26:40 -05:00
|
|
|
named_args :none
|
2018-03-25 17:48:22 +05:30
|
|
|
end
|
2018-07-30 18:25:38 +05:30
|
|
|
end
|
2018-09-08 22:21:04 +05:30
|
|
|
|
2024-01-31 14:54:56 -08:00
|
|
|
def self.use_buildpulse?
|
2021-06-29 12:43:47 +01:00
|
|
|
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
|
|
|
|
|
2024-01-31 14:54:56 -08:00
|
|
|
def self.run_buildpulse
|
2021-06-29 12:43:47 +01:00
|
|
|
require "formula"
|
|
|
|
|
2021-11-23 22:48:39 +08:00
|
|
|
with_env(HOMEBREW_NO_AUTO_UPDATE: "1", HOMEBREW_NO_BOOTSNAP: "1") do
|
|
|
|
ensure_formula_installed!("buildpulse-test-reporter",
|
2021-11-23 23:59:09 +08:00
|
|
|
reason: "reporting test flakiness")
|
2021-06-29 12:43:47 +01:00
|
|
|
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")
|
2021-06-29 12:43:47 +01:00
|
|
|
|
2021-06-30 08:41:19 +01:00
|
|
|
ohai "Sending test results to BuildPulse"
|
|
|
|
|
2023-03-31 03:41:52 -04:00
|
|
|
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")
|
|
|
|
]
|
2021-06-29 12:43:47 +01:00
|
|
|
end
|
|
|
|
|
2024-01-31 14:54:56 -08:00
|
|
|
def self.changed_test_files
|
2022-05-03 00:16:33 -07:00
|
|
|
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}
|
2024-02-22 23:29:55 +00:00
|
|
|
changed_files.scan(filestub_regex).map(&:last).filter_map do |filestub|
|
2022-05-03 00:16:33 -07:00
|
|
|
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
|
2024-02-22 23:29:55 +00:00
|
|
|
end.select(&:exist?)
|
2022-05-03 00:16:33 -07:00
|
|
|
end
|
|
|
|
|
2024-01-31 14:54:56 -08:00
|
|
|
def self.tests
|
2020-07-30 18:40:10 +02:00
|
|
|
args = tests_args.parse
|
2018-03-25 13:18:23 +05:30
|
|
|
|
2023-09-04 21:52:51 +01:00
|
|
|
# Given we might be testing various commands, we probably want everything (except sorbet-static)
|
|
|
|
Homebrew.install_bundler_gems!(groups: Homebrew.valid_gem_groups - ["sorbet"])
|
2019-02-26 22:13:00 +00:00
|
|
|
|
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)
|
2016-01-04 14:54:09 +01:00
|
|
|
|
2017-02-28 14:33:39 +01:00
|
|
|
parallel = true
|
2016-09-20 14:57:08 +01:00
|
|
|
|
2018-03-25 13:18:23 +05:30
|
|
|
files = if args.only
|
|
|
|
test_name, line = args.only.split(":", 2)
|
2016-09-20 14:57:08 +01:00
|
|
|
|
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
|
2022-04-14 20:33:39 -07:00
|
|
|
elsif args.changed?
|
2022-05-03 00:16:33 -07:00
|
|
|
changed_test_files
|
2017-02-28 14:33:39 +01:00
|
|
|
else
|
2019-02-21 15:41:42 +00:00
|
|
|
Dir.glob("test/**/*_spec.rb")
|
2016-01-20 07:06:09 +01:00
|
|
|
end
|
2016-09-20 14:57:08 +01:00
|
|
|
|
2022-04-14 20:33:39 -07:00
|
|
|
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
|
2022-04-14 20:33:39 -07:00
|
|
|
|
|
|
|
if args.changed?
|
|
|
|
opoo "No tests are directly associated with the changed files!"
|
|
|
|
return
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2024-01-06 12:51:15 -08:00
|
|
|
parallel = false if args.profile
|
|
|
|
|
2021-04-06 09:38:37 +09:00
|
|
|
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"]
|
2021-04-06 09:38:37 +09:00
|
|
|
"tests/#{parallel_rspec_log_name}"
|
2021-04-01 23:15:51 +09:00
|
|
|
else
|
2021-04-06 09:38:37 +09:00
|
|
|
"#{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
|
|
|
|
2019-02-27 14:02:38 +00:00
|
|
|
parallel_args = if ENV["CI"]
|
2021-04-01 23:15:51 +09:00
|
|
|
%W[
|
2017-05-08 08:38:25 +01:00
|
|
|
--combine-stderr
|
|
|
|
--serialize-stdout
|
2021-04-08 20:23:50 +09:00
|
|
|
--runtime-log #{parallel_rspec_log_path}
|
2017-05-08 08:38:25 +01:00
|
|
|
]
|
|
|
|
else
|
|
|
|
%w[
|
|
|
|
--nice
|
|
|
|
]
|
2017-02-28 14:33:39 +01:00
|
|
|
end
|
2017-02-10 21:21:57 +01:00
|
|
|
|
2017-12-15 09:14:44 +00: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
|
2017-12-15 09:14:44 +00:00
|
|
|
|
2018-05-05 18:40:01 +05:30
|
|
|
bundle_args = ["-I", HOMEBREW_LIBRARY_PATH/"test"]
|
|
|
|
bundle_args += %W[
|
2017-12-15 09:14:44 +00:00
|
|
|
--seed #{seed}
|
2017-05-08 08:38:25 +01:00
|
|
|
--color
|
|
|
|
--require spec_helper
|
2017-02-10 21:21:57 +01:00
|
|
|
]
|
2023-08-10 15:47:51 +01:00
|
|
|
bundle_args << "--fail-fast" if args.fail_fast?
|
2024-01-06 12:51:15 -08:00
|
|
|
bundle_args << "--profile" << args.profile if args.profile
|
2017-02-21 21:55:11 +01:00
|
|
|
|
2022-11-21 22:14:04 -08: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"
|
2021-09-30 10:13:43 +01:00
|
|
|
files = files.grep_v(%r{^test/(os/mac|cask)(/.*|_spec\.rb)$})
|
2015-07-22 16:04:59 +08:00
|
|
|
end
|
2017-02-28 14:33:39 +01:00
|
|
|
|
2017-03-05 20:45:48 -08:00
|
|
|
unless OS.linux?
|
2018-05-05 18:40:01 +05:30
|
|
|
bundle_args << "--tag" << "~needs_linux"
|
2021-09-30 10:13:43 +01:00
|
|
|
files = files.grep_v(%r{^test/os/linux(/.*|_spec\.rb)$})
|
2017-03-05 20:45:48 -08:00
|
|
|
end
|
2022-11-21 22:14:04 -08:00
|
|
|
# rubocop:enable Homebrew/MoveToExtendOS
|
2017-03-05 20:45:48 -08:00
|
|
|
|
2023-02-17 15:26:18 +00:00
|
|
|
bundle_args << "--tag" << "~needs_network" unless args.online?
|
|
|
|
unless ENV["CI"]
|
|
|
|
bundle_args << "--tag" << "~needs_ci" \
|
|
|
|
<< "--tag" << "~needs_svn"
|
|
|
|
end
|
|
|
|
|
2017-12-15 09:14:44 +00:00
|
|
|
puts "Randomized with seed #{seed}"
|
|
|
|
|
2021-06-29 12:43:47 +01:00
|
|
|
# Submit test flakiness information using BuildPulse
|
|
|
|
# BUILDPULSE used in spec_helper.rb
|
2021-06-30 08:41:19 +01:00
|
|
|
if use_buildpulse?
|
|
|
|
ENV["BUILDPULSE"] = "1"
|
|
|
|
ohai "Running tests with BuildPulse-friendly settings"
|
|
|
|
end
|
2021-06-29 12:43:47 +01:00
|
|
|
|
2017-05-07 17:28:39 +01:00
|
|
|
if parallel
|
2019-02-27 14:02:38 +00:00
|
|
|
system "bundle", "exec", "parallel_rspec", *parallel_args, "--", *bundle_args, "--", *files
|
2017-05-07 17:28:39 +01:00
|
|
|
else
|
2018-05-05 18:40:01 +05:30
|
|
|
system "bundle", "exec", "rspec", *bundle_args, "--", *files
|
2017-02-28 14:33:39 +01:00
|
|
|
end
|
2023-03-01 20:09:27 +00:00
|
|
|
success = $CHILD_STATUS.success?
|
2017-02-28 14:33:39 +01:00
|
|
|
|
2021-06-29 12:43:47 +01:00
|
|
|
run_buildpulse if use_buildpulse?
|
|
|
|
|
2023-03-01 20:09:27 +00:00
|
|
|
return if success
|
2018-09-17 02:45:00 +02:00
|
|
|
|
2017-02-28 14:33:39 +01:00
|
|
|
Homebrew.failed = true
|
2012-04-16 16:44:11 -05:00
|
|
|
end
|
|
|
|
end
|
2022-11-09 14:45:43 +00:00
|
|
|
|
2024-01-31 14:54:56 -08:00
|
|
|
def self.setup_environment!(args)
|
2022-11-09 14:45:43 +00:00
|
|
|
# Cleanup any unwanted user configuration.
|
|
|
|
allowed_test_env = %w[
|
|
|
|
HOMEBREW_GITHUB_API_TOKEN
|
|
|
|
HOMEBREW_CACHE
|
|
|
|
HOMEBREW_LOGS
|
|
|
|
HOMEBREW_TEMP
|
|
|
|
]
|
2023-09-29 01:58:41 +01:00
|
|
|
allowed_test_env << "HOMEBREW_USE_RUBY_FROM_PATH" if Homebrew::EnvConfig.developer?
|
2022-11-09 14:45:43 +00:00
|
|
|
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"
|
|
|
|
|
2023-02-07 19:25:40 +01:00
|
|
|
# TODO: remove this and fix tests when possible.
|
|
|
|
ENV["HOMEBREW_NO_INSTALL_FROM_API"] = "1"
|
2024-02-28 21:06:10 -08:00
|
|
|
ENV.delete("HOMEBREW_INTERNAL_JSON_V3")
|
2023-02-07 19:25:40 +01:00
|
|
|
|
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
|
2012-03-25 00:49:18 +11:00
|
|
|
end
|