diff --git a/rust/Cargo.Bazel.lock b/rust/Cargo.Bazel.lock index da69ac1bc2c03..b024cfdfc8898 100644 --- a/rust/Cargo.Bazel.lock +++ b/rust/Cargo.Bazel.lock @@ -1,5 +1,5 @@ { - "checksum": "0a20f0fe60fda64d9bb35f8a482f95239754a053b83e53e92d2a259eab911369", + "checksum": "45490f1b2f9461b7a6461df267ed0788d1783a8231446ca1b047d8db3e7a9a06", "crates": { "addr2line 0.19.0": { "name": "addr2line", diff --git a/rust/src/chrome.rs b/rust/src/chrome.rs index aa2fec4a83253..35e3c651f435b 100644 --- a/rust/src/chrome.rs +++ b/rust/src/chrome.rs @@ -449,15 +449,15 @@ impl SeleniumManager for ChromeManager { let major_browser_version_int = major_browser_version.parse::().unwrap_or_default(); let driver_version = - if !major_browser_version.is_empty() && major_browser_version_int < 115 { + if self.is_browser_version_stable() || major_browser_version.is_empty() { + // For discovering the latest driver version, the CfT endpoints are also used + self.request_latest_driver_version_from_cft()? + } else if !major_browser_version.is_empty() && major_browser_version_int < 115 { // For old versions (chromedriver 114-), the traditional method should work: // https://chromedriver.chromium.org/downloads self.request_driver_version_from_latest( self.create_latest_release_with_version_url(), )? - } else if major_browser_version.is_empty() { - // For discovering the latest driver version, the CfT endpoints are also used - self.request_latest_driver_version_from_cft()? } else { // As of chromedriver 115+, the metadata for version discovery are published // by the "Chrome for Testing" (CfT) JSON endpoints: @@ -481,6 +481,10 @@ impl SeleniumManager for ChromeManager { } } + fn request_browser_version(&mut self) -> Result, Box> { + Ok(Some(self.request_latest_browser_version_from_cft()?)) + } + fn get_driver_url(&mut self) -> Result> { let major_driver_version = self .get_major_driver_version() @@ -551,15 +555,14 @@ impl SeleniumManager for ChromeManager { } fn download_browser(&mut self) -> Result, Box> { + let browser_version; let browser_name = self.browser_name; - let browser_version_unstable = self.is_browser_version_unstable(); let mut metadata = get_metadata(self.get_logger()); - let mut browser_version = self.get_browser_version().to_string(); let major_browser_version = self.get_major_browser_version(); let major_browser_version_int = major_browser_version.parse::().unwrap_or_default(); - if !browser_version_unstable - && !major_browser_version.is_empty() + if !self.is_browser_version_unstable() + && !self.is_browser_version_stable() && major_browser_version_int < MIN_CHROME_VERSION_CFT { return Err(format_three_args( @@ -587,13 +590,15 @@ impl SeleniumManager for ChromeManager { } _ => { // If not in metadata, discover version using Chrome for Testing (CfT) endpoints - if browser_version.is_empty() { + if self.is_browser_version_stable() { browser_version = self.request_latest_browser_version_from_cft()?; } else { browser_version = self.request_fixed_browser_version_from_cft()?; } + self.set_browser_version(browser_version.clone()); + let browser_ttl = self.get_browser_ttl(); - if browser_ttl > 0 && !browser_version.is_empty() { + if browser_ttl > 0 && !self.is_browser_version_stable() { metadata.browsers.push(create_browser_metadata( browser_name, &major_browser_version, @@ -608,7 +613,6 @@ impl SeleniumManager for ChromeManager { "Required browser: {} {}", browser_name, browser_version )); - self.set_browser_version(browser_version.clone()); // Checking if browser version is in the cache let browser_binary_path = self.get_browser_binary_path_in_cache(); @@ -622,7 +626,7 @@ impl SeleniumManager for ChromeManager { let browser_url = if let Some(url) = self.browser_url.clone() { url } else { - if browser_version.is_empty() { + if self.is_browser_version_stable() { self.request_latest_browser_version_from_cft()?; } else { self.request_fixed_browser_version_from_cft()?; diff --git a/rust/src/edge.rs b/rust/src/edge.rs index f496b3b196fdd..f4b05990a9380 100644 --- a/rust/src/edge.rs +++ b/rust/src/edge.rs @@ -178,7 +178,7 @@ impl SeleniumManager for EdgeManager { _ => { self.assert_online_or_err(OFFLINE_REQUEST_ERR_MSG)?; - if major_browser_version.is_empty() { + if self.is_browser_version_stable() || major_browser_version.is_empty() { let latest_stable_url = format!("{}{}", DRIVER_URL, LATEST_STABLE); self.log.debug(format!( "Reading {} latest version from {}", @@ -226,6 +226,10 @@ impl SeleniumManager for EdgeManager { } } + fn request_browser_version(&mut self) -> Result, Box> { + Ok(None) + } + fn get_driver_url(&mut self) -> Result> { let driver_version = self.get_driver_version(); let os = self.get_os(); diff --git a/rust/src/firefox.rs b/rust/src/firefox.rs index 2ab4594118465..1d35892394bad 100644 --- a/rust/src/firefox.rs +++ b/rust/src/firefox.rs @@ -197,6 +197,10 @@ impl SeleniumManager for FirefoxManager { } } + fn request_browser_version(&mut self) -> Result, Box> { + Ok(None) + } + fn get_driver_url(&mut self) -> Result> { let driver_version = self.get_driver_version(); let os = self.get_os(); diff --git a/rust/src/grid.rs b/rust/src/grid.rs index 7ccd1a444a1db..0b22713258ed8 100644 --- a/rust/src/grid.rs +++ b/rust/src/grid.rs @@ -167,6 +167,10 @@ impl SeleniumManager for GridManager { } } + fn request_browser_version(&mut self) -> Result, Box> { + Ok(None) + } + fn get_driver_url(&mut self) -> Result> { if self.driver_url.is_some() { return Ok(self.driver_url.as_ref().unwrap().to_string()); diff --git a/rust/src/iexplorer.rs b/rust/src/iexplorer.rs index f6264930ad3e2..2d2bd2b3eea3f 100644 --- a/rust/src/iexplorer.rs +++ b/rust/src/iexplorer.rs @@ -167,6 +167,10 @@ impl SeleniumManager for IExplorerManager { } } + fn request_browser_version(&mut self) -> Result, Box> { + Ok(None) + } + fn get_driver_url(&mut self) -> Result> { if self.driver_url.is_some() { return Ok(self.driver_url.as_ref().unwrap().to_string()); diff --git a/rust/src/lib.rs b/rust/src/lib.rs index abacfcc9374b6..872934c11fc03 100644 --- a/rust/src/lib.rs +++ b/rust/src/lib.rs @@ -110,6 +110,8 @@ pub trait SeleniumManager { fn request_driver_version(&mut self) -> Result>; + fn request_browser_version(&mut self) -> Result, Box>; + fn get_driver_url(&mut self) -> Result>; fn get_driver_path_in_cache(&self) -> PathBuf; @@ -262,7 +264,28 @@ pub trait SeleniumManager { } let discovered_major_browser_version = self.get_major_version(&version).unwrap_or_default(); - if !major_browser_version.is_empty() + + if self.is_browser_version_stable() { + let online_browser_version = self.request_browser_version()?; + if online_browser_version.is_some() { + let major_online_browser_version = + self.get_major_version(&online_browser_version.unwrap())?; + if major_browser_version.eq(&major_online_browser_version) { + self.get_logger().debug(format!( + "Online stable browser version ({}) different to specified browser version ({})", + major_online_browser_version, + major_browser_version, + )); + download_browser = true; + } else { + self.get_logger().debug(format!( + "Online stable {} version ({}) is the same as the one installed in the system", + self.get_browser_name(), + major_online_browser_version, + )); + } + } + } else if !major_browser_version.is_empty() && !self.is_browser_version_unstable() && !major_browser_version.eq(&discovered_major_browser_version) { @@ -410,6 +433,11 @@ pub trait SeleniumManager { || browser_version.eq_ignore_ascii_case(CANARY) } + fn is_browser_version_stable(&self) -> bool { + let browser_version = self.get_browser_version(); + browser_version.is_empty() || browser_version.eq_ignore_ascii_case(STABLE) + } + fn resolve_driver(&mut self) -> Result> { let mut driver_in_path = None; let mut driver_in_path_version = None; @@ -576,7 +604,9 @@ pub trait SeleniumManager { } fn get_major_browser_version(&self) -> String { - if self.is_browser_version_unstable() { + if self.is_browser_version_stable() { + STABLE.to_string() + } else if self.is_browser_version_unstable() { self.get_browser_version().to_string() } else { self.get_major_version(self.get_browser_version()) diff --git a/rust/src/safari.rs b/rust/src/safari.rs index 7620af0c0588b..d7807205b058f 100644 --- a/rust/src/safari.rs +++ b/rust/src/safari.rs @@ -101,6 +101,10 @@ impl SeleniumManager for SafariManager { Ok("(local)".to_string()) } + fn request_browser_version(&mut self) -> Result, Box> { + Ok(None) + } + fn get_driver_url(&mut self) -> Result> { Err(format!("{} not available for download", self.get_driver_name()).into()) } diff --git a/rust/src/safaritp.rs b/rust/src/safaritp.rs index 3b118a5993b07..02415305107eb 100644 --- a/rust/src/safaritp.rs +++ b/rust/src/safaritp.rs @@ -106,6 +106,10 @@ impl SeleniumManager for SafariTPManager { Ok("(local)".to_string()) } + fn request_browser_version(&mut self) -> Result, Box> { + Ok(None) + } + fn get_driver_url(&mut self) -> Result> { Err(format!("{} not available for download", self.get_driver_name()).into()) } diff --git a/rust/tests/chrome_download_tests.rs b/rust/tests/chrome_download_tests.rs index 73c09deed618b..ecb071657d555 100644 --- a/rust/tests/chrome_download_tests.rs +++ b/rust/tests/chrome_download_tests.rs @@ -16,12 +16,11 @@ // under the License. use assert_cmd::Command; -use std::path::Path; -use is_executable::is_executable; +use crate::common::assert_driver_and_browser; use rstest::rstest; -use selenium_manager::logger::JsonOutput; -use std::str; + +mod common; #[test] fn chrome_latest_download_test() { @@ -59,18 +58,3 @@ fn chrome_version_download_test(#[case] browser_version: String) { assert_driver_and_browser(&mut cmd); } - -fn assert_driver_and_browser(cmd: &mut Command) { - let stdout = &cmd.unwrap().stdout; - let output = str::from_utf8(stdout).unwrap(); - println!("{}", output); - - let json: JsonOutput = serde_json::from_str(output).unwrap(); - let driver_path = Path::new(&json.result.driver_path); - assert!(driver_path.exists()); - assert!(is_executable(driver_path)); - - let browser_path = Path::new(&json.result.browser_path); - assert!(browser_path.exists()); - assert!(is_executable(browser_path)); -} diff --git a/rust/tests/common.rs b/rust/tests/common.rs new file mode 100644 index 0000000000000..f23e6713df11f --- /dev/null +++ b/rust/tests/common.rs @@ -0,0 +1,37 @@ +// Licensed to the Software Freedom Conservancy (SFC) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The SFC licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +use assert_cmd::Command; +use std::path::Path; + +use is_executable::is_executable; +use selenium_manager::logger::JsonOutput; + +pub fn assert_driver_and_browser(cmd: &mut Command) { + let stdout = &cmd.unwrap().stdout; + let output = std::str::from_utf8(stdout).unwrap(); + println!("{}", output); + + let json: JsonOutput = serde_json::from_str(output).unwrap(); + let driver_path = Path::new(&json.result.driver_path); + assert!(driver_path.exists()); + assert!(is_executable(driver_path)); + + let browser_path = Path::new(&json.result.browser_path); + assert!(browser_path.exists()); + assert!(is_executable(browser_path)); +} diff --git a/rust/tests/stable_browser_tests.rs b/rust/tests/stable_browser_tests.rs new file mode 100644 index 0000000000000..bdee4ebf0ec90 --- /dev/null +++ b/rust/tests/stable_browser_tests.rs @@ -0,0 +1,44 @@ +// Licensed to the Software Freedom Conservancy (SFC) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The SFC licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +use assert_cmd::Command; + +use crate::common::assert_driver_and_browser; +use rstest::rstest; + +mod common; + +#[rstest] +#[case("chrome")] +#[case("firefox")] +#[case("edge")] +fn stable_browser_test(#[case] browser_name: String) { + let mut cmd = Command::new(env!("CARGO_BIN_EXE_selenium-manager")); + cmd.args([ + "--browser", + &browser_name, + "--browser-version", + "stable", + "--output", + "json", + ]) + .assert() + .success() + .code(0); + + assert_driver_and_browser(&mut cmd); +}