Merge pull request #1984 from reitermarkus/brew-tests-rspec

Add RSpec support to `brew tests`.
This commit is contained in:
Markus Reiter 2017-02-11 18:22:06 +01:00 committed by GitHub
commit cf18a999f1
12 changed files with 448 additions and 197 deletions

View File

@ -7,10 +7,21 @@ require "tap"
module Homebrew
module_function
def run_tests(executable, files, args = [])
opts = []
opts << "--serialize-stdout" if ENV["CI"]
system "bundle", "exec", executable, *opts, "--", *args, "--", *files
return if $?.success?
Homebrew.failed = true
end
def tests
HOMEBREW_LIBRARY_PATH.cd do
ENV.delete "HOMEBREW_VERBOSE"
ENV.delete "VERBOSE"
ENV.delete("HOMEBREW_CASK_OPTS")
ENV["HOMEBREW_NO_ANALYTICS_THIS_RUN"] = "1"
ENV["HOMEBREW_DEVELOPER"] = "1"
ENV["TESTOPTS"] = "-v" if ARGV.verbose?
@ -45,27 +56,35 @@ module Homebrew
# Make it easier to reproduce test runs.
ENV["SEED"] = ARGV.next if ARGV.include? "--seed"
files = Dir.glob("test/**/*_test.rb")
files = Dir.glob("test/**/*_{spec,test}.rb")
.reject { |p| !OS.mac? && p.start_with?("test/os/mac/") }
.reject { |p| !OS.mac? && p.start_with?("test/cask/") }
.reject { |p| p.start_with?("test/vendor/bundle/") }
opts = []
opts << "--serialize-stdout" if ENV["CI"]
args = []
args << "--trace" if ARGV.include? "--trace"
test_args = []
test_args << "--trace" if ARGV.include? "--trace"
if ARGV.value("only")
test_name, test_method = ARGV.value("only").split(":", 2)
files = Dir.glob("test/{#{test_name},#{test_name}/**/*}_test.rb")
args << "--name=test_#{test_method}" if test_method
files = Dir.glob("test/{#{test_name},#{test_name}/**/*}_{spec,test}.rb")
test_args << "--name=test_#{test_method}" if test_method
end
args += ARGV.named.select { |v| v[/^TEST(OPTS)?=/] }
test_files = files.select { |p| p.end_with?("_test.rb") }
spec_files = files.select { |p| p.end_with?("_spec.rb") }
system "bundle", "exec", "parallel_test", *opts, "--", *args, "--", *files
test_args += ARGV.named.select { |v| v[/^TEST(OPTS)?=/] }
run_tests "parallel_test", test_files, test_args
Homebrew.failed = !$?.success?
spec_args = [
"--color",
"-I", HOMEBREW_LIBRARY_PATH/"test",
"--require", "spec_helper",
"--format", "progress",
"--format", "ParallelTests::RSpec::RuntimeLogger",
"--out", "tmp/parallel_runtime_rspec.log"
]
run_tests "parallel_rspec", spec_files, spec_args
if (fs_leak_log = HOMEBREW_LIBRARY_PATH/"tmp/fs_leak.log").file?
fs_leak_log_content = fs_leak_log.read

View File

@ -0,0 +1,149 @@
require "extend/ARGV"
describe HomebrewArgvExtension do
subject { argv.extend(HomebrewArgvExtension) }
let(:argv) { ["mxcl"] }
describe "#formulae" do
it "raises an error when a Formula is unavailable" do
expect { subject.formulae }.to raise_error FormulaUnavailableError
end
context "when there are no Formulae" do
let(:argv) { [] }
it "returns an empty array" do
expect(subject.formulae).to be_empty
end
end
end
describe "#casks" do
it "returns an empty array if there is no match" do
expect(subject.casks).to eq []
end
end
describe "#kegs" do
context "when there are matching Kegs" do
before(:each) do
keg = HOMEBREW_CELLAR + "mxcl/10.0"
keg.mkpath
end
it "returns an array of Kegs" do
expect(subject.kegs.length).to eq 1
end
end
context "when there are no matching Kegs" do
let(:argv) { [] }
it "returns an empty array" do
expect(subject.kegs).to be_empty
end
end
end
describe "#named" do
let(:argv) { ["foo", "--debug", "-v"] }
it "returns an array of non-option arguments" do
expect(subject.named).to eq ["foo"]
end
context "when there are no named arguments" do
let(:argv) { [] }
it "returns an empty array" do
expect(subject.named).to be_empty
end
end
end
describe "#options_only" do
let(:argv) { ["--foo", "-vds", "a", "b", "cdefg"] }
it "returns an array of option arguments" do
expect(subject.options_only).to eq ["--foo", "-vds"]
end
end
describe "#flags_only" do
let(:argv) { ["--foo", "-vds", "a", "b", "cdefg"] }
it "returns an array of flags" do
expect(subject.flags_only).to eq ["--foo"]
end
end
describe "#empty?" do
let(:argv) { [] }
it "returns true if it is empty" do
expect(subject).to be_empty
end
end
describe "#switch?" do
let(:argv) { ["-ns", "-i", "--bar", "-a-bad-arg"] }
it "returns true if the given string is a switch" do
%w[n s i].each do |s|
expect(subject.switch?(s)).to be true
end
end
it "returns false if the given string is not a switch" do
%w[b ns bar --bar -n a bad arg].each do |s|
expect(subject.switch?(s)).to be false
end
end
end
describe "#flag?" do
let(:argv) { ["--foo", "-bq", "--bar"] }
it "returns true if the given string is a flag" do
expect(subject.flag?("--foo")).to eq true
expect(subject.flag?("--bar")).to eq true
end
it "returns true if there is a switch with the same initial character" do
expect(subject.flag?("--baz")).to eq true
expect(subject.flag?("--qux")).to eq true
end
it "returns false if there is no matching flag" do
expect(subject.flag?("--frotz")).to eq false
expect(subject.flag?("--debug")).to eq false
end
end
describe "#value" do
let(:argv) { ["--foo=", "--bar=ab"] }
it "returns the value for a given string" do
expect(subject.value("foo")).to eq ""
expect(subject.value("bar")).to eq "ab"
end
it "returns nil if there is no matching argument" do
expect(subject.value("baz")).to be nil
end
end
describe "#values" do
let(:argv) { ["--foo=", "--bar=a", "--baz=b,c"] }
it "returns the value for a given argument" do
expect(subject.values("foo")).to eq []
expect(subject.values("bar")).to eq ["a"]
expect(subject.values("baz")).to eq ["b", "c"]
end
it "returns nil if there is no matching argument" do
expect(subject.values("qux")).to be nil
end
end
end

View File

@ -1,79 +0,0 @@
require "testing_env"
require "extend/ARGV"
class ArgvExtensionTests < Homebrew::TestCase
def setup
super
@argv = [].extend(HomebrewArgvExtension)
end
def test_argv_formulae
@argv.unshift "mxcl"
assert_raises(FormulaUnavailableError) { @argv.formulae }
end
def test_argv_casks
@argv.unshift "mxcl"
assert_equal [], @argv.casks
end
def test_argv_kegs
keg = HOMEBREW_CELLAR + "mxcl/10.0"
keg.mkpath
@argv << "mxcl"
assert_equal 1, @argv.kegs.length
end
def test_argv_named
@argv << "foo" << "--debug" << "-v"
assert_equal %w[foo], @argv.named
end
def test_options_only
@argv << "--foo" << "-vds" << "a" << "b" << "cdefg"
assert_equal %w[--foo -vds], @argv.options_only
end
def test_flags_only
@argv << "--foo" << "-vds" << "a" << "b" << "cdefg"
assert_equal %w[--foo], @argv.flags_only
end
def test_empty_argv
assert_empty @argv.named
assert_empty @argv.kegs
assert_empty @argv.formulae
assert_empty @argv
end
def test_switch?
@argv << "-ns" << "-i" << "--bar" << "-a-bad-arg"
%w[n s i].each { |s| assert @argv.switch?(s) }
%w[b ns bar --bar -n a bad arg].each { |s| assert !@argv.switch?(s) }
end
def test_flag?
@argv << "--foo" << "-bq" << "--bar"
assert @argv.flag?("--foo")
assert @argv.flag?("--bar")
assert @argv.flag?("--baz")
assert @argv.flag?("--qux")
assert !@argv.flag?("--frotz")
assert !@argv.flag?("--debug")
end
def test_value
@argv << "--foo=" << "--bar=ab"
assert_equal "", @argv.value("foo")
assert_equal "ab", @argv.value("bar")
assert_nil @argv.value("baz")
end
def test_values
@argv << "--foo=" << "--bar=a" << "--baz=b,c"
assert_equal [], @argv.values("foo")
assert_equal ["a"], @argv.values("bar")
assert_equal ["b", "c"], @argv.values("baz")
assert_nil @argv.values("qux")
end
end

View File

@ -4,6 +4,9 @@ gem "mocha"
gem "minitest"
gem "minitest-reporters"
gem "parallel_tests"
gem "rspec"
gem "rspec-its", require: false
gem "rspec-wait", require: false
group :coverage do
gem "simplecov", require: false

View File

@ -7,6 +7,7 @@ GEM
json
simplecov
url
diff-lcs (1.3)
docile (1.1.5)
json (2.0.3)
metaclass (0.0.4)
@ -21,6 +22,24 @@ GEM
parallel (1.10.0)
parallel_tests (2.13.0)
parallel
rspec (3.5.0)
rspec-core (~> 3.5.0)
rspec-expectations (~> 3.5.0)
rspec-mocks (~> 3.5.0)
rspec-core (3.5.4)
rspec-support (~> 3.5.0)
rspec-expectations (3.5.0)
diff-lcs (>= 1.2.0, < 2.0)
rspec-support (~> 3.5.0)
rspec-its (1.2.0)
rspec-core (>= 3.0.0)
rspec-expectations (>= 3.0.0)
rspec-mocks (3.5.0)
diff-lcs (>= 1.2.0, < 2.0)
rspec-support (~> 3.5.0)
rspec-support (3.5.0)
rspec-wait (0.0.9)
rspec (>= 3, < 4)
ruby-progressbar (1.8.1)
simplecov (0.13.0)
docile (~> 1.1.0)
@ -38,7 +57,10 @@ DEPENDENCIES
minitest-reporters
mocha
parallel_tests
rspec
rspec-its
rspec-wait
simplecov
BUNDLED WITH
1.13.7
1.14.3

View File

@ -0,0 +1,52 @@
require "open3"
RSpec::Matchers.define :have_valid_bash_syntax do
match do |file|
stdout, stderr, status = Open3.capture3("/bin/bash", "-n", file)
@actual = [file, stderr]
stdout.empty? && status.success?
end
failure_message do |(file, stderr)|
"expected that #{file} is a valid Bash file:\n#{stderr}"
end
end
describe "Bash" do
context "brew" do
subject { HOMEBREW_LIBRARY_PATH.parent.parent/"bin/brew" }
it { is_expected.to have_valid_bash_syntax }
end
context "every `.sh` file" do
it "has valid bash syntax" do
Pathname.glob("#{HOMEBREW_LIBRARY_PATH}/**/*.sh").each do |path|
relative_path = path.relative_path_from(HOMEBREW_LIBRARY_PATH)
next if relative_path.to_s.start_with?("shims/", "test/", "vendor/")
expect(path).to have_valid_bash_syntax
end
end
end
context "Bash completion" do
subject { HOMEBREW_LIBRARY_PATH.parent.parent/"completions/bash/brew" }
it { is_expected.to have_valid_bash_syntax }
end
context "every shim script" do
it "has valid bash syntax" do
# These have no file extension, but can be identified by their shebang.
(HOMEBREW_LIBRARY_PATH/"shims").find do |path|
next if path.directory?
next if path.symlink?
next unless path.executable?
next unless path.read(12) == "#!/bin/bash\n"
expect(path).to have_valid_bash_syntax
end
end
end
end

View File

@ -1,35 +0,0 @@
require "testing_env"
class BashTests < Homebrew::TestCase
def assert_valid_bash_syntax(file)
return unless file.exist?
output = Utils.popen_read("/bin/bash -n #{file} 2>&1")
assert $?.success?, output
end
def test_bin_brew
assert_valid_bash_syntax HOMEBREW_LIBRARY_PATH.parent.parent/"bin/brew"
end
def test_bash_code
Pathname.glob("#{HOMEBREW_LIBRARY_PATH}/**/*.sh").each do |pn|
pn_relative = pn.relative_path_from(HOMEBREW_LIBRARY_PATH)
next if pn_relative.to_s.start_with?("shims/", "test/", "vendor/")
assert_valid_bash_syntax pn
end
end
def test_bash_completion
script = HOMEBREW_LIBRARY_PATH.parent.parent/"completions/bash/brew"
assert_valid_bash_syntax script
end
def test_bash_shims
# These have no file extension, but can be identified by their shebang.
(HOMEBREW_LIBRARY_PATH/"shims").find do |pn|
next if pn.directory? || pn.symlink?
next unless pn.executable? && pn.read(12) == "#!/bin/bash\n"
assert_valid_bash_syntax pn
end
end
end

View File

@ -0,0 +1,111 @@
require "blacklist"
RSpec::Matchers.define :be_blacklisted do
match do |actual|
blacklisted?(actual)
end
end
describe "Blacklist" do
context "rubygems" do
%w[gem rubygem rubygems].each do |s|
subject { s }
it { is_expected.to be_blacklisted }
end
end
context "latex" do
%w[latex tex tex-live texlive TexLive].each do |s|
subject { s }
it { is_expected.to be_blacklisted }
end
end
context "pip" do
subject { "pip" }
it { is_expected.to be_blacklisted }
end
context "pil" do
subject { "pil" }
it { is_expected.to be_blacklisted }
end
context "macruby" do
subject { "MacRuby" }
it { is_expected.to be_blacklisted }
end
context "lzma" do
%w[lzma liblzma].each do |s|
subject { s }
it { is_expected.to be_blacklisted }
end
end
context "gtest" do
%w[gtest googletest google-test].each do |s|
subject { s }
it { is_expected.to be_blacklisted }
end
end
context "gmock" do
%w[gmock googlemock google-mock].each do |s|
subject { s }
it { is_expected.to be_blacklisted }
end
end
context "sshpass" do
subject { "sshpass" }
it { is_expected.to be_blacklisted }
end
context "gsutil" do
subject { "gsutil" }
it { is_expected.to be_blacklisted }
end
context "clojure" do
subject { "clojure" }
it { is_expected.to be_blacklisted }
end
context "osmium" do
%w[osmium Osmium].each do |s|
subject { s }
it { is_expected.to be_blacklisted }
end
end
context "gfortran" do
subject { "gfortran" }
it { is_expected.to be_blacklisted }
end
context "play" do
subject { "play" }
it { is_expected.to be_blacklisted }
end
context "haskell_platform" do
subject { "haskell-platform" }
it { is_expected.to be_blacklisted }
end
end

View File

@ -1,68 +0,0 @@
require "testing_env"
require "blacklist"
class BlacklistTests < Homebrew::TestCase
def assert_blacklisted(s)
assert blacklisted?(s), "'#{s}' should be blacklisted"
end
def test_rubygems
%w[gem rubygem rubygems].each { |s| assert_blacklisted s }
end
def test_latex
%w[latex tex tex-live texlive TexLive].each { |s| assert_blacklisted s }
end
def test_pip
assert_blacklisted "pip"
end
def test_pil
assert_blacklisted "pil"
end
def test_macruby
assert_blacklisted "MacRuby"
end
def test_lzma
%w[lzma liblzma].each { |s| assert_blacklisted s }
end
def test_gtest
%w[gtest googletest google-test].each { |s| assert_blacklisted s }
end
def test_gmock
%w[gmock googlemock google-mock].each { |s| assert_blacklisted s }
end
def test_sshpass
assert_blacklisted "sshpass"
end
def test_gsutil
assert_blacklisted "gsutil"
end
def test_clojure
assert_blacklisted "clojure"
end
def test_osmium
%w[osmium Osmium].each { |s| assert_blacklisted s }
end
def test_gfortran
assert_blacklisted "gfortran"
end
def test_play
assert_blacklisted "play"
end
def test_haskell_platform
assert_blacklisted "haskell-platform"
end
end

View File

@ -0,0 +1,77 @@
require "find"
require "pathname"
require "rspec/its"
require "rspec/wait"
require "set"
if ENV["HOMEBREW_TESTS_COVERAGE"]
require "simplecov"
end
$LOAD_PATH.unshift(File.expand_path("#{ENV["HOMEBREW_LIBRARY"]}/Homebrew"))
$LOAD_PATH.unshift(File.expand_path("#{ENV["HOMEBREW_LIBRARY"]}/Homebrew/test/support/lib"))
require "global"
require "tap"
require "test/support/helper/shutup"
TEST_DIRECTORIES = [
CoreTap.instance.path/"Formula",
HOMEBREW_CACHE,
HOMEBREW_CACHE_FORMULA,
HOMEBREW_CELLAR,
HOMEBREW_LOCK_DIR,
HOMEBREW_LOGS,
HOMEBREW_TEMP,
].freeze
RSpec.configure do |config|
config.order = :random
config.include(Test::Helper::Shutup)
config.around(:each) do |example|
begin
TEST_DIRECTORIES.each(&:mkpath)
@__files_before_test = Find.find(TEST_TMPDIR).map { |f| f.sub(TEST_TMPDIR, "") }
@__argv = ARGV.dup
@__env = ENV.to_hash # dup doesn't work on ENV
example.run
ensure
ARGV.replace(@__argv)
ENV.replace(@__env)
Tab.clear_cache
FileUtils.rm_rf [
TEST_DIRECTORIES.map(&:children),
HOMEBREW_LINKED_KEGS,
HOMEBREW_PINNED_KEGS,
HOMEBREW_PREFIX/".git",
HOMEBREW_PREFIX/"bin",
HOMEBREW_PREFIX/"share",
HOMEBREW_PREFIX/"opt",
HOMEBREW_PREFIX/"Caskroom",
HOMEBREW_LIBRARY/"Taps/caskroom",
HOMEBREW_LIBRARY/"Taps/homebrew/homebrew-bundle",
HOMEBREW_LIBRARY/"Taps/homebrew/homebrew-foo",
HOMEBREW_LIBRARY/"Taps/homebrew/homebrew-services",
HOMEBREW_LIBRARY/"Taps/homebrew/homebrew-shallow",
HOMEBREW_REPOSITORY/".git",
CoreTap.instance.path/".git",
CoreTap.instance.alias_dir,
CoreTap.instance.path/"formula_renames.json",
]
files_after_test = Find.find(TEST_TMPDIR).map { |f| f.sub(TEST_TMPDIR, "") }
diff = Set.new(@__files_before_test).difference(Set.new(files_after_test))
expect(diff).to be_empty, <<-EOS.undent
file leak detected:
#{diff.map { |f| " #{f}" }.join("\n")}
EOS
end
end
end

View File

@ -12,9 +12,6 @@ module Homebrew
include Test::Helper::Shutup
include Test::Helper::VersionAssertions
TEST_SHA1 = "deadbeefdeadbeefdeadbeefdeadbeefdeadbeef".freeze
TEST_SHA256 = "deadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef".freeze
TEST_DIRECTORIES = [
CoreTap.instance.path/"Formula",
HOMEBREW_CACHE,

View File

@ -38,3 +38,6 @@ TESTBALL_SHA256 = "91e3f7930c98d7ccfb288e115ed52d06b0e5bc16fec7dce8bdda865300270
TESTBALL_PATCHES_SHA256 = "799c2d551ac5c3a5759bea7796631a7906a6a24435b52261a317133a0bfb34d9".freeze
PATCH_A_SHA256 = "83404f4936d3257e65f176c4ffb5a5b8d6edd644a21c8d8dcc73e22a6d28fcfa".freeze
PATCH_B_SHA256 = "57958271bb802a59452d0816e0670d16c8b70bdf6530bcf6f78726489ad89b90".freeze
TEST_SHA1 = "deadbeefdeadbeefdeadbeefdeadbeefdeadbeef".freeze
TEST_SHA256 = "deadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef".freeze