diff options
Diffstat (limited to 'spec/bundled_gems_spec.rb')
| -rw-r--r-- | spec/bundled_gems_spec.rb | 422 |
1 files changed, 422 insertions, 0 deletions
diff --git a/spec/bundled_gems_spec.rb b/spec/bundled_gems_spec.rb new file mode 100644 index 0000000000..9af06dd181 --- /dev/null +++ b/spec/bundled_gems_spec.rb @@ -0,0 +1,422 @@ +require "bundled_gems" + +require "bundler" +require "fileutils" + +require_relative "bundler/support/builders" +require_relative "bundler/support/helpers" +require_relative "bundler/support/path" + +module Gem + def self.ruby=(ruby) + @ruby = ruby + end +end + +RSpec.configure do |config| + config.include Spec::Builders + config.include Spec::Helpers + config.include Spec::Path + + config.before(:suite) do + Gem.ruby = ENV["RUBY"] if ENV["RUBY"] + + require_relative "bundler/support/rubygems_ext" + Spec::Helpers.install_dev_bundler + FileUtils.mkdir_p Spec::Path.gem_path + end + + config.around(:each) do |example| + FileUtils.cp_r Spec::Path.pristine_system_gem_path, Spec::Path.system_gem_path + + with_gem_path_as(system_gem_path) do + Bundler.ui.silence { example.run } + + all_output = all_commands_output + if example.exception && !all_output.empty? + message = all_output + "\n" + example.exception.message + (class << example.exception; self; end).send(:define_method, :message) do + message + end + end + end + ensure + reset! + end + + config.after :suite do + FileUtils.rm_rf Spec::Path.pristine_system_gem_path + end +end + +RSpec.describe "bundled_gems.rb" do + let(:stub_code) { + source_lib_dir = File.realpath(Spec::Path.source_lib_dir.to_s) + <<~STUB + Gem::BUNDLED_GEMS.send(:remove_const, :LIBDIR) + Gem::BUNDLED_GEMS.send(:remove_const, :ARCHDIR) + Gem::BUNDLED_GEMS.send(:remove_const, :SINCE) + Gem::BUNDLED_GEMS.const_set(:LIBDIR, "#{source_lib_dir}/") + Gem::BUNDLED_GEMS.const_set(:ARCHDIR, File.expand_path($LOAD_PATH.find{|path| path.include?(".ext/common") }) + "/") + Gem::BUNDLED_GEMS.const_set(:SINCE, { "openssl" => RUBY_VERSION, "fileutils" => RUBY_VERSION, "csv" => "3.4.0", "net-smtp" => "3.1.0" }) + STUB + } + + def script(code, options = {}) + options[:artifice] ||= "compact_index" + code = <<~RUBY + #{stub_code} + require 'bundler/inline' + + #{code} + RUBY + ruby(code, options) + end + + it "Show warning require and LoadError" do + script <<-RUBY + gemfile do + source "https://rubygems.org" + end + + begin + require "csv" + rescue LoadError + end + require "openssl" + RUBY + + expect(err).to include(/csv used to be loaded from (.*) since Ruby 3.4.0/) + expect(err).to include(/-e:15/) + expect(err).to include(/openssl used to be loaded from (.*) since Ruby #{RUBY_VERSION}/) + expect(err).to include(/-e:18/) + end + + it "Show warning when bundled gems called as dependency" do + build_lib "activesupport", "7.0.7.2" do |s| + s.write "lib/active_support/all.rb", "require 'openssl'" + end + + script <<-RUBY, env: { "BUNDLER_SPEC_GEM_REPO" => gem_repo1.to_s } + gemfile do + source "https://gem.repo1" + path "#{lib_path}" do + gem "activesupport", "7.0.7.2" + end + end + + require "active_support/all" + RUBY + + expect(err).to include(/openssl used to be loaded from (.*) since Ruby #{RUBY_VERSION}/) + expect(err).to include(/lib\/active_support\/all\.rb:1/) + end + + it "Show warning dash gem like net/smtp" do + script <<-RUBY + gemfile do + source "https://rubygems.org" + end + + begin + require "net/smtp" + rescue LoadError + end + RUBY + + expect(err).to include(/net\/smtp used to be loaded from (.*) since Ruby 3.1.0/) + expect(err).to include(/-e:15/) + expect(err).to include("You can add net-smtp") + end + + it "Show warning sub-feature like openssl/bn" do + skip "This test is not working on Windows" if Gem.win_platform? + + script <<-RUBY + gemfile do + source "https://rubygems.org" + end + + require "openssl/bn" + RUBY + + expect(err).to include(/openssl\/bn is found in openssl, (.*) part of the default gems since Ruby #{RUBY_VERSION}/) + expect(err).to include(/-e:14/) + end + + it "Show warning when bundle exec with ruby and script" do + code = <<-RUBY + #{stub_code} + require "openssl" + RUBY + create_file("script.rb", code) + create_file("Gemfile", "source 'https://rubygems.org'") + + bundle "exec ruby script.rb" + + expect(err).to include(/openssl used to be loaded from (.*) since Ruby #{RUBY_VERSION}/) + expect(err).to include(/script\.rb:8/) + end + + it "Show warning when bundle exec with shebang's script" do + skip "This test is not working on Windows" if Gem.win_platform? + + code = <<-RUBY + #!/usr/bin/env ruby + #{stub_code} + require "openssl" + RUBY + create_file("script.rb", code) + FileUtils.chmod(0o777, bundled_app("script.rb")) + create_file("Gemfile", "source 'https://rubygems.org'") + + bundle "exec ./script.rb" + + expect(err).to include(/openssl used to be loaded from (.*) since Ruby #{RUBY_VERSION}/) + expect(err).to include(/script\.rb:9/) + end + + it "Show warning when bundle exec with -r option" do + create_file("stub.rb", stub_code) + create_file("Gemfile", "source 'https://rubygems.org'") + bundle "exec ruby -r./stub -ropenssl -e ''" + + expect(err).to include(/openssl used to be loaded from (.*) since Ruby #{RUBY_VERSION}/) + end + + it "Show warning when warn is not the standard one in the current scope" do + script <<-RUBY + module My + def warn(msg) + end + + def my + gemfile do + source "https://rubygems.org" + end + + require "openssl" + end + + extend self + end + + My.my + RUBY + + expect(err).to include(/openssl used to be loaded from (.*) since Ruby #{RUBY_VERSION}/) + expect(err).to include(/-e:19/) + end + + it "Don't show warning when bundled gems called as dependency" do + build_lib "activesupport", "7.0.7.2" do |s| + s.write "lib/active_support/all.rb", "require 'openssl'" + end + build_lib "openssl", "1.0.0" do |s| + s.write "lib/openssl.rb", "puts 'openssl'" + end + + script <<-RUBY, env: { "BUNDLER_SPEC_GEM_REPO" => gem_repo1.to_s } + gemfile do + source "https://gem.repo1" + path "#{lib_path}" do + gem "activesupport", "7.0.7.2" + gem "openssl" + end + end + + require "active_support/all" + RUBY + + expect(err).to be_empty + end + + it "Show warning with bootsnap cases" do + script <<-RUBY + gemfile do + source "https://rubygems.org" + # gem "bootsnap", require: false + end + + # require 'bootsnap' + # Bootsnap.setup(cache_dir: 'tmp/cache') + + # bootsnap expand required feature to full path + # require 'openssl' + require Gem::BUNDLED_GEMS::ARCHDIR + 'openssl' + RUBY + + expect(err).to include(/openssl used to be loaded from (.*) since Ruby #{RUBY_VERSION}/) + # TODO: We should assert caller location like below: + # test_warn_bootsnap.rb:14: warning: ... + end + + it "Show warning with bootsnap for gem with native extension" do + script <<-RUBY + gemfile do + source "https://rubygems.org" + # gem "bootsnap", require: false + end + + # require 'bootsnap' + # Bootsnap.setup(cache_dir: 'tmp/cache') + + # bootsnap expand required feature to full path + # require 'openssl' + require Gem::BUNDLED_GEMS::ARCHDIR + "openssl" + RUBY + + expect(err).to include(/openssl used to be loaded from (.*) since Ruby #{RUBY_VERSION}/) + # TODO: We should assert caller location like below: + # test_warn_bootsnap_rubyarchdir_gem.rb:14: warning: ... + end + + it "Show warning with bootsnap and some gem in Gemfile" do + # Original issue is childprocess 5.0.0 and logger. + build_lib "fileutils2", "5.0.0" do |s| + # bootsnap expand required feature to full path + rubylibpath = File.realpath(File.join(__dir__, "..", "lib")) + s.write "lib/fileutils2.rb", "require '#{rubylibpath}/fileutils'" + end + + script <<-RUBY + gemfile do + source "https://rubygems.org" + # gem "bootsnap", require: false + path "#{lib_path}" do + gem "fileutils2", "5.0.0" + end + end + + # require 'bootsnap' + # Bootsnap.setup(cache_dir: 'tmp/cache') + + # bootsnap expand required feature to full path + require Gem.loaded_specs["fileutils2"].full_gem_path + '/lib/fileutils2' + RUBY + + expect(err).to include(/fileutils used to be loaded from (.*) since Ruby #{RUBY_VERSION}/) + # TODO: We should assert caller location like below: + # $GEM_HOME/gems/childprocess-5.0.0/lib/childprocess.rb:7: warning: + end + + it "Show warning with zeitwerk" do + libpath = Dir[File.expand_path("../.bundle/gems/{zeitwerk}-*/lib", __dir__)].map(&:to_s).first + code = <<-RUBY + #{stub_code} + $LOAD_PATH.unshift("#{libpath}") + require "zeitwerk" + loader = Zeitwerk::Loader.for_gem(warn_on_extra_files: false) + loader.setup + + require 'openssl' + RUBY + create_file("script.rb", code) + create_file("Gemfile", "source 'https://rubygems.org'") + bundle "exec ruby script.rb" + + expect(err).to include(/openssl used to be loaded from (.*) since Ruby #{RUBY_VERSION}/) + expect(err).to include(/script\.rb:13/) + end + + it "Don't show warning openssl/bn when openssl on Gemfile" do + build_lib "openssl", "1.0.0" do |s| + s.write "lib/openssl.rb", "puts 'openssl'" + s.write "lib/openssl/bn.rb", "puts 'openssl/bn'" + end + + script <<-RUBY, env: { "BUNDLER_SPEC_GEM_REPO" => gem_repo1.to_s } + gemfile do + source "https://gem.repo1" + path "#{lib_path}" do + gem "openssl" + end + end + + require "openssl/bn" + RUBY + + expect(err).to be_empty + end + + it "Don't show warning with net/smtp when net-smtp on Gemfile" do + build_lib "net-smtp", "1.0.0" do |s| + s.write "lib/net/smtp.rb", "puts 'net-smtp'" + end + + script <<-RUBY, env: { "BUNDLER_SPEC_GEM_REPO" => gem_repo1.to_s } + gemfile do + source "https://gem.repo1" + path "#{lib_path}" do + gem "net-smtp" + end + end + + require "net/smtp" + RUBY + + expect(err).to be_empty + end + + describe ".force_activate" do + before do + allow_any_instance_of(Bundler::Runtime).to receive(:setup).and_raise(Bundler::GemNotFound) + end + + context "with bundle environment" do + before do + code = <<-RUBY + #!/usr/bin/env ruby + + Gem::BUNDLED_GEMS.force_activate("csv") + RUBY + create_file("script.rb", code) + create_file("Gemfile", "source 'https://rubygems.org'") + end + + it "lockfile is available" do + bundle "install" + bundle "exec ./script.rb" + + expect(err).to include("gem install csv") + end + + it "lockfile is not available" do + bundle "exec ./script.rb" + + expect(err).to include("gem install csv") + end + end + + context "with bundler/inline" do + it "foo is available on LOAD_PATH" do + build_lib "foo", "1.0.0" do |s| + s.write "lib/foo.rb", "puts :foo" + end + + script <<-RUBY, env: { "BUNDLER_SPEC_GEM_REPO" => gem_repo1.to_s } + #!/usr/bin/env ruby + gemfile do + source "https://gem.repo1" + path "#{lib_path}" do + gem "foo", "1.0.0" + end + end + + Gem::BUNDLED_GEMS.force_activate("csv") + puts $LOAD_PATH + RUBY + + expect(err).to include("gem install csv") + expect(out).to include("foo-1.0.0/lib") + end + end + + context "without bundle environment" do + it "warns about installation requirement" do + expect_any_instance_of(Object).to receive(:warn) + Gem::BUNDLED_GEMS.force_activate("csv") + end + end + end +end |
