summaryrefslogtreecommitdiff
path: root/jni/ruby/test/rubygems/test_gem_remote_fetcher.rb
diff options
context:
space:
mode:
authorJari Vetoniemi <jari.vetoniemi@indooratlas.com>2020-03-16 18:49:26 +0900
committerJari Vetoniemi <jari.vetoniemi@indooratlas.com>2020-03-30 00:39:06 +0900
commitfcbf63e62c627deae76c1b8cb8c0876c536ed811 (patch)
tree64cb17de3f41a2b6fef2368028fbd00349946994 /jni/ruby/test/rubygems/test_gem_remote_fetcher.rb
Fresh start
Diffstat (limited to 'jni/ruby/test/rubygems/test_gem_remote_fetcher.rb')
-rw-r--r--jni/ruby/test/rubygems/test_gem_remote_fetcher.rb987
1 files changed, 987 insertions, 0 deletions
diff --git a/jni/ruby/test/rubygems/test_gem_remote_fetcher.rb b/jni/ruby/test/rubygems/test_gem_remote_fetcher.rb
new file mode 100644
index 0000000..63dd8fe
--- /dev/null
+++ b/jni/ruby/test/rubygems/test_gem_remote_fetcher.rb
@@ -0,0 +1,987 @@
+require 'rubygems/test_case'
+
+require 'webrick'
+begin
+ require 'webrick/https'
+rescue LoadError => e
+ raise unless (e.respond_to?(:path) && e.path == 'openssl') ||
+ e.message =~ / -- openssl$/
+end
+
+require 'rubygems/remote_fetcher'
+require 'rubygems/package'
+require 'minitest/mock'
+
+# = Testing Proxy Settings
+#
+# These tests check the proper proxy server settings by running two
+# web servers. The web server at http://localhost:#{SERVER_PORT}
+# represents the normal gem server and returns a gemspec with a rake
+# version of 0.4.11. The web server at http://localhost:#{PROXY_PORT}
+# represents the proxy server and returns a different dataset where
+# rake has version 0.4.2. This allows us to detect which server is
+# returning the data.
+#
+# Note that the proxy server is not a *real* proxy server. But our
+# software doesn't really care, as long as we hit the proxy URL when a
+# proxy is configured.
+
+class TestGemRemoteFetcher < Gem::TestCase
+
+ include Gem::DefaultUserInteraction
+
+ SERVER_DATA = <<-EOY
+--- !ruby/object:Gem::Cache
+gems:
+ rake-0.4.11: !ruby/object:Gem::Specification
+ rubygems_version: "0.7"
+ specification_version: 1
+ name: rake
+ version: !ruby/object:Gem::Version
+ version: 0.4.11
+ date: 2004-11-12
+ summary: Ruby based make-like utility.
+ require_paths:
+ - lib
+ author: Jim Weirich
+ email: jim@weirichhouse.org
+ homepage: http://rake.rubyforge.org
+ rubyforge_project: rake
+ description: Rake is a Make-like program implemented in Ruby. Tasks and dependencies are specified in standard Ruby syntax.
+ autorequire:
+ default_executable: rake
+ bindir: bin
+ has_rdoc: true
+ required_ruby_version: !ruby/object:Gem::Version::Requirement
+ requirements:
+ -
+ - ">"
+ - !ruby/object:Gem::Version
+ version: 0.0.0
+ version:
+ platform: ruby
+ files:
+ - README
+ test_files: []
+ library_stubs:
+ rdoc_options:
+ extra_rdoc_files:
+ executables:
+ - rake
+ extensions: []
+ requirements: []
+ dependencies: []
+ EOY
+
+ PROXY_DATA = SERVER_DATA.gsub(/0.4.11/, '0.4.2')
+
+ DIR = File.expand_path(File.dirname(__FILE__))
+
+ def setup
+ @proxies = %w[http_proxy HTTP_PROXY http_proxy_user HTTP_PROXY_USER http_proxy_pass HTTP_PROXY_PASS no_proxy NO_PROXY]
+ @old_proxies = @proxies.map {|k| ENV[k] }
+ @proxies.each {|k| ENV[k] = nil }
+
+ super
+ self.class.start_servers
+ self.class.enable_yaml = true
+ self.class.enable_zip = false
+
+ base_server_uri = "http://localhost:#{self.class.normal_server_port}"
+ @proxy_uri = "http://localhost:#{self.class.proxy_server_port}"
+
+ @server_uri = base_server_uri + "/yaml"
+ @server_z_uri = base_server_uri + "/yaml.Z"
+
+ # REFACTOR: copied from test_gem_dependency_installer.rb
+ @gems_dir = File.join @tempdir, 'gems'
+ @cache_dir = File.join @gemhome, "cache"
+ FileUtils.mkdir @gems_dir
+
+ # 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
+
+ @fetcher = Gem::RemoteFetcher.fetcher
+ end
+
+ def teardown
+ @fetcher.close_all
+ self.class.stop_servers
+ super
+ Gem.configuration[:http_proxy] = nil
+ @proxies.each_with_index {|k, i| ENV[k] = @old_proxies[i] }
+ 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
+ end
+
+ def test_fetch_size_bad_uri
+ fetcher = Gem::RemoteFetcher.new nil
+ @fetcher = fetcher
+
+ e = assert_raises ArgumentError do
+ fetcher.fetch_size 'gems.example.com/yaml'
+ end
+
+ assert_equal 'uri scheme is invalid: nil', e.message
+ end
+
+ def test_fetch_size_socket_error
+ fetcher = Gem::RemoteFetcher.new nil
+ @fetcher = fetcher
+ def fetcher.request(uri, request_class, last_modified = nil)
+ raise SocketError, "tarded"
+ end
+
+ uri = 'http://gems.example.com/yaml'
+ e = assert_raises Gem::RemoteFetcher::FetchError do
+ fetcher.fetch_size uri
+ end
+
+ assert_equal "SocketError: tarded (#{uri})", e.message
+ end
+
+ def test_no_proxy
+ use_ui @ui do
+ assert_data_from_server @fetcher.fetch_path(@server_uri)
+ assert_equal SERVER_DATA.size, @fetcher.fetch_size(@server_uri)
+ end
+ end
+
+ def test_api_endpoint
+ uri = URI.parse "http://example.com/foo"
+ target = MiniTest::Mock.new
+ target.expect :target, "gems.example.com"
+
+ dns = MiniTest::Mock.new
+ dns.expect :getresource, target, [String, Object]
+
+ fetch = Gem::RemoteFetcher.new nil, dns
+ assert_equal URI.parse("http://gems.example.com/foo"), fetch.api_endpoint(uri)
+
+ target.verify
+ dns.verify
+ end
+
+ def test_api_endpoint_ignores_trans_domain_values
+ uri = URI.parse "http://gems.example.com/foo"
+ target = MiniTest::Mock.new
+ target.expect :target, "blah.com"
+
+ dns = MiniTest::Mock.new
+ dns.expect :getresource, target, [String, Object]
+
+ fetch = Gem::RemoteFetcher.new nil, dns
+ assert_equal URI.parse("http://gems.example.com/foo"), fetch.api_endpoint(uri)
+
+ target.verify
+ dns.verify
+ end
+
+ def test_api_endpoint_ignores_trans_domain_values_that_starts_with_original
+ uri = URI.parse "http://example.com/foo"
+ target = MiniTest::Mock.new
+ target.expect :target, "example.combadguy.com"
+
+ dns = MiniTest::Mock.new
+ dns.expect :getresource, target, [String, Object]
+
+ fetch = Gem::RemoteFetcher.new nil, dns
+ assert_equal URI.parse("http://example.com/foo"), fetch.api_endpoint(uri)
+
+ target.verify
+ dns.verify
+ end
+
+ def test_api_endpoint_ignores_trans_domain_values_that_end_with_original
+ uri = URI.parse "http://example.com/foo"
+ target = MiniTest::Mock.new
+ target.expect :target, "badexample.com"
+
+ dns = MiniTest::Mock.new
+ dns.expect :getresource, target, [String, Object]
+
+ fetch = Gem::RemoteFetcher.new nil, dns
+ assert_equal URI.parse("http://example.com/foo"), fetch.api_endpoint(uri)
+
+ target.verify
+ dns.verify
+ end
+
+ def test_cache_update_path
+ uri = 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_no_update
+ uri = 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
+
+ refute_path_exists path
+ end
+
+ def util_fuck_with_fetcher data, blow = false
+ fetcher = Gem::RemoteFetcher.fetcher
+ fetcher.instance_variable_set :@test_data, data
+
+ unless blow then
+ def fetcher.fetch_path arg, *rest
+ @test_arg = arg
+ @test_data
+ end
+ else
+ 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!", nil)
+ 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_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
+ 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
+ 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' do |fp|
+ fp.read
+ end
+
+ 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 win_platform? # File.chmod doesn't work
+ def test_download_local_read_only
+ FileUtils.mv @a1_gem, @tempdir
+ local_path = File.join @tempdir, @a1.file_name
+ inst = nil
+ FileUtils.chmod 0555, @a1.cache_dir
+
+ Dir.chdir @tempdir do
+ inst = Gem::RemoteFetcher.fetcher
+ end
+
+ assert_equal(File.join(@tempdir, @a1.file_name),
+ inst.download(@a1, local_path))
+ ensure
+ FileUtils.chmod 0755, @a1.cache_dir
+ end
+
+ def test_download_read_only
+ FileUtils.chmod 0555, @a1.cache_dir
+ FileUtils.chmod 0555, @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 0755, @gemhome
+ FileUtils.chmod 0755, @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
+ 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_raises 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.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_equal 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_raises 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_raises 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_raises Gem::RemoteFetcher::FetchError do
+ fetcher.fetch_path url
+ end
+
+ assert_match %r|ECONNREFUSED:.*connect\(2\) \(#{Regexp.escape url}\)\z|,
+ 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_equal nil, fetcher.fetch_path(URI.parse(@gem_repo), Time.at(0))
+ end
+
+ def test_implicit_no_proxy
+ use_ui @ui do
+ ENV['http_proxy'] = 'http://fakeurl:12345'
+ fetcher = Gem::RemoteFetcher.new :no_proxy
+ @fetcher = fetcher
+ assert_data_from_server fetcher.fetch_path(@server_uri)
+ end
+ end
+
+ def test_implicit_proxy
+ use_ui @ui do
+ ENV['http_proxy'] = @proxy_uri
+ fetcher = Gem::RemoteFetcher.new nil
+ @fetcher = fetcher
+ assert_data_from_proxy fetcher.fetch_path(@server_uri)
+ end
+ end
+
+ def test_implicit_upper_case_proxy
+ use_ui @ui do
+ ENV['HTTP_PROXY'] = @proxy_uri
+ fetcher = Gem::RemoteFetcher.new nil
+ @fetcher = fetcher
+ assert_data_from_proxy fetcher.fetch_path(@server_uri)
+ end
+ end
+
+ def test_implicit_proxy_no_env
+ use_ui @ui do
+ fetcher = Gem::RemoteFetcher.new nil
+ @fetcher = fetcher
+ assert_data_from_server fetcher.fetch_path(@server_uri)
+ end
+ 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'
+ unless defined? @requested then
+ @requested = true
+ res = Net::HTTPMovedPermanently.new nil, 301, nil
+ res.add_field 'Location', url
+ res
+ else
+ res = Net::HTTPOK.new nil, 200, nil
+ def res.body() 'real_path' end
+ res
+ end
+ end
+
+ data = fetcher.fetch_http 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 = Net::HTTPMovedPermanently.new nil, 301, nil
+ res.add_field 'Location', url
+ res
+ end
+
+ e = assert_raises Gem::RemoteFetcher::FetchError do
+ fetcher.fetch_http URI.parse(url)
+ end
+
+ assert_equal "too many redirects (#{url})", e.message
+ end
+
+ def test_fetch_s3
+ fetcher = Gem::RemoteFetcher.new nil
+ @fetcher = fetcher
+ url = 's3://testuser:testpass@my-bucket/gems/specs.4.8.gz'
+ $fetched_uri = nil
+
+ def fetcher.request(uri, request_class, last_modified = nil)
+ $fetched_uri = uri
+ res = Net::HTTPOK.new nil, 200, nil
+ def res.body() 'success' end
+ res
+ end
+
+ def fetcher.s3_expiration
+ 1395098371
+ end
+
+ data = fetcher.fetch_s3 URI.parse(url)
+
+ assert_equal 'https://my-bucket.s3.amazonaws.com/gems/specs.4.8.gz?AWSAccessKeyId=testuser&Expires=1395098371&Signature=eUTr7NkpZEet%2BJySE%2BfH6qukroI%3D', $fetched_uri.to_s
+ assert_equal 'success', data
+ ensure
+ $fetched_uri = nil
+ end
+
+ def test_fetch_s3_no_creds
+ fetcher = Gem::RemoteFetcher.new nil
+ @fetcher = fetcher
+ url = 's3://my-bucket/gems/specs.4.8.gz'
+ e = assert_raises Gem::RemoteFetcher::FetchError do
+ fetcher.fetch_s3 URI.parse(url)
+ end
+
+ assert_match "credentials needed", e.message
+ end
+
+ def test_observe_no_proxy_env_single_host
+ use_ui @ui do
+ ENV["http_proxy"] = @proxy_uri
+ ENV["no_proxy"] = URI::parse(@server_uri).host
+ fetcher = Gem::RemoteFetcher.new nil
+ @fetcher = fetcher
+ assert_data_from_server fetcher.fetch_path(@server_uri)
+ end
+ end
+
+ def test_observe_no_proxy_env_list
+ use_ui @ui do
+ ENV["http_proxy"] = @proxy_uri
+ ENV["no_proxy"] = "fakeurl.com, #{URI::parse(@server_uri).host}"
+ fetcher = Gem::RemoteFetcher.new nil
+ @fetcher = fetcher
+ assert_data_from_server fetcher.fetch_path(@server_uri)
+ end
+ end
+
+ def test_request_block
+ fetcher = Gem::RemoteFetcher.new nil
+ @fetcher = fetcher
+
+ assert_throws :block_called do
+ fetcher.request URI('http://example'), Net::HTTP::Get do |req|
+ assert_kind_of Net::HTTPGenericRequest, req
+ throw :block_called
+ end
+ end
+ end
+
+ def test_yaml_error_on_size
+ use_ui @ui do
+ self.class.enable_yaml = false
+ fetcher = Gem::RemoteFetcher.new nil
+ @fetcher = fetcher
+ assert_error { fetcher.size }
+ end
+ end
+
+ def test_ssl_connection
+ ssl_server = self.class.start_ssl_server
+ temp_ca_cert = File.join(DIR, 'ca_cert.pem')
+ with_configured_fetcher(":ssl_ca_cert: #{temp_ca_cert}") do |fetcher|
+ fetcher.fetch_path("https://localhost:#{ssl_server.config[:Port]}/yaml")
+ end
+ end
+
+ def test_ssl_client_cert_auth_connection
+ skip 'openssl is missing' unless defined?(OpenSSL::SSL)
+
+ ssl_server = self.class.start_ssl_server({
+ :SSLVerifyClient =>
+ OpenSSL::SSL::VERIFY_PEER|OpenSSL::SSL::VERIFY_FAIL_IF_NO_PEER_CERT})
+
+ temp_ca_cert = File.join(DIR, 'ca_cert.pem')
+ temp_client_cert = File.join(DIR, 'client.pem')
+
+ with_configured_fetcher(
+ ":ssl_ca_cert: #{temp_ca_cert}\n" +
+ ":ssl_client_cert: #{temp_client_cert}\n") do |fetcher|
+ fetcher.fetch_path("https://localhost:#{ssl_server.config[:Port]}/yaml")
+ end
+ end
+
+ def test_do_not_allow_invalid_client_cert_auth_connection
+ skip 'openssl is missing' unless defined?(OpenSSL::SSL)
+
+ ssl_server = self.class.start_ssl_server({
+ :SSLVerifyClient =>
+ OpenSSL::SSL::VERIFY_PEER|OpenSSL::SSL::VERIFY_FAIL_IF_NO_PEER_CERT})
+
+ temp_ca_cert = File.join(DIR, 'ca_cert.pem')
+ temp_client_cert = File.join(DIR, 'invalid_client.pem')
+
+ with_configured_fetcher(
+ ":ssl_ca_cert: #{temp_ca_cert}\n" +
+ ":ssl_client_cert: #{temp_client_cert}\n") do |fetcher|
+ assert_raises Gem::RemoteFetcher::FetchError do
+ fetcher.fetch_path("https://localhost:#{ssl_server.config[:Port]}/yaml")
+ end
+ end
+ end
+
+ def test_do_not_allow_insecure_ssl_connection_by_default
+ ssl_server = self.class.start_ssl_server
+ with_configured_fetcher do |fetcher|
+ assert_raises Gem::RemoteFetcher::FetchError do
+ fetcher.fetch_path("https://localhost:#{ssl_server.config[:Port]}/yaml")
+ end
+ end
+ end
+
+ def test_ssl_connection_allow_verify_none
+ ssl_server = self.class.start_ssl_server
+ with_configured_fetcher(":ssl_verify_mode: 0") do |fetcher|
+ fetcher.fetch_path("https://localhost:#{ssl_server.config[:Port]}/yaml")
+ end
+ end
+
+ def test_do_not_follow_insecure_redirect
+ ssl_server = self.class.start_ssl_server
+ temp_ca_cert = File.join(DIR, 'ca_cert.pem'),
+ with_configured_fetcher(":ssl_ca_cert: #{temp_ca_cert}") do |fetcher|
+ assert_raises Gem::RemoteFetcher::FetchError do
+ fetcher.fetch_path("https://localhost:#{ssl_server.config[:Port]}/insecure_redirect?to=#{@server_uri}")
+ end
+ end
+ end
+
+ def with_configured_fetcher(config_str = nil, &block)
+ if config_str
+ temp_conf = File.join @tempdir, '.gemrc'
+ File.open temp_conf, 'w' do |fp|
+ fp.puts config_str
+ end
+ Gem.configuration = Gem::ConfigFile.new %W[--config-file #{temp_conf}]
+ end
+ fetcher = Gem::RemoteFetcher.new
+ yield fetcher
+ ensure
+ fetcher.close_all
+ Gem.configuration = nil
+ 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
+
+ def assert_data_from_server(data)
+ assert_match(/0\.4\.11/, data, "Data is not from server")
+ end
+
+ def assert_data_from_proxy(data)
+ assert_match(/0\.4\.2/, data, "Data is not from proxy")
+ end
+
+ class NilLog < WEBrick::Log
+ def log(level, data) #Do nothing
+ end
+ end
+
+ class << self
+ attr_reader :normal_server, :proxy_server
+ attr_accessor :enable_zip, :enable_yaml
+
+ def start_servers
+ @normal_server ||= start_server(SERVER_DATA)
+ @proxy_server ||= start_server(PROXY_DATA)
+ @enable_yaml = true
+ @enable_zip = false
+ @ssl_server = nil
+ @ssl_server_thread = nil
+ end
+
+ def stop_servers
+ if @normal_server
+ @normal_server.kill.join
+ @normal_server = nil
+ end
+ if @proxy_server
+ @proxy_server.kill.join
+ @proxy_server = nil
+ end
+ if @ssl_server
+ @ssl_server.stop
+ @ssl_server = nil
+ end
+ if @ssl_server_thread
+ @ssl_server_thread.kill.join
+ @ssl_server_thread = nil
+ end
+ end
+
+ def normal_server_port
+ @normal_server[:server].config[:Port]
+ end
+
+ def proxy_server_port
+ @proxy_server[:server].config[:Port]
+ end
+
+ DIR = File.expand_path(File.dirname(__FILE__))
+
+ def start_ssl_server(config = {})
+ raise MiniTest::Skip, 'openssl not installed' unless
+ defined?(OpenSSL::SSL)
+
+ null_logger = NilLog.new
+ server = WEBrick::HTTPServer.new({
+ :Port => 0,
+ :Logger => null_logger,
+ :AccessLog => [],
+ :SSLEnable => true,
+ :SSLCACertificateFile => File.join(DIR, 'ca_cert.pem'),
+ :SSLCertificate => cert('ssl_cert.pem'),
+ :SSLPrivateKey => key('ssl_key.pem'),
+ :SSLVerifyClient => nil,
+ :SSLCertName => nil
+ }.merge(config))
+ server.mount_proc("/yaml") { |req, res|
+ res.body = "--- true\n"
+ }
+ server.mount_proc("/insecure_redirect") { |req, res|
+ res.set_redirect(WEBrick::HTTPStatus::MovedPermanently, req.query['to'])
+ }
+ server.ssl_context.tmp_dh_callback = proc {|_, _, k| OpenSSL::PKey::DH.new(k) }
+ t = Thread.new do
+ begin
+ server.start
+ rescue Exception => ex
+ abort ex.message
+ puts "ERROR during server thread: #{ex.message}"
+ ensure
+ server.shutdown
+ end
+ end
+ while server.status != :Running
+ sleep 0.1
+ unless t.alive?
+ t.join
+ raise
+ end
+ end
+ @ssl_server = server
+ @ssl_server_thread = t
+ server
+ end
+
+ private
+
+ def start_server(data)
+ null_logger = NilLog.new
+ s = WEBrick::HTTPServer.new(
+ :Port => 0,
+ :DocumentRoot => nil,
+ :Logger => null_logger,
+ :AccessLog => null_logger
+ )
+ s.mount_proc("/kill") { |req, res| s.shutdown }
+ s.mount_proc("/yaml") { |req, res|
+ if @enable_yaml
+ res.body = data
+ res['Content-Type'] = 'text/plain'
+ res['content-length'] = data.size
+ else
+ res.status = "404"
+ res.body = "<h1>NOT FOUND</h1>"
+ res['Content-Type'] = 'text/html'
+ end
+ }
+ s.mount_proc("/yaml.Z") { |req, res|
+ if @enable_zip
+ res.body = Zlib::Deflate.deflate(data)
+ res['Content-Type'] = 'text/plain'
+ else
+ res.status = "404"
+ res.body = "<h1>NOT FOUND</h1>"
+ res['Content-Type'] = 'text/html'
+ end
+ }
+ th = Thread.new do
+ begin
+ s.start
+ rescue Exception => ex
+ abort "ERROR during server thread: #{ex.message}"
+ ensure
+ s.shutdown
+ end
+ end
+ th[:server] = s
+ th
+ end
+
+ def cert(filename)
+ OpenSSL::X509::Certificate.new(File.read(File.join(DIR, filename)))
+ end
+
+ def key(filename)
+ OpenSSL::PKey::RSA.new(File.read(File.join(DIR, filename)))
+ end
+ end
+
+ def test_correct_for_windows_path
+ path = "/C:/WINDOWS/Temp/gems"
+ assert_equal "C:/WINDOWS/Temp/gems", @fetcher.correct_for_windows_path(path)
+
+ path = "/home/skillet"
+ assert_equal "/home/skillet", @fetcher.correct_for_windows_path(path)
+ end
+
+end
+