Skip to content

Commit

Permalink
[rust] Use online mapping to discover proper geckodriver version (#11671
Browse files Browse the repository at this point in the history
) (#13133)
  • Loading branch information
bonigarcia authored Nov 10, 2023
1 parent 753766e commit 69ea44a
Show file tree
Hide file tree
Showing 2 changed files with 104 additions and 14 deletions.
76 changes: 69 additions & 7 deletions rust/src/firefox.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,8 @@ use crate::config::ManagerConfig;
use crate::config::ARCH::{ARM64, X32};
use crate::config::OS::{LINUX, MACOS, WINDOWS};
use crate::downloads::{
parse_generic_json_from_url, read_content_from_link, read_redirect_from_link,
parse_generic_json_from_url, parse_json_from_url, read_content_from_link,
read_redirect_from_link,
};
use crate::files::{compose_driver_path_in_cache, BrowserPath};
use crate::metadata::{
Expand All @@ -33,13 +34,16 @@ use crate::{
use anyhow::anyhow;
use anyhow::Error;
use reqwest::Client;
use serde::Deserialize;
use serde::Serialize;
use std::collections::HashMap;
use std::path::PathBuf;

pub const FIREFOX_NAME: &str = "firefox";
pub const GECKODRIVER_NAME: &str = "geckodriver";
const DRIVER_URL: &str = "https://github.com/mozilla/geckodriver/releases/";
const LATEST_RELEASE: &str = "latest";
const DRIVER_VERSIONS_URL: &str = "https://raw.githubusercontent.com/SeleniumHQ/selenium/trunk/common/geckodriver/geckodriver-support.json";
const BROWSER_URL: &str = "https://ftp.mozilla.org/pub/firefox/releases/";
const FIREFOX_DEFAULT_LANG: &str = "en-US";
const FIREFOX_MACOS_APP_NAME: &str = "Firefox.app/Contents/MacOS/firefox";
Expand Down Expand Up @@ -212,13 +216,55 @@ impl SeleniumManager for FirefoxManager {
_ => {
self.assert_online_or_err(OFFLINE_REQUEST_ERR_MSG)?;

let latest_url = format!(
"{}{}",
self.get_driver_mirror_url_or_default(DRIVER_URL),
LATEST_RELEASE
let driver_releases_result = parse_json_from_url::<GeckodriverReleases>(
self.get_http_client(),
DRIVER_VERSIONS_URL.to_string(),
);
let driver_version =
read_redirect_from_link(self.get_http_client(), latest_url, self.get_logger())?;
let driver_version = if driver_releases_result.is_ok() {
let driver_releases = driver_releases_result.unwrap();
let major_browser_version_int =
major_browser_version.parse::<u32>().unwrap_or_default();
let filtered_versions: Vec<String> = driver_releases
.geckodriver_releases
.into_iter()
.filter(|r| {
major_browser_version_int >= r.min_firefox_version
&& (r.max_firefox_version.is_none()
|| (r.max_firefox_version.is_some()
&& major_browser_version_int
<= r.max_firefox_version.unwrap()))
})
.map(|r| r.geckodriver_version)
.collect();
self.log.debug(format!(
"Valid {} versions for {} {}: {:?}",
&self.driver_name,
&self.browser_name,
major_browser_version_int,
filtered_versions
));
if filtered_versions.is_empty() {
return Err(anyhow!(format!(
"Not valid {} version found for {} {}",
&self.driver_name, &self.browser_name, major_browser_version_int
)));
} else {
filtered_versions.first().unwrap().to_string()
}
} else {
self.log.warn(format!(
"Problem reading {} versions: {}. Using latest {} version",
&self.driver_name,
driver_releases_result.err().unwrap(),
&self.driver_name,
));
let latest_url = format!(
"{}{}",
self.get_driver_mirror_url_or_default(DRIVER_URL),
LATEST_RELEASE
);
read_redirect_from_link(self.get_http_client(), latest_url, self.get_logger())?
};

let driver_ttl = self.get_ttl();
if driver_ttl > 0 && !major_browser_version.is_empty() {
Expand Down Expand Up @@ -545,6 +591,22 @@ impl SeleniumManager for FirefoxManager {
}
}

#[derive(Serialize, Deserialize, Debug)]
pub struct GeckodriverReleases {
#[serde(rename = "geckodriver-releases")]
pub geckodriver_releases: Vec<GeckodriverRelease>,
}

#[derive(Serialize, Deserialize, Debug)]
pub struct GeckodriverRelease {
#[serde(rename = "geckodriver-version")]
pub geckodriver_version: String,
#[serde(rename = "min-firefox-version")]
pub min_firefox_version: u32,
#[serde(rename = "max-firefox-version")]
pub max_firefox_version: Option<u32>,
}

#[cfg(test)]
mod unit_tests {
use super::*;
Expand Down
42 changes: 35 additions & 7 deletions rust/tests/browser_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@

use crate::common::{assert_driver, assert_output};
use assert_cmd::Command;
use exitcode::DATAERR;
use rstest::rstest;
use std::env::consts::OS;

Expand All @@ -27,6 +28,11 @@ mod common;
#[case("chrome", "chromedriver", "115", "115.0.5790")]
#[case("edge", "msedgedriver", "105", "105.0")]
#[case("edge", "msedgedriver", "106", "106.0")]
#[case("firefox", "geckodriver", "101", "0.31.0")]
#[case("firefox", "geckodriver", "91", "0.31.0")]
#[case("firefox", "geckodriver", "90", "0.30.0")]
#[case("firefox", "geckodriver", "62", "0.29.1")]
#[case("firefox", "geckodriver", "53", "0.18.0")]
fn browser_version_test(
#[case] browser: String,
#[case] driver_name: String,
Expand Down Expand Up @@ -57,13 +63,13 @@ fn browser_version_test(
}

#[rstest]
#[case("wrong-browser", "", "", exitcode::DATAERR)]
#[case("chrome", "wrong-browser-version", "", exitcode::DATAERR)]
#[case("chrome", "", "wrong-driver-version", exitcode::DATAERR)]
#[case("firefox", "", "wrong-driver-version", exitcode::DATAERR)]
#[case("edge", "wrong-browser-version", "", exitcode::DATAERR)]
#[case("edge", "", "wrong-driver-version", exitcode::DATAERR)]
#[case("iexplorer", "", "wrong-driver-version", exitcode::DATAERR)]
#[case("wrong-browser", "", "", DATAERR)]
#[case("chrome", "wrong-browser-version", "", DATAERR)]
#[case("chrome", "", "wrong-driver-version", DATAERR)]
#[case("firefox", "", "wrong-driver-version", DATAERR)]
#[case("edge", "wrong-browser-version", "", DATAERR)]
#[case("edge", "", "wrong-driver-version", DATAERR)]
#[case("iexplorer", "", "wrong-driver-version", DATAERR)]
fn wrong_parameters_test(
#[case] browser: String,
#[case] browser_version: String,
Expand All @@ -87,6 +93,28 @@ fn wrong_parameters_test(
assert_output(&mut cmd, result, vec!["in PATH"], error_code);
}

#[test]
fn invalid_geckodriver_version_test() {
let mut cmd = Command::new(env!("CARGO_BIN_EXE_selenium-manager"));
let result = cmd
.args([
"--browser",
"firefox",
"--browser-version",
"51",
"--avoid-browser-download",
])
.assert()
.try_success();

assert_output(
&mut cmd,
result,
vec!["Not valid geckodriver version found"],
DATAERR,
);
}

#[rstest]
#[case("chrome", "chromedriver")]
#[case("edge", "msedgedriver")]
Expand Down

0 comments on commit 69ea44a

Please sign in to comment.