Skip to content

Commit 69ea44a

Browse files
authored
[rust] Use online mapping to discover proper geckodriver version (#11671) (#13133)
1 parent 753766e commit 69ea44a

File tree

2 files changed

+104
-14
lines changed

2 files changed

+104
-14
lines changed

rust/src/firefox.rs

Lines changed: 69 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,8 @@ use crate::config::ManagerConfig;
2020
use crate::config::ARCH::{ARM64, X32};
2121
use crate::config::OS::{LINUX, MACOS, WINDOWS};
2222
use crate::downloads::{
23-
parse_generic_json_from_url, read_content_from_link, read_redirect_from_link,
23+
parse_generic_json_from_url, parse_json_from_url, read_content_from_link,
24+
read_redirect_from_link,
2425
};
2526
use crate::files::{compose_driver_path_in_cache, BrowserPath};
2627
use crate::metadata::{
@@ -33,13 +34,16 @@ use crate::{
3334
use anyhow::anyhow;
3435
use anyhow::Error;
3536
use reqwest::Client;
37+
use serde::Deserialize;
38+
use serde::Serialize;
3639
use std::collections::HashMap;
3740
use std::path::PathBuf;
3841

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

215-
let latest_url = format!(
216-
"{}{}",
217-
self.get_driver_mirror_url_or_default(DRIVER_URL),
218-
LATEST_RELEASE
219+
let driver_releases_result = parse_json_from_url::<GeckodriverReleases>(
220+
self.get_http_client(),
221+
DRIVER_VERSIONS_URL.to_string(),
219222
);
220-
let driver_version =
221-
read_redirect_from_link(self.get_http_client(), latest_url, self.get_logger())?;
223+
let driver_version = if driver_releases_result.is_ok() {
224+
let driver_releases = driver_releases_result.unwrap();
225+
let major_browser_version_int =
226+
major_browser_version.parse::<u32>().unwrap_or_default();
227+
let filtered_versions: Vec<String> = driver_releases
228+
.geckodriver_releases
229+
.into_iter()
230+
.filter(|r| {
231+
major_browser_version_int >= r.min_firefox_version
232+
&& (r.max_firefox_version.is_none()
233+
|| (r.max_firefox_version.is_some()
234+
&& major_browser_version_int
235+
<= r.max_firefox_version.unwrap()))
236+
})
237+
.map(|r| r.geckodriver_version)
238+
.collect();
239+
self.log.debug(format!(
240+
"Valid {} versions for {} {}: {:?}",
241+
&self.driver_name,
242+
&self.browser_name,
243+
major_browser_version_int,
244+
filtered_versions
245+
));
246+
if filtered_versions.is_empty() {
247+
return Err(anyhow!(format!(
248+
"Not valid {} version found for {} {}",
249+
&self.driver_name, &self.browser_name, major_browser_version_int
250+
)));
251+
} else {
252+
filtered_versions.first().unwrap().to_string()
253+
}
254+
} else {
255+
self.log.warn(format!(
256+
"Problem reading {} versions: {}. Using latest {} version",
257+
&self.driver_name,
258+
driver_releases_result.err().unwrap(),
259+
&self.driver_name,
260+
));
261+
let latest_url = format!(
262+
"{}{}",
263+
self.get_driver_mirror_url_or_default(DRIVER_URL),
264+
LATEST_RELEASE
265+
);
266+
read_redirect_from_link(self.get_http_client(), latest_url, self.get_logger())?
267+
};
222268

223269
let driver_ttl = self.get_ttl();
224270
if driver_ttl > 0 && !major_browser_version.is_empty() {
@@ -545,6 +591,22 @@ impl SeleniumManager for FirefoxManager {
545591
}
546592
}
547593

594+
#[derive(Serialize, Deserialize, Debug)]
595+
pub struct GeckodriverReleases {
596+
#[serde(rename = "geckodriver-releases")]
597+
pub geckodriver_releases: Vec<GeckodriverRelease>,
598+
}
599+
600+
#[derive(Serialize, Deserialize, Debug)]
601+
pub struct GeckodriverRelease {
602+
#[serde(rename = "geckodriver-version")]
603+
pub geckodriver_version: String,
604+
#[serde(rename = "min-firefox-version")]
605+
pub min_firefox_version: u32,
606+
#[serde(rename = "max-firefox-version")]
607+
pub max_firefox_version: Option<u32>,
608+
}
609+
548610
#[cfg(test)]
549611
mod unit_tests {
550612
use super::*;

rust/tests/browser_tests.rs

Lines changed: 35 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717

1818
use crate::common::{assert_driver, assert_output};
1919
use assert_cmd::Command;
20+
use exitcode::DATAERR;
2021
use rstest::rstest;
2122
use std::env::consts::OS;
2223

@@ -27,6 +28,11 @@ mod common;
2728
#[case("chrome", "chromedriver", "115", "115.0.5790")]
2829
#[case("edge", "msedgedriver", "105", "105.0")]
2930
#[case("edge", "msedgedriver", "106", "106.0")]
31+
#[case("firefox", "geckodriver", "101", "0.31.0")]
32+
#[case("firefox", "geckodriver", "91", "0.31.0")]
33+
#[case("firefox", "geckodriver", "90", "0.30.0")]
34+
#[case("firefox", "geckodriver", "62", "0.29.1")]
35+
#[case("firefox", "geckodriver", "53", "0.18.0")]
3036
fn browser_version_test(
3137
#[case] browser: String,
3238
#[case] driver_name: String,
@@ -57,13 +63,13 @@ fn browser_version_test(
5763
}
5864

5965
#[rstest]
60-
#[case("wrong-browser", "", "", exitcode::DATAERR)]
61-
#[case("chrome", "wrong-browser-version", "", exitcode::DATAERR)]
62-
#[case("chrome", "", "wrong-driver-version", exitcode::DATAERR)]
63-
#[case("firefox", "", "wrong-driver-version", exitcode::DATAERR)]
64-
#[case("edge", "wrong-browser-version", "", exitcode::DATAERR)]
65-
#[case("edge", "", "wrong-driver-version", exitcode::DATAERR)]
66-
#[case("iexplorer", "", "wrong-driver-version", exitcode::DATAERR)]
66+
#[case("wrong-browser", "", "", DATAERR)]
67+
#[case("chrome", "wrong-browser-version", "", DATAERR)]
68+
#[case("chrome", "", "wrong-driver-version", DATAERR)]
69+
#[case("firefox", "", "wrong-driver-version", DATAERR)]
70+
#[case("edge", "wrong-browser-version", "", DATAERR)]
71+
#[case("edge", "", "wrong-driver-version", DATAERR)]
72+
#[case("iexplorer", "", "wrong-driver-version", DATAERR)]
6773
fn wrong_parameters_test(
6874
#[case] browser: String,
6975
#[case] browser_version: String,
@@ -87,6 +93,28 @@ fn wrong_parameters_test(
8793
assert_output(&mut cmd, result, vec!["in PATH"], error_code);
8894
}
8995

96+
#[test]
97+
fn invalid_geckodriver_version_test() {
98+
let mut cmd = Command::new(env!("CARGO_BIN_EXE_selenium-manager"));
99+
let result = cmd
100+
.args([
101+
"--browser",
102+
"firefox",
103+
"--browser-version",
104+
"51",
105+
"--avoid-browser-download",
106+
])
107+
.assert()
108+
.try_success();
109+
110+
assert_output(
111+
&mut cmd,
112+
result,
113+
vec!["Not valid geckodriver version found"],
114+
DATAERR,
115+
);
116+
}
117+
90118
#[rstest]
91119
#[case("chrome", "chromedriver")]
92120
#[case("edge", "msedgedriver")]

0 commit comments

Comments
 (0)