mirror of
https://github.com/ruby/ruby.git
synced 2025-08-23 13:04:13 +02:00
606 lines
16 KiB
Ruby
606 lines
16 KiB
Ruby
# frozen_string_literal: true
|
|
|
|
require_relative "helper"
|
|
|
|
require "rubygems/remote_fetcher"
|
|
require "rubygems/package"
|
|
|
|
class TestGemRemoteFetcher < Gem::TestCase
|
|
include Gem::DefaultUserInteraction
|
|
|
|
def setup
|
|
super
|
|
|
|
@cache_dir = File.join @gemhome, "cache"
|
|
|
|
# TODO: why does the remote fetcher need it written to disk?
|
|
@a1, @a1_gem = util_gem "a", "1" do |s|
|
|
s.executables << "a_bin"
|
|
end
|
|
|
|
@a1.loaded_from = File.join(@gemhome, "specifications", @a1.full_name)
|
|
|
|
Gem::RemoteFetcher.fetcher = nil
|
|
@stub_ui = Gem::MockGemUi.new
|
|
@fetcher = Gem::RemoteFetcher.fetcher
|
|
end
|
|
|
|
def test_self_fetcher
|
|
fetcher = Gem::RemoteFetcher.fetcher
|
|
refute_nil fetcher
|
|
assert_kind_of Gem::RemoteFetcher, fetcher
|
|
end
|
|
|
|
def test_self_fetcher_with_proxy
|
|
proxy_uri = "http://proxy.example.com"
|
|
Gem.configuration[:http_proxy] = proxy_uri
|
|
Gem::RemoteFetcher.fetcher = nil
|
|
|
|
fetcher = Gem::RemoteFetcher.fetcher
|
|
|
|
refute_nil fetcher
|
|
assert_kind_of Gem::RemoteFetcher, fetcher
|
|
assert_equal proxy_uri, fetcher.instance_variable_get(:@proxy).to_s
|
|
ensure
|
|
Gem.configuration[:http_proxy] = nil
|
|
end
|
|
|
|
def test_fetch_path_bad_uri
|
|
fetcher = Gem::RemoteFetcher.new nil
|
|
@fetcher = fetcher
|
|
|
|
e = assert_raise ArgumentError do
|
|
@fetcher.fetch_path("gems.example.com/yaml", nil, true)
|
|
end
|
|
|
|
assert_equal "uri scheme is invalid: nil", e.message
|
|
end
|
|
|
|
def test_cache_update_path
|
|
uri = Gem::URI "http://example/file"
|
|
path = File.join @tempdir, "file"
|
|
|
|
fetcher = util_fuck_with_fetcher "hello"
|
|
|
|
data = fetcher.cache_update_path uri, path
|
|
|
|
assert_equal "hello", data
|
|
|
|
assert_equal "hello", File.read(path)
|
|
end
|
|
|
|
def test_cache_update_path_with_utf8_internal_encoding
|
|
with_internal_encoding("UTF-8") do
|
|
uri = Gem::URI "http://example/file"
|
|
path = File.join @tempdir, "file"
|
|
data = String.new("\xC8").force_encoding(Encoding::BINARY)
|
|
|
|
fetcher = util_fuck_with_fetcher data
|
|
|
|
written_data = fetcher.cache_update_path uri, path
|
|
|
|
assert_equal data, written_data
|
|
assert_equal data, File.binread(path)
|
|
end
|
|
end
|
|
|
|
def test_cache_update_path_no_update
|
|
uri = Gem::URI "http://example/file"
|
|
path = File.join @tempdir, "file"
|
|
|
|
fetcher = util_fuck_with_fetcher "hello"
|
|
|
|
data = fetcher.cache_update_path uri, path, false
|
|
|
|
assert_equal "hello", data
|
|
|
|
assert_path_not_exist path
|
|
end
|
|
|
|
def util_fuck_with_fetcher(data, blow = false)
|
|
fetcher = Gem::RemoteFetcher.fetcher
|
|
fetcher.instance_variable_set :@test_data, data
|
|
|
|
if blow
|
|
def fetcher.fetch_path(arg, *rest)
|
|
# OMG I'm such an ass
|
|
class << self; remove_method :fetch_path; end
|
|
def self.fetch_path(arg, *rest)
|
|
@test_arg = arg
|
|
@test_data
|
|
end
|
|
|
|
raise Gem::RemoteFetcher::FetchError.new("haha!", "")
|
|
end
|
|
else
|
|
def fetcher.fetch_path(arg, *rest)
|
|
@test_arg = arg
|
|
@test_data
|
|
end
|
|
end
|
|
|
|
fetcher
|
|
end
|
|
|
|
def test_download
|
|
a1_data = nil
|
|
File.open @a1_gem, "rb" do |fp|
|
|
a1_data = fp.read
|
|
end
|
|
|
|
fetcher = util_fuck_with_fetcher a1_data
|
|
|
|
a1_cache_gem = @a1.cache_file
|
|
assert_equal a1_cache_gem, fetcher.download(@a1, "http://gems.example.com")
|
|
assert_equal("http://gems.example.com/gems/a-1.gem",
|
|
fetcher.instance_variable_get(:@test_arg).to_s)
|
|
assert File.exist?(a1_cache_gem)
|
|
end
|
|
|
|
def test_download_with_auth
|
|
a1_data = nil
|
|
File.open @a1_gem, "rb" do |fp|
|
|
a1_data = fp.read
|
|
end
|
|
|
|
fetcher = util_fuck_with_fetcher a1_data
|
|
|
|
a1_cache_gem = @a1.cache_file
|
|
assert_equal a1_cache_gem, fetcher.download(@a1, "http://user:password@gems.example.com")
|
|
assert_equal("http://user:password@gems.example.com/gems/a-1.gem",
|
|
fetcher.instance_variable_get(:@test_arg).to_s)
|
|
assert File.exist?(a1_cache_gem)
|
|
end
|
|
|
|
def test_download_with_token
|
|
a1_data = nil
|
|
File.open @a1_gem, "rb" do |fp|
|
|
a1_data = fp.read
|
|
end
|
|
|
|
fetcher = util_fuck_with_fetcher a1_data
|
|
|
|
a1_cache_gem = @a1.cache_file
|
|
assert_equal a1_cache_gem, fetcher.download(@a1, "http://token@gems.example.com")
|
|
assert_equal("http://token@gems.example.com/gems/a-1.gem",
|
|
fetcher.instance_variable_get(:@test_arg).to_s)
|
|
assert File.exist?(a1_cache_gem)
|
|
end
|
|
|
|
def test_download_with_x_oauth_basic
|
|
a1_data = nil
|
|
File.open @a1_gem, "rb" do |fp|
|
|
a1_data = fp.read
|
|
end
|
|
|
|
fetcher = util_fuck_with_fetcher a1_data
|
|
|
|
a1_cache_gem = @a1.cache_file
|
|
assert_equal a1_cache_gem, fetcher.download(@a1, "http://token:x-oauth-basic@gems.example.com")
|
|
assert_equal("http://token:x-oauth-basic@gems.example.com/gems/a-1.gem",
|
|
fetcher.instance_variable_get(:@test_arg).to_s)
|
|
assert File.exist?(a1_cache_gem)
|
|
end
|
|
|
|
def test_download_with_encoded_auth
|
|
a1_data = nil
|
|
File.open @a1_gem, "rb" do |fp|
|
|
a1_data = fp.read
|
|
end
|
|
|
|
fetcher = util_fuck_with_fetcher a1_data
|
|
|
|
a1_cache_gem = @a1.cache_file
|
|
assert_equal a1_cache_gem, fetcher.download(@a1, "http://user:%25pas%25sword@gems.example.com")
|
|
assert_equal("http://user:%25pas%25sword@gems.example.com/gems/a-1.gem",
|
|
fetcher.instance_variable_get(:@test_arg).to_s)
|
|
assert File.exist?(a1_cache_gem)
|
|
end
|
|
|
|
def test_download_cached
|
|
FileUtils.mv @a1_gem, @cache_dir
|
|
|
|
inst = Gem::RemoteFetcher.fetcher
|
|
|
|
assert_equal @a1.cache_file, inst.download(@a1, "http://gems.example.com")
|
|
end
|
|
|
|
def test_download_local
|
|
omit "doesn't work if tempdir has +" if @tempdir.include?("+")
|
|
FileUtils.mv @a1_gem, @tempdir
|
|
local_path = File.join @tempdir, @a1.file_name
|
|
inst = nil
|
|
|
|
Dir.chdir @tempdir do
|
|
inst = Gem::RemoteFetcher.fetcher
|
|
end
|
|
|
|
assert_equal @a1.cache_file, inst.download(@a1, local_path)
|
|
end
|
|
|
|
def test_download_local_space
|
|
omit "doesn't work if tempdir has +" if @tempdir.include?("+")
|
|
space_path = File.join @tempdir, "space path"
|
|
FileUtils.mkdir space_path
|
|
FileUtils.mv @a1_gem, space_path
|
|
local_path = File.join space_path, @a1.file_name
|
|
inst = nil
|
|
|
|
Dir.chdir @tempdir do
|
|
inst = Gem::RemoteFetcher.fetcher
|
|
end
|
|
|
|
assert_equal @a1.cache_file, inst.download(@a1, local_path)
|
|
end
|
|
|
|
def test_download_install_dir
|
|
a1_data = File.open @a1_gem, "rb", &:read
|
|
|
|
fetcher = util_fuck_with_fetcher a1_data
|
|
|
|
install_dir = File.join @tempdir, "more_gems"
|
|
|
|
a1_cache_gem = File.join install_dir, "cache", @a1.file_name
|
|
FileUtils.mkdir_p(File.dirname(a1_cache_gem))
|
|
actual = fetcher.download(@a1, "http://gems.example.com", install_dir)
|
|
|
|
assert_equal a1_cache_gem, actual
|
|
assert_equal("http://gems.example.com/gems/a-1.gem",
|
|
fetcher.instance_variable_get(:@test_arg).to_s)
|
|
|
|
assert File.exist?(a1_cache_gem)
|
|
end
|
|
|
|
unless Gem.win_platform? || Process.uid.zero? # File.chmod doesn't work
|
|
def test_download_local_read_only
|
|
omit "doesn't work if tempdir has +" if @tempdir.include?("+")
|
|
FileUtils.mv @a1_gem, @tempdir
|
|
local_path = File.join @tempdir, @a1.file_name
|
|
inst = nil
|
|
FileUtils.chmod 0o555, @a1.cache_dir
|
|
begin
|
|
FileUtils.mkdir_p File.join(Gem.user_dir, "cache")
|
|
rescue StandardError
|
|
nil
|
|
end
|
|
FileUtils.chmod 0o555, File.join(Gem.user_dir, "cache")
|
|
|
|
Dir.chdir @tempdir do
|
|
inst = Gem::RemoteFetcher.fetcher
|
|
end
|
|
|
|
assert_equal(File.join(@tempdir, @a1.file_name),
|
|
inst.download(@a1, local_path))
|
|
ensure
|
|
if local_path
|
|
FileUtils.chmod 0o755, File.join(Gem.user_dir, "cache")
|
|
FileUtils.chmod 0o755, @a1.cache_dir
|
|
end
|
|
end
|
|
|
|
def test_download_read_only
|
|
FileUtils.chmod 0o555, @a1.cache_dir
|
|
FileUtils.chmod 0o555, @gemhome
|
|
|
|
fetcher = util_fuck_with_fetcher File.read(@a1_gem)
|
|
fetcher.download(@a1, "http://gems.example.com")
|
|
a1_cache_gem = File.join Gem.user_dir, "cache", @a1.file_name
|
|
assert File.exist? a1_cache_gem
|
|
ensure
|
|
FileUtils.chmod 0o755, @gemhome
|
|
FileUtils.chmod 0o755, @a1.cache_dir
|
|
end
|
|
end
|
|
|
|
def test_download_platform_legacy
|
|
original_platform = "old-platform"
|
|
|
|
e1, e1_gem = util_gem "e", "1" do |s|
|
|
s.platform = Gem::Platform::CURRENT
|
|
s.instance_variable_set :@original_platform, original_platform
|
|
end
|
|
e1.loaded_from = File.join(@gemhome, "specifications", e1.full_name)
|
|
|
|
e1_data = nil
|
|
File.open e1_gem, "rb" do |fp|
|
|
e1_data = fp.read
|
|
end
|
|
|
|
fetcher = util_fuck_with_fetcher e1_data, :blow_chunks
|
|
|
|
e1_cache_gem = e1.cache_file
|
|
|
|
assert_equal e1_cache_gem, fetcher.download(e1, "http://gems.example.com")
|
|
|
|
assert_equal("http://gems.example.com/gems/#{e1.original_name}.gem",
|
|
fetcher.instance_variable_get(:@test_arg).to_s)
|
|
assert File.exist?(e1_cache_gem)
|
|
end
|
|
|
|
def test_download_same_file
|
|
omit "doesn't work if tempdir has +" if @tempdir.include?("+")
|
|
FileUtils.mv @a1_gem, @tempdir
|
|
local_path = File.join @tempdir, @a1.file_name
|
|
inst = nil
|
|
|
|
Dir.chdir @tempdir do
|
|
inst = Gem::RemoteFetcher.fetcher
|
|
end
|
|
|
|
cache_path = @a1.cache_file
|
|
FileUtils.mv local_path, cache_path
|
|
|
|
gem = Gem::Package.new cache_path
|
|
|
|
assert_equal cache_path, inst.download(gem.spec, cache_path)
|
|
end
|
|
|
|
def test_download_unsupported
|
|
inst = Gem::RemoteFetcher.fetcher
|
|
|
|
e = assert_raise ArgumentError do
|
|
inst.download @a1, "ftp://gems.rubyforge.org"
|
|
end
|
|
|
|
assert_equal "unsupported URI scheme ftp", e.message
|
|
end
|
|
|
|
def test_download_to_cache
|
|
@a2, @a2_gem = util_gem "a", "2"
|
|
|
|
util_setup_spec_fetcher @a1, @a2
|
|
@fetcher.instance_variable_set :@a1, @a1
|
|
@fetcher.instance_variable_set :@a2, @a2
|
|
def @fetcher.fetch_path(uri, mtime = nil, head = false)
|
|
case uri.request_uri
|
|
when /#{@a1.spec_name}/ then
|
|
Gem.deflate Marshal.dump @a1
|
|
when /#{@a2.spec_name}/ then
|
|
Gem.deflate Marshal.dump @a2
|
|
else
|
|
uri.to_s
|
|
end
|
|
end
|
|
|
|
gem = Gem::RemoteFetcher.fetcher.download_to_cache dep "a"
|
|
|
|
assert_equal @a2.file_name, File.basename(gem)
|
|
end
|
|
|
|
def test_fetch_path_gzip
|
|
fetcher = Gem::RemoteFetcher.new nil
|
|
@fetcher = fetcher
|
|
|
|
def fetcher.fetch_http(uri, mtime, head = nil)
|
|
Gem::Util.gzip "foo"
|
|
end
|
|
|
|
assert_equal "foo", fetcher.fetch_path(@uri + "foo.gz")
|
|
end
|
|
|
|
def test_fetch_path_gzip_unmodified
|
|
fetcher = Gem::RemoteFetcher.new nil
|
|
@fetcher = fetcher
|
|
|
|
def fetcher.fetch_http(uri, mtime, head = nil)
|
|
nil
|
|
end
|
|
|
|
assert_nil fetcher.fetch_path(@uri + "foo.gz", Time.at(0))
|
|
end
|
|
|
|
def test_fetch_path_io_error
|
|
fetcher = Gem::RemoteFetcher.new nil
|
|
@fetcher = fetcher
|
|
|
|
def fetcher.fetch_http(*)
|
|
raise EOFError
|
|
end
|
|
|
|
url = "http://example.com/uri"
|
|
|
|
e = assert_raise Gem::RemoteFetcher::FetchError do
|
|
fetcher.fetch_path url
|
|
end
|
|
|
|
assert_equal "EOFError: EOFError (#{url})", e.message
|
|
assert_equal url, e.uri
|
|
end
|
|
|
|
def test_fetch_path_socket_error
|
|
fetcher = Gem::RemoteFetcher.new nil
|
|
@fetcher = fetcher
|
|
|
|
def fetcher.fetch_http(uri, mtime, head = nil)
|
|
raise SocketError
|
|
end
|
|
|
|
url = "http://example.com/uri"
|
|
|
|
e = assert_raise Gem::RemoteFetcher::FetchError do
|
|
fetcher.fetch_path url
|
|
end
|
|
|
|
assert_equal "SocketError: SocketError (#{url})", e.message
|
|
assert_equal url, e.uri
|
|
end
|
|
|
|
def test_fetch_path_system_call_error
|
|
fetcher = Gem::RemoteFetcher.new nil
|
|
@fetcher = fetcher
|
|
|
|
def fetcher.fetch_http(uri, mtime = nil, head = nil)
|
|
raise Errno::ECONNREFUSED, "connect(2)"
|
|
end
|
|
|
|
url = "http://example.com/uri"
|
|
|
|
e = assert_raise Gem::RemoteFetcher::FetchError do
|
|
fetcher.fetch_path url
|
|
end
|
|
|
|
assert_match(/ECONNREFUSED:.*connect\(2\) \(#{Regexp.escape url}\)\z/,
|
|
e.message)
|
|
assert_equal url, e.uri
|
|
end
|
|
|
|
def test_fetch_path_timeout_error
|
|
fetcher = Gem::RemoteFetcher.new nil
|
|
@fetcher = fetcher
|
|
|
|
def fetcher.fetch_http(uri, mtime = nil, head = nil)
|
|
raise Gem::Timeout::Error, "timed out"
|
|
end
|
|
|
|
url = "http://example.com/uri"
|
|
|
|
e = assert_raise Gem::RemoteFetcher::FetchError do
|
|
fetcher.fetch_path url
|
|
end
|
|
|
|
assert_match(/Gem::Timeout::Error: timed out \(#{Regexp.escape url}\)\z/,
|
|
e.message)
|
|
assert_equal url, e.uri
|
|
end
|
|
|
|
def test_fetch_path_getaddrinfo_error
|
|
fetcher = Gem::RemoteFetcher.new nil
|
|
@fetcher = fetcher
|
|
|
|
def fetcher.fetch_http(uri, mtime = nil, head = nil)
|
|
raise SocketError, "getaddrinfo: nodename nor servname provided"
|
|
end
|
|
|
|
url = "http://example.com/uri"
|
|
|
|
e = assert_raise Gem::RemoteFetcher::FetchError do
|
|
fetcher.fetch_path url
|
|
end
|
|
|
|
assert_match(/SocketError: getaddrinfo: nodename nor servname provided \(#{Regexp.escape url}\)\z/,
|
|
e.message)
|
|
assert_equal url, e.uri
|
|
end
|
|
|
|
def test_fetch_path_openssl_ssl_sslerror
|
|
fetcher = Gem::RemoteFetcher.new nil
|
|
@fetcher = fetcher
|
|
|
|
def fetcher.fetch_http(uri, mtime = nil, head = nil)
|
|
raise OpenSSL::SSL::SSLError
|
|
end
|
|
|
|
url = "http://example.com/uri"
|
|
|
|
e = assert_raise Gem::RemoteFetcher::FetchError do
|
|
fetcher.fetch_path url
|
|
end
|
|
|
|
assert_equal "OpenSSL::SSL::SSLError: OpenSSL::SSL::SSLError (#{url})", e.message
|
|
assert_equal url, e.uri
|
|
end
|
|
|
|
def test_fetch_path_unmodified
|
|
fetcher = Gem::RemoteFetcher.new nil
|
|
@fetcher = fetcher
|
|
|
|
def fetcher.fetch_http(uri, mtime, head = nil)
|
|
nil
|
|
end
|
|
|
|
assert_nil fetcher.fetch_path(Gem::URI.parse(@gem_repo), Time.at(0))
|
|
end
|
|
|
|
def test_fetch_http
|
|
fetcher = Gem::RemoteFetcher.new nil
|
|
@fetcher = fetcher
|
|
url = "http://gems.example.com/redirect"
|
|
|
|
def fetcher.request(uri, request_class, last_modified = nil)
|
|
url = "http://gems.example.com/redirect"
|
|
if defined? @requested
|
|
res = Gem::Net::HTTPOK.new nil, 200, nil
|
|
def res.body
|
|
"real_path"
|
|
end
|
|
else
|
|
@requested = true
|
|
res = Gem::Net::HTTPMovedPermanently.new nil, 301, nil
|
|
res.add_field "Location", url
|
|
end
|
|
res
|
|
end
|
|
|
|
data = fetcher.fetch_http Gem::URI.parse(url)
|
|
|
|
assert_equal "real_path", data
|
|
end
|
|
|
|
def test_fetch_http_redirects
|
|
fetcher = Gem::RemoteFetcher.new nil
|
|
@fetcher = fetcher
|
|
url = "http://gems.example.com/redirect"
|
|
|
|
def fetcher.request(uri, request_class, last_modified = nil)
|
|
url = "http://gems.example.com/redirect"
|
|
res = Gem::Net::HTTPMovedPermanently.new nil, 301, nil
|
|
res.add_field "Location", url
|
|
res
|
|
end
|
|
|
|
e = assert_raise Gem::RemoteFetcher::FetchError do
|
|
fetcher.fetch_http Gem::URI.parse(url)
|
|
end
|
|
|
|
assert_equal "too many redirects (#{url})", e.message
|
|
end
|
|
|
|
def test_fetch_http_redirects_without_location
|
|
fetcher = Gem::RemoteFetcher.new nil
|
|
@fetcher = fetcher
|
|
url = "http://gems.example.com/redirect"
|
|
|
|
def fetcher.request(uri, request_class, last_modified = nil)
|
|
res = Gem::Net::HTTPMovedPermanently.new nil, 301, nil
|
|
res
|
|
end
|
|
|
|
e = assert_raise Gem::RemoteFetcher::FetchError do
|
|
fetcher.fetch_http Gem::URI.parse(url)
|
|
end
|
|
|
|
assert_equal "redirecting but no redirect location was given (#{url})", e.message
|
|
end
|
|
|
|
def test_request_block
|
|
fetcher = Gem::RemoteFetcher.new nil
|
|
@fetcher = fetcher
|
|
|
|
assert_throws :block_called do
|
|
fetcher.request Gem::URI("http://example"), Gem::Net::HTTP::Get do |req|
|
|
assert_kind_of Gem::Net::HTTPGenericRequest, req
|
|
throw :block_called
|
|
end
|
|
end
|
|
end
|
|
|
|
def test_yaml_error_on_size
|
|
use_ui @stub_ui do
|
|
fetcher = Gem::RemoteFetcher.new nil
|
|
@fetcher = fetcher
|
|
assert_error { fetcher.size }
|
|
end
|
|
end
|
|
|
|
def assert_error(exception_class=Exception)
|
|
got_exception = false
|
|
|
|
begin
|
|
yield
|
|
rescue exception_class
|
|
got_exception = true
|
|
end
|
|
|
|
assert got_exception, "Expected exception conforming to #{exception_class}"
|
|
end
|
|
end
|