fix(command_test): select correct webdriver version

master
Martin Kavík 6 years ago
parent 439e523192
commit 2facd17653
  1. 113
      src/test/webdriver.rs
  2. 77
      src/test/webdriver/chromedriver.rs
  3. 93
      src/test/webdriver/geckodriver.rs
  4. 13
      src/test/webdriver/safaridriver.rs

@ -1,12 +1,22 @@
//! Getting WebDriver client binaries.
mod chromedriver;
mod geckodriver;
mod safaridriver;
use binary_install::Cache;
use failure;
use install::InstallMode;
use std::path::PathBuf;
use target;
use PBAR;
pub use self::{
chromedriver::{get_or_install_chromedriver, install_chromedriver},
geckodriver::{get_or_install_geckodriver, install_geckodriver},
safaridriver::get_safaridriver,
};
// ------ driver helpers ------
fn get_and_notify(
cache: &Cache,
installation_allowed: bool,
@ -25,100 +35,11 @@ fn get_and_notify(
}
}
/// Get the path to an existing `chromedriver`, or install it if no existing
/// binary is found.
pub fn get_or_install_chromedriver(
cache: &Cache,
mode: InstallMode,
) -> Result<PathBuf, failure::Error> {
if let Ok(path) = which::which("chromedriver") {
return Ok(path);
}
install_chromedriver(cache, mode.install_permitted())
}
/// Download and install a pre-built `chromedriver` binary.
pub fn install_chromedriver(
cache: &Cache,
installation_allowed: bool,
) -> Result<PathBuf, failure::Error> {
let target = if target::LINUX && target::x86_64 {
"linux64"
} else if target::MACOS && target::x86_64 {
"mac64"
} else if target::WINDOWS {
"win32"
} else {
bail!("chromedriver binaries are unavailable for this target")
};
let url = format!(
"https://chromedriver.storage.googleapis.com/2.46/chromedriver_{}.zip",
target
);
match get_and_notify(cache, installation_allowed, "chromedriver", &url)? {
Some(path) => Ok(path),
None => bail!(
"No cached `chromedriver` binary found, and could not find a global \
`chromedriver` on the `$PATH`. Not installing `chromedriver` because of noinstall \
mode."
),
}
}
/// Get the path to an existing `geckodriver`, or install it if no existing
/// binary is found.
pub fn get_or_install_geckodriver(
cache: &Cache,
mode: InstallMode,
) -> Result<PathBuf, failure::Error> {
if let Ok(path) = which::which("geckodriver") {
return Ok(path);
}
install_geckodriver(cache, mode.install_permitted())
}
/// Download and install a pre-built `geckodriver` binary.
pub fn install_geckodriver(
cache: &Cache,
installation_allowed: bool,
) -> Result<PathBuf, failure::Error> {
let (target, ext) = if target::LINUX && target::x86 {
("linux32", "tar.gz")
} else if target::LINUX && target::x86_64 {
("linux64", "tar.gz")
} else if target::MACOS {
("macos", "tar.gz")
} else if target::WINDOWS && target::x86 {
("win32", "zip")
} else if target::WINDOWS && target::x86_64 {
("win64", "zip")
} else {
bail!("geckodriver binaries are unavailable for this target")
};
let url = format!(
"https://github.com/mozilla/geckodriver/releases/download/v0.24.0/geckodriver-v0.24.0-{}.{}",
target,
ext,
);
match get_and_notify(cache, installation_allowed, "geckodriver", &url)? {
Some(path) => Ok(path),
None => bail!(
"No cached `geckodriver` binary found, and could not find a global `geckodriver` \
on the `$PATH`. Not installing `geckodriver` because of noinstall mode."
),
}
}
struct Collector(Vec<u8>);
/// Get the path to an existing `safaridriver`.
///
/// We can't install `safaridriver` if an existing one is not found because
/// Apple does not provide pre-built binaries. However, `safaridriver` *should*
/// be present by default.
pub fn get_safaridriver() -> Result<PathBuf, failure::Error> {
match which::which("safaridriver") {
Ok(p) => Ok(p),
Err(_) => bail!("could not find `safaridriver` on the `$PATH`"),
impl curl::easy::Handler for Collector {
fn write(&mut self, data: &[u8]) -> Result<usize, curl::easy::WriteError> {
self.0.extend_from_slice(data);
Ok(data.len())
}
}

@ -0,0 +1,77 @@
use super::{get_and_notify, Collector};
use binary_install::Cache;
use failure;
use install::InstallMode;
use std::path::PathBuf;
use target;
/// Get the path to an existing `chromedriver`, or install it if no existing
/// binary is found or if there is a new binary version.
pub fn get_or_install_chromedriver(
cache: &Cache,
mode: InstallMode,
) -> Result<PathBuf, failure::Error> {
if let Ok(path) = which::which("chromedriver") {
return Ok(path);
}
install_chromedriver(cache, mode.install_permitted())
}
/// Download and install a pre-built `chromedriver` binary.
pub fn install_chromedriver(
cache: &Cache,
installation_allowed: bool,
) -> Result<PathBuf, failure::Error> {
let target = if target::LINUX && target::x86_64 {
"linux64"
} else if target::MACOS && target::x86_64 {
"mac64"
} else if target::WINDOWS {
"win32"
} else {
bail!("chromedriver binaries are unavailable for this target")
};
let url = get_chromedriver_url(target)?;
match get_and_notify(cache, installation_allowed, "chromedriver", &url)? {
Some(path) => Ok(path),
None => bail!(
"No cached `chromedriver` binary found, and could not find a global \
`chromedriver` on the `$PATH`. Not installing `chromedriver` because of noinstall \
mode."
),
}
}
/// Get `chromedriver` download URL.
///
/// It returns the latest one without checking the installed `Chrome` version
/// because it's not easy to find out `Chrome` version on `Windows` -
/// https://bugs.chromium.org/p/chromium/issues/detail?id=158372
///
/// The official algorithm for `chromedriver` version selection:
/// https://chromedriver.chromium.org/downloads/version-selection
fn get_chromedriver_url(target: &str) -> Result<String, failure::Error> {
let chromedriver_version = fetch_chromedriver_version()?;
Ok(assemble_chromedriver_url(&chromedriver_version, target))
}
// ------ `get_chromedriver_url` steps ------
fn fetch_chromedriver_version() -> Result<String, failure::Error> {
let mut handle = curl::easy::Easy2::new(Collector(Vec::new()));
handle.url("https://chromedriver.storage.googleapis.com/LATEST_RELEASE")?;
handle.perform()?;
let contents = handle.get_ref();
Ok(String::from_utf8_lossy(&contents.0).into_owned())
}
fn assemble_chromedriver_url(chromedriver_version: &str, target: &str) -> String {
format!(
"https://chromedriver.storage.googleapis.com/{version}/chromedriver_{target}.zip",
version = chromedriver_version,
target = target,
)
}

@ -0,0 +1,93 @@
use super::{get_and_notify, Collector};
use binary_install::Cache;
use failure;
use install::InstallMode;
use std::path::PathBuf;
use target;
/// Get the path to an existing `geckodriver`, or install it if no existing
/// binary is found or if there is a new binary version.
pub fn get_or_install_geckodriver(
cache: &Cache,
mode: InstallMode,
) -> Result<PathBuf, failure::Error> {
if let Ok(path) = which::which("geckodriver") {
return Ok(path);
}
install_geckodriver(cache, mode.install_permitted())
}
/// Download and install a pre-built `geckodriver` binary.
pub fn install_geckodriver(
cache: &Cache,
installation_allowed: bool,
) -> Result<PathBuf, failure::Error> {
let (target, ext) = if target::LINUX && target::x86 {
("linux32", "tar.gz")
} else if target::LINUX && target::x86_64 {
("linux64", "tar.gz")
} else if target::MACOS {
("macos", "tar.gz")
} else if target::WINDOWS && target::x86 {
("win32", "zip")
} else if target::WINDOWS && target::x86_64 {
("win64", "zip")
} else {
bail!("geckodriver binaries are unavailable for this target")
};
let url = get_geckodriver_url(target, ext)?;
match get_and_notify(cache, installation_allowed, "geckodriver", &url)? {
Some(path) => Ok(path),
None => bail!(
"No cached `geckodriver` binary found, and could not find a global `geckodriver` \
on the `$PATH`. Not installing `geckodriver` because of noinstall mode."
),
}
}
/// Get `geckodriver` download URL.
///
/// It returns the latest one without checking the installed `Firefox` version
/// - it should be relatively safe because each `geckodriver` supports many `Firefox` versions:
/// https://firefox-source-docs.mozilla.org/testing/geckodriver/Support.html#supported-platforms
fn get_geckodriver_url(target: &str, ext: &str) -> Result<String, failure::Error> {
// JSON example: `{"id":15227534,"tag_name":"v0.24.0","update_url":"/mozzila...`
let latest_tag_json = fetch_latest_geckodriver_tag_json()?;
let latest_tag = get_tag_name_from_json(&latest_tag_json)?;
Ok(assemble_geckodriver_url(&latest_tag, target, ext))
}
// ------ `get_geckodriver_url` steps ------
fn fetch_latest_geckodriver_tag_json() -> Result<String, failure::Error> {
let mut headers = curl::easy::List::new();
headers.append("Accept: application/json")?;
let mut handle = curl::easy::Easy2::new(Collector(Vec::new()));
handle.url("https://github.com/mozilla/geckodriver/releases/latest")?;
handle.http_headers(headers)?;
// We will be redirected from the `latest` placeholder to the specific tag name.
handle.follow_location(true)?;
handle.perform()?;
let contents = handle.get_ref();
Ok(String::from_utf8_lossy(&contents.0).into_owned())
}
fn get_tag_name_from_json(json: &str) -> Result<String, failure::Error> {
let json: serde_json::Value = serde_json::from_str(json)?;
json.get("tag_name")
.and_then(|tag_name| tag_name.as_str().map(ToOwned::to_owned))
.ok_or_else(|| failure::err_msg("cannot get `tag_name` from JSON response"))
}
fn assemble_geckodriver_url(tag: &str, target: &str, ext: &str) -> String {
format!(
"https://github.com/mozilla/geckodriver/releases/download/{tag}/geckodriver-{tag}-{target}.{ext}",
tag=tag,
target=target,
ext=ext,
)
}

@ -0,0 +1,13 @@
use std::path::PathBuf;
/// Get the path to an existing `safaridriver`.
///
/// We can't install `safaridriver` if an existing one is not found because
/// Apple does not provide pre-built binaries. However, `safaridriver` *should*
/// be present by default.
pub fn get_safaridriver() -> Result<PathBuf, failure::Error> {
match which::which("safaridriver") {
Ok(p) => Ok(p),
Err(_) => bail!("could not find `safaridriver` on the `$PATH`"),
}
}
Loading…
Cancel
Save