Skip to content

Commit

Permalink
test: scripts to assert on packaged gem files and installed gems
Browse files Browse the repository at this point in the history
some tests are skipped because they assert new behavior which will be
implemented in the next few commits.

Closes #2076
Closes #2078
  • Loading branch information
flavorjones committed Dec 22, 2020
1 parent 17c7754 commit 8118e97
Show file tree
Hide file tree
Showing 2 changed files with 324 additions and 0 deletions.
210 changes: 210 additions & 0 deletions scripts/test-gem-file-contents
@@ -0,0 +1,210 @@
#! /usr/bin/env ruby
# frozen_string_literal: true
#
# this script is intended to run as part of the CI test suite.
#
# it inspects the contents of a nokogiri gem file -- both the files and the gemspec -- to ensure
# we're packaging what we expect, and that we're not packaging anything we don't expect.
#
# this file isn't in the `test/` subdirectory because it's intended to be run standalone against a
# built gem file (and not against the source code or behavior of the gem itself).
#

require "bundler/inline"

gemfile do
source "https://rubygems.org"
gem "minitest"
gem "minitest-reporters"
end

require "yaml"

def usage_and_exit(message = nil)
puts "ERROR: #{message}" if message
puts "USAGE: #{File.basename(__FILE__)} <gemfile> [options]"
exit(1)
end

usage_and_exit if ARGV.include?("-h")
usage_and_exit unless gemfile = ARGV[0]
usage_and_exit("#{gemfile} does not exist") unless File.file?(gemfile)
usage_and_exit("#{gemfile} is not a gem") unless /\.gem$/.match(gemfile)
gemfile = File.expand_path(gemfile)

gemfile_contents = Dir.mktmpdir do |dir|
Dir.chdir(dir) do
unless system("tar -xf #{gemfile} data.tar.gz")
raise "could not unpack gem #{gemfile}"
end
%x(tar -ztf data.tar.gz).split("\n")
end
end

gemspec = Dir.mktmpdir do |dir|
Dir.chdir(dir) do
unless system("tar -xf #{gemfile} metadata.gz")
raise "could not unpack gem #{gemfile}"
end
YAML.load(%x(gunzip -c metadata.gz))
end
end

if ARGV.include?("-v")
puts "---------- gemfile contents ----------"
puts gemfile_contents
puts
puts "---------- gemspec ----------"
puts gemspec.to_ruby
puts
end

require "minitest/autorun"
require "minitest/reporters"
Minitest::Reporters.use!([Minitest::Reporters::SpecReporter.new])

puts "Testing '#{gemfile}' (#{gemspec.platform})"
describe File.basename(gemfile) do
let(:cross_rubies_path) { File.join(File.dirname(__FILE__), "..", ".cross_rubies") }
let(:native_ruby_versions) do
File.read(cross_rubies_path).split("\n").map do |line|
line.split(":").first.split(".").take(2).join(".") # ugh
end.uniq.sort
end

describe "setup" do
it "gemfile contains some files" do
actual = gemfile_contents.length
assert_operator(actual, :>, 60, "expected gemfile to contain more than #{actual} files")
end

it "gemspec is a Gem::Specfication" do
assert_equal(Gem::Specification, gemspec.class)
end
end

describe "all platforms" do
it "contains every ruby file in lib/" do
expected = %x(git ls-files lib).split("\n").grep(/\.rb$/).sort
actual = gemfile_contents.grep(%r{^lib/}).grep(/\.rb$/).sort
assert_equal(expected, actual)
end
end

describe "ruby platform" do
it "contains the port files" do
actual_ports = gemfile_contents.grep(%r{^ports/})
assert(actual_ports.grep(/libxml2-\d+\.\d+\.\d+\.tar\.gz/).length == 1,
"expected #{actual_ports} to include libxml2")
assert(actual_ports.grep(/libxslt-\d+\.\d+\.\d+\.tar\.gz/).length == 1,
"expected #{actual_ports} to include libxslt")
assert_equal(2, actual_ports.length)
end

it "contains the patch files" do
actual_patches = gemfile_contents.grep(%r{^patches/})
assert_operator(actual_patches.length, :>, 0)
end

it "does not contain header files in lib/nokogiri/include" do
# these are copied to lib/nokogiri/include during compilation, not packaged
assert_empty(gemfile_contents.grep(%r{^lib/.*\.h$}))
end

it "contains ext/nokogiri" do
assert_operator(gemfile_contents.grep(%r{^ext/nokogiri/.*\.[ch]}).length, :>, 20)
end

it "does not contain the java jar files" do
assert_empty(gemfile_contents.grep(/.*\.jar$/))
end

it "depends on mini_portile2" do
assert(gemspec.dependencies.find { |d| d.name == "mini_portile2" })
end

it "includes C files in extra_rdoc_files" do
assert_operator(gemspec.extra_rdoc_files.grep(%r{ext/nokogiri/.*\.c$}).length, :>, 10)
end
end if gemspec.platform == Gem::Platform::RUBY

describe "native platform" do
it "does not contain the port files" do
actual_ports = gemfile_contents.grep(%r{^ports/})
assert_empty(actual_ports)
end

it "does not contain the patch files" do
actual_patches = gemfile_contents.grep(%r{^patches/})
assert_empty(actual_patches)
end

it "contains nokogiri header files in lib/nokogiri/include" do
skip "until we fix https://github.com/sparklemotion/nokogiri/pull/1788"
assert_includes(gemfile_contents, "lib/nokogiri/include/nokogiri.h")
end

it "contains packaged libraries' header files in lib/nokogiri/include" do
skip "until we fix https://github.com/sparklemotion/nokogiri/pull/1788"
assert_includes(gemfile_contents, "lib/nokogiri/include/libxml2/libxml/tree.h")
assert_includes(gemfile_contents, "lib/nokogiri/include/libxslt/xslt.h")
assert_includes(gemfile_contents, "lib/nokogiri/include/libexslt/exslt.h")
end

it "does not contain ext/nokogiri" do
skip "until we fix https://github.com/sparklemotion/nokogiri/issues/2077"
assert_empty(gemfile_contents.grep(%r{^ext/nokogiri/}))
end

it "does not contain the java jar files" do
assert_empty(gemfile_contents.grep(/.*\.jar$/))
end

it "does not depend on mini_portile2" do
# https://github.com/sparklemotion/nokogiri/issues/2078
refute(gemspec.dependencies.find { |d| d.name == "mini_portile2" })
end

it "packages only ruby-version-specific libraries" do
# https://github.com/sparklemotion/nokogiri/issues/2076
native_ruby_versions.each do |version|
assert_includes(gemfile_contents, "lib/nokogiri/#{version}/nokogiri.so")
end
refute_includes(gemfile_contents, "lib/nokogiri/nokogiri.so")
end
end if gemspec.platform.is_a?(Gem::Platform) && gemspec.platform.cpu

describe "java platform" do
it "does not contain the port files" do
actual_ports = gemfile_contents.grep(%r{^ports/})
assert_empty(actual_ports)
end

it "does not contain the patch files" do
actual_patches = gemfile_contents.grep(%r{^patches/})
assert_empty(actual_patches)
end

it "does not contain header files in lib/nokogiri/include" do
skip "until we fix https://github.com/sparklemotion/nokogiri/pull/1788"
assert_empty(gemfile_contents.grep(%r{^lib/.*\.h$}))
end

it "does not contain ext/nokogiri" do
skip "until we fix https://github.com/sparklemotion/nokogiri/issues/2099"
assert_empty(gemfile_contents.grep(%r{^ext/nokogiri/}))
end

it "does contains the java jar files" do
actual_jars = gemfile_contents.grep(/.*\.jar$/)
["nokogiri", "isorelax", "jing", "nekodtd", "nekohtml", "serializer", "xalan", "xercesImpl", "xml-apis"].each do |jar|
assert_equal(1, actual_jars.grep(%r{/#{jar}\.jar$}).length, "expected to contain #{jar}.jar")
end
end

it "does not depend on mini_portile2" do
# https://github.com/sparklemotion/nokogiri/issues/2078
refute(gemspec.dependencies.find { |d| d.name == "mini_portile2" })
end
end if gemspec.platform == Gem::Platform.new("java")
end
114 changes: 114 additions & 0 deletions scripts/test-gem-installation
@@ -0,0 +1,114 @@
#! /usr/bin/env ruby
# frozen_string_literal: true
#
# this script is intended to run as part of the CI test suite.
#
# it inspects the filesystem of a nokogiri gem installation to ensure it's complete and sane, and
# doesn't install anything we don't expect.
#
# this file isn't in the `test/` subdirectory because it's intended to be run standalone against an
# installed gem (and not against the source code or behavior of the gem itself).
#

# this line needs to come before the bundler bit, to assert that we're running against an
# already-installed version (and not some other version that bundler/inline might install if it came
# first)
gemspec = Gem::Specification.find_by_name('nokogiri')
raise "could not find installed gem" unless gemspec

require "bundler/inline"

gemfile do
source "https://rubygems.org"
gem "minitest"
gem "minitest-reporters"
gem "nokogiri"
end

require 'nokogiri'
require 'yaml'

if ARGV.include?("-v")
puts "---------- Nokogiri version info ----------"
puts Nokogiri::VERSION_INFO.to_yaml
puts
puts "---------- Nokogiri installed gemspec ----------"
puts gemspec.to_ruby
puts
end

require "minitest/autorun"
require "minitest/reporters"
Minitest::Reporters.use!([Minitest::Reporters::SpecReporter.new])

puts "Testing #{gemspec.full_name} installed in #{gemspec.base_dir}"
describe gemspec.full_name do
let(:nokogiri_include_dir) { File.join(gemspec.gem_dir, "lib/nokogiri/include") }

# representative sample of the files
let(:nokogiri_header_files) { ["nokogiri.h", "xml_document.h", "xml_node.h"] }
let(:packaged_library_header_files) { ["libxml2/libxml/tree.h", "libxslt/xslt.h", "libexslt/exslt.h"] }

it "loads the same version as the spec we've loaded" do
assert_equal(Nokogiri::VERSION, gemspec.version.to_s)
end

describe "cruby" do
it "installs nokogiri headers" do
skip "until we fix https://github.com/sparklemotion/nokogiri/pull/1788"
assert(File.directory?(nokogiri_include_dir),
"expected directory to exist: #{nokogiri_include_dir}")

nokogiri_header_files.each do |header|
assert(File.file?(File.join(nokogiri_include_dir, header)),
"expected #{header} to be installed in #{nokogiri_include_dir}")
end
end

describe "native platform" do
it "acknowledges it is using packaged, precompiled libraries" do
assert(Nokogiri::VersionInfo.instance.libxml2_using_packaged?)
assert(Nokogiri::VERSION_INFO["libxml"].key?("source"))
assert_equal("packaged", Nokogiri::VERSION_INFO["libxml"]["source"])

assert(Nokogiri::VersionInfo.instance.libxml2_precompiled?)
assert(Nokogiri::VERSION_INFO["libxml"].key?("precompiled"))
assert(Nokogiri::VERSION_INFO["libxml"]["precompiled"])
end
end if gemspec.platform.is_a?(Gem::Platform) && gemspec.platform.cpu

describe "library" do
describe "packaged" do
it "declares where headers are installed" do
skip "until we fix https://github.com/sparklemotion/nokogiri/pull/1788"
# this is for nokogumbo and shouldn't be forever
nokogiri_include_parent_dir = File.dirname(nokogiri_include_dir)
assert_equal(nokogiri_include_parent_dir, Nokogiri::VERSION_INFO["libxml"]["libxml2_path"],
"expected Nokogiri::VERSION_INFO to point to #{nokogiri_include_parent_dir}")
end

it "installs packaged libraries' headers" do
skip "until we fix https://github.com/sparklemotion/nokogiri/pull/1788"
packaged_library_header_files.each do |header|
assert(File.file?(File.join(nokogiri_include_dir, header)),
"expected #{header} to be installed in #{nokogiri_include_dir}")
end
end
end if Nokogiri::VersionInfo.instance.libxml2_using_packaged?

describe "using system libraries" do
it "doesn't declare where headers are installed" do
refute(Nokogiri::VERSION_INFO["libxml"].key?("libxml2_path"))
end

it "does not install packaged libraries' headers" do
packaged_library_header_files.each do |header|
dir = File.join(nokogiri_include_dir, File.dirname(header))
refute(File.directory?(dir),
"expected directory #{dir} to not exist")
end
end
end unless Nokogiri::VersionInfo.instance.libxml2_using_packaged?
end
end unless gemspec.platform == Gem::Platform.new("java")
end

0 comments on commit 8118e97

Please sign in to comment.