diff --git a/.rubocop.yml b/.rubocop.yml index 8f53ed5b..d1d5b448 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -1,3 +1,6 @@ +AllCops: + TargetRubyVersion: 2.4.6 + require: - rubocop-rspec - rubocop-performance @@ -21,13 +24,15 @@ Metrics/BlockLength: - 'spec/**/*' Metrics/ClassLength: - Max: 102 + Max: 116 Metrics/CyclomaticComplexity: Max: 8 Metrics/AbcSize: Max: 16 + Exclude: + - 'lib/webdrivers/chromedriver.rb' Style/Documentation: Enabled: false diff --git a/.travis.yml b/.travis.yml index 909550f8..8adfbca8 100644 --- a/.travis.yml +++ b/.travis.yml @@ -20,5 +20,5 @@ matrix: env: RAKE_TASK=spec - rvm: 2.4.6 env: RAKE_TASK=rubocop - - rvm: jruby-9.2.0.0 + - rvm: jruby-9.2.7.0 env: RAKE_TASK=spec diff --git a/lib/webdrivers/chromedriver.rb b/lib/webdrivers/chromedriver.rb index d9d922b2..cd8c0588 100644 --- a/lib/webdrivers/chromedriver.rb +++ b/lib/webdrivers/chromedriver.rb @@ -22,7 +22,7 @@ def latest_version # Versions before 70 do not have a LATEST_RELEASE file return normalize_version('2.41') if release_version < normalize_version('70') - latest_applicable = latest_point_release(release_version) + latest_applicable = with_cache(file_name) { latest_point_release(release_version) } Webdrivers.logger.debug "Latest version available: #{latest_applicable}" normalize_version(latest_applicable) @@ -73,7 +73,7 @@ def download_url normalize_version(required_version) end - file_name = System.platform == 'win' ? 'windows32' : "#{System.platform}64" + file_name = System.platform == 'win' ? 'win32' : "#{System.platform}64" url = "#{base_url}/#{version}/chromedriver_#{file_name}.zip" Webdrivers.logger.debug "chromedriver URL: #{url}" @download_url = url diff --git a/lib/webdrivers/common.rb b/lib/webdrivers/common.rb index 340e9fc6..42a22673 100644 --- a/lib/webdrivers/common.rb +++ b/lib/webdrivers/common.rb @@ -17,6 +17,12 @@ class VersionError < StandardError class << self attr_accessor :proxy_addr, :proxy_port, :proxy_user, :proxy_pass, :install_dir + attr_writer :cache_time + + def cache_time + @cache_time || 0 + end + def logger @logger ||= Webdrivers::Logger.new end @@ -34,6 +40,7 @@ def net_http_ssl_fix class Common class << self attr_writer :required_version + attr_reader :cache_warning def version Webdrivers.logger.deprecate("#{self.class}#version", "#{self.class}#required_version") @@ -46,7 +53,7 @@ def version=(version) end def required_version - Gem::Version.new @required_version + normalize_version @required_version end def update @@ -67,13 +74,10 @@ def desired_version desired_version.version.empty? ? latest_version : normalize_version(desired_version) end - def latest_version - @latest_version ||= downloads.keys.max - end - def remove @download_url = nil @latest_version = nil + System.delete "#{System.install_dir}/#{file_name.gsub('.exe', '')}.version" System.delete driver_path end @@ -120,7 +124,7 @@ def sufficient_binary? end def normalize_version(version) - Gem::Version.new(version.to_s) + Gem::Version.new(version&.to_s) end def binary_version @@ -131,6 +135,21 @@ def binary_version Webdrivers.logger.debug "No Such File or Directory: #{driver_path}" nil end + + def with_cache(file_name) + if System.valid_cache?(file_name) + normalize_version System.cached_version(file_name) + else + unless cache_warning + Webdrivers.logger.warn 'Driver caching is turned off in this version, but will be '\ + 'enabled by default in 4.x. Set the value with `Webdrivers#cache_time=` in seconds' + @cache_warning = true + end + version = yield + System.cache_version(file_name, version) + normalize_version version + end + end end end end diff --git a/lib/webdrivers/geckodriver.rb b/lib/webdrivers/geckodriver.rb index 12f1f074..9afd639c 100644 --- a/lib/webdrivers/geckodriver.rb +++ b/lib/webdrivers/geckodriver.rb @@ -17,7 +17,7 @@ def current_version end def latest_version - @latest_version ||= Gem::Version.new(Network.get_url("#{base_url}/latest")[/[^v]*$/]) + @latest_version ||= with_cache(file_name) { normalize_version(Network.get_url("#{base_url}/latest")[/[^v]*$/]) } end private diff --git a/lib/webdrivers/iedriver.rb b/lib/webdrivers/iedriver.rb index 61aa0fc6..e2446cbf 100644 --- a/lib/webdrivers/iedriver.rb +++ b/lib/webdrivers/iedriver.rb @@ -17,6 +17,10 @@ def current_version normalize_version version.match(/IEDriverServer.exe (\d\.\d+\.\d+)/)[1] end + def latest_version + @latest_version ||= with_cache(file_name) { downloads.keys.max } + end + private def file_name diff --git a/lib/webdrivers/system.rb b/lib/webdrivers/system.rb index ae43ef6c..811b3cff 100644 --- a/lib/webdrivers/system.rb +++ b/lib/webdrivers/system.rb @@ -26,6 +26,25 @@ def install_dir Webdrivers.install_dir || File.expand_path(File.join(ENV['HOME'], '.webdrivers')) end + def cache_version(file_name, version) + FileUtils.mkdir_p(install_dir) unless File.exist?(install_dir) + + File.open("#{install_dir}/#{file_name.gsub('.exe', '')}.version", 'w+') do |file| + file.print(version) + end + end + + def cached_version(file_name) + File.open("#{install_dir}/#{file_name.gsub('.exe', '')}.version", 'r', &:read) + end + + def valid_cache?(file_name) + file = "#{install_dir}/#{file_name.gsub('.exe', '')}.version" + return false unless File.exist?(file) + + Time.now - File.mtime(file) < Webdrivers.cache_time + end + def download(url, target) FileUtils.mkdir_p(install_dir) unless File.exist?(install_dir) @@ -99,7 +118,7 @@ def unzip_file(filename) zip_file.each do |f| @top_path ||= f.name f_path = File.join(Dir.pwd, f.name) - FileUtils.rm_rf(f_path) if File.exist?(f_path) + delete(f_path) FileUtils.mkdir_p(File.dirname(f_path)) unless File.exist?(File.dirname(f_path)) zip_file.extract(f, f_path) end diff --git a/spec/webdrivers/chromedriver_spec.rb b/spec/webdrivers/chromedriver_spec.rb index f3b2161c..043372c8 100644 --- a/spec/webdrivers/chromedriver_spec.rb +++ b/spec/webdrivers/chromedriver_spec.rb @@ -95,6 +95,17 @@ expect { chromedriver.update }.to raise_error(Webdrivers::ConnectionError, msg) end end + + it 'makes a network call if cached driver does not match the browser' do + Webdrivers::System.cache_version('chromedriver', '71.0.3578.137') + allow(chromedriver).to receive(:chrome_version).and_return(Gem::Version.new('73.0.3683.68')) + allow(Webdrivers::Network).to receive(:get).and_return('73.0.3683.68') + allow(Webdrivers::System).to receive(:download) + + chromedriver.update + + expect(Webdrivers::Network).to have_received(:get).twice + end end describe '#current_version' do @@ -150,6 +161,34 @@ msg = %r{^Can not reach https://chromedriver.storage.googleapis.com} expect { chromedriver.latest_version }.to raise_error(Webdrivers::ConnectionError, msg) end + + it 'creates cached file' do + allow(Webdrivers::Network).to receive(:get).and_return('71.0.3578.137') + + chromedriver.latest_version + expect(File.exist?("#{Webdrivers::System.install_dir}/chromedriver.version")).to eq true + end + + it 'does not make network call if cache is valid' do + allow(Webdrivers).to receive(:cache_time).and_return(3600) + Webdrivers::System.cache_version('chromedriver', '71.0.3578.137') + allow(Webdrivers::Network).to receive(:get) + + expect(chromedriver.latest_version).to eq Gem::Version.new('71.0.3578.137') + + expect(Webdrivers::Network).not_to have_received(:get) + end + + it 'makes a network call if cache is expired' do + Webdrivers::System.cache_version('chromedriver', '71.0.3578.137') + allow(Webdrivers::Network).to receive(:get).and_return('73.0.3683.68') + allow(Webdrivers::System).to receive(:valid_cache?) + + expect(chromedriver.latest_version).to eq Gem::Version.new('73.0.3683.68') + + expect(Webdrivers::Network).to have_received(:get) + expect(Webdrivers::System).to have_received(:valid_cache?) + end end describe '#required_version=' do diff --git a/spec/webdrivers/geckodriver_spec.rb b/spec/webdrivers/geckodriver_spec.rb index fd3be21a..d526fd50 100644 --- a/spec/webdrivers/geckodriver_spec.rb +++ b/spec/webdrivers/geckodriver_spec.rb @@ -76,7 +76,7 @@ it 'finds the required version from parsed downloads page' do base = 'https://github.com/mozilla/geckodriver/releases/download' - url = %r{#{base}\/v0\.2\.0\/geckodriver-v0\.2\.0-.*\.tar\.gz} + url = %r{#{base}\/v0\.2\.0\/geckodriver-v0\.2\.0-} allow(Webdrivers::System).to receive(:download).with(url, geckodriver.driver_path) @@ -127,6 +127,35 @@ expect(geckodriver.latest_version).to eq Gem::Version.new('0.24.0') end + + it 'creates cached file' do + allow(Webdrivers::Network).to receive(:get).and_return('0.24.0') + + geckodriver.latest_version + expect(File.exist?("#{Webdrivers::System.install_dir}/geckodriver.version")).to eq true + end + + it 'does not make network call if cache is valid' do + allow(Webdrivers).to receive(:cache_time).and_return(3600) + Webdrivers::System.cache_version('geckodriver', '0.23.0') + allow(Webdrivers::Network).to receive(:get) + + expect(geckodriver.latest_version).to eq Gem::Version.new('0.23.0') + + expect(Webdrivers::Network).not_to have_received(:get) + end + + it 'makes a network call if cache is expired' do + Webdrivers::System.cache_version('geckodriver', '0.23.0') + url = 'https://github.com/mozilla/geckodriver/releases/tag/v0.24.0' + allow(Webdrivers::Network).to receive(:get_url).and_return(url) + allow(Webdrivers::System).to receive(:valid_cache?) + + expect(geckodriver.latest_version).to eq Gem::Version.new('0.24.0') + + expect(Webdrivers::Network).to have_received(:get_url) + expect(Webdrivers::System).to have_received(:valid_cache?) + end end describe '#required_version=' do diff --git a/spec/webdrivers/i_edriver_spec.rb b/spec/webdrivers/i_edriver_spec.rb index 502cb5b2..5e396df8 100644 --- a/spec/webdrivers/i_edriver_spec.rb +++ b/spec/webdrivers/i_edriver_spec.rb @@ -107,6 +107,37 @@ it 'correctly parses the downloads page' do expect(iedriver.send(:downloads)).not_to be_empty end + + it 'creates cached file' do + allow(Webdrivers::Network).to receive(:get).and_return('3.4.0') + + iedriver.latest_version + expect(File.exist?("#{Webdrivers::System.install_dir}/IEDriverServer.version")).to eq true + end + + it 'does not make network call if cache is valid' do + allow(Webdrivers).to receive(:cache_time).and_return(3600) + Webdrivers::System.cache_version('IEDriverServer', '3.4.0') + allow(Webdrivers::Network).to receive(:get) + + expect(iedriver.latest_version).to eq Gem::Version.new('3.4.0') + + expect(Webdrivers::Network).not_to have_received(:get) + end + + it 'makes a network call if cache is expired' do + Webdrivers::System.cache_version('IEDriverServer', '3.4.0') + base = 'https://selenium-release.storage.googleapis.com/' + hash = {Gem::Version.new('3.4.0') => "#{base}/3.4/IEDriverServer_Win32_3.4.0.zip", + Gem::Version.new('3.5.0') => "#{base}/3.5/IEDriverServer_Win32_3.5.0.zip", + Gem::Version.new('3.5.1') => "#{base}/3.5/IEDriverServer_Win32_3.5.1.zip"} + allow(iedriver).to receive(:downloads).and_return(hash) + allow(Webdrivers::System).to receive(:valid_cache?) + + expect(iedriver.latest_version).to eq Gem::Version.new('3.5.1') + expect(iedriver).to have_received(:downloads) + expect(Webdrivers::System).to have_received(:valid_cache?) + end end describe '#required_version=' do